forty-cdk 0.14.0 → 0.15.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 (90) hide show
  1. package/README.md +1 -1
  2. package/carousel/README.md +27 -9
  3. package/date-field/README.md +11 -11
  4. package/date-range-field/README.md +11 -11
  5. package/drag-drop/README.md +34 -10
  6. package/fesm2022/forty-cdk-calendar.mjs +0 -1
  7. package/fesm2022/forty-cdk-calendar.mjs.map +1 -1
  8. package/fesm2022/forty-cdk-carousel.mjs +76 -29
  9. package/fesm2022/forty-cdk-carousel.mjs.map +1 -1
  10. package/fesm2022/forty-cdk-combobox.mjs +42 -6
  11. package/fesm2022/forty-cdk-combobox.mjs.map +1 -1
  12. package/fesm2022/forty-cdk-core.mjs +1240 -2207
  13. package/fesm2022/forty-cdk-core.mjs.map +1 -1
  14. package/fesm2022/forty-cdk-date-field.mjs.map +1 -1
  15. package/fesm2022/forty-cdk-drag-drop.mjs +409 -40
  16. package/fesm2022/forty-cdk-drag-drop.mjs.map +1 -1
  17. package/fesm2022/forty-cdk-drawer.mjs +341 -3
  18. package/fesm2022/forty-cdk-drawer.mjs.map +1 -1
  19. package/fesm2022/forty-cdk-fieldset.mjs +0 -1
  20. package/fesm2022/forty-cdk-fieldset.mjs.map +1 -1
  21. package/fesm2022/forty-cdk-listbox.mjs +8 -1
  22. package/fesm2022/forty-cdk-listbox.mjs.map +1 -1
  23. package/fesm2022/forty-cdk-menu.mjs +0 -1
  24. package/fesm2022/forty-cdk-menu.mjs.map +1 -1
  25. package/fesm2022/forty-cdk-number-input.mjs +203 -1
  26. package/fesm2022/forty-cdk-number-input.mjs.map +1 -1
  27. package/fesm2022/forty-cdk-pane-resizer.mjs +46 -14
  28. package/fesm2022/forty-cdk-pane-resizer.mjs.map +1 -1
  29. package/fesm2022/forty-cdk-scroll-area.mjs +407 -105
  30. package/fesm2022/forty-cdk-scroll-area.mjs.map +1 -1
  31. package/fesm2022/forty-cdk-select.mjs +53 -16
  32. package/fesm2022/forty-cdk-select.mjs.map +1 -1
  33. package/fesm2022/forty-cdk-shared.mjs +6 -0
  34. package/fesm2022/forty-cdk-shared.mjs.map +1 -0
  35. package/fesm2022/forty-cdk-table.mjs +272 -123
  36. package/fesm2022/forty-cdk-table.mjs.map +1 -1
  37. package/fesm2022/forty-cdk-time-field.mjs.map +1 -1
  38. package/fesm2022/forty-cdk-tree.mjs +146 -1
  39. package/fesm2022/forty-cdk-tree.mjs.map +1 -1
  40. package/fesm2022/forty-cdk-virtualization.mjs +18 -9
  41. package/fesm2022/forty-cdk-virtualization.mjs.map +1 -1
  42. package/fesm2022/forty-cdk-visually-hidden.mjs +6 -0
  43. package/fesm2022/forty-cdk-visually-hidden.mjs.map +1 -0
  44. package/package.json +9 -1
  45. package/pane-resizer/README.md +28 -26
  46. package/scroll-area/README.md +72 -8
  47. package/shared/README.md +84 -0
  48. package/table/README.md +25 -0
  49. package/types/forty-cdk-accordion.d.ts +0 -1
  50. package/types/forty-cdk-calendar.d.ts +0 -1
  51. package/types/forty-cdk-carousel.d.ts +64 -15
  52. package/types/forty-cdk-combobox.d.ts +117 -49
  53. package/types/forty-cdk-context-menu.d.ts +0 -1
  54. package/types/forty-cdk-core.d.ts +316 -918
  55. package/types/forty-cdk-date-field.d.ts +0 -1
  56. package/types/forty-cdk-date-picker.d.ts +0 -1
  57. package/types/forty-cdk-date-range-field.d.ts +0 -1
  58. package/types/forty-cdk-dialog.d.ts +0 -1
  59. package/types/forty-cdk-drag-drop.d.ts +36 -10
  60. package/types/forty-cdk-drawer.d.ts +1 -1
  61. package/types/forty-cdk-dropdown-menu.d.ts +0 -1
  62. package/types/forty-cdk-fieldset.d.ts +0 -1
  63. package/types/forty-cdk-hover-card.d.ts +0 -1
  64. package/types/forty-cdk-internationalized-date.d.ts +0 -1
  65. package/types/forty-cdk-listbox.d.ts +0 -1
  66. package/types/forty-cdk-menu.d.ts +0 -1
  67. package/types/forty-cdk-menubar.d.ts +0 -1
  68. package/types/forty-cdk-navigation-menu.d.ts +0 -1
  69. package/types/forty-cdk-number-input.d.ts +1 -1
  70. package/types/forty-cdk-pagination.d.ts +0 -1
  71. package/types/forty-cdk-pane-resizer.d.ts +13 -6
  72. package/types/forty-cdk-popover.d.ts +0 -1
  73. package/types/forty-cdk-radio-group.d.ts +0 -1
  74. package/types/forty-cdk-scroll-area.d.ts +158 -14
  75. package/types/forty-cdk-select.d.ts +68 -48
  76. package/types/forty-cdk-shared.d.ts +1 -0
  77. package/types/forty-cdk-slider.d.ts +0 -1
  78. package/types/forty-cdk-stepper.d.ts +0 -1
  79. package/types/forty-cdk-table.d.ts +44 -233
  80. package/types/forty-cdk-tabs.d.ts +0 -1
  81. package/types/forty-cdk-time-field.d.ts +0 -1
  82. package/types/forty-cdk-time-picker.d.ts +0 -1
  83. package/types/forty-cdk-time-range-field.d.ts +0 -1
  84. package/types/forty-cdk-toast.d.ts +0 -1
  85. package/types/forty-cdk-toggle.d.ts +0 -1
  86. package/types/forty-cdk-toolbar.d.ts +0 -1
  87. package/types/forty-cdk-tooltip.d.ts +0 -1
  88. package/types/forty-cdk-tree.d.ts +0 -1
  89. package/types/forty-cdk-visually-hidden.d.ts +1 -0
  90. 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
 
@@ -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
@@ -189,16 +194,19 @@ captured, so page scrolling on the perpendicular axis is unaffected.
189
194
 
190
195
  ## Localizing the default labels
191
196
 
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:
197
+ Each slide's default `aria-label` is the positional `"N of M"` string, each
198
+ indicator's is `"Go to slide N"`, and the rotation control's swaps between
199
+ `"Start automatic slide show"` and `"Stop automatic slide show"`. Localize them
200
+ all centrally with `provideForCarouselDefaults` instead of setting `ariaLabel` on
201
+ every slide and indicator:
196
202
 
197
203
  ```ts
198
204
  providers: [
199
205
  provideForCarouselDefaults({
200
206
  slideLabel: (position, total) => `Diapositiva ${position} de ${total}`,
201
207
  indicatorLabel: (position) => `Ir a la diapositiva ${position}`,
208
+ rotationStartLabel: 'Iniciar la presentación',
209
+ rotationStopLabel: 'Detener la presentación',
202
210
  }),
203
211
  ];
204
212
  ```
@@ -206,7 +214,8 @@ providers: [
206
214
  `position` is the 1-based slide index and `total` is the slide count. Overrides
207
215
  merge with the parent scope, so you can localize just the labels and inherit the
208
216
  rest of the defaults. A per-element `ariaLabel` on `[forCarouselSlide]` /
209
- `[forCarouselIndicator]` still takes precedence over the localized default.
217
+ `[forCarouselIndicator]` still takes precedence over the localized default, as do
218
+ `[startLabel]` / `[stopLabel]` on `[forCarouselRotationControl]`.
210
219
 
211
220
  ## API
212
221
 
@@ -229,8 +238,8 @@ All inputs are on `[forCarousel]` unless noted.
229
238
  | `ariaLabel` (on `[forCarouselIndicators]`) | `string \| null` | Label for the picker group.<br>**Default:** `null` |
230
239
  | `ariaLabel` (on `[forCarouselSlide]`) | `string \| null` | Override the positional "N of M" label.<br>**Default:** `null` |
231
240
  | `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'` |
241
+ | `startLabel` (on `[forCarouselRotationControl]`) | `string \| null` | Accessible name while rotation is stopped.<br>**Default:** scope `rotationStartLabel` (`'Start automatic slide show'`) |
242
+ | `stopLabel` (on `[forCarouselRotationControl]`) | `string \| null` | Accessible name while rotation is playing.<br>**Default:** scope `rotationStopLabel` (`'Stop automatic slide show'`) |
234
243
 
235
244
  Reflected on the `[forCarousel]` host:
236
245
 
@@ -298,8 +307,10 @@ Implements the [WAI-ARIA Carousel pattern](https://www.w3.org/WAI/ARIA/apg/patte
298
307
  accessibility tree and focus order.
299
308
  - The indicator group should be labelled (e.g. `ariaLabel="Choose slide to display"`).
300
309
  - 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.
310
+ - Prev/next buttons never use the native `disabled` attribute. At a boundary without `loop`
311
+ they reflect `aria-disabled="true"` + `data-disabled` and ignore activation, so a keyboard
312
+ user who reaches the last slide keeps focus on the button instead of being dropped to
313
+ `<body>`. Style the boundary state off `[data-disabled]`, never `:disabled`.
303
314
  - The viewport carries `aria-live` and `aria-atomic="false"`. While the carousel is actively
304
315
  auto-rotating, `aria-live` is `"off"` so advancing slides do not bombard the screen reader.
305
316
  When stopped or paused, it is `"polite"` so manual navigation announces. The per-slide
@@ -365,6 +376,13 @@ children, unless noted otherwise:
365
376
  | `data-rotating` | On `[forCarousel]` — actively rotating right now |
366
377
  | `data-autoplay` | On `[forCarousel]` — the `autoplay` input is `true` |
367
378
 
379
+ ### Boundary styling hooks
380
+
381
+ | Attribute | When present |
382
+ | --------------- | --------------------------------------------------------- |
383
+ | `data-disabled` | On `[forCarouselPrevious]` — at index 0 without `loop` |
384
+ | `data-disabled` | On `[forCarouselNext]` — at the last index without `loop` |
385
+
368
386
  ### Drag styling hooks
369
387
 
370
388
  | Attribute | Host | When present |
@@ -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
 
@@ -158,17 +158,17 @@ export class StayFormField {
158
158
 
159
159
  ### `ForDateRangeField`
160
160
 
161
- | Property | Type | Description |
162
- | ------------- | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
163
- | `value` | `model<DateRange<D> \| null>` | Two-way bindable committed range, or `null` while incomplete or out of order. The `FormValueControl` backing.<br>**Default:** `null` |
164
- | `minDate` | `input<D \| null>` | Minimum date (inclusive) for both endpoints. A composed endpoint below it is clamped up. Named `minDate` — see note below.<br>**Default:** `null` |
165
- | `maxDate` | `input<D \| null>` | Maximum date (inclusive) for both endpoints. A composed endpoint above it is clamped down.<br>**Default:** `null` |
166
- | `granularity` | `input<'day' \| 'hour' \| 'minute' \| 'second'>` | Date-time precision shared by both endpoints. `'day'` is date-only; coarser-than-day appends time segments.<br>**Default:** `'day'` |
167
- | `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` |
168
- | `locale` | `input<string \| null>` | BCP 47 locale driving segment order, separators, and month name. `null` → runtime locale.<br>**Default:** `null` |
169
- | `placeholder` | `input<Partial<Record<DateTimeSegmentType, string>>>` | Per-segment placeholder while empty, applied to both endpoints.<br>**Default:** `{}` |
170
- | `ariaLabel` | `input<string \| null>` | Accessible name for the whole range field group. Emits no `aria-label` while `null`.<br>**Default:** `null` |
171
- | `dir` | `input<'ltr' \| 'rtl' \| null>` | Writing direction. `null` resolves the ambient direction; mirrors ArrowLeft / ArrowRight segment navigation.<br>**Default:** `null` |
161
+ | Property | Type | Description |
162
+ | ------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- |
163
+ | `value` | `model<DateRange<D> \| null>` | Two-way bindable committed range, or `null` while incomplete or out of order. The `FormValueControl` backing.<br>**Default:** `null` |
164
+ | `minDate` | `input<D \| null>` | Minimum date (inclusive) for both endpoints. A composed endpoint below it is clamped up. Named `minDate` — see note below.<br>**Default:** `null` |
165
+ | `maxDate` | `input<D \| null>` | Maximum date (inclusive) for both endpoints. A composed endpoint above it is clamped down.<br>**Default:** `null` |
166
+ | `granularity` | `input<'day' \| 'hour' \| 'minute' \| 'second'>` | Date-time precision shared by both endpoints. `'day'` is date-only; coarser-than-day appends time segments.<br>**Default:** `'day'` |
167
+ | `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` |
168
+ | `locale` | `input<string \| null>` | BCP 47 locale driving segment order, separators, and month name. `null` → runtime locale.<br>**Default:** `null` |
169
+ | `placeholder` | `input<Partial<Record<SegmentType, string>>>` | Per-segment placeholder while empty, applied to both endpoints.<br>**Default:** `{}` |
170
+ | `ariaLabel` | `input<string \| null>` | Accessible name for the whole range field group. Emits no `aria-label` while `null`.<br>**Default:** `null` |
171
+ | `dir` | `input<'ltr' \| 'rtl' \| null>` | Writing direction. `null` resolves the ambient direction; mirrors ArrowLeft / ArrowRight segment navigation.<br>**Default:** `null` |
172
172
 
173
173
  The endpoint groups (`[forDateRangeFieldStart]` / `[forDateRangeFieldEnd]`) each accept an `ariaLabel` input for their own group label, falling back to the scope defaults (`'Start date'` / `'End date'`).
174
174
 
@@ -7,15 +7,15 @@ whole dialog around by its header — see [`[forFreeDrag]`](#free-drag).
7
7
 
8
8
  ## Keyboard
9
9
 
10
- | State | Key | Action |
11
- | ------ | ----------- | ------------------------------------------------- |
12
- | Idle | Arrow keys | Move roving focus between items |
13
- | Idle | Home / End | Jump to first / last item |
14
- | Idle | Space/Enter | **Lift** the focused item |
15
- | Lifted | Arrow keys | Step the logical drop position |
16
- | Lifted | Home / End | Jump the lifted item to the first / last position |
17
- | Lifted | Space/Enter | **Drop** (commits and emits `(dragDrop)`) |
18
- | Lifted | Escape | **Cancel** (no event, focus stays on item) |
10
+ | State | Key | Action |
11
+ | ------ | ----------- | -------------------------------------------------------------- |
12
+ | Idle | Arrow keys | Move roving focus between items |
13
+ | Idle | Home / End | Jump to first / last item |
14
+ | Idle | Space/Enter | **Lift** the focused item |
15
+ | Lifted | Arrow keys | Step the logical drop position |
16
+ | Lifted | Home / End | Jump the lifted item to the first / last position |
17
+ | Lifted | Space/Enter | **Drop** (commits, emits `(dragDrop)`, focus follows the item) |
18
+ | Lifted | Escape | **Cancel** (no event, focus stays on item) |
19
19
 
20
20
  Arrow direction follows the list's `orientation` and respects RTL via `dir`. In
21
21
  `orientation="mixed"` every arrow key steps the lifted item linearly in DOM order.
@@ -24,6 +24,21 @@ Arrow direction follows the list's `orientation` and respects RTL via `dir`. In
24
24
 
25
25
  Keyboard lifting, stepping, dropping, and cancellation are announced via ARIA live regions. Override the default messages at any injector scope via `provideForDragDropDefaults` (see Announcement customisation below). Free-drag is pointer-only — there is no WAI-ARIA pattern for "reposition an element", so `[forFreeDrag]` owns no role or ARIA state; the consumer is responsible for keeping the moved element fully usable at its default position.
26
26
 
27
+ ### Focus after a keyboard drop
28
+
29
+ Applying the move in `(dragDrop)` destroys or re-inserts the lifted element, which would otherwise
30
+ leave focus on `<body>`. So after a **keyboard** drop whose lifted item held focus, `[forDropList]`
31
+ restores focus to the item at `currentIndex` in the target container on the next render — the same
32
+ element the user just placed, whether it stayed in this list or transferred to a connected one.
33
+
34
+ Two escape hatches:
35
+
36
+ - **Focus something yourself** inside the `(dragDrop)` handler (a status region, a toolbar, the next
37
+ row). The restore only fires when focus has already fallen to `<body>`, so whatever you focus wins.
38
+ - **Pointer drops are untouched** — focus is never moved after a mouse / touch / pen drop.
39
+
40
+ If your handler leaves the data unchanged, nothing is detached and focus simply stays on the item.
41
+
27
42
  ## Pointer dragging
28
43
 
29
44
  When a pointer drag starts, the dragged item stays in place and reflects
@@ -119,7 +134,8 @@ stays in the dragged item's source slot.
119
134
  ```
120
135
 
121
136
  `[liveSort]` has no visible effect without a `[forDragPlaceholder]` template, and has no effect
122
- on keyboard dragging.
137
+ on keyboard dragging. The drop index is resolved from the geometry measured at lift, so
138
+ `[liveSort]` never changes which index a pointer path commits — it only moves the placeholder.
123
139
 
124
140
  ### Boundary & axis lock
125
141
 
@@ -198,6 +214,10 @@ preview is destroyed promptly.
198
214
  happens to render as a single row or single column resolves identically to `"horizontal"` /
199
215
  `"vertical"`.
200
216
 
217
+ In a cross-list transfer each container resolves the drop index on **its own** `orientation` and
218
+ `dir`, so a vertical list can be connected to a horizontal one (or to one in the opposite writing
219
+ direction) and the pointer index lands on the target's axis.
220
+
201
221
  ```html
202
222
  <ul class="grid" forDropList orientation="mixed" (dragDrop)="onDrop($event)">
203
223
  @for (item of items(); track item.id) {
@@ -413,3 +433,7 @@ providers: [
413
433
  }),
414
434
  ];
415
435
  ```
436
+
437
+ `total` is the number of valid drop positions in the list being announced: the item count for a
438
+ same-list reorder, and one more than the item count for a transfer into a connected list (the
439
+ append gap counts).
@@ -1,7 +1,6 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { computed, InjectionToken, inject, signal, Injector, model, input, booleanAttribute, numberAttribute, linkedSignal, effect, afterNextRender, Directive, ElementRef, Injectable } from '@angular/core';
3
3
  import { compareDateOf, clampToBounds, Collection, createDefaults, IdGenerator, LiveAnnouncer, injectDateAdapter, injectTextDirection, adoptHostId, hostLabelledBy, registerHandle, hostAriaLabel, createFormatterCache, FOR_DATE_ADAPTER } from 'forty-cdk/core';
4
- export { FOR_DATE_ADAPTER, assertTimeCapable, injectDateAdapter } from 'forty-cdk/core';
5
4
 
6
5
  /**
7
6
  * Owns every `[min, max]` bounds question a `ForCalendar` asks: whole-month /