forty-cdk 0.24.0 → 0.24.1

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.
@@ -140,7 +140,7 @@ Both triggers carry `[menuPositioning]`, a partial `{ side, align, sideOffset, a
140
140
 
141
141
  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`.
142
142
 
143
- `(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.
143
+ `(autoFocusOnOpen)` / `(autoFocusOnClose)` are output-shape because ContextMenu always routes close transitions through `[(open)]` (via the implicit `openChange` emitter). Dialog and Drawer take callback-shape inputs for the same pair instead: either can be closed by a direct `open.set(false)` that bypasses the `(dismiss)` output entirely, so their close hook has to be a stored function reference that still runs during teardown.
144
144
 
145
145
  ### Data attributes
146
146
 
package/dialog/README.md CHANGED
@@ -249,7 +249,7 @@ Keep `dismissible: true` (the default) so Escape still closes, and veto only the
249
249
 
250
250
  ### Inputs — focus callbacks
251
251
 
252
- The auto-focus pair is bound as **function references** (input callbacks), not as event listeners. Each callback receives a `VetoableEvent` whose `preventDefault()` suppresses the directive's default focus action. This shape mirrors `ForDialogManager`'s `config.autoFocusOn*` callbacks and guarantees the `autoFocusOnClose` callback fires reliably on every close path — including a direct `open.set(false)` that bypasses the `(dismiss)` output. See [Conventions › Auto-focus hook shape](../../../.claude/rules/conventions.md#auto-focus-hook-shape) for why the free-floating overlays (Dialog, Drawer) use callback-shape inputs while the trigger-anchored ones use output-shape.
252
+ The auto-focus pair is bound as **function references** (input callbacks), not as event listeners. Each callback receives a `VetoableEvent` whose `preventDefault()` suppresses the directive's default focus action. This shape mirrors `ForDialogManager`'s `config.autoFocusOn*` callbacks and guarantees the `autoFocusOnClose` callback fires reliably on every close path — including a direct `open.set(false)` that bypasses the `(dismiss)` output. The trigger-anchored overlays (Popover, DropdownMenu, Select, …) expose the same pair as **outputs** instead, because every close transition there runs through their own `[(open)]` model, so no path can bypass the emitter.
253
253
 
254
254
  | Property | Type | Description |
255
255
  | ------------------ | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -369,8 +369,9 @@ A custom integration that cannot use either companion must supply the same three
369
369
  mechanisms itself: map window-relative to absolute indices with the reusable
370
370
  `translateWindowReorder` helper (`forty-cdk/core`), keep the lifted row mounted
371
371
  for the duration of the drag, and step the keyboard target over the true total
372
- count. See [`docs/drag-in-virtualized-list-spike.md`](../../../docs/drag-in-virtualized-list-spike.md)
373
- for the full analysis.
372
+ count. Miss any one of the three and the failure is silent — an index that
373
+ addresses the wrong row, a lifted row recycled mid-drag, or a keyboard move that
374
+ stops at the window edge.
374
375
 
375
376
  ## Data attributes
376
377
 
@@ -156,7 +156,7 @@ Angular resolves `ng-template` DI at the template's **declaration** site, not wh
156
156
 
157
157
  Every output above is vetoable — each handler receives a `VetoableEvent` (or `VetoableNativeEvent<E>` when there is a native DOM event). Call `preventDefault()` on the emitted veto to suppress the directive's default action; the original DOM event, when present, is on `.event`.
158
158
 
159
- `(autoFocusOnOpen)` / `(autoFocusOnClose)` are output-shape because DropdownMenu 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.
159
+ `(autoFocusOnOpen)` / `(autoFocusOnClose)` are output-shape because DropdownMenu always routes close transitions through `[(open)]` (via the implicit `openChange` emitter). Dialog and Drawer take callback-shape inputs for the same pair instead: either can be closed by a direct `open.set(false)` that bypasses the `(dismiss)` output entirely, so their close hook has to be a stored function reference that still runs during teardown.
160
160
 
161
161
  ### Data attributes
162
162
 
@@ -628,8 +628,11 @@ class ForListbox extends FormUiControlBase {
628
628
  }
629
629
  this.markTouched();
630
630
  }
631
+ onPointerLeave() {
632
+ this.#pointerHost.set(null);
633
+ }
631
634
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForListbox, deps: [], target: i0.ɵɵFactoryTarget.Directive });
632
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: ForListbox, isStandalone: true, selector: "[forListbox]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "compareWith", isSignal: true, isRequired: false, transformFunction: null }, itemToFormValue: { classPropertyName: "itemToFormValue", publicName: "itemToFormValue", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, loop: { classPropertyName: "loop", publicName: "loop", isSignal: true, isRequired: false, transformFunction: null }, totalCount: { classPropertyName: "totalCount", publicName: "totalCount", isSignal: true, isRequired: false, transformFunction: null }, visibleRange: { classPropertyName: "visibleRange", publicName: "visibleRange", isSignal: true, isRequired: false, transformFunction: null }, dataVersion: { classPropertyName: "dataVersion", publicName: "dataVersion", isSignal: true, isRequired: false, transformFunction: null }, _dirInput: { classPropertyName: "_dirInput", publicName: "dir", isSignal: true, isRequired: false, transformFunction: null }, selectionFollowsFocus: { classPropertyName: "selectionFollowsFocus", publicName: "selectionFollowsFocus", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", scrollToIndex: "scrollToIndex" }, host: { attributes: { "role": "listbox" }, listeners: { "keydown": "onHostKeyDown($event)", "focusin": "onHostFocusIn()", "focusout": "onFocusOut($event)" }, properties: { "attr.aria-label": "resolvedAriaLabel()", "attr.aria-orientation": "orientation()", "attr.aria-multiselectable": "multiple() ? \"true\" : null", "attr.aria-disabled": "effectiveDisabled() ? \"true\" : null", "attr.aria-readonly": "readonly() ? \"true\" : null", "attr.aria-required": "required() ? \"true\" : null", "attr.aria-invalid": "invalid() ? \"true\" : null", "attr.aria-busy": "pending() ? \"true\" : null", "attr.aria-activedescendant": "activeDescendantId()", "attr.tabindex": "hostTabindex()", "attr.data-orientation": "orientation()", "attr.data-disabled": "effectiveDisabled() ? \"\" : null", "attr.data-readonly": "readonly() ? \"\" : null", "attr.dir": "dir()" } }, providers: [{ provide: FOR_LISTBOX_CONTEXT, useExisting: ForListbox }], exportAs: ["forListbox"], usesInheritance: true, ngImport: i0 });
635
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: ForListbox, isStandalone: true, selector: "[forListbox]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "compareWith", isSignal: true, isRequired: false, transformFunction: null }, itemToFormValue: { classPropertyName: "itemToFormValue", publicName: "itemToFormValue", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, loop: { classPropertyName: "loop", publicName: "loop", isSignal: true, isRequired: false, transformFunction: null }, totalCount: { classPropertyName: "totalCount", publicName: "totalCount", isSignal: true, isRequired: false, transformFunction: null }, visibleRange: { classPropertyName: "visibleRange", publicName: "visibleRange", isSignal: true, isRequired: false, transformFunction: null }, dataVersion: { classPropertyName: "dataVersion", publicName: "dataVersion", isSignal: true, isRequired: false, transformFunction: null }, _dirInput: { classPropertyName: "_dirInput", publicName: "dir", isSignal: true, isRequired: false, transformFunction: null }, selectionFollowsFocus: { classPropertyName: "selectionFollowsFocus", publicName: "selectionFollowsFocus", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", scrollToIndex: "scrollToIndex" }, host: { attributes: { "role": "listbox" }, listeners: { "keydown": "onHostKeyDown($event)", "focusin": "onHostFocusIn()", "focusout": "onFocusOut($event)", "pointerleave": "onPointerLeave()" }, properties: { "attr.aria-label": "resolvedAriaLabel()", "attr.aria-orientation": "orientation()", "attr.aria-multiselectable": "multiple() ? \"true\" : null", "attr.aria-disabled": "effectiveDisabled() ? \"true\" : null", "attr.aria-readonly": "readonly() ? \"true\" : null", "attr.aria-required": "required() ? \"true\" : null", "attr.aria-invalid": "invalid() ? \"true\" : null", "attr.aria-busy": "pending() ? \"true\" : null", "attr.aria-activedescendant": "activeDescendantId()", "attr.tabindex": "hostTabindex()", "attr.data-orientation": "orientation()", "attr.data-disabled": "effectiveDisabled() ? \"\" : null", "attr.data-readonly": "readonly() ? \"\" : null", "attr.dir": "dir()" } }, providers: [{ provide: FOR_LISTBOX_CONTEXT, useExisting: ForListbox }], exportAs: ["forListbox"], usesInheritance: true, ngImport: i0 });
633
636
  }
634
637
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ForListbox, decorators: [{
635
638
  type: Directive,
@@ -655,6 +658,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
655
658
  '(keydown)': 'onHostKeyDown($event)',
656
659
  '(focusin)': 'onHostFocusIn()',
657
660
  '(focusout)': 'onFocusOut($event)',
661
+ '(pointerleave)': 'onPointerLeave()',
658
662
  },
659
663
  providers: [{ provide: FOR_LISTBOX_CONTEXT, useExisting: ForListbox }],
660
664
  }]
@@ -685,6 +689,8 @@ const FOR_LISTBOX_OPTION = new InjectionToken('FOR_LISTBOX_OPTION');
685
689
 
686
690
 
687
691
 
692
+
693
+
688
694
  class ForListboxOption {
689
695
  buttonType = hostButtonType();
690
696
  #group = injectListboxContext('ForListboxOption');