forty-cdk 0.31.0 → 0.32.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 (102) hide show
  1. package/calendar/README.md +2 -2
  2. package/combobox/README.md +15 -1
  3. package/context-menu/README.md +2 -2
  4. package/date-picker/README.md +13 -9
  5. package/drawer/README.md +34 -33
  6. package/fesm2022/forty-cdk-calendar.mjs +33 -8
  7. package/fesm2022/forty-cdk-calendar.mjs.map +1 -1
  8. package/fesm2022/forty-cdk-combobox.mjs +69 -10
  9. package/fesm2022/forty-cdk-combobox.mjs.map +1 -1
  10. package/fesm2022/forty-cdk-context-menu.mjs +8 -3
  11. package/fesm2022/forty-cdk-context-menu.mjs.map +1 -1
  12. package/fesm2022/forty-cdk-core-overlay.mjs +108 -13
  13. package/fesm2022/forty-cdk-core-overlay.mjs.map +1 -1
  14. package/fesm2022/forty-cdk-core.mjs +49 -3
  15. package/fesm2022/forty-cdk-core.mjs.map +1 -1
  16. package/fesm2022/forty-cdk-date-picker.mjs +34 -15
  17. package/fesm2022/forty-cdk-date-picker.mjs.map +1 -1
  18. package/fesm2022/forty-cdk-defaults.mjs.map +1 -1
  19. package/fesm2022/forty-cdk-dialog.mjs +12 -19
  20. package/fesm2022/forty-cdk-dialog.mjs.map +1 -1
  21. package/fesm2022/forty-cdk-drag-drop.mjs +12 -6
  22. package/fesm2022/forty-cdk-drag-drop.mjs.map +1 -1
  23. package/fesm2022/forty-cdk-drawer.mjs +134 -77
  24. package/fesm2022/forty-cdk-drawer.mjs.map +1 -1
  25. package/fesm2022/forty-cdk-hover-card.mjs +119 -17
  26. package/fesm2022/forty-cdk-hover-card.mjs.map +1 -1
  27. package/fesm2022/forty-cdk-listbox.mjs +182 -11
  28. package/fesm2022/forty-cdk-listbox.mjs.map +1 -1
  29. package/fesm2022/forty-cdk-menu.mjs +15 -5
  30. package/fesm2022/forty-cdk-menu.mjs.map +1 -1
  31. package/fesm2022/forty-cdk-menubar.mjs +29 -14
  32. package/fesm2022/forty-cdk-menubar.mjs.map +1 -1
  33. package/fesm2022/forty-cdk-number-input.mjs +44 -1
  34. package/fesm2022/forty-cdk-number-input.mjs.map +1 -1
  35. package/fesm2022/forty-cdk-otp-input.mjs +8 -1
  36. package/fesm2022/forty-cdk-otp-input.mjs.map +1 -1
  37. package/fesm2022/forty-cdk-select.mjs +10 -17
  38. package/fesm2022/forty-cdk-select.mjs.map +1 -1
  39. package/fesm2022/forty-cdk-stepper.mjs +25 -5
  40. package/fesm2022/forty-cdk-stepper.mjs.map +1 -1
  41. package/fesm2022/forty-cdk-table-virtualization.mjs +16 -11
  42. package/fesm2022/forty-cdk-table-virtualization.mjs.map +1 -1
  43. package/fesm2022/forty-cdk-table.mjs +34 -8
  44. package/fesm2022/forty-cdk-table.mjs.map +1 -1
  45. package/fesm2022/forty-cdk-tabs.mjs +0 -1
  46. package/fesm2022/forty-cdk-tabs.mjs.map +1 -1
  47. package/fesm2022/forty-cdk-time-picker.mjs +17 -0
  48. package/fesm2022/forty-cdk-time-picker.mjs.map +1 -1
  49. package/fesm2022/forty-cdk-toast.mjs +84 -16
  50. package/fesm2022/forty-cdk-toast.mjs.map +1 -1
  51. package/fesm2022/forty-cdk-tooltip.mjs +22 -11
  52. package/fesm2022/forty-cdk-tooltip.mjs.map +1 -1
  53. package/fesm2022/forty-cdk-tree.mjs +51 -5
  54. package/fesm2022/forty-cdk-tree.mjs.map +1 -1
  55. package/fesm2022/forty-cdk-virtual-reorder.mjs +24 -10
  56. package/fesm2022/forty-cdk-virtual-reorder.mjs.map +1 -1
  57. package/fesm2022/forty-cdk-virtualization.mjs +62 -5
  58. package/fesm2022/forty-cdk-virtualization.mjs.map +1 -1
  59. package/hover-card/README.md +17 -16
  60. package/input/README.md +1 -1
  61. package/listbox/README.md +121 -3
  62. package/menu/README.md +2 -1
  63. package/menubar/README.md +11 -11
  64. package/number-input/README.md +5 -5
  65. package/otp-input/README.md +3 -2
  66. package/package.json +1 -1
  67. package/select/README.md +3 -2
  68. package/stepper/README.md +12 -12
  69. package/table/README.md +2 -2
  70. package/tabs/README.md +7 -7
  71. package/time-picker/README.md +15 -9
  72. package/toast/README.md +9 -8
  73. package/tooltip/README.md +19 -17
  74. package/tree/README.md +3 -3
  75. package/types/forty-cdk-calendar.d.ts +26 -7
  76. package/types/forty-cdk-combobox.d.ts +32 -10
  77. package/types/forty-cdk-context-menu.d.ts +7 -2
  78. package/types/forty-cdk-core-overlay.d.ts +91 -17
  79. package/types/forty-cdk-core.d.ts +53 -5
  80. package/types/forty-cdk-date-picker.d.ts +14 -5
  81. package/types/forty-cdk-defaults.d.ts +4 -1
  82. package/types/forty-cdk-drag-drop.d.ts +10 -2
  83. package/types/forty-cdk-drawer.d.ts +16 -5
  84. package/types/forty-cdk-hover-card.d.ts +64 -7
  85. package/types/forty-cdk-listbox.d.ts +137 -12
  86. package/types/forty-cdk-menu.d.ts +14 -6
  87. package/types/forty-cdk-menubar.d.ts +8 -2
  88. package/types/forty-cdk-number-input.d.ts +10 -1
  89. package/types/forty-cdk-otp-input.d.ts +5 -1
  90. package/types/forty-cdk-select.d.ts +5 -8
  91. package/types/forty-cdk-stepper.d.ts +47 -12
  92. package/types/forty-cdk-table-virtualization.d.ts +3 -1
  93. package/types/forty-cdk-table.d.ts +13 -4
  94. package/types/forty-cdk-tabs.d.ts +3 -4
  95. package/types/forty-cdk-time-picker.d.ts +7 -1
  96. package/types/forty-cdk-toast.d.ts +14 -7
  97. package/types/forty-cdk-tooltip.d.ts +7 -4
  98. package/types/forty-cdk-tree.d.ts +10 -4
  99. package/types/forty-cdk-virtual-reorder.d.ts +15 -6
  100. package/types/forty-cdk-virtualization.d.ts +32 -3
  101. package/virtual-reorder/README.md +3 -1
  102. package/virtualization/README.md +15 -8
@@ -214,7 +214,7 @@ Click the heading button to cycle from day → month → year view. Click a mont
214
214
  | ------------------- | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
215
215
  | `value` | `model<D \| null>` | Two-way bindable selected date, or `null`. Used in `selectionMode="single"`. `(valueChange)` fires only on internal selection.<br>**Default:** `null` |
216
216
  | `selectionMode` | `input<'single' \| 'range'>` | `'single'` (default) keeps the single-date `value` flow. `'range'` switches to anchor → commit and exposes `range`.<br>**Default:** `'single'` |
217
- | `range` | `model<DateRange<D> \| null>` | Two-way bindable committed range. Only used in `selectionMode="range"`. `(rangeChange)` fires only on internal commits/clears.<br>**Default:** `null` |
217
+ | `range` | `model<DateRange<D> \| null>` | Two-way bindable committed range. Only used in `selectionMode="range"`. `(rangeChange)` fires only on internal commits.<br>**Default:** `null` |
218
218
  | `minRangeLength` | `input<number \| null>` | Minimum inclusive day count. A commit shorter than this is a no-op.<br>**Default:** `null` (no minimum) |
219
219
  | `maxRangeLength` | `input<number \| null>` | Maximum inclusive day count. A commit longer than this is a no-op.<br>**Default:** `null` (no maximum) |
220
220
  | `min` | `input<D \| null>` | Minimum selectable date (inclusive). Earlier dates are unavailable.<br>**Default:** `null` |
@@ -251,7 +251,7 @@ Set `selectionMode="range"` and bind `[(range)]` to get date-range selection. In
251
251
  </div>
252
252
  ```
253
253
 
254
- **Interaction model.** Click (or `Enter` / `Space`) a first cell to set the anchor; the grid enters selecting state. Click (or `Enter` / `Space`) a second cell **in either direction** to commit the range. Clicking before the anchor commits the inverted band `[click, anchor]` (matching the hover preview) rather than starting over. There is no separate "start over" gesture and no explicit Escape-to-cancel: once a range is committed, the next click begins a fresh anchor.
254
+ **Interaction model.** Click (or `Enter` / `Space`) a first cell to set the anchor; the grid enters selecting state. Click (or `Enter` / `Space`) a second cell **in either direction** to commit the range. Clicking before the anchor commits the inverted band `[click, anchor]` (matching the hover preview) rather than starting over. There is no separate "start over" gesture and no explicit Escape-to-cancel: once a range is committed, the next click begins a fresh anchor, and `range` keeps the committed range until the second click replaces it.
255
255
 
256
256
  **Keyboard in range mode.** `Enter` / `Space` on the focused cell sets the anchor on the first press and commits on the second (same key as single mode). While selecting, arrow / `Home` / `End` / `PageUp` / `PageDown` move the keyboard focus and update the preview cursor (the keyboard equivalent of pointer hover); moving before the anchor previews (and commits) the inverted band.
257
257
 
@@ -549,6 +549,15 @@ The `autocompleteMode` input mirrors the WAI-ARIA `aria-autocomplete` property:
549
549
 
550
550
  Inline completion preserves the user's typed prefix as unselected and selects the appended remainder, so the next keystroke replaces the selection (matching native browser autofill behavior). Backspace deletes the selection without re-completing, so the user can always shorten the query.
551
551
 
552
+ The completed text is a suggestion: `query()` keeps the typed prefix until the user accepts it, and accepting writes the full label into `query` (emitting `(queryChange)`). These gestures accept a pending completion:
553
+
554
+ - **Tab**, before the listbox closes and focus moves on.
555
+ - **Enter** when no option is activated (the listbox is closed, or open with nothing highlighted).
556
+ - A caret move that keeps the completed text: **ArrowLeft** / **ArrowRight**, and **Home** / **End** while the listbox is closed. While it is open, Home and End move the highlight instead and the completion stays pending.
557
+ - A **click** in the input, and **blur**.
558
+
559
+ Typing replaces the suggestion, Backspace removes it, and Escape on an open listbox closes it and restores the typed prefix. Accepting never opens the listbox, so a completion accepted on blur does not reopen a popup the same click dismissed.
560
+
552
561
  > **Pure `'inline'` needs a warm cache.** `'inline'` never opens the popup (per APG, `aria-autocomplete="inline"` has no listbox), so in the default `@if (open())` anatomy no `[forComboboxOption]` ever renders and the label cache starts cold. A first keystroke into a combobox that has never been opened completes against nothing; inline completion only works once the options have rendered at least once (the user opened the popup via ArrowDown or `[openOnFocus]`, warming the cache). If completion must work from the very first keystroke, use `'both'`, which opens the popup, so the options render and the cache warms. Leaving `[forComboboxContent]` permanently mounted instead is not a supported shape and warns in dev mode: mount **is** the open state for this surface, so it never runs `animate.enter` / `animate.leave`, and its dismissible layer stays active while closed.
553
562
 
554
563
  ## Dismiss events
@@ -707,6 +716,8 @@ readonly v = injectVirtualizer({
707
716
 
708
717
  This uses the library's own [`injectVirtualizer`](../virtualization/README.md) core: `v.virtualItems()` is the windowed slice, `v.totalSize()` the spacer height, `v.range()` feeds `[visibleRange]`, and `v.scrollToIndex(idx)` brings an absolute index into view. The scroll container belongs to the consumer's virtualizer, not the directive (here `[forComboboxContent]` is the scroll element).
709
718
 
719
+ `[totalCount]` is also the result count the message pieces read: `[forComboboxStatus]`'s `count()` reports it rather than the size of the rendered window, so `{{ status.count() }} results.` announces the full count once and stays put while the window scrolls, and `[forComboboxEmpty]` stays hidden while a window with results has not rendered yet.
720
+
710
721
  When `[totalCount]` is omitted, the directive falls back to `options().length` and behaves exactly as before: `aria-setsize` is left to the platform default and navigation never emits `(scrollToIndex)`.
711
722
 
712
723
  > **Disabled options off-screen.** The directive learns an option's `disabled` only when it's been rendered at least once. While the consumer can pre-mark disabled rows with their own filter (most apps do), arrow nav cannot skip an off-screen disabled option it has never seen: it will land on it, the option will mount, and the next arrow press skips. Mark disabled rows in the source array if this matters.
@@ -792,9 +803,12 @@ Focus stays in the input throughout: arrow keys move the listbox's _active desce
792
803
  | **Tab** _(open, no action)_ | Close the listbox and let Tab flow to the next focusable. |
793
804
  | **Tab / Shift+Tab** _(open, action present)_ | Move focus around the input↔actions ring without dismissing (see [Action items](#action-items)). |
794
805
  | **Backspace** _(empty input, multi only)_ | Focus the last chip; a second Backspace there removes it. |
806
+ | **ArrowLeft / ArrowRight** | Move the caret, accepting a pending inline completion. |
795
807
  | Printable keys | Update `query`. With `'inline'` / `'both'` autocomplete, complete the rest of the first match into the input as selected text. |
796
808
 
797
- Hovering an option also makes it the activedescendant, so mouse and keyboard intent stay synchronized.
809
+ With `'inline'` / `'both'` autocomplete, Tab, Enter with no option activated, and Home / End while closed also accept a pending completion (see [Autocomplete modes](#autocomplete-modes)).
810
+
811
+ Hovering an option also makes it the activedescendant, so mouse and keyboard intent stay synchronized. For a short window after the directive scrolls an option into view (arrow navigation, the auto-highlight seed after the list changes, and the reveal on open), a hover is ignored, so an option the scroll slides under a resting cursor cannot take the highlight.
798
812
 
799
813
  ## Accessibility
800
814
 
@@ -92,7 +92,7 @@ The same menu vocabulary the Dropdown Menu exposes, anchored to the pointer on r
92
92
  | `dir` | `input<string>` | Writing direction. In RTL the swap is automatic: ArrowLeft opens submenus and ArrowRight closes them. Inherited by every nested `[forMenuSub]` underneath unless overridden.<br>**Default:** `'ltr'` |
93
93
  | `disabled` | `input<boolean>` | When `true`, the contextmenu event falls through to the native browser menu.<br>**Default:** `false` |
94
94
  | `dismissible` | `input<boolean>` | When `false`, Escape and outside interactions don't close.<br>**Default:** `true` |
95
- | `returnFocus` | `input<boolean>` | When `true`, focus returns to the trigger element on close.<br>**Default:** `true` |
95
+ | `returnFocus` | `input<boolean>` | When `true`, focus returns on close to the trigger element, or to the focused element inside it that a keyboard activation started from.<br>**Default:** `true` |
96
96
  | `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` |
97
97
  | `escapeKeyDown` | `output<VetoableNativeEvent<KeyboardEvent>>` | Output. Escape pressed while the menu is the topmost dismissible layer.<br>**Default:** — |
98
98
  | `pointerDownOutside` | `output<VetoableNativeEvent<PointerEvent>>` | Output. Pointer-down on a target outside content + trigger.<br>**Default:** — |
@@ -135,7 +135,7 @@ forty-cdk ships no styles: put your own class on each piece and key your CSS off
135
135
  ## Behavior notes
136
136
 
137
137
  - **Trigger is NOT exempt** from outside-pointer / outside-focus checks. Unlike DropdownMenu (where the trigger button toggles via its own click handler), the context-menu region is treated like any other "outside" element: a left-click on the region while the menu is open closes it. Right-clicking again immediately reopens at the new position. This is a full close → open cycle, not an in-place reposition: re-right-clicking while the menu is already open tears the surface down and rebuilds it (so any `animate.enter` / `animate.leave` replays and focus resets). Keep enter/leave animations cheap, or gate expensive ones, since a user can fire this rapidly. The directive deliberately exempts nothing, so there is no smooth reposition path to attach to.
138
- - **Virtual anchor.** Right-click captures a 0×0 rect at the pointer location. `Shift+F10` and `ContextMenu` snapshot the bounding rect of the focused element (or the trigger if focus is on it directly), so the menu floats off the element under attention. Both forms feed floating-ui's `flip` and `shift` middleware, so corners and screen edges work without special-casing.
138
+ - **Virtual anchor.** Right-click captures a 0×0 rect at the pointer location. `Shift+F10` and `ContextMenu` snapshot the bounding rect of the focused element (or the trigger if focus is on it directly), so the menu floats off the element under attention. Closing a keyboard-opened menu returns focus to that same element, so a row in a roving-tabindex list keeps its position; when a menu action removed it, focus falls back to the region. Both forms feed floating-ui's `flip` and `shift` middleware, so corners and screen edges work without special-casing.
139
139
  - **Keyboard activators only fire while focus is inside the trigger.** Keyboard events dispatch to the focused element, so `Shift+F10` / `ContextMenu` anywhere outside the trigger goes to the browser default. The trigger is focusable by default (host-bound `tabindex="-1"`), so this works out of the box and focus can return to it programmatically when the menu closes. Your own `tabindex` wins over that default: use `tabindex="0"` if you want the region itself reachable via Tab.
140
140
  - **Native menu suppressed.** The trigger calls `event.preventDefault()` on `contextmenu` and on the keyboard activators. Set `disabled` to let the browser's native menu surface for that region.
141
141
  - **An open that renders nothing closes again.** When a right-click, `Shift+F10`, the `ContextMenu` key or a long-press opens a menu whose template renders no `[forMenuContent]`, the trigger closes it after the next render with reason `'programmatic'`, and dev mode logs `FORCDK-CONTEXT-MENU-002` once. The native menu cannot come back for that gesture, because it was already suppressed, so bind `[disabled]` to the same condition that renders the content: `[disabled]="!hasActions(col)"` beside `@if (hasActions(col))`.
@@ -48,7 +48,7 @@ All date math and formatting go through a `DateAdapter<D>`, shared with `ForCale
48
48
  </div>
49
49
  ```
50
50
 
51
- Bind the projected `[forCalendar]` to the picker: `[(value)]` to the same date signal, and forward `[min]` / `[max]` / `[isDateUnavailable]` from the picker's accessors (`#picker="forDatePicker"`). The picker observes the calendar's selection through a `contentChild` query and never mutates the calendar, so picking a date sets the value, flips `touched`, and (when `closeOnSelect` is on) closes the surface.
51
+ Bind the projected `[forCalendar]` to the picker: `[(value)]` to the same date signal, and forward `[min]` / `[max]` / `[isDateUnavailable]` from the picker's accessors (`#picker="forDatePicker"`). The picker observes the calendar's selection through a `contentChild` query and never mutates the calendar, so picking a date sets the value, flips `touched`, and (when `closeOnSelect` is on) closes the surface. The calendar takes the picker's `readonly` and `disabled` without a binding, so a read-only or disabled picker lets no pick through and paints no selection, whichever way the calendar is bound.
52
52
 
53
53
  Presence in the DOM is yours: wrap `[forDatePickerContent]` in `@if (picker.open())`, and `animate.enter` / `animate.leave` drive its transitions.
54
54
 
@@ -191,7 +191,7 @@ With `granularity="minute"` and a time-capable adapter the picker becomes a date
191
191
 
192
192
  ### Range selection
193
193
 
194
- Open the picker and click a first day: the trigger keeps its placeholder, because the value `[formField]` reads stays `null` until a second click commits the range. Close the panel with only one end picked and the required error appears. [`ForDateRangePicker`](#range-selection--fordaterangepicker) documents the root, its bounds and native submission.
194
+ Open the picker and click a first day: the trigger keeps its placeholder, because the value `[formField]` reads does not change until a second click commits the range. Close the panel with only one end picked and the required error appears. [`ForDateRangePicker`](#range-selection--fordaterangepicker) documents the root, its bounds and native submission.
195
195
 
196
196
  ## API
197
197
 
@@ -231,6 +231,9 @@ Plus the shared `FormUiControl` inputs from the base (`disabled`, `readonly`, `r
231
231
  | `[forDatePicker]` | `data-state` | `open` \| `closed` |
232
232
  | `[forDatePicker]` | `data-disabled` | present \| absent |
233
233
  | `[forDatePicker]` | `data-readonly` | present \| absent |
234
+ | `[forDateRangePicker]` | `data-state` | `open` \| `closed` |
235
+ | `[forDateRangePicker]` | `data-disabled` | present \| absent |
236
+ | `[forDateRangePicker]` | `data-readonly` | present \| absent |
234
237
  | `[forDatePickerTrigger]` | `data-state` | `open` \| `closed` |
235
238
  | `[forDatePickerTrigger]` | `data-disabled` | present \| absent |
236
239
  | `[forDatePickerTrigger]` | `data-readonly` | present \| absent |
@@ -383,7 +386,7 @@ The anatomy is explicit, so a date field placed inside the surface of a trigger-
383
386
 
384
387
  For date-range selection use the dedicated `ForDateRangePicker` root (selector `[forDateRangePicker]`). It is the root **and** the form value, implementing `FormValueControl<DateRange<D> | null>`, so the committed range auto-wires with `[formField]` exactly like any other control.
385
388
 
386
- It reuses the same pieces (`[forDatePickerTrigger]`, `[forDatePickerContent]`, `[forDatePickerValue]`, `[forDatePickerAnchor]`) through a shared base, and provides `FOR_DATE_PICKER_CONTEXT` so they resolve under it. Project a `[forCalendar]` in `selectionMode="range"` and bind its range to the picker's `value`; the two-click anchor → commit flow keeps `value` `null` until both endpoints are chosen (the form never sees a half-entered range), and `start <= end` is an invariant. Range is day-granular (no time composition).
389
+ It reuses the same pieces (`[forDatePickerTrigger]`, `[forDatePickerContent]`, `[forDatePickerValue]`, `[forDatePickerAnchor]`) through a shared base, and provides `FOR_DATE_PICKER_CONTEXT` so they resolve under it. Project a `[forCalendar]` in `selectionMode="range"` and bind its range to the picker's `value`; the two-click anchor → commit flow leaves `value` unchanged until both endpoints are chosen, so the form never sees a half-entered range, and abandoning a new selection with Escape or an outside click keeps the range committed before it. `start <= end` is an invariant. Range is day-granular (no time composition).
387
390
 
388
391
  <!-- snippet: fragment -->
389
392
 
@@ -428,7 +431,7 @@ readonly booking = form(this.model, (p) => required(p.stay));
428
431
  ```
429
432
 
430
433
  - **Form value.** The committed `DateRange<D> | null` is the `value` model. `null` is the empty state. Pair it with `required(p.stay)` so `invalid()` flips when the form demands a range and none is committed. `touched` fires on commit and on close, exactly like the single-date picker.
431
- - **Validity.** `start <= end` is guaranteed by construction and is never an error. Forward `minDate` / `maxDate` to the calendar's `[min]` / `[max]`, and `minRangeLength` / `maxRangeLength` to the calendar's `[minRangeLength]` / `[maxRangeLength]` (a too-short / too-long range is rejected as a no-op by the calendar's two-click flow).
434
+ - **Validity.** `start <= end` is guaranteed by construction and is never an error. Forward `minDate` / `maxDate` to the calendar's `[min]` / `[max]` so out-of-range days are disabled in the grid; a range picked in a calendar without them is clamped into `[minDate, maxDate]` on commit. Forward `minRangeLength` / `maxRangeLength` to the calendar's `[minRangeLength]` / `[maxRangeLength]` (a too-short / too-long range is rejected as a no-op by the calendar's two-click flow).
432
435
  - **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.
433
436
  - **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.
434
437
 
@@ -436,12 +439,13 @@ Defaults are configured with `provideForDateRangePickerDefaults` (`side` / `alig
436
439
 
437
440
  ## Keyboard
438
441
 
439
- | Key | Behavior |
440
- | ---------------------------- | ------------------------------------------------------------------------- |
441
- | **Enter / Space** on trigger | Open the surface (native button activation). |
442
- | **Escape** | Dismiss the surface and return focus to the trigger (when `dismissible`). |
442
+ | Key | Behavior |
443
+ | -------------------------------------------------- | ------------------------------------------------------------------------- |
444
+ | **Enter / Space** on trigger | Open the surface (native button activation). |
445
+ | **ArrowDown / Alt+ArrowDown / ArrowUp** on trigger | Open the surface and move focus to the calendar. |
446
+ | **Escape** | Dismiss the surface and return focus to the trigger (when `dismissible`). |
443
447
 
444
- Inside the surface, the projected `ForCalendar` owns the full grid keyboard map (arrows / `Home` / `End` / `PageUp` / `PageDown` / `Enter` / `Space`). On open, focus lands on the calendar's focused cell (`value ?? today`) in non-modal mode, or the first focusable element in modal mode.
448
+ Inside the surface, the projected `ForCalendar` owns the full grid keyboard map (arrows / `Home` / `End` / `PageUp` / `PageDown` / `Enter` / `Space`). On open, focus lands on the calendar's focused cell (`value ?? today`, with today clamped into the calendar's `[min, max]`) in non-modal mode, or the first focusable element in modal mode.
445
449
 
446
450
  ## Accessibility
447
451
 
package/drawer/README.md CHANGED
@@ -153,7 +153,7 @@ class DemoHost {
153
153
 
154
154
  `injectDrawerData<T>()` is typed `T | null`: the manager provides `null` when `open()` is called without `data`, so guard (`data?.message`) before dereferencing the payload. `await ref.closed` resolves `{ reason, result }`, whose `reason` (a `ForDrawerCloseReason`) tells apart an imperative `close()` (`'programmatic'`) from Escape / backdrop / outside / swipe / close-button dismissals.
155
155
 
156
- Drawers opened by the manager join the same `ForDrawerStack` as declarative ones, so mixed stacking (a programmatic drawer over a declarative parent, or vice versa) reflects correct `data-depth` / `data-state-nested` and routes Escape through the LIFO dismissible layer.
156
+ Drawers opened by the manager share the LIFO dismissible layer with declarative ones, so Escape closes the topmost drawer first whichever API opened it. Nesting is resolved from where a drawer is declared, not from the order drawers open in: a declarative `[forDrawer]` inside a programmatic drawer's component is its child (`data-depth="1"`, and the programmatic parent reflects `data-state-nested`), but a drawer the manager opens over a declarative one is a root, so it reflects `data-depth="0"` and its declarative neighbour gets no `data-state-nested`.
157
157
 
158
158
  `ForDrawerManager.openCount` is a `Signal<number>` of the drawers it has open, counting a closed one until its exit animation finishes. `closeAll(result?)` closes every one of them, topmost first, with reason `'programmatic'`: each `ref.closed` resolves as it does for `ref.close()`, exit animations still play, and focus ends where the bottom drawer returns it.
159
159
 
@@ -359,39 +359,39 @@ Press the button: the manager opens the confirmation as a bottom drawer, and the
359
359
 
360
360
  ### `ForDrawer`
361
361
 
362
- | Property | Type | Description |
363
- | --------------------------- | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
364
- | `side` | `'top' \| 'right' \| 'bottom' \| 'left'` | Anchored edge. Drives swipe direction and `data-side`.<br>**Default:** `'bottom'` |
365
- | `modal` | `boolean` | `aria-modal`, scroll lock, focus trap, inert siblings.<br>**Default:** `true` |
366
- | `dismissible` | `boolean` | Whether Escape / backdrop / outside / swipe close.<br>**Default:** `true` |
367
- | `alert` | `boolean` | `role="alertdialog"`.<br>**Default:** `false` |
368
- | `returnFocus` | `boolean` | Restore focus on close.<br>**Default:** `true` |
369
- | `initialFocus` | `'first' \| 'container'` | **Default:** `'first'` |
370
- | `ariaLabel` | `string \| null` | Use when no visible title is rendered.<br>**Default:** `null` |
371
- | `animateEnter` | `string` | CSS class applied on mount (via `animate.enter`) to play an enter animation.<br>**Default:** — |
372
- | `animateLeave` | `string` | CSS class applied on close; the host stays mounted until its animation finishes, then tears down.<br>**Default:** — |
373
- | `autoFocusOnOpen` | `(e: VetoableEvent) => void` \| `undefined` | `event.preventDefault()` skips the imperative focus move.<br>**Default:** — |
374
- | `autoFocusOnClose` | `(e: VetoableEvent) => void` \| `undefined` | Fires on every close path regardless of mode. In non-modal mode the directive doesn't move focus, so the veto is informational; in modal mode `event.preventDefault()` skips return-focus.<br>**Default:** — |
375
- | `swipeToDismiss` | `boolean` | Disabled automatically under `prefers-reduced-motion: reduce`.<br>**Default:** `true` |
376
- | `closeThreshold` | `number` | Fraction past which a release dismisses, measured against the full dimension without `snapPoints` and against the lowest snap's extent with them.<br>**Default:** `0.25` |
377
- | `handleOnly` | `boolean` | Swipe arms only on the registered `[forDrawerHandle]`.<br>**Default:** `false` |
378
- | `snapPoints` | `ReadonlyArray<ForDrawerSnapPoint>` | `number ∈ [0,1]` \| `'NN%'` \| `'NNpx'`. Strictly increasing.<br>**Default:** — |
379
- | `activeSnapPoint` | `ModelSignal<ForDrawerSnapPoint \| null>` | Two-way bindable. Initialised to `snapPoints[0]` on mount when null.<br>**Default:** `null` |
380
- | `fadeFromIndex` | `number` | Backdrop reflects `data-fade-from-active` once active >= this index.<br>**Default:** — |
381
- | `scaleBackground` | `boolean` | Asks `[forDrawerWrapper]` to scale + translate behind the drawer.<br>**Default:** `false` |
382
- | `setBackgroundColorOnScale` | `boolean` | Paints `<body>` to mask the gap between scaled wrapper and viewport edge.<br>**Default:** `true` |
383
- | `dismiss` | `OutputEmitterRef<ForDrawerCloseReason>` | Output. Wire to `(dismiss)="open.set(false)"`.<br>**Default:** — |
384
- | `escapeKeyDown` | `OutputEmitterRef<VetoableNativeEvent<KeyboardEvent>>` | Output. `preventDefault()` suppresses auto-close.<br>**Default:** — |
385
- | `pointerDownOutside` | `OutputEmitterRef<VetoableNativeEvent<PointerEvent>>` | Output. `preventDefault()` suppresses auto-close.<br>**Default:** — |
386
- | `focusOutside` | `OutputEmitterRef<VetoableNativeEvent<FocusEvent>>` | Output. `preventDefault()` suppresses auto-close.<br>**Default:** — |
387
- | `interactOutside` | `OutputEmitterRef<VetoableNativeEvent<PointerEvent \| FocusEvent>>` | Output. Composite, vetoed by either specific event.<br>**Default:** — |
388
- | `swipeStart` | `OutputEmitterRef<ForDrawerSwipeEvent>` | Output. Fires once on the arming pointer move; `progress` is `0`.<br>**Default:** — |
389
- | `swipeMove` | `OutputEmitterRef<ForDrawerSwipeEvent>` | Output. Streams `progress` ∈ [0,1] and the originating `PointerEvent`.<br>**Default:** — |
390
- | `swipeEnd` | `OutputEmitterRef<ForDrawerSwipeEndEvent>` | Output. `willClose`, `nextSnapPoint`. Directive already updated state.<br>**Default:** — |
391
- | `swipeCancel` | `OutputEmitterRef<ForDrawerSwipeEvent>` | Output. `pointercancel` or mid-gesture direction abort; the surface springs back.<br>**Default:** — |
362
+ | Property | Type | Description |
363
+ | --------------------------- | ------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
364
+ | `side` | `'top' \| 'right' \| 'bottom' \| 'left'` | Anchored edge. Drives swipe direction and `data-side`.<br>**Default:** `'bottom'` |
365
+ | `modal` | `boolean` | `aria-modal`, scroll lock, focus trap, inert siblings.<br>**Default:** `true` |
366
+ | `dismissible` | `boolean` | Whether Escape / backdrop / outside / swipe close. When `false`, no swipe dismisses; `snapPoints` still drag between snaps.<br>**Default:** `true` |
367
+ | `alert` | `boolean` | `role="alertdialog"`.<br>**Default:** `false` |
368
+ | `returnFocus` | `boolean` | Restore focus on close.<br>**Default:** `true` |
369
+ | `initialFocus` | `'first' \| 'container'` | **Default:** `'first'` |
370
+ | `ariaLabel` | `string \| null` | Use when no visible title is rendered.<br>**Default:** `null` |
371
+ | `autoFocusOnOpen` | `(e: VetoableEvent) => void` \| `undefined` | `event.preventDefault()` skips the imperative focus move.<br>**Default:** — |
372
+ | `autoFocusOnClose` | `(e: VetoableEvent) => void` \| `undefined` | Fires on every close path regardless of mode. In non-modal mode the directive doesn't move focus, so the veto is informational; in modal mode `event.preventDefault()` skips return-focus.<br>**Default:** — |
373
+ | `swipeToDismiss` | `boolean` | Whether a swipe toward the anchored edge dismisses. When `false`, `snapPoints` still drag between snaps and stop at the lowest one. No drag arms under `prefers-reduced-motion: reduce`.<br>**Default:** `true` |
374
+ | `closeThreshold` | `number` | Fraction past which a release dismisses, measured against the full dimension without `snapPoints` and against the lowest snap's extent with them.<br>**Default:** `0.25` |
375
+ | `handleOnly` | `boolean` | Swipe arms only on the registered `[forDrawerHandle]`.<br>**Default:** `false` |
376
+ | `snapPoints` | `ReadonlyArray<ForDrawerSnapPoint>` | `number ∈ [0,1]` \| `'NN%'` \| `'NNpx'`. Strictly increasing.<br>**Default:** — |
377
+ | `activeSnapPoint` | `ModelSignal<ForDrawerSnapPoint \| null>` | Two-way bindable. Initialised to `snapPoints[0]` on mount when null.<br>**Default:** `null` |
378
+ | `fadeFromIndex` | `number` | Backdrop reflects `data-fade-from-active` once active >= this index.<br>**Default:** — |
379
+ | `scaleBackground` | `boolean` | Asks `[forDrawerWrapper]` to scale + translate behind the drawer.<br>**Default:** `false` |
380
+ | `setBackgroundColorOnScale` | `boolean` | Paints `<body>` to mask the gap between scaled wrapper and viewport edge.<br>**Default:** `true` |
381
+ | `dismiss` | `OutputEmitterRef<ForDrawerCloseReason>` | Output. Wire to `(dismiss)="open.set(false)"`.<br>**Default:** — |
382
+ | `escapeKeyDown` | `OutputEmitterRef<VetoableNativeEvent<KeyboardEvent>>` | Output. `preventDefault()` suppresses auto-close.<br>**Default:** — |
383
+ | `pointerDownOutside` | `OutputEmitterRef<VetoableNativeEvent<PointerEvent>>` | Output. `preventDefault()` suppresses auto-close.<br>**Default:** — |
384
+ | `focusOutside` | `OutputEmitterRef<VetoableNativeEvent<FocusEvent>>` | Output. `preventDefault()` suppresses auto-close.<br>**Default:** — |
385
+ | `interactOutside` | `OutputEmitterRef<VetoableNativeEvent<PointerEvent \| FocusEvent>>` | Output. Composite, vetoed by either specific event.<br>**Default:** — |
386
+ | `swipeStart` | `OutputEmitterRef<ForDrawerSwipeEvent>` | Output. Fires once on the arming pointer move; `progress` is `0`.<br>**Default:** — |
387
+ | `swipeMove` | `OutputEmitterRef<ForDrawerSwipeEvent>` | Output. Streams `progress` ∈ [0,1] and the originating `PointerEvent`.<br>**Default:** — |
388
+ | `swipeEnd` | `OutputEmitterRef<ForDrawerSwipeEndEvent>` | Output. `willClose`, `nextSnapPoint`. Directive already updated state.<br>**Default:** — |
389
+ | `swipeCancel` | `OutputEmitterRef<ForDrawerSwipeEvent>` | Output. `pointercancel` or mid-gesture direction abort; the surface springs back.<br>**Default:** — |
392
390
 
393
391
  `ForDrawerCloseReason`: `'escape' | 'backdrop' | 'pointerDownOutside' | 'focusOutside' | 'closeButton' | 'swipe' | 'programmatic'`.
394
392
 
393
+ Enter and exit animations are not inputs. On a declarative drawer, put `animate.enter` / `animate.leave` on the `[forDrawer]` host inside its `@if`; on a programmatic one, pass `animateEnter` / `animateLeave` to [`ForDrawerManager.open()`](#programmatic--fordrawermanageropen).
394
+
395
395
  > **The declarative and imperative surfaces spell this differently, on purpose.** The output is `(dismiss)`, because an output named `close` would collide with the native DOM event and break any wrapper re-exposing it through `hostDirectives`. Nothing else changes name: the imperative handle method is `ForDrawerRef.close()`, the directive selector is `[forDrawerClose]`, and the payload type is `ForDrawerCloseReason`.
396
396
 
397
397
  | Data attribute | Values |
@@ -444,7 +444,7 @@ Three accepted shapes:
444
444
  - `'NN%'`: equivalent to a fraction (`'50%' === 0.5`).
445
445
  - `'NNpx'`: absolute pixel size measured from the anchored edge.
446
446
 
447
- Pass them in **strictly increasing** order (closest-to-edge first); the directive throws `FORCDK-DRAWER-009` otherwise. Mixed units (`'200px'` next to `0.5`) can only be ordered against the live drawer size, so they are re-checked on first measurement and fail with `FORCDK-DRAWER-010`, which names the offending point and the dimension it resolved against. `fadeFromIndex` must be a valid index into `snapPoints`.
447
+ Pass them in **strictly increasing** order (closest-to-edge first); in dev mode the directive throws `FORCDK-DRAWER-009` otherwise. Mixed units (`'200px'` next to `0.5`) can only be ordered against the live drawer size, so they are re-checked on first measurement and fail with `FORCDK-DRAWER-010`, which names the offending point and the dimension it resolved against. `fadeFromIndex` must be a valid index into `snapPoints`.
448
448
 
449
449
  ```html
450
450
  <div
@@ -514,10 +514,11 @@ For a seamless release, transition **both** `translate` and your snap-position p
514
514
 
515
515
  - Pointer drag toward the anchored edge translates the surface and resolves to the nearest snap (or a dismiss) on release.
516
516
  - With `snapPoints`, the drag is bidirectional: a drag **away** from the anchored edge grows the surface toward a larger snap (bounded by the largest snap), and a drag toward the edge shrinks it / dismisses past the lowest one. Without `snapPoints` the gesture is one-way (toward the edge to dismiss).
517
+ - Dismissal and dragging are separate. With `swipeToDismiss` or `dismissible` set to `false`, a drawer with `snapPoints` still drags between them and stops at the lowest snap, and `(swipeEnd)` reports `willClose: false`; a drawer without `snapPoints` arms no drag at all.
517
518
  - `closeThreshold` (default `0.25`) is the fraction past which a release from the lowest snap dismisses. It is measured against that snap's own extent (not the full dimension), so a small "peek" snap stays dismissible without dragging it off-screen.
518
519
  - `handleOnly: true` confines the gesture to a registered `[forDrawerHandle]`, leaving the rest of the surface free for content scroll.
519
520
  - Gestures starting inside a scrollable element that hasn't reached its edge are NOT treated as swipes (the helper defers to inner scroll).
520
- - **`prefers-reduced-motion: reduce`** disables the swipe listener entirely. Escape, backdrop, outside-pointer, and close button continue to work.
521
+ - **`prefers-reduced-motion: reduce`** disables the drag entirely, snap dragging included. Escape, backdrop, outside-pointer, and close button continue to work.
521
522
 
522
523
  ## Scale background
523
524
 
@@ -1,6 +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 } from '@angular/core';
3
- import { compareDateOf, clampToBounds, orphanContextError, Collection, IdGenerator, LiveAnnouncer, injectDateAdapter, injectTextDirection, adoptHostId, hostLabelledBy, registerHandle, hostButtonType, hostAriaLabel } from 'forty-cdk/core';
3
+ import { compareDateOf, clampToBounds, orphanContextError, Collection, IdGenerator, LiveAnnouncer, FOR_CALENDAR_HOST, injectDateAdapter, injectTextDirection, adoptHostId, hostLabelledBy, registerHandle, hostButtonType, hostAriaLabel } from 'forty-cdk/core';
4
4
  import { FOR_CALENDAR_DEFAULTS } from 'forty-cdk/defaults';
5
5
  export { FOR_CALENDAR_DEFAULTS, provideForCalendarDefaults } from 'forty-cdk/defaults';
6
6
  export { NativeDateAdapter, provideNativeDateAdapter } from 'forty-cdk/date-adapter';
@@ -660,11 +660,11 @@ class CalendarRangeSelection {
660
660
 
661
661
 
662
662
 
663
+
663
664
  select(date) {
664
665
  const adapter = this.#host.adapter;
665
666
  const anchor = this.#anchor();
666
667
  if (anchor === null) {
667
- this.#host.range.set(null);
668
668
  this.#anchor.set(date);
669
669
  return true;
670
670
  }
@@ -846,6 +846,7 @@ class ForCalendar {
846
846
  #idGen = inject(IdGenerator);
847
847
  #injector = inject(Injector);
848
848
  #announcer = inject(LiveAnnouncer);
849
+ #pickerHost = inject(FOR_CALENDAR_HOST, { optional: true });
849
850
 
850
851
  adapter = injectDateAdapter('ForCalendar', { scope: 'calendar' });
851
852
 
@@ -882,9 +883,27 @@ class ForCalendar {
882
883
  }, /* @ts-ignore */
883
884
  ...(ngDevMode ? [{ debugName: "dateLabel" }] : /* istanbul ignore next */ []));
884
885
 
885
- disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
886
886
 
887
- readonly = input(false, { ...(ngDevMode ? { debugName: "readonly" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
887
+
888
+
889
+ disabledInput = input(false, { ...(ngDevMode ? { debugName: "disabledInput" } : /* istanbul ignore next */ {}), transform: booleanAttribute, alias: 'disabled' });
890
+
891
+
892
+
893
+
894
+ readonlyInput = input(false, { ...(ngDevMode ? { debugName: "readonlyInput" } : /* istanbul ignore next */ {}), transform: booleanAttribute, alias: 'readonly' });
895
+
896
+
897
+
898
+
899
+ disabled = computed(() => this.disabledInput() || (this.#pickerHost?.effectiveDisabled() ?? false), /* @ts-ignore */
900
+ ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
901
+
902
+
903
+
904
+
905
+ readonly = computed(() => this.readonlyInput() || (this.#pickerHost?.readonly() ?? false), /* @ts-ignore */
906
+ ...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []));
888
907
 
889
908
 
890
909
 
@@ -954,7 +973,10 @@ class ForCalendar {
954
973
  ...(ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []));
955
974
  #initialToday = this.adapter.today();
956
975
 
957
- focusedDate = linkedSignal(() => this.value() ?? this.range()?.start ?? this.#initialToday, /* @ts-ignore */
976
+
977
+
978
+
979
+ focusedDate = linkedSignal(() => this.#seedDate(), /* @ts-ignore */
958
980
  ...(ngDevMode ? [{ debugName: "focusedDate" }] : /* istanbul ignore next */ []));
959
981
  #bounds = new CalendarBounds({
960
982
  adapter: this.adapter,
@@ -988,7 +1010,7 @@ class ForCalendar {
988
1010
  announce: (label) => this.#announcer.announce(label, 'polite'),
989
1011
  scheduleFocus: (fn) => this.#scheduleFocus(fn),
990
1012
  focusDayCell: (target) => this.#focusDayCell(target),
991
- }, this.value() ?? this.range()?.start ?? this.#initialToday);
1013
+ }, this.#seedDate());
992
1014
  #dayNav = new CalendarDayNavigator({
993
1015
  ...this.#subGridHost(),
994
1016
  visibleMonth: () => this.visibleMonth(),
@@ -1014,6 +1036,9 @@ class ForCalendar {
1014
1036
  month: this.#monthNav,
1015
1037
  year: this.#yearNav,
1016
1038
  };
1039
+ #seedDate() {
1040
+ return this.value() ?? this.range()?.start ?? this.#bounds.clamp(this.#initialToday);
1041
+ }
1017
1042
  #strategyFor(view) {
1018
1043
  return this.#strategies[view];
1019
1044
  }
@@ -1320,7 +1345,7 @@ class ForCalendar {
1320
1345
  afterNextRender(() => this.#dayNav.focusCell(target), { injector: this.#injector });
1321
1346
  }
1322
1347
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForCalendar, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1323
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: ForCalendar, isStandalone: true, selector: "[forCalendar]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, isDateUnavailable: { classPropertyName: "isDateUnavailable", publicName: "isDateUnavailable", isSignal: true, isRequired: false, transformFunction: null }, dateLabel: { classPropertyName: "dateLabel", publicName: "dateLabel", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: false, transformFunction: null }, yearBlockSize: { classPropertyName: "yearBlockSize", publicName: "yearBlockSize", isSignal: true, isRequired: false, transformFunction: null }, range: { classPropertyName: "range", publicName: "range", isSignal: true, isRequired: false, transformFunction: null }, minRangeLength: { classPropertyName: "minRangeLength", publicName: "minRangeLength", isSignal: true, isRequired: false, transformFunction: null }, maxRangeLength: { classPropertyName: "maxRangeLength", publicName: "maxRangeLength", isSignal: true, isRequired: false, transformFunction: null }, firstDayOfWeek: { classPropertyName: "firstDayOfWeek", publicName: "firstDayOfWeek", isSignal: true, isRequired: false, transformFunction: null }, _dirInput: { classPropertyName: "_dirInput", publicName: "dir", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", view: "viewChange", range: "rangeChange" }, host: { properties: { "attr.dir": "dir()", "attr.data-disabled": "disabled() ? \"\" : null", "attr.data-readonly": "readonly() ? \"\" : null", "attr.data-view": "view()" } }, providers: [{ provide: FOR_CALENDAR_CONTEXT, useExisting: ForCalendar }], exportAs: ["forCalendar"], ngImport: i0 });
1348
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: ForCalendar, isStandalone: true, selector: "[forCalendar]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, isDateUnavailable: { classPropertyName: "isDateUnavailable", publicName: "isDateUnavailable", isSignal: true, isRequired: false, transformFunction: null }, dateLabel: { classPropertyName: "dateLabel", publicName: "dateLabel", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonlyInput: { classPropertyName: "readonlyInput", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: false, transformFunction: null }, yearBlockSize: { classPropertyName: "yearBlockSize", publicName: "yearBlockSize", isSignal: true, isRequired: false, transformFunction: null }, range: { classPropertyName: "range", publicName: "range", isSignal: true, isRequired: false, transformFunction: null }, minRangeLength: { classPropertyName: "minRangeLength", publicName: "minRangeLength", isSignal: true, isRequired: false, transformFunction: null }, maxRangeLength: { classPropertyName: "maxRangeLength", publicName: "maxRangeLength", isSignal: true, isRequired: false, transformFunction: null }, firstDayOfWeek: { classPropertyName: "firstDayOfWeek", publicName: "firstDayOfWeek", isSignal: true, isRequired: false, transformFunction: null }, _dirInput: { classPropertyName: "_dirInput", publicName: "dir", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", view: "viewChange", range: "rangeChange" }, host: { properties: { "attr.dir": "dir()", "attr.data-disabled": "disabled() ? \"\" : null", "attr.data-readonly": "readonly() ? \"\" : null", "attr.data-view": "view()" } }, providers: [{ provide: FOR_CALENDAR_CONTEXT, useExisting: ForCalendar }], exportAs: ["forCalendar"], ngImport: i0 });
1324
1349
  }
1325
1350
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForCalendar, decorators: [{
1326
1351
  type: Directive,
@@ -1335,7 +1360,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
1335
1360
  },
1336
1361
  providers: [{ provide: FOR_CALENDAR_CONTEXT, useExisting: ForCalendar }],
1337
1362
  }]
1338
- }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], isDateUnavailable: [{ type: i0.Input, args: [{ isSignal: true, alias: "isDateUnavailable", required: false }] }], dateLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateLabel", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], selectionMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionMode", required: false }] }], view: [{ type: i0.Input, args: [{ isSignal: true, alias: "view", required: false }] }, { type: i0.Output, args: ["viewChange"] }], yearBlockSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "yearBlockSize", required: false }] }], range: [{ type: i0.Input, args: [{ isSignal: true, alias: "range", required: false }] }, { type: i0.Output, args: ["rangeChange"] }], minRangeLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "minRangeLength", required: false }] }], maxRangeLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxRangeLength", required: false }] }], firstDayOfWeek: [{ type: i0.Input, args: [{ isSignal: true, alias: "firstDayOfWeek", required: false }] }], _dirInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "dir", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }] } });
1363
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], isDateUnavailable: [{ type: i0.Input, args: [{ isSignal: true, alias: "isDateUnavailable", required: false }] }], dateLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateLabel", required: false }] }], disabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonlyInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], selectionMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionMode", required: false }] }], view: [{ type: i0.Input, args: [{ isSignal: true, alias: "view", required: false }] }, { type: i0.Output, args: ["viewChange"] }], yearBlockSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "yearBlockSize", required: false }] }], range: [{ type: i0.Input, args: [{ isSignal: true, alias: "range", required: false }] }, { type: i0.Output, args: ["rangeChange"] }], minRangeLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "minRangeLength", required: false }] }], maxRangeLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxRangeLength", required: false }] }], firstDayOfWeek: [{ type: i0.Input, args: [{ isSignal: true, alias: "firstDayOfWeek", required: false }] }], _dirInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "dir", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }] } });
1339
1364
 
1340
1365
 
1341
1366