forty-cdk 0.10.0 → 0.11.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.
@@ -1105,9 +1105,10 @@ class ForCombobox extends FormUiControlBase {
1105
1105
  * Re-applies the scroll unconditionally — the bridge already recorded this id
1106
1106
  * as positioned, but the portal move invalidated the real scroll position, so
1107
1107
  * the usual "already positioned" guard must not short-circuit here. Fires once
1108
- * per open (the positioner hook is one-shot per run), so a later hover never
1109
- * scrolls. No-op while virtualizing: the navigator owns the virtualized scroll
1110
- * and the indexed seed is intentionally passive.
1108
+ * per open (the positioner hook is per-open, not per-run, so a side flip while
1109
+ * open never re-fires it and yanks the user's scroll back), so a later hover
1110
+ * never scrolls. No-op while virtualizing: the navigator owns the virtualized
1111
+ * scroll and the indexed seed is intentionally passive.
1111
1112
  */
1112
1113
  scrollActiveOptionIntoView() {
1113
1114
  if (this.totalCount() !== undefined) {
@@ -1658,6 +1659,7 @@ class ForComboboxInput {
1658
1659
  // and shouldn't bubble through nested layers before it sees it.
1659
1660
  if (this.ctx.open()) {
1660
1661
  event.preventDefault();
1662
+ event.stopPropagation();
1661
1663
  this.ctx.emitEscapeKeyDown(event);
1662
1664
  }
1663
1665
  break;
@@ -1750,13 +1752,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
1750
1752
  * trigger are exempt from outside checks.
1751
1753
  *
1752
1754
  * Focus:
1753
- * - **Editable anatomy** — focus stays in the input across the whole open
1754
- * lifecycle; the directive never moves DOM focus and exposes no focus hooks.
1755
- * Active-option highlighting is `aria-activedescendant`-driven.
1755
+ * - **Editable anatomy** — focus normally stays in the input across the whole
1756
+ * open lifecycle and active-option highlighting is `aria-activedescendant`-
1757
+ * driven, so the directive exposes no focus hooks. The surface itself is
1758
+ * focusable (`tabindex="-1"`), so a click on non-option padding can move focus
1759
+ * onto it; the input's inline Escape handler then never sees the key, so the
1760
+ * shell wires a fallback Escape channel that closes the popup and returns focus
1761
+ * to the input.
1756
1762
  * - **Picker anatomy** — on open, focus moves into the input (the search field
1757
1763
  * inside the panel); on close it returns to the trigger. Both moves are
1758
1764
  * vetoable via `(autoFocusOnOpen)` / `(autoFocusOnClose)` on `[forCombobox]`,
1759
- * and the return is gated by `[returnFocus]`. Escape stays owned by the input.
1765
+ * and the return is gated by `[returnFocus]`. Escape from the input is owned by
1766
+ * the input directive; the shell's fallback channel covers presses that land on
1767
+ * the surface or list instead.
1760
1768
  *
1761
1769
  * The lifecycle (positioner + dismissable layer, plus the picker anatomy's
1762
1770
  * focus bundles) is owned by the shared `injectOverlayShell` helper.
@@ -1795,9 +1803,12 @@ class ForComboboxContent {
1795
1803
  dismiss: {
1796
1804
  dismissible: ctx.dismissible,
1797
1805
  requestClose: (reason) => ctx.requestClose(reason),
1798
- // Escape is handled by the input directive (focus stays in the
1799
- // input, so Escape there shouldn't bubble through nested layers
1800
- // before the input sees it). Omitted here intentionally.
1806
+ emitEscapeKeyDown: (event) => {
1807
+ ctx.emitEscapeKeyDown(event);
1808
+ if (!hasTrigger && !ctx.open()) {
1809
+ ctx.input()?.focus();
1810
+ }
1811
+ },
1801
1812
  emitPointerDownOutside: (veto) => ctx.emitPointerDownOutside(veto),
1802
1813
  emitFocusOutside: (veto) => ctx.emitFocusOutside(veto),
1803
1814
  emitInteractOutside: (veto) => ctx.emitInteractOutside(veto),
@@ -1813,6 +1824,8 @@ class ForComboboxContent {
1813
1824
  const trigger = ctx.trigger();
1814
1825
  if (trigger)
1815
1826
  els.push(trigger);
1827
+ for (const chip of ctx.chips())
1828
+ els.push(chip.host);
1816
1829
  return els;
1817
1830
  },
1818
1831
  },
@@ -2262,6 +2275,7 @@ class ForComboboxAction {
2262
2275
  break;
2263
2276
  case 'Escape':
2264
2277
  event.preventDefault();
2278
+ event.stopPropagation();
2265
2279
  this.#ctx.emitEscapeKeyDown(event);
2266
2280
  if (!this.#ctx.open() && this.#ctx.trigger() === null) {
2267
2281
  this.#ctx.input()?.focus();