forty-cdk 0.14.0 → 0.16.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.
Files changed (197) hide show
  1. package/README.md +2 -2
  2. package/accordion/README.md +5 -1
  3. package/aspect-ratio/README.md +1 -1
  4. package/avatar/README.md +5 -1
  5. package/button/README.md +1 -1
  6. package/calendar/README.md +5 -1
  7. package/carousel/README.md +59 -29
  8. package/checkbox/README.md +9 -6
  9. package/combobox/README.md +25 -18
  10. package/context-menu/README.md +9 -5
  11. package/date-field/README.md +13 -13
  12. package/date-picker/README.md +6 -6
  13. package/date-range-field/README.md +13 -13
  14. package/dialog/README.md +10 -6
  15. package/disclosure/README.md +5 -1
  16. package/drag-drop/README.md +73 -14
  17. package/drawer/README.md +38 -31
  18. package/dropdown-menu/README.md +9 -5
  19. package/fesm2022/forty-cdk-accordion.mjs +4 -3
  20. package/fesm2022/forty-cdk-accordion.mjs.map +1 -1
  21. package/fesm2022/forty-cdk-button.mjs +9 -43
  22. package/fesm2022/forty-cdk-button.mjs.map +1 -1
  23. package/fesm2022/forty-cdk-calendar.mjs +10 -8
  24. package/fesm2022/forty-cdk-calendar.mjs.map +1 -1
  25. package/fesm2022/forty-cdk-carousel.mjs +101 -41
  26. package/fesm2022/forty-cdk-carousel.mjs.map +1 -1
  27. package/fesm2022/forty-cdk-checkbox.mjs +34 -8
  28. package/fesm2022/forty-cdk-checkbox.mjs.map +1 -1
  29. package/fesm2022/forty-cdk-combobox.mjs +100 -174
  30. package/fesm2022/forty-cdk-combobox.mjs.map +1 -1
  31. package/fesm2022/forty-cdk-context-menu.mjs +2 -2
  32. package/fesm2022/forty-cdk-context-menu.mjs.map +1 -1
  33. package/fesm2022/forty-cdk-core.mjs +2319 -3012
  34. package/fesm2022/forty-cdk-core.mjs.map +1 -1
  35. package/fesm2022/forty-cdk-date-field.mjs.map +1 -1
  36. package/fesm2022/forty-cdk-date-picker.mjs +8 -7
  37. package/fesm2022/forty-cdk-date-picker.mjs.map +1 -1
  38. package/fesm2022/forty-cdk-dialog.mjs +8 -6
  39. package/fesm2022/forty-cdk-dialog.mjs.map +1 -1
  40. package/fesm2022/forty-cdk-disclosure.mjs +4 -3
  41. package/fesm2022/forty-cdk-disclosure.mjs.map +1 -1
  42. package/fesm2022/forty-cdk-drag-drop.mjs +439 -60
  43. package/fesm2022/forty-cdk-drag-drop.mjs.map +1 -1
  44. package/fesm2022/forty-cdk-drawer.mjs +454 -97
  45. package/fesm2022/forty-cdk-drawer.mjs.map +1 -1
  46. package/fesm2022/forty-cdk-dropdown-menu.mjs +7 -6
  47. package/fesm2022/forty-cdk-dropdown-menu.mjs.map +1 -1
  48. package/fesm2022/forty-cdk-fieldset.mjs +0 -1
  49. package/fesm2022/forty-cdk-fieldset.mjs.map +1 -1
  50. package/fesm2022/forty-cdk-file-upload.mjs +4 -3
  51. package/fesm2022/forty-cdk-file-upload.mjs.map +1 -1
  52. package/fesm2022/forty-cdk-hover-card.mjs +4 -4
  53. package/fesm2022/forty-cdk-hover-card.mjs.map +1 -1
  54. package/fesm2022/forty-cdk-listbox.mjs +26 -18
  55. package/fesm2022/forty-cdk-listbox.mjs.map +1 -1
  56. package/fesm2022/forty-cdk-menu.mjs +28 -19
  57. package/fesm2022/forty-cdk-menu.mjs.map +1 -1
  58. package/fesm2022/forty-cdk-menubar.mjs +142 -58
  59. package/fesm2022/forty-cdk-menubar.mjs.map +1 -1
  60. package/fesm2022/forty-cdk-navigation-menu.mjs +28 -29
  61. package/fesm2022/forty-cdk-navigation-menu.mjs.map +1 -1
  62. package/fesm2022/forty-cdk-number-input.mjs +209 -5
  63. package/fesm2022/forty-cdk-number-input.mjs.map +1 -1
  64. package/fesm2022/forty-cdk-otp-input.mjs +14 -14
  65. package/fesm2022/forty-cdk-otp-input.mjs.map +1 -1
  66. package/fesm2022/forty-cdk-pagination.mjs +10 -7
  67. package/fesm2022/forty-cdk-pagination.mjs.map +1 -1
  68. package/fesm2022/forty-cdk-pane-resizer.mjs +46 -14
  69. package/fesm2022/forty-cdk-pane-resizer.mjs.map +1 -1
  70. package/fesm2022/forty-cdk-popover.mjs +12 -10
  71. package/fesm2022/forty-cdk-popover.mjs.map +1 -1
  72. package/fesm2022/forty-cdk-radio-group.mjs +4 -3
  73. package/fesm2022/forty-cdk-radio-group.mjs.map +1 -1
  74. package/fesm2022/forty-cdk-scroll-area.mjs +407 -105
  75. package/fesm2022/forty-cdk-scroll-area.mjs.map +1 -1
  76. package/fesm2022/forty-cdk-search.mjs +5 -4
  77. package/fesm2022/forty-cdk-search.mjs.map +1 -1
  78. package/fesm2022/forty-cdk-select.mjs +107 -94
  79. package/fesm2022/forty-cdk-select.mjs.map +1 -1
  80. package/fesm2022/forty-cdk-shared.mjs +6 -0
  81. package/fesm2022/forty-cdk-shared.mjs.map +1 -0
  82. package/fesm2022/forty-cdk-slider.mjs +26 -28
  83. package/fesm2022/forty-cdk-slider.mjs.map +1 -1
  84. package/fesm2022/forty-cdk-stepper.mjs +13 -9
  85. package/fesm2022/forty-cdk-stepper.mjs.map +1 -1
  86. package/fesm2022/forty-cdk-switch.mjs +33 -7
  87. package/fesm2022/forty-cdk-switch.mjs.map +1 -1
  88. package/fesm2022/forty-cdk-table.mjs +272 -123
  89. package/fesm2022/forty-cdk-table.mjs.map +1 -1
  90. package/fesm2022/forty-cdk-tabs.mjs +4 -3
  91. package/fesm2022/forty-cdk-tabs.mjs.map +1 -1
  92. package/fesm2022/forty-cdk-time-field.mjs.map +1 -1
  93. package/fesm2022/forty-cdk-time-picker.mjs +7 -6
  94. package/fesm2022/forty-cdk-time-picker.mjs.map +1 -1
  95. package/fesm2022/forty-cdk-toast.mjs +32 -23
  96. package/fesm2022/forty-cdk-toast.mjs.map +1 -1
  97. package/fesm2022/forty-cdk-toggle.mjs +7 -5
  98. package/fesm2022/forty-cdk-toggle.mjs.map +1 -1
  99. package/fesm2022/forty-cdk-toolbar.mjs +8 -5
  100. package/fesm2022/forty-cdk-toolbar.mjs.map +1 -1
  101. package/fesm2022/forty-cdk-tooltip.mjs +4 -4
  102. package/fesm2022/forty-cdk-tooltip.mjs.map +1 -1
  103. package/fesm2022/forty-cdk-tree.mjs +149 -3
  104. package/fesm2022/forty-cdk-tree.mjs.map +1 -1
  105. package/fesm2022/forty-cdk-virtualization.mjs +28 -15
  106. package/fesm2022/forty-cdk-virtualization.mjs.map +1 -1
  107. package/fesm2022/forty-cdk-visually-hidden.mjs +6 -0
  108. package/fesm2022/forty-cdk-visually-hidden.mjs.map +1 -0
  109. package/field/README.md +5 -1
  110. package/fieldset/README.md +5 -1
  111. package/file-upload/README.md +5 -1
  112. package/hover-card/README.md +10 -6
  113. package/input/README.md +2 -2
  114. package/internationalized-date/README.md +23 -23
  115. package/listbox/README.md +13 -13
  116. package/menu/README.md +10 -6
  117. package/menubar/README.md +24 -6
  118. package/meter/README.md +5 -1
  119. package/navigation-menu/README.md +8 -4
  120. package/number-input/README.md +2 -2
  121. package/otp-input/README.md +6 -6
  122. package/package.json +9 -1
  123. package/pagination/README.md +4 -0
  124. package/pane-resizer/README.md +29 -27
  125. package/popover/README.md +10 -6
  126. package/progress/README.md +5 -1
  127. package/radio-group/README.md +2 -2
  128. package/scroll-area/README.md +77 -9
  129. package/search/README.md +1 -1
  130. package/select/README.md +24 -25
  131. package/separator/README.md +1 -1
  132. package/shared/README.md +99 -0
  133. package/signal-forms/README.md +2 -2
  134. package/slider/README.md +22 -23
  135. package/stepper/README.md +6 -2
  136. package/switch/README.md +9 -7
  137. package/table/README.md +45 -956
  138. package/tabs/README.md +5 -1
  139. package/time-field/README.md +2 -2
  140. package/time-picker/README.md +2 -2
  141. package/time-range-field/README.md +2 -2
  142. package/toast/README.md +7 -3
  143. package/toggle/README.md +2 -2
  144. package/toolbar/README.md +5 -1
  145. package/tooltip/README.md +8 -4
  146. package/tree/README.md +5 -1
  147. package/types/forty-cdk-accordion.d.ts +1 -1
  148. package/types/forty-cdk-breakpoints.d.ts +1 -1
  149. package/types/forty-cdk-button.d.ts +1 -1
  150. package/types/forty-cdk-calendar.d.ts +3 -1
  151. package/types/forty-cdk-carousel.d.ts +75 -18
  152. package/types/forty-cdk-checkbox.d.ts +20 -4
  153. package/types/forty-cdk-combobox.d.ts +160 -72
  154. package/types/forty-cdk-context-menu.d.ts +2 -3
  155. package/types/forty-cdk-core.d.ts +637 -1009
  156. package/types/forty-cdk-date-field.d.ts +0 -1
  157. package/types/forty-cdk-date-picker.d.ts +7 -9
  158. package/types/forty-cdk-date-range-field.d.ts +0 -1
  159. package/types/forty-cdk-dialog.d.ts +4 -3
  160. package/types/forty-cdk-disclosure.d.ts +1 -0
  161. package/types/forty-cdk-drag-drop.d.ts +47 -20
  162. package/types/forty-cdk-drawer.d.ts +88 -55
  163. package/types/forty-cdk-dropdown-menu.d.ts +3 -3
  164. package/types/forty-cdk-fieldset.d.ts +0 -1
  165. package/types/forty-cdk-file-upload.d.ts +1 -0
  166. package/types/forty-cdk-hover-card.d.ts +5 -6
  167. package/types/forty-cdk-internationalized-date.d.ts +0 -1
  168. package/types/forty-cdk-listbox.d.ts +10 -10
  169. package/types/forty-cdk-menu.d.ts +14 -5
  170. package/types/forty-cdk-menubar.d.ts +98 -14
  171. package/types/forty-cdk-navigation-menu.d.ts +10 -10
  172. package/types/forty-cdk-number-input.d.ts +3 -1
  173. package/types/forty-cdk-otp-input.d.ts +7 -7
  174. package/types/forty-cdk-pagination.d.ts +3 -1
  175. package/types/forty-cdk-pane-resizer.d.ts +13 -6
  176. package/types/forty-cdk-popover.d.ts +8 -7
  177. package/types/forty-cdk-radio-group.d.ts +1 -1
  178. package/types/forty-cdk-scroll-area.d.ts +158 -14
  179. package/types/forty-cdk-search.d.ts +15 -14
  180. package/types/forty-cdk-select.d.ts +81 -59
  181. package/types/forty-cdk-shared.d.ts +1 -0
  182. package/types/forty-cdk-slider.d.ts +24 -24
  183. package/types/forty-cdk-stepper.d.ts +8 -5
  184. package/types/forty-cdk-switch.d.ts +23 -7
  185. package/types/forty-cdk-table.d.ts +44 -233
  186. package/types/forty-cdk-tabs.d.ts +1 -1
  187. package/types/forty-cdk-time-field.d.ts +0 -1
  188. package/types/forty-cdk-time-picker.d.ts +5 -5
  189. package/types/forty-cdk-time-range-field.d.ts +0 -1
  190. package/types/forty-cdk-toast.d.ts +12 -7
  191. package/types/forty-cdk-toggle.d.ts +2 -1
  192. package/types/forty-cdk-toolbar.d.ts +5 -3
  193. package/types/forty-cdk-tooltip.d.ts +5 -6
  194. package/types/forty-cdk-tree.d.ts +1 -1
  195. package/types/forty-cdk-visually-hidden.d.ts +1 -0
  196. package/virtualization/README.md +4 -0
  197. package/visually-hidden/README.md +78 -0
package/README.md CHANGED
@@ -36,7 +36,7 @@ Optional — install only if you use the matching entry point / primitives:
36
36
 
37
37
  ## Primitives
38
38
 
39
- Every primitive ships as its own **secondary entry point** — import `ForDialog` from `forty-cdk/dialog`, `ForAccordion` from `forty-cdk/accordion`, and so on — backed by the shared `forty-cdk/core` entry point. Each lives in its own folder under `projects/forty-cdk/` with its own `README.md` documenting its anatomy, API, keyboard interaction and styling hooks. The `@internationalized/date` adapters live in a dedicated `forty-cdk/internationalized-date` entry point so that optional peer stays truly optional. The main `forty-cdk` barrel is **intentionally empty** (it exports no symbols): always import from the specific `forty-cdk/<primitive>` entry point. Standalone directives plus `"sideEffects": false` mean your bundle only ever includes the primitives you import.
39
+ Every primitive ships as its own **secondary entry point** — import `ForDialog` from `forty-cdk/dialog`, `ForAccordion` from `forty-cdk/accordion`, and so on — backed by the shared `forty-cdk/core` entry point. Each lives in its own folder under `projects/forty-cdk/` with its own `README.md` documenting its anatomy, API, keyboard interaction and styling hooks. The `@internationalized/date` adapters live in a dedicated `forty-cdk/internationalized-date` entry point so that optional peer stays truly optional. The cross-primitive contract types a primitive's public API references — `WritingDirection`, `VetoableEvent`, `DateAdapter`, `FloatingSide`, … — are published by [`forty-cdk/shared`](shared); the main `forty-cdk` barrel is **intentionally empty** (it exports no symbols), so always import primitives from the specific `forty-cdk/<primitive>` entry point. Standalone directives plus `"sideEffects": false` mean your bundle only ever includes the primitives you import.
40
40
 
41
41
  The tables below group the primitives by purpose. The link on each name opens that primitive's README — the canonical reference for which HTML element each directive belongs on, its inputs / outputs, `data-*` attributes and keyboard map.
42
42
 
@@ -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 dismissable popover. |
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. |
@@ -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](../../../../../docs/styling.md)). Key your CSS off the reflected `data-*` attributes listed per piece in the [API](#api) section.
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 re-provide `FOR_ACCORDION_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).
@@ -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](../../../../../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]`.
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](../../../../../docs/styling.md)). Key your CSS off the reflected `data-*` attributes listed per piece in the [API](#api) section.
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](../../../../../docs/styling.md)). Key your CSS off the reflected `data-*` attributes listed per piece in the [API](#api) section.
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] {
@@ -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](../../../../../docs/styling.md)). Key your CSS off the reflected `data-*` attributes listed under [Data attributes](#data-attributes).
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).
@@ -110,6 +110,11 @@ the defaults with `startLabel` / `stopLabel` inputs:
110
110
  <button forCarouselRotationControl startLabel="Play slideshow" stopLabel="Pause slideshow"></button>
111
111
  ```
112
112
 
113
+ Both defaults come from the scope's `rotationStartLabel` / `rotationStopLabel`
114
+ (see [Localizing the default labels](#localizing-the-default-labels)); set either
115
+ input to `null` when the button carries a visible text label and you don't want
116
+ an `aria-label` overriding it.
117
+
113
118
  **Programmatic control** via `exportAs`:
114
119
 
115
120
  ```html
@@ -141,17 +146,22 @@ don't use it.
141
146
 
142
147
  ### CSS contract
143
148
 
144
- The directive publishes `--for-carousel-drag` (a raw px value) on the viewport
145
- host during the gesture. Compose it with `--for-carousel-offset` on the track
146
- transform:
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:
147
153
 
148
154
  ```css
149
155
  [forCarouselTrack] {
150
- transform: translateX(calc(var(--for-carousel-offset) + var(--for-carousel-drag, 0px)));
156
+ transform: translateX(
157
+ calc(var(--for-carousel-offset) + var(--for-carousel-swipe-movement-x, 0px))
158
+ );
151
159
  transition: transform 300ms ease;
152
160
  }
153
161
  [forCarousel][data-orientation='vertical'] [forCarouselTrack] {
154
- transform: translateY(calc(var(--for-carousel-offset) + var(--for-carousel-drag, 0px)));
162
+ transform: translateY(
163
+ calc(var(--for-carousel-offset) + var(--for-carousel-swipe-movement-y, 0px))
164
+ );
155
165
  }
156
166
  /* Kill the settle transition while the finger is down so the track follows 1:1 */
157
167
  [forCarouselViewport][data-dragging] [forCarouselTrack] {
@@ -164,20 +174,22 @@ transform:
164
174
 
165
175
  ### RTL
166
176
 
167
- `--for-carousel-drag` is always the **physical** finger displacement, so compose
168
- it **without** the `-1` factor the consumer may apply to `--for-carousel-offset`
169
- 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:
170
180
 
171
181
  ```css
172
182
  [dir='rtl'] [forCarouselTrack] {
173
- transform: translateX(calc(-1 * var(--for-carousel-offset) + var(--for-carousel-drag, 0px)));
183
+ transform: translateX(
184
+ calc(-1 * var(--for-carousel-offset) + var(--for-carousel-swipe-movement-x, 0px))
185
+ );
174
186
  }
175
187
  ```
176
188
 
177
189
  ### Reduced motion
178
190
 
179
191
  Under `prefers-reduced-motion: reduce` the directive does **not** publish
180
- `--for-carousel-drag` (no live track motion). The gesture still snaps
192
+ `--for-carousel-swipe-movement-x` / `-y` (no live track motion). The gesture still snaps
181
193
  `activeIndex` on release — only the continuous live offset is suppressed.
182
194
 
183
195
  ### Cross-axis / touch
@@ -189,16 +201,19 @@ captured, so page scrolling on the perpendicular axis is unaffected.
189
201
 
190
202
  ## Localizing the default labels
191
203
 
192
- Each slide's default `aria-label` is the positional `"N of M"` string, and each
193
- indicator's is `"Go to slide N"`. Localize both centrally with
194
- `provideForCarouselDefaults` instead of setting `ariaLabel` on every slide and
195
- indicator:
204
+ Each slide's default `aria-label` is the positional `"N of M"` string, each
205
+ indicator's is `"Go to slide N"`, and the rotation control's swaps between
206
+ `"Start automatic slide show"` and `"Stop automatic slide show"`. Localize them
207
+ all centrally with `provideForCarouselDefaults` instead of setting `ariaLabel` on
208
+ every slide and indicator:
196
209
 
197
210
  ```ts
198
211
  providers: [
199
212
  provideForCarouselDefaults({
200
213
  slideLabel: (position, total) => `Diapositiva ${position} de ${total}`,
201
214
  indicatorLabel: (position) => `Ir a la diapositiva ${position}`,
215
+ rotationStartLabel: 'Iniciar la presentación',
216
+ rotationStopLabel: 'Detener la presentación',
202
217
  }),
203
218
  ];
204
219
  ```
@@ -206,7 +221,8 @@ providers: [
206
221
  `position` is the 1-based slide index and `total` is the slide count. Overrides
207
222
  merge with the parent scope, so you can localize just the labels and inherit the
208
223
  rest of the defaults. A per-element `ariaLabel` on `[forCarouselSlide]` /
209
- `[forCarouselIndicator]` still takes precedence over the localized default.
224
+ `[forCarouselIndicator]` still takes precedence over the localized default, as do
225
+ `[startLabel]` / `[stopLabel]` on `[forCarouselRotationControl]`.
210
226
 
211
227
  ## API
212
228
 
@@ -229,8 +245,8 @@ All inputs are on `[forCarousel]` unless noted.
229
245
  | `ariaLabel` (on `[forCarouselIndicators]`) | `string \| null` | Label for the picker group.<br>**Default:** `null` |
230
246
  | `ariaLabel` (on `[forCarouselSlide]`) | `string \| null` | Override the positional "N of M" label.<br>**Default:** `null` |
231
247
  | `disabled` (on `[forCarouselIndicator]`) | `boolean` | Disable this indicator.<br>**Default:** `false` |
232
- | `startLabel` (on `[forCarouselRotationControl]`) | `string` | Accessible name while rotation is stopped.<br>**Default:** `'Start automatic slide show'` |
233
- | `stopLabel` (on `[forCarouselRotationControl]`) | `string` | Accessible name while rotation is playing.<br>**Default:** `'Stop automatic slide show'` |
248
+ | `startLabel` (on `[forCarouselRotationControl]`) | `string \| null` | Accessible name while rotation is stopped.<br>**Default:** scope `rotationStartLabel` (`'Start automatic slide show'`) |
249
+ | `stopLabel` (on `[forCarouselRotationControl]`) | `string \| null` | Accessible name while rotation is playing.<br>**Default:** scope `rotationStopLabel` (`'Stop automatic slide show'`) |
234
250
 
235
251
  Reflected on the `[forCarousel]` host:
236
252
 
@@ -298,8 +314,10 @@ Implements the [WAI-ARIA Carousel pattern](https://www.w3.org/WAI/ARIA/apg/patte
298
314
  accessibility tree and focus order.
299
315
  - The indicator group should be labelled (e.g. `ariaLabel="Choose slide to display"`).
300
316
  - The current indicator is marked with `aria-current="true"`.
301
- - Prev/next buttons use native `disabled` so they are removed from the tab order when
302
- at the boundary without loop.
317
+ - Prev/next buttons never use the native `disabled` attribute. At a boundary without `loop`
318
+ they reflect `aria-disabled="true"` + `data-disabled` and ignore activation, so a keyboard
319
+ user who reaches the last slide keeps focus on the button instead of being dropped to
320
+ `<body>`. Style the boundary state off `[data-disabled]`, never `:disabled`.
303
321
  - The viewport carries `aria-live` and `aria-atomic="false"`. While the carousel is actively
304
322
  auto-rotating, `aria-live` is `"off"` so advancing slides do not bombard the screen reader.
305
323
  When stopped or paused, it is `"polite"` so manual navigation announces. The per-slide
@@ -308,7 +326,7 @@ Implements the [WAI-ARIA Carousel pattern](https://www.w3.org/WAI/ARIA/apg/patte
308
326
 
309
327
  ## Styling
310
328
 
311
- 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.
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.
312
330
 
313
331
  ```css
314
332
  [forCarouselViewport] {
@@ -338,15 +356,16 @@ forty-cdk ships no styles. Add your own class to each piece — the `for*` selec
338
356
  The following properties are set on the `[forCarousel]` host and cascade to
339
357
  children, unless noted otherwise:
340
358
 
341
- | Property | Host | Value | Notes |
342
- | -------------------------------- | ----------------------- | ------------- | --------------------------------------------------------------------------------------------------------------- |
343
- | `--for-carousel-offset` | `[forCarousel]` | e.g. `-100%` | Pure arithmetic from `activeIndex`, `slidesPerView`, `align`. |
344
- | `--for-carousel-active-index` | `[forCarousel]` | integer | Current `activeIndex`. |
345
- | `--for-carousel-slide-count` | `[forCarousel]` | integer | Total registered slides. |
346
- | `--for-carousel-slides-per-view` | `[forCarousel]` | integer | From the `slidesPerView` input. |
347
- | `--for-carousel-viewport-width` | `[forCarousel]` | e.g. `640px` | Measured via `ResizeObserver`. Absent on the server and before first measurement. |
348
- | `--for-carousel-viewport-height` | `[forCarousel]` | e.g. `400px` | Same as above, for the block axis. |
349
- | `--for-carousel-drag` | `[forCarouselViewport]` | e.g. `-128px` | Live px offset along the primary axis during a drag; absent at rest and under `prefers-reduced-motion: reduce`. |
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`. |
350
369
 
351
370
  ### Autoplay styling hooks
352
371
 
@@ -365,6 +384,13 @@ children, unless noted otherwise:
365
384
  | `data-rotating` | On `[forCarousel]` — actively rotating right now |
366
385
  | `data-autoplay` | On `[forCarousel]` — the `autoplay` input is `true` |
367
386
 
387
+ ### Boundary styling hooks
388
+
389
+ | Attribute | When present |
390
+ | --------------- | --------------------------------------------------------- |
391
+ | `data-disabled` | On `[forCarouselPrevious]` — at index 0 without `loop` |
392
+ | `data-disabled` | On `[forCarouselNext]` — at the last index without `loop` |
393
+
368
394
  ### Drag styling hooks
369
395
 
370
396
  | Attribute | Host | When present |
@@ -397,3 +423,7 @@ in RTL is the consumer's CSS concern. For example, to flip the translate sign in
397
423
  ```
398
424
 
399
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 re-provide `FOR_CAROUSEL_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).
@@ -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 — the directive sits on a `<button>`, a documented superset, not an APG violation. |
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](../../../../../docs/styling.md)). Key your CSS off the reflected data-\* attributes listed per piece in the [API](#api) section.
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](../../../../../docs/wrapping-form-primitives.md).
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).
@@ -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](../../../../../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.
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 (action)="createNew(query())">Create "{{ query() }}"</button>
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 `(action)` instead of mutating `[(value)]`. The
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 `(action)`
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
- | `(action)` | `output<void>` | Fired on click / Enter / Space. Never mutates `[(value)]`. |
286
+ | `(activate)` | `output<void>` | Fired on click / Enter / Space. Never mutates `[(value)]`. |
287
287
 
288
- `[forComboboxAction]` host-binds `role="button"`, `type="button"`, a
289
- primitive-managed `tabindex`, `aria-disabled` (when disabled), and reflects
290
- `data-highlighted` while it holds DOM focus + `data-disabled` when disabled.
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 | Default | Purpose |
444
- | ---------------------- | ------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------- |
445
- | `[isItemEqualToValue]` | `(a, b) => a === b` | How two items compare. Override for object values so selection / removal locate by id (or any stable key). |
446
- | `[itemToStringLabel]` | `(item) => String(item)` | Render an item as a string. Drives `commitOnSelect` writes into the input and the chip-label fallback. |
447
- | `[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). |
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
- [isItemEqualToValue]="byId"
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](../../../../../docs/styling.md)). Key your CSS off the reflected data-\* attributes listed under [Data attributes](#data-attributes).
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](../../../../../docs/styling-floating-content.md) for the full positioner-variable list and the portal styling rules.
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](../../../../../docs/wrapping-form-primitives.md).
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).
@@ -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](../../../../../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.
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 dismissable layer.<br>**Default:** — |
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 [CLAUDE.md › Auto-focus hook shape](../../../../../CLAUDE.md#auto-focus-hook-shape) for why Dialog uses callback-shape inputs instead.
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](../../../../../docs/styling.md)). Key your CSS off the reflected data-\* attributes listed under [Data attributes](#data-attributes).
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](../../../../../docs/styling-floating-content.md) for the full list and the animation rules.
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).
@@ -118,17 +118,17 @@ export class DobFormField {
118
118
 
119
119
  ### `ForDateField`
120
120
 
121
- | Property | Type | Description |
122
- | ------------- | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
123
- | `value` | `model<D \| null>` | Two-way bindable entered date, or `null` while any segment is empty. The `FormValueControl` backing.<br>**Default:** `null` |
124
- | `minDate` | `input<D \| null>` | Minimum date (inclusive). A composed value below it is clamped up. Named `minDate` — see note below.<br>**Default:** `null` |
125
- | `maxDate` | `input<D \| null>` | Maximum date (inclusive). A composed value above it is clamped down.<br>**Default:** `null` |
126
- | `granularity` | `input<'day' \| 'hour' \| 'minute' \| 'second'>` | Date-time precision. `'day'` is date-only; coarser-than-day appends time segments. See below.<br>**Default:** `'day'` |
127
- | `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` |
128
- | `locale` | `input<string \| null>` | BCP 47 locale driving segment order, separators, and month name. `null` → runtime locale.<br>**Default:** `null` |
129
- | `placeholder` | `input<Partial<Record<DateTimeSegmentType, string>>>` | Per-segment placeholder while empty. Unspecified parts fall back to `dd` / `mm` / `yyyy` / `hh` / `mm` / `ss` / `--`.<br>**Default:** `{}` |
130
- | `ariaLabel` | `input<string \| null>` | Accessible name for the group. Emits no `aria-label` while `null`.<br>**Default:** `null` |
131
- | `dir` | `input<'ltr' \| 'rtl' \| null>` | Writing direction. `null` resolves the ambient direction; mirrors ArrowLeft / ArrowRight segment navigation.<br>**Default:** `null` |
121
+ | Property | Type | Description |
122
+ | ------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ |
123
+ | `value` | `model<D \| null>` | Two-way bindable entered date, or `null` while any segment is empty. The `FormValueControl` backing.<br>**Default:** `null` |
124
+ | `minDate` | `input<D \| null>` | Minimum date (inclusive). A composed value below it is clamped up. Named `minDate` — see note below.<br>**Default:** `null` |
125
+ | `maxDate` | `input<D \| null>` | Maximum date (inclusive). A composed value above it is clamped down.<br>**Default:** `null` |
126
+ | `granularity` | `input<'day' \| 'hour' \| 'minute' \| 'second'>` | Date-time precision. `'day'` is date-only; coarser-than-day appends time segments. See below.<br>**Default:** `'day'` |
127
+ | `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` |
128
+ | `locale` | `input<string \| null>` | BCP 47 locale driving segment order, separators, and month name. `null` → runtime locale.<br>**Default:** `null` |
129
+ | `placeholder` | `input<Partial<Record<SegmentType, string>>>` | Per-segment placeholder while empty. Unspecified parts fall back to `dd` / `mm` / `yyyy` / `hh` / `mm` / `ss` / `--`.<br>**Default:** `{}` |
130
+ | `ariaLabel` | `input<string \| null>` | Accessible name for the group. Emits no `aria-label` while `null`.<br>**Default:** `null` |
131
+ | `dir` | `input<'ltr' \| 'rtl' \| null>` | Writing direction. `null` resolves the ambient direction; mirrors ArrowLeft / ArrowRight segment navigation.<br>**Default:** `null` |
132
132
 
133
133
  Plus the shared `FormUiControl` members from `@angular/forms/signals`: `disabled`, `readonly`, `required`, `invalid`, `name`, `errors`, `touched` (bound automatically by `[formField]`).
134
134
 
@@ -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](../../../../../docs/styling.md)). Key your CSS off the reflected data-\* attributes listed under [Data attributes](#data-attributes).
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](../../../../../docs/wrapping-form-primitives.md).
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).
@@ -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 dismissable popover with min / max bounds and per-date availability.
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, dismissable 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).
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](../../../../../docs/wrapping-form-primitives.md).
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
 
@@ -341,9 +341,9 @@ Implements the [WAI-ARIA Date Picker Dialog pattern](https://www.w3.org/WAI/ARIA
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](../../../../../docs/styling.md)). Key your CSS off the reflected `data-*` attributes listed under [Data attributes](#data-attributes).
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](../../../../../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.
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](../../../../../docs/wrapping-form-primitives.md).
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).