forty-cdk 0.35.0 → 0.36.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.
@@ -1 +1 @@
1
- {"version":3,"file":"forty-cdk-core-overlay.mjs","names":[],"sources":["../../../projects/forty-cdk/core-overlay/src/body-scroll-lock/body-scroll-lock.ts","../../../projects/forty-cdk/core-overlay/src/dismissible-layer/dismissible-layer.ts","../../../projects/forty-cdk/core-overlay/src/drawer-stack/drawer-stack.ts","../../../projects/forty-cdk/core-overlay/src/floating/anchored-positioning-inputs.ts","../../../projects/forty-cdk/core-overlay/src/floating/anchored-form-value-control-base.ts","../../../projects/forty-cdk/core-overlay/src/floating/anchored-overlay-positioning-base.ts","../../../projects/forty-cdk/core-overlay/src/hover-intent/debounced-action.ts","../../../projects/forty-cdk/core-overlay/src/hover-intent/hover-intent.ts","../../../projects/forty-cdk/core-overlay/src/pointer-grace/pointer-grace.ts","../../../projects/forty-cdk/core-overlay/src/hover-intent/hover-surface-state.ts","../../../projects/forty-cdk/core-overlay/src/inert-siblings/inert-siblings.ts","../../../projects/forty-cdk/core-overlay/src/overlay-controller/element-registry.ts","../../../projects/forty-cdk/core-overlay/src/overlay-controller/close-reason-state.ts","../../../projects/forty-cdk/core-overlay/src/overlay-controller/initial-focus-state.ts","../../../projects/forty-cdk/core-overlay/src/overlay-controller/overlay-controller.ts","../../../projects/forty-cdk/core-overlay/src/listbox-overlay/listbox-overlay-controller.ts","../../../projects/forty-cdk/core-overlay/src/menu-overlay/menu-context.ts","../../../projects/forty-cdk/core-overlay/src/menu-overlay/menu-item-list.ts","../../../projects/forty-cdk/core-overlay/src/menu-overlay/menu-opener-registry.ts","../../../projects/forty-cdk/core-overlay/src/menu-overlay/menu-overlay.ts","../../../projects/forty-cdk/core-overlay/src/menu-overlay/menu-overlay-host.ts","../../../projects/forty-cdk/core-overlay/src/modal-shell/modal-backdrop.ts","../../../projects/forty-cdk/core-overlay/src/overlay-controller/outside-veto.ts","../../../projects/forty-cdk/core-overlay/src/modal-shell/modal-activation-order.ts","../../../projects/forty-cdk/core-overlay/src/modal-shell/modal-shell.ts","../../../projects/forty-cdk/core-overlay/src/modal-shell/modal-trigger.ts","../../../projects/forty-cdk/core-overlay/src/modal-shell/modal-surface-base.ts","../../../projects/forty-cdk/core-overlay/src/overlay-controller/mounted-while-closed.ts","../../../projects/forty-cdk/core-overlay/src/floating/floating-custom-properties.ts","../../../projects/forty-cdk/core-overlay/src/floating/run-positioning.ts","../../../projects/forty-cdk/core-overlay/src/floating/floating.ts","../../../projects/forty-cdk/core-overlay/src/floating/item-aligned.ts","../../../projects/forty-cdk/core-overlay/src/overlay-controller/overlay-shell.ts","../../../projects/forty-cdk/core-overlay/src/overlay-controller/uncontrolled-trigger.ts","../../../projects/forty-cdk/core-overlay/src/overlay-controller/unnamed-dialog.ts","../../../projects/forty-cdk/core-overlay/src/overlay-manager/overlay-manager.ts","../../../projects/forty-cdk/core-overlay/src/overlay-manager/overlay-ref.ts","../../../projects/forty-cdk/core-overlay/src/scroll-dismiss/scroll-dismiss-dispatcher.ts"],"sourcesContent":["import { DOCUMENT, Injectable, PLATFORM_ID, inject } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\n\n/**\n * Refcounted scroll lock, keyed per target element (default `<body>`).\n * Multiple modal surfaces acquire and release locks independently — only the\n * first acquire for a given target mutates that target, only the last release\n * un-mutates it. Different targets (body vs a container element) are fully\n * independent: locking a container does not affect body scroll and vice versa.\n *\n * **Semantic: clear, do not restore.** On the first lock for a target the\n * service writes `overflow: hidden` and an optional scrollbar-compensating\n * `padding-right` inline on that target. On the final unlock it _clears_ the\n * inline styles it set (`target.style.overflow = ''`, and\n * `target.style.paddingRight = ''` only when this lock actually wrote it) and\n * lets the CSS cascade take over again. It does NOT snapshot the values at\n * lock time and rewrite them at unlock time.\n *\n * On overlay-scrollbar / mobile platforms there is no classic scrollbar\n * (`innerWidth - clientWidth === 0` for the body path), so the lock never\n * writes `padding-right`. In that case the final unlock leaves\n * `target.style.paddingRight` untouched, so a consumer's unrelated inline\n * `padding-right` survives. The clear-don't-restore contract only applies to\n * values the lock owns.\n *\n * Why: any code (route transition, theme toggle, the consumer themselves)\n * that mutates `target.style.overflow` between `lock()` and the final\n * `unlock()` would otherwise be silently clobbered when we restored the\n * stale snapshot. Clearing on unlock means the lock owns the inline style\n * only while it exists; intervening mutations win, and the resting state\n * is whatever stylesheet rules apply.\n *\n * The scrollbar-width compensation prevents content jumping when overflow\n * goes from `auto` (scrollbar shown) to `hidden` (scrollbar hidden).\n * For the body path the width is `window.innerWidth - documentElement.clientWidth`;\n * for an element path it is `target.offsetWidth - target.clientWidth`.\n *\n * SSR: the service is `providedIn: 'root'` so its counter map is scoped to a\n * single Angular bootstrap (one per SSR request). Server-side calls are\n * no-ops.\n */\n@Injectable({ providedIn: 'root' })\nexport class BodyScrollLock {\n readonly #document = inject(DOCUMENT);\n readonly #window = this.#document.defaultView;\n readonly #isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n readonly #targets = new Map<HTMLElement, { count: number; wrotePaddingRight: boolean }>();\n\n /**\n * Acquire the scroll lock on `target` (default `document.body`). The first\n * call for a given target sets `overflow: hidden` and compensates for the\n * scrollbar width; subsequent calls increment the refcount only.\n */\n lock(target: HTMLElement = this.#document.body): void {\n if (!this.#isBrowser) {\n return;\n }\n let record = this.#targets.get(target);\n if (!record) {\n record = { count: 0, wrotePaddingRight: false };\n this.#targets.set(target, record);\n }\n if (record.count === 0) {\n target.style.overflow = 'hidden';\n const isBody = target === this.#document.body;\n const win = this.#window;\n let scrollbarWidth: number;\n if (isBody) {\n const docEl = this.#document.documentElement;\n scrollbarWidth = win ? win.innerWidth - docEl.clientWidth : 0;\n if (scrollbarWidth > 0 && win && !this.#gutterIsStable(win, [docEl, target])) {\n const computed = win.getComputedStyle(target).paddingRight;\n const currentPx = parseFloat(computed) || 0;\n target.style.paddingRight = `${currentPx + scrollbarWidth}px`;\n record.wrotePaddingRight = true;\n }\n } else {\n scrollbarWidth = target.offsetWidth - target.clientWidth;\n if (scrollbarWidth > 0 && win && !this.#gutterIsStable(win, [target])) {\n const computed = win.getComputedStyle(target).paddingRight;\n const currentPx = parseFloat(computed) || 0;\n target.style.paddingRight = `${currentPx + scrollbarWidth}px`;\n record.wrotePaddingRight = true;\n }\n }\n }\n record.count++;\n }\n\n /**\n * Release the scroll lock on `target` (default `document.body`). The last\n * release clears the inline `overflow` (and `padding-right` if written) and\n * lets the CSS cascade take over.\n */\n unlock(target: HTMLElement = this.#document.body): void {\n if (!this.#isBrowser) {\n return;\n }\n const record = this.#targets.get(target);\n if (!record || record.count === 0) {\n return;\n }\n record.count--;\n if (record.count === 0) {\n target.style.overflow = '';\n if (record.wrotePaddingRight) {\n target.style.paddingRight = '';\n record.wrotePaddingRight = false;\n }\n this.#targets.delete(target);\n }\n }\n\n /**\n * True when any of the given elements reserves the scrollbar gutter via\n * `scrollbar-gutter: stable` (or `stable both-edges`). The gutter then\n * survives the `overflow: hidden` toggle, so no padding compensation is\n * needed.\n */\n #gutterIsStable(win: Window, els: readonly HTMLElement[]): boolean {\n for (const el of els) {\n const gutter = win.getComputedStyle(el).getPropertyValue('scrollbar-gutter');\n if (gutter.trim().split(/\\s+/).includes('stable')) {\n return true;\n }\n }\n return false;\n }\n}\n","import { DOCUMENT, DestroyRef, ElementRef, Injectable, PLATFORM_ID, inject } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\n\nimport { composedContains, isImeComposing, resolveEventTarget } from 'forty-cdk/core';\n\n/**\n * The outside-interaction channels a {@link DismissibleLayer} can own. A layer\n * declares the channels it wants routed to it at {@link DismissibleLayer.activate};\n * {@link DismissibleLayerStack} dispatches an outside `pointerdown` / `focusin`\n * to the topmost layer that declared the matching channel. Escape is not a\n * channel — it is dispatched to the topmost active layer, and to a layer below\n * only while every layer above it declines the key (see\n * {@link DismissibleLayerActivateOptions.onEscapeKeyDown}).\n */\nexport type DismissibleLayerChannel = 'pointer' | 'focus';\n\n/**\n * Declared nesting position of a layer inside a chain of layers that are\n * structurally nested (a menubar menu and its submenus, a submenu and its own\n * submenu). {@link DismissibleLayerStack} orders such a chain by `depth` rather\n * than by activation order, so a deeper level is always dispatched to before\n * its ancestors even when both levels mount in the same render pass and the\n * `afterNextRender` callbacks fire child-before-parent.\n *\n * A layer that declares no nesting keeps the plain LIFO behaviour: it is pushed\n * on top of everything, and never reorders relative to a chain it does not\n * belong to (a Dialog opened from inside a submenu still lands topmost).\n */\nexport interface DismissibleLayerNesting {\n /**\n * Identity of the chain this layer belongs to — typically the coordination\n * context of the outermost level. Only layers sharing a chain are ordered\n * against each other by `depth`.\n */\n readonly chain: object;\n /** `0` for the outermost level, `+1` per nesting level below it. */\n readonly depth: number;\n}\n\n/**\n * Options passed to `DismissibleLayer.activate`. Each handler receives the\n * native event; the consumer owns the close decision inside its own handler\n * (there is no separate default-dismiss callback).\n */\nexport interface DismissibleLayerActivateOptions {\n /**\n * The outside-interaction channels this layer owns. The stack routes an\n * outside `pointerdown` to the topmost layer declaring `'pointer'` and an\n * outside `focusin` to the topmost layer declaring `'focus'`, so an\n * Escape-only surface (Tooltip, HoverCard) declares `[]` and stays\n * transparent to the real dismissible layers beneath it. Escape is dispatched\n * from the topmost layer down regardless of this declaration.\n */\n channels: readonly DismissibleLayerChannel[];\n\n /**\n * Declared position of this layer inside a chain of structurally nested\n * layers. When present, {@link DismissibleLayerStack} inserts the layer by\n * depth within its chain instead of pushing it on top, so the stack order\n * reflects the nesting rather than the order the levels happened to activate\n * in. Omit for a standalone overlay.\n */\n nesting?: DismissibleLayerNesting;\n\n /**\n * Fired when the user presses `Escape` while this is the topmost layer, or while every layer\n * stacked above it declined the key. Return `false` to decline it too: the key is then offered\n * to the layer below, unless this layer is\n * {@link DismissibleLayerActivateOptions.modal | modal}. Any other return value keeps it.\n */\n onEscapeKeyDown?: (event: KeyboardEvent) => unknown;\n\n /**\n * Fired when the user pointer-downs outside this layer's host. Return `true` when the handler\n * closed the layer: only then is the press offered to the pointer layer below, and only when that\n * layer opted in through {@link DismissibleLayerActivateOptions.cascadeOutsidePress}.\n */\n onPointerDownOutside?: (event: PointerEvent) => unknown;\n\n /**\n * Fired when the user pointer-downs **inside** this layer's host or one of its `exemptElements`\n * — the mirror of `onPointerDownOutside`.\n *\n * It answers \"was that press mine?\" with the same containment rule the dismissal path uses,\n * instead of the owner re-deriving the surface set from its own host listeners.\n */\n onPointerDownInside?: (event: PointerEvent) => void;\n\n /** Fired when focus moves outside this layer's host. */\n onFocusOutside?: (event: FocusEvent) => void;\n\n /**\n * Fired in addition to `onPointerDownOutside` / `onFocusOutside` for\n * consumers that don't care which one occurred.\n */\n onInteractOutside?: (event: PointerEvent | FocusEvent) => void;\n\n /**\n * Extra elements whose subtrees count as \"inside\" for outside-pointer /\n * outside-focus checks (e.g. a portaled popover content owned by this\n * layer). Recomputed on every event so that DOM mutations are picked up,\n * and handed the node being tested so an owner can leave part of an exempt\n * subtree outside.\n */\n exemptElements?: (target: Node) => readonly Element[];\n\n /**\n * Whether this layer also closes on an outside press that the pointer layer directly above it\n * closed on. Read on every press. Without it, an outside press reaches only the topmost pointer\n * layer.\n *\n * The cascade walks down one pointer layer at a time and stops at the first layer that contains\n * the press, keeps itself open, did not opt in, or is\n * {@link DismissibleLayerActivateOptions.modal | modal}.\n */\n cascadeOutsidePress?: () => boolean;\n\n /**\n * Whether this layer is a modal surface. A modal layer ends an outside-press cascade: a press it\n * receives is never offered to the layers beneath it.\n */\n modal?: boolean;\n}\n\nconst EMPTY_ACTIVATE_OPTIONS: DismissibleLayerActivateOptions = { channels: [] };\n\n/**\n * Application-scoped registry that owns the document listeners used by\n * dismissible layers. Created once per Angular bootstrap (one per SSR\n * request), tied to the root injector lifetime.\n *\n * Listeners are installed on the first layer activation and removed with the last, and a\n * `DestroyRef` hook clears both the listeners and the stack, so no bootstrap leaves listeners\n * behind. Installation is a no-op off-browser.\n *\n * **Stack order** is activation order for standalone layers, but a layer declaring a\n * {@link DismissibleLayerNesting} is inserted by nesting depth within its chain. Activation order\n * is a render-timing artifact — a menu and its submenu mounted in one pass run their\n * `afterNextRender` callbacks child-before-parent — so ordering by timing would place an ancestor\n * above its own descendant, making the descendant's first focus read as `focusOutside` and collapse\n * the chain.\n *\n * **Listener phases are asymmetric.** `pointerdown` and `focusin` register on the\n * capture phase, so an outside interaction is detected even when overlay content stops\n * propagation. `keydown` registers on the bubble phase instead, because the per-overlay Escape\n * handlers call `stopPropagation()` after closing — which is what keeps one Escape from closing an\n * ancestor layer too. The accepted trade-off is that overlay content with its own bubble-phase\n * `keydown` handler calling `stopPropagation()` can swallow Escape before it arrives.\n *\n * An Escape that belongs to an IME composition (see `isImeComposing`) is never dispatched: it\n * cancels the conversion, not the topmost layer.\n */\n@Injectable({ providedIn: 'root' })\nexport class DismissibleLayerStack {\n readonly #document = inject(DOCUMENT);\n readonly #isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n readonly #stack: DismissibleLayer[] = [];\n #suppressDepth = 0;\n #listening = false;\n\n readonly #onKeyDown = (event: KeyboardEvent): void => {\n if (event.key !== 'Escape' || isImeComposing(event)) {\n return;\n }\n if (event.defaultPrevented) {\n return;\n }\n if (this.#suppressDepth > 0) {\n return;\n }\n for (const layer of [...this.#stack].reverse()) {\n if (layer.isActive && (layer.handleEscape(event) || layer.isModal)) {\n return;\n }\n }\n };\n readonly #onPointerDown = (event: Event): void => {\n if (this.#suppressDepth > 0) {\n return;\n }\n const [topmost, ...below] = this.#layersForChannel('pointer');\n if (!topmost?.handlePointerDown(event as PointerEvent) || topmost.isModal) {\n return;\n }\n for (const layer of below) {\n if (!layer.isActive || !layer.cascadesOutsidePress()) {\n return;\n }\n if (!layer.handlePointerDown(event as PointerEvent) || layer.isModal) {\n return;\n }\n }\n };\n readonly #onFocusIn = (event: Event): void => {\n if (this.#suppressDepth > 0) {\n return;\n }\n this.#topmostForChannel('focus')?.handleFocusIn(event as FocusEvent);\n };\n\n constructor() {\n inject(DestroyRef).onDestroy(() => {\n this.#removeListeners();\n this.#stack.length = 0;\n this.#suppressDepth = 0;\n });\n }\n\n /** @internal */\n push(layer: DismissibleLayer): void {\n this.#stack.splice(this.#insertionIndex(layer), 0, layer);\n if (this.#stack.length === 1) {\n this.#installListeners();\n }\n }\n\n /** @internal */\n remove(layer: DismissibleLayer): void {\n const idx = this.#stack.indexOf(layer);\n if (idx >= 0) {\n this.#stack.splice(idx, 1);\n if (this.#stack.length === 0) {\n this.#removeListeners();\n }\n }\n }\n\n /**\n * @internal Whether `target` is inside `layer` or inside any layer stacked\n * above it. A layer stacked above the chosen channel handler (e.g. an\n * interactive Escape-only HoverCard over a Popover) counts as \"inside\", so an\n * interaction within it never leaks an \"outside\" dismissal to the layer below.\n */\n containsFromLayer(layer: DismissibleLayer, target: Node): boolean {\n const idx = this.#stack.indexOf(layer);\n if (idx < 0) {\n return layer.contains(target);\n }\n for (let i = idx; i < this.#stack.length; i++) {\n const above = this.#stack[i];\n if (above && above.contains(target)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * @internal Whether `layer` is the topmost layer declaring `channel`, i.e. the\n * one an outside interaction on that channel is dispatched to.\n */\n isTopmostForChannel(layer: DismissibleLayer, channel: DismissibleLayerChannel): boolean {\n return this.#topmostForChannel(channel) === layer;\n }\n\n /**\n * Runs `fn` with the dispatcher suppressed. While suppressed, neither\n * Escape, pointer-down outside, nor focus-outside events are forwarded\n * to the topmost layer. Refcounted so nested teardowns nest correctly.\n */\n suppress<T>(fn: () => T): T {\n this.#suppressDepth++;\n try {\n return fn();\n } finally {\n this.#suppressDepth--;\n }\n }\n\n #installListeners(): void {\n if (!this.#isBrowser || this.#listening) {\n return;\n }\n this.#listening = true;\n this.#document.addEventListener('keydown', this.#onKeyDown);\n this.#document.addEventListener('pointerdown', this.#onPointerDown, true);\n this.#document.addEventListener('focusin', this.#onFocusIn, true);\n }\n\n #removeListeners(): void {\n if (!this.#listening) {\n return;\n }\n this.#listening = false;\n this.#document.removeEventListener('keydown', this.#onKeyDown);\n this.#document.removeEventListener('pointerdown', this.#onPointerDown, true);\n this.#document.removeEventListener('focusin', this.#onFocusIn, true);\n }\n\n /**\n * Where a newly activated layer belongs. Plain LIFO (the top of the stack)\n * unless the layer declared a {@link DismissibleLayerNesting}: then it slides\n * down past the trailing run of layers from the same chain that sit deeper\n * than it, so an ancestor activating after its own descendant still lands\n * below it. The scan stops at the first layer that is not a deeper\n * level of the same chain, so an unrelated overlay (a Dialog opened from\n * inside a submenu) is never jumped over.\n */\n #insertionIndex(layer: DismissibleLayer): number {\n const nesting = layer.nesting;\n let idx = this.#stack.length;\n if (!nesting) {\n return idx;\n }\n while (idx > 0) {\n const below = this.#stack[idx - 1]?.nesting;\n if (!below || below.chain !== nesting.chain || below.depth <= nesting.depth) {\n break;\n }\n idx--;\n }\n return idx;\n }\n\n #layersForChannel(channel: DismissibleLayerChannel): DismissibleLayer[] {\n const layers: DismissibleLayer[] = [];\n for (let i = this.#stack.length - 1; i >= 0; i--) {\n const layer = this.#stack[i];\n if (layer && layer.ownsChannel(channel)) {\n layers.push(layer);\n }\n }\n return layers;\n }\n\n #topmostForChannel(channel: DismissibleLayerChannel): DismissibleLayer | undefined {\n for (let i = this.#stack.length - 1; i >= 0; i--) {\n const layer = this.#stack[i];\n if (layer && layer.ownsChannel(channel)) {\n return layer;\n }\n }\n return undefined;\n }\n}\n\n/**\n * Coordinates the standard \"dismissible surface\" interactions used by modal\n * dialogs, popovers, dropdown menus, drawers, and any other transient\n * overlay: Escape, pointer-down outside, focus-outside.\n *\n * Dispatch is per channel. Escape goes to the topmost active layer, and reaches\n * a layer below only when every layer above it declined the key, so one Escape\n * still closes at most one layer and never crosses a modal layer.\n * Pointer-down-outside and focus-outside instead go to the topmost\n * layer that declared the matching channel: a layer that owns only Escape (e.g.\n * a Tooltip, declaring `channels: []`) is transparent to outside-pointer /\n * focus for the real dismissible layers beneath it, so a tooltip visible over\n * an open menu never shadows the menu's outside-click dismissal. Nested\n * real layers (a popover inside a dialog) still resolve to a single topmost\n * handler per channel, so single-dismiss semantics hold — unless a lower layer\n * opts into `cascadeOutsidePress`, in which case an outside press the layer\n * above it closed on reaches it too.\n *\n * Containment is stack-aware: an interaction inside a layer stacked *above* the\n * chosen handler counts as \"inside\", so an interactive Escape-only surface (a\n * HoverCard over a Popover) never leaks an outside dismissal to the layer below.\n *\n * Dispatch goes through a single shared document listener, so synchronous\n * changes to the stack from a handler don't leak into sibling listeners.\n */\nexport class DismissibleLayer {\n readonly #host: HTMLElement;\n readonly #stack: DismissibleLayerStack;\n #options: DismissibleLayerActivateOptions = EMPTY_ACTIVATE_OPTIONS;\n #channels: ReadonlySet<DismissibleLayerChannel> = new Set();\n #active = false;\n\n constructor(host: HTMLElement, stack: DismissibleLayerStack) {\n this.#host = host;\n this.#stack = stack;\n }\n\n get host(): HTMLElement {\n return this.#host;\n }\n\n get isActive(): boolean {\n return this.#active;\n }\n\n /**\n * @internal The nesting position declared at `activate`, or `undefined` for a\n * standalone layer. Read by {@link DismissibleLayerStack} to place the layer\n * by nesting depth instead of activation order. Public only so the stack can\n * read it, not part of the supported API.\n */\n get nesting(): DismissibleLayerNesting | undefined {\n return this.#options.nesting;\n }\n\n /**\n * Pushes this layer onto the dispatch stack. Calling `activate` twice\n * without an intervening `deactivate` is a no-op.\n */\n activate(options: DismissibleLayerActivateOptions): void {\n if (this.#active) {\n return;\n }\n this.#active = true;\n this.#options = options;\n this.#channels = new Set(options.channels);\n this.#stack.push(this);\n }\n\n /** Removes this layer from the stack. */\n deactivate(): void {\n if (!this.#active) {\n return;\n }\n this.#active = false;\n this.#stack.remove(this);\n this.#options = EMPTY_ACTIVATE_OPTIONS;\n this.#channels = new Set();\n }\n\n /**\n * Convenience wrapper around the stack's `suppress`. Lets owners\n * suppress the dispatcher without needing a fresh injection context\n * (e.g. inside `DestroyRef.onDestroy` or imperative teardown closures).\n */\n suppress<T>(fn: () => T): T {\n return this.#stack.suppress(fn);\n }\n\n /**\n * @internal Whether this layer declared ownership of `channel`. Read by\n * {@link DismissibleLayerStack} to route an outside pointer-down / focus to\n * the topmost owning layer. Public only so the stack can read it, not part of\n * the supported API.\n */\n ownsChannel(channel: DismissibleLayerChannel): boolean {\n return this.#channels.has(channel);\n }\n\n /**\n * Whether this layer is active and is the topmost layer declaring `channel`, so no other layer\n * stacked above it would receive an outside interaction on that channel first.\n */\n isTopmostFor(channel: DismissibleLayerChannel): boolean {\n return this.#active && this.#stack.isTopmostForChannel(this, channel);\n }\n\n /**\n * @internal Whether `target` is inside this layer's host or its exempt\n * elements. Read by {@link DismissibleLayerStack} when walking the stack for\n * stack-aware containment. Public only so the stack can read it.\n *\n * Containment is composed-tree containment, the counterpart of the deep\n * target {@link resolveEventTarget} resolves: plain `Node.contains` answers\n * within one node tree, so a press on a control inside a web component's\n * shadow root — a target the composed path resolves precisely — would read as\n * a press outside the surface that renders it.\n */\n contains(target: Node): boolean {\n if (composedContains(this.#host, target)) {\n return true;\n }\n const exempt = this.#options.exemptElements?.(target);\n if (!exempt) {\n return false;\n }\n for (const el of exempt) {\n if (composedContains(el, target)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * @internal Dispatched by {@link DismissibleLayerStack} to the topmost layer\n * on `Escape`, and to each layer below it while the layers above decline the\n * key. Returns whether this layer kept it. Public only so the stack can call it\n * without exploiting a TS visibility loophole; not part of the supported API\n * (stripped from `.d.ts`).\n */\n handleEscape(event: KeyboardEvent): boolean {\n return this.#options.onEscapeKeyDown?.(event) !== false;\n }\n\n /**\n * @internal Dispatched by {@link DismissibleLayerStack} to the topmost layer\n * declaring the `'pointer'` channel on an outside `pointerdown`, and to each\n * layer below it an outside-press cascade reaches. Returns whether the press\n * was outside and the layer closed on it. See {@link handleEscape}.\n */\n handlePointerDown(event: PointerEvent): boolean {\n const target = resolveEventTarget(event);\n if (!target) {\n return false;\n }\n if (this.#stack.containsFromLayer(this, target)) {\n this.#options.onPointerDownInside?.(event);\n return false;\n }\n const closed = this.#options.onPointerDownOutside?.(event) === true;\n this.#options.onInteractOutside?.(event);\n return closed;\n }\n\n /**\n * @internal Whether this layer declared itself modal at `activate`. Read by\n * {@link DismissibleLayerStack} to end an outside-press cascade.\n */\n get isModal(): boolean {\n return this.#options.modal === true;\n }\n\n /**\n * @internal Whether this layer currently opts into an outside-press cascade.\n * Read by {@link DismissibleLayerStack} on every press.\n */\n cascadesOutsidePress(): boolean {\n return this.#options.cascadeOutsidePress?.() === true;\n }\n\n /**\n * @internal Dispatched by {@link DismissibleLayerStack} to the topmost layer\n * declaring the `'focus'` channel on an outside `focusin`. See\n * {@link handleEscape}.\n */\n handleFocusIn(event: FocusEvent): void {\n const target = resolveEventTarget(event);\n if (!target || this.#stack.containsFromLayer(this, target)) {\n return;\n }\n this.#options.onFocusOutside?.(event);\n this.#options.onInteractOutside?.(event);\n }\n}\n\n/**\n * Creates a `DismissibleLayer` for the directive's host element and wires\n * deactivation into `DestroyRef`. The host primitive owns activation\n * (typically via an `effect()` watching the open state).\n *\n * Use `layer.suppress(fn)` to run a callback with the dispatcher\n * suppressed (e.g. across a focus-return that would otherwise\n * cascade-dismiss the next topmost layer).\n */\nexport function injectDismissibleLayer(): DismissibleLayer {\n const host = inject<ElementRef<HTMLElement>>(ElementRef);\n const stack = inject(DismissibleLayerStack);\n const layer = new DismissibleLayer(host.nativeElement, stack);\n inject(DestroyRef).onDestroy(() => layer.deactivate());\n return layer;\n}\n","import { computed, Injectable, type Signal, signal } from '@angular/core';\n\nimport { type ForDrawerSide } from './drawer-side';\nimport { fortyError } from 'forty-cdk/core';\n\n/**\n * Snapshot of a single drawer registered with {@link ForDrawerStack}. The\n * stack is LIFO ordered (root → topmost) and exposes only what other\n * coordinators need — `host` for ancestry checks, `side` (a `Signal`, so a\n * runtime side flip recomputes dependent transforms) for layout heuristics,\n * `parent` for topology, `dragging` so visual coordinators (e.g.\n * `ForDrawerScaleCoordinator`'s nested-transform pass) can yield the\n * surface to imperative drag handlers, and the resolved nested-transform\n * tunables so the coordinator never needs to re-read scope-dependent\n * defaults.\n */\nexport interface DrawerStackNode {\n readonly host: HTMLElement;\n /**\n * Reactive edge the drawer is anchored to. Read inside the coordinator's\n * nested-transform effect so a runtime `[side]` rebind recomputes the\n * parent surface's transform axis, mirroring the reactive `dragging`\n * channel.\n */\n readonly side: Signal<ForDrawerSide>;\n readonly parent: HTMLElement | null;\n /**\n * Reactive flag that flips to `true` while a swipe gesture is in flight\n * on this drawer's surface. Visual coordinators must yield the host's\n * inline transform to the drag handlers while this is `true`.\n */\n readonly dragging: Signal<boolean>;\n /**\n * Scale factor applied to *this* drawer's host while it owns one or\n * more direct child drawers (the nested-drawer visual). Resolved from\n * the drawer's own injector scope at push time so per-scope\n * `provideForDrawerDefaults` overrides flow through.\n */\n readonly nestedScaleAmount: number;\n /**\n * Pixels of translation applied to *this* drawer's host while it owns\n * one or more direct child drawers, in the direction *away* from its\n * anchored edge.\n */\n readonly nestedTranslateYpx: number;\n}\n\n/**\n * Returned by {@link ForDrawerStack.push}. `depth` is the number of\n * ancestor drawers in the node's `parent` chain (0 for a root drawer, 1 for a\n * single-nested child, …), recomputed whenever the stack changes. `cleanup`\n * pops the node; calling it while descendants are still registered throws so\n * consumers surface their own destroy-order bugs instead of silently leaking.\n */\nexport interface DrawerStackHandle {\n readonly depth: Signal<number>;\n cleanup(): void;\n}\n\n/**\n * App-scoped LIFO registry of every active `[forDrawer]`. Mounted drawers\n * push themselves on first render and pop on destroy; the stack's signal\n * is the single source of truth for nesting topology consumed by:\n *\n * - `[forDrawer]` itself, to derive `data-depth` and `data-state-nested`\n * on its host (the latter when the stack contains a node whose\n * `parent` is this drawer's host).\n * - `ForDrawerScaleCoordinator`, when `scaleBackground` is opted in by\n * multiple levels of nesting and the visual effect must compose along\n * the LIFO topmost.\n *\n * The companion to {@link DismissibleLayerStack} and `InertSiblingsStack`:\n * those keep the focus / dismiss / inert behaviour LIFO-correct, this one\n * keeps the *visual* / *topology* layer LIFO-correct. Both are read-only\n * to consumers — there is no public API for explicit ordering. A drawer is\n * pushed on top unless one of its descendants is already registered, as\n * when parent and child mount in one render pass, in which case it is\n * inserted below its first descendant.\n *\n * SSR: `providedIn: 'root'` so state is per Angular bootstrap. The\n * directives that call `push` only do so from `afterNextRender`, which\n * doesn't run on the server, so there is nothing to guard here.\n *\n * Internal core tier — exported from `forty-cdk/core` for the library's own\n * entry points, with no semver guarantee.\n */\n@Injectable({ providedIn: 'root' })\nexport class ForDrawerStack {\n readonly #stack = signal<readonly DrawerStackNode[]>([]);\n\n /**\n * Reactive view of the current drawer stack (root → topmost). Reading\n * this from a `computed`/`effect` lets primitives react to nesting\n * changes synchronously when a child drawer mounts or unmounts.\n */\n readonly stack: Signal<readonly DrawerStackNode[]> = this.#stack.asReadonly();\n\n /**\n * Push a drawer onto the stack. Returns a {@link DrawerStackHandle}\n * carrying the computed `depth` and a `cleanup` that pops the same\n * node. `depth` is derived from the node's `parent` chain through the\n * registered drawers: a root drawer (no `parent`) is depth 0; a child of\n * a depth-N drawer is depth N+1.\n *\n * `cleanup` is idempotent on a node that's already gone, but throws if\n * the node still has descendants in the stack — the canonical signal\n * that the consumer's template tore down a parent before its child\n * (typically because the parent's `@if` flipped to `false` while the\n * child sits in a separate template branch). Nest the child's\n * `@if (childOpen())` *inside* the parent's `@if (parentOpen())` to\n * inherit Angular's bottom-up destroy order automatically.\n */\n push(node: DrawerStackNode): DrawerStackHandle {\n this.#stack.update((s) => {\n const descendant = s.findIndex((other) => this.#isDescendant(other, node, s));\n const next = s.slice();\n next.splice(descendant === -1 ? next.length : descendant, 0, node);\n return next;\n });\n return {\n depth: computed(() => this.#computeDepth(node, this.#stack())),\n cleanup: () => this.#cleanup(node),\n };\n }\n\n #cleanup(node: DrawerStackNode): void {\n const current = this.#stack();\n const idx = current.indexOf(node);\n if (idx === -1) {\n return;\n }\n const hasDescendant = current.some(\n (other) => other !== node && this.#isDescendant(other, node, current),\n );\n if (hasDescendant) {\n throw fortyError({\n code: 'FORCDK-DRAWER-001',\n message: 'A parent drawer was destroyed while a nested child drawer was still registered.',\n cause:\n 'The drawer stack unwinds last-in-first-out, so a child must unmount before its parent. ' +\n 'Sibling @if blocks unmount in template order instead.',\n fix: \"Wrap the child drawer's @if inside the parent's, so the child unmounts first.\",\n });\n }\n const next = current.slice();\n next.splice(idx, 1);\n this.#stack.set(next);\n }\n\n #computeDepth(node: DrawerStackNode, stack: readonly DrawerStackNode[]): number {\n if (node.parent === null) {\n return 0;\n }\n let depth = 0;\n let cursor: HTMLElement | null = node.parent;\n while (cursor) {\n depth += 1;\n const ancestor = stack.find((n) => n.host === cursor);\n if (!ancestor) {\n break;\n }\n cursor = ancestor.parent;\n }\n return depth;\n }\n\n #isDescendant(\n candidate: DrawerStackNode,\n ancestor: DrawerStackNode,\n stack: readonly DrawerStackNode[],\n ): boolean {\n let cursor: HTMLElement | null = candidate.parent;\n while (cursor) {\n if (cursor === ancestor.host) {\n return true;\n }\n const next = stack.find((n) => n.host === cursor);\n if (!next) {\n return false;\n }\n cursor = next.parent;\n }\n return false;\n }\n}\n","import type { Signal } from '@angular/core';\nimport type { ReferenceElement } from '@floating-ui/dom';\n\nimport type { FloatingAlign, FloatingConfig, FloatingSide } from './floating';\n\n/**\n * Single source of truth for the floating-ui positioning defaults shared by\n * every trigger-anchored overlay root. It is read once, by the two bases the\n * roots inherit their positioning block from\n * (`AnchoredOverlayPositioningBase` / `AnchoredFormValueControlBase`), so no\n * root spells a non-seed default itself.\n *\n * Only `side` / `align` / `sideOffset` / `collisionPadding` are seeded from\n * each root's own defaults provider (`provideForPopoverDefaults`,\n * `provideForSelectDefaults`, …) so a scope override flows through — those are\n * the placement values a design system tunes, and they legitimately vary per\n * root. Everything below is identical for every anchored overlay in the\n * library, which is why `arrowPadding` is not among them: only the three roots\n * shipping an arrow piece declare it, each seeded from its own defaults\n * provider.\n */\nexport const ANCHORED_POSITIONING_DEFAULTS = {\n /** Default gap (px) along the cross axis (parallel to `side`). */\n alignOffset: 0,\n /** `flip` / `shift` keep the surface inside the viewport by default. */\n avoidCollisions: true,\n /** Default stickiness behaviour for `shift`. */\n sticky: 'partial' as 'partial' | 'always' | false,\n /** `data-detached=\"\"` is not reflected by default. */\n hideWhenDetached: false,\n /** Content is clipped until floating-ui resolves its first position by default. */\n clipUntilPositioned: true,\n} as const;\n\n/**\n * The resolved floating-ui positioning surface every trigger-anchored overlay\n * root publishes on its context. `ForPopoverContext`, `ForTooltipContext`, and\n * `ForHoverCardContext` all `extends` this so the 12-member positioning half of\n * each context interface is single-sourced rather than copied verbatim.\n *\n * Each member is the *effective* value — the per-instance input merged with the\n * scope default — so a content directive forwards it straight into\n * `injectOverlayShell` via `toFloatingPositioner` without re-resolving defaults.\n *\n * `open` is included because the floating positioner gates `autoUpdate` on it;\n * it is published by every root's open `model()` (a `ModelSignal` is a\n * `Signal`), so a single `extends` covers the whole positioner surface.\n */\nexport interface AnchoredPositioningContext {\n readonly open: Signal<boolean>;\n readonly side: Signal<FloatingSide>;\n readonly align: Signal<FloatingAlign>;\n readonly sideOffset: Signal<number>;\n readonly alignOffset: Signal<number>;\n readonly avoidCollisions: Signal<boolean>;\n readonly collisionPadding: Signal<number>;\n readonly arrowPadding: Signal<number>;\n readonly sticky: Signal<'partial' | 'always' | false>;\n readonly hideWhenDetached: Signal<boolean>;\n readonly clipUntilPositioned: Signal<boolean>;\n readonly arrow: Signal<HTMLElement | null>;\n}\n\n/**\n * Builds the `injectOverlayShell` floating-positioner block from an\n * `AnchoredPositioningContext` and the element the overlay anchors against.\n * Each of the three content directives (`ForPopoverContent`,\n * `ForTooltipContent`, `ForHoverCardContent`) built this 13-field block\n * verbatim; the only difference is the `reference` source — popover anchors to\n * its registered `[forPopoverAnchor]` (falling back to the trigger), tooltip\n * and hover-card anchor directly to the trigger — so the caller passes it in.\n */\nexport function toFloatingPositioner(\n ctx: AnchoredPositioningContext,\n reference: Signal<ReferenceElement | null>,\n): { kind: 'floating' } & FloatingConfig {\n return {\n kind: 'floating',\n reference,\n open: ctx.open,\n side: ctx.side,\n align: ctx.align,\n sideOffset: ctx.sideOffset,\n alignOffset: ctx.alignOffset,\n avoidCollisions: ctx.avoidCollisions,\n collisionPadding: ctx.collisionPadding,\n arrowPadding: ctx.arrowPadding,\n sticky: ctx.sticky,\n hideWhenDetached: ctx.hideWhenDetached,\n clipUntilPositioned: ctx.clipUntilPositioned,\n arrow: ctx.arrow,\n };\n}\n","import { booleanAttribute, computed, Directive, input, numberAttribute } from '@angular/core';\n\nimport { FormUiControlBase } from 'forty-cdk/core';\nimport { ANCHORED_POSITIONING_DEFAULTS } from './anchored-positioning-inputs';\nimport type {\n AnchoredPositioningOverride,\n AnchoredPositioningSeedDefaults,\n} from './anchored-overlay-positioning-base';\nimport type { FloatingAlign, FloatingSide } from './floating';\n\n/**\n * `AnchoredOverlayPositioningBase` for the anchored roots that are also form\n * values — `[forSelect]`, `[forCombobox]`, `[forTimePicker]`, and both\n * date-picker roots through `DatePickerBase`. They must extend\n * `FormUiControlBase` for the Signal Forms contract, and TypeScript has single\n * inheritance, so the positioning block cannot reach them by extending the\n * other base as the remaining eight roots do.\n *\n * This class is therefore the **second and last** declaration site of that\n * block, and it is a verbatim copy on purpose:\n * `anchored-positioning-inputs.spec.ts` reads both files and fails when the two\n * regions stop matching character-for-character, so a change to one is a change\n * to both. Everything the block means is documented on\n * {@link AnchoredOverlayPositioningBase}; do not restate it here, and do not add\n * a member to one base without adding it to the other.\n */\n@Directive()\nexport abstract class AnchoredFormValueControlBase extends FormUiControlBase {\n /**\n * The four positioning seeds this root resolves from its own scoped defaults\n * provider. Concrete roots implement it with\n * `protected readonly positioningDefaults = inject(FOR_X_DEFAULTS)`, or with\n * a getter over a `computed` when one seed is derived (writing direction).\n */\n protected abstract readonly positioningDefaults: AnchoredPositioningSeedDefaults;\n\n /**\n * Placement override for the current open, resolved ahead of this root's own\n * inputs. `null` (the default) leaves the inputs in charge; the menu roots\n * override it with the active opener's `[menuPositioning]`.\n */\n protected positioningOverride(): AnchoredPositioningOverride | null {\n return null;\n }\n\n /**\n * Per-instance override for the side the overlay is anchored to. Pair with\n * `align` for the full positioning API. When `undefined` (default), falls\n * back to the scope default. Aliased to `side`; consumers bind `[side]=\"...\"`\n * and read the effective value via the public {@link side} computed.\n */\n readonly _sideInput = input<FloatingSide | undefined>(undefined, { alias: 'side' });\n\n /** Effective anchor side: the per-open override, else the `side` input, else the scope default. */\n readonly side = computed<FloatingSide>(\n () => this.positioningOverride()?.side ?? this._sideInput() ?? this.positioningDefaults.side,\n );\n\n /**\n * Per-instance override for the alignment along the chosen `side`. When\n * `undefined` (default), falls back to the scope default. Aliased to `align`;\n * consumers bind `[align]=\"...\"` and read the effective value via the public\n * {@link align} computed.\n */\n readonly _alignInput = input<FloatingAlign | undefined>(undefined, { alias: 'align' });\n\n /** Effective alignment: the per-open override, else the `align` input, else the scope default. */\n readonly align = computed<FloatingAlign>(\n () => this.positioningOverride()?.align ?? this._alignInput() ?? this.positioningDefaults.align,\n );\n\n /**\n * Per-instance override for the gap (px) between trigger and content along\n * the main axis. When `undefined` (default), falls back to the scope default.\n * Aliased to `sideOffset`; consumers bind `[sideOffset]=\"...\"` and read the\n * effective value via the public {@link sideOffset} computed.\n */\n readonly _sideOffsetInput = input(undefined, {\n alias: 'sideOffset',\n transform: (v: unknown): number | undefined => (v == null ? undefined : numberAttribute(v)),\n });\n\n /** Effective main-axis gap (px): the per-open override, else the input, else the scope default. */\n readonly sideOffset = computed<number>(\n () =>\n this.positioningOverride()?.sideOffset ??\n this._sideOffsetInput() ??\n this.positioningDefaults.sideOffset,\n );\n\n /**\n * Per-instance gap (px) along the cross axis (parallel to `side`). Default\n * `0`. Aliased to `alignOffset`; consumers bind `[alignOffset]=\"...\"` and read\n * the effective value via the public {@link alignOffset} computed.\n */\n readonly _alignOffsetInput = input(ANCHORED_POSITIONING_DEFAULTS.alignOffset, {\n alias: 'alignOffset',\n transform: numberAttribute,\n });\n\n /** Effective cross-axis gap (px): the per-open override, else the `alignOffset` input. */\n readonly alignOffset = computed<number>(\n () => this.positioningOverride()?.alignOffset ?? this._alignOffsetInput(),\n );\n\n /**\n * When `true` (default), `flip` and `shift` keep the overlay inside the\n * viewport. Disable for strict positioning where overflow is acceptable.\n */\n readonly avoidCollisions = input(ANCHORED_POSITIONING_DEFAULTS.avoidCollisions, {\n transform: booleanAttribute,\n });\n\n /**\n * Per-instance override for the padding (px) applied uniformly to the `flip`,\n * `shift`, and `size` middlewares. When `undefined` (default), falls back to\n * the scope default. Aliased to `collisionPadding`; consumers bind\n * `[collisionPadding]=\"...\"` and read the effective value via the public\n * {@link collisionPadding} computed.\n */\n readonly _collisionPaddingInput = input(undefined, {\n alias: 'collisionPadding',\n transform: (v: unknown): number | undefined => (v == null ? undefined : numberAttribute(v)),\n });\n\n /** Effective collision padding (px): the `collisionPadding` input when set, else the scope default. */\n readonly collisionPadding = computed<number>(\n () => this._collisionPaddingInput() ?? this.positioningDefaults.collisionPadding,\n );\n\n /**\n * Stickiness behaviour for `shift`. `'partial'` (default) lets the overlay\n * shift to stay visible. `'always'` keeps the requested placement even\n * off-screen.\n */\n readonly sticky = input<'partial' | 'always' | false>(ANCHORED_POSITIONING_DEFAULTS.sticky);\n\n /**\n * When `true`, sets `data-detached=\"\"` while the trigger has scrolled off all\n * clipping ancestors.\n */\n readonly hideWhenDetached = input(ANCHORED_POSITIONING_DEFAULTS.hideWhenDetached, {\n transform: booleanAttribute,\n });\n\n /**\n * When `true` (default), the content is clipped until floating-ui resolves\n * its first position, preventing a flash at the viewport corner. Set to\n * `false` so a dramatic `animate.enter` plays from its first frame (the\n * surface may flash briefly at the unresolved position while positioning\n * computes).\n */\n readonly clipUntilPositioned = input(ANCHORED_POSITIONING_DEFAULTS.clipUntilPositioned, {\n transform: booleanAttribute,\n });\n}\n","import { booleanAttribute, computed, Directive, input, numberAttribute } from '@angular/core';\n\nimport { ANCHORED_POSITIONING_DEFAULTS } from './anchored-positioning-inputs';\nimport type { FloatingAlign, FloatingSide } from './floating';\n\n/**\n * The four positioning seeds a trigger-anchored overlay root resolves from its\n * own scoped defaults provider (`provideForPopoverDefaults`,\n * `provideForSelectDefaults`, …), rather than from the shared\n * {@link ANCHORED_POSITIONING_DEFAULTS} constant. A root's `ForXDefaults`\n * interface `extends` this whenever all four keys are plain values, so the\n * shared seed contract stays typed identically across roots, and every concrete\n * {@link AnchoredOverlayPositioningBase} subclass supplies an instance of it\n * through its `positioningDefaults` accessor.\n *\n * A root whose library fallback for one seed is *derived* rather than fixed —\n * MenuSub's writing-direction `side` — declares that key nullable on its own\n * defaults interface and resolves it inside `positioningDefaults`, so what the\n * base reads is always a settled value.\n */\nexport interface AnchoredPositioningSeedDefaults {\n /** Side the overlay is anchored to when the `side` input is unset. */\n side: FloatingSide;\n /** Alignment along the chosen `side` when the `align` input is unset. */\n align: FloatingAlign;\n /** Gap (px) between trigger and content along the main axis when the `sideOffset` input is unset. */\n sideOffset: number;\n /** Padding (px) applied uniformly to `flip` / `shift` / `size` when the `collisionPadding` input is unset. */\n collisionPadding: number;\n}\n\n/**\n * Per-open override of the four **placement** values, resolved ahead of the\n * root's own inputs. It exists for the menu roots, where one surface is shared\n * by heterogeneous openers and the opener that fired legitimately decides the\n * placement (`MenuOpenerPositioning` is the shape flowing through\n * `[menuPositioning]`); every other root inherits the base's `null` and\n * resolves its inputs directly.\n *\n * Only the four placement values are overridable. The rest of the surface\n * (`avoidCollisions`, `collisionPadding`, `sticky`, …) is collision / viewport\n * policy for the overlay rather than a property of what opened it.\n */\nexport interface AnchoredPositioningOverride {\n /** Side the overlay is anchored to for this open. */\n readonly side?: FloatingSide;\n /** Alignment along the chosen `side` for this open. */\n readonly align?: FloatingAlign;\n /** Gap (px) along the main axis for this open. */\n readonly sideOffset?: number;\n /** Gap (px) along the cross axis for this open. */\n readonly alignOffset?: number;\n}\n\n/**\n * Abstract base for the trigger-anchored overlay roots. It single-sources the\n * nine shared floating-ui positioning inputs and the five effective computeds\n * over them, so the declarations live in one place instead of being copied per\n * root.\n *\n * Each of the four placement values resolves in the same three steps — the\n * per-open {@link positioningOverride}, then the root's own input, then the\n * scope default read through {@link positioningDefaults}. The five non-placement\n * inputs (`avoidCollisions` / `sticky` / `hideWhenDetached` /\n * `clipUntilPositioned`, plus `alignOffset`'s own library fallback) default from\n * the shared {@link ANCHORED_POSITIONING_DEFAULTS} constant.\n *\n * `arrowPadding` is **not** here: floating-ui installs the `arrow` middleware\n * only when an arrow element is supplied, so it belongs to the three roots that\n * ship one — `[forPopover]`, `[forTooltip]`, `[forHoverCard]` — each declaring\n * the input itself, seeded from its own defaults provider.\n *\n * Roots that must also extend `FormUiControlBase` reach the identical block\n * through `AnchoredFormValueControlBase` instead.\n */\n@Directive()\nexport abstract class AnchoredOverlayPositioningBase {\n /**\n * The four positioning seeds this root resolves from its own scoped defaults\n * provider. Concrete roots implement it with\n * `protected readonly positioningDefaults = inject(FOR_X_DEFAULTS)`, or with\n * a getter over a `computed` when one seed is derived (writing direction).\n */\n protected abstract readonly positioningDefaults: AnchoredPositioningSeedDefaults;\n\n /**\n * Placement override for the current open, resolved ahead of this root's own\n * inputs. `null` (the default) leaves the inputs in charge; the menu roots\n * override it with the active opener's `[menuPositioning]`.\n */\n protected positioningOverride(): AnchoredPositioningOverride | null {\n return null;\n }\n\n /**\n * Per-instance override for the side the overlay is anchored to. Pair with\n * `align` for the full positioning API. When `undefined` (default), falls\n * back to the scope default. Aliased to `side`; consumers bind `[side]=\"...\"`\n * and read the effective value via the public {@link side} computed.\n */\n readonly _sideInput = input<FloatingSide | undefined>(undefined, { alias: 'side' });\n\n /** Effective anchor side: the per-open override, else the `side` input, else the scope default. */\n readonly side = computed<FloatingSide>(\n () => this.positioningOverride()?.side ?? this._sideInput() ?? this.positioningDefaults.side,\n );\n\n /**\n * Per-instance override for the alignment along the chosen `side`. When\n * `undefined` (default), falls back to the scope default. Aliased to `align`;\n * consumers bind `[align]=\"...\"` and read the effective value via the public\n * {@link align} computed.\n */\n readonly _alignInput = input<FloatingAlign | undefined>(undefined, { alias: 'align' });\n\n /** Effective alignment: the per-open override, else the `align` input, else the scope default. */\n readonly align = computed<FloatingAlign>(\n () => this.positioningOverride()?.align ?? this._alignInput() ?? this.positioningDefaults.align,\n );\n\n /**\n * Per-instance override for the gap (px) between trigger and content along\n * the main axis. When `undefined` (default), falls back to the scope default.\n * Aliased to `sideOffset`; consumers bind `[sideOffset]=\"...\"` and read the\n * effective value via the public {@link sideOffset} computed.\n */\n readonly _sideOffsetInput = input(undefined, {\n alias: 'sideOffset',\n transform: (v: unknown): number | undefined => (v == null ? undefined : numberAttribute(v)),\n });\n\n /** Effective main-axis gap (px): the per-open override, else the input, else the scope default. */\n readonly sideOffset = computed<number>(\n () =>\n this.positioningOverride()?.sideOffset ??\n this._sideOffsetInput() ??\n this.positioningDefaults.sideOffset,\n );\n\n /**\n * Per-instance gap (px) along the cross axis (parallel to `side`). Default\n * `0`. Aliased to `alignOffset`; consumers bind `[alignOffset]=\"...\"` and read\n * the effective value via the public {@link alignOffset} computed.\n */\n readonly _alignOffsetInput = input(ANCHORED_POSITIONING_DEFAULTS.alignOffset, {\n alias: 'alignOffset',\n transform: numberAttribute,\n });\n\n /** Effective cross-axis gap (px): the per-open override, else the `alignOffset` input. */\n readonly alignOffset = computed<number>(\n () => this.positioningOverride()?.alignOffset ?? this._alignOffsetInput(),\n );\n\n /**\n * When `true` (default), `flip` and `shift` keep the overlay inside the\n * viewport. Disable for strict positioning where overflow is acceptable.\n */\n readonly avoidCollisions = input(ANCHORED_POSITIONING_DEFAULTS.avoidCollisions, {\n transform: booleanAttribute,\n });\n\n /**\n * Per-instance override for the padding (px) applied uniformly to the `flip`,\n * `shift`, and `size` middlewares. When `undefined` (default), falls back to\n * the scope default. Aliased to `collisionPadding`; consumers bind\n * `[collisionPadding]=\"...\"` and read the effective value via the public\n * {@link collisionPadding} computed.\n */\n readonly _collisionPaddingInput = input(undefined, {\n alias: 'collisionPadding',\n transform: (v: unknown): number | undefined => (v == null ? undefined : numberAttribute(v)),\n });\n\n /** Effective collision padding (px): the `collisionPadding` input when set, else the scope default. */\n readonly collisionPadding = computed<number>(\n () => this._collisionPaddingInput() ?? this.positioningDefaults.collisionPadding,\n );\n\n /**\n * Stickiness behaviour for `shift`. `'partial'` (default) lets the overlay\n * shift to stay visible. `'always'` keeps the requested placement even\n * off-screen.\n */\n readonly sticky = input<'partial' | 'always' | false>(ANCHORED_POSITIONING_DEFAULTS.sticky);\n\n /**\n * When `true`, sets `data-detached=\"\"` while the trigger has scrolled off all\n * clipping ancestors.\n */\n readonly hideWhenDetached = input(ANCHORED_POSITIONING_DEFAULTS.hideWhenDetached, {\n transform: booleanAttribute,\n });\n\n /**\n * When `true` (default), the content is clipped until floating-ui resolves\n * its first position, preventing a flash at the viewport corner. Set to\n * `false` so a dramatic `animate.enter` plays from its first frame (the\n * surface may flash briefly at the unresolved position while positioning\n * computes).\n */\n readonly clipUntilPositioned = input(ANCHORED_POSITIONING_DEFAULTS.clipUntilPositioned, {\n transform: booleanAttribute,\n });\n}\n","/**\n * A single self-clearing debounce timer: the `Math.max(0, delay)` clamp, the\n * `delay === 0` synchronous fast-path, and the lone pending\n * `setTimeout` / `clearTimeout` pair.\n *\n * The hover-driven menus (`[forMenuSub]`, `[forMenubar]`, `[forNavigationMenu]`)\n * each hand-rolled this exact timer arming/clearing under their own divergent\n * open/close policy (chain keep-alive, hover-after-open, per-value cancel\n * guards, skip-delay). This factory owns only the timing mechanics so those\n * policies stay at the call site — the caller arms with `schedule(delay)`,\n * which clears any in-flight timer first, runs `run` immediately when the\n * clamped delay is `0`, else fires it once after the delay.\n *\n * Internal core tier — exported from `forty-cdk/core` for the library's own\n * entry points, with no semver guarantee.\n */\nexport interface DebouncedAction {\n /**\n * Arm the action after `delay` ms (clamped to `>= 0`). Clears any pending\n * timer first; a clamped delay of `0` runs `run` synchronously.\n */\n schedule(delay: number): void;\n /** Cancel a pending action without running it. Safe with no pending timer. */\n cancel(): void;\n /** `true` while an action is armed but not yet fired. */\n isPending(): boolean;\n}\n\n/**\n * Builds a {@link DebouncedAction} around `run`. Framework-free.\n */\nexport function createDebouncedAction(run: () => void): DebouncedAction {\n let timer: ReturnType<typeof setTimeout> | null = null;\n\n function cancel(): void {\n if (timer !== null) {\n clearTimeout(timer);\n timer = null;\n }\n }\n\n function schedule(delay: number): void {\n cancel();\n const clamped = Math.max(0, delay);\n if (clamped === 0) {\n run();\n return;\n }\n timer = setTimeout(() => {\n timer = null;\n run();\n }, clamped);\n }\n\n return {\n schedule,\n cancel,\n isPending: () => timer !== null,\n };\n}\n","import { effect, type Signal, untracked, type WritableSignal } from '@angular/core';\n\n/**\n * Per-injector-scope coordinator the hover-intent scheduler consults to decide\n * whether the open delay should be skipped, and to open the skip-delay window\n * when a primitive finishes closing. Both `TooltipCoordinator` and\n * `HoverCardCoordinator` satisfy this contract structurally.\n */\nexport interface HoverIntentCoordinator {\n /** True while a peer in this scope just closed and the next open is instant. */\n skipDelay(): boolean;\n /** Opens the skip-delay window. Called by the scheduler when it closes. */\n startSkipDelay(): void;\n}\n\n/**\n * Inputs for {@link createHoverIntent}. Delays are passed as accessor\n * functions so the scheduler reads resolved values (per-instance override or\n * scope default) at the moment a timer is armed.\n */\nexport interface HoverIntentOptions {\n /** Writable open-state signal the scheduler flips. */\n open: WritableSignal<boolean>;\n /** Whether all hover / focus interaction is currently ignored. */\n isDisabled: () => boolean;\n /** Resolved open delay (ms) to use when arming an open timer. */\n openDelay: () => number;\n /** Resolved close delay (ms) to use when arming a close timer. */\n closeDelay: () => number;\n /** Skip-delay coordinator shared by peers in the same scope. */\n coordinator: HoverIntentCoordinator;\n}\n\n/**\n * Hover-intent scheduler handle returned by {@link createHoverIntent}.\n */\nexport interface HoverIntentScheduler {\n /** Schedule the open after the resolved open delay (instant when delay is 0 or skipped). */\n scheduleOpen(): void;\n /** Schedule the close after the resolved close delay; `immediate` bypasses the delay. */\n scheduleClose(immediate: boolean): void;\n /** Cancel any pending open / close timer without changing state. */\n cancelPending(): void;\n /** Whether an open or close timer is pending. */\n isPending(): boolean;\n}\n\n/**\n * Shared hover-intent scheduler for Tooltip and Hover-card.\n *\n * Both primitives carry an identical open / close timer with skip-delay\n * coordination and `Math.max(0, …)` guards; this framework-free factory holds\n * the single pending timer and the open / close logic, parameterized by the\n * resolved open / close delays plus a {@link HoverIntentCoordinator}. The\n * directive constructs it once (after its `open` signal exists) and delegates\n * its public scheduling methods to the returned handle.\n *\n * Internal core tier — exported from `forty-cdk/core` for the library's own\n * entry points, with no semver guarantee.\n */\nexport function createHoverIntent(options: HoverIntentOptions): HoverIntentScheduler {\n let pendingTimer: ReturnType<typeof setTimeout> | null = null;\n\n function cancelPending(): void {\n if (pendingTimer !== null) {\n clearTimeout(pendingTimer);\n pendingTimer = null;\n }\n }\n\n function close(): void {\n options.open.set(false);\n options.coordinator.startSkipDelay();\n }\n\n function scheduleOpen(): void {\n cancelPending();\n if (options.isDisabled()) {\n return;\n }\n if (options.open()) {\n return;\n }\n const base = options.coordinator.skipDelay() ? 0 : options.openDelay();\n const delay = Math.max(0, base);\n if (delay === 0) {\n options.open.set(true);\n return;\n }\n pendingTimer = setTimeout(() => {\n pendingTimer = null;\n if (options.isDisabled()) {\n return;\n }\n options.open.set(true);\n }, delay);\n }\n\n function scheduleClose(immediate: boolean): void {\n cancelPending();\n if (!options.open()) {\n return;\n }\n if (immediate) {\n close();\n return;\n }\n const delay = Math.max(0, options.closeDelay());\n if (delay === 0) {\n close();\n return;\n }\n pendingTimer = setTimeout(() => {\n pendingTimer = null;\n close();\n }, delay);\n }\n\n return { scheduleOpen, scheduleClose, cancelPending, isPending: () => pendingTimer !== null };\n}\n\n/**\n * Inputs for {@link forceCloseWhenDisabled}.\n */\nexport interface ForceCloseWhenDisabledOptions {\n /** Open-state signal that is force-closed when `disabled` flips to true. */\n open: WritableSignal<boolean>;\n /** Whether all hover / focus interaction is currently ignored. */\n disabled: Signal<boolean>;\n /** Imperative cleanup run before the force-close (cancel any pending timers). */\n onForceClose: () => void;\n}\n\n/**\n * The single audited place that force-closes a hover-driven overlay when its\n * `disabled` input flips to `true` while open.\n *\n * Tooltip and Hover-card each carried a byte-identical copy of this reaction;\n * it is the **one sanctioned exception** to the project's \"never propagate\n * state inside `effect()`\" rule, so it must live in exactly one place rather\n * than two carve-outs to audit. The hover scheduler already early-returns on\n * `disabled()`, so hover / focus can't open a disabled overlay; this isolated\n * reaction only covers the remaining path — an open overlay being disabled out\n * from under itself.\n *\n * The `open` read is `untracked` so the effect never re-runs as a function of\n * `open` (no read+write cycle on the same signal); it reacts to `disabled`\n * alone. It integrates the disabled gate with the public `model()` instead of\n * wrapping the model in a parallel signal.\n *\n * Must be called from an injection context (registers an `effect`). Internal\n * core tier — no semver guarantee.\n */\nexport function forceCloseWhenDisabled(options: ForceCloseWhenDisabledOptions): void {\n // @sanctioned-effect(untracked-read): the `open` read is untracked, so the\n // effect reacts to `disabled` alone and never cycles on the signal it writes.\n effect(() => {\n if (options.disabled() && untracked(options.open)) {\n options.onForceClose();\n options.open.set(false);\n }\n });\n}\n","import { isHoverCapablePointer } from 'forty-cdk/core';\nimport type { FloatingSide } from '../floating/floating';\n\n/**\n * Pointer-grace (\"safe triangle\") helper.\n *\n * When a mouse leaves a submenu trigger heading toward the submenu content,\n * a naive \"close on pointer-leave\" would dismiss the submenu the moment the\n * cursor crosses the gap between the trigger and the content. The fix native\n * desktop menus use is a *safe triangle*: a polygon drawn\n * from the cursor's exit point to the near edge of the submenu content. While\n * the pointer stays inside that polygon it is assumed to be travelling toward\n * the submenu, so the close is held off.\n *\n * This module keeps no Angular DI surface — the geometry is pure functions\n * (unit-tested in `pointer-grace.spec.ts`) and {@link attachPointerGrace} is a\n * plain `addEventListener` wrapper returning a cleanup, wired by the directive\n * through its `DestroyRef`. The DOM-measured inputs (cursor position, content\n * rect, resolved side) are supplied by the caller, so the geometry stays\n * testable without faking layout.\n */\n\n/** A point in client (viewport) coordinates. */\nexport interface Point {\n readonly x: number;\n readonly y: number;\n}\n\n/** The subset of `DOMRect` the grace polygon needs. */\nexport interface GraceRect {\n readonly top: number;\n readonly right: number;\n readonly bottom: number;\n readonly left: number;\n}\n\n/**\n * Resolves which side a submenu actually rendered on by comparing the\n * geometry of the trigger and content rects, independent of any requested\n * placement. Picks the axis (horizontal vs vertical) with the larger\n * centre-to-centre separation, then the direction along it.\n *\n * This is the load-bearing fix for the safe-triangle: `injectFloating` only\n * writes the resolved `data-side` inside the async `computePosition().then()`,\n * so on the first hover-open it is still `undefined` and a `flip` near a\n * viewport edge would have armed the grace polygon toward the *requested*\n * side. Deriving the side from the live rects at arm time reflects the real\n * placement even before positioning settles.\n *\n * @param trigger Sub-trigger rect (client coords), from `getBoundingClientRect`.\n * @param content Submenu content rect (client coords), from `getBoundingClientRect`.\n */\nexport function resolveGraceSide(trigger: GraceRect, content: GraceRect): FloatingSide {\n const triggerCenterX = (trigger.left + trigger.right) / 2;\n const triggerCenterY = (trigger.top + trigger.bottom) / 2;\n const contentCenterX = (content.left + content.right) / 2;\n const contentCenterY = (content.top + content.bottom) / 2;\n const dx = contentCenterX - triggerCenterX;\n const dy = contentCenterY - triggerCenterY;\n if (Math.abs(dx) >= Math.abs(dy)) {\n return dx >= 0 ? 'right' : 'left';\n }\n return dy >= 0 ? 'bottom' : 'top';\n}\n\n/** An ordered list of vertices describing a simple (non-self-intersecting) polygon. */\nexport type Polygon = readonly Point[];\n\n/**\n * Pixels the cursor apex is pulled *back* (away from the content) when the\n * polygon is built, so the exit point sits reliably inside the polygon even\n * after sub-pixel rounding of the pointer-leave coordinates.\n */\nconst GRACE_BLEED_PX = 5;\n\n/**\n * Standard even-odd ray-casting point-in-polygon test. Returns `true` when\n * {@link point} lies inside {@link polygon}. Points exactly on an edge are\n * reported inconsistently (as with any ray-cast) — that is acceptable here\n * because the bleed keeps the cursor apex strictly inside and the close path\n * is delay-guarded, so a single ambiguous edge sample never decides the\n * outcome.\n */\nexport function isPointInPolygon(point: Point, polygon: Polygon): boolean {\n let inside = false;\n for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {\n const vi = polygon[i]!;\n const vj = polygon[j]!;\n const intersects =\n vi.y > point.y !== vj.y > point.y &&\n point.x < ((vj.x - vi.x) * (point.y - vi.y)) / (vj.y - vi.y) + vi.x;\n if (intersects) {\n inside = !inside;\n }\n }\n return inside;\n}\n\n/**\n * Builds the safe-triangle polygon for a submenu opening on {@link side}.\n *\n * The polygon is a pentagon: the (bleeded) cursor apex plus the four corners\n * of the content rect, ordered so the cursor is adjacent to the two corners of\n * the content edge *nearest* the trigger. That shape covers both the triangle\n * the pointer travels through and the content itself, so the pointer is \"in\n * the grace area\" right up until it reaches the content.\n *\n * @param cursor Pointer position (client coords) captured at pointer-leave.\n * @param rect Submenu content rect (client coords), from `getBoundingClientRect`.\n * @param side Resolved side the content actually rendered on, from {@link resolveGraceSide}.\n */\nexport function buildSubmenuGracePolygon(\n cursor: Point,\n rect: GraceRect,\n side: FloatingSide,\n): Polygon {\n const { top, right, bottom, left } = rect;\n switch (side) {\n // Content to the right; near edge = content's left edge.\n case 'right':\n return [\n { x: cursor.x - GRACE_BLEED_PX, y: cursor.y },\n { x: left, y: top },\n { x: right, y: top },\n { x: right, y: bottom },\n { x: left, y: bottom },\n ];\n // Content to the left; near edge = content's right edge.\n case 'left':\n return [\n { x: cursor.x + GRACE_BLEED_PX, y: cursor.y },\n { x: right, y: top },\n { x: left, y: top },\n { x: left, y: bottom },\n { x: right, y: bottom },\n ];\n // Content below; near edge = content's top edge.\n case 'bottom':\n return [\n { x: cursor.x, y: cursor.y - GRACE_BLEED_PX },\n { x: left, y: top },\n { x: left, y: bottom },\n { x: right, y: bottom },\n { x: right, y: top },\n ];\n // Content above; near edge = content's bottom edge.\n case 'top':\n return [\n { x: cursor.x, y: cursor.y + GRACE_BLEED_PX },\n { x: left, y: bottom },\n { x: left, y: top },\n { x: right, y: top },\n { x: right, y: bottom },\n ];\n }\n}\n\n/** Options for {@link attachPointerGrace}. */\nexport interface PointerGraceOptions {\n /**\n * Which pointer moves the polygon tracks; a move it rejects is ignored.\n * Defaults to `isHoverCapablePointer` (mouse only), the menu family's hover\n * vocabulary. A caller whose trigger also opens on pen hover passes\n * `isNonTouchPointer`, so the pen that opened the surface can close it.\n */\n readonly tracksPointer?: (event: Pick<PointerEvent, 'pointerType'>) => boolean;\n readonly exitsOutOfRange?: boolean;\n}\n\n/**\n * Attaches a document-level `pointermove` listener that calls {@link onExit}\n * on every tracked move outside {@link polygon}, until the returned cleanup\n * disarms it. With {@link PointerGraceOptions.exitsOutOfRange}, a tracked\n * `pointerout` with no `relatedTarget` (the pointer left the document, or a pen\n * left the digitizer's hover range) is an exit too. The caller arms this on a\n * trigger pointer-leave and disarms it once the pointer reaches the content,\n * the grace window elapses, or the surface is otherwise resolved.\n *\n * Moves {@link PointerGraceOptions.tracksPointer} rejects are ignored: touch\n * opens by tap, never by hover, so a touch move has no safe triangle to leave.\n *\n * Static-polygon assumption: {@link polygon} is captured once at arm time and\n * never re-measured for the lifetime of this listener. If the submenu content\n * repositions (a flip, a scroll, a resize) while the grace window is open, the\n * polygon goes stale and no longer matches the content's live rect. This is an\n * accepted trade-off: the grace window is short (a single pointer traversal\n * from trigger to content) and is itself delay-guarded downstream, so a\n * mid-window reposition is out of scope. Callers that need re-measurement\n * should re-arm (call the cleanup, then re-attach with a fresh polygon) rather\n * than expecting this handler to track layout.\n *\n * @returns A cleanup that aborts the listener's `AbortSignal`. Idempotent —\n * safe to store and call from a `DestroyRef` hook after an earlier disarm.\n */\nexport function attachPointerGrace(\n doc: Document,\n polygon: Polygon,\n onExit: () => void,\n options: PointerGraceOptions = {},\n): () => void {\n const tracksPointer = options.tracksPointer ?? isHoverCapablePointer;\n const onMove = (event: PointerEvent): void => {\n if (!tracksPointer(event)) {\n return;\n }\n if (!isPointInPolygon({ x: event.clientX, y: event.clientY }, polygon)) {\n onExit();\n }\n };\n const controller = new AbortController();\n doc.addEventListener('pointermove', onMove, { signal: controller.signal });\n if (options.exitsOutOfRange) {\n const onOut = (event: PointerEvent): void => {\n if (tracksPointer(event) && event.relatedTarget === null) {\n onExit();\n }\n };\n doc.addEventListener('pointerout', onOut, { signal: controller.signal });\n }\n return () => controller.abort();\n}\n","import { isNonTouchPointer } from 'forty-cdk/core';\n\nimport type { FloatingSide } from '../floating/floating';\nimport {\n attachPointerGrace,\n buildSubmenuGracePolygon,\n type Point,\n resolveGraceSide,\n} from '../pointer-grace/pointer-grace';\n\n/**\n * Inputs for {@link createHoverSurfaceState}.\n */\nexport interface HoverSurfaceOptions {\n /** The registered trigger, measured to orient the grace polygon. */\n readonly trigger: () => HTMLElement | null;\n /** The registered content the grace polygon bridges toward. */\n readonly content: () => HTMLElement | null;\n /** Side the grace polygon assumes when no trigger is registered to measure. */\n readonly side: () => FloatingSide;\n /** Closes the surface once no keep-alive source is active. */\n readonly close: () => void;\n}\n\n/**\n * Keep-alive bookkeeping of a hover-scheduled overlay, returned by\n * {@link createHoverSurfaceState}.\n */\nexport interface HoverSurfaceState {\n /** Whether the trigger holds focus. */\n triggerFocused(): boolean;\n /** Whether the trigger or the content holds focus. */\n focused(): boolean;\n /** The pointer entered the trigger: marks it hovered and disarms the grace. */\n enterTrigger(): void;\n /** The pointer left the trigger: clears its hover, leaving the close to the caller. */\n leaveTrigger(): void;\n /** The trigger received focus. */\n focusTrigger(): void;\n /** The trigger lost focus: closes when nothing else keeps the surface alive. */\n blurTrigger(): void;\n /** The pointer entered the content: marks it hovered and disarms the grace. */\n enterContent(): void;\n /** The pointer left the content: closes when nothing else keeps the surface alive. */\n leaveContent(): void;\n /** Focus entered the content. */\n focusContent(): void;\n /** Focus left the content: closes when nothing else keeps the surface alive. */\n blurContent(): void;\n /** The trigger unmounted: clears its hover and focus and disarms the grace. */\n resetTrigger(): void;\n /** The content unmounted: clears its hover and focus and disarms the grace. */\n resetContent(): void;\n /** Closes unless the trigger or the content is hovered or focused. */\n closeIfInactive(): void;\n /**\n * Arms a pointer-grace polygon from `cursor` toward the content, so the\n * pointer can cross the gap without closing. Leaving it disarms the grace and\n * closes when nothing else keeps the surface alive. Without registered\n * content it closes the same way at once.\n */\n armGrace(cursor: Point): void;\n /** Detaches an armed grace polygon. Safe when none is armed. */\n disarmGrace(): void;\n}\n\n/**\n * Shared keep-alive state for Tooltip and Hover-card: which side of the\n * overlay is hovered or focused, and the pointer-grace bridge between them.\n * Each `reset*` clears one side when its element unmounts, since an element\n * removed under the pointer never reports `pointerleave` or `blur`.\n *\n * Internal core tier — exported from `forty-cdk/core-overlay` for the\n * library's own entry points, with no semver guarantee.\n */\nexport function createHoverSurfaceState(options: HoverSurfaceOptions): HoverSurfaceState {\n let triggerHovered = false;\n let triggerFocused = false;\n let contentHovered = false;\n let contentFocused = false;\n let detachGrace: (() => void) | null = null;\n\n function disarmGrace(): void {\n if (detachGrace) {\n detachGrace();\n detachGrace = null;\n }\n }\n\n function closeIfInactive(): void {\n if (triggerHovered || triggerFocused || contentHovered || contentFocused) {\n return;\n }\n options.close();\n }\n\n function armGrace(cursor: Point): void {\n const content = options.content();\n if (!content) {\n closeIfInactive();\n return;\n }\n const rect = content.getBoundingClientRect();\n const trigger = options.trigger();\n const side = trigger ? resolveGraceSide(trigger.getBoundingClientRect(), rect) : options.side();\n const polygon = buildSubmenuGracePolygon(cursor, rect, side);\n disarmGrace();\n detachGrace = attachPointerGrace(\n content.ownerDocument,\n polygon,\n () => {\n disarmGrace();\n closeIfInactive();\n },\n { tracksPointer: isNonTouchPointer, exitsOutOfRange: true },\n );\n }\n\n return {\n triggerFocused: () => triggerFocused,\n focused: () => triggerFocused || contentFocused,\n enterTrigger: () => {\n triggerHovered = true;\n disarmGrace();\n },\n leaveTrigger: () => {\n triggerHovered = false;\n },\n focusTrigger: () => {\n triggerFocused = true;\n },\n blurTrigger: () => {\n triggerFocused = false;\n closeIfInactive();\n },\n enterContent: () => {\n contentHovered = true;\n disarmGrace();\n },\n leaveContent: () => {\n contentHovered = false;\n closeIfInactive();\n },\n focusContent: () => {\n contentFocused = true;\n },\n blurContent: () => {\n contentFocused = false;\n closeIfInactive();\n },\n resetTrigger: () => {\n triggerHovered = false;\n triggerFocused = false;\n disarmGrace();\n },\n resetContent: () => {\n contentHovered = false;\n contentFocused = false;\n disarmGrace();\n },\n closeIfInactive,\n armGrace,\n disarmGrace,\n };\n}\n","import { DOCUMENT, Injectable, PLATFORM_ID, inject } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\n\nimport {\n composedContains,\n composedParentElement,\n MODAL_EXEMPT_ATTRIBUTE,\n MODAL_PEER_ATTRIBUTE,\n} from 'forty-cdk/core';\n\ninterface SnapshotEntry {\n readonly el: HTMLElement;\n readonly hadInert: boolean;\n readonly prevAriaHidden: string | null;\n}\n\nexport interface InertSiblingsHandle {\n /** Pop this owner off the stack and recompute. */\n deactivate(): void;\n /** Whether this handle is still on the stack. */\n readonly isActive: boolean;\n}\n\ninterface RootState {\n readonly root: HTMLElement;\n readonly stack: HTMLElement[];\n appliedSnapshot: SnapshotEntry[];\n observer: MutationObserver | null;\n}\n\ntype PeerAnchors = readonly Element[] | 'always';\n\n/**\n * Marks every direct child of a **root element** (default `document.body`,\n * or a positioned container when a region-scoped modal passes one)\n * other than the topmost active owner (and any peer of that owner) as `inert` and\n * `aria-hidden=\"true\"` while at least one owner is active on that root.\n * Restores each touched element to its exact prior state once the last\n * owner deactivates.\n *\n * `aria-modal=\"true\"` alone is insufficient: Safari with VoiceOver, among other combinations, still\n * announces siblings of an aria-modal node unless the rest of the document is explicitly hidden.\n *\n * **Stacking.** Each root keeps its own owner stack, snapshot and `MutationObserver`, so a\n * `document.body` root and a container root are fully independent. The element-level outcome is\n * recomputed from the current topmost owner whenever the stack changes: the previous outcome is\n * reverted to its snapshot first, then a fresh one is applied. Closing owners out of LIFO order\n * therefore still leaves a coherent document, and full restoration runs when the stack empties.\n *\n * **Portals.** The owner need not be a direct child of the root — the root-level child that is an\n * ancestor of the owner is resolved and its subtree excluded, so an in-place dialog keeps its\n * enclosing app shell interactive. That walk climbs the composed tree, so an owner rendered inside\n * a shadow root still resolves to the root-level child hosting it.\n *\n * **Peers.** An overlay registered through {@link InertSiblingsStack.registerPeer} is excluded from\n * the snapshot only while it belongs to the topmost owner of the root it sits in, so the peer of a\n * background modal is inerted again under a nested one. The stack reflects that state as\n * `data-for-modal-peer` on the registered host. An element carrying the attribute without being\n * registered (a backdrop) is excluded under every owner, as is one carrying\n * {@link MODAL_EXEMPT_ATTRIBUTE}, which additionally opts out of the dismissible layer.\n *\n * **Late siblings.** While any owner is active, a `MutationObserver` inerts each newly added\n * sibling under the same rules, so an element portaled to the root after activation is isolated and\n * restored too.\n *\n * SSR: every operation is a no-op on the server, since `activate()` is only ever called from\n * `afterNextRender`.\n */\n@Injectable({ providedIn: 'root' })\nexport class InertSiblingsStack {\n readonly #document = inject(DOCUMENT);\n readonly #isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n readonly #roots = new Map<HTMLElement, RootState>();\n readonly #peers = new Map<HTMLElement, PeerAnchors>();\n\n /**\n * Push `owner` onto the inert-siblings stack for `root` (default\n * `document.body`) and (re)apply the isolation outcome for the new topmost\n * owner. Returns a handle whose `deactivate()` pops this specific owner —\n * order-safe, so closing out of LIFO order works.\n *\n * When `root` is a positioned container (e.g. a region-scoped modal), only\n * that container's other children are inerted; body siblings outside the\n * container stay fully interactive.\n */\n activate(owner: HTMLElement, root: HTMLElement = this.#document.body): InertSiblingsHandle {\n if (!this.#isBrowser) {\n return {\n deactivate: () => {},\n get isActive(): boolean {\n return false;\n },\n };\n }\n const state = this.#stateFor(root);\n this.#revertAppliedSnapshot(state);\n if (state.stack.length === 0) {\n this.#startObserving(state);\n }\n state.stack.push(owner);\n this.#applyForCurrentTopmost(state);\n this.#syncPeerAttributes();\n\n let active = true;\n return {\n get isActive(): boolean {\n return active;\n },\n deactivate: (): void => {\n if (!active) {\n return;\n }\n active = false;\n const idx = state.stack.indexOf(owner);\n if (idx === -1) {\n return;\n }\n this.#revertAppliedSnapshot(state);\n state.stack.splice(idx, 1);\n if (state.stack.length > 0) {\n this.#applyForCurrentTopmost(state);\n } else {\n this.#stopObserving(state);\n this.#roots.delete(root);\n }\n this.#syncPeerAttributes();\n },\n };\n }\n\n /**\n * Whether an overlay anchored to `anchor` should be left interactive over\n * the active modal — i.e. treated as a peer of the topmost owner instead of\n * inerted. Returns `true` only while at least one owner is active AND\n * `anchor` lives inside the current protected root for any active root, or\n * inside a registered peer that does, which means the overlay was opened\n * from within a modal (e.g. a Select / DropdownMenu opened from a form inside\n * a Dialog, or a submenu opened from that DropdownMenu).\n *\n * Returns `false` when no owner is active — so an overlay opened with no\n * modal present is never pre-marked, and a modal opened later inerts it like\n * any other background sibling — and when `anchor` sits in an already-inerted\n * background subtree (a toast or a tooltip anchored to a backdrop element).\n * SSR-safe: on the server the roots map is always empty (no owner\n * activates), so this returns `false`.\n */\n ownsAnchor(anchor: Element): boolean {\n for (const state of this.#roots.values()) {\n const protectedRoot = this.#currentProtectedRoot(state);\n if (protectedRoot !== null && this.#owns(protectedRoot, [anchor], new Set())) {\n return true;\n }\n }\n return false;\n }\n\n registerPeer(host: HTMLElement, anchors: PeerAnchors): () => void {\n if (!this.#isBrowser) {\n return () => {};\n }\n this.#peers.set(host, anchors);\n this.#reapplyAll();\n return () => {\n if (this.#peers.get(host) !== anchors) {\n return;\n }\n this.#peers.delete(host);\n host.removeAttribute(MODAL_PEER_ATTRIBUTE);\n this.#reapplyAll();\n };\n }\n\n #stateFor(root: HTMLElement): RootState {\n let state = this.#roots.get(root);\n if (!state) {\n state = { root, stack: [], appliedSnapshot: [], observer: null };\n this.#roots.set(root, state);\n }\n return state;\n }\n\n #applyForCurrentTopmost(state: RootState): void {\n const protectedRoot = this.#currentProtectedRoot(state);\n if (!protectedRoot) {\n return;\n }\n\n for (const child of Array.from(state.root.children)) {\n this.#inertChild(child, protectedRoot, state);\n }\n }\n\n #inertChild(child: Element, protectedRoot: HTMLElement, state: RootState): void {\n if (!(child instanceof HTMLElement)) {\n return;\n }\n if (child === protectedRoot || child.hasAttribute(MODAL_EXEMPT_ATTRIBUTE)) {\n return;\n }\n const anchors = this.#peers.get(child);\n const exempt =\n anchors === undefined\n ? child.hasAttribute(MODAL_PEER_ATTRIBUTE)\n : anchors === 'always' || this.#owns(protectedRoot, anchors, new Set());\n if (exempt) {\n return;\n }\n if (state.appliedSnapshot.some((entry) => entry.el === child)) {\n return;\n }\n\n state.appliedSnapshot.push({\n el: child,\n hadInert: child.hasAttribute('inert'),\n prevAriaHidden: child.getAttribute('aria-hidden'),\n });\n\n child.setAttribute('inert', '');\n child.setAttribute('aria-hidden', 'true');\n }\n\n #owns(\n protectedRoot: HTMLElement,\n anchors: readonly Element[],\n visited: Set<HTMLElement>,\n ): boolean {\n return anchors.some((anchor) => {\n if (composedContains(protectedRoot, anchor)) {\n return true;\n }\n for (const [peer, peerAnchors] of this.#peers) {\n if (peerAnchors === 'always' || visited.has(peer) || !composedContains(peer, anchor)) {\n continue;\n }\n visited.add(peer);\n if (this.#owns(protectedRoot, peerAnchors, visited)) {\n return true;\n }\n }\n return false;\n });\n }\n\n #reapplyAll(): void {\n for (const state of this.#roots.values()) {\n this.#revertAppliedSnapshot(state);\n this.#applyForCurrentTopmost(state);\n }\n this.#syncPeerAttributes();\n }\n\n #syncPeerAttributes(): void {\n for (const [peer, anchors] of this.#peers) {\n peer.toggleAttribute(MODAL_PEER_ATTRIBUTE, this.#isLivePeer(peer, anchors));\n }\n }\n\n #isLivePeer(peer: HTMLElement, anchors: PeerAnchors): boolean {\n if (anchors === 'always') {\n return true;\n }\n for (const state of this.#roots.values()) {\n const protectedRoot = this.#currentProtectedRoot(state);\n if (protectedRoot !== null && this.#owns(protectedRoot, anchors, new Set())) {\n return true;\n }\n }\n return false;\n }\n\n #currentProtectedRoot(state: RootState): HTMLElement | null {\n const top = state.stack[state.stack.length - 1];\n if (!top) {\n return null;\n }\n return this.#rootLevelChild(top, state.root) ?? top;\n }\n\n #startObserving(state: RootState): void {\n const win = this.#document.defaultView;\n if (state.observer || !win || typeof win.MutationObserver !== 'function') {\n return;\n }\n state.observer = new win.MutationObserver((records) => {\n const protectedRoot = this.#currentProtectedRoot(state);\n if (!protectedRoot) {\n return;\n }\n let addedPeer = false;\n for (const record of records) {\n for (const node of Array.from(record.addedNodes)) {\n if (node instanceof HTMLElement && node.parentElement === state.root) {\n addedPeer ||= this.#peers.has(node);\n this.#inertChild(node, protectedRoot, state);\n }\n }\n }\n if (addedPeer) {\n this.#syncPeerAttributes();\n }\n });\n state.observer.observe(state.root, { childList: true });\n }\n\n #stopObserving(state: RootState): void {\n state.observer?.disconnect();\n state.observer = null;\n }\n\n #revertAppliedSnapshot(state: RootState): void {\n for (const entry of state.appliedSnapshot) {\n if (!entry.hadInert) {\n entry.el.removeAttribute('inert');\n }\n if (entry.prevAriaHidden === null) {\n entry.el.removeAttribute('aria-hidden');\n } else {\n entry.el.setAttribute('aria-hidden', entry.prevAriaHidden);\n }\n }\n state.appliedSnapshot = [];\n }\n\n #rootLevelChild(el: HTMLElement, root: HTMLElement): HTMLElement | null {\n let cur: HTMLElement = el;\n let parent = composedParentElement(cur);\n while (parent && parent !== root) {\n cur = parent;\n parent = composedParentElement(cur);\n }\n return parent === root ? cur : null;\n }\n}\n","import { computed, inject, type Signal, signal, type WritableSignal } from '@angular/core';\nimport type { ReferenceElement } from '@floating-ui/dom';\n\nimport {\n adoptHostId,\n createSingleSlot,\n IdGenerator,\n type SingleSlot,\n type SingleSlotConfig,\n} from 'forty-cdk/core';\n\n/**\n * A registered overlay element whose aria-wiring id the surface exposes. Backs\n * the trigger / content / list / input slots the overlay controllers used to\n * each hand-copy: the register step adopts a consumer-set static `id` into the\n * seeded id signal (so external `aria-labelledby` / label `for` references keep\n * resolving), the unregister step clears the element only when the same node\n * deregisters.\n *\n * Construct through {@link injectIdentifiedSlot} so the id signal is seeded from\n * the shared {@link IdGenerator} at the controller's construction.\n *\n * @typeParam E Concrete element type registered here (e.g. `HTMLInputElement`\n * for the combobox input). Defaults to `HTMLElement`.\n */\nexport class IdentifiedElementSlot<E extends HTMLElement = HTMLElement> {\n readonly #el = signal<E | null>(null);\n readonly #id: WritableSignal<string>;\n\n /** The registered element, or `null` while nothing is mounted. */\n readonly element: Signal<E | null> = this.#el.asReadonly();\n\n /** The element's aria-wiring id — the generated fallback until a static id is adopted. */\n readonly id: WritableSignal<string>;\n\n constructor(id: WritableSignal<string>) {\n this.#id = id;\n this.id = id;\n }\n\n /** Register the element, adopting a consumer-set static `id` into the id signal. */\n register(el: E): void {\n adoptHostId(el, this.#id);\n this.#el.set(el);\n }\n\n /** Deregister the element (no-op unless the same node registered). */\n unregister(el: E): void {\n if (this.#el() === el) {\n this.#el.set(null);\n }\n }\n}\n\n/**\n * A registered overlay element whose aria-wiring id the controller does not\n * own — the combobox trigger, which host-binds its own. Same register/unregister\n * identity guard as {@link IdentifiedElementSlot}, and it mints nothing, so the\n * shared {@link IdGenerator} counter does not move for the anatomies that never\n * mount here.\n */\nexport class ElementSlot<E extends HTMLElement = HTMLElement> {\n readonly #el = signal<E | null>(null);\n\n /** The registered element, or `null` while nothing is mounted. */\n readonly element: Signal<E | null> = this.#el.asReadonly();\n\n /** Register the element. */\n register(el: E): void {\n this.#el.set(el);\n }\n\n /** Deregister the element (no-op unless the same node registered). */\n unregister(el: E): void {\n if (this.#el() === el) {\n this.#el.set(null);\n }\n }\n}\n\n/**\n * The floating-ui anchor slot shared by the listbox overlays, combobox and the\n * date pickers. An explicit `[for…Anchor]` registers here; the resolved\n * anchor prefers it and otherwise walks the fallback chain (field anchor,\n * trigger, input) so a primitive without an explicit anchor keeps its\n * behaviour.\n *\n * Registrations are stacked like a core `createSingleSlot`: the newest\n * anchor is the one used, unregistering it restores the previous survivor,\n * and a second anchor still registered once the change-detection pass\n * settles warns in dev mode. A structural swap that mounts the replacement\n * anchor before destroying the outgoing one is therefore not reported.\n */\nexport class AnchorSlot {\n readonly #slot: SingleSlot<HTMLElement>;\n\n /** The explicitly-registered anchor element, or `null`. */\n readonly element: Signal<HTMLElement | null>;\n\n constructor(config: SingleSlotConfig) {\n this.#slot = createSingleSlot<HTMLElement>(config);\n this.element = this.#slot.value;\n }\n\n /**\n * Register the explicit anchor, making it the one the overlay positions\n * against. Registering the current anchor again is a no-op.\n */\n register(el: HTMLElement): void {\n if (this.element() === el) {\n return;\n }\n this.#slot.register(el);\n }\n\n /** Deregister the anchor (no-op unless the same node registered). */\n unregister(el: HTMLElement): void {\n this.#slot.unregister(el);\n }\n\n /**\n * Build the resolved-anchor signal: the explicit anchor, otherwise the first\n * non-null fallback in order (field anchor → trigger → input). Decoupled from\n * those elements so they keep driving their own aria-wiring / keyboard\n * interaction regardless of where the surface paints.\n */\n resolve(...fallbacks: Signal<HTMLElement | null>[]): Signal<ReferenceElement | null> {\n return computed<ReferenceElement | null>(() => {\n const explicit = this.element();\n if (explicit !== null) {\n return explicit;\n }\n for (const fallback of fallbacks) {\n const el = fallback();\n if (el !== null) {\n return el;\n }\n }\n return null;\n });\n }\n}\n\n/**\n * A writable `<idPrefix>-<suffix>` id signal off the shared {@link IdGenerator},\n * for a controller that owns the element side itself — the menu overlay's opener\n * registry keeps one seed id across many openers, so it needs the id without a\n * slot's single-element storage.\n *\n * Call it from an injection context — a directive's field initializer, or a\n * controller constructed from one — so the generator resolves and slot id\n * sequences stay deterministic across renders (hydration relies on it).\n */\nexport function injectSlotId(idPrefix: string, suffix: string): WritableSignal<string> {\n return signal(inject(IdGenerator).next(`${idPrefix}-${suffix}`));\n}\n\n/**\n * A slot whose element registration adopts a consumer-set static `id`. Seeds the\n * id signal with `<idPrefix>-<suffix>` off the shared {@link IdGenerator}, so it\n * carries the same injection-context requirement as {@link injectSlotId}.\n *\n * @typeParam E Concrete element type the slot registers. Defaults to\n * `HTMLElement`.\n */\nexport function injectIdentifiedSlot<E extends HTMLElement = HTMLElement>(\n idPrefix: string,\n suffix: string,\n): IdentifiedElementSlot<E> {\n return new IdentifiedElementSlot<E>(injectSlotId(idPrefix, suffix));\n}\n\n/**\n * A slot for an element whose aria-wiring id the controller does not own.\n * Depends on nothing, so it needs no injection context.\n *\n * @typeParam E Concrete element type the slot registers. Defaults to\n * `HTMLElement`.\n */\nexport function elementSlot<E extends HTMLElement = HTMLElement>(): ElementSlot<E> {\n return new ElementSlot<E>();\n}\n\n/**\n * The floating-ui anchor slot with the settled single-anchor warning + fallback\n * chain. Must be called in an injection context, which a directive field\n * initializer is, because the dev-mode duplicate warning runs on an `effect`.\n *\n * @param config Names the root and its anchor piece in the duplicate warning.\n */\nexport function anchorSlot(config: SingleSlotConfig): AnchorSlot {\n return new AnchorSlot(config);\n}\n","import { linkedSignal, type Signal, untracked, type WritableSignal } from '@angular/core';\n\n/**\n * Records the reason of an overlay's most recent close, and clears it whenever the overlay's open\n * source turns `true`, whoever wrote it: an owner's own open path, an APG key, or a consumer's\n * `[(open)]` binding. The shared content pieces read it to skip their return-focus on a `'tab'`\n * close (so Tab advances focus out of the surface instead of snapping back to the trigger).\n *\n * `close` records the reason before running the close, so a synchronous `openChange` handler\n * already reads it, and settles it against the closed state before returning. A later read that\n * finds the source changed but closed again therefore knows an open happened in between, even one\n * nothing read during.\n *\n * Generic over the reason union so every overlay controller shares one implementation —\n * `OverlayController` (and through it `MenuOverlay`, the listbox overlays, combobox and\n * `[forMenubar]`'s multiplexed menu context) and `[forPopover]` compose it. Plain class (no\n * `inject()`) so each composes it instead of hand-copying the signal.\n *\n * @typeParam Reason Close-reason union owned by the controller.\n */\nexport class CloseReasonState<Reason> {\n readonly #reason: WritableSignal<Reason | null>;\n\n /**\n * Reason of the most recent close, or `null` while the overlay is open / has never closed.\n */\n readonly reason: Signal<Reason | null>;\n\n constructor(isOpen: () => boolean) {\n this.#reason = linkedSignal<boolean, Reason | null>({\n source: isOpen,\n computation: (open, previous) => (open || !previous?.source ? null : previous.value),\n });\n this.reason = this.#reason.asReadonly();\n }\n\n close(reason: Reason, apply: () => void): void {\n this.#reason.set(reason);\n apply();\n untracked(this.#reason);\n }\n}\n","import { type Signal, signal } from '@angular/core';\n\n/**\n * Tracks where an overlay's initial focus should land on the next open and\n * whether that one programmatic move should reflect `data-highlighted` on the\n * focused item.\n *\n * `target` is set by triggers before they flip the overlay open (ArrowDown →\n * `'first'`, ArrowUp → `'last'`, or a primitive-specific `'selected'`).\n * `highlightOnNextFocus` is armed per open via {@link prepareOpen}: a keyboard\n * activation highlights the focused item per the APG menu-button pattern; a\n * pointer activation (click, hover-after-open) suppresses the highlight so a\n * mouse-opened surface doesn't read as \"preselected\". {@link consumeHighlight}\n * reads the flag once and re-arms it to `true`, so the suppression applies only\n * to the single initial-focus move that follows an open.\n *\n * Generic over the focus-target union so every overlay controller reuses the\n * same one-shot protocol: `MenuOverlay` / `[forMenubar]`'s multiplexed menu\n * context keep `'first' | 'last'` (the default), while the listbox overlays and\n * combobox widen it with `'selected'`. Plain class (no `inject()`) so each\n * controller composes the same implementation instead of hand-copying it.\n *\n * @typeParam Focus Initial-focus target union. Defaults to `'first' | 'last'`.\n */\nexport class InitialFocusState<Focus = 'first' | 'last'> {\n readonly #target: ReturnType<typeof signal<Focus>>;\n #highlightOnNextFocus = true;\n\n /** Where focus should land when the overlay mounts. */\n readonly target: Signal<Focus>;\n\n /**\n * @param defaultTarget Initial focus target before any open. Defaults to\n * `'first'`, valid for the default `'first' | 'last'` union.\n */\n constructor(defaultTarget: Focus = 'first' as Focus) {\n this.#target = signal<Focus>(defaultTarget);\n this.target = this.#target.asReadonly();\n }\n\n setTarget(target: Focus): void {\n this.#target.set(target);\n }\n\n /**\n * Arms the state for the next open: records the initial-focus target and\n * whether the upcoming initial-focus move should highlight the focused item\n * (`true` for keyboard activation, `false` for pointer activation).\n */\n prepareOpen(target: Focus, highlight: boolean): void {\n this.#target.set(target);\n this.#highlightOnNextFocus = highlight;\n }\n\n /**\n * Returns whether the next initial-focus move should highlight, then re-arms\n * the flag to `true` so the suppression is one-shot.\n */\n consumeHighlight(): boolean {\n const highlight = this.#highlightOnNextFocus;\n this.#highlightOnNextFocus = true;\n return highlight;\n }\n}\n","import type { OutputEmitterRef, Signal, WritableSignal } from '@angular/core';\n\nimport {\n emitVetoableNativeEvent,\n injectVetoableEmitter,\n type VetoableEvent,\n type VetoableNativeEvent,\n} from 'forty-cdk/core';\nimport { CloseReasonState } from './close-reason-state';\nimport { IdentifiedElementSlot, injectSlotId } from './element-registry';\nimport { InitialFocusState } from './initial-focus-state';\n\n/**\n * The dismiss / auto-focus outputs an overlay controller forwards to. Each\n * primitive owns the `output()` instances (they must be declared as class-field\n * initializers for the Angular compiler to detect them); the controller only\n * emits through them, so the shared dismiss pipeline lives in one place.\n */\nexport interface OverlayEmitTargets {\n readonly escapeKeyDown: OutputEmitterRef<VetoableNativeEvent<KeyboardEvent>>;\n readonly pointerDownOutside: OutputEmitterRef<VetoableNativeEvent<PointerEvent>>;\n readonly focusOutside: OutputEmitterRef<VetoableNativeEvent<FocusEvent>>;\n readonly interactOutside: OutputEmitterRef<VetoableNativeEvent<PointerEvent | FocusEvent>>;\n readonly autoFocusOnOpen: OutputEmitterRef<VetoableEvent>;\n readonly autoFocusOnClose: OutputEmitterRef<VetoableEvent>;\n}\n\n/**\n * One of the two element sides a surface has — the trigger focus returns to, and\n * the content that mounts. Both are supplied by the composing controller,\n * because neither is the same object twice in the library: a listbox overlay's\n * trigger is a single {@link IdentifiedElementSlot}, a menu overlay's is a\n * registry of openers resolving one active element and its id, and\n * `[forMenubar]`'s multiplexed context resolves both sides off whichever bar\n * trigger is — or was last — active. All of them answer the same four\n * questions, which is all the shared machine asks of them.\n */\nexport interface OverlaySlot {\n /**\n * The element's aria-wiring id. Non-empty for a slot minting its own; the\n * menubar's multiplexed sources resolve `''` until a trigger has been active,\n * which `[forMenuContent]` emits as no attribute rather than as `id=\"\"`.\n */\n readonly id: Signal<string>;\n /** The registered element, or `null` while none is registered. */\n readonly element: Signal<HTMLElement | null>;\n /** Register the element. */\n register(el: HTMLElement): void;\n /** Deregister the element. */\n unregister(el: HTMLElement): void;\n}\n\n/**\n * Per-transition options forwarded verbatim to the `onOpen` / `onClose` hooks so\n * a host directive can react to *how* a transition was driven without\n * re-deriving it from outside the pipeline.\n */\nexport interface OverlayTransitionOptions {\n /**\n * When `true`, the transition is pointer-driven (hover) and the surface's\n * imperative focus move must be suppressed — an open must not pull focus into\n * the surface, and a close must not return focus to the trigger. Defaults to\n * `false`, so keyboard / click / programmatic transitions move focus as usual.\n */\n readonly suppressFocusMoves?: boolean;\n}\n\n/** Per-call options for {@link OverlayController.open}. */\nexport interface OverlayOpenOptions {\n /**\n * Arms the initial-focus state's one-shot highlight flag for this open —\n * `true` for a keyboard activation, `false` for a pointer one. Omit it\n * entirely on a surface that does not reflect `data-highlighted` on its\n * initial focus, so the flag is left untouched.\n */\n readonly highlight?: boolean;\n /** Transition options handed verbatim to the `onOpen` hook. */\n readonly transition?: OverlayTransitionOptions;\n}\n\n/**\n * What {@link OverlayController.open} did, so a composing controller can run its\n * own tail without re-reading the open model (which the call may just have\n * written).\n *\n * - `'blocked'` — the control is disabled; nothing happened.\n * - `'opened'` — the surface transitioned from closed to open.\n * - `'already-open'` — the surface was already mounted, so no state transition\n * (and therefore no `openChange` emit) happened. The initial-focus target and\n * the close reason were still re-armed.\n */\nexport type OverlayOpenOutcome = 'blocked' | 'opened' | 'already-open';\n\n/**\n * Construction-time wiring for {@link OverlayController}. Plain signals and\n * callbacks only — the controller never imports a primitive's context token,\n * mirroring `injectOverlayShell`, so it stays orthogonal to each root's surface.\n *\n * @typeParam Focus Initial-focus union owned by the composing controller.\n * @typeParam CloseReason Close-reason union owned by the composing controller.\n */\nexport interface OverlayControllerDeps<Focus, CloseReason> {\n /** Id-generator prefix base, e.g. `'for-select'` (suffixed with `-trigger` / `-content`). */\n readonly idPrefix: string;\n /**\n * Builds the trigger side, from a factory minting the seeded\n * `<idPrefix>-trigger` id. Call the factory exactly once for a trigger that\n * owns an id, and **not at all** for one whose id lives elsewhere — the\n * combobox's lives on its input, the menubar's on each bar trigger — because\n * the `IdGenerator` counter is per application, so an id nothing ever emits\n * still shifts every id minted after it.\n *\n * Runs during construction, ahead of {@link createContent}, so the\n * trigger-then-content minting order is fixed here rather than per caller —\n * hydration's id adoption depends on both renders repeating it. It may\n * `inject()`, and so may the factory.\n */\n readonly createTrigger: (mintId: () => WritableSignal<string>) => OverlaySlot;\n /**\n * Builds the content side, same contract as {@link createTrigger} and called\n * immediately after it. Optional: omitted, the controller registers its own\n * {@link IdentifiedElementSlot} over the minted `<idPrefix>-content` id, which\n * is what every surface owning its content id wants. Supply it when the id\n * comes from somewhere else, or when registration does more than adopt a\n * static id — `[forMenubar]` resolves the id off the active trigger and\n * records whether the surface is shared across the bar's triggers.\n */\n readonly createContent?: (mintId: () => WritableSignal<string>) => OverlaySlot;\n /** Default initial-focus target before any open. */\n readonly defaultInitialFocus: Focus;\n /** The control's effective disabled — gates `open` and `toggle`. */\n readonly disabled: Signal<boolean>;\n /** Whether Escape / outside interactions dismiss the surface. */\n readonly dismissible: Signal<boolean>;\n /** Read the control's current open state. */\n readonly isOpen: () => boolean;\n /** Write the control's open state — the open / close machine's only channel. */\n readonly setOpen: (open: boolean) => void;\n /** Dismiss / auto-focus outputs to forward to. */\n readonly emit: OverlayEmitTargets;\n /** Close reason recorded when Escape dismisses the surface. */\n readonly escapeReason: CloseReason;\n /** Close reason recorded when {@link OverlayController.toggle} closes the surface. */\n readonly programmaticReason: CloseReason;\n /**\n * Side effect run after {@link OverlayController.open} resolves an un-blocked\n * open, receiving the resolved initial-focus target and the transition\n * options. Runs on the `'already-open'` outcome too, so a pending hover-close\n * is still cancelled by an open key pressed on a mounted surface.\n */\n readonly onOpen?: (initialFocus: Focus, options: OverlayTransitionOptions) => void;\n /**\n * Side effect run after {@link OverlayController.close} flips the open state\n * to `false`, receiving the close reason and the transition options.\n */\n readonly onClose?: (reason: CloseReason, options: OverlayTransitionOptions) => void;\n /**\n * Side effect run on a user-driven dismissal — an un-vetoed Escape, or the\n * shell's implicit close after an un-vetoed outside interaction — just before\n * the close. Optional: only a form control has touched state to mark, so the\n * menu overlays pass nothing.\n */\n readonly onDismiss?: () => void;\n}\n\n/**\n * The open / close / dismiss machine every trigger-anchored overlay surface\n * runs, composed by `MenuOverlay` (the four menu roots), by\n * `ListboxOverlayController` (`[forSelect]` / `[forTimePicker]`), and by\n * `[forCombobox]` and `[forMenubar]`. It owns the initial-focus and close-reason\n * state, the `disabled`-gated open / close / toggle transitions, the four\n * outside / Escape emit forwarders, the shell's implicit `requestClose`, and the\n * two auto-focus veto pass-throughs — plus the order in which the two supplied\n * element sides mint their ids.\n *\n * It does not own the item **collection**: the menu side composes `MenuItemList`\n * separately, and the two navigate tails differ — the menu suppresses the item\n * highlight and scrolls the surface's own overflow, the listbox runs a\n * per-primitive `onNavigateFocus` and gates the move on `disabled`.\n *\n * Construct it from a directive's field initializer, or from a controller\n * constructed there: it reads that directive's `DestroyRef` for the auto-focus\n * vetoes, and the slot factories' `inject()` calls resolve through the same\n * injector.\n *\n * @typeParam Focus Initial-focus union owned by the composing controller.\n * @typeParam CloseReason Close-reason union owned by the composing controller.\n */\nexport class OverlayController<Focus, CloseReason> {\n readonly #deps: OverlayControllerDeps<Focus, CloseReason>;\n\n readonly #triggerSlot: OverlaySlot;\n readonly #contentSlot: OverlaySlot;\n\n readonly #initialFocusState: InitialFocusState<Focus>;\n readonly #closeReasonState: CloseReasonState<CloseReason>;\n\n readonly #autoFocusOnOpen: () => boolean;\n readonly #autoFocusOnClose: () => boolean;\n\n /** The trigger's stable id, adopted from a consumer-set static id when present. */\n readonly triggerId: Signal<string>;\n\n /** The content surface's stable id, adopted from a consumer-set static id when present. */\n readonly contentId: Signal<string>;\n\n /** The focusable element the surface returns focus to on close. */\n readonly trigger: Signal<HTMLElement | null>;\n\n /** The mounted content element, or `null` while the surface is closed. */\n readonly content: Signal<HTMLElement | null>;\n\n /** Where focus should land when the surface mounts. Set by triggers before flipping open. */\n readonly initialFocus: Signal<Focus>;\n\n /**\n * Reason of the most recent close, or `null` while the surface is open / has\n * never closed. Reset to `null` on every open — the content pieces read it to\n * skip their return-focus on a `'tab'` close.\n */\n readonly lastCloseReason: Signal<CloseReason | null>;\n\n constructor(deps: OverlayControllerDeps<Focus, CloseReason>) {\n this.#deps = deps;\n const mintContentId = () => injectSlotId(deps.idPrefix, 'content');\n this.#triggerSlot = deps.createTrigger(() => injectSlotId(deps.idPrefix, 'trigger'));\n this.#contentSlot = deps.createContent\n ? deps.createContent(mintContentId)\n : new IdentifiedElementSlot(mintContentId());\n this.#initialFocusState = new InitialFocusState<Focus>(deps.defaultInitialFocus);\n this.#closeReasonState = new CloseReasonState<CloseReason>(deps.isOpen);\n this.#autoFocusOnOpen = injectVetoableEmitter(deps.emit.autoFocusOnOpen);\n this.#autoFocusOnClose = injectVetoableEmitter(deps.emit.autoFocusOnClose);\n this.triggerId = this.#triggerSlot.id;\n this.contentId = this.#contentSlot.id;\n this.trigger = this.#triggerSlot.element;\n this.content = this.#contentSlot.element;\n this.initialFocus = this.#initialFocusState.target;\n this.lastCloseReason = this.#closeReasonState.reason;\n }\n\n /** Set the initial-focus target ahead of the next open. */\n setInitialFocus(target: Focus): void {\n this.#initialFocusState.setTarget(target);\n }\n\n /**\n * Reads the initial-focus state's one-shot highlight flag and re-arms it, so\n * the composing controller's initial-focus move can suppress the focused\n * item's `data-highlighted` for a pointer-driven open only.\n */\n consumeInitialHighlight(): boolean {\n return this.#initialFocusState.consumeHighlight();\n }\n\n /** Register the trigger element. */\n registerTrigger(el: HTMLElement): void {\n this.#triggerSlot.register(el);\n }\n\n /** Deregister the trigger element (no-op unless the same node registered). */\n unregisterTrigger(el: HTMLElement): void {\n this.#triggerSlot.unregister(el);\n }\n\n /** Register the mounted content element. */\n registerContent(el: HTMLElement): void {\n this.#contentSlot.register(el);\n }\n\n /** Deregister the content element (no-op unless the same node registered). */\n unregisterContent(el: HTMLElement): void {\n this.#contentSlot.unregister(el);\n }\n\n /**\n * Opens the surface when closed, closes it with the deps' programmatic reason\n * when open. Honours `disabled` on both branches — there is no distinct\n * `'trigger'` close reason for the user-initiated toggle-close path.\n */\n toggle(initialFocus: Focus, options: OverlayOpenOptions = {}): void {\n if (this.#deps.disabled()) {\n return;\n }\n if (this.#deps.isOpen()) {\n this.close(this.#deps.programmaticReason);\n } else {\n this.open(initialFocus, options);\n }\n }\n\n /**\n * Records where the initial focus should land and flips the open state,\n * which clears the close reason. Returns the {@link OverlayOpenOutcome} so a composing\n * controller can branch on an already-open surface — no state transition\n * happened there, so nothing emitted `openChange`, and a re-focus is the only\n * way an APG open key stays live on a mounted surface.\n */\n open(initialFocus: Focus, options: OverlayOpenOptions = {}): OverlayOpenOutcome {\n if (this.#deps.disabled()) {\n return 'blocked';\n }\n const alreadyOpen = this.#deps.isOpen();\n if (options.highlight === undefined) {\n this.#initialFocusState.setTarget(initialFocus);\n } else {\n this.#initialFocusState.prepareOpen(initialFocus, options.highlight);\n }\n if (!alreadyOpen) {\n this.#deps.setOpen(true);\n }\n this.#deps.onOpen?.(initialFocus, options.transition ?? {});\n return alreadyOpen ? 'already-open' : 'opened';\n }\n\n /**\n * Closes the surface, recording `reason` as the {@link lastCloseReason} the\n * content pieces read. Never gated on `disabled`: a control disabled while its\n * surface is open must still be closable.\n */\n close(reason: CloseReason, transition: OverlayTransitionOptions = {}): void {\n this.#closeReasonState.close(reason, () => this.#deps.setOpen(false));\n this.#deps.onClose?.(reason, transition);\n }\n\n /**\n * Escape on the anchored path: emit `(escapeKeyDown)`, then close when\n * un-vetoed and dismissible.\n */\n emitEscapeKeyDown(event: KeyboardEvent): void {\n const vetoed = emitVetoableNativeEvent(this.#deps.emit.escapeKeyDown, event);\n if (!vetoed && this.#deps.dismissible()) {\n // Load-bearing, not redundant: the bubble-phase Escape handler stops the\n // same keydown from reaching an *ancestor* overlay's keydown listener,\n // which is how nested overlays close one layer per Escape (see the\n // listener-phase note in `core-overlay/dismissible-layer/dismissible-layer.ts`).\n event.stopPropagation();\n this.#deps.onDismiss?.();\n this.close(this.#deps.escapeReason);\n }\n }\n\n /** Modal-path Escape forwarder: emit only; the modal shell owns the close. */\n forwardEscapeKeyDown(veto: VetoableNativeEvent<KeyboardEvent>): void {\n this.#deps.emit.escapeKeyDown.emit(veto);\n }\n\n /**\n * Outside-interaction emit forwarders. The shared `#pendingOutsideVeto` reuse\n * between the specific outside channels and the composite `interactOutside`\n * lives in `injectOverlayShell`; these only fire the matching output with the\n * veto the shell built.\n */\n emitPointerDownOutside(veto: VetoableNativeEvent<PointerEvent>): void {\n this.#deps.emit.pointerDownOutside.emit(veto);\n }\n\n /** Focus-outside emit forwarder — see {@link emitPointerDownOutside}. */\n emitFocusOutside(veto: VetoableNativeEvent<FocusEvent>): void {\n this.#deps.emit.focusOutside.emit(veto);\n }\n\n /** Composite outside-interaction emit forwarder — see {@link emitPointerDownOutside}. */\n emitInteractOutside(veto: VetoableNativeEvent<PointerEvent | FocusEvent>): void {\n this.#deps.emit.interactOutside.emit(veto);\n }\n\n /**\n * Implicit close requested by `injectOverlayShell` after an un-vetoed outside\n * interaction. The shell owns the shared `#pendingOutsideVeto` reuse between\n * the specific outside channels and the composite `interactOutside`; this\n * controller only owns the close. The open guard keeps a stale event from\n * re-closing an already-closed surface and clobbering its\n * {@link lastCloseReason} (e.g. a `'tab'` close must survive so the content\n * skips its return-focus).\n */\n requestClose(reason: CloseReason): void {\n if (!this.#deps.isOpen()) {\n return;\n }\n this.#deps.onDismiss?.();\n this.close(reason);\n }\n\n /**\n * Emits `(autoFocusOnOpen)`, returning whether the mount's focus move is\n * vetoed — by a consumer, or by the root's own destruction.\n */\n emitAutoFocusOnOpen(): boolean {\n return this.#autoFocusOnOpen();\n }\n\n /**\n * Emits `(autoFocusOnClose)`, returning whether the return-focus move is\n * vetoed — by a consumer, or by the root's own destruction.\n */\n emitAutoFocusOnClose(): boolean {\n return this.#autoFocusOnClose();\n }\n}\n","import { type Signal } from '@angular/core';\nimport type { ReferenceElement } from '@floating-ui/dom';\n\nimport {\n accessibleTextContent,\n Collection,\n firstEnabledHost,\n injectFieldAnchor,\n injectTypeahead,\n lastEnabledHost,\n type ListNavigationAction,\n nextEnabledHandle,\n resolveActiveElement,\n resolveListTypeahead,\n type SingleSlotConfig,\n type VetoableNativeEvent,\n} from 'forty-cdk/core';\nimport {\n anchorSlot,\n type AnchorSlot,\n IdentifiedElementSlot,\n} from '../overlay-controller/element-registry';\nimport {\n OverlayController,\n type OverlayEmitTargets,\n} from '../overlay-controller/overlay-controller';\nimport type { OverlayShellTabOutConfig } from '../overlay-controller/overlay-shell';\n\n/**\n * Minimal option-handle shape the controller's focus algorithm needs: a host\n * element to focus and a `disabled` signal to skip. Each primitive widens this\n * with its own per-option fields (value, label, id, posInSet, …) and registers\n * the widened handle through {@link ListboxOverlayController.registerOption}.\n */\nexport interface ListboxOverlayOptionHandle {\n readonly host: HTMLElement;\n readonly disabled: Signal<boolean>;\n}\n\n/**\n * Construction-time wiring for {@link ListboxOverlayController}. Plain signals\n * and callbacks only — the controller never imports a primitive's context\n * token, mirroring `injectOverlayShell`, so it stays orthogonal to each root's\n * surface.\n *\n * @typeParam H Primitive option-handle type.\n * @typeParam Focus Initial-focus union (identical `'first' | 'last' | 'selected'`\n * in both primitives, kept generic so each keeps its own named alias).\n * @typeParam CloseReason Close-reason union owned by the primitive.\n */\nexport interface ListboxOverlayControllerDeps<\n H extends ListboxOverlayOptionHandle,\n Focus,\n CloseReason,\n> {\n /** Id-generator prefix base, e.g. `'for-select'` (suffixed with `-trigger` / `-content`). */\n readonly idPrefix: string;\n /** Names the root and its anchor piece in the dev-mode duplicate-anchor warning. */\n readonly anchorSlot: SingleSlotConfig;\n /** Default initial-focus target when none is set explicitly. */\n readonly defaultInitialFocus: Focus;\n /** The control's effective disabled — gates open / navigate / toggle. */\n readonly effectiveDisabled: Signal<boolean>;\n /** The control's two-way `open` model — flipped by the open / close machine. */\n readonly setOpen: (open: boolean) => void;\n /** Read the control's current open state. */\n readonly isOpen: () => boolean;\n /** Dismiss / auto-focus outputs to forward to. */\n readonly emit: OverlayEmitTargets;\n /** Whether keyboard navigation wraps at the ends of the option list. */\n readonly loop: Signal<boolean>;\n /** Whether Escape / outside interactions dismiss the overlay. */\n readonly dismissible: Signal<boolean>;\n /** Close reason set when Escape dismisses the overlay (both primitives use `'escape'`). */\n readonly escapeReason: CloseReason;\n /** Close reason set when {@link ListboxOverlayController.toggle} closes the overlay (both primitives use `'programmatic'`). */\n readonly programmaticReason: CloseReason;\n /** Mark the control touched (mirrors the trigger blur) on Escape / outside dismissal. */\n readonly markTouched: () => void;\n /**\n * Per-primitive close side effect, run after the open model flips to `false`\n * (Select clears the virtualized activedescendant + pending navigation here).\n */\n readonly onClose?: (reason: CloseReason) => void;\n /**\n * Per-option focus side effect, run after `navigate` or a typeahead match focuses the target\n * (Select scrolls the option into view and applies `selectionFollowsFocus`).\n */\n readonly onNavigateFocus?: (target: H) => void;\n /** Per-primitive option-unregister side effect (Select clears a stale activedescendant). */\n readonly onUnregisterOption?: (handle: H) => void;\n}\n\n/**\n * The narrow, typed facade a primitive surfaces on its coordination context\n * (`ctx.overlay`) so child directives read the shared overlay-listbox state and\n * behavior here instead of the root re-forwarding every member. Implemented by\n * {@link ListboxOverlayController}; each primitive's context exposes it as a\n * sub-object, keeping the child-facing surface a single, self-documenting seam.\n *\n * @typeParam H Primitive option-handle type.\n * @typeParam Focus Initial-focus union.\n * @typeParam CloseReason Close-reason union owned by the primitive.\n */\nexport interface ListboxOverlayContext<H extends ListboxOverlayOptionHandle, Focus, CloseReason> {\n /** The trigger's stable id, adopted from a consumer-set static id when present. */\n readonly triggerId: Signal<string>;\n /** The content surface's stable id, adopted from a consumer-set static id when present. */\n readonly contentId: Signal<string>;\n /** Where focus should land after the content mounts. Triggers set this before flipping `open`. */\n readonly initialFocus: Signal<Focus>;\n /** Reason of the most recent close, or `null` while open (or before any close). */\n readonly lastCloseReason: Signal<CloseReason | null>;\n /** The button trigger — exempt from outside-pointer checks and the focus-return target. */\n readonly trigger: Signal<HTMLElement | null>;\n /**\n * Element floating-ui anchors the content against. Prefers a registered\n * anchor, otherwise falls back to the trigger.\n */\n readonly anchor: Signal<ReferenceElement | null>;\n /** The mounted content element. */\n readonly content: Signal<HTMLElement | null>;\n /** All registered options in DOM order. */\n readonly options: Signal<readonly H[]>;\n\n /** Set the initial-focus target ahead of the next open. */\n setInitialFocus(target: Focus): void;\n\n registerTrigger(el: HTMLElement): void;\n unregisterTrigger(el: HTMLElement): void;\n registerAnchor(el: HTMLElement): void;\n unregisterAnchor(el: HTMLElement): void;\n registerContent(el: HTMLElement): void;\n unregisterContent(el: HTMLElement): void;\n registerOption(handle: H): void;\n unregisterOption(handle: H): void;\n\n /** Move focus inside the open content in response to an arrow / Home / End key. */\n navigate(currentOption: HTMLElement, action: ListNavigationAction): void;\n /**\n * Open-state typeahead: focus the first enabled option after the event target whose\n * accessible text matches the buffered prefix. Returns `true` when the key was consumed,\n * so a Space the buffer took must not also activate.\n */\n handleTypeahead(event: KeyboardEvent): boolean;\n focusFirstEnabledOption(): boolean;\n focusLastEnabledOption(): boolean;\n\n toggle(initialFocus: Focus): void;\n openOverlay(initialFocus: Focus): void;\n closeOverlay(reason: CloseReason): void;\n\n /** Escape on the anchored path: emit `(escapeKeyDown)`, then close when un-vetoed and dismissible. */\n emitEscapeKeyDown(event: KeyboardEvent): void;\n emitPointerDownOutside(veto: VetoableNativeEvent<PointerEvent>): void;\n emitFocusOutside(veto: VetoableNativeEvent<FocusEvent>): void;\n emitInteractOutside(veto: VetoableNativeEvent<PointerEvent | FocusEvent>): void;\n /** Modal-path Escape forwarder: emit only; the modal shell owns the close. */\n forwardEscapeKeyDown(veto: VetoableNativeEvent<KeyboardEvent>): void;\n /** Implicit close requested by the shell after an un-vetoed outside interaction. */\n requestClose(reason: CloseReason): void;\n emitAutoFocusOnOpen(): boolean;\n emitAutoFocusOnClose(): boolean;\n}\n\n/**\n * The overlay-listbox state machine shared by `ForSelect` and `ForTimePicker`\n * (the WAI-ARIA select-only combobox and the slot-listbox time picker). It owns\n * the option collection, the anchor slot, the DOM-focus navigation algorithm and\n * the trigger focus move; everything the menu overlays run identically — the\n * trigger / content slots and their ids, the initial-focus and close-reason\n * state, the open / close machine, the dismiss / auto-focus forwarders — is the\n * shared {@link OverlayController}'s, composed here rather than re-declared.\n *\n * Value-specific behaviour (selection equality, `activate`, `focusSelectedOption`,\n * closed-state typeahead, the virtualized activedescendant path, `commitOnTab`'s value set)\n * stays in the root and is threaded through {@link ListboxOverlayControllerDeps}\n * callbacks where it must run as a side effect of a shared transition.\n *\n * Internal core tier — exported from `forty-cdk/core-overlay` for the library's\n * own entry points, with no semver guarantee.\n *\n * Construct it from a directive's field initializer, so the slot factories'\n * `inject()` calls resolve through the directive's injector.\n *\n * @typeParam H Primitive option-handle type.\n * @typeParam Focus Initial-focus union.\n * @typeParam CloseReason Close-reason union.\n */\nexport class ListboxOverlayController<\n H extends ListboxOverlayOptionHandle,\n Focus,\n CloseReason,\n> implements ListboxOverlayContext<H, Focus, CloseReason> {\n readonly #deps: ListboxOverlayControllerDeps<H, Focus, CloseReason>;\n readonly #items = new Collection<H>();\n readonly #typeahead = injectTypeahead();\n\n readonly #anchorSlot: AnchorSlot;\n readonly #controller: OverlayController<Focus, CloseReason>;\n\n /** The trigger's stable id, adopted from a consumer-set static id when present. */\n readonly triggerId: Signal<string>;\n\n /** The content surface's stable id, adopted from a consumer-set static id when present. */\n readonly contentId: Signal<string>;\n\n /** Where focus should land after the content mounts. Triggers set this before flipping `open`. */\n readonly initialFocus: Signal<Focus>;\n\n /** Reason of the most recent close, or `null` while open (or before any close). */\n readonly lastCloseReason: Signal<CloseReason | null>;\n\n /** The button trigger — exempt from outside-pointer checks and the focus-return target. */\n readonly trigger: Signal<HTMLElement | null>;\n\n /**\n * Element floating-ui anchors the listbox against. Prefers an optional\n * registered anchor, then the surrounding field's `[forFieldAnchor]`,\n * otherwise falls back to the trigger so primitives without an anchor keep\n * their behavior.\n */\n readonly anchor: Signal<ReferenceElement | null>;\n\n /** The mounted content element. */\n readonly content: Signal<HTMLElement | null>;\n\n /** All registered options in DOM order. */\n readonly options: Signal<readonly H[]>;\n\n constructor(deps: ListboxOverlayControllerDeps<H, Focus, CloseReason>) {\n this.#deps = deps;\n this.#controller = new OverlayController<Focus, CloseReason>({\n idPrefix: deps.idPrefix,\n createTrigger: (mintId) => new IdentifiedElementSlot(mintId()),\n defaultInitialFocus: deps.defaultInitialFocus,\n disabled: deps.effectiveDisabled,\n dismissible: deps.dismissible,\n isOpen: deps.isOpen,\n setOpen: deps.setOpen,\n emit: deps.emit,\n escapeReason: deps.escapeReason,\n programmaticReason: deps.programmaticReason,\n onClose: deps.onClose,\n onDismiss: deps.markTouched,\n });\n this.#anchorSlot = anchorSlot(deps.anchorSlot);\n this.triggerId = this.#controller.triggerId;\n this.contentId = this.#controller.contentId;\n this.initialFocus = this.#controller.initialFocus;\n this.lastCloseReason = this.#controller.lastCloseReason;\n this.trigger = this.#controller.trigger;\n this.content = this.#controller.content;\n this.anchor = this.#anchorSlot.resolve(injectFieldAnchor(), this.#controller.trigger);\n this.options = this.#items.items;\n }\n\n setInitialFocus(target: Focus): void {\n this.#controller.setInitialFocus(target);\n }\n\n registerTrigger(el: HTMLElement): void {\n this.#controller.registerTrigger(el);\n }\n unregisterTrigger(el: HTMLElement): void {\n this.#controller.unregisterTrigger(el);\n }\n\n registerAnchor(el: HTMLElement): void {\n this.#anchorSlot.register(el);\n }\n unregisterAnchor(el: HTMLElement): void {\n this.#anchorSlot.unregister(el);\n }\n\n registerContent(el: HTMLElement): void {\n this.#controller.registerContent(el);\n }\n unregisterContent(el: HTMLElement): void {\n this.#controller.unregisterContent(el);\n }\n\n registerOption(handle: H): void {\n this.#items.register(handle);\n }\n unregisterOption(handle: H): void {\n this.#items.unregister(handle);\n this.#deps.onUnregisterOption?.(handle);\n }\n\n navigate(currentOption: HTMLElement, action: ListNavigationAction): void {\n if (this.#deps.effectiveDisabled()) {\n return;\n }\n const target = nextEnabledHandle(this.#items.items(), currentOption, action, {\n loop: this.#deps.loop(),\n });\n if (target === null) {\n return;\n }\n target.host.focus();\n this.#deps.onNavigateFocus?.(target);\n }\n\n handleTypeahead(event: KeyboardEvent): boolean {\n const items = this.#items.items();\n const { handled, match } = resolveListTypeahead(this.#typeahead, event, {\n items,\n anchorIndex: items.findIndex((o) => o.host === event.target),\n getText: (o) => accessibleTextContent(o.host),\n isDisabled: (o) => o.disabled(),\n });\n if (match) {\n match.host.focus();\n this.#deps.onNavigateFocus?.(match);\n }\n return handled;\n }\n\n focusFirstEnabledOption(): boolean {\n const host = firstEnabledHost(this.#items.items());\n if (!host) {\n return false;\n }\n host.focus();\n return true;\n }\n\n focusLastEnabledOption(): boolean {\n const host = lastEnabledHost(this.#items.items());\n if (!host) {\n return false;\n }\n host.focus();\n return true;\n }\n\n /**\n * The option an open surface still has to scroll into view: the registered option holding DOM\n * focus, else `fallback()` when focus is on none of them. `null` when that option is the first\n * enabled one, which the surface already shows at its top, or when there is none.\n */\n revealTarget(fallback: () => HTMLElement | null = () => null): HTMLElement | null {\n const content = this.content();\n if (content === null) {\n return null;\n }\n const items = this.#items.items();\n const active = resolveActiveElement(content.ownerDocument);\n const target = items.find((o) => o.host === active)?.host ?? fallback();\n return target === firstEnabledHost(items) ? null : target;\n }\n\n /**\n * The overlay shell's Tab-out wiring: a Tab that leaves the open surface's tab cycle moves focus\n * to the trigger, so the browser advances from there rather than from the body-appended portal,\n * and closes with `reason`. The target resolves only while the overlay is open and `enabled()`\n * holds, so an option that already committed and closed on the same Tab keeps the browser's own\n * advance from the trigger.\n */\n tabOut(reason: CloseReason, enabled: () => boolean = () => true): OverlayShellTabOutConfig {\n return {\n target: () => (this.#deps.isOpen() && enabled() ? this.trigger() : null),\n close: () => this.closeOverlay(reason),\n };\n }\n\n toggle(initialFocus: Focus): void {\n this.#controller.toggle(initialFocus);\n }\n\n openOverlay(initialFocus: Focus): void {\n this.#controller.open(initialFocus);\n }\n\n closeOverlay(reason: CloseReason): void {\n this.#controller.close(reason);\n }\n\n emitEscapeKeyDown(event: KeyboardEvent): void {\n this.#controller.emitEscapeKeyDown(event);\n }\n\n emitPointerDownOutside(veto: VetoableNativeEvent<PointerEvent>): void {\n this.#controller.emitPointerDownOutside(veto);\n }\n emitFocusOutside(veto: VetoableNativeEvent<FocusEvent>): void {\n this.#controller.emitFocusOutside(veto);\n }\n emitInteractOutside(veto: VetoableNativeEvent<PointerEvent | FocusEvent>): void {\n this.#controller.emitInteractOutside(veto);\n }\n\n forwardEscapeKeyDown(veto: VetoableNativeEvent<KeyboardEvent>): void {\n this.#controller.forwardEscapeKeyDown(veto);\n }\n\n /**\n * Implicit close requested by the shell after an un-vetoed outside\n * interaction. The `isOpen` guard keeps a stale event from re-closing an\n * already-closed overlay and clobbering its `lastCloseReason` (e.g. a `'tab'`\n * close must survive so the content skips its return-focus).\n */\n requestClose(reason: CloseReason): void {\n this.#controller.requestClose(reason);\n }\n\n emitAutoFocusOnOpen(): boolean {\n return this.#controller.emitAutoFocusOnOpen();\n }\n\n emitAutoFocusOnClose(): boolean {\n return this.#controller.emitAutoFocusOnClose();\n }\n\n /** Focus the trigger, e.g. on a Tab commit before the content unmounts. */\n focusTrigger(): void {\n this.#controller.trigger()?.focus();\n }\n}\n","import { inject, InjectionToken, type Signal } from '@angular/core';\nimport type { ReferenceElement } from '@floating-ui/dom';\n\nimport {\n type CollectionHandle,\n type ListNavigationAction,\n orphanContextError,\n type VetoableNativeEvent,\n type WritingDirection,\n} from 'forty-cdk/core';\nimport type { DismissibleLayerNesting } from '../dismissible-layer/dismissible-layer';\nimport type {\n FloatingAlign,\n FloatingFallbackAxisSideDirection,\n FloatingSide,\n} from '../floating/floating';\nimport type { MenuActivationModality } from './menu-overlay';\nimport type { Point } from '../pointer-grace/pointer-grace';\n\n/**\n * Minimal upward contract a menu uses to move between sibling menus of an\n * enclosing menubar. Implemented by the menubar root; keeps the generic menu\n * layer free of any concrete-root import.\n */\nexport interface MenuSiblingNavigator {\n /**\n * Move focus/open to the previous or next sibling menu, returning whether the\n * bar actually moved. `false` means there was nowhere to go — the bar is\n * disabled, it has no registered triggers, or no enabled sibling exists in\n * that direction with `loop` off — so a caller must not tear down state (an\n * open submenu chain) it would then be unable to leave.\n */\n switchToSibling(direction: 'next' | 'prev'): boolean;\n}\n\n/**\n * Why a menu requested close. Enumerates the close reasons without the\n * focus-routing decision baked in. `'programmatic'` also\n * covers the user-initiated trigger toggle-close (clicking an open menu's\n * trigger): the toggle path reuses this reason by design rather than\n * exposing a distinct `'trigger'` reason. `'hover'` is a pointer-driven\n * (hover-leave) close and, like `'escape'` / `'programmatic'`, affects only\n * the level that scheduled it — it never propagates up the menu chain.\n */\nexport type ForMenuCloseReason =\n 'escape' | 'pointerDownOutside' | 'focusOutside' | 'select' | 'tab' | 'hover' | 'programmatic';\n\n/**\n * Handle every item type (`menuitem`, `menuitemcheckbox`, `menuitemradio`)\n * registers with the parent menu. The collection orders them by DOM\n * position so groups, separators, and `@for` loops don't affect navigation.\n *\n * `textValue`, when present and non-empty, overrides the item's accessible\n * text for typeahead matching — useful when announced content such as a kbd\n * shortcut, a badge, or an SVG title would otherwise bleed into the match\n * string. Empty / unset means \"fall back to the host's accessible text\", which\n * already excludes any `aria-hidden` subtree.\n */\nexport interface ForMenuItemHandle extends CollectionHandle {\n /**\n * Narrowed from {@link CollectionHandle}'s `Node`: the menu focuses its items\n * and scrolls them into view.\n */\n readonly host: HTMLElement;\n readonly disabled: Signal<boolean>;\n readonly textValue?: Signal<string>;\n /**\n * Tells the item that the next focus it receives is a programmatic move\n * that must not reflect `data-highlighted` (the initial focus of a\n * pointer-driven open). One-shot: the item consumes the suppression on its\n * next `focus` event. Optional — items that don't reflect a highlight\n * (e.g. `[forMenuSubTrigger]`) simply omit it.\n */\n suppressHighlightOnNextFocus?(): void;\n /**\n * Drops the item's `data-highlighted` without moving DOM focus. The menu\n * surface calls this on `pointerleave` so the hover highlight stops once the\n * pointer leaves, while keyboard navigation stays anchored on the item.\n * Optional — items that don't reflect a highlight (e.g.\n * `[forMenuSubTrigger]`) simply omit it.\n */\n clearHighlight?(): void;\n}\n\n/**\n * Coordination contract owned by the root that opens the menu —\n * `[forDropdownMenu]` (button trigger) or `[forContextMenu]`\n * (right-click / `Shift+F10`). Items, content, separators, etc. inject\n * this contract so they don't depend on a specific root flavor.\n */\nexport interface ForMenuContext {\n /**\n * Whether the menu is currently shown. Read-only at the contract level —\n * concrete roots (`[forDropdownMenu]`, `[forContextMenu]`, `[forMenuSub]`)\n * back this with their own `model<boolean>` and write through their own\n * `openMenu` / `closeMenu` plumbing. Pieces consuming this contract\n * (`[forMenuContent]`, the trigger directives) only ever read.\n */\n readonly open: Signal<boolean>;\n readonly disabled: Signal<boolean>;\n readonly dismissible: Signal<boolean>;\n readonly returnFocus: Signal<boolean>;\n /**\n * Writing direction. Drives ArrowLeft / ArrowRight semantics on submenu\n * triggers and items, and the default `side` of submenus (`'right'` in\n * LTR, `'left'` in RTL). On `[forMenuSub]` defaults to the parent menu's\n * `dir` and can be overridden per-submenu.\n */\n readonly dir: Signal<WritingDirection>;\n readonly side: Signal<FloatingSide | undefined>;\n readonly align: Signal<FloatingAlign | undefined>;\n readonly sideOffset: Signal<number>;\n readonly alignOffset: Signal<number>;\n readonly avoidCollisions: Signal<boolean>;\n /**\n * Direction `flip` falls back to on the perpendicular axis when both sides of\n * the preferred axis overflow. `'none'` (default) keeps only the opposite\n * same-axis placement; `'start'` / `'end'` let a submenu drop to a vertical\n * side on a narrow viewport. Threaded through to `injectOverlayShell`'s\n * floating positioner.\n */\n readonly fallbackAxisSideDirection: Signal<FloatingFallbackAxisSideDirection>;\n readonly collisionPadding: Signal<number>;\n readonly sticky: Signal<'partial' | 'always' | false>;\n readonly hideWhenDetached: Signal<boolean>;\n readonly clipUntilPositioned: Signal<boolean>;\n readonly loop: Signal<boolean>;\n\n /** Where focus should land after the menu mounts. Set by triggers before flipping `open`. */\n readonly initialFocus: Signal<'first' | 'last'>;\n setInitialFocus(target: 'first' | 'last'): void;\n\n /**\n * Id of the trigger, used as the surface's `aria-labelledby` fallback. An\n * empty string means the context has no trigger to name the surface with, and\n * `[forMenuContent]` emits no attribute at all — never `aria-labelledby=\"\"`.\n */\n readonly triggerId: Signal<string>;\n /**\n * Id the surface exposes, and the trigger's `aria-controls` target. An empty\n * string means the context has not associated a trigger with the surface yet\n * (only reachable under `[forMenubar]`, whose single context multiplexes over\n * the triggers), and `[forMenuContent]` emits no `id` at all — never `id=\"\"`.\n */\n readonly contentId: Signal<string>;\n readonly ariaLabel: Signal<string | null>;\n\n /**\n * Whether the trigger's own accessible name is a valid name for the menu\n * surface. `true` — the default when a root omits the member entirely — lets\n * `[forMenuContent]` fall back to `aria-labelledby=\"<triggerId>\"` when no\n * `ariaLabel` is set, which is correct for a discrete labelling control (a\n * `[forDropdownMenuTrigger]` button, a `[forMenubarTrigger]` or\n * `[forMenuSubTrigger]` menuitem). `[forContextMenu]` reports `false`: its\n * trigger is the whole right-click region, so an `aria-labelledby` pointing at\n * it would make screen readers announce the entire row / card text as the\n * menu's name. A root that reports `false` must expose `ariaLabel` as the way\n * to name the menu.\n *\n * A `Signal` rather than a plain `boolean` because a multi-opener root\n * (`[forMenu]`) has heterogeneous openers: a button opener *is* a labelling\n * control while a right-click region is not, so the answer is a property of\n * the **active** opener and changes as the menu is opened from a different one. Roots with a\n * single fixed trigger flavour report a constant signal.\n */\n readonly triggerLabelsMenu?: Signal<boolean>;\n\n /** Anchor passed to floating-ui — `HTMLElement` (Dropdown) or `VirtualElement` (Context). */\n readonly anchor: Signal<ReferenceElement | null>;\n\n /**\n * The element the menu was opened from (the trigger button or right-click\n * region). Focus returns here on close, except after a keyboard activation\n * from a focused element inside a right-click region, which returns focus to\n * that element while it is still in the document.\n */\n readonly trigger: Signal<HTMLElement | null>;\n registerTrigger(el: HTMLElement): void;\n unregisterTrigger(el: HTMLElement): void;\n\n /** The mounted `[forMenuContent]` element. Submenus exempt their parent's content. */\n readonly content: Signal<HTMLElement | null>;\n registerContent(el: HTMLElement): void;\n unregisterContent(el: HTMLElement): void;\n\n /**\n * The enclosing menu, when this context is a `[forMenuSub]`. `null` for\n * top-level roots (`[forDropdownMenu]`, `[forContextMenu]`, and the\n * `[forMenubar]`-flavored ctx). Items use it to route ArrowLeft /\n * item-activation upward.\n */\n readonly parentMenu: ForMenuContext | null;\n\n /**\n * The enclosing menubar, when this context is the top-level menu of a\n * `[forMenubar]`. `null` otherwise. `[forMenuItem]` and `[forMenuContent]`\n * route ArrowLeft / ArrowRight up to it for cross-menu navigation when\n * there's no parent submenu. Typed as the minimal `MenuSiblingNavigator`\n * so the generic menu layer stays free of any concrete-root import.\n */\n readonly menubar?: MenuSiblingNavigator | null;\n\n /**\n * Elements treated as \"inside\" by the dismissible layer. DropdownMenu\n * exempts the trigger button (clicks on it toggle via the trigger\n * directive — without exemption they'd also fire pointer-down-outside\n * and double-close). ContextMenu exempts nothing — a left-click on the\n * region while the menu is open should close it.\n */\n readonly dismissibleExemptions: Signal<readonly HTMLElement[]>;\n\n registerItem(handle: ForMenuItemHandle): void;\n unregisterItem(handle: ForMenuItemHandle): void;\n\n /** Move focus inside the menu in response to an arrow / Home / End key. */\n navigate(currentItem: HTMLElement, action: ListNavigationAction): void;\n /**\n * Prefix-match against item text content and focus the first match. Returns\n * `true` when the key was consumed as a typeahead character (a printable\n * char, or Space while the buffer is already non-empty). Items applied on a\n * native `<button>` use this to `preventDefault()` a mid-typeahead Space so\n * it extends the buffer instead of activating the focused item.\n */\n handleTypeahead(event: KeyboardEvent): boolean;\n /**\n * Clear `data-highlighted` from every item without moving focus. Called by\n * `[forMenuContent]` on `pointerleave` so the hover highlight follows the\n * pointer off the surface (hover-follows-pointer).\n */\n clearItemHighlights(): void;\n /**\n * Focuses the first or last enabled item per `target` — the contract-level\n * resolution of {@link initialFocus}, so a piece that reads that signal hands\n * the value straight back instead of re-deriving which of the two granular\n * calls it maps to. `[forMenuContent]` uses it for the mount-time initial\n * focus; the mapping itself is owned once by core's `MenuItemList`. This is\n * the contract's only initial-focus entry point — the granular\n * `focusFirstEnabledItem` / `focusLastEnabledItem` pair stays on the concrete\n * controllers as an imperative escape hatch and is not part of what an\n * implementor owes. Returns `true` if focus moved; `false` when no enabled\n * items exist.\n */\n focusInitialEnabledItem(target: 'first' | 'last'): boolean;\n\n /**\n * Trigger entry points — toggle/open honour `disabled`. `modality`\n * (default `'keyboard'`) records how the open was activated: a `'pointer'`\n * open keeps the programmatic initial focus from reflecting\n * `data-highlighted` on the focused item, while a `'keyboard'` open\n * highlights it per the APG menu-button pattern. The DOM focus move itself\n * is identical in both modalities.\n */\n toggle(initialFocus?: 'first' | 'last', modality?: MenuActivationModality): void;\n openMenu(initialFocus?: 'first' | 'last', modality?: MenuActivationModality): void;\n closeMenu(reason: ForMenuCloseReason): void;\n\n /**\n * Reason of the most recent close, or `null` while the menu is open / has\n * never closed. Reset to `null` on every open. `[forMenuContent]` reads it\n * to skip its return-focus when the close was a `'tab'` — letting Tab move\n * focus out of the menu (per WAI-ARIA APG) instead of snapping it back to\n * the trigger.\n */\n readonly lastCloseReason: Signal<ForMenuCloseReason | null>;\n\n /**\n * Abort a pending pointer-driven (hover) close on this menu, if one is\n * scheduled. A descendant submenu walks up the `parentMenu` chain calling\n * this so the whole open chain stays alive while the pointer travels\n * between levels. Optional — only `[forMenuSub]` schedules hover-closes, so\n * top-level roots (Dropdown / Context / Menubar) need not implement it.\n */\n cancelPendingClose?(): void;\n\n /**\n * Schedule a pointer-driven (hover) open of this menu. Optional — only\n * `[forMenuSub]` opens on hover; top-level roots open on click / right-click.\n * The sub-trigger calls it on `pointerenter` via optional chaining.\n */\n scheduleOpenByPointer?(): void;\n\n /**\n * The pointer left this menu's trigger (client coordinates of the leave).\n * Optional — only `[forMenuSub]` reacts, arming the pointer-grace \"safe\n * triangle\" toward its content. The sub-trigger calls it on `pointerleave`.\n */\n onTriggerPointerLeave?(cursor: Point): void;\n\n /**\n * Escape is consumer-owned (its close emits `(escapeKeyDown)`, stops\n * propagation, and closes with reason `'escape'`); Content forwards the raw\n * `KeyboardEvent`.\n */\n emitEscapeKeyDown(event: KeyboardEvent): void;\n /**\n * Outside-interaction emit forwarders. The specific and composite channels\n * observe the same veto, so `preventDefault()` from either one suppresses the\n * close that otherwise follows.\n */\n emitPointerDownOutside(veto: VetoableNativeEvent<PointerEvent>): void;\n emitFocusOutside(veto: VetoableNativeEvent<FocusEvent>): void;\n emitInteractOutside(veto: VetoableNativeEvent<PointerEvent | FocusEvent>): void;\n /** Implicit close requested by the shell after an un-vetoed outside interaction. */\n requestClose(reason: 'pointerDownOutside' | 'focusOutside'): void;\n\n /**\n * Hooks into the auto-focus pipeline. Content fires these just before\n * its imperative `.focus()` (open) or the trigger return-focus (close);\n * `event.preventDefault()` skips the move. Returns `true` when the\n * consumer vetoed.\n */\n emitAutoFocusOnOpen(): boolean;\n emitAutoFocusOnClose(): boolean;\n}\n\nexport type { MenuActivationModality };\n\n/**\n * Nesting descriptor for a menu level's dismissible layer, derived from the\n * `parentMenu` chain: the chain identity is the outermost menu context and the\n * depth is the number of hops needed to reach it (`0` for a top-level\n * `[forDropdownMenu]` / `[forContextMenu]` / `[forMenubar]` menu, `1` for its\n * first `[forMenuSub]`, and so on).\n *\n * Menu levels are ordered on the layer stack by this depth rather than by the\n * order their `afterNextRender` callbacks ran, because a menu and its submenu\n * mounted in the same render pass activate child-before-parent — which would\n * put the parent above its own submenu and make the submenu's first focus close\n * the whole chain with reason `'focusOutside'`.\n */\nexport function menuLayerNesting(ctx: ForMenuContext): DismissibleLayerNesting {\n let chain: ForMenuContext = ctx;\n let depth = 0;\n while (chain.parentMenu) {\n chain = chain.parentMenu;\n depth++;\n }\n return { chain, depth };\n}\n\nexport const FOR_MENU_CONTEXT = new InjectionToken<ForMenuContext>('FOR_MENU_CONTEXT');\n\nexport function injectMenuContext(piece: string): ForMenuContext {\n const ctx = inject(FOR_MENU_CONTEXT, { optional: true });\n if (!ctx) {\n throw orphanContextError({\n code: 'FORCDK-MENU-001',\n piece,\n root: '[forMenu], [forDropdownMenu], [forContextMenu], [forMenubar], or [forMenuSub]',\n token: 'FOR_MENU_CONTEXT',\n });\n }\n return ctx;\n}\n","import { type Signal } from '@angular/core';\n\nimport {\n accessibleTextContent,\n Collection,\n type CollectionHandle,\n firstEnabledHandle,\n injectTypeahead,\n lastEnabledHandle,\n type ListNavigationAction,\n nextEnabledHandle,\n resolveListTypeahead,\n type Typeahead,\n} from 'forty-cdk/core';\n\n/**\n * Item handle the list's `Collection` registers. Structurally compatible\n * with primitives' `ForMenuItemHandle` — typing is generic so the unit\n * stays orthogonal to `./menu-context` (no cycle into a primitive).\n *\n * Stays exported from `core/src/public-api.ts` — internal tier, not blessed —\n * because it is the default type argument of `MenuOverlay`, which the emitted\n * `.d.ts` names as `MenuOverlay<MenuItemHandle>` for the `protected readonly\n * _overlay` field on `[forDropdownMenu]` / `[forContextMenu]` / `[forMenu]`.\n */\nexport interface MenuItemHandle extends CollectionHandle {\n /**\n * Narrowed from {@link CollectionHandle}'s `Node`: the list focuses its items\n * and scrolls them into view.\n */\n readonly host: HTMLElement;\n readonly disabled: Signal<boolean>;\n readonly textValue?: Signal<string>;\n /**\n * Tells the item that the next focus it receives is a programmatic move\n * that must not reflect `data-highlighted` (the initial focus of a\n * pointer-driven open). One-shot: the item consumes the suppression on its\n * next `focus` event. Optional — items that don't reflect a highlight\n * (e.g. `[forMenuSubTrigger]`) simply omit it.\n */\n suppressHighlightOnNextFocus?(): void;\n /**\n * Drops the item's `data-highlighted` without moving DOM focus. Called when\n * the pointer leaves the menu surface so the hovered item stops reading as\n * the active candidate while keyboard navigation stays anchored on it.\n * Optional — items that don't reflect a highlight omit it.\n */\n clearHighlight?(): void;\n}\n\n/**\n * The keyboard-focus mechanics shared by every menu surface that holds a\n * vertical list of `menuitem`s: the item `Collection`, a typeahead buffer,\n * arrow / Home / End navigation, prefix-match typeahead, and the\n * first/last-enabled focus moves used on mount.\n *\n * Both `MenuOverlay` (for `[forDropdownMenu]` / `[forContextMenu]` /\n * `[forMenuSub]`) and `[forMenubar]`'s multiplexed menu context delegate their\n * navigate / typeahead / focus behaviour to this unit.\n *\n * `loop` is read through an accessor so the owner can forward its own\n * reactive `loop` input without the unit depending on a specific source.\n *\n * Construct via `createMenuItemList` from a directive / helper field\n * initializer so the `injectTypeahead()` `DestroyRef` hookup resolves\n * through the surrounding injector.\n */\nexport class MenuItemList<H extends MenuItemHandle = MenuItemHandle> {\n readonly #items = new Collection<H>();\n readonly #typeahead: Typeahead;\n readonly #loop: () => boolean;\n\n constructor(loop: () => boolean, typeahead: Typeahead) {\n this.#loop = loop;\n this.#typeahead = typeahead;\n }\n\n registerItem(handle: H): void {\n this.#items.register(handle);\n }\n\n unregisterItem(handle: H): void {\n this.#items.unregister(handle);\n }\n\n /** Items registered with the menu, in DOM order. Exposed for tests / sub-menu wiring. */\n items(): readonly H[] {\n return this.#items.items();\n }\n\n /**\n * Moves focus to the next enabled item for an Arrow / Home / End action,\n * honouring the owner's `loop`. The focus move passes `preventScroll` and\n * then scrolls the target into view with `block: 'nearest'`, so a menu with\n * its own overflow scrolls minimally while the page underneath the portaled\n * surface never jumps.\n */\n navigate(currentItem: HTMLElement, action: ListNavigationAction): void {\n const target = nextEnabledHandle(this.#items.items(), currentItem, action, {\n loop: this.#loop(),\n });\n if (!target) {\n return;\n }\n focusMenuItemHost(target.host);\n }\n\n /**\n * Feeds `event` to the typeahead buffer and focuses the first matching item.\n * An item matches on its `textValue` when set, else on its accessible text:\n * an `aria-hidden` subtree (a `[forMenuItemIndicator]` glyph, an icon, a\n * badge) contributes nothing, while visually-hidden but announced content\n * still does. Text and buffer are compared trimmed, case-insensitively and\n * diacritics-insensitively, so `e` reaches `Éditer`.\n * Returns `true` when the key was consumed as a typeahead character (a\n * printable char, or Space while the buffer is already non-empty), `false`\n * otherwise. A consumed Space is `preventDefault()`-ed, so it extends the\n * buffer instead of triggering a native `<button>` item's activation. The\n * focus move passes `preventScroll` and reveals the match with\n * `scrollIntoView({ block: 'nearest' })`.\n */\n handleTypeahead(event: KeyboardEvent): boolean {\n const items = this.#items.items();\n const { handled, match } = resolveListTypeahead(this.#typeahead, event, {\n items,\n anchorIndex: items.findIndex((item) => item.host === event.target),\n getText: (item) => {\n const override = item.textValue?.() ?? '';\n return override !== '' ? override : accessibleTextContent(item.host);\n },\n isDisabled: (item) => item.disabled(),\n });\n if (match) {\n focusMenuItemHost(match.host);\n }\n return handled;\n }\n\n /**\n * Focuses the first enabled item. Pass `highlight: false` when the move is\n * the programmatic initial focus of a pointer-driven open, so the item\n * receives DOM focus without reflecting `data-highlighted`. The move passes\n * `preventScroll`: the menu surface is portaled and `position: fixed`, and\n * floating-ui has not resolved its placement yet when the initial focus\n * runs, so letting the browser scroll for it would move the page (and the\n * anchor) under a pointer-driven open.\n */\n focusFirstEnabledItem(highlight = true): boolean {\n const target = firstEnabledHandle(this.#items.items());\n if (!target) {\n return false;\n }\n this.#focusItem(target, highlight);\n return true;\n }\n\n /**\n * Focuses the last enabled item. Pass `highlight: false` when the move is\n * the programmatic initial focus of a pointer-driven open, so the item\n * receives DOM focus without reflecting `data-highlighted`. Like\n * {@link focusFirstEnabledItem} the move passes `preventScroll` and reveals\n * the item with `scrollIntoView({ block: 'nearest' })`, so a scrollable menu\n * still scrolls its own overflow to the last item.\n */\n focusLastEnabledItem(highlight = true): boolean {\n const target = lastEnabledHandle(this.#items.items());\n if (!target) {\n return false;\n }\n this.#focusItem(target, highlight);\n return true;\n }\n\n /**\n * Focuses the first or last enabled item per `target`. The single owner of the\n * `'first' | 'last'` → focus-call mapping every menu surface resolves its\n * initial focus through — the mount path, the already-open re-focus branch of\n * a `MenuOverlay`, and `[forMenubar]`'s equivalent — so the fallback ordering\n * and any future widening of the target union live in one place instead of one\n * copy per surface. `highlight` behaves exactly as on\n * {@link focusFirstEnabledItem} / {@link focusLastEnabledItem}.\n */\n focusInitialEnabledItem(target: 'first' | 'last', highlight = true): boolean {\n return target === 'last'\n ? this.focusLastEnabledItem(highlight)\n : this.focusFirstEnabledItem(highlight);\n }\n\n #focusItem(item: H, highlight: boolean): void {\n if (!highlight) {\n item.suppressHighlightOnNextFocus?.();\n }\n focusMenuItemHost(item.host);\n }\n\n /**\n * Drops `data-highlighted` from every registered item without touching DOM\n * focus. Used when the pointer leaves the menu surface so no item keeps\n * reading as the active candidate.\n */\n clearHighlights(): void {\n for (const item of this.#items.items()) {\n item.clearHighlight?.();\n }\n }\n}\n\n/**\n * Creates a `MenuItemList` from a directive / helper field initializer.\n * `loop` is the owner's reactive loop accessor; the typeahead instance is\n * created with `injectTypeahead()` so its debounce timer is torn down with\n * the surrounding `DestroyRef`.\n */\nexport function createMenuItemList<H extends MenuItemHandle = MenuItemHandle>(\n loop: () => boolean,\n): MenuItemList<H> {\n return new MenuItemList<H>(loop, injectTypeahead());\n}\n\nfunction focusMenuItemHost(host: HTMLElement): void {\n host.focus({ preventScroll: true });\n host.scrollIntoView?.({ block: 'nearest' });\n}\n","import { computed, signal, type Signal, type WritableSignal } from '@angular/core';\nimport type { ReferenceElement, VirtualElement } from '@floating-ui/dom';\n\nimport type { FloatingAlign, FloatingSide } from '../floating/floating';\nimport { adoptHostId } from 'forty-cdk/core';\nimport type { ForMenuContext } from './menu-context';\n\n/**\n * Builds a floating-ui `VirtualElement` pinned to a by-value rect snapshot, so\n * later layout changes never shift the anchor. A 0×0 box models a pointer\n * position; a real box models the focused element a keyboard activation\n * anchored at.\n */\nfunction menuVirtualAnchor(x: number, y: number, width: number, height: number): VirtualElement {\n return {\n getBoundingClientRect: () => ({\n x,\n y,\n width,\n height,\n top: y,\n left: x,\n right: x + width,\n bottom: y + height,\n toJSON() {\n return this;\n },\n }),\n };\n}\n\n/**\n * Per-opener override of a menu root's **placement** inputs, applied only while\n * that opener is the active one. Every key is optional and an omitted one\n * resolves the root's own input, so an opener that overrides nothing positions\n * exactly as the root does.\n *\n * It carries the four values an opener's own geometry can legitimately decide.\n * The root keeps the rest of the positioning surface (`avoidCollisions`,\n * `collisionPadding`, `sticky`, …), which is collision / viewport policy for the\n * surface rather than a property of the opener that fired.\n *\n * The canonical case is a `[forMenu]` shared by heterogeneous openers: a button\n * opener wants the few pixels of clearance `[forDropdownMenu]` seeds, while a\n * pointer-anchored right-click region wants to sit flush at the cursor.\n */\nexport interface MenuOpenerPositioning {\n /** Side the menu is anchored to for this opener's opens. */\n readonly side?: FloatingSide;\n /** Alignment along the chosen side for this opener's opens. */\n readonly align?: FloatingAlign;\n /** Gap (px) between this opener's anchor and the menu along the main axis. */\n readonly sideOffset?: number;\n /** Gap (px) along the cross axis for this opener's opens. */\n readonly alignOffset?: number;\n}\n\n/** What an opener declares about itself when it registers with a menu root. */\nexport interface MenuOpenerOptions {\n /**\n * The opener's own aria-wiring id. Openers that own an id (`hostId`) pass it\n * so two openers on one root never emit the same `id`; omitting it falls the\n * opener back to the root's seeded trigger id, which is the single-opener\n * shape `[forMenuSubTrigger]` / `[forMenubarTrigger]` still use.\n */\n readonly id?: Signal<string>;\n /**\n * Whether a pointer-down on this opener counts as \"inside\" the menu. A\n * toggle-style opener (a `[forDropdownMenuTrigger]` button) must be exempt,\n * or its own click would also fire pointer-down-outside and double-close. A\n * right-click region must not be, so a left-click on it closes the menu like\n * any other outside click. Defaults to `false`.\n */\n readonly dismissibleExempt?: boolean;\n /**\n * Whether this opener's own accessible name is a valid name for the menu\n * surface. A discrete labelling control (a `[forDropdownMenuTrigger]` button)\n * passes `true`, so the surface can fall back to\n * `aria-labelledby=\"<openerId>\"`; a right-click region\n * (`[forContextMenuTrigger]`) passes `false`, because pointing the menu's name\n * at a whole row would announce the row's entire text. Defaults to `false` —\n * the conservative answer, which is also what a root with no resolvable active\n * opener reports.\n */\n readonly labelsMenu?: boolean;\n /**\n * This opener's placement override, read while it is the active one. Passed as\n * a signal so a bound `[menuPositioning]` flows through without\n * re-registering the element. Omitting it (and emitting `null`) resolves the\n * root's own positioning inputs.\n */\n readonly positioning?: Signal<MenuOpenerPositioning | null>;\n}\n\n/**\n * The opener-registration protocol a multi-opener menu root exposes. Deliberately\n * **not** part of `ForMenuContext`: how openers wire themselves into a root is\n * the piece-registration protocol the library refactors freely, whereas\n * `ForMenuContext` is the blessed consumer read surface. It stays out of every\n * stable entry point's barrel and out of every public signature — the trigger\n * directives resolve it by narrowing their already-resolved root with\n * {@link asMenuOpenerRegistration}.\n */\nexport interface MenuOpenerRegistration {\n /** Registers `element` as an opener of this menu. Re-registering replaces the entry. */\n registerOpener(element: HTMLElement, options?: MenuOpenerOptions): void;\n /** Removes `element` from the opener registry, clearing it as active if it was. */\n unregisterOpener(element: HTMLElement): void;\n /**\n * Marks `element` as the opener driving the current open. Return-focus, the\n * surface's `aria-labelledby` fallback, and the anchor all resolve against it.\n * `returnFocusTarget` records where focus returns for this open instead of\n * `element` — the focused descendant a keyboard activation started from.\n */\n activateOpener(element: HTMLElement, returnFocusTarget?: HTMLElement | null): void;\n /**\n * The element focus returns to when the menu closes: the target the active\n * opener recorded for this open while it is still in the document, else the\n * active opener itself.\n */\n returnFocusTarget(): HTMLElement | null;\n /** Anchors the active opener's next open at a 0×0 point in viewport coordinates. */\n setVirtualAnchor(x: number, y: number): void;\n /** Anchors the active opener's next open at a by-value snapshot of `rect`. */\n setVirtualAnchorFromRect(rect: DOMRect): void;\n}\n\n/**\n * Narrows a resolved menu root to its opener-registration protocol, or `null`\n * when the root does not implement one. Every root built on `MenuOverlayHost`\n * does; `[forMenubar]`'s multiplexed context does not, because the bar owns its\n * own trigger multiplexing. A trigger that gets `null` falls back to the\n * single-opener `registerTrigger` path, which is exactly the behaviour it had\n * before multi-opener support existed.\n */\nexport function asMenuOpenerRegistration(root: object): MenuOpenerRegistration | null {\n const candidate = root as Partial<MenuOpenerRegistration>;\n return typeof candidate.registerOpener === 'function'\n ? (candidate as MenuOpenerRegistration)\n : null;\n}\n\n/**\n * The element a menu returns focus to on close: the opener registry's per-open\n * target on a root that has one, the context's `trigger` otherwise.\n */\nexport function menuReturnFocusTarget(ctx: Pick<ForMenuContext, 'trigger'>): HTMLElement | null {\n const openers = asMenuOpenerRegistration(ctx);\n return openers ? openers.returnFocusTarget() : ctx.trigger();\n}\n\ninterface MenuOpenerEntry {\n readonly element: HTMLElement;\n readonly id: Signal<string>;\n readonly virtualAnchor: WritableSignal<ReferenceElement | null>;\n readonly dismissibleExempt: boolean;\n readonly labelsMenu: boolean;\n readonly positioning: Signal<MenuOpenerPositioning | null> | null;\n}\n\n/**\n * The registry of openers behind a menu root. Several triggers may drive one\n * menu definition, which is what lets `[forMenu]` be declared once and opened\n * from many places.\n *\n * Everything the mounted surface reads resolves against the **active** opener:\n * the element return-focus lands on, the id the surface names itself after,\n * whether that id is a valid name at all, the floating-ui anchor, and the\n * placement override that anchor is measured with. \"Active\" is whichever opener\n * last called {@link activate}, falling back to the sole registered opener — so\n * a single-opener root and a programmatic open resolve unambiguously.\n *\n * Each opener carries its own optional virtual anchor, so switching openers\n * switches the anchor with no clearing step: a pointer-anchored right-click\n * opener keeps its `VirtualElement` while a button opener keeps resolving to its\n * own element.\n */\nexport class MenuOpenerRegistry {\n readonly #seedId: WritableSignal<string>;\n readonly #entries = signal<readonly MenuOpenerEntry[]>([]);\n readonly #activeElement = signal<HTMLElement | null>(null);\n #returnFocusTarget: HTMLElement | null = null;\n\n readonly #active = computed<MenuOpenerEntry | null>(() => {\n const entries = this.#entries();\n const active = this.#activeElement();\n if (active !== null) {\n const match = entries.find((entry) => entry.element === active);\n if (match !== undefined) {\n return match;\n }\n }\n return entries.length === 1 ? (entries[0] ?? null) : null;\n });\n\n /**\n * Id of the opener driving the current open, falling back to the root's seeded\n * trigger id while no single opener is resolvable. Never the empty string, so\n * the surface's `aria-labelledby` fallback keeps the shape it had when the id\n * lived on the root.\n */\n readonly id: Signal<string>;\n\n /**\n * The active opener's element — the return-focus target, unless the open\n * recorded one of its own (see {@link returnFocusTarget}).\n */\n readonly element = computed<HTMLElement | null>(() => this.#active()?.element ?? null);\n\n /**\n * The active opener's floating-ui anchor: its virtual anchor when it set one\n * (a pointer / rect activation), otherwise its own element.\n */\n readonly anchor = computed<ReferenceElement | null>(() => {\n const active = this.#active();\n if (active === null) {\n return null;\n }\n return active.virtualAnchor() ?? active.element;\n });\n\n /**\n * The active opener's virtual anchor only — `null` until an opener sets one.\n * `[forContextMenu]` resolves its anchor through this so a right-click menu\n * with no recorded pointer position stays unanchored rather than falling back\n * to its whole right-click region.\n */\n readonly virtualAnchor = computed<ReferenceElement | null>(\n () => this.#active()?.virtualAnchor() ?? null,\n );\n\n /** Every registered opener that asked to count as \"inside\" the menu. */\n readonly dismissibleExemptions = computed<readonly HTMLElement[]>(() =>\n this.#entries()\n .filter((entry) => entry.dismissibleExempt)\n .map((entry) => entry.element),\n );\n\n /**\n * Whether the **active** opener's accessible name is a valid name for the menu\n * surface, so `[forMenuContent]` may fall back to\n * `aria-labelledby=\"<openerId>\"`. Per-opener rather than per-root because a\n * shared menu's openers are heterogeneous — a button opener is a labelling\n * control, a right-click region is not — and the answer therefore flips as the\n * menu is opened from a different one.\n *\n * `false` while no single opener is resolvable: the surface would otherwise\n * name itself after the root's seeded trigger id, which no element carries\n * once every opener owns an id of its own.\n */\n readonly labelsMenu = computed<boolean>(() => this.#active()?.labelsMenu ?? false);\n\n /**\n * The **active** opener's placement override, or `null` when it declared none\n * (and while no single opener is resolvable). Per-opener for the same reason\n * the anchor is: a shared menu's openers are heterogeneous, so the offsets a\n * button opener wants are not the ones a pointer-anchored region wants. A\n * root resolves each key against its own input — `positioning()?.x ??\n * xInput()` — so an opener that overrides nothing changes nothing.\n */\n readonly positioning = computed<MenuOpenerPositioning | null>(\n () => this.#active()?.positioning?.() ?? null,\n );\n\n constructor(seedId: WritableSignal<string>) {\n this.#seedId = seedId;\n this.id = computed(() => this.#active()?.id() ?? this.#seedId());\n }\n\n /**\n * Registers `element`, adopting a consumer-set static `id` into the seed when\n * the opener owns no id of its own.\n *\n * Reads no signal: openers register from inside their trigger's\n * `effect`, so touching `#entries` here would make that effect depend on the\n * very signal it writes and spin forever.\n */\n register(element: HTMLElement, options: MenuOpenerOptions = {}): void {\n const id = options.id;\n if (id === undefined) {\n adoptHostId(element, this.#seedId);\n }\n const entry: MenuOpenerEntry = {\n element,\n id: id ?? this.#seedId,\n virtualAnchor: signal<ReferenceElement | null>(null),\n dismissibleExempt: options.dismissibleExempt ?? false,\n labelsMenu: options.labelsMenu ?? false,\n positioning: options.positioning ?? null,\n };\n this.#entries.update((entries) => [\n ...entries.filter((existing) => existing.element !== element),\n entry,\n ]);\n }\n\n unregister(element: HTMLElement): void {\n this.#entries.update((entries) => entries.filter((entry) => entry.element !== element));\n if (this.#activeElement() === element) {\n this.#activeElement.set(null);\n this.#returnFocusTarget = null;\n }\n }\n\n activate(element: HTMLElement, returnFocusTarget: HTMLElement | null = null): void {\n this.#activeElement.set(element);\n this.#returnFocusTarget = returnFocusTarget;\n }\n\n /**\n * The return-focus target of the current open: the one {@link activate}\n * recorded while it is still in the document, else the active opener. Read at\n * close time rather than derived, because a menu action may remove the\n * recorded element from the document.\n */\n returnFocusTarget(): HTMLElement | null {\n const target = this.#returnFocusTarget;\n return target !== null && target.isConnected ? target : this.element();\n }\n\n setVirtualAnchor(x: number, y: number): void {\n this.#active()?.virtualAnchor.set(menuVirtualAnchor(x, y, 0, 0));\n }\n\n setVirtualAnchorFromRect(rect: DOMRect): void {\n this.#active()?.virtualAnchor.set(menuVirtualAnchor(rect.x, rect.y, rect.width, rect.height));\n }\n}\n","import type { ModelSignal, Signal } from '@angular/core';\nimport type { ReferenceElement } from '@floating-ui/dom';\n\nimport { type ListNavigationAction, type VetoableNativeEvent } from 'forty-cdk/core';\nimport {\n OverlayController,\n type OverlayEmitTargets,\n type OverlayTransitionOptions,\n} from '../overlay-controller/overlay-controller';\nimport {\n MenuOpenerRegistry,\n type MenuOpenerOptions,\n type MenuOpenerPositioning,\n} from './menu-opener-registry';\nimport type { ForMenuCloseReason } from './menu-context';\nimport { createMenuItemList, type MenuItemHandle, type MenuItemList } from './menu-item-list';\n\n/**\n * How a menu open was activated. `'keyboard'` (the default) highlights the\n * initially focused item per the APG menu-button pattern; `'pointer'` keeps\n * the programmatic initial focus from reflecting `data-highlighted` so a\n * mouse-opened menu doesn't read as \"preselected\". The DOM focus move itself\n * is identical in both modalities.\n */\nexport type MenuActivationModality = 'pointer' | 'keyboard';\n\n/**\n * Wiring the directive forwards into the helper. Inputs / outputs / models\n * stay declared on the directive (Angular needs them as fields for template\n * binding); the helper reads them through these references so the close\n * decisions, navigation, and veto plumbing live in one place.\n */\nexport interface MenuOverlayHooks extends OverlayEmitTargets {\n readonly open: ModelSignal<boolean>;\n readonly disabled: Signal<boolean>;\n readonly dismissible: Signal<boolean>;\n readonly loop: Signal<boolean>;\n\n /**\n * Optional side effect run after `openMenu` resolves the open, receiving the\n * resolved initial-focus target. `[forMenuSub]` uses it to cancel in-flight\n * hover scheduling and set its focus-suppression flags from\n * `options.suppressFocusMoves` (a keyboard / click open supersedes hover).\n * Top-level roots (`[forDropdownMenu]` / `[forContextMenu]`) pass neither\n * hook.\n *\n * It also runs when `openMenu` re-targets an **already-open** menu (no model\n * write, focus moved instead), so a pending hover-close is still cancelled by\n * an open key pressed on a mounted submenu.\n */\n readonly onOpen?: (initialFocus: 'first' | 'last', options: OverlayTransitionOptions) => void;\n\n /**\n * Optional side effect run after `closeMenu` flips `open` to `false`,\n * receiving the close reason and the transition options. `[forMenuSub]` uses\n * it to cancel in-flight hover scheduling, set its focus-suppression flags\n * from `options.suppressFocusMoves`, and propagate the close upward through\n * the menu chain for every reason except `'escape'` / `'hover'` /\n * `'programmatic'`. Top-level roots pass neither hook.\n */\n readonly onClose?: (reason: ForMenuCloseReason, options: OverlayTransitionOptions) => void;\n}\n\n/**\n * Shared coordination behaviour between `ForDropdownMenu` and `ForContextMenu`\n * (and any future menu overlay root with the same item-collection / typeahead /\n * navigate / dismissible shape — Menubar's per-bar menu, a future free-floating\n * SubMenu).\n *\n * The helper owns:\n *\n * - the item list (`MenuItemList`: the item `Collection`, typeahead and the navigate / focus\n * moves), shared with `[forMenubar]`'s multiplexed menu context,\n * - the opener registry: every trigger that can open this menu, which one is driving the current\n * open, and the per-opener id / anchor / labelling policy resolved against it,\n * - the menu vocabulary over the shared {@link OverlayController} — `'first' | 'last'` initial\n * focus, `ForMenuCloseReason`, the `'pointer' | 'keyboard'` activation modality, and\n * `openMenu`'s already-open re-focus branch.\n *\n * Everything below that vocabulary — the trigger / content slots and their ids, the\n * initial-focus and close-reason state, the `disabled`-gated open / close / toggle transitions,\n * the outside / Escape forwarders, `requestClose`, and the auto-focus vetoes — is the shared\n * controller's, declared once and composed here.\n *\n * It does not own:\n *\n * - the resolved `anchor` signal, which each root derives differently — from the trigger element,\n * from a virtual anchor, or from the active opener,\n * - `dismissibleExemptions`, since only some roots exempt their trigger to stop a click toggle\n * double-firing as a pointer-down-outside,\n * - the `input()` / `output()` / `model()` declarations, which must stay on the directive class for\n * Angular's template binding to see them.\n *\n * Construct via `createMenuOverlay` from a directive's field initializer, so the helper's `inject()`\n * calls resolve through the directive's injector.\n */\nexport class MenuOverlay<H extends MenuItemHandle = MenuItemHandle> {\n readonly #itemList: MenuItemList<H>;\n\n readonly #openers: MenuOpenerRegistry;\n readonly #controller: OverlayController<'first' | 'last', ForMenuCloseReason>;\n\n /**\n * Id of the opener driving the current open — the active opener's own id when\n * it owns one, else the seeded `<idPrefix>-trigger-*` fallback. Non-empty from\n * construction, so `[forMenuContent]`'s `aria-labelledby` fallback keeps the\n * shape it had when a single id lived on the root.\n */\n readonly triggerId: Signal<string>;\n\n /** Unique id for the content element. Stable across the menu's lifetime. */\n readonly contentId: Signal<string>;\n\n /** Where focus should land when the menu mounts. Set by triggers before flipping `open`. */\n readonly initialFocus: Signal<'first' | 'last'>;\n\n /**\n * Reason of the most recent close, or `null` while the menu is open / has\n * never closed. Reset to `null` on every open. The shared `[forMenuContent]`\n * reads this to skip its return-focus on `'tab'` so Tab can advance focus\n * out of the menu instead of snapping back to the trigger.\n */\n readonly lastCloseReason: Signal<ForMenuCloseReason | null>;\n\n /**\n * The focusable element the menu should return focus to on close — the opener\n * that actually opened this instance, so a menu shared by several openers\n * hands focus back to the one the user used.\n */\n readonly trigger: Signal<HTMLElement | null>;\n\n /** The mounted `[forMenuContent]` element, or `null` while the menu is closed. */\n readonly content: Signal<HTMLElement | null>;\n\n /**\n * The active opener's floating-ui anchor: its virtual anchor when it recorded\n * one, else its own element. `[forMenu]` resolves its `anchor` through this so\n * the surface follows whichever opener fired.\n */\n readonly openerAnchor: Signal<ReferenceElement | null>;\n\n /**\n * The active opener's virtual anchor only, `null` until one is recorded.\n * `[forContextMenu]` resolves its `anchor` through this so a menu with no\n * recorded pointer position stays unanchored rather than falling back to its\n * whole right-click region.\n */\n readonly openerVirtualAnchor: Signal<ReferenceElement | null>;\n\n /** Registered openers that count as \"inside\" for outside-dismissal. */\n readonly openerExemptions: Signal<readonly HTMLElement[]>;\n\n /**\n * Whether the active opener is a discrete labelling control, so\n * `[forMenuContent]` may name itself `aria-labelledby=\"<triggerId>\"`.\n * `[forMenu]` exposes this as its `ForMenuContext.triggerLabelsMenu` so a\n * shared menu's name follows whichever opener fired.\n */\n readonly openerLabelsMenu: Signal<boolean>;\n\n /**\n * The active opener's placement override, `null` when it declared none. Each\n * root resolves its `side` / `align` / `sideOffset` / `alignOffset` against\n * its own input through this, so a shared menu positions per the opener that\n * fired while an opener with no override keeps the root's values.\n */\n readonly openerPositioning: Signal<MenuOpenerPositioning | null>;\n\n constructor(idPrefix: string, hooks: MenuOverlayHooks) {\n this.#itemList = createMenuItemList<H>(() => hooks.loop());\n let openers!: MenuOpenerRegistry;\n this.#controller = new OverlayController<'first' | 'last', ForMenuCloseReason>({\n idPrefix,\n createTrigger: (mintId) => {\n openers = new MenuOpenerRegistry(mintId());\n return openers;\n },\n defaultInitialFocus: 'first',\n disabled: hooks.disabled,\n dismissible: hooks.dismissible,\n isOpen: () => hooks.open(),\n setOpen: (open) => hooks.open.set(open),\n emit: hooks,\n escapeReason: 'escape',\n programmaticReason: 'programmatic',\n onOpen: hooks.onOpen,\n onClose: hooks.onClose,\n });\n this.#openers = openers;\n this.triggerId = this.#controller.triggerId;\n this.contentId = this.#controller.contentId;\n this.initialFocus = this.#controller.initialFocus;\n this.lastCloseReason = this.#controller.lastCloseReason;\n this.trigger = this.#controller.trigger;\n this.content = this.#controller.content;\n this.openerAnchor = this.#openers.anchor;\n this.openerVirtualAnchor = this.#openers.virtualAnchor;\n this.openerExemptions = this.#openers.dismissibleExemptions;\n this.openerLabelsMenu = this.#openers.labelsMenu;\n this.openerPositioning = this.#openers.positioning;\n }\n\n setInitialFocus(target: 'first' | 'last'): void {\n this.#controller.setInitialFocus(target);\n }\n\n registerTrigger(el: HTMLElement): void {\n this.#controller.registerTrigger(el);\n }\n\n unregisterTrigger(el: HTMLElement): void {\n this.#controller.unregisterTrigger(el);\n }\n\n registerOpener(element: HTMLElement, options?: MenuOpenerOptions): void {\n this.#openers.register(element, options);\n }\n\n unregisterOpener(element: HTMLElement): void {\n this.#openers.unregister(element);\n }\n\n activateOpener(element: HTMLElement, returnFocusTarget: HTMLElement | null = null): void {\n this.#openers.activate(element, returnFocusTarget);\n }\n\n /**\n * The element focus returns to on close: the target the active opener\n * recorded for this open while it is still in the document, else\n * {@link trigger}.\n */\n returnFocusTarget(): HTMLElement | null {\n return this.#openers.returnFocusTarget();\n }\n\n setVirtualAnchor(x: number, y: number): void {\n this.#openers.setVirtualAnchor(x, y);\n }\n\n setVirtualAnchorFromRect(rect: DOMRect): void {\n this.#openers.setVirtualAnchorFromRect(rect);\n }\n\n registerContent(el: HTMLElement): void {\n this.#controller.registerContent(el);\n }\n\n unregisterContent(el: HTMLElement): void {\n this.#controller.unregisterContent(el);\n }\n\n registerItem(handle: H): void {\n this.#itemList.registerItem(handle);\n }\n\n unregisterItem(handle: H): void {\n this.#itemList.unregisterItem(handle);\n }\n\n /** Items registered with the menu, in DOM order. Exposed for tests / sub-menu wiring. */\n items(): readonly H[] {\n return this.#itemList.items();\n }\n\n navigate(currentItem: HTMLElement, action: ListNavigationAction): void {\n this.#itemList.navigate(currentItem, action);\n }\n\n handleTypeahead(event: KeyboardEvent): boolean {\n return this.#itemList.handleTypeahead(event);\n }\n\n /**\n * Clears `data-highlighted` from every item without moving focus. The shared\n * `[forMenuContent]` calls this on `pointerleave` so the hover highlight\n * follows the pointer off the surface.\n */\n clearItemHighlights(): void {\n this.#itemList.clearHighlights();\n }\n\n /**\n * Focuses the first enabled item. When the most recent `openMenu` was\n * pointer-activated, this one move suppresses the item's focus-driven\n * `data-highlighted` (one-shot — later calls highlight normally).\n *\n * An imperative escape hatch for an explicit first / last move, independent of the resolved\n * {@link initialFocus} target. No piece of the library routes through it — they all go through\n * {@link focusInitialEnabledItem} — and `ForMenuContext` does not declare it.\n */\n focusFirstEnabledItem(): boolean {\n return this.#itemList.focusFirstEnabledItem(this.#controller.consumeInitialHighlight());\n }\n\n /**\n * Focuses the last enabled item. When the most recent `openMenu` was\n * pointer-activated, this one move suppresses the item's focus-driven\n * `data-highlighted` (one-shot — later calls highlight normally). The\n * granular counterpart of {@link focusFirstEnabledItem}, and like it an\n * imperative escape hatch rather than a `ForMenuContext` member.\n */\n focusLastEnabledItem(): boolean {\n return this.#itemList.focusLastEnabledItem(this.#controller.consumeInitialHighlight());\n }\n\n /**\n * Focuses the first or last enabled item per `target`, resolving the mapping\n * through the shared `MenuItemList` rather than re-deriving it here. Used by\n * the mount path (through the `ForMenuContext` contract) and by `openMenu`'s\n * already-open re-focus branch. When the most recent `openMenu` was\n * pointer-activated, this one move suppresses the item's focus-driven\n * `data-highlighted` (one-shot — later calls highlight normally).\n */\n focusInitialEnabledItem(target: 'first' | 'last'): boolean {\n return this.#itemList.focusInitialEnabledItem(\n target,\n this.#controller.consumeInitialHighlight(),\n );\n }\n\n /**\n * Toggle the menu open/closed from the trigger. The close branch reuses the\n * `'programmatic'` close reason by design — there is no distinct `'trigger'`\n * reason for the user-initiated toggle-close path.\n */\n toggle(\n initialFocus: 'first' | 'last' = 'first',\n modality: MenuActivationModality = 'keyboard',\n ): void {\n this.#controller.toggle(initialFocus, { highlight: modality === 'keyboard' });\n }\n\n /**\n * Opens the menu, recording where the initial focus should land and how\n * the open was activated. A `'pointer'` modality keeps that one initial\n * focus move from reflecting `data-highlighted` on the focused item.\n * `options` is forwarded verbatim to the `onOpen` hook — `[forMenuSub]`'s\n * hover-open passes `{ suppressFocusMoves: true }` so the mount does not\n * pull focus off whatever the user was on.\n *\n * When the menu is **already open** there is no state transition (and\n * therefore no `(openChange)` emit): focus moves straight to the requested\n * first / last enabled item instead, so an APG open key pressed on a trigger\n * whose menu is already mounted is never a dead key. The menu is never\n * toggled closed — the open keys have no close semantics in the APG patterns\n * — and a menu with no enabled item moves nothing rather than pulling focus\n * onto an item-less surface. The re-focus is not gated on the\n * `(autoFocusOnOpen)` veto: that veto covers the mount's automatic focus\n * move, and honouring it here would silently restore the dead key for\n * consumers who opted out of auto-focus-on-open. It *is* skipped for a\n * `{ suppressFocusMoves: true }` transition, whose whole contract is that no\n * imperative focus move may happen (`[forMenuSub]`'s hover-open).\n *\n * This branch is the menu's own: it stays out of the shared controller, which\n * reports the already-open case as an outcome rather than acting on it.\n */\n openMenu(\n initialFocus: 'first' | 'last' = 'first',\n modality: MenuActivationModality = 'keyboard',\n options: OverlayTransitionOptions = {},\n ): void {\n const outcome = this.#controller.open(initialFocus, {\n highlight: modality === 'keyboard',\n transition: options,\n });\n if (outcome === 'already-open' && !options.suppressFocusMoves) {\n this.focusInitialEnabledItem(initialFocus);\n }\n }\n\n /**\n * Closes the menu, recording `reason` as the `lastCloseReason` the content\n * pieces read. `options` is forwarded verbatim to the `onClose` hook —\n * `[forMenuSub]`'s hover-close passes `{ suppressFocusMoves: true }` so the\n * unmount does not yank focus back to the sub-trigger.\n */\n closeMenu(reason: ForMenuCloseReason, options: OverlayTransitionOptions = {}): void {\n this.#controller.close(reason, options);\n }\n\n emitEscapeKeyDown(event: KeyboardEvent): void {\n this.#controller.emitEscapeKeyDown(event);\n }\n\n emitPointerDownOutside(veto: VetoableNativeEvent<PointerEvent>): void {\n this.#controller.emitPointerDownOutside(veto);\n }\n\n emitFocusOutside(veto: VetoableNativeEvent<FocusEvent>): void {\n this.#controller.emitFocusOutside(veto);\n }\n\n emitInteractOutside(veto: VetoableNativeEvent<PointerEvent | FocusEvent>): void {\n this.#controller.emitInteractOutside(veto);\n }\n\n requestClose(reason: 'pointerDownOutside' | 'focusOutside'): void {\n this.#controller.requestClose(reason);\n }\n\n emitAutoFocusOnOpen(): boolean {\n return this.#controller.emitAutoFocusOnOpen();\n }\n\n emitAutoFocusOnClose(): boolean {\n return this.#controller.emitAutoFocusOnClose();\n }\n}\n\n/**\n * Creates a `MenuOverlay` from a directive field initializer. `idPrefix`\n * is the namespace fed to the shared `IdGenerator` (e.g.\n * `'for-dropdown-menu'`, `'for-context-menu'`); the helper generates\n * `<idPrefix>-trigger` and `<idPrefix>-content` ids off it.\n */\nexport function createMenuOverlay<H extends MenuItemHandle = MenuItemHandle>(\n idPrefix: string,\n hooks: MenuOverlayHooks,\n): MenuOverlay<H> {\n return new MenuOverlay<H>(idPrefix, hooks);\n}\n","import { Directive, type Signal } from '@angular/core';\n\nimport { AnchoredOverlayPositioningBase } from '../floating/anchored-overlay-positioning-base';\nimport { type ListNavigationAction, type VetoableNativeEvent } from 'forty-cdk/core';\nimport type { ForMenuCloseReason } from './menu-context';\nimport type { MenuItemHandle } from './menu-item-list';\nimport type { MenuOpenerOptions } from './menu-opener-registry';\nimport type { MenuActivationModality, MenuOverlay } from './menu-overlay';\n\n/**\n * Abstract base that forwards the `MenuOverlay` coordination slice every menu\n * root re-exposes — `[forDropdownMenu]`, `[forContextMenu]`, and `[forMenuSub]`\n * all extend it. Each subclass owns its own `MenuOverlay` instance (created\n * with its own id prefix and lifecycle hooks) and exposes it through the\n * abstract `_overlay` accessor; the base implements the trigger / content /\n * item registration, navigation, open/close, and veto pass-throughs once.\n *\n * This is the single place to add a member that is a pure pass-through to\n * `MenuOverlay`: declaring it here gives all three directives the method\n * without hand-written `.bind()` forwarding in each. Subclasses override only\n * the members that need extra behaviour (e.g. `[forMenuSub]` wraps\n * `registerContent` to attach pointer listeners and overrides the auto-focus\n * emitters to honour its hover focus-suppression flags).\n *\n * Kept generic over the item handle so the subclass's `MenuOverlay<H>` flows\n * through `registerItem` / `unregisterItem` without a cast.\n *\n * It also carries `AnchoredOverlayPositioningBase` for its subclasses: every\n * menu root is a trigger-anchored overlay, so inheriting the shared positioning\n * block here is what keeps the four of them from redeclaring it. The\n * `@Directive()` decorator is required for that inheritance — Angular only\n * collects signal inputs through a decorated chain.\n */\n@Directive()\nexport abstract class MenuOverlayHost<\n H extends MenuItemHandle = MenuItemHandle,\n> extends AnchoredOverlayPositioningBase {\n /** The subclass's `MenuOverlay` instance the base forwards to. */\n protected abstract readonly _overlay: MenuOverlay<H>;\n\n get triggerId(): Signal<string> {\n return this._overlay.triggerId;\n }\n\n get contentId(): Signal<string> {\n return this._overlay.contentId;\n }\n\n get initialFocus(): Signal<'first' | 'last'> {\n return this._overlay.initialFocus;\n }\n\n get lastCloseReason(): Signal<ForMenuCloseReason | null> {\n return this._overlay.lastCloseReason;\n }\n\n get trigger(): Signal<HTMLElement | null> {\n return this._overlay.trigger;\n }\n\n get content(): Signal<HTMLElement | null> {\n return this._overlay.content;\n }\n\n setInitialFocus(target: 'first' | 'last'): void {\n this._overlay.setInitialFocus(target);\n }\n\n registerTrigger(el: HTMLElement): void {\n this._overlay.registerTrigger(el);\n }\n\n unregisterTrigger(el: HTMLElement): void {\n this._overlay.unregisterTrigger(el);\n }\n\n /**\n * The `MenuOpenerRegistration` protocol, forwarded once for every root. Kept\n * `protected` on purpose: it is the piece-registration protocol, so it\n * must stay out of the roots' emitted `.d.ts` while remaining callable at\n * runtime — which is what the trigger directives' `asMenuOpenerRegistration`\n * narrowing relies on.\n */\n private registerOpener(element: HTMLElement, options?: MenuOpenerOptions): void {\n this._overlay.registerOpener(element, options);\n }\n\n private unregisterOpener(element: HTMLElement): void {\n this._overlay.unregisterOpener(element);\n }\n\n private activateOpener(element: HTMLElement, returnFocusTarget?: HTMLElement | null): void {\n this._overlay.activateOpener(element, returnFocusTarget);\n }\n\n private returnFocusTarget(): HTMLElement | null {\n return this._overlay.returnFocusTarget();\n }\n\n protected setVirtualAnchor(x: number, y: number): void {\n this._overlay.setVirtualAnchor(x, y);\n }\n\n protected setVirtualAnchorFromRect(rect: DOMRect): void {\n this._overlay.setVirtualAnchorFromRect(rect);\n }\n\n registerContent(el: HTMLElement): void {\n this._overlay.registerContent(el);\n }\n\n unregisterContent(el: HTMLElement): void {\n this._overlay.unregisterContent(el);\n }\n\n registerItem(handle: H): void {\n this._overlay.registerItem(handle);\n }\n\n unregisterItem(handle: H): void {\n this._overlay.unregisterItem(handle);\n }\n\n navigate(currentItem: HTMLElement, action: ListNavigationAction): void {\n this._overlay.navigate(currentItem, action);\n }\n\n handleTypeahead(event: KeyboardEvent): boolean {\n return this._overlay.handleTypeahead(event);\n }\n\n clearItemHighlights(): void {\n this._overlay.clearItemHighlights();\n }\n\n focusFirstEnabledItem(): boolean {\n return this._overlay.focusFirstEnabledItem();\n }\n\n focusLastEnabledItem(): boolean {\n return this._overlay.focusLastEnabledItem();\n }\n\n focusInitialEnabledItem(target: 'first' | 'last'): boolean {\n return this._overlay.focusInitialEnabledItem(target);\n }\n\n toggle(\n initialFocus: 'first' | 'last' = 'first',\n modality: MenuActivationModality = 'keyboard',\n ): void {\n this._overlay.toggle(initialFocus, modality);\n }\n\n openMenu(\n initialFocus: 'first' | 'last' = 'first',\n modality: MenuActivationModality = 'keyboard',\n ): void {\n this._overlay.openMenu(initialFocus, modality);\n }\n\n closeMenu(reason: ForMenuCloseReason): void {\n this._overlay.closeMenu(reason);\n }\n\n requestClose(reason: 'pointerDownOutside' | 'focusOutside'): void {\n this._overlay.requestClose(reason);\n }\n\n emitEscapeKeyDown(event: KeyboardEvent): void {\n this._overlay.emitEscapeKeyDown(event);\n }\n\n emitPointerDownOutside(veto: VetoableNativeEvent<PointerEvent>): void {\n this._overlay.emitPointerDownOutside(veto);\n }\n\n emitFocusOutside(veto: VetoableNativeEvent<FocusEvent>): void {\n this._overlay.emitFocusOutside(veto);\n }\n\n emitInteractOutside(veto: VetoableNativeEvent<PointerEvent | FocusEvent>): void {\n this._overlay.emitInteractOutside(veto);\n }\n\n emitAutoFocusOnOpen(): boolean {\n return this._overlay.emitAutoFocusOnOpen();\n }\n\n emitAutoFocusOnClose(): boolean {\n return this._overlay.emitAutoFocusOnClose();\n }\n}\n","import { DestroyRef, ElementRef, inject, type Signal } from '@angular/core';\n\nimport { injectPortal } from 'forty-cdk/core';\n\n/**\n * The members a modal surface's internal context adds for its backdrop piece. `ForDialog` and\n * `ForDrawer` implement them through `ModalSurfaceBase`.\n */\nexport interface ModalSurfaceBackdropContext {\n /**\n * The surface's host element, which the backdrop is portaled immediately before. `null` when no\n * surface host is rendered, and the backdrop is then appended to the container.\n */\n surfaceElement(): HTMLElement | null;\n /**\n * Whether the surface is the topmost layer owning the pointer channel, so a press on its\n * backdrop is not an outside press of a layer stacked above it.\n */\n isTopmostPointerLayer(): boolean;\n /**\n * Registers the backdrop as part of the surface, so the dismissible layer treats a press on it\n * as inside. The newest registration is the surface's backdrop, and a second one still mounted\n * once the render settles warns in dev mode.\n */\n registerBackdrop(el: HTMLElement): void;\n /** Removes a registered backdrop, leaving any newer registration in place. */\n unregisterBackdrop(el: HTMLElement): void;\n}\n\n/** What a backdrop piece reads off the modal surface that owns it. */\nexport interface ModalBackdropSurface extends ModalSurfaceBackdropContext {\n /** Portal target shared with the surface. `null` ⇒ `document.body`. */\n readonly container: Signal<HTMLElement | null>;\n /** Asks the surface to close with reason `'backdrop'`, gated on its `dismissible()`. */\n requestClose(reason: 'backdrop'): void;\n}\n\n/** Host listeners {@link injectModalBackdrop} hands back to the backdrop piece. */\nexport interface ModalBackdropHandle {\n /** Bind to the backdrop host's `(pointerdown)`. */\n readonly pointerDown: () => void;\n /** Bind to the backdrop host's `(click)`. */\n readonly click: (event: MouseEvent) => void;\n}\n\n/**\n * Wires a modal surface's backdrop piece: portals the host to the surface's container, registers\n * it on the surface for the piece's lifetime, and closes the surface with reason `'backdrop'` on a\n * click that lands on the backdrop itself.\n *\n * The backdrop lands immediately before its surface in the container, so two positioned elements\n * with no `z-index` paint the surface on top, and each backdrop of a stacked pair sits directly\n * below its own surface.\n *\n * The click closes the surface only when the surface was the topmost pointer layer as the press\n * began. A press that goes down while another layer is stacked above it (a nested drawer without a\n * backdrop of its own, a popover open inside the dialog) is that layer's outside press, so the\n * click ending it leaves the surface beneath open. A click with no preceding `pointerdown` is\n * judged on the stack as it stands.\n *\n * Must be called from the backdrop directive's injection context.\n */\nexport function injectModalBackdrop(surface: ModalBackdropSurface): ModalBackdropHandle {\n const host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n injectPortal({ target: surface.container, before: () => surface.surfaceElement() });\n surface.registerBackdrop(host);\n inject(DestroyRef).onDestroy(() => surface.unregisterBackdrop(host));\n\n let pressOwned: boolean | null = null;\n return {\n pointerDown: () => {\n pressOwned = surface.isTopmostPointerLayer();\n },\n click: (event) => {\n const owned = pressOwned ?? surface.isTopmostPointerLayer();\n pressOwned = null;\n if (event.target === host && owned) {\n surface.requestClose('backdrop');\n }\n },\n };\n}\n","import type { Signal } from '@angular/core';\n\nimport type {\n DismissibleLayerActivateOptions,\n DismissibleLayerChannel,\n} from '../dismissible-layer/dismissible-layer';\nimport { createVetoableNativeEvent, type VetoableNativeEvent } from 'forty-cdk/core';\n\n/**\n * Emit forwarders + implicit-close wiring for the outside-interaction channels\n * that {@link buildOutsideVetoOptions} folds into self-closing layer handlers.\n * Each wired outside channel builds one veto, emits it through the specific\n * output (if wired) and the composite `interactOutside` output (if wired), then\n * closes itself when un-vetoed and `dismissible()` is `true`. Escape is\n * intentionally absent: it never participates in the outside-close (it is a\n * one-shot channel whose close behaviour differs per shell), so each shell\n * wires its own `onEscapeKeyDown` alongside the object this returns.\n *\n * Every field is optional so a shell can register a layer listener only for the\n * channels its consumer actually forwards — the trigger-anchored overlays opt\n * out of individual channels (an input-focused combobox owns Escape on its\n * input and omits it here), while the modal shell forwards all three.\n */\nexport interface OutsideVetoConfig {\n /**\n * Whether an un-vetoed outside interaction fires the implicit\n * `requestClose`. Read fresh on every outside interaction.\n */\n readonly dismissible?: Signal<boolean>;\n /**\n * Called with the matching reason (`'pointerDownOutside'` / `'focusOutside'`)\n * when the consumer doesn't veto the outside interaction and `dismissible()`\n * is `true`. Each wired outside channel fires its own close.\n */\n readonly requestClose?: (reason: 'pointerDownOutside' | 'focusOutside') => void;\n /** Forwards the pointer-down-outside veto to the directive's `(pointerDownOutside)` output. */\n readonly emitPointerDownOutside?: (veto: VetoableNativeEvent<PointerEvent>) => void;\n /** Forwards the focus-outside veto to the directive's `(focusOutside)` output. */\n readonly emitFocusOutside?: (veto: VetoableNativeEvent<FocusEvent>) => void;\n /** Forwards the composite veto to the directive's `(interactOutside)` output. */\n readonly emitInteractOutside?: (veto: VetoableNativeEvent<PointerEvent | FocusEvent>) => void;\n}\n\n/**\n * Builds the pointer-down-outside / focus-outside entries of a\n * {@link DismissibleLayerActivateOptions}, folding the composite\n * `interactOutside` emit and the implicit close into each specific channel so\n * every wired outside channel closes itself.\n *\n * The protocol: each handler builds a single {@link VetoableNativeEvent} for\n * its physical interaction, hands it to the specific emitter (if wired) and\n * then to the composite `interactOutside` emitter (if wired), and — when\n * neither subscriber vetoed and `dismissible()` is `true` — calls\n * `requestClose(reason)` with the channel's reason (`'pointerDownOutside'` /\n * `'focusOutside'`). A `preventDefault()` from either the specific or the\n * composite subscriber suppresses the close, since both observe the same veto.\n * The pointer handler returns whether it closed, which is what lets an outside\n * press cascade to a lower layer that opted in.\n *\n * `onPointerDownOutside` is registered when either the specific\n * `emitPointerDownOutside` or the composite `emitInteractOutside` is wired, and\n * `onFocusOutside` likewise — matching what {@link outsideVetoChannels}\n * declares — so an interact-only wiring still gets both self-closing handlers.\n * Returns only the channels whose emitter is present, so the caller can spread\n * the result into its `dismissible.activate({...})` call alongside the pieces\n * that stay shell-specific (`exemptElements`, `onEscapeKeyDown`).\n */\nexport function buildOutsideVetoOptions(\n config: OutsideVetoConfig,\n): Pick<DismissibleLayerActivateOptions, 'onPointerDownOutside' | 'onFocusOutside'> {\n const options: Pick<DismissibleLayerActivateOptions, 'onPointerDownOutside' | 'onFocusOutside'> =\n {};\n const {\n dismissible,\n requestClose,\n emitPointerDownOutside,\n emitFocusOutside,\n emitInteractOutside,\n } = config;\n\n if (emitPointerDownOutside || emitInteractOutside) {\n options.onPointerDownOutside = (event) => {\n const veto = createVetoableNativeEvent<PointerEvent | FocusEvent>(event);\n emitPointerDownOutside?.(veto as VetoableNativeEvent<PointerEvent>);\n emitInteractOutside?.(veto);\n if (!veto.defaultPrevented && dismissible?.() && requestClose) {\n requestClose('pointerDownOutside');\n return true;\n }\n return false;\n };\n }\n\n if (emitFocusOutside || emitInteractOutside) {\n options.onFocusOutside = (event) => {\n const veto = createVetoableNativeEvent<PointerEvent | FocusEvent>(event);\n emitFocusOutside?.(veto as VetoableNativeEvent<FocusEvent>);\n emitInteractOutside?.(veto);\n if (!veto.defaultPrevented && dismissible?.() && requestClose) {\n requestClose('focusOutside');\n }\n };\n }\n\n return options;\n}\n\n/**\n * Derives the outside-interaction channels a shell must declare at\n * `dismissible.activate({ channels })` from the same {@link OutsideVetoConfig}\n * passed to {@link buildOutsideVetoOptions}. A layer owns `'pointer'` when it\n * forwards either the specific pointer-down-outside channel or the composite\n * interact-outside channel (which fires for pointer-downs too), and likewise\n * `'focus'` for focus-outside / interact-outside. A shell that forwards no\n * outside channel (an Escape-only surface) gets `[]` and stays transparent to\n * the real dismissible layers beneath it.\n */\nexport function outsideVetoChannels(config: OutsideVetoConfig): DismissibleLayerChannel[] {\n const channels: DismissibleLayerChannel[] = [];\n if (config.emitPointerDownOutside || config.emitInteractOutside) {\n channels.push('pointer');\n }\n if (config.emitFocusOutside || config.emitInteractOutside) {\n channels.push('focus');\n }\n return channels;\n}\n","import { Injectable } from '@angular/core';\n\nimport { composedParentElement } from 'forty-cdk/core';\n\n@Injectable({ providedIn: 'root' })\nexport class ModalActivationOrder {\n readonly #held = new Map<HTMLElement, (() => void)[]>();\n\n hold(host: HTMLElement): void {\n this.#held.set(host, []);\n }\n\n enclosingHeld(node: Element | null): HTMLElement | null {\n let cursor: Element | null = node;\n while (cursor !== null) {\n if (cursor instanceof HTMLElement && this.#held.has(cursor)) {\n return cursor;\n }\n cursor = composedParentElement(cursor);\n }\n return null;\n }\n\n after(enclosing: HTMLElement | null, activate: () => void): void {\n const queue = enclosing === null ? undefined : this.#held.get(enclosing);\n if (queue === undefined) {\n activate();\n } else {\n queue.push(activate);\n }\n }\n\n release(host: HTMLElement): void {\n const queue = this.#held.get(host);\n if (queue === undefined) {\n return;\n }\n this.#held.delete(host);\n for (const activate of queue) {\n activate();\n }\n }\n}\n","import { DestroyRef, DOCUMENT, ElementRef, inject, type Signal } from '@angular/core';\n\nimport {\n afterNextRenderCancellable,\n composedContains,\n composedParentElement,\n createVetoableEvent,\n createVetoableNativeEvent,\n findFirstFocusable,\n injectFocusTrap,\n injectPortal,\n isInitialFocusTarget,\n MODAL_EXEMPT_ATTRIBUTE,\n resolveActiveElement,\n type VetoableEvent,\n type VetoableNativeEvent,\n} from 'forty-cdk/core';\nimport { BodyScrollLock } from '../body-scroll-lock/body-scroll-lock';\nimport { injectDismissibleLayer } from '../dismissible-layer/dismissible-layer';\nimport { type InertSiblingsHandle, InertSiblingsStack } from '../inert-siblings/inert-siblings';\nimport { buildOutsideVetoOptions, outsideVetoChannels } from '../overlay-controller/outside-veto';\nimport { ModalActivationOrder } from './modal-activation-order';\n\n/**\n * Dismissal wiring for a modal surface.\n *\n * Each channel builds one `VetoableNativeEvent` and hands it to both the specific emitter and the\n * composite `interactOutside` one, so a `preventDefault()` from either suppresses the close. When\n * nothing vetoes and `dismissible()` is `true`, the shell calls `requestClose` with the reason\n * matching the channel.\n *\n * `exemptElements` is re-read on every event, so elements portaled after activation are honoured.\n */\nexport interface ModalShellDismissConfig {\n /** Whether dismissals via the layer fire the implicit `requestClose`. */\n readonly dismissible: Signal<boolean>;\n /** Called with the matching reason when the consumer doesn't veto. */\n readonly requestClose: (reason: 'escape' | 'pointerDownOutside' | 'focusOutside') => void;\n /** Forwards the Escape `VetoableNativeEvent` to the directive's `(escapeKeyDown)` output. */\n readonly emitEscapeKeyDown: (veto: VetoableNativeEvent<KeyboardEvent>) => void;\n /** Forwards the pointer-down-outside veto to the directive's `(pointerDownOutside)` output. */\n readonly emitPointerDownOutside: (veto: VetoableNativeEvent<PointerEvent>) => void;\n /** Forwards the focus-outside veto to the directive's `(focusOutside)` output. */\n readonly emitFocusOutside: (veto: VetoableNativeEvent<FocusEvent>) => void;\n /** Forwards the composite veto to the directive's `(interactOutside)` output. */\n readonly emitInteractOutside: (veto: VetoableNativeEvent<PointerEvent | FocusEvent>) => void;\n /**\n * Live \"elements that count as inside\" set — Drawer uses this to exempt\n * its portaled backdrop so a backdrop click routes through the backdrop's\n * own `requestClose('backdrop')` path instead of `pointerDownOutside`.\n *\n * The shell always merges every `MODAL_EXEMPT_ATTRIBUTE` overlay (e.g. toast\n * viewports) on top of whatever this returns, so a primitive only lists its\n * *own* extra exemptions here. It is handed the node being tested.\n */\n readonly exemptElements?: (target: Node) => readonly Element[];\n}\n\n/**\n * Primitive-owned initial-focus algorithm for the surface. The richer\n * alternative to the `'first' | 'container'` literal: the shell sets up the\n * focus trap (Tab cycling + return capture) WITHOUT its own imperative focus\n * move, runs the optional `veto`, and — unless vetoed — calls `move()`. When\n * `move()` returns `false` (no candidate found) focus falls back to the trap\n * container (modal) or the first focusable descendant (non-modal).\n *\n * Mirrors `OverlayShellInitialFocusConfig` so a content directive can hand the\n * same focus algorithm to either shell. Used by Select (selected → first →\n * last option) and available for a future date-picker calendar-cell move.\n */\nexport interface ModalShellInitialFocusConfig {\n /** Primitive focus algorithm. Returns `true` on success, `false` to fall back. */\n readonly move: () => boolean;\n /** `(autoFocusOnOpen)` veto. Returning `true` skips the imperative focus move. */\n readonly veto?: () => boolean;\n}\n\n/**\n * Single config for the free-floating modal-overlay lifecycle. Mirrors the\n * `injectOverlayShell` shape on the trigger-anchored side. Each sub-bundle\n * is individually optional so a primitive can opt out of the channels it\n * doesn't need (e.g. a dismiss-less confirm dialog, though none ship today).\n */\nexport interface ModalShellConfig {\n /** Whether the surface activates focus-trap + scroll-lock + inert siblings. */\n readonly modal: Signal<boolean>;\n /**\n * Whether focus returns to the previously-focused element on destroy. No effect in non-modal\n * mode, where the shell never moves focus on close.\n */\n readonly returnFocus: Signal<boolean>;\n /**\n * Overrides the return-focus target, read at close time instead of captured in the constructor.\n * A `null` value falls back to the construction-time capture.\n *\n * Supply it when the surface may be constructed while focus lives inside another surface that is\n * about to be destroyed — a close→open modal swap in one change-detection pass — where the\n * captured element would be disconnected by close time and focus would fall back to `<body>`.\n *\n * Read only in modal mode, and only under the same gate as the construction-time capture:\n * {@link returnFocus} is `true` and `autoFocusOnClose` did not veto.\n */\n readonly returnFocusTarget?: Signal<HTMLElement | null>;\n /**\n * Where to send focus on mount. Two shapes:\n * - `Signal<'first' | 'container'>` — `'first'` = first focusable descendant\n * (falls back to host); `'container'` = host element. Same vocabulary as\n * `FocusTrap.activate({ initialFocus })`. Used by Dialog / Drawer /\n * date-picker.\n * - {@link ModalShellInitialFocusConfig} — a primitive-owned `move()`\n * algorithm (e.g. Select's selected → first → last option) with its own\n * open-veto, falling back to the container / first focusable on a miss.\n */\n readonly initialFocus: Signal<'first' | 'container'> | ModalShellInitialFocusConfig;\n /**\n * Element the consumer marked as the initial focus target, read once at mount. Honoured with the\n * literal `initialFocus` form only: when it resolves to an element that passes\n * `isInitialFocusTarget`, focus lands there, and otherwise the literal applies.\n */\n readonly initialFocusTarget?: () => HTMLElement | null;\n /**\n * `(autoFocusOnOpen)` veto. Bound as a function reference (not as an\n * Angular `output()`) so the shell can invoke it during the destroy hook\n * without depending on `OutputEmitterRef` lifecycle. Read at every mount;\n * a `preventDefault()` on the emitted event skips the imperative initial\n * focus move while still leaving the focus-trap (Tab cycling, return\n * capture) wired in modal mode.\n */\n readonly autoFocusOnOpen?: () => ((event: VetoableEvent) => void) | undefined;\n /**\n * `(autoFocusOnClose)` veto. Same shape as `autoFocusOnOpen`. Fired\n * synchronously from the `DestroyRef.onDestroy` hook, BEFORE the modal /\n * non-modal teardown so it runs reliably on every close path — including a\n * direct `open.set(false)` from the consumer that bypasses any\n * close-output emission.\n */\n readonly autoFocusOnClose?: () => ((event: VetoableEvent) => void) | undefined;\n /**\n * Portal target for the surface. A signal so it is read once at the first\n * render (the portal moves the host once), after the consumer's input is\n * bound. `undefined` / a signal yielding `null` ⇒ `document.body`.\n */\n readonly container?: Signal<HTMLElement | null>;\n /** Optional dismiss bundle. Absent for primitives that don't dismiss via the layer. */\n readonly dismiss?: ModalShellDismissConfig;\n}\n\n/** Imperative handle returned by `injectModalShell`. */\nexport interface ModalShellHandle {\n /** True while the shell activated focus-trap + scroll-lock + inert (modal mode). */\n readonly isModal: () => boolean;\n /**\n * Whether the surface's dismissible layer is active and no layer owning the pointer channel is\n * stacked above it, so an outside press is the surface's to handle.\n */\n readonly isTopmostPointerLayer: () => boolean;\n}\n\n/**\n * Resolves the live set of independent overlay surfaces that opt out of every\n * modal's dismissible layer via {@link MODAL_EXEMPT_ATTRIBUTE} — today\n * `ForToastViewport`. Queried fresh on each interaction (no snapshot) so a\n * surface mounted *after* the modal opened still counts as \"inside\", which is\n * exactly the toast-over-open-dialog case. An interaction inside any returned\n * element therefore never dismisses the modal.\n */\nexport function resolveModalExemptOverlays(doc: Document): readonly Element[] {\n return Array.from(doc.querySelectorAll(`[${MODAL_EXEMPT_ATTRIBUTE}]`));\n}\n\n/**\n * Owns the lifecycle of a free-floating modal surface — the overlay primitives that mount as their\n * own root, `[forDialog]` and `[forDrawer]` today.\n *\n * The shell captures the return-focus target, portals the host to `document.body` (or to\n * `config.container`), and activates the dismissible layer. In modal mode it additionally inerts\n * the siblings, activates the focus trap and locks scroll, all scoped to `config.container` when\n * one is supplied; in non-modal mode it only performs the initial focus move.\n *\n * Teardown reverses that order on destroy, deactivating inert siblings before focus returns so the\n * target is not blocked by an inert ancestor.\n *\n * Must be called from an injection context. The host's `ElementRef` is forwarded to every\n * collaborator, so the caller never wires them up directly.\n */\nexport function injectModalShell(config: ModalShellConfig): ModalShellHandle {\n const host = inject<ElementRef<HTMLElement>>(ElementRef);\n const document = inject(DOCUMENT);\n const focusTrap = injectFocusTrap();\n const dismissible = injectDismissibleLayer();\n const inertStack = inject(InertSiblingsStack);\n const scrollLock = inject(BodyScrollLock);\n\n // 1. Capture the return-focus target SYNCHRONOUSLY, before any side effect\n // runs. WebKit (#136) blurs the previously-focused element as soon as\n // `inert` is applied to an ancestor, so by the time `afterNextRender`\n // fires the focus trap could no longer read the trigger from\n // `document.activeElement`. Reading it now locks the trigger in.\n //\n // Resolved through open shadow roots (#1586): a raw `document.activeElement`\n // reports the shadow *host* when the trigger lives inside one — a consumer\n // component using `ViewEncapsulation.ShadowDom`, or a design-system web\n // component — and that host is typically not focusable, so return-focus\n // would silently drop to `<body>` on close. Because this target is always\n // passed to `trap.activate()`, the trap's own shadow-aware capture never\n // runs for a modal surface; this is the one that has to resolve.\n const active = resolveActiveElement(document);\n let returnFocusTarget: HTMLElement | null = active instanceof HTMLElement ? active : null;\n\n const order = inject(ModalActivationOrder);\n order.hold(host.nativeElement);\n let origin: Element | null = null;\n let enclosing: HTMLElement | null = null;\n afterNextRenderCancellable(() => {\n origin = composedParentElement(host.nativeElement);\n enclosing = order.enclosingHeld(origin);\n });\n\n // 2. Portal — moves the host to `document.body` after first render and\n // cleans up on destroy. `DestroyRef.onDestroy` callbacks fire in\n // registration order (FIFO), and the portal registers its hook here,\n // before the shell's own destroy hook below — so on teardown the portal\n // removes the host from the DOM FIRST, then the shell runs return-focus.\n // The ordering is harmless either way: return-focus targets the\n // previously-focused element (the trigger, captured synchronously above),\n // which lives OUTSIDE the portaled host, so removing the host first never\n // affects it.\n injectPortal(config.container ? { target: config.container } : {});\n\n // Captured at mount time so the destroy path can mirror the same mode the\n // shell activated, regardless of any `modal()` toggle on a doomed\n // instance.\n let activatedAsModal = false;\n let inertHandle: InertSiblingsHandle | null = null;\n let activatedContainer: HTMLElement | null = null;\n\n const resolveMarkedTarget = (): HTMLElement | null => {\n const target = config.initialFocusTarget?.() ?? null;\n return target !== null && isInitialFocusTarget(target, host.nativeElement) ? target : null;\n };\n\n // 3. Side-effect setup runs after Angular has applied input bindings.\n // Reading `config.modal()` etc. in the constructor would always see the\n // default value because the input writes haven't flowed through yet.\n // `afterNextRenderCancellable` makes the destroy-before-render path safe.\n // On the true-async path (queued render after destroy) the callback is\n // cancelled, so inert siblings / focus trap / scroll lock / dismissible\n // layer are never activated (`activatedAsModal` stays false). On the\n // synchronous-teardown path the callback flushes just before the destroy\n // hook, so it sets `activatedAsModal = true` and the destroy hook below\n // tears the side-effect stack back down. Either way nothing leaks.\n let destroyed = false;\n let releasePeer: (() => void) | null = null;\n const activate = (deferred: boolean): void => {\n if (deferred) {\n const current = resolveActiveElement(document);\n if (\n current instanceof HTMLElement &&\n enclosing !== null &&\n composedContains(enclosing, current)\n ) {\n returnFocusTarget = current;\n }\n }\n const isModal = config.modal();\n activatedAsModal = isModal;\n\n // 3a. Dismissible layer. Pushed onto the stack BEFORE moving focus so\n // focusin events triggered by our own focus management land on this\n // layer, not on whatever lower layer was previously topmost.\n //\n // Outside channels are self-closing: `buildOutsideVetoOptions` builds\n // one veto per physical interaction and hands it to both the specific\n // (pointer-down-outside / focus-outside) and the composite\n // `interactOutside` emitter, so a `preventDefault()` in either handler\n // vetoes the close.\n const dismissCfg = config.dismiss;\n if (dismissCfg !== undefined) {\n dismissible.activate({\n channels: outsideVetoChannels(dismissCfg),\n modal: isModal,\n exemptElements: (target) => [\n ...(dismissCfg.exemptElements?.(target) ?? []),\n ...resolveModalExemptOverlays(document),\n ],\n onEscapeKeyDown: (event) => {\n const veto = createVetoableNativeEvent(event);\n dismissCfg.emitEscapeKeyDown(veto);\n if (!veto.defaultPrevented && dismissCfg.dismissible()) {\n event.stopPropagation();\n dismissCfg.requestClose('escape');\n }\n },\n ...buildOutsideVetoOptions(dismissCfg),\n });\n }\n\n // 3b. Resolve the initial-focus config. The simple form is a\n // `Signal<'first' | 'container'>` (Dialog / Drawer / date-picker); the\n // richer form carries a primitive-owned `move()` algorithm (Select's\n // selected → first → last option) plus its own veto. A `Signal` is\n // callable, so `typeof === 'function'` distinguishes the two shapes;\n // the literal mode is read eagerly only in the simple form.\n const initialFocusCfg = config.initialFocus;\n const moveCfg: ModalShellInitialFocusConfig | null =\n typeof initialFocusCfg === 'function' ? null : initialFocusCfg;\n const literalFocus: 'first' | 'container' | null =\n typeof initialFocusCfg === 'function' ? initialFocusCfg() : null;\n const markedTarget = literalFocus === null ? null : resolveMarkedTarget();\n\n // 3c. `(autoFocusOnOpen)` veto — read once for this mount. The move-config\n // carries its own boolean veto (mirroring `injectOverlayShell`); the\n // simple form routes through the top-level `autoFocusOnOpen` callback.\n let skipInitialFocus: boolean;\n if (moveCfg) {\n skipInitialFocus = moveCfg.veto?.() ?? false;\n } else {\n const autoFocusOpenEvent = createVetoableEvent();\n config.autoFocusOnOpen?.()?.(autoFocusOpenEvent);\n skipInitialFocus = autoFocusOpenEvent.defaultPrevented;\n }\n\n if (isModal) {\n // 3d. Modal mode. Inert + aria-hide siblings BEFORE the focus trap\n // activates so the trap's `focus()` call lands on an\n // already-isolated tree. The return-focus target was captured\n // synchronously above (#136).\n const containerEl = config.container?.() ?? null;\n inertHandle = inertStack.activate(host.nativeElement, containerEl ?? undefined);\n activatedContainer = containerEl;\n if (moveCfg) {\n // The primitive owns the focus move. Set up Tab cycling + return\n // capture WITHOUT the trap's own imperative focus, then run the\n // algorithm; fall back to the container when it finds no candidate.\n focusTrap.activate({\n preventInitialFocus: true,\n returnFocus: returnFocusTarget,\n });\n if (!skipInitialFocus && !moveCfg.move()) {\n focusTrap.container.focus();\n }\n } else {\n focusTrap.activate({\n initialFocus: markedTarget ?? literalFocus ?? 'first',\n preventInitialFocus: skipInitialFocus,\n returnFocus: returnFocusTarget,\n });\n }\n scrollLock.lock(containerEl ?? undefined);\n } else {\n // 3e. Non-modal mode. No trap, no scroll lock, no inert. Still respect\n // the configured initial focus: the primitive's `move()` algorithm\n // (falling back to the first focusable on a miss), the first\n // focusable descendant ('first'), or the host ('container').\n releasePeer = inertStack.registerPeer(\n host.nativeElement,\n [origin, returnFocusTarget].filter((anchor): anchor is Element => anchor !== null),\n );\n if (!skipInitialFocus) {\n const el = focusTrap.container;\n if (moveCfg) {\n if (!moveCfg.move()) {\n (findFirstFocusable(el) ?? el).focus();\n }\n } else if (markedTarget) {\n markedTarget.focus();\n } else if (literalFocus === 'container') {\n el.focus();\n } else {\n (findFirstFocusable(el) ?? el).focus();\n }\n }\n }\n };\n afterNextRenderCancellable(() => {\n let synchronous = true;\n order.after(enclosing, () => {\n if (!destroyed) {\n activate(!synchronous);\n }\n order.release(host.nativeElement);\n });\n synchronous = false;\n });\n\n // 4. Destroy. Hooks fire in registration order; the portal's destroy hook\n // was registered inside `injectPortal()` (above) so it runs BEFORE\n // ours, removing the element from the DOM first. We tear down the\n // side-effect stack here in the inverse order it was activated.\n inject(DestroyRef).onDestroy(() => {\n destroyed = true;\n order.release(host.nativeElement);\n releasePeer?.();\n releasePeer = null;\n dismissible.deactivate();\n // Invoke `(autoFocusOnClose)` synchronously, BEFORE either the modal or\n // non-modal teardown runs. Fires on every close path regardless of mode\n // (the consumer's `(dismiss)` flow AND a direct `open.set(false)` that\n // bypasses any close-output emission). The callback is a plain function\n // reference — input signals stay readable during destroy and there is no\n // dependency on `OutputEmitterRef` lifecycle. Non-modal mode never moves\n // focus on close, so `skipReturnFocus` is only consulted in the modal\n // branch — but the hook still fires for symmetry with the manager and so\n // consumers can wire their own focus moves on close in non-modal mode.\n const autoFocusCloseEvent = createVetoableEvent();\n config.autoFocusOnClose?.()?.(autoFocusCloseEvent);\n const skipReturnFocus = autoFocusCloseEvent.defaultPrevented;\n if (activatedAsModal) {\n // Lift inert + aria-hide BEFORE moving focus back: an `inert` ancestor\n // blocks `.focus()` on its descendants, so the return-focus target\n // needs to be live again first.\n inertHandle?.deactivate();\n inertHandle = null;\n const shouldReturnFocus = config.returnFocus() && !skipReturnFocus;\n const overrideTarget = config.returnFocusTarget?.() ?? null;\n // Suppress the dismissible-layer dispatcher across focus-return so the\n // synthetic `focusin` triggered by `.focus()`-ing the previous element\n // does not cascade-dismiss whatever modal is now topmost (a stacked\n // dialog opened above this one).\n dismissible.suppress(() => {\n if (shouldReturnFocus && overrideTarget?.isConnected) {\n focusTrap.deactivate({ returnFocus: false });\n overrideTarget.focus();\n } else {\n focusTrap.deactivate({ returnFocus: shouldReturnFocus });\n }\n });\n scrollLock.unlock(activatedContainer ?? undefined);\n }\n });\n\n return {\n isModal: () => activatedAsModal,\n isTopmostPointerLayer: () => dismissible.isTopmostFor('pointer'),\n };\n}\n","import { DestroyRef, ElementRef, inject, Injectable, type Signal } from '@angular/core';\n\n/** The trigger state a modal-shell surface reads to recognise its own trigger. */\nexport interface ModalTriggerConfig {\n /** The trigger's open state. */\n readonly open: Signal<boolean>;\n /** The id of the surface the trigger controls, or `null` when unset. */\n readonly controls: Signal<string | null>;\n}\n\ninterface ModalTriggerEntry extends ModalTriggerConfig {\n readonly element: HTMLElement;\n}\n\n/**\n * The mounted triggers that toggle a modal-shell surface. A surface counts its own controlling\n * triggers as inside itself for outside-press and outside-focus dismissal, so the press that\n * precedes a trigger's toggling click never closes the surface the click is about to close.\n */\n@Injectable({ providedIn: 'root' })\nexport class ModalTriggerRegistry {\n readonly #entries = new Set<ModalTriggerEntry>();\n\n /** Adds a trigger and returns the function that removes it. */\n register(entry: ModalTriggerEntry): () => void {\n this.#entries.add(entry);\n return () => this.#entries.delete(entry);\n }\n\n /**\n * The open triggers controlling `surface`: those whose `controls` names the surface's id, and\n * those with no `controls`, which name no surface and so count as controlling any open one.\n */\n controlling(surface: HTMLElement): HTMLElement[] {\n const out: HTMLElement[] = [];\n for (const entry of this.#entries) {\n if (!entry.open()) {\n continue;\n }\n const controls = entry.controls();\n if (controls === null || (controls !== '' && controls === surface.id)) {\n out.push(entry.element);\n }\n }\n return out;\n }\n}\n\n/**\n * Registers the host as a trigger toggling a modal-shell surface, for as long as the host lives.\n * Must be called from an injection context.\n */\nexport function injectModalTrigger(config: ModalTriggerConfig): void {\n const element = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n const release = inject(ModalTriggerRegistry).register({ ...config, element });\n inject(DestroyRef).onDestroy(release);\n}\n","import {\n booleanAttribute,\n computed,\n Directive,\n ElementRef,\n inject,\n input,\n output,\n signal,\n type Signal,\n} from '@angular/core';\n\nimport {\n hostAriaLabel,\n hostDescribedBy,\n hostLabelledBy,\n type SingleSlot,\n type VetoableEvent,\n type VetoableNativeEvent,\n} from 'forty-cdk/core';\nimport { type ModalShellConfig, type ModalShellHandle } from './modal-shell';\nimport { ModalTriggerRegistry } from './modal-trigger';\n\n/**\n * Abstract base for free-floating modal-surface primitives — a directive that\n * mounts a modal surface as its own root, coordinates label / description\n * registration, and drives its lifecycle through {@link injectModalShell}.\n * `ForDialog` and `ForDrawer` extend it; a future modal Toast / full-screen\n * sheet / command palette can too.\n *\n * The base owns everything the two surfaces used to duplicate verbatim: the\n * `aria-labelledby` / `aria-describedby` registry, the backdrop registration,\n * the exemption of the backdrop and of the controlling triggers\n * (`injectModalTrigger`) from outside dismissal,\n * the `requestClose` dismissible gating, the `lastCloseValue` bridge read by\n * the programmatic managers, the seven shared ARIA / state host bindings (`role`, `aria-modal`, `aria-label`,\n * `aria-labelledby`, `aria-describedby`, `data-state=\"open\"`, `tabindex=\"-1\"`),\n * the non-defaults inputs and dismiss outputs, and the {@link modalShellConfig}\n * factory. Anything primitive-specific (Drawer's drag / snap / scale / stack,\n * the four defaults-backed inputs each subclass seeds from its own\n * `FOR_<PRIMITIVE>_DEFAULTS`) stays on the subclass.\n *\n * The base does **not** call {@link injectModalShell} itself —\n * each subclass calls `injectModalShell(this.modalShellConfig())` from its own\n * constructor. A base-owned call would register its `afterNextRender` during\n * `super()`, before a subclass (Drawer) could register its own pre-shell\n * `afterNextRender` (stack push + snap validation), breaking the documented\n * ordering.\n *\n * Implemented as an `@Directive()`-decorated abstract class because Angular\n * recognises signal inputs / outputs and host bindings only when the\n * `input()` / `output()` calls and the `host` block appear on a decorated\n * class; inheritance is the supported mechanism for sharing them across\n * directives.\n *\n * Internal core tier — exported from `forty-cdk/core` for the library's own\n * entry points, with no semver guarantee. Subclassing a library base is not a\n * supported contract, so it is absent from `CORE_PUBLISHERS` and\n * from every primitive's own barrel; the public-types gate ignores\n * `extends`-only heritage, which is why the base may appear in the shipped\n * `.d.ts` as the parent of `[forDialog]` / `[forDrawer]` without being blessed.\n */\n@Directive({\n host: {\n '[attr.role]': 'alert() ? \"alertdialog\" : \"dialog\"',\n '[attr.aria-modal]': 'modal() ? \"true\" : null',\n '[attr.aria-label]': 'resolvedAriaLabel()',\n 'data-state': 'open',\n tabindex: '-1',\n },\n})\nexport abstract class ModalSurfaceBase<Reason extends string> {\n /** When true, role becomes `alertdialog` (interrupts assistive tech). */\n readonly alert = input(false, { transform: booleanAttribute });\n\n /**\n * Explicit element focus returns to on close, read at close time. Overrides\n * the element the shell captures at construction — supply it when this\n * surface can be constructed while focus lives inside a *different, doomed*\n * surface, the canonical case being a close→open swap in one change-detection\n * pass. The programmatic managers thread the true origin through this input\n * automatically; declarative consumers driving such a swap by hand can bind\n * it too. `null` (default) keeps the construction-time capture, so ordinary\n * usage is unaffected. Has no effect in non-modal mode (the shell never moves\n * focus on close then).\n */\n readonly returnFocusTarget = input<HTMLElement | null>(null);\n\n /** Manual `aria-label`. Use this when no visible title element exists. */\n readonly ariaLabel = input<string | null>(null);\n\n /**\n * Resolved `aria-label`: a consumer-set static value on the surface when\n * present, else the {@link ariaLabel} input.\n */\n private readonly resolvedAriaLabel = hostAriaLabel(() => this.ariaLabel() || null);\n\n /**\n * Portal target for the surface. Defaults to `document.body`. Pair with\n * `[modal]=\"false\"` for a surface scoped to a positioned region instead of\n * the viewport. Read once at mount. The backdrop portals to the same\n * container.\n */\n readonly container = input<HTMLElement | null>(null);\n\n /**\n * Callback invoked just before the surface moves focus into itself on mount.\n * Receives a `VetoableEvent`; call `event.preventDefault()` to skip the\n * imperative focus move — useful when opening from an input you want to keep\n * focused. The focus trap (modal mode) still cycles Tab inside the surface\n * once focus enters it.\n *\n * Bound as a function reference (`[autoFocusOnOpen]=\"onOpen\"`), not as an\n * event binding. The callback shape (rather than an `output()`) lets the\n * shell invoke it during the destroy hook without depending on Angular's\n * `OutputEmitterRef` lifecycle.\n */\n readonly autoFocusOnOpen = input<((event: VetoableEvent) => void) | undefined>(undefined);\n\n /**\n * Callback invoked just before focus returns to the previously focused\n * element on unmount. Receives a `VetoableEvent`; call\n * `event.preventDefault()` to skip the return-focus — useful when the\n * consumer wants to send focus elsewhere imperatively. Fires reliably on\n * both close paths: the `(dismiss)` output flow AND a direct\n * `open.set(false)` from the consumer.\n */\n readonly autoFocusOnClose = input<((event: VetoableEvent) => void) | undefined>(undefined);\n\n /**\n * Whether dismiss interactions (Escape, backdrop, outside interaction, and\n * any primitive-specific gesture) close the surface. Implemented by the\n * subclass so its default can be seeded from the primitive's scope defaults.\n */\n abstract readonly dismissible: Signal<boolean>;\n\n /**\n * Whether the surface activates modal semantics (`aria-modal`, focus trap,\n * body scroll lock, inert siblings). Implemented by the subclass so its\n * default can be seeded from the primitive's scope defaults.\n */\n abstract readonly modal: Signal<boolean>;\n\n /**\n * Whether focus returns to the previously focused element on close.\n * Implemented by the subclass so its default can be seeded from the\n * primitive's scope defaults.\n */\n abstract readonly returnFocus: Signal<boolean>;\n\n /**\n * Where to send focus on mount — `'first'` (first focusable descendant) or\n * `'container'` (the surface host). Implemented by the subclass so its\n * default can be seeded from the primitive's scope defaults.\n */\n abstract readonly initialFocus: Signal<'first' | 'container'>;\n\n /**\n * Entry-point name the shared surface errors report under, e.g. `'dialog'`.\n * The subclass supplies it because the shell's checks are shared while the\n * `[forty-cdk/<scope>]` prefix a consumer reads must name the primitive they\n * actually wrote.\n */\n protected abstract readonly entryPoint: string;\n\n /**\n * The element the primitive's initial-focus marker registered inside the surface, or `null`.\n * Implemented by the subclass, which owns the marker's registration slot. The shell focuses it on\n * mount when it is a usable target, and falls back to {@link initialFocus} otherwise.\n */\n protected abstract readonly initialFocusTarget: Signal<HTMLElement | null>;\n\n /**\n * The slot the primitive's backdrop piece registers into. Implemented by the subclass, so the\n * dev-mode duplicate warning names the primitive's own surface and backdrop selectors.\n */\n protected abstract readonly backdropSlot: SingleSlot<HTMLElement>;\n\n /**\n * Emitted when the surface wants to close. Consumers wire this to flip the\n * signal that gates the surrounding `@if`. The reason union is\n * primitive-specific.\n */\n readonly dismiss = output<Reason>();\n\n /**\n * Fires when the user presses Escape while this surface is the topmost\n * dismissible layer. Call `preventDefault()` on the emitted veto to suppress\n * the subsequent `(dismiss)` emission. The original `KeyboardEvent` is on\n * `.event`.\n */\n readonly escapeKeyDown = output<VetoableNativeEvent<KeyboardEvent>>();\n\n /**\n * Fires when a pointer goes down outside the surface. Call `preventDefault()`\n * on the emitted veto to suppress the auto `(dismiss)`. The native\n * `PointerEvent` is on `.event`.\n */\n readonly pointerDownOutside = output<VetoableNativeEvent<PointerEvent>>();\n\n /**\n * Fires when focus moves outside the surface. `preventDefault()` on the veto\n * suppresses the auto `(dismiss)`. The native `FocusEvent` is on `.event`.\n */\n readonly focusOutside = output<VetoableNativeEvent<FocusEvent>>();\n\n /**\n * Composite event: fires alongside `pointerDownOutside` and `focusOutside`\n * and shares their veto state — `preventDefault()` on either one suppresses\n * the auto `(dismiss)`.\n */\n readonly interactOutside = output<VetoableNativeEvent<PointerEvent | FocusEvent>>();\n\n readonly #labelIds = signal<readonly string[]>([]);\n readonly #describedByIds = signal<readonly string[]>([]);\n readonly #lastCloseValue = signal<unknown>(undefined);\n readonly #host = inject<ElementRef<HTMLElement>>(ElementRef);\n readonly #triggers = inject(ModalTriggerRegistry);\n #shell: ModalShellHandle | null = null;\n\n /**\n * Resolved `aria-labelledby`: a consumer-set static value when present, else\n * the space-joined ids of the registered titles, or `null` when none.\n */\n readonly labelledBy = hostLabelledBy(() => {\n const ids = this.#labelIds();\n return ids.length === 0 ? null : ids.join(' ');\n });\n\n /**\n * Resolved `aria-describedby`: a consumer-set static value composed with the\n * space-joined ids of the registered descriptions, or `null` when neither is\n * present.\n */\n readonly describedBy = hostDescribedBy(() => {\n const ids = this.#describedByIds();\n return ids.length === 0 ? null : ids.join(' ');\n });\n\n /** Register a title element's id into `aria-labelledby`. */\n registerLabel(id: string): void {\n this.#labelIds.update((arr) => (arr.includes(id) ? arr : [...arr, id]));\n }\n\n /** Remove a title element's id from `aria-labelledby`. */\n unregisterLabel(id: string): void {\n this.#labelIds.update((arr) => arr.filter((x) => x !== id));\n }\n\n /** Register a description element's id into `aria-describedby`. */\n registerDescription(id: string): void {\n this.#describedByIds.update((arr) => (arr.includes(id) ? arr : [...arr, id]));\n }\n\n /** Remove a description element's id from `aria-describedby`. */\n unregisterDescription(id: string): void {\n this.#describedByIds.update((arr) => arr.filter((x) => x !== id));\n }\n\n private surfaceElement(): HTMLElement {\n return this.#host.nativeElement;\n }\n\n private registerBackdrop(el: HTMLElement): void {\n this.backdropSlot.register(el);\n }\n\n private unregisterBackdrop(el: HTMLElement): void {\n this.backdropSlot.unregister(el);\n }\n\n /**\n * Request that the surface close. `'closeButton'` and `'programmatic'` always\n * emit `(dismiss)`; every other reason is gated on `dismissible()`. `value`\n * is the close result, captured for the programmatic managers' close bridge.\n */\n requestClose(reason: Reason, value?: unknown): void {\n if (reason !== 'closeButton' && reason !== 'programmatic' && !this.dismissible()) {\n return;\n }\n this.#lastCloseValue.set(value);\n this.dismiss.emit(reason);\n }\n\n /**\n * The `value` argument from the most recent `requestClose(reason, value)`\n * call. Read by the programmatic managers to bridge `[for…Close] [closeWith]`\n * into `For…Ref.close(value)`. Part of the internal composition surface with\n * no semver guarantee; declarative consumers never need this.\n */\n readonly lastCloseValue = this.#lastCloseValue.asReadonly();\n\n /**\n * The registered backdrop element, or `null` when none is rendered. Read by\n * the programmatic managers' surface registrar so `beginLeave` drives the\n * backdrop's exit animation by direct reference instead of a document query.\n * Part of the internal composition surface with no semver guarantee;\n * declarative consumers never need this.\n */\n readonly backdropElement = computed(() => this.backdropSlot.value());\n\n /**\n * Keeps the handle the subclass's `injectModalShell(this.modalShellConfig())` call returned, which\n * the backdrop piece reads through {@link isTopmostPointerLayer}. Called once from the subclass\n * constructor.\n */\n protected attachModalShell(shell: ModalShellHandle): void {\n this.#shell = shell;\n }\n\n /**\n * Whether this surface is the topmost layer owning the pointer channel. Read by the backdrop\n * piece through the internal context to decide whether a press on it is this surface's.\n */\n private isTopmostPointerLayer(): boolean {\n return this.#shell?.isTopmostPointerLayer() ?? true;\n }\n\n protected modalShellConfig(): ModalShellConfig {\n return {\n modal: this.modal,\n returnFocus: this.returnFocus,\n returnFocusTarget: this.returnFocusTarget,\n initialFocus: this.initialFocus,\n initialFocusTarget: () => this.initialFocusTarget(),\n container: this.container,\n autoFocusOnOpen: () => this.autoFocusOnOpen(),\n autoFocusOnClose: () => this.autoFocusOnClose(),\n dismiss: {\n dismissible: this.dismissible,\n requestClose: (reason) => this.requestClose(reason as Reason),\n emitEscapeKeyDown: (veto) => this.escapeKeyDown.emit(veto),\n emitPointerDownOutside: (veto) => this.pointerDownOutside.emit(veto),\n emitFocusOutside: (veto) => this.focusOutside.emit(veto),\n emitInteractOutside: (veto) => this.interactOutside.emit(veto),\n exemptElements: () => {\n const backdrop = this.backdropSlot.value();\n const triggers = this.#triggers.controlling(this.#host.nativeElement);\n return backdrop ? [backdrop, ...triggers] : triggers;\n },\n },\n };\n }\n}\n","import { afterNextRender, isDevMode } from '@angular/core';\nimport { fortyWarn } from 'forty-cdk/core';\n\n/**\n * Identifies the piece in the dev-mode mounted-while-closed warning and tells\n * the helper how to read its surface's open state.\n */\nexport interface MountedWhileClosedConfig {\n /** Entry-point name used in the `[forty-cdk/<primitive>]` prefix (e.g. `'select'`). */\n readonly primitive: string;\n /**\n * Selector of the mounted piece (e.g. `'[forSelectContent]'`). A directive\n * with more than one selector resolves the one the consumer actually wrote,\n * so the report names a piece they can find in their template —\n * `[forMenuContent]` serves `[forMenuSubContent]` too.\n */\n readonly piece: string;\n /**\n * The `@if` condition the primitive's README uses, quoted back as the fix\n * (e.g. `'select.open()'`). Keep the two in sync — a consumer following the\n * link should read the same expression there.\n *\n * A thunk is resolved inside the render hook, which is what lets a condition\n * interpolate a bound input: `[forNavigationMenuContent]` quotes its owning\n * item's value, unreadable at construction (see below).\n */\n readonly condition: string | (() => string);\n /** The surface's open state, read once after the first render. */\n readonly open: () => boolean;\n}\n\n/**\n * Warns — dev mode only, once per instance — when an overlay surface is still mounted after its\n * first render while its own open state reports closed, which is the consumer forgetting the `@if`.\n *\n * It is the library's quietest first-use mistake: the surface renders permanently,\n * `data-state=\"closed\"` lands on a visible element, the ARIA stays internally consistent and the\n * primitive keeps working, so it reads as a CSS bug rather than a wiring one.\n *\n * Mount equals open is structural for these surfaces, so the `@if` is the whole contract and no\n * input suppresses the warning. Only pieces whose closed state has no supported mounted shape adopt\n * it, so the always-mounted panel families do not.\n *\n * **The check is mount-time**, reading the open state inside `afterNextRender` and never again,\n * which buys three things:\n *\n * - The exit-animation window stays silent. A closed surface is legitimately mounted for as long as\n * `animate.leave` keeps it, so re-checking on close would report every correct overlay.\n * - Bindings have settled. A piece deriving its open state from an `input.required` its parent has\n * not written yet would throw NG0950 on a construction-time read. `condition` takes a thunk for\n * the same reason, so the quoted fix is built where the input is readable.\n * - It is inert on the server, where `afterNextRender` never fires.\n *\n * The cost is a deliberate false negative: a surface that mounts open and is then left mounted\n * forever goes unreported, since catching it would mean re-checking on close.\n *\n * Must be called from an injection context. A production build registers no render hook at all.\n */\nexport function warnIfMountedWhileClosed(config: MountedWhileClosedConfig): void {\n if (!isDevMode()) {\n return;\n }\n\n afterNextRender(() => {\n if (config.open()) {\n return;\n }\n const condition =\n typeof config.condition === 'function' ? config.condition() : config.condition;\n fortyWarn({\n code: 'FORCDK-CORE-006',\n scope: config.primitive,\n message: `${config.piece} is mounted while the surface is closed.`,\n cause:\n \"Presence in the DOM is the consumer's job, and there is no forceMount input — a surface \" +\n 'kept mounted while closed never runs `animate.enter` / `animate.leave`, and the lifecycle ' +\n 'it sets up on mount stays live while closed.',\n fix: `Wrap it with \\`@if (${condition})\\` so it unmounts on close. See the ${config.primitive} README.`,\n });\n });\n}\n","import { inject } from '@angular/core';\nimport { CssVarNamespacer } from '@angular/platform-browser';\n\nexport interface FloatingCustomProperties {\n readonly anchorWidth: string;\n readonly anchorHeight: string;\n readonly availableWidth: string;\n readonly availableHeight: string;\n readonly contentTransformOrigin: string;\n readonly arrowOffset: string;\n}\n\nexport function injectFloatingCustomProperties(): FloatingCustomProperties {\n const namespacer = inject(CssVarNamespacer);\n return {\n anchorWidth: namespacer.namespace('--for-floating-anchor-width'),\n anchorHeight: namespacer.namespace('--for-floating-anchor-height'),\n availableWidth: namespacer.namespace('--for-floating-available-width'),\n availableHeight: namespacer.namespace('--for-floating-available-height'),\n contentTransformOrigin: namespacer.namespace('--for-floating-content-transform-origin'),\n arrowOffset: namespacer.namespace('--for-floating-arrow-offset'),\n };\n}\n","import { isPlatformBrowser } from '@angular/common';\nimport {\n afterNextRender,\n effect,\n ElementRef,\n inject,\n PLATFORM_ID,\n type Signal,\n} from '@angular/core';\nimport {\n autoUpdate,\n computePosition,\n type ComputePositionReturn,\n type Middleware,\n type Placement,\n type ReferenceElement,\n} from '@floating-ui/dom';\n\nimport { injectPortal } from 'forty-cdk/core';\n\n/**\n * The positioner-specific work for a single open run, returned by\n * {@link PositioningConfig.computeAndApply}. The shared scaffold owns the\n * platform gate, portal, anti-flash baseline, `autoUpdate` loop, the\n * `!open()` / cancelled-run bail, the `translate` write, the `clip-path` drop,\n * the per-open {@link PositioningConfig.onFirstPosition} dispatch, and the\n * `.catch(() => {})`; a run supplies only the parts that genuinely differ\n * between positioners.\n */\nexport interface PositioningRun {\n /**\n * The requested placement handed to `@floating-ui/dom`'s `computePosition`.\n * (The strategy is always `'fixed'`, owned by the scaffold.)\n */\n readonly placement: Placement;\n\n /** The middleware stack handed to `computePosition` for this run. */\n readonly middleware: Middleware[];\n\n /**\n * Applies a resolved position. Runs on every `autoUpdate` frame, after the\n * scaffold has bailed on a mid-frame close, written the resolved `translate`,\n * and dropped the `clip-path` anti-flash baseline. Writes the positioner's\n * own `data-*` attributes and CSS variables (and, for the anchored\n * positioner, the arrow).\n */\n apply(result: ComputePositionReturn): void;\n\n /**\n * Resets everything the run wrote, invoked from the effect's `onCleanup`\n * when `open` flips back to `false`, the config changes while open, or the\n * host is destroyed. What is reset (and what is intentionally retained for\n * `animate.leave`) is the positioner's decision.\n */\n reset(): void;\n}\n\n/**\n * Configuration for {@link runPositioning}. Mirrors the shared shape of the\n * two positioners (`injectFloating`, `injectItemAlignedPositioner`) — the\n * reactive `reference` / `open`, the optional `portal` and anti-flash toggle —\n * and defers the positioner-specific compute + apply + reset to\n * {@link computeAndApply}.\n */\nexport interface PositioningConfig {\n /**\n * The anchor. Reactive — should emit `null` until the anchor is available;\n * positioning is skipped while `null` or `open` is `false`.\n */\n readonly reference: Signal<ReferenceElement | null>;\n\n /**\n * Whether the floating element is currently visible. `autoUpdate` is started\n * when this becomes `true` and torn down when it goes back to `false`.\n */\n readonly open: Signal<boolean>;\n\n /**\n * When `true` (default), the floating element is moved to `document.body` on\n * first render and removed on destroy. Set to `false` to keep it in its\n * declared parent (or when the caller already invokes `injectPortal()`).\n */\n readonly portal?: boolean;\n\n /**\n * When the signal returns anything other than `false` (the default when the\n * signal is omitted), the surface is clipped with `clip-path: inset(50%)`\n * until the first position resolves, so a CSS enter animation never flashes\n * at the viewport corner before the async `computePosition` lands.\n */\n readonly clipUntilPositioned?: Signal<boolean>;\n\n /**\n * Invoked once per **open cycle**, immediately after the first\n * `computePosition` of that cycle resolves and its `run.apply` has run —\n * i.e. after the portal move, after the `clip-path` anti-flash baseline is\n * dropped, and after the positioner has written its `data-*` / CSS vars.\n *\n * The semantics are **per-open, not per-run**: a positioner\n * config change while the surface stays open re-runs the effect (a new\n * positioning run), but this hook does **not** fire again — it fires only on\n * the run that first resolves after `open` transitions to `true`. A run that\n * is superseded (config change while open) or torn down (close / destroy)\n * before its `computePosition` resolves is cancelled: its resolution writes\n * nothing and never fires this hook. This matters because consumers use it to\n * seed one-shot state that a re-fire would corrupt — e.g. scrolling an active\n * option into view inside a freshly portaled listbox, which a per-run re-fire\n * would yank back mid-interaction on every side flip.\n */\n readonly onFirstPosition?: () => void;\n\n /**\n * Builds the per-run controller. Called once per open run, synchronously\n * inside the positioning effect, so its reactive reads (side, align,\n * offsets, selected option, …) register as effect dependencies and a change\n * while open re-runs the effect. Receives the floating element and the\n * resolved (non-null) reference.\n */\n readonly computeAndApply: (el: HTMLElement, reference: ReferenceElement) => PositioningRun;\n}\n\n/**\n * Shared scaffold behind the library's two `@floating-ui/dom` positioners —\n * `injectFloating` (the general anchored positioner) and\n * `injectItemAlignedPositioner` (the macOS-style over-trigger positioner for\n * `[forSelectContent]`). Must be called from an injection context, and takes the `ElementRef` it\n * lives on as the floating element.\n *\n * It owns the portal, the positioning effect and `autoUpdate`, and tears all three down\n * symmetrically so a re-open never inherits stale geometry. While closed the effect tracks only\n * `open` and `reference`, so an offset or side change on a closed overlay re-runs nothing. A\n * `computePosition` that loses its reference mid-frame is swallowed, since `autoUpdate` reschedules\n * on the next live frame.\n *\n * Until the first position resolves the surface wears a `clip-path` anti-flash baseline, re-armed\n * whenever a config change restarts an open run so it stays hidden at the retained stale position.\n * `clip-path` rather than `visibility: hidden` keeps the element focusable, so the overlay shell's\n * initial-focus move still lands while the surface is unpainted.\n *\n * Position is written to `translate`, never `transform`. CSS composes `translate` outside\n * `transform`, so a consumer's `scale` enter animation pivots in place instead of scaling the\n * position offset and dragging the surface in from the viewport corner — leaving `transform` free\n * for the consumer is the point.\n *\n * SSR-safe: `effect()` runs server-side, so the browser gate here is explicit.\n */\nexport function runPositioning(config: PositioningConfig): void {\n const host = inject<ElementRef<HTMLElement>>(ElementRef);\n const el = host.nativeElement;\n\n if (!isPlatformBrowser(inject(PLATFORM_ID))) {\n return;\n }\n\n if (config.portal !== false) {\n injectPortal();\n }\n\n const shouldClip = (): boolean => config.clipUntilPositioned?.() !== false;\n\n afterNextRender(() => {\n Object.assign(el.style, {\n position: 'fixed',\n left: '0',\n top: '0',\n });\n if (shouldClip()) {\n el.style.clipPath = 'inset(50%)';\n }\n });\n\n let openCycleActive = false;\n let firstPositionFired = false;\n\n effect((onCleanup) => {\n const isOpen = config.open();\n const reference = config.reference();\n\n if (!isOpen || !reference) {\n openCycleActive = false;\n return;\n }\n\n if (!openCycleActive) {\n openCycleActive = true;\n firstPositionFired = false;\n }\n\n if (shouldClip()) {\n el.style.clipPath = 'inset(50%)';\n }\n\n const run = config.computeAndApply(el, reference);\n let cancelled = false;\n\n const cleanup = autoUpdate(reference, el, () => {\n computePosition(reference, el, {\n strategy: 'fixed',\n placement: run.placement,\n middleware: run.middleware,\n })\n .then((result) => {\n if (cancelled || !config.open()) {\n return;\n }\n el.style.translate = `${Math.round(result.x)}px ${Math.round(result.y)}px`;\n el.style.clipPath = '';\n run.apply(result);\n if (!firstPositionFired) {\n firstPositionFired = true;\n config.onFirstPosition?.();\n }\n })\n .catch(() => {});\n });\n\n onCleanup(() => {\n cancelled = true;\n cleanup();\n run.reset();\n });\n });\n}\n","import { type Signal } from '@angular/core';\nimport {\n arrow,\n type ComputePositionReturn,\n flip,\n type FlipOptions,\n hide,\n type Middleware,\n offset,\n type Padding,\n type Placement,\n type ReferenceElement,\n shift,\n size,\n} from '@floating-ui/dom';\n\nimport {\n type FloatingCustomProperties,\n injectFloatingCustomProperties,\n} from './floating-custom-properties';\nimport { runPositioning } from './run-positioning';\n\nconst PLACEMENT_OPPOSITE: Record<FloatingSide, FloatingSide> = {\n top: 'bottom',\n right: 'left',\n bottom: 'top',\n left: 'right',\n};\n\n/** The four cardinal sides a floating element can be anchored to. */\nexport type FloatingSide = 'top' | 'right' | 'bottom' | 'left';\n\n/** Alignment along the side axis: at the start edge, centered, or at the end edge. */\nexport type FloatingAlign = 'start' | 'center' | 'end';\n\n/**\n * Direction floating-ui's `flip` middleware falls back to on the *perpendicular*\n * axis when no placement on the preferred axis fits. `'none'` (the default)\n * keeps floating-ui's historical behavior — only the opposite same-axis\n * placement is tried; `'start'` / `'end'` let the surface drop to a\n * perpendicular side (e.g. a right-anchored submenu dropping to `top` / `bottom`)\n * when both sides of the preferred axis overflow.\n */\nexport type FloatingFallbackAxisSideDirection = 'none' | 'start' | 'end';\n\nexport interface FloatingConfig {\n /**\n * The anchor. Either a real DOM element (e.g. a button trigger) or a\n * floating-ui `VirtualElement` (e.g. for context menus that anchor at the\n * pointer position). Reactive — should emit `null` until the anchor is\n * available; positioning is skipped while `null`.\n */\n readonly reference: Signal<ReferenceElement | null>;\n\n /**\n * Whether the floating element is currently visible. `autoUpdate` is\n * started when this becomes `true` and torn down when it goes back to\n * `false`, so consumers don't pay for positioning while closed.\n */\n readonly open: Signal<boolean>;\n\n /**\n * Side the floating element is anchored to (`'top'`/`'right'`/`'bottom'`/\n * `'left'`). When omitted (or the signal returns `undefined`), defaults\n * to `'bottom'`. Pair with `align` for the full positioning\n * API.\n */\n readonly side?: Signal<FloatingSide | undefined>;\n\n /**\n * Alignment along the chosen side. Defaults to `'center'`. With `side`\n * this composes the floating-ui placement (e.g. `side: 'bottom'` +\n * `align: 'start'` → placement `'bottom-start'`).\n */\n readonly align?: Signal<FloatingAlign | undefined>;\n\n /**\n * Distance (px) between reference and floating along the *main* axis\n * (perpendicular to `side`). Forwarded to floating-ui's `offset`\n * middleware. Defaults to `0`.\n */\n readonly sideOffset?: Signal<number | undefined>;\n\n /**\n * Distance (px) along the *cross* axis (parallel to `side`). Useful for\n * shifting an `align: 'start'` popover slightly past the trigger edge.\n */\n readonly alignOffset?: Signal<number | undefined>;\n\n /**\n * Optional arrow element. When non-null, the `arrow` middleware is\n * registered and the helper writes `position: absolute`, the resolved\n * `left` / `top` from floating-ui, and a side-aware\n * `var(--for-floating-arrow-offset, 0px)` on the *opposite* axis once floating-ui\n * resolves a position. Consumers control how far the arrow pokes out of\n * the bubble by setting `--for-floating-arrow-offset` (typically a negative `px`\n * value) on the arrow element or any ancestor — the helper ships no\n * default visual.\n */\n readonly arrow?: Signal<HTMLElement | null>;\n\n /**\n * When `true` (default), the floating element is moved to `document.body`\n * on first render and removed on destroy. Set to `false` to keep it in\n * its declared parent (rare — only for designs where positioning ancestors\n * are guaranteed safe).\n */\n readonly portal?: boolean;\n\n /**\n * When `true` (default), the `flip` and `shift` middlewares are active so\n * the floating element stays inside the viewport. Set to `false` to keep\n * the requested placement even when it overflows — useful for tooltips\n * inside scroll containers where the consumer wants strict positioning.\n */\n readonly avoidCollisions?: Signal<boolean>;\n\n /**\n * Padding (px or per-side rect) applied to both `flip` and `shift`. When\n * unset, `flip` uses padding 0 (legacy behavior) and `shift` uses\n * `shiftPadding` (default 8). Setting this overrides both uniformly.\n */\n readonly collisionPadding?: Signal<number | Padding>;\n\n /**\n * Boundary the collision middlewares (`flip`, `shift`, `size`) measure\n * against. Defaults to the viewport. Pass an element (or list) to keep\n * the floating element inside a scroll container.\n */\n readonly collisionBoundary?: Signal<Element | Element[] | null>;\n\n /**\n * Direction floating-ui's `flip` falls back to on the *perpendicular* axis\n * when no placement on the preferred axis fits. `'none'` (default) keeps the\n * historical behavior — only the opposite same-axis placement is tried; set\n * `'start'` / `'end'` to let a side-anchored surface (e.g. a submenu) drop to\n * a perpendicular side when both sides of the preferred axis overflow. Only\n * consulted when `avoidCollisions` is on.\n */\n readonly fallbackAxisSideDirection?: Signal<FloatingFallbackAxisSideDirection>;\n\n /**\n * Explicit ordered list of fallback placements handed to `flip`. Advanced\n * control; overrides floating-ui's axis-side heuristic when provided. Only\n * consulted when `avoidCollisions` is on.\n */\n readonly fallbackPlacements?: Signal<readonly Placement[] | undefined>;\n\n /** Padding (px) handed to the `arrow` middleware so the arrow stays inside the floating element's rounded corners. */\n readonly arrowPadding?: Signal<number>;\n\n /**\n * Stickiness behaviour for `shift`. `'partial'` (default behavior of\n * `shift`) lets the floating element shift to stay visible. `'always'`\n * disables `shift` so the floating element keeps its requested placement\n * even off-screen. `false` is equivalent to `'partial'`.\n */\n readonly sticky?: Signal<'partial' | 'always' | false>;\n\n /**\n * When `true`, sets `data-detached=\"\"` on the host while the reference\n * element has scrolled off all clipping ancestors (`hide({ strategy:\n * 'escaped' })`). Lets consumers fade out tooltips/popovers tied to\n * scrolled-away triggers.\n */\n readonly hideWhenDetached?: Signal<boolean>;\n\n /**\n * When `true` (default / omitted), the floating element is clipped with\n * `clip-path: inset(50%)` until `@floating-ui/dom` resolves its first\n * position, so a short enter animation never flashes at the viewport\n * corner before placement lands. Set to `false` to paint from the first\n * frame — useful for a dramatic `animate.enter` that would otherwise lose\n * its opening frames while the async `computePosition` resolves, at the\n * cost of a possible first-frame flash at the pre-resolved position.\n */\n readonly clipUntilPositioned?: Signal<boolean>;\n\n /**\n * Invoked once per **open cycle**, on the first resolved position after\n * `open` transitions to `true` — after `@floating-ui/dom`'s async\n * `computePosition` lands, the helper drops the `clip-path` anti-flash\n * baseline, and the positioner has written its `data-*` / CSS vars.\n *\n * The semantics are **per-open, not per-run**: a positioner-config change\n * while the surface stays open re-runs the positioning effect, but this\n * callback does **not** re-fire — it fires only on the run that first\n * resolves after opening, and never while the surface stays closed. A run\n * superseded by a config change (or torn down by a close / destroy) before\n * its `computePosition` resolves is cancelled: its resolution writes nothing\n * and never fires this hook.\n *\n * This per-open guarantee is load-bearing for the seed-once consumers.\n * Because the hook runs strictly after the optional portal's `appendChild`\n * and after `computePosition` (so the `size` middleware's `max-height` is\n * already applied), it is the only moment a consumer can touch the\n * now-portaled, now-sized surface. Combobox uses it to scroll the active\n * descendant into view inside a `max-height`-constrained listbox whose\n * `scrollTop` the portal move reset to 0 — see `[forComboboxContent]`; a\n * per-run re-fire would yank that scroll back on every side flip.\n */\n readonly onFirstPosition?: () => void;\n\n /**\n * Padding (px) handed to the `shift` middleware so the floating element\n * never crowds the viewport edge. Default `8`. Used as the fallback for\n * `collisionPadding` when that signal is not provided.\n */\n readonly shiftPadding?: number;\n}\n\nfunction joinPlacement(side: FloatingSide, align: FloatingAlign): Placement {\n return (align === 'center' ? side : `${side}-${align}`) as Placement;\n}\n\nfunction splitPlacement(p: Placement): { side: FloatingSide; align: FloatingAlign } {\n const [rawSide, rawAlign] = p.split('-') as [FloatingSide, 'start' | 'end' | undefined];\n return { side: rawSide, align: rawAlign ?? 'center' };\n}\n\n/**\n * Compute the CSS `transform-origin` so a CSS scale animates outward from\n * the anchor edge. With `side: 'bottom', align: 'start'` the origin is\n * `left top` — a `scale(0.95)` collapses toward the trigger's bottom-left\n * corner.\n */\nfunction transformOriginFor(side: FloatingSide, align: FloatingAlign): string {\n let x: 'left' | 'right' | 'center';\n let y: 'top' | 'bottom' | 'center';\n if (side === 'top' || side === 'bottom') {\n y = side === 'top' ? 'bottom' : 'top';\n x = align === 'start' ? 'left' : align === 'end' ? 'right' : 'center';\n } else {\n x = side === 'left' ? 'right' : 'left';\n y = align === 'start' ? 'top' : align === 'end' ? 'bottom' : 'center';\n }\n return `${x} ${y}`;\n}\n\n/**\n * Assemble the options handed to floating-ui's `flip` middleware. Kept as a\n * pure function so the collision-fallback wiring (`fallbackAxisSideDirection`,\n * `fallbackPlacements`) is unit-testable without a live DOM — jsdom returns\n * zero rects, so `flip` never actually relocates there.\n *\n * `fallbackAxisSideDirection` is omitted (rather than passed as `'none'`) so the\n * emitted options match floating-ui's own default exactly, and\n * `fallbackPlacements` is omitted when empty / unset.\n */\nexport function buildFlipOptions(options: {\n readonly padding: number | Padding;\n readonly boundary: Element | Element[] | null;\n readonly fallbackAxisSideDirection: FloatingFallbackAxisSideDirection;\n readonly fallbackPlacements: readonly Placement[] | undefined;\n}): FlipOptions {\n const flipOptions: FlipOptions = { padding: options.padding };\n if (options.boundary) {\n flipOptions.boundary = options.boundary;\n }\n if (options.fallbackAxisSideDirection !== 'none') {\n flipOptions.fallbackAxisSideDirection = options.fallbackAxisSideDirection;\n }\n if (options.fallbackPlacements?.length) {\n flipOptions.fallbackPlacements = [...options.fallbackPlacements];\n }\n return flipOptions;\n}\n\n/**\n * Wires a floating UI element (tooltip, popover, menu...) to its anchor.\n * Must be called from an injection context. Delegates the platform gate,\n * portal, anti-flash baseline, `autoUpdate` loop, and symmetric cleanup to\n * the shared {@link runPositioning} scaffold, and supplies the anchored\n * positioner's own per-run body: the `offset` / `flip` / `shift` / `size` /\n * `hide` / `arrow` middleware stack, plus the writes that follow each resolved\n * position — `data-placement`, `data-side`, `data-align`, `data-occluded`\n * (when the `hide` middleware reports the reference is off-screen),\n * `data-detached` (when `hideWhenDetached` is on and the reference escaped its\n * clipping ancestors), the `--for-floating-anchor-width/-height`,\n * `--for-floating-available-width/-height`, and `--for-floating-content-transform-origin` CSS\n * variables, and the optional arrow's position + `--for-floating-arrow-offset`.\n *\n * Once per open cycle, on the first resolved position after opening, it invokes\n * `onFirstPosition` — after the portal move and after `size` applied its\n * `max-height`, so a consumer can touch the now-portaled, now-sized surface. A\n * config change while open does not re-fire it; see\n * {@link FloatingConfig.onFirstPosition}.\n *\n * Cleanup is asymmetric on purpose: {@link resetFloatingStyles} strips the\n * transient sizing vars and occlusion attributes but retains the resolved\n * `translate` and placement outputs so a closing surface stays anchored to its\n * trigger through `animate.leave`; the next mount re-arms the baseline and\n * recomputes everything before painting.\n *\n * Stylistic concerns (which side gets the arrow offset via\n * `--for-floating-arrow-offset`, pointer events, background, animations) stay with the\n * consumer.\n */\nexport function injectFloating(config: FloatingConfig): void {\n const fallbackShiftPadding = config.shiftPadding ?? 8;\n const vars = injectFloatingCustomProperties();\n\n runPositioning({\n reference: config.reference,\n open: config.open,\n portal: config.portal,\n clipUntilPositioned: config.clipUntilPositioned,\n onFirstPosition: config.onFirstPosition,\n computeAndApply: (el, reference) => {\n const arrowEl = config.arrow?.() ?? null;\n\n // Resolve placement from `side` + `align` with sensible defaults.\n const sideInput = config.side?.() ?? 'bottom';\n const alignInput = config.align?.() ?? 'center';\n const requestedPlacement: Placement = joinPlacement(sideInput, alignInput);\n\n const sideOffsetVal = config.sideOffset?.() ?? 0;\n const alignOffsetVal = config.alignOffset?.() ?? 0;\n const avoidCollisions = config.avoidCollisions?.() ?? true;\n // `collisionPadding`, when set, applies uniformly to flip + shift +\n // size. When unset, preserve the historical defaults:\n // `flip` had no padding, `shift` had `shiftPadding ?? 8`.\n const collisionPaddingExplicit = config.collisionPadding?.();\n const flipPaddingValue = collisionPaddingExplicit ?? 0;\n const shiftPaddingValue = collisionPaddingExplicit ?? fallbackShiftPadding;\n const sizePaddingValue = collisionPaddingExplicit ?? fallbackShiftPadding;\n const collisionBoundary = config.collisionBoundary?.() ?? null;\n const arrowPaddingVal = config.arrowPadding?.() ?? 0;\n const stickyVal = config.sticky?.() ?? false;\n const hideOnDetach = config.hideWhenDetached?.() ?? false;\n\n const middleware: Middleware[] = [\n offset({ mainAxis: sideOffsetVal, crossAxis: alignOffsetVal }),\n ];\n\n if (avoidCollisions) {\n middleware.push(\n flip(\n buildFlipOptions({\n padding: flipPaddingValue,\n boundary: collisionBoundary,\n fallbackAxisSideDirection: config.fallbackAxisSideDirection?.() ?? 'none',\n fallbackPlacements: config.fallbackPlacements?.(),\n }),\n ),\n );\n\n if (stickyVal !== 'always') {\n const shiftOptions: Parameters<typeof shift>[0] = { padding: shiftPaddingValue };\n if (collisionBoundary) shiftOptions.boundary = collisionBoundary;\n middleware.push(shift(shiftOptions));\n }\n }\n\n // `size` exposes available width/height as CSS variables so the\n // consumer can `max-height: var(--for-floating-available-height)` etc.\n const sizeOptions: Parameters<typeof size>[0] = {\n padding: sizePaddingValue,\n apply({ availableWidth, availableHeight }) {\n el.style.setProperty(vars.availableWidth, `${Math.max(0, Math.round(availableWidth))}px`);\n el.style.setProperty(\n vars.availableHeight,\n `${Math.max(0, Math.round(availableHeight))}px`,\n );\n },\n };\n if (collisionBoundary) sizeOptions.boundary = collisionBoundary;\n middleware.push(size(sizeOptions));\n\n middleware.push(hide({ strategy: 'referenceHidden' }));\n if (hideOnDetach) {\n middleware.push(hide({ strategy: 'escaped' }));\n }\n\n if (arrowEl) {\n middleware.push(arrow({ element: arrowEl, padding: arrowPaddingVal }));\n }\n\n return {\n placement: requestedPlacement,\n middleware,\n apply({ placement: resolvedPlacement, middlewareData }: ComputePositionReturn) {\n const { side: resolvedSide, align: resolvedAlign } = splitPlacement(\n resolvedPlacement as Placement,\n );\n\n el.dataset['placement'] = resolvedPlacement;\n el.dataset['side'] = resolvedSide;\n el.dataset['align'] = resolvedAlign;\n\n // Anchor box → CSS vars so the consumer can size the floating\n // element relative to the anchor (`width: var(--for-floating-anchor-width)`).\n // Both real `Element`s and floating-ui `VirtualElement`s expose\n // `getBoundingClientRect`, so the call is safe.\n const rect = reference.getBoundingClientRect();\n el.style.setProperty(vars.anchorWidth, `${Math.round(rect.width)}px`);\n el.style.setProperty(vars.anchorHeight, `${Math.round(rect.height)}px`);\n el.style.setProperty(\n vars.contentTransformOrigin,\n transformOriginFor(resolvedSide, resolvedAlign),\n );\n\n // hide() with strategy 'referenceHidden' — anchor scrolled off-screen.\n if (middlewareData.hide?.['referenceHidden']) {\n el.dataset['occluded'] = '';\n } else {\n delete el.dataset['occluded'];\n }\n // hide() with strategy 'escaped' — only registered when\n // `hideWhenDetached` is on.\n if (hideOnDetach && middlewareData.hide?.['escaped']) {\n el.dataset['detached'] = '';\n } else {\n delete el.dataset['detached'];\n }\n\n if (arrowEl && middlewareData.arrow) {\n const { x: ax, y: ay } = middlewareData.arrow;\n const opposite = PLACEMENT_OPPOSITE[resolvedSide];\n Object.assign(arrowEl.style, {\n position: 'absolute',\n left: ax != null ? `${ax}px` : '',\n top: ay != null ? `${ay}px` : '',\n right: '',\n bottom: '',\n [opposite]: `var(${vars.arrowOffset}, 0px)`,\n });\n // `data-placement` on the arrow stores the *side* only, for\n // historical reasons (CSS like `[data-placement=\"top\"]`).\n // `data-side` is the new canonical attribute; both stay in\n // sync until consumers migrate.\n arrowEl.dataset['placement'] = resolvedSide;\n arrowEl.dataset['side'] = resolvedSide;\n }\n },\n reset() {\n resetFloatingStyles(el, vars);\n if (arrowEl) {\n resetArrowStyles(arrowEl);\n }\n },\n };\n },\n });\n}\n\n/**\n * Strip the transient sizing CSS custom properties, the occlusion `data-*`\n * attributes, and the `clip-path` hide baseline `injectFloating` writes to the\n * floating element. The resolved `translate` and the resolved-placement outputs\n * (`--for-floating-content-transform-origin`, `data-placement`, `data-side`,\n * `data-align`) are intentionally retained so a closing surface stays anchored\n * to its trigger — and keeps pivoting its scale leave from the trigger edge —\n * through `animate.leave`; the next mount re-arms the `clip-path` baseline in\n * `afterNextRender` and recomputes all of them before painting, so a retained\n * value never produces a stale-position flash.\n */\nfunction resetFloatingStyles(el: HTMLElement, vars: FloatingCustomProperties): void {\n // Clearing (not re-arming) the hide baseline keeps a closing surface\n // visible for its `animate.leave`; the next mount re-applies the\n // `clip-path` baseline in `afterNextRender`.\n el.style.removeProperty('clip-path');\n el.style.removeProperty(vars.anchorWidth);\n el.style.removeProperty(vars.anchorHeight);\n el.style.removeProperty(vars.availableWidth);\n el.style.removeProperty(vars.availableHeight);\n el.removeAttribute('data-occluded');\n el.removeAttribute('data-detached');\n}\n\n/**\n * Strip every inline style and `data-*` attribute `injectFloating` writes\n * to the optional arrow element. Mirrors `resetFloatingStyles`.\n */\nfunction resetArrowStyles(arrowEl: HTMLElement): void {\n arrowEl.style.removeProperty('position');\n arrowEl.style.removeProperty('left');\n arrowEl.style.removeProperty('top');\n arrowEl.style.removeProperty('right');\n arrowEl.style.removeProperty('bottom');\n arrowEl.removeAttribute('data-placement');\n arrowEl.removeAttribute('data-side');\n}\n","import { type Signal } from '@angular/core';\nimport {\n type Middleware,\n type Padding,\n type Placement,\n type ReferenceElement,\n} from '@floating-ui/dom';\n\nimport {\n type FloatingCustomProperties,\n injectFloatingCustomProperties,\n} from './floating-custom-properties';\nimport { runPositioning } from './run-positioning';\n\nexport interface ItemAlignedConfig {\n /**\n * The anchor (typically a `<button>` trigger). Reactive — should emit\n * `null` until the anchor is available; positioning is skipped while\n * `null` or `open` is `false`.\n */\n readonly reference: Signal<ReferenceElement | null>;\n\n /**\n * Whether the listbox is currently visible. `autoUpdate` is started when\n * this becomes `true` and torn down when it goes back to `false`.\n */\n readonly open: Signal<boolean>;\n\n /**\n * The selected option element to anchor over the trigger. When `null`,\n * the algorithm falls back to the first enabled `[role=\"option\"]` inside\n * the listbox. Reactive — re-running `computePosition` if the selection\n * changes while open.\n */\n readonly selectedOption: Signal<HTMLElement | null>;\n\n /**\n * Padding (px) the listbox keeps from the viewport edge. Default `8`.\n * Drives both the viewport clamp on the listbox top/bottom and the\n * `--for-floating-available-height` CSS variable.\n */\n readonly collisionPadding?: Signal<number | Padding>;\n\n /**\n * Called once per open cycle, on the first resolved position, after the listbox has been\n * portaled and its CSS vars written. When set it replaces the positioner's own first-position\n * scroll of the anchored option, so the caller decides which option to reveal.\n */\n readonly onFirstPosition?: () => void;\n\n /**\n * When `true` (default), the floating element is moved to `document.body`\n * on first render and removed on destroy. Set to `false` when the caller\n * already invokes `injectPortal()` on its own.\n */\n readonly portal?: boolean;\n}\n\nfunction paddingTop(padding: number | Padding | undefined, fallback: number): number {\n if (padding == null) {\n return fallback;\n }\n if (typeof padding === 'number') {\n return padding;\n }\n return padding.top ?? fallback;\n}\n\nfunction findFirstEnabledOption(listbox: HTMLElement): HTMLElement | null {\n const options = listbox.querySelectorAll<HTMLElement>('[role=\"option\"]');\n for (let i = 0; i < options.length; i++) {\n const opt = options[i]!;\n if (opt.getAttribute('aria-disabled') === 'true' || opt.hasAttribute('disabled')) {\n continue;\n }\n return opt;\n }\n return null;\n}\n\nexport interface ItemAlignedGeometry {\n /** Viewport-relative top edge of the anchor. */\n readonly triggerTop: number;\n\n readonly triggerHeight: number;\n\n /** Border-box height of the listbox, excluding any CSS transform. */\n readonly listboxHeight: number;\n\n /**\n * Distance from the listbox's top border edge to the vertical center of the\n * option to anchor over the trigger, or `null` when the listbox holds no\n * anchorable option — the listbox then aligns to the trigger's top edge.\n */\n readonly targetCenter: number | null;\n\n readonly viewportHeight: number;\n\n /** Distance the listbox keeps from the viewport's top and bottom edges. */\n readonly padding: number;\n}\n\n/**\n * Resolves the listbox's vertical offset so the target option's center lines up\n * with the trigger's center, clamped inside the viewport. A listbox taller than\n * the band the padding leaves cannot satisfy both edges and pins to the top.\n */\nexport function resolveItemAlignedY(geometry: ItemAlignedGeometry): number {\n const { triggerTop, triggerHeight, listboxHeight, targetCenter, viewportHeight, padding } =\n geometry;\n const minY = padding;\n const maxY = viewportHeight - listboxHeight - padding;\n\n if (targetCenter == null) {\n return Math.max(minY, Math.min(triggerTop, maxY));\n }\n\n const desiredY = triggerTop + triggerHeight / 2 - targetCenter;\n return maxY > minY ? Math.max(minY, Math.min(desiredY, maxY)) : minY;\n}\n\nfunction offsetTopWithinChain(el: HTMLElement): number {\n const view = el.ownerDocument.defaultView;\n let top = 0;\n let node: HTMLElement | null = el;\n while (node) {\n top += node.offsetTop;\n const parent: Element | null = node.offsetParent;\n node = view && parent instanceof view.HTMLElement ? parent : null;\n }\n return top;\n}\n\n/**\n * Distance from `listbox`'s top border edge to `target`'s vertical center, read\n * from offset geometry so a CSS transform on either element cannot skew it.\n * Offset geometry is integer-rounded, so the result is accurate to about a\n * pixel.\n */\nexport function offsetCenterWithinListbox(target: HTMLElement, listbox: HTMLElement): number {\n return offsetTopWithinChain(target) + target.offsetHeight / 2 - offsetTopWithinChain(listbox);\n}\n\n/**\n * Custom floating-ui middleware. Computes raw `x`/`y` so the *target option's\n * vertical center* lines up with the *trigger's vertical center*, then clamps\n * the listbox inside the viewport with `padding`. Cross-axis: listbox left\n * edge aligned to the trigger left edge.\n *\n * Falls back to the first enabled option inside the listbox when no option\n * is selected — matches the macOS `<select>` behavior.\n */\nfunction itemAligned(\n selectedOption: () => HTMLElement | null,\n paddingFn: () => number,\n): Middleware {\n return {\n name: 'item-aligned',\n fn(state) {\n const reference = state.elements.reference;\n const floating = state.elements.floating;\n const triggerRect = reference.getBoundingClientRect();\n const target = selectedOption() ?? findFirstEnabledOption(floating);\n // Read the viewport height through the floating element's own\n // window so the middleware works in iframes / multiple-document\n // contexts and stays SSR-safe (the middleware itself only runs\n // inside a `computePosition` callback, which is browser-only).\n const viewportHeight = floating.ownerDocument.defaultView?.innerHeight ?? 0;\n\n const y = resolveItemAlignedY({\n triggerTop: triggerRect.top,\n triggerHeight: triggerRect.height,\n listboxHeight: floating.offsetHeight,\n targetCenter: target ? offsetCenterWithinListbox(target, floating) : null,\n viewportHeight,\n padding: paddingFn(),\n });\n\n return { x: triggerRect.left, y };\n },\n };\n}\n\n/**\n * Item-aligned positioner for `[forSelectContent]` (the `position=\"item-aligned\"`\n * mode). The listbox overlays the trigger so the *selected option*'s center\n * lines up with the trigger's center on the cross axis — visually the menu\n * \"snaps over\" the trigger when opened, mirroring macOS native `<select>`\n * dropdowns.\n *\n * Delegates the platform gate, portal, anti-flash baseline, `autoUpdate` loop,\n * `translate` write, `clip-path` drop, and symmetric cleanup to the shared\n * {@link runPositioning} scaffold, and supplies its own per-run body: the\n * custom `itemAligned` middleware plus the writes that follow each resolved\n * position — `data-position=\"item-aligned\"`, the `--for-floating-anchor-width/-height`\n * and `--for-floating-available-height` CSS vars — and, on the first resolved position,\n * `scrollIntoView({ block: 'nearest' })` on the target option so the visual\n * anchor stays correct when the listbox is taller than the viewport, unless\n * `onFirstPosition` is supplied, which then owns that reveal.\n *\n * `--for-floating-available-height` is the same *concept* the anchored positioner\n * publishes (the maximum block-size the surface may occupy before it\n * collides), computed for this algorithm: the surface overlays the trigger\n * rather than sitting beside it, so the band is the full viewport minus\n * `collisionPadding` on both edges (`innerHeight - 2 * collisionPadding`)\n * rather than the anchor-relative space floating-ui's `size` middleware\n * reports. A consumer's `max-height: var(--for-floating-available-height)` therefore\n * works unchanged across `position=\"popper\"` and `position=\"item-aligned\"`.\n * `--for-floating-available-width` is **not** published here: item-aligned\n * pins the cross axis to the trigger's left edge and computes no width budget.\n *\n * `side`, `align`, `sideOffset`, `alignOffset`, `placement`, `flip`, `shift`,\n * and `arrow` are intentionally **not** part of this API — item-aligned mode\n * treats them as no-ops.\n */\nexport function injectItemAlignedPositioner(config: ItemAlignedConfig): void {\n const vars = injectFloatingCustomProperties();\n runPositioning({\n reference: config.reference,\n open: config.open,\n portal: config.portal,\n onFirstPosition: config.onFirstPosition,\n computeAndApply: (el, reference) => {\n const collisionPadding = paddingTop(config.collisionPadding?.(), 8);\n\n let initialScrollDone = config.onFirstPosition !== undefined;\n\n return {\n // Placement is irrelevant — `itemAligned` overrides x/y outright —\n // but `computePosition` requires *some* placement. Pick a stable one\n // so middleware data stays predictable.\n placement: 'bottom-start' satisfies Placement,\n middleware: [\n itemAligned(\n () => config.selectedOption(),\n () => collisionPadding,\n ),\n ],\n apply() {\n el.dataset['position'] = 'item-aligned';\n\n const triggerRect = reference.getBoundingClientRect();\n el.style.setProperty(vars.anchorWidth, `${Math.round(triggerRect.width)}px`);\n el.style.setProperty(vars.anchorHeight, `${Math.round(triggerRect.height)}px`);\n\n const innerHeight = el.ownerDocument.defaultView?.innerHeight ?? 0;\n const availableHeight = Math.max(0, innerHeight - 2 * collisionPadding);\n el.style.setProperty(vars.availableHeight, `${Math.round(availableHeight)}px`);\n\n if (!initialScrollDone) {\n initialScrollDone = true;\n const target = config.selectedOption() ?? findFirstEnabledOption(el);\n // jsdom (test env) doesn't implement scrollIntoView — guard the\n // call so the helper stays usable in non-browser environments.\n target?.scrollIntoView?.({ block: 'nearest' });\n }\n },\n reset() {\n resetItemAlignedStyles(el, vars);\n },\n };\n },\n });\n}\n\n/**\n * Strip the transient sizing vars, CSS custom properties, and `data-*`\n * attributes `injectItemAlignedPositioner` writes to the listbox — including\n * the `clip-path` hide baseline — while **retaining** the resolved `translate`.\n * Mirrors `resetFloatingStyles` in `floating.ts`: the surface is portaled\n * until `getAnimations().finished`, so during an `animate.leave` exit the host\n * keeps `position: fixed; left: 0; top: 0` and the retained `translate` stays\n * anchored over the trigger instead of flashing at the viewport origin. The\n * next mount re-arms the `clip-path` baseline in `afterNextRender` and\n * recomputes the position before painting, so the retained `translate` never\n * produces a stale-position flash.\n */\nfunction resetItemAlignedStyles(el: HTMLElement, vars: FloatingCustomProperties): void {\n el.style.removeProperty('clip-path');\n el.style.removeProperty(vars.anchorWidth);\n el.style.removeProperty(vars.anchorHeight);\n el.style.removeProperty(vars.availableHeight);\n el.removeAttribute('data-position');\n}\n","import { DestroyRef, ElementRef, inject, type Signal } from '@angular/core';\n\nimport {\n afterNextRenderCancellable,\n findFirstFocusable,\n findTabbableEdges,\n isInitialFocusTarget,\n leavesTabSequence,\n resolveActiveElement,\n resolveEventTarget,\n type VetoableNativeEvent,\n} from 'forty-cdk/core';\nimport {\n injectDismissibleLayer,\n type DismissibleLayerActivateOptions,\n type DismissibleLayerNesting,\n} from '../dismissible-layer/dismissible-layer';\nimport { injectFloating, type FloatingConfig } from '../floating/floating';\nimport { InertSiblingsStack } from '../inert-siblings/inert-siblings';\nimport { ModalActivationOrder } from '../modal-shell/modal-activation-order';\nimport { injectItemAlignedPositioner, type ItemAlignedConfig } from '../floating/item-aligned';\nimport { buildOutsideVetoOptions, outsideVetoChannels } from './outside-veto';\n\n/**\n * Tagged-union positioner config. The shell delegates to either\n * `injectFloating` (the standard anchored placement) or\n * `injectItemAlignedPositioner` (the macOS-style overlay used by Select's\n * `position=\"item-aligned\"` mode). Both helpers portal by default, so the\n * shell never calls `injectPortal` itself — that responsibility stays with\n * the positioner.\n */\nexport type OverlayShellPositionerConfig =\n | ({ readonly kind: 'floating' } & FloatingConfig)\n | ({ readonly kind: 'item-aligned' } & ItemAlignedConfig);\n\n/**\n * Outside-interaction wiring for a trigger-anchored overlay.\n *\n * Each wired channel builds one `VetoableNativeEvent` and hands it to both the specific emitter and\n * the composite `interactOutside` one, so a `preventDefault()` from either vetoes the close. When\n * nothing vetoes and `dismissible()` is `true`, the shell calls `requestClose` with the channel's\n * reason. `dismissible` and `requestClose` are required whenever any outside channel is wired.\n *\n * `exemptElements` is re-read on every event, so newly portaled siblings and swapped triggers are\n * honoured.\n *\n * Escape is forwarded verbatim and never participates in the outside-close: its close behaviour\n * differs per primitive, so emitting and closing stay the consumer's decision.\n *\n * Every callback is optional; the shell registers a listener only for the channels supplied.\n */\nexport interface OverlayShellDismissConfig {\n /**\n * Whether an un-vetoed outside interaction fires the implicit\n * `requestClose`. Required when any outside channel\n * (`emitPointerDownOutside` / `emitFocusOutside` / `emitInteractOutside`)\n * is wired.\n */\n readonly dismissible?: Signal<boolean>;\n /**\n * Called with the matching reason when the consumer doesn't veto an outside\n * interaction. The consumer owns the close (and any bookkeeping such as\n * marking the control touched); the shell never touches the directive's\n * close output directly. Required alongside `dismissible`. Each wired outside\n * channel fires its own close, so a specific channel (`emitPointerDownOutside`\n * / `emitFocusOutside`) closes even without `emitInteractOutside` wired. A\n * close requested here never returns focus on destroy.\n */\n readonly requestClose?: (reason: 'pointerDownOutside' | 'focusOutside') => void;\n /** Forwards the raw Escape `KeyboardEvent` to the consumer; close is consumer-owned. */\n readonly emitEscapeKeyDown?: (event: KeyboardEvent) => void;\n /** Forwards the pointer-down-outside veto to the directive's `(pointerDownOutside)` output. */\n readonly emitPointerDownOutside?: (veto: VetoableNativeEvent<PointerEvent>) => void;\n /** Forwards the focus-outside veto to the directive's `(focusOutside)` output. */\n readonly emitFocusOutside?: (veto: VetoableNativeEvent<FocusEvent>) => void;\n /** Forwards the composite veto to the directive's `(interactOutside)` output. */\n readonly emitInteractOutside?: (veto: VetoableNativeEvent<PointerEvent | FocusEvent>) => void;\n /**\n * Extra elements whose subtrees count as \"inside\" for outside-pointer /\n * outside-focus checks (e.g. an anchored trigger that lives outside the\n * portaled content). Recomputed on every event so DOM mutations are\n * picked up, and handed the node being tested.\n */\n readonly exemptElements?: (target: Node) => readonly Element[];\n /**\n * Declared nesting position of this surface inside a chain of structurally\n * nested overlays (a menu and its submenus). Forwarded verbatim to the\n * dismissible layer so the stack orders the chain by depth instead of by the\n * order the levels happened to render in. Omit for a standalone overlay.\n */\n readonly nesting?: DismissibleLayerNesting;\n /**\n * Whether the surface also closes on an outside press the overlay stacked directly above it\n * closed on, instead of leaving that press to the topmost overlay alone. Read on every press.\n */\n readonly cascadeOutsidePress?: () => boolean;\n}\n\n/**\n * Where initial focus should land when the surface mounts.\n *\n * - `'first'` — first focusable descendant of the host (uses the shared\n * `findFirstFocusable` selector). Falls back to the host element itself.\n * - `'container'` — host element (gets `tabindex=\"-1\"` semantics from the\n * primitive's host bindings).\n * - `move()` — primitive-owned focus algorithm (e.g. Menu's\n * `focusInitialEnabledItem`, Select's `focusSelectedOption`). Should return\n * `true` on success and `false` if no candidate was found, so the shell can\n * fall back to focusing the host element.\n */\nexport type OverlayShellInitialFocusMove = 'first' | 'container' | (() => boolean);\n\n/**\n * Optional initial-focus wiring. Absent when the consumer wants focus to\n * stay where it is (Combobox keeps focus in the input; Tooltip / HoverCard\n * have no focus moves).\n *\n * `veto` corresponds to the `(autoFocusOnOpen)` output: returning `true`\n * skips the imperative focus move.\n */\nexport interface OverlayShellInitialFocusConfig {\n readonly move: OverlayShellInitialFocusMove;\n readonly veto?: () => boolean;\n /**\n * Element the consumer marked as the initial focus target, read once at mount. When it resolves\n * to an element that passes `isInitialFocusTarget`, focus lands there instead of running `move`.\n */\n readonly target?: () => HTMLElement | null;\n}\n\n/**\n * Optional return-focus wiring. Absent when the consumer never wants to\n * return focus on destroy (Combobox closes back into the input via its own\n * keydown / blur paths; Tooltip / HoverCard are non-focusing).\n *\n * - `enabled` — the primitive's `[returnFocus]` input. When `false`, the\n * shell skips the return-focus call entirely.\n * - `target` — the element to focus on destroy (typically the trigger).\n * Returning `null` is a safe no-op (the trigger may have unmounted).\n * - `veto` — `(autoFocusOnClose)` veto. Returning `true` skips the focus\n * call.\n * - `skip` — additional opt-out, read before `veto`. The shell already skips\n * the return after a close it requested itself, through an outside channel\n * or a Tab out, since focus is then where the user moved it. `skip` covers\n * the closes that reach the root another way, such as a Tab the root handles\n * or a close propagated from a nested surface.\n */\nexport interface OverlayShellReturnFocusConfig {\n readonly enabled: Signal<boolean>;\n readonly target: () => HTMLElement | null;\n readonly veto?: () => boolean;\n readonly skip?: () => boolean;\n}\n\n/**\n * Optional Tab-out wiring for a non-modal surface portaled away from its trigger. A Tab past the\n * surface's last tabbable lands on the element after `target` in the page's tab order, and a\n * Shift+Tab before its first lands on `target` itself, as if the surface sat right after it.\n *\n * - `target` — the element the surface follows in the tab order (typically the trigger).\n * Returning `null` leaves Tab to the browser.\n * - `close` — closes the surface after the focus move, unless `dismiss.dismissible()` is\n * `false`. Return focus is skipped for that close.\n */\nexport interface OverlayShellTabOutConfig {\n readonly target: () => HTMLElement | null;\n readonly close: () => void;\n}\n\n/**\n * Single config for the overlay-content lifecycle. Each sub-bundle is\n * individually optional so the nine concrete primitives (Popover, Menu,\n * MenuSub, ContextMenu, DropdownMenu, Combobox, Select, Tooltip, HoverCard)\n * can opt in to only the pieces they need.\n *\n * The shell never reads any of the primitive's own context tokens — the\n * caller forwards each piece as plain signals / callbacks so the shell stays\n * orthogonal to the primitive surface and trivially mockable in tests.\n */\nexport interface OverlayShellConfig {\n readonly positioner: OverlayShellPositionerConfig;\n readonly dismiss?: OverlayShellDismissConfig;\n readonly initialFocus?: OverlayShellInitialFocusConfig;\n readonly returnFocus?: OverlayShellReturnFocusConfig;\n readonly tabOut?: OverlayShellTabOutConfig;\n}\n\n/**\n * Owns the lifecycle of a portaled, trigger-anchored overlay surface — the `*-content` directives\n * of Popover, the menu family, Combobox, Select, Tooltip and HoverCard.\n *\n * Positioning is delegated to the configured positioner, which portals the host itself: the caller\n * must not also call `injectPortal`.\n *\n * When configured, the shell activates a dismissible layer after the first render, performs the\n * initial focus move — falling back to the host when the move finds no candidate — and restores\n * focus to the return target on destroy. Both focus moves are skipped when their `veto()` returns\n * truthy, which is how `autoFocusOnOpen` / `autoFocusOnClose` are honoured. The return is also\n * skipped when the surface closed through one of its own outside channels or a Tab out, without\n * consulting `veto`: focus already moved where the user put it.\n *\n * Return focus runs after the portaled node has been detached, so the trigger receives the focus\n * event in a settled layout.\n *\n * Must be called from an injection context. The host's `ElementRef` is forwarded to the dismissible\n * layer and the positioner.\n */\nexport function injectOverlayShell(config: OverlayShellConfig): void {\n const host = inject<ElementRef<HTMLElement>>(ElementRef);\n const el = host.nativeElement;\n const inertStack = inject(InertSiblingsStack);\n const order = inject(ModalActivationOrder);\n\n // 1. Dismissible layer. Created BEFORE the positioner so its\n // `DestroyRef.onDestroy` (dismissible.deactivate) registers first and\n // therefore runs first on teardown — i.e. the layer is removed from\n // the stack before the positioner's portal removes the node from the\n // DOM. That ordering matches every pre-shell *-content directive and\n // avoids a window where a focusin fired during DOM removal could\n // route through `handleFocusIn` and trigger a spurious onFocusOutside.\n const dismissCfg = config.dismiss;\n const layer = dismissCfg !== undefined ? injectDismissibleLayer() : null;\n\n // 2. Positioner. The kind is read once at construction; switching modes\n // at runtime would require unmounting + remounting the directive,\n // which is the expected pattern for primitives whose positioning\n // algorithm is structurally different (Select's two modes).\n if (config.positioner.kind === 'item-aligned') {\n const { kind: _ignored, ...rest } = config.positioner;\n injectItemAlignedPositioner(rest);\n } else {\n const { kind: _ignored, ...rest } = config.positioner;\n injectFloating(rest);\n }\n\n // 3. afterNextRender — activate the layer and run initial focus once\n // input bindings have settled. Both pieces depend on having a\n // fully-rendered host element (exempt-element queries, focus targets).\n // `afterNextRenderCancellable` makes the destroy-before-render path safe.\n // On the true-async path (queued render after destroy) the callback is\n // cancelled, so the dismissible layer is never pushed onto the stack. On\n // the synchronous-teardown path the callback flushes just before the\n // layer's own `DestroyRef.onDestroy` (registered above via\n // `injectDismissibleLayer`, so it runs first among the destroy hooks),\n // which pops the just-pushed layer. Either way the stack is left without\n // a dead topmost entry that would swallow every later Escape /\n // pointer-down-outside.\n let destroyed = false;\n let releasePeer: (() => void) | null = null;\n inject(DestroyRef).onDestroy(() => {\n destroyed = true;\n releasePeer?.();\n releasePeer = null;\n });\n afterNextRenderCancellable(() => {\n const anchor = resolveModalAnchor(config);\n order.after(order.enclosingHeld(anchor), () => {\n if (!destroyed) {\n activate(anchor);\n }\n });\n });\n\n const activate = (anchor: Element | null): void => {\n // Modal-peer registration (#676). The positioner's portal ran in an\n // earlier hook of this same render batch, so the host is already in\n // `body`. Registering it with the anchor lets `InertSiblingsStack` leave it\n // live while the anchor belongs to the topmost modal — opened from inside a\n // Dialog / Drawer (a Select in a form, a context menu on dialog content) —\n // and inert it under any other owner, so a toast / background overlay stays\n // isolated (#388) and a background modal's overlay is inerted under a\n // nested modal. The registration lands before the inert observer's\n // microtask inspects the portaled host.\n if (anchor !== null) {\n releasePeer = inertStack.registerPeer(el, [anchor]);\n }\n\n if (layer && dismissCfg) {\n const requestClose = dismissCfg.requestClose;\n const options: DismissibleLayerActivateOptions = {\n channels: outsideVetoChannels(dismissCfg),\n ...buildOutsideVetoOptions(\n requestClose\n ? {\n ...dismissCfg,\n requestClose: (reason) => {\n closedByOutside = true;\n requestClose(reason);\n },\n }\n : dismissCfg,\n ),\n };\n\n if (dismissCfg.exemptElements) {\n options.exemptElements = dismissCfg.exemptElements;\n }\n if (dismissCfg.nesting) {\n options.nesting = dismissCfg.nesting;\n }\n if (dismissCfg.cascadeOutsidePress) {\n options.cascadeOutsidePress = dismissCfg.cascadeOutsidePress;\n }\n // Escape: forwarded verbatim. The consumer owns the emit + close\n // decision (combobox routes it through its input directive instead and\n // omits this channel; hover-card schedules a timed close).\n if (dismissCfg.emitEscapeKeyDown) {\n options.onEscapeKeyDown = dismissCfg.emitEscapeKeyDown;\n }\n\n layer.activate(options);\n }\n\n const focusCfg = config.initialFocus;\n if (focusCfg) {\n // Veto first — the `(autoFocusOnOpen)` output's `preventDefault`\n // returns true here, mirroring what the per-primitive code did.\n if (focusCfg.veto?.()) {\n return;\n }\n const marked = focusCfg.target?.() ?? null;\n const move = focusCfg.move;\n if (marked !== null && isInitialFocusTarget(marked, el)) {\n marked.focus();\n } else if (move === 'first') {\n (findFirstFocusable(el) ?? el).focus();\n } else if (move === 'container') {\n el.focus();\n } else {\n // Primitive-owned focus algorithm (Menu's first/last item, Select's\n // selected option, etc.). Returns true on success; on miss we fall\n // back to the host so keyboard users land somewhere predictable.\n const moved = move();\n if (!moved) {\n el.focus();\n }\n }\n }\n };\n\n let tabbedOut = false;\n let closedByOutside = false;\n const tabOutCfg = config.tabOut;\n if (tabOutCfg) {\n const onKeyDown = (event: KeyboardEvent): void => {\n if (handleTabOut(event, el, tabOutCfg, dismissCfg?.dismissible?.() ?? true)) {\n tabbedOut = true;\n layer?.deactivate();\n }\n };\n el.addEventListener('keydown', onKeyDown);\n inject(DestroyRef).onDestroy(() => el.removeEventListener('keydown', onKeyDown));\n }\n\n // 4. Return focus on destroy. The hook is registered AFTER the layer's\n // destroy hook (created above) and AFTER the positioner's portal hook\n // (created inside injectFloating / injectItemAlignedPositioner) so it\n // runs last — same ordering as the pre-shell hand-rolled code.\n const rfCfg = config.returnFocus;\n if (rfCfg) {\n inject(DestroyRef).onDestroy(() => {\n if (tabbedOut || closedByOutside || rfCfg.skip?.()) {\n return;\n }\n if (rfCfg.veto?.()) {\n return;\n }\n if (!rfCfg.enabled()) {\n return;\n }\n rfCfg.target()?.focus();\n });\n }\n}\n\n/**\n * Moves focus to the tab-out target when a Tab press would leave the surface's Tab cycle, then\n * closes the surface when `closes`. A forward Tab keeps its default action so the browser advances\n * from the target; a backward one is prevented so focus stays on it. Returns whether it closed.\n */\nfunction handleTabOut(\n event: KeyboardEvent,\n host: HTMLElement,\n config: OverlayShellTabOutConfig,\n closes: boolean,\n): boolean {\n if (\n event.key !== 'Tab' ||\n event.defaultPrevented ||\n event.altKey ||\n event.ctrlKey ||\n event.metaKey\n ) {\n return false;\n }\n const target = config.target();\n if (target === null) {\n return false;\n }\n const from = resolveEventTarget(event);\n const backward = event.shiftKey;\n if (\n !leavesTabSequence(findTabbableEdges(host), from instanceof Element ? from : null, backward)\n ) {\n return false;\n }\n target.focus();\n if (resolveActiveElement(target.ownerDocument) !== target) {\n return false;\n }\n if (backward) {\n event.preventDefault();\n }\n if (!closes) {\n return false;\n }\n config.close();\n return true;\n}\n\n/**\n * Resolves the real DOM element an overlay is anchored to, for the modal-peer ownership check.\n *\n * Falls back to the `VirtualElement`'s `contextElement` and then to the return-focus target for\n * pointer-positioned overlays. Returns `null` when no backing element exists, leaving the overlay\n * unmarked.\n */\nfunction resolveModalAnchor(config: OverlayShellConfig): Element | null {\n const ref = config.positioner.reference();\n if (ref instanceof Element) {\n return ref;\n }\n const contextElement = ref?.contextElement;\n if (contextElement instanceof Element) {\n return contextElement;\n }\n return config.returnFocus?.target() ?? null;\n}\n","import { effect, isDevMode, type Signal } from '@angular/core';\n\n/** The trigger state the dev-mode missing-`[controls]` warning watches, and the warning itself. */\nexport interface UncontrolledTriggerConfig {\n /** The trigger's open state. */\n readonly open: Signal<boolean>;\n /** The id the trigger mirrors to `aria-controls`, or `null` when unset. */\n readonly controls: Signal<string | null>;\n /** Emits the primitive's own `fortyWarn`, so each primitive keeps its own code. */\n readonly warn: () => void;\n}\n\n/**\n * Warns — dev mode only — when a trigger that mirrors `[controls]` to `aria-controls` opens while\n * `controls` is unset, so the missing relationship is visible during development.\n *\n * It warns once per entry into that state: reopening without `controls` stays silent, and setting\n * then clearing it warns again. Must be called from an injection context. A production build\n * creates no effect at all.\n */\nexport function warnIfOpenWithoutControls(config: UncontrolledTriggerConfig): void {\n if (!isDevMode()) {\n return;\n }\n let warned = false;\n effect(() => {\n if (config.controls() !== null) {\n warned = false;\n } else if (config.open() && !warned) {\n warned = true;\n config.warn();\n }\n });\n}\n","import { afterNextRender, ElementRef, inject, isDevMode } from '@angular/core';\nimport { fortyWarn } from 'forty-cdk/core';\n\n/** Identifies the surface and its two naming channels in the dev-mode missing-name warning. */\nexport interface UnnamedDialogConfig {\n /** Entry-point name used in the `[forty-cdk/<primitive>]` prefix (e.g. `'dialog'`). */\n readonly primitive: string;\n /** Selector of the piece carrying the dialog role (e.g. `'[forDialog]'`). */\n readonly piece: string;\n /** Selector of the title piece that names the surface (e.g. `'[forDialogTitle]'`). */\n readonly title: string;\n /**\n * Where the consumer binds `ariaLabel` for this surface, quoted into the fix (e.g.\n * `'[forPopover]'`, whose content reads the root's input).\n */\n readonly ariaLabelOn: string;\n}\n\n/**\n * Warns — dev mode only, once per instance — when a surface carrying the dialog role has no\n * accessible name after its first render: neither an `aria-labelledby` nor a non-empty\n * `aria-label` resolved on its host.\n *\n * The attributes are read from the host inside `afterNextRender`, so a title registered during the\n * first render, a bound `ariaLabel` and a static `aria-label` attribute all count. Must be called\n * from an injection context on the surface's own host. A production build registers no render hook\n * at all, and the check is inert on the server.\n */\nexport function warnIfDialogUnnamed(config: UnnamedDialogConfig): void {\n if (!isDevMode()) {\n return;\n }\n const host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n\n afterNextRender(() => {\n const label = host.getAttribute('aria-label')?.trim() ?? '';\n if (label !== '' || host.hasAttribute('aria-labelledby')) {\n return;\n }\n fortyWarn({\n code: 'FORCDK-CORE-011',\n scope: config.primitive,\n message: `${config.piece} has no accessible name.`,\n cause:\n 'Neither `aria-labelledby` nor a non-empty `aria-label` resolved on its host, so assistive ' +\n 'technology announces the surface as a bare \"dialog\". Automated audits tagged for WCAG ' +\n 'A / AA do not report it.',\n fix: `Render a ${config.title} inside it, or bind \\`ariaLabel\\` on ${config.ariaLabelOn}.`,\n });\n });\n}\n","import {\n ApplicationRef,\n type ComponentRef,\n computed,\n DOCUMENT,\n EnvironmentInjector,\n inject,\n Injector,\n PLATFORM_ID,\n type Provider,\n type ProviderToken,\n type Signal,\n signal,\n} from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\n\nimport { composedClosest, IdGenerator, resolveActiveElement } from 'forty-cdk/core';\nimport { InertSiblingsStack } from '../inert-siblings/inert-siblings';\nimport type { OverlayRef } from './overlay-ref';\n\n/**\n * Minimal shape every overlay entry must satisfy so the shared core can index,\n * render, and tear it down. Per-primitive entries (`ForDialogEntry`,\n * `ForDrawerEntry`) extend this with their own directive-input fields and\n * narrow `ref` to their concrete `For<Primitive>Ref`. The core closes an\n * entry's ref and reads its `isClosed` flag (to tell a still-open parent apart\n * from one being swapped out during return-focus origin resolution), so the\n * base requires just those two members — both reason-agnostic, so the base\n * stays independent of each ref's close-reason union.\n *\n * Internal core tier — exported from `forty-cdk/core` for the library's own\n * entry points, with no semver guarantee.\n */\nexport interface OverlayManagerEntry {\n readonly id: string;\n readonly ref: Pick<OverlayRef, 'close' | 'isClosed'>;\n}\n\n/**\n * A rendered overlay's exit-animation surface, registered with the core at\n * attach time so `beginLeave` targets the exact host (and its backdrop) by\n * direct reference instead of re-querying the whole document on every close.\n *\n * `host` is the overlay root — the `[forDialog]` / `[forDrawer]` element the\n * outlet stamps. `backdrop()` reads the currently-registered\n * `[for<Primitive>Backdrop]` element **live at close time** (`null` when none\n * is rendered), preserving the \"read the backdrop when it closes\" semantics a\n * registration-time snapshot would lose.\n *\n * Part of the shared core composition surface; carries no semver guarantees.\n */\nexport interface OverlaySurface {\n readonly host: HTMLElement;\n backdrop(): HTMLElement | null;\n}\n\n/**\n * The reactive surface a manager's outlet component is wired with on first\n * `open()`. Mirrors `ForDialogOutletHost` / `ForDrawerOutletHost`.\n *\n * Internal core tier — exported from `forty-cdk/core` for the library's own\n * entry points, with no semver guarantee.\n */\nexport interface OverlayManagerOutletHost<TEntry extends OverlayManagerEntry> {\n readonly entries: Signal<readonly TEntry[]>;\n closeAllForDestroy(): void;\n /**\n * Registers a rendered entry's exit-animation surface under its id so\n * `beginLeave` can drive the leave classes by direct reference. Called from\n * the per-row surface-registrar directive's `afterNextRender` (so it also\n * runs for an entry whose mount was deferred to a later render). The core\n * drops the surface when the entry is removed.\n */\n registerSurface(id: string, surface: OverlaySurface): void;\n}\n\n/**\n * The minimal surface a manager's outlet component exposes so the core can\n * wire it on first `open()`. Mirrors `ForDialogOutlet` / `ForDrawerOutlet`.\n *\n * Internal core tier — exported from `forty-cdk/core` for the library's own\n * entry points, with no semver guarantee.\n */\nexport interface OverlayManagerOutlet<TEntry extends OverlayManagerEntry> {\n init(host: OverlayManagerOutletHost<TEntry>): void;\n}\n\n/**\n * Per-primitive bindings the shared core needs: how to name ids and the\n * exit-animation host / backdrop attributes, and how to create the outlet\n * component that renders the entries.\n *\n * Internal core tier — exported from `forty-cdk/core` for the library's own\n * entry points, with no semver guarantee.\n */\nexport interface OverlayManagerConfig<TEntry extends OverlayManagerEntry> {\n /**\n * Per-instance id prefix passed to `IdGenerator.next` (e.g.\n * `'for-dialog-instance'`).\n */\n readonly idPrefix: string;\n /**\n * Attribute the overlay root + backdrop reflect their per-instance id on\n * (e.g. `'data-for-dialog-id'`), read during return-focus origin resolution.\n */\n readonly idAttribute: string;\n /**\n * Attribute marking the portaled backdrop element (e.g.\n * `'data-for-dialog-backdrop'`), used to exclude the backdrop during\n * return-focus origin resolution.\n */\n readonly backdropAttribute: string;\n /** Creates the manager-owned outlet component (e.g. `ForDialogOutlet`). */\n createOutlet(\n environmentInjector: EnvironmentInjector,\n ): ComponentRef<OverlayManagerOutlet<TEntry>>;\n}\n\n/**\n * Shared imperative-overlay engine behind `ForDialogManager` and\n * `ForDrawerManager`. Owns the entries signal, the reactive `openCount`, the\n * lazily-created outlet, the public `closeAll()` and the destroy-time close-all\n * sweep, the exit-animation `beginLeave` driver, and the parent-cached\n * per-component `Injector` factory.\n *\n * In the browser the outlet host is appended to `document.body` before its\n * first render, as a `display: contents` modal peer, so opened content is\n * connected (and never under an `inert` ancestor) from its first render on\n * rather than only once its row is portaled.\n * The two managers differ only in their entry shape and directive-input\n * mapping; everything structural lives here once.\n *\n * Internal core tier — no semver guarantee; the public surface is\n * `ForDialogManager` / `ForDrawerManager`.\n */\nexport class OverlayManagerCore<TEntry extends OverlayManagerEntry> {\n readonly #appRef = inject(ApplicationRef);\n readonly #envInjector = inject(EnvironmentInjector);\n readonly #document = inject(DOCUMENT);\n readonly #isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n readonly #inertStack = inject(InertSiblingsStack);\n private readonly idGen = inject(IdGenerator);\n\n readonly #entries = signal<readonly TEntry[]>([]);\n readonly #surfaces = new Map<string, OverlaySurface>();\n readonly #config: OverlayManagerConfig<TEntry>;\n\n /**\n * Reactive count of the overlays this manager has open. A closed overlay stops counting once its\n * exit animation finishes.\n */\n readonly openCount = computed(() => this.#entries().length);\n\n #outletRef: ComponentRef<OverlayManagerOutlet<TEntry>> | null = null;\n #destroying = false;\n #lastReturnFocusOrigin: HTMLElement | null = null;\n\n constructor(config: OverlayManagerConfig<TEntry>) {\n this.#config = config;\n }\n\n /**\n * Resolves the element focus should return to when the overlay this `open()`\n * is about to register later closes — the \"true origin\". Threaded to the\n * directive's `returnFocusTarget` so `injectModalShell` restores focus there\n * instead of to whatever it happened to capture at construction (which breaks\n * on a close→open swap, where the incoming surface is built while focus still\n * lives inside the outgoing, doomed one).\n *\n * Read the currently-focused element **synchronously at `open()` time**,\n * before the render tick mounts the new overlay and swaps the DOM, and\n * classify it:\n *\n * - **Genuine outside element** (focus is on the trigger, not inside any\n * managed overlay host) → that element is the origin.\n * - **Inside a still-live managed overlay** (a stacked open on top of an open\n * overlay) → return focus into that live parent, so the origin is the\n * focused element itself.\n * - **Inside an overlay that is closing / already gone** (a close→open swap:\n * its ref is closed, or it has left the entries list but its DOM host is\n * still mounted for this tick) → inherit the chain's origin, i.e. the\n * origin resolved for the most recent open.\n * - **No usable focus** (`<body>` / `documentElement` / none) → inherit the\n * chain's origin too.\n *\n * The resolved origin is remembered so the next swap in the chain can inherit\n * it. Callers may bypass this and thread a caller-chosen element instead.\n *\n * Both halves of the resolution read the composed tree: the capture\n * descends through open shadow roots, so a trigger inside one is the origin\n * rather than its (usually unfocusable) host, and the \"am I inside a managed\n * overlay?\" walk climbs back out of them. The two go together — resolving the\n * deep element while classifying it with a plain `closest` would report every\n * shadow-nested trigger as an outside element.\n */\n protected resolveReturnFocusTarget(): HTMLElement | null {\n const active = resolveActiveElement(this.#document);\n const captured = active instanceof HTMLElement ? active : null;\n const origin = this.#computeReturnFocusOrigin(captured);\n this.#lastReturnFocusOrigin = origin;\n return origin;\n }\n\n #computeReturnFocusOrigin(captured: HTMLElement | null): HTMLElement | null {\n const { body, documentElement } = this.#document;\n if (captured === null || captured === body || captured === documentElement) {\n return this.#lastReturnFocusOrigin;\n }\n const { idAttribute, backdropAttribute } = this.#config;\n const host = composedClosest(captured, `[${idAttribute}]:not([${backdropAttribute}])`);\n if (host === null) {\n return captured;\n }\n const hostId = host.getAttribute(idAttribute);\n const parentStillOpen = this.#entries().some(\n (entry) => entry.id === hostId && !entry.ref.isClosed(),\n );\n return parentStillOpen ? captured : this.#lastReturnFocusOrigin;\n }\n\n /**\n * Generates the next per-instance id and a paired idempotent\n * `remove` that drops the entry. The caller builds the `ref` with a teardown\n * that drives the exit animation before invoking `remove`.\n */\n protected nextId(): { id: string; remove: () => void } {\n const id = this.idGen.next(this.#config.idPrefix);\n let removed = false;\n const remove = (): void => {\n if (removed) {\n return;\n }\n removed = true;\n this.#surfaces.delete(id);\n this.#entries.update((arr) => arr.filter((e) => e.id !== id));\n };\n return { id, remove };\n }\n\n /**\n * Drives the exit animation on the overlay root and, in lockstep,\n * on the portaled backdrop (both resolved from the `OverlaySurface` stored at\n * attach time — the backdrop's template `animate.leave` never fires under the\n * manager's `ngComponentOutlet` mount), then calls `remove`. Runs `remove`\n * immediately when destroying, when `requestAnimationFrame` is unavailable,\n * when no surface was registered (nothing rendered), or when there is nothing\n * to animate.\n */\n protected beginLeave(\n id: string,\n leaveClass: string | undefined,\n backdropLeaveClass: string | undefined,\n remove: () => void,\n ): void {\n if (this.#destroying || typeof requestAnimationFrame === 'undefined') {\n remove();\n return;\n }\n const surface = this.#surfaces.get(id);\n const targets: HTMLElement[] = [];\n if (surface && leaveClass && typeof surface.host.getAnimations === 'function') {\n surface.host.classList.add(leaveClass);\n targets.push(surface.host);\n }\n if (surface && backdropLeaveClass) {\n const backdrop = surface.backdrop();\n if (backdrop && typeof backdrop.getAnimations === 'function') {\n backdrop.classList.add(backdropLeaveClass);\n targets.push(backdrop);\n }\n }\n if (targets.length === 0) {\n remove();\n return;\n }\n requestAnimationFrame(() => {\n const finite = targets\n .flatMap((el) => el.getAnimations({ subtree: true }))\n .filter(isFiniteAnimation);\n if (finite.length === 0) {\n remove();\n return;\n }\n Promise.all(finite.map((animation) => animation.finished.catch(() => undefined))).then(() =>\n remove(),\n );\n });\n }\n\n /**\n * Builds a parent-cached per-component `Injector`. The returned\n * factory recreates the injector only when its parent changes, so re-renders\n * with the same enclosing `[forDialog]` / `[forDrawer]` host reuse it.\n *\n * With no `scope`, the opened component's injector is parented on the\n * declarative host's element injector (`parent`), matching the declarative\n * path. When the caller passed an `injector` on the `open()` config, `scope`\n * re-parents the opened component on that caller scope instead — so DI inside\n * the opened component resolves the scope's providers (a lazy route, a\n * component `providers`). The host's `contextToken` is copied across as a\n * value provider so the primitive's own pieces still resolve\n * `FOR_<PRIMITIVE>_CONTEXT` exactly as on the declarative path.\n */\n protected createInjectorFactory(\n providers: readonly Provider[],\n scope?: { readonly injector: Injector; readonly contextToken: ProviderToken<unknown> },\n ): (parent: Injector) => Injector {\n let cachedInjector: Injector | null = null;\n let cachedParent: Injector | null = null;\n return (parent: Injector): Injector => {\n if (cachedInjector && cachedParent === parent) {\n return cachedInjector;\n }\n cachedParent = parent;\n cachedInjector = scope\n ? Injector.create({\n parent: scope.injector,\n providers: [\n { provide: scope.contextToken, useValue: parent.get(scope.contextToken) },\n ...providers,\n ],\n })\n : Injector.create({ parent, providers: [...providers] });\n return cachedInjector;\n };\n }\n\n /**\n * Registers a fully-built entry, ensures the outlet exists, and requests a\n * render so the `@for` mounts it.\n *\n * The render is attempted synchronously via `ApplicationRef.tick()` so the\n * overlay DOM is available the moment `open()` returns — the common case.\n * When `open()` is itself called from within change detection (an `effect`,\n * `ngOnInit`, or an `afterNextRender` callback) a tick is already in flight\n * and a nested `tick()` is illegal (NG0101); the synchronous attempt is then\n * skipped and the `#entries` signal write drives the mount on the next\n * scheduled render instead. The entry is registered immediately either way,\n * so the returned overlay ref is usable straight away.\n */\n protected register(entry: TEntry): void {\n this.#ensureOutlet();\n this.#entries.update((arr) => [...arr, entry]);\n this.#renderNow();\n }\n\n #renderNow(): void {\n try {\n this.#appRef.tick();\n } catch (error: unknown) {\n if (isRecursiveTickError(error)) {\n return;\n }\n throw error;\n }\n }\n\n /**\n * Closes every overlay this manager has open, topmost first, with reason `'programmatic'` and\n * `result` as each close result. Each ref's `closed` resolves as it does for `ref.close()`, exit\n * animations still play, and focus ends where the bottom overlay's return focus sends it. A no-op\n * when nothing is open.\n */\n closeAll(result?: unknown): void {\n for (const entry of [...this.#entries()].reverse()) {\n entry.ref.close(result);\n }\n }\n\n #closeAllForDestroy(): void {\n this.#destroying = true;\n for (const entry of this.#entries()) {\n entry.ref.close();\n }\n }\n\n #ensureOutlet(): void {\n if (this.#outletRef) {\n return;\n }\n const outletRef = this.#config.createOutlet(this.#envInjector);\n this.#appRef.attachView(outletRef.hostView);\n if (this.#isBrowser) {\n const outletHost = outletRef.location.nativeElement as HTMLElement;\n outletHost.style.display = 'contents';\n const releasePeer = this.#inertStack.registerPeer(outletHost, 'always');\n this.#document.body.appendChild(outletHost);\n outletRef.onDestroy(() => {\n releasePeer();\n outletHost.remove();\n });\n }\n outletRef.instance.init({\n entries: this.#entries.asReadonly(),\n closeAllForDestroy: () => this.#closeAllForDestroy(),\n registerSurface: (id, surface) => {\n this.#surfaces.set(id, surface);\n },\n });\n this.#outletRef = outletRef;\n }\n}\n\n/**\n * True when `error` is Angular's recursive-`ApplicationRef.tick()` runtime\n * error (`NG0101`), thrown when a change-detection tick is already in flight.\n * Matched by the stable numeric `RuntimeError.code` with a message-prefix\n * fallback so it survives production builds where the message text is stripped.\n */\nfunction isRecursiveTickError(error: unknown): boolean {\n if (error === null || typeof error !== 'object') {\n return false;\n }\n const { code, message } = error as { code?: unknown; message?: unknown };\n return code === 101 || (typeof message === 'string' && message.startsWith('NG0101'));\n}\n\n/**\n * True when `animation` will actually finish — i.e. it does not run forever.\n * An infinite exit animation (a shimmer / pulse with `animation-iteration-count:\n * infinite`) reports `Infinity` iterations, and its `finished` promise never\n * resolves; awaiting it would strand `beginLeave` and leak the overlay entry.\n * Filtering these out before awaiting `finished` lets teardown proceed once the\n * finite animations settle (or immediately, when none remain). Guards for a\n * possibly-null effect and for environments lacking `getComputedTiming`.\n */\nfunction isFiniteAnimation(animation: Animation): boolean {\n const effect = animation.effect;\n if (!effect || typeof effect.getComputedTiming !== 'function') {\n return true;\n }\n return effect.getComputedTiming().iterations !== Infinity;\n}\n","import { signal } from '@angular/core';\n\n/**\n * The awaitable close payload resolved by `OverlayRef.closed` — the reason the\n * overlay closed plus the optional close result. Homogeneous with\n * `ForToastRef.closed` so all three programmatic overlay handles expose the\n * same `{ reason, result }` shape.\n *\n * Internal core tier — exported from `forty-cdk/core` for the library's own\n * entry points, with no semver guarantee.\n */\nexport interface OverlayCloseEvent<R, Reason> {\n /** Why the overlay closed (e.g. `'escape'`, `'closeButton'`, `'programmatic'`). */\n readonly reason: Reason;\n /** The close result passed to `close(result)`, or `undefined`. */\n readonly result: R | undefined;\n}\n\n/**\n * Shared handle returned by an imperative overlay manager's `open()`.\n * `ForDialogRef` / `ForDrawerRef` extend this verbatim to keep their public\n * class identity (and DI token) while the close engine lives here once.\n *\n * Both reactive (`isClosed`, `result`) and awaitable (`closed`) APIs are\n * exposed — pick what fits the call site. `R` is the close-result type and\n * `Reason` the close-reason union (`ForDialogCloseReason` /\n * `ForDrawerCloseReason`).\n *\n * Internal core tier — no semver guarantee; the public surface is\n * `ForDialogRef` / `ForDrawerRef`.\n */\nexport class OverlayRef<R = unknown, Reason = string> {\n readonly #result = signal<R | undefined>(undefined);\n readonly #closed = signal(false);\n\n /** Reactive: `true` once `close()` has been called. */\n readonly isClosed = this.#closed.asReadonly();\n\n /** Reactive: the close result. `undefined` while open. */\n readonly result = this.#result.asReadonly();\n\n /**\n * Awaitable: resolves with `{ reason, result }` the first time `close()`\n * runs. The reason distinguishes an explicit `close(result)` (the manager's\n * default reason, `'programmatic'`) from a dismiss channel (Escape, backdrop,\n * outside-pointer, close button), which a bare result cannot.\n */\n readonly closed: Promise<OverlayCloseEvent<R, Reason>>;\n\n #resolveClosed!: (event: OverlayCloseEvent<R, Reason>) => void;\n readonly #teardown: () => void;\n readonly #defaultReason: Reason;\n\n /** Internal composition surface (no semver guarantees). */\n constructor(teardown: () => void, defaultReason: Reason) {\n this.#teardown = teardown;\n this.#defaultReason = defaultReason;\n this.closed = new Promise((resolve) => {\n this.#resolveClosed = resolve;\n });\n }\n\n /**\n * Close the overlay, optionally returning a result. Idempotent — calling\n * twice is a no-op. `reason` defaults to the manager's default (`'programmatic'`\n * for a direct imperative close); the dismiss channels pass their own reason.\n */\n close(result?: R, reason: Reason = this.#defaultReason): void {\n if (this.#closed()) {\n return;\n }\n this.#result.set(result);\n this.#closed.set(true);\n this.#resolveClosed({ reason, result });\n this.#teardown();\n }\n}\n","import { DestroyRef, DOCUMENT, inject, Injectable, PLATFORM_ID } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\n\nimport { composedContains } from 'forty-cdk/core';\n\n/** Window (ms) hover opens stay suppressed after the last scroll that concerns an overlay. */\nexport const DEFAULT_SCROLL_DISMISS_SUPPRESSION_MS = 200;\n\n/**\n * Which scrolls concern one registered overlay. Both accessors are read when a\n * scroll is dispatched or a suppression is queried, so a trigger or surface\n * registered after the overlay is picked up.\n */\nexport interface ScrollDismissScope {\n /**\n * The element the overlay is anchored to. A scroll of an element that does\n * not contain it moves nothing the overlay is positioned against, so it\n * neither dismisses nor suppresses. `null`, or an anchor no longer in the\n * document, leaves every scroll in scope.\n */\n readonly anchor: () => Element | null;\n /**\n * The overlay's own surface. A scroll inside it (an `overflow: auto` region\n * in the content) neither dismisses nor suppresses.\n */\n readonly surface: () => Element | null;\n}\n\n/** Inputs for {@link ScrollDismissDispatcher.register}. */\nexport interface ScrollDismissOptions {\n /**\n * Closes the overlay and cancels its pending timers. Called synchronously on\n * every scroll in scope while {@link active} holds.\n */\n readonly dismiss: () => void;\n /** Narrows which scrolls dismiss and suppress. Omitted, every scroll does. */\n readonly scope?: ScrollDismissScope;\n /**\n * Whether a scroll has anything to dismiss: the overlay is open, or an open /\n * close timer is pending. Read before the scope, so an idle overlay costs one\n * call per scroll. Omitted, the registration is always active.\n */\n readonly active?: () => boolean;\n}\n\n/** Handle returned by {@link ScrollDismissDispatcher.register}. */\nexport interface ScrollDismissRegistration {\n /**\n * Whether a scroll in this registration's scope happened within the\n * suppression window. Hover opens bail while this returns `true`, so content\n * sliding under a stationary pointer cannot flicker the overlay open.\n * Always `false` on the server and after {@link unregister}.\n */\n isSuppressed(): boolean;\n /** Removes this registration. Idempotent; call it from a `DestroyRef` hook. */\n unregister(): void;\n}\n\ninterface Registration {\n readonly dismiss: () => void;\n readonly scope: ScrollDismissScope | undefined;\n readonly active: () => boolean;\n}\n\nconst ALWAYS_ACTIVE = (): boolean => true;\n\nconst SERVER_REGISTRATION: ScrollDismissRegistration = {\n isSuppressed: () => false,\n unregister: () => {},\n};\n\n/**\n * Application-scoped owner of the single capture-phase document `scroll`\n * listener shared by every hover-driven anchored overlay (Tooltip, HoverCard).\n *\n * When an ancestor scroll container moves its content under a stationary\n * cursor, the browser does not reliably dispatch `pointerleave` /\n * `pointerenter` on the triggers sliding past the pointer. On each scroll the\n * dispatcher therefore dismisses every active registration whose scope the\n * scroll concerns, and records the scrolled element with a timestamp. A\n * registration is suppressed while a recorded scroll within\n * {@link DEFAULT_SCROLL_DISMISS_SUPPRESSION_MS} concerns its own scope, so a\n * scroll elsewhere on the page, or inside the overlay's own surface, never\n * blocks its hover opens.\n *\n * One listener is installed with the first registration and removed with the\n * last. Per scroll the work is one map write plus one `active()` call per\n * registration; the containment walk runs only for active registrations, and\n * for idle ones only when their own hover asks whether it is suppressed.\n *\n * `providedIn: 'root'`, so it is one instance per application injector and is\n * garbage-collected with it. Internal core tier, exported for the tooltip /\n * hover-card entry points, never for consumers.\n */\n@Injectable({ providedIn: 'root' })\nexport class ScrollDismissDispatcher {\n readonly #doc = inject(DOCUMENT);\n readonly #isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n readonly #registrations = new Set<Registration>();\n readonly #recentScrolls = new Map<EventTarget | null, number>();\n #listener: AbortController | null = null;\n\n constructor() {\n inject(DestroyRef).onDestroy(() => {\n this.#listener?.abort();\n this.#listener = null;\n this.#registrations.clear();\n this.#recentScrolls.clear();\n });\n }\n\n /**\n * Registers an overlay for scroll dismissal and per-overlay suppression. Each\n * call is an independent registration, so registering the same callback\n * twice yields two handles that must both be unregistered. A no-op handle on\n * the server.\n */\n register(options: ScrollDismissOptions): ScrollDismissRegistration {\n if (!this.#isBrowser) {\n return SERVER_REGISTRATION;\n }\n const registration: Registration = {\n dismiss: options.dismiss,\n scope: options.scope,\n active: options.active ?? ALWAYS_ACTIVE,\n };\n this.#registrations.add(registration);\n this.#listen();\n return {\n isSuppressed: () =>\n this.#registrations.has(registration) && this.#suppresses(registration.scope),\n unregister: () => this.#unregister(registration),\n };\n }\n\n #listen(): void {\n if (this.#listener) {\n return;\n }\n this.#listener = new AbortController();\n this.#doc.addEventListener('scroll', (event) => this.#onScroll(event), {\n capture: true,\n passive: true,\n signal: this.#listener.signal,\n });\n }\n\n #unregister(registration: Registration): void {\n if (!this.#registrations.delete(registration) || this.#registrations.size > 0) {\n return;\n }\n this.#listener?.abort();\n this.#listener = null;\n this.#recentScrolls.clear();\n }\n\n #onScroll(event: Event): void {\n const now = Date.now();\n this.#recentScrolls.delete(event.target);\n this.#recentScrolls.set(event.target, now + DEFAULT_SCROLL_DISMISS_SUPPRESSION_MS);\n this.#pruneExpired(now);\n for (const registration of this.#registrations) {\n if (\n registration.active() &&\n (!registration.scope || scrollConcerns(event.target, registration.scope))\n ) {\n registration.dismiss();\n }\n }\n }\n\n #pruneExpired(now: number): void {\n for (const [target, until] of this.#recentScrolls) {\n if (until > now) {\n return;\n }\n this.#recentScrolls.delete(target);\n }\n }\n\n #suppresses(scope: ScrollDismissScope | undefined): boolean {\n const now = Date.now();\n this.#pruneExpired(now);\n for (const target of this.#recentScrolls.keys()) {\n if (!scope || scrollConcerns(target, scope)) {\n return true;\n }\n }\n return false;\n }\n}\n\nfunction scrollConcerns(target: EventTarget | null, scope: ScrollDismissScope): boolean {\n if (!(target instanceof Node)) {\n return true;\n }\n const surface = scope.surface();\n if (surface && composedContains(surface, target)) {\n return false;\n }\n const anchor = scope.anchor();\n if (!anchor || !anchor.isConnected) {\n return true;\n }\n return composedContains(target, anchor);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"forty-cdk-core-overlay.mjs","names":[],"sources":["../../../projects/forty-cdk/core-overlay/src/body-scroll-lock/body-scroll-lock.ts","../../../projects/forty-cdk/core-overlay/src/dismissible-layer/dismissible-layer.ts","../../../projects/forty-cdk/core-overlay/src/drawer-stack/drawer-stack.ts","../../../projects/forty-cdk/core-overlay/src/floating/anchored-positioning-inputs.ts","../../../projects/forty-cdk/core-overlay/src/floating/anchored-form-value-control-base.ts","../../../projects/forty-cdk/core-overlay/src/floating/anchored-overlay-positioning-base.ts","../../../projects/forty-cdk/core-overlay/src/hover-intent/debounced-action.ts","../../../projects/forty-cdk/core-overlay/src/hover-intent/hover-intent.ts","../../../projects/forty-cdk/core-overlay/src/pointer-grace/pointer-grace.ts","../../../projects/forty-cdk/core-overlay/src/hover-intent/hover-surface-state.ts","../../../projects/forty-cdk/core-overlay/src/inert-siblings/inert-siblings.ts","../../../projects/forty-cdk/core-overlay/src/overlay-controller/element-registry.ts","../../../projects/forty-cdk/core-overlay/src/overlay-controller/close-reason-state.ts","../../../projects/forty-cdk/core-overlay/src/overlay-controller/initial-focus-state.ts","../../../projects/forty-cdk/core-overlay/src/overlay-controller/overlay-controller.ts","../../../projects/forty-cdk/core-overlay/src/listbox-overlay/listbox-overlay-controller.ts","../../../projects/forty-cdk/core-overlay/src/menu-overlay/menu-context.ts","../../../projects/forty-cdk/core-overlay/src/menu-overlay/menu-item-list.ts","../../../projects/forty-cdk/core-overlay/src/menu-overlay/menu-opener-registry.ts","../../../projects/forty-cdk/core-overlay/src/menu-overlay/menu-overlay.ts","../../../projects/forty-cdk/core-overlay/src/menu-overlay/menu-overlay-host.ts","../../../projects/forty-cdk/core-overlay/src/modal-shell/modal-backdrop.ts","../../../projects/forty-cdk/core-overlay/src/overlay-controller/outside-veto.ts","../../../projects/forty-cdk/core-overlay/src/modal-shell/modal-activation-order.ts","../../../projects/forty-cdk/core-overlay/src/modal-shell/modal-shell.ts","../../../projects/forty-cdk/core-overlay/src/modal-shell/modal-trigger.ts","../../../projects/forty-cdk/core-overlay/src/modal-shell/modal-surface-base.ts","../../../projects/forty-cdk/core-overlay/src/overlay-controller/mounted-while-closed.ts","../../../projects/forty-cdk/core-overlay/src/floating/floating-custom-properties.ts","../../../projects/forty-cdk/core-overlay/src/floating/run-positioning.ts","../../../projects/forty-cdk/core-overlay/src/floating/floating.ts","../../../projects/forty-cdk/core-overlay/src/floating/item-aligned.ts","../../../projects/forty-cdk/core-overlay/src/overlay-controller/overlay-shell.ts","../../../projects/forty-cdk/core-overlay/src/overlay-controller/uncontrolled-trigger.ts","../../../projects/forty-cdk/core-overlay/src/overlay-controller/unnamed-dialog.ts","../../../projects/forty-cdk/core-overlay/src/overlay-manager/overlay-manager.ts","../../../projects/forty-cdk/core-overlay/src/overlay-manager/overlay-ref.ts","../../../projects/forty-cdk/core-overlay/src/scroll-dismiss/scroll-dismiss-dispatcher.ts"],"sourcesContent":["import { DOCUMENT, Injectable, PLATFORM_ID, inject } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\n\n/**\n * Refcounted scroll lock, keyed per target element (default `<body>`).\n * Multiple modal surfaces acquire and release locks independently — only the\n * first acquire for a given target mutates that target, only the last release\n * un-mutates it. Different targets (body vs a container element) are fully\n * independent: locking a container does not affect body scroll and vice versa.\n *\n * **Semantic: clear, do not restore.** On the first lock for a target the\n * service writes `overflow: hidden` and an optional scrollbar-compensating\n * `padding-right` inline on that target. On the final unlock it _clears_ the\n * inline styles it set (`target.style.overflow = ''`, and\n * `target.style.paddingRight = ''` only when this lock actually wrote it) and\n * lets the CSS cascade take over again. It does NOT snapshot the values at\n * lock time and rewrite them at unlock time.\n *\n * On overlay-scrollbar / mobile platforms there is no classic scrollbar\n * (`innerWidth - clientWidth === 0` for the body path), so the lock never\n * writes `padding-right`. In that case the final unlock leaves\n * `target.style.paddingRight` untouched, so a consumer's unrelated inline\n * `padding-right` survives. The clear-don't-restore contract only applies to\n * values the lock owns.\n *\n * Why: any code (route transition, theme toggle, the consumer themselves)\n * that mutates `target.style.overflow` between `lock()` and the final\n * `unlock()` would otherwise be silently clobbered when we restored the\n * stale snapshot. Clearing on unlock means the lock owns the inline style\n * only while it exists; intervening mutations win, and the resting state\n * is whatever stylesheet rules apply.\n *\n * The scrollbar-width compensation prevents content jumping when overflow\n * goes from `auto` (scrollbar shown) to `hidden` (scrollbar hidden).\n * For the body path the width is `window.innerWidth - documentElement.clientWidth`;\n * for an element path it is `target.offsetWidth - target.clientWidth`.\n *\n * SSR: the service is `providedIn: 'root'` so its counter map is scoped to a\n * single Angular bootstrap (one per SSR request). Server-side calls are\n * no-ops.\n */\n@Injectable({ providedIn: 'root' })\nexport class BodyScrollLock {\n readonly #document = inject(DOCUMENT);\n readonly #window = this.#document.defaultView;\n readonly #isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n readonly #targets = new Map<HTMLElement, { count: number; wrotePaddingRight: boolean }>();\n\n /**\n * Acquire the scroll lock on `target` (default `document.body`). The first\n * call for a given target sets `overflow: hidden` and compensates for the\n * scrollbar width; subsequent calls increment the refcount only.\n */\n lock(target: HTMLElement = this.#document.body): void {\n if (!this.#isBrowser) {\n return;\n }\n let record = this.#targets.get(target);\n if (!record) {\n record = { count: 0, wrotePaddingRight: false };\n this.#targets.set(target, record);\n }\n if (record.count === 0) {\n target.style.overflow = 'hidden';\n const isBody = target === this.#document.body;\n const win = this.#window;\n let scrollbarWidth: number;\n if (isBody) {\n const docEl = this.#document.documentElement;\n scrollbarWidth = win ? win.innerWidth - docEl.clientWidth : 0;\n if (scrollbarWidth > 0 && win && !this.#gutterIsStable(win, [docEl, target])) {\n const computed = win.getComputedStyle(target).paddingRight;\n const currentPx = parseFloat(computed) || 0;\n target.style.paddingRight = `${currentPx + scrollbarWidth}px`;\n record.wrotePaddingRight = true;\n }\n } else {\n scrollbarWidth = target.offsetWidth - target.clientWidth;\n if (scrollbarWidth > 0 && win && !this.#gutterIsStable(win, [target])) {\n const computed = win.getComputedStyle(target).paddingRight;\n const currentPx = parseFloat(computed) || 0;\n target.style.paddingRight = `${currentPx + scrollbarWidth}px`;\n record.wrotePaddingRight = true;\n }\n }\n }\n record.count++;\n }\n\n /**\n * Release the scroll lock on `target` (default `document.body`). The last\n * release clears the inline `overflow` (and `padding-right` if written) and\n * lets the CSS cascade take over.\n */\n unlock(target: HTMLElement = this.#document.body): void {\n if (!this.#isBrowser) {\n return;\n }\n const record = this.#targets.get(target);\n if (!record || record.count === 0) {\n return;\n }\n record.count--;\n if (record.count === 0) {\n target.style.overflow = '';\n if (record.wrotePaddingRight) {\n target.style.paddingRight = '';\n record.wrotePaddingRight = false;\n }\n this.#targets.delete(target);\n }\n }\n\n /**\n * True when any of the given elements reserves the scrollbar gutter via\n * `scrollbar-gutter: stable` (or `stable both-edges`). The gutter then\n * survives the `overflow: hidden` toggle, so no padding compensation is\n * needed.\n */\n #gutterIsStable(win: Window, els: readonly HTMLElement[]): boolean {\n for (const el of els) {\n const gutter = win.getComputedStyle(el).getPropertyValue('scrollbar-gutter');\n if (gutter.trim().split(/\\s+/).includes('stable')) {\n return true;\n }\n }\n return false;\n }\n}\n","import { DOCUMENT, DestroyRef, ElementRef, Injectable, PLATFORM_ID, inject } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\n\nimport { composedContains, isImeComposing, resolveEventTarget } from 'forty-cdk/core';\n\n/**\n * The outside-interaction channels a {@link DismissibleLayer} can own. A layer\n * declares the channels it wants routed to it at {@link DismissibleLayer.activate};\n * {@link DismissibleLayerStack} dispatches an outside `pointerdown` / `focusin`\n * to the topmost layer that declared the matching channel. Escape is not a\n * channel — it is dispatched to the topmost active layer, and to a layer below\n * only while every layer above it declines the key (see\n * {@link DismissibleLayerActivateOptions.onEscapeKeyDown}).\n */\nexport type DismissibleLayerChannel = 'pointer' | 'focus';\n\n/**\n * Declared nesting position of a layer inside a chain of layers that are\n * structurally nested (a menubar menu and its submenus, a submenu and its own\n * submenu). {@link DismissibleLayerStack} orders such a chain by `depth` rather\n * than by activation order, so a deeper level is always dispatched to before\n * its ancestors even when both levels mount in the same render pass and the\n * `afterNextRender` callbacks fire child-before-parent.\n *\n * A layer that declares no nesting keeps the plain LIFO behaviour: it is pushed\n * on top of everything, and never reorders relative to a chain it does not\n * belong to (a Dialog opened from inside a submenu still lands topmost).\n */\nexport interface DismissibleLayerNesting {\n /**\n * Identity of the chain this layer belongs to — typically the coordination\n * context of the outermost level. Only layers sharing a chain are ordered\n * against each other by `depth`.\n */\n readonly chain: object;\n /** `0` for the outermost level, `+1` per nesting level below it. */\n readonly depth: number;\n}\n\n/**\n * Options passed to `DismissibleLayer.activate`. Each handler receives the\n * native event; the consumer owns the close decision inside its own handler\n * (there is no separate default-dismiss callback).\n */\nexport interface DismissibleLayerActivateOptions {\n /**\n * The outside-interaction channels this layer owns. The stack routes an\n * outside `pointerdown` to the topmost layer declaring `'pointer'` and an\n * outside `focusin` to the topmost layer declaring `'focus'`, so an\n * Escape-only surface (Tooltip, HoverCard) declares `[]` and stays\n * transparent to the real dismissible layers beneath it. Escape is dispatched\n * from the topmost layer down regardless of this declaration.\n */\n channels: readonly DismissibleLayerChannel[];\n\n /**\n * Declared position of this layer inside a chain of structurally nested\n * layers. When present, {@link DismissibleLayerStack} inserts the layer by\n * depth within its chain instead of pushing it on top, so the stack order\n * reflects the nesting rather than the order the levels happened to activate\n * in. Omit for a standalone overlay.\n */\n nesting?: DismissibleLayerNesting;\n\n /**\n * Fired when the user presses `Escape` while this is the topmost layer, or while every layer\n * stacked above it declined the key. Return `false` to decline it too: the key is then offered\n * to the layer below, unless this layer is\n * {@link DismissibleLayerActivateOptions.modal | modal}. Any other return value keeps it.\n */\n onEscapeKeyDown?: (event: KeyboardEvent) => unknown;\n\n /**\n * Fired when the user pointer-downs outside this layer's host. Return `true` when the handler\n * closed the layer: only then is the press offered to the pointer layer below, and only when that\n * layer opted in through {@link DismissibleLayerActivateOptions.cascadeOutsidePress}.\n */\n onPointerDownOutside?: (event: PointerEvent) => unknown;\n\n /**\n * Fired when the user pointer-downs **inside** this layer's host or one of its `exemptElements`\n * — the mirror of `onPointerDownOutside`.\n *\n * It answers \"was that press mine?\" with the same containment rule the dismissal path uses,\n * instead of the owner re-deriving the surface set from its own host listeners.\n */\n onPointerDownInside?: (event: PointerEvent) => void;\n\n /** Fired when focus moves outside this layer's host. */\n onFocusOutside?: (event: FocusEvent) => void;\n\n /**\n * Fired in addition to `onPointerDownOutside` / `onFocusOutside` for\n * consumers that don't care which one occurred.\n */\n onInteractOutside?: (event: PointerEvent | FocusEvent) => void;\n\n /**\n * Extra elements whose subtrees count as \"inside\" for outside-pointer /\n * outside-focus checks (e.g. a portaled popover content owned by this\n * layer). Recomputed on every event so that DOM mutations are picked up,\n * and handed the node being tested so an owner can leave part of an exempt\n * subtree outside.\n */\n exemptElements?: (target: Node) => readonly Element[];\n\n /**\n * Whether this layer also closes on an outside press that the pointer layer directly above it\n * closed on. Read on every press. Without it, an outside press reaches only the topmost pointer\n * layer.\n *\n * The cascade walks down one pointer layer at a time and stops at the first layer that contains\n * the press, keeps itself open, did not opt in, or is\n * {@link DismissibleLayerActivateOptions.modal | modal}.\n */\n cascadeOutsidePress?: () => boolean;\n\n /**\n * Whether this layer is a modal surface. A modal layer ends an outside-press cascade: a press it\n * receives is never offered to the layers beneath it.\n */\n modal?: boolean;\n}\n\nconst EMPTY_ACTIVATE_OPTIONS: DismissibleLayerActivateOptions = { channels: [] };\n\n/**\n * Application-scoped registry that owns the document listeners used by\n * dismissible layers. Created once per Angular bootstrap (one per SSR\n * request), tied to the root injector lifetime.\n *\n * Listeners are installed on the first layer activation and removed with the last, and a\n * `DestroyRef` hook clears both the listeners and the stack, so no bootstrap leaves listeners\n * behind. Installation is a no-op off-browser.\n *\n * **Stack order** is activation order for standalone layers, but a layer declaring a\n * {@link DismissibleLayerNesting} is inserted by nesting depth within its chain. Activation order\n * is a render-timing artifact — a menu and its submenu mounted in one pass run their\n * `afterNextRender` callbacks child-before-parent — so ordering by timing would place an ancestor\n * above its own descendant, making the descendant's first focus read as `focusOutside` and collapse\n * the chain.\n *\n * **Listener phases are asymmetric.** `pointerdown` and `focusin` register on the\n * capture phase, so an outside interaction is detected even when overlay content stops\n * propagation. `keydown` registers on the bubble phase instead, because the per-overlay Escape\n * handlers call `stopPropagation()` after closing — which is what keeps one Escape from closing an\n * ancestor layer too. The accepted trade-off is that overlay content with its own bubble-phase\n * `keydown` handler calling `stopPropagation()` can swallow Escape before it arrives.\n *\n * An Escape that belongs to an IME composition (see `isImeComposing`) is never dispatched: it\n * cancels the conversion, not the topmost layer.\n */\n@Injectable({ providedIn: 'root' })\nexport class DismissibleLayerStack {\n readonly #document = inject(DOCUMENT);\n readonly #isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n readonly #stack: DismissibleLayer[] = [];\n #suppressDepth = 0;\n #listening = false;\n\n readonly #onKeyDown = (event: KeyboardEvent): void => {\n if (event.key !== 'Escape' || isImeComposing(event)) {\n return;\n }\n if (event.defaultPrevented) {\n return;\n }\n if (this.#suppressDepth > 0) {\n return;\n }\n for (const layer of [...this.#stack].reverse()) {\n if (layer.isActive && (layer.handleEscape(event) || layer.isModal)) {\n return;\n }\n }\n };\n readonly #onPointerDown = (event: Event): void => {\n if (this.#suppressDepth > 0) {\n return;\n }\n const [topmost, ...below] = this.#layersForChannel('pointer');\n if (!topmost?.handlePointerDown(event as PointerEvent) || topmost.isModal) {\n return;\n }\n for (const layer of below) {\n if (!layer.isActive || !layer.cascadesOutsidePress()) {\n return;\n }\n if (!layer.handlePointerDown(event as PointerEvent) || layer.isModal) {\n return;\n }\n }\n };\n readonly #onFocusIn = (event: Event): void => {\n if (this.#suppressDepth > 0) {\n return;\n }\n this.#topmostForChannel('focus')?.handleFocusIn(event as FocusEvent);\n };\n\n constructor() {\n inject(DestroyRef).onDestroy(() => {\n this.#removeListeners();\n this.#stack.length = 0;\n this.#suppressDepth = 0;\n });\n }\n\n /** @internal */\n push(layer: DismissibleLayer): void {\n this.#stack.splice(this.#insertionIndex(layer), 0, layer);\n if (this.#stack.length === 1) {\n this.#installListeners();\n }\n }\n\n /** @internal */\n remove(layer: DismissibleLayer): void {\n const idx = this.#stack.indexOf(layer);\n if (idx >= 0) {\n this.#stack.splice(idx, 1);\n if (this.#stack.length === 0) {\n this.#removeListeners();\n }\n }\n }\n\n /**\n * @internal Whether `target` is inside `layer` or inside any layer stacked\n * above it. A layer stacked above the chosen channel handler (e.g. an\n * interactive Escape-only HoverCard over a Popover) counts as \"inside\", so an\n * interaction within it never leaks an \"outside\" dismissal to the layer below.\n */\n containsFromLayer(layer: DismissibleLayer, target: Node): boolean {\n const idx = this.#stack.indexOf(layer);\n if (idx < 0) {\n return layer.contains(target);\n }\n for (let i = idx; i < this.#stack.length; i++) {\n const above = this.#stack[i];\n if (above && above.contains(target)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * @internal Whether `layer` is the topmost layer declaring `channel`, i.e. the\n * one an outside interaction on that channel is dispatched to.\n */\n isTopmostForChannel(layer: DismissibleLayer, channel: DismissibleLayerChannel): boolean {\n return this.#topmostForChannel(channel) === layer;\n }\n\n /**\n * Runs `fn` with the dispatcher suppressed. While suppressed, neither\n * Escape, pointer-down outside, nor focus-outside events are forwarded\n * to the topmost layer. Refcounted so nested teardowns nest correctly.\n */\n suppress<T>(fn: () => T): T {\n this.#suppressDepth++;\n try {\n return fn();\n } finally {\n this.#suppressDepth--;\n }\n }\n\n #installListeners(): void {\n if (!this.#isBrowser || this.#listening) {\n return;\n }\n this.#listening = true;\n this.#document.addEventListener('keydown', this.#onKeyDown);\n this.#document.addEventListener('pointerdown', this.#onPointerDown, true);\n this.#document.addEventListener('focusin', this.#onFocusIn, true);\n }\n\n #removeListeners(): void {\n if (!this.#listening) {\n return;\n }\n this.#listening = false;\n this.#document.removeEventListener('keydown', this.#onKeyDown);\n this.#document.removeEventListener('pointerdown', this.#onPointerDown, true);\n this.#document.removeEventListener('focusin', this.#onFocusIn, true);\n }\n\n /**\n * Where a newly activated layer belongs. Plain LIFO (the top of the stack)\n * unless the layer declared a {@link DismissibleLayerNesting}: then it slides\n * down past the trailing run of layers from the same chain that sit deeper\n * than it, so an ancestor activating after its own descendant still lands\n * below it. The scan stops at the first layer that is not a deeper\n * level of the same chain, so an unrelated overlay (a Dialog opened from\n * inside a submenu) is never jumped over.\n */\n #insertionIndex(layer: DismissibleLayer): number {\n const nesting = layer.nesting;\n let idx = this.#stack.length;\n if (!nesting) {\n return idx;\n }\n while (idx > 0) {\n const below = this.#stack[idx - 1]?.nesting;\n if (!below || below.chain !== nesting.chain || below.depth <= nesting.depth) {\n break;\n }\n idx--;\n }\n return idx;\n }\n\n #layersForChannel(channel: DismissibleLayerChannel): DismissibleLayer[] {\n const layers: DismissibleLayer[] = [];\n for (let i = this.#stack.length - 1; i >= 0; i--) {\n const layer = this.#stack[i];\n if (layer && layer.ownsChannel(channel)) {\n layers.push(layer);\n }\n }\n return layers;\n }\n\n #topmostForChannel(channel: DismissibleLayerChannel): DismissibleLayer | undefined {\n for (let i = this.#stack.length - 1; i >= 0; i--) {\n const layer = this.#stack[i];\n if (layer && layer.ownsChannel(channel)) {\n return layer;\n }\n }\n return undefined;\n }\n}\n\n/**\n * Coordinates the standard \"dismissible surface\" interactions used by modal\n * dialogs, popovers, dropdown menus, drawers, and any other transient\n * overlay: Escape, pointer-down outside, focus-outside.\n *\n * Dispatch is per channel. Escape goes to the topmost active layer, and reaches\n * a layer below only when every layer above it declined the key, so one Escape\n * still closes at most one layer and never crosses a modal layer.\n * Pointer-down-outside and focus-outside instead go to the topmost\n * layer that declared the matching channel: a layer that owns only Escape (e.g.\n * a Tooltip, declaring `channels: []`) is transparent to outside-pointer /\n * focus for the real dismissible layers beneath it, so a tooltip visible over\n * an open menu never shadows the menu's outside-click dismissal. Nested\n * real layers (a popover inside a dialog) still resolve to a single topmost\n * handler per channel, so single-dismiss semantics hold — unless a lower layer\n * opts into `cascadeOutsidePress`, in which case an outside press the layer\n * above it closed on reaches it too.\n *\n * Containment is stack-aware: an interaction inside a layer stacked *above* the\n * chosen handler counts as \"inside\", so an interactive Escape-only surface (a\n * HoverCard over a Popover) never leaks an outside dismissal to the layer below.\n *\n * Dispatch goes through a single shared document listener, so synchronous\n * changes to the stack from a handler don't leak into sibling listeners.\n */\nexport class DismissibleLayer {\n readonly #host: HTMLElement;\n readonly #stack: DismissibleLayerStack;\n #options: DismissibleLayerActivateOptions = EMPTY_ACTIVATE_OPTIONS;\n #channels: ReadonlySet<DismissibleLayerChannel> = new Set();\n #active = false;\n\n constructor(host: HTMLElement, stack: DismissibleLayerStack) {\n this.#host = host;\n this.#stack = stack;\n }\n\n get host(): HTMLElement {\n return this.#host;\n }\n\n get isActive(): boolean {\n return this.#active;\n }\n\n /**\n * @internal The nesting position declared at `activate`, or `undefined` for a\n * standalone layer. Read by {@link DismissibleLayerStack} to place the layer\n * by nesting depth instead of activation order. Public only so the stack can\n * read it, not part of the supported API.\n */\n get nesting(): DismissibleLayerNesting | undefined {\n return this.#options.nesting;\n }\n\n /**\n * Pushes this layer onto the dispatch stack. Calling `activate` twice\n * without an intervening `deactivate` is a no-op.\n */\n activate(options: DismissibleLayerActivateOptions): void {\n if (this.#active) {\n return;\n }\n this.#active = true;\n this.#options = options;\n this.#channels = new Set(options.channels);\n this.#stack.push(this);\n }\n\n /** Removes this layer from the stack. */\n deactivate(): void {\n if (!this.#active) {\n return;\n }\n this.#active = false;\n this.#stack.remove(this);\n this.#options = EMPTY_ACTIVATE_OPTIONS;\n this.#channels = new Set();\n }\n\n /**\n * Convenience wrapper around the stack's `suppress`. Lets owners\n * suppress the dispatcher without needing a fresh injection context\n * (e.g. inside `DestroyRef.onDestroy` or imperative teardown closures).\n */\n suppress<T>(fn: () => T): T {\n return this.#stack.suppress(fn);\n }\n\n /**\n * @internal Whether this layer declared ownership of `channel`. Read by\n * {@link DismissibleLayerStack} to route an outside pointer-down / focus to\n * the topmost owning layer. Public only so the stack can read it, not part of\n * the supported API.\n */\n ownsChannel(channel: DismissibleLayerChannel): boolean {\n return this.#channels.has(channel);\n }\n\n /**\n * Whether this layer is active and is the topmost layer declaring `channel`, so no other layer\n * stacked above it would receive an outside interaction on that channel first.\n */\n isTopmostFor(channel: DismissibleLayerChannel): boolean {\n return this.#active && this.#stack.isTopmostForChannel(this, channel);\n }\n\n /**\n * @internal Whether `target` is inside this layer's host or its exempt\n * elements. Read by {@link DismissibleLayerStack} when walking the stack for\n * stack-aware containment. Public only so the stack can read it.\n *\n * Containment is composed-tree containment, the counterpart of the deep\n * target {@link resolveEventTarget} resolves: plain `Node.contains` answers\n * within one node tree, so a press on a control inside a web component's\n * shadow root — a target the composed path resolves precisely — would read as\n * a press outside the surface that renders it.\n */\n contains(target: Node): boolean {\n if (composedContains(this.#host, target)) {\n return true;\n }\n const exempt = this.#options.exemptElements?.(target);\n if (!exempt) {\n return false;\n }\n for (const el of exempt) {\n if (composedContains(el, target)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * @internal Dispatched by {@link DismissibleLayerStack} to the topmost layer\n * on `Escape`, and to each layer below it while the layers above decline the\n * key. Returns whether this layer kept it. Public only so the stack can call it\n * without exploiting a TS visibility loophole; not part of the supported API\n * (stripped from `.d.ts`).\n */\n handleEscape(event: KeyboardEvent): boolean {\n return this.#options.onEscapeKeyDown?.(event) !== false;\n }\n\n /**\n * @internal Dispatched by {@link DismissibleLayerStack} to the topmost layer\n * declaring the `'pointer'` channel on an outside `pointerdown`, and to each\n * layer below it an outside-press cascade reaches. Returns whether the press\n * was outside and the layer closed on it. See {@link handleEscape}.\n */\n handlePointerDown(event: PointerEvent): boolean {\n const target = resolveEventTarget(event);\n if (!target) {\n return false;\n }\n if (this.#stack.containsFromLayer(this, target)) {\n this.#options.onPointerDownInside?.(event);\n return false;\n }\n const closed = this.#options.onPointerDownOutside?.(event) === true;\n this.#options.onInteractOutside?.(event);\n return closed;\n }\n\n /**\n * @internal Whether this layer declared itself modal at `activate`. Read by\n * {@link DismissibleLayerStack} to end an outside-press cascade.\n */\n get isModal(): boolean {\n return this.#options.modal === true;\n }\n\n /**\n * @internal Whether this layer currently opts into an outside-press cascade.\n * Read by {@link DismissibleLayerStack} on every press.\n */\n cascadesOutsidePress(): boolean {\n return this.#options.cascadeOutsidePress?.() === true;\n }\n\n /**\n * @internal Dispatched by {@link DismissibleLayerStack} to the topmost layer\n * declaring the `'focus'` channel on an outside `focusin`. See\n * {@link handleEscape}.\n */\n handleFocusIn(event: FocusEvent): void {\n const target = resolveEventTarget(event);\n if (!target || this.#stack.containsFromLayer(this, target)) {\n return;\n }\n this.#options.onFocusOutside?.(event);\n this.#options.onInteractOutside?.(event);\n }\n}\n\n/**\n * Creates a `DismissibleLayer` for the directive's host element and wires\n * deactivation into `DestroyRef`. The host primitive owns activation\n * (typically via an `effect()` watching the open state).\n *\n * Use `layer.suppress(fn)` to run a callback with the dispatcher\n * suppressed (e.g. across a focus-return that would otherwise\n * cascade-dismiss the next topmost layer).\n */\nexport function injectDismissibleLayer(): DismissibleLayer {\n const host = inject<ElementRef<HTMLElement>>(ElementRef);\n const stack = inject(DismissibleLayerStack);\n const layer = new DismissibleLayer(host.nativeElement, stack);\n inject(DestroyRef).onDestroy(() => layer.deactivate());\n return layer;\n}\n","import { computed, Injectable, type Signal, signal } from '@angular/core';\n\nimport { type ForDrawerSide } from './drawer-side';\nimport { fortyError } from 'forty-cdk/core';\n\n/**\n * Snapshot of a single drawer registered with {@link ForDrawerStack}. The\n * stack is LIFO ordered (root → topmost) and exposes only what other\n * coordinators need — `host` for ancestry checks, `side` (a `Signal`, so a\n * runtime side flip recomputes dependent transforms) for layout heuristics,\n * `parent` for topology, `dragging` so visual coordinators (e.g.\n * `ForDrawerScaleCoordinator`'s nested-transform pass) can yield the\n * surface to imperative drag handlers, and the resolved nested-transform\n * tunables so the coordinator never needs to re-read scope-dependent\n * defaults.\n */\nexport interface DrawerStackNode {\n readonly host: HTMLElement;\n /**\n * Reactive edge the drawer is anchored to. Read inside the coordinator's\n * nested-transform effect so a runtime `[side]` rebind recomputes the\n * parent surface's transform axis, mirroring the reactive `dragging`\n * channel.\n */\n readonly side: Signal<ForDrawerSide>;\n readonly parent: HTMLElement | null;\n /**\n * Reactive flag that flips to `true` while a swipe gesture is in flight\n * on this drawer's surface. Visual coordinators must yield the host's\n * inline transform to the drag handlers while this is `true`.\n */\n readonly dragging: Signal<boolean>;\n /**\n * Scale factor applied to *this* drawer's host while it owns one or\n * more direct child drawers (the nested-drawer visual). Resolved from\n * the drawer's own injector scope at push time so per-scope\n * `provideForDrawerDefaults` overrides flow through.\n */\n readonly nestedScaleAmount: number;\n /**\n * Pixels of translation applied to *this* drawer's host while it owns\n * one or more direct child drawers, in the direction *away* from its\n * anchored edge.\n */\n readonly nestedTranslateYpx: number;\n}\n\n/**\n * Returned by {@link ForDrawerStack.push}. `depth` is the number of\n * ancestor drawers in the node's `parent` chain (0 for a root drawer, 1 for a\n * single-nested child, …), recomputed whenever the stack changes. `cleanup`\n * pops the node; calling it while descendants are still registered throws so\n * consumers surface their own destroy-order bugs instead of silently leaking.\n */\nexport interface DrawerStackHandle {\n readonly depth: Signal<number>;\n cleanup(): void;\n}\n\n/**\n * App-scoped LIFO registry of every active `[forDrawer]`. Mounted drawers\n * push themselves on first render and pop on destroy; the stack's signal\n * is the single source of truth for nesting topology consumed by:\n *\n * - `[forDrawer]` itself, to derive `data-depth` and `data-state-nested`\n * on its host (the latter when the stack contains a node whose\n * `parent` is this drawer's host).\n * - `ForDrawerScaleCoordinator`, when `scaleBackground` is opted in by\n * multiple levels of nesting and the visual effect must compose along\n * the LIFO topmost.\n *\n * The companion to {@link DismissibleLayerStack} and `InertSiblingsStack`:\n * those keep the focus / dismiss / inert behaviour LIFO-correct, this one\n * keeps the *visual* / *topology* layer LIFO-correct. Both are read-only\n * to consumers — there is no public API for explicit ordering. A drawer is\n * pushed on top unless one of its descendants is already registered, as\n * when parent and child mount in one render pass, in which case it is\n * inserted below its first descendant.\n *\n * SSR: `providedIn: 'root'` so state is per Angular bootstrap. The\n * directives that call `push` only do so from `afterNextRender`, which\n * doesn't run on the server, so there is nothing to guard here.\n *\n * Internal core tier — exported from `forty-cdk/core` for the library's own\n * entry points, with no semver guarantee.\n */\n@Injectable({ providedIn: 'root' })\nexport class ForDrawerStack {\n readonly #stack = signal<readonly DrawerStackNode[]>([]);\n\n /**\n * Reactive view of the current drawer stack (root → topmost). Reading\n * this from a `computed`/`effect` lets primitives react to nesting\n * changes synchronously when a child drawer mounts or unmounts.\n */\n readonly stack: Signal<readonly DrawerStackNode[]> = this.#stack.asReadonly();\n\n /**\n * Push a drawer onto the stack. Returns a {@link DrawerStackHandle}\n * carrying the computed `depth` and a `cleanup` that pops the same\n * node. `depth` is derived from the node's `parent` chain through the\n * registered drawers: a root drawer (no `parent`) is depth 0; a child of\n * a depth-N drawer is depth N+1.\n *\n * `cleanup` is idempotent on a node that's already gone, but throws if\n * the node still has descendants in the stack — the canonical signal\n * that the consumer's template tore down a parent before its child\n * (typically because the parent's `@if` flipped to `false` while the\n * child sits in a separate template branch). Nest the child's\n * `@if (childOpen())` *inside* the parent's `@if (parentOpen())` to\n * inherit Angular's bottom-up destroy order automatically.\n */\n push(node: DrawerStackNode): DrawerStackHandle {\n this.#stack.update((s) => {\n const descendant = s.findIndex((other) => this.#isDescendant(other, node, s));\n const next = s.slice();\n next.splice(descendant === -1 ? next.length : descendant, 0, node);\n return next;\n });\n return {\n depth: computed(() => this.#computeDepth(node, this.#stack())),\n cleanup: () => this.#cleanup(node),\n };\n }\n\n #cleanup(node: DrawerStackNode): void {\n const current = this.#stack();\n const idx = current.indexOf(node);\n if (idx === -1) {\n return;\n }\n const hasDescendant = current.some(\n (other) => other !== node && this.#isDescendant(other, node, current),\n );\n if (hasDescendant) {\n throw fortyError({\n code: 'FORCDK-DRAWER-001',\n message: 'A parent drawer was destroyed while a nested child drawer was still registered.',\n cause:\n 'The drawer stack unwinds last-in-first-out, so a child must unmount before its parent. ' +\n 'Sibling @if blocks unmount in template order instead.',\n fix: \"Wrap the child drawer's @if inside the parent's, so the child unmounts first.\",\n });\n }\n const next = current.slice();\n next.splice(idx, 1);\n this.#stack.set(next);\n }\n\n #computeDepth(node: DrawerStackNode, stack: readonly DrawerStackNode[]): number {\n if (node.parent === null) {\n return 0;\n }\n let depth = 0;\n let cursor: HTMLElement | null = node.parent;\n while (cursor) {\n depth += 1;\n const ancestor = stack.find((n) => n.host === cursor);\n if (!ancestor) {\n break;\n }\n cursor = ancestor.parent;\n }\n return depth;\n }\n\n #isDescendant(\n candidate: DrawerStackNode,\n ancestor: DrawerStackNode,\n stack: readonly DrawerStackNode[],\n ): boolean {\n let cursor: HTMLElement | null = candidate.parent;\n while (cursor) {\n if (cursor === ancestor.host) {\n return true;\n }\n const next = stack.find((n) => n.host === cursor);\n if (!next) {\n return false;\n }\n cursor = next.parent;\n }\n return false;\n }\n}\n","import type { Signal } from '@angular/core';\nimport type { ReferenceElement } from '@floating-ui/dom';\n\nimport type { FloatingAlign, FloatingConfig, FloatingSide } from './floating';\n\n/**\n * Single source of truth for the floating-ui positioning defaults shared by\n * every trigger-anchored overlay root. It is read once, by the two bases the\n * roots inherit their positioning block from\n * (`AnchoredOverlayPositioningBase` / `AnchoredFormValueControlBase`), so no\n * root spells a non-seed default itself.\n *\n * Only `side` / `align` / `sideOffset` / `collisionPadding` are seeded from\n * each root's own defaults provider (`provideForPopoverDefaults`,\n * `provideForSelectDefaults`, …) so a scope override flows through — those are\n * the placement values a design system tunes, and they legitimately vary per\n * root. Everything below is identical for every anchored overlay in the\n * library, which is why `arrowPadding` is not among them: only the three roots\n * shipping an arrow piece declare it, each seeded from its own defaults\n * provider.\n */\nexport const ANCHORED_POSITIONING_DEFAULTS = {\n /** Default gap (px) along the cross axis (parallel to `side`). */\n alignOffset: 0,\n /** `flip` / `shift` keep the surface inside the viewport by default. */\n avoidCollisions: true,\n /** Default stickiness behaviour for `shift`. */\n sticky: 'partial' as 'partial' | 'always' | false,\n /** `data-detached=\"\"` is not reflected by default. */\n hideWhenDetached: false,\n /** Content is clipped until floating-ui resolves its first position by default. */\n clipUntilPositioned: true,\n} as const;\n\n/**\n * The resolved floating-ui positioning surface every trigger-anchored overlay\n * root publishes on its context. `ForPopoverContext`, `ForTooltipContext`, and\n * `ForHoverCardContext` all `extends` this so the 12-member positioning half of\n * each context interface is single-sourced rather than copied verbatim.\n *\n * Each member is the *effective* value — the per-instance input merged with the\n * scope default — so a content directive forwards it straight into\n * `injectOverlayShell` via `toFloatingPositioner` without re-resolving defaults.\n *\n * `open` is included because the floating positioner gates `autoUpdate` on it;\n * it is published by every root's open `model()` (a `ModelSignal` is a\n * `Signal`), so a single `extends` covers the whole positioner surface.\n */\nexport interface AnchoredPositioningContext {\n readonly open: Signal<boolean>;\n readonly side: Signal<FloatingSide>;\n readonly align: Signal<FloatingAlign>;\n readonly sideOffset: Signal<number>;\n readonly alignOffset: Signal<number>;\n readonly avoidCollisions: Signal<boolean>;\n readonly collisionPadding: Signal<number>;\n readonly arrowPadding: Signal<number>;\n readonly sticky: Signal<'partial' | 'always' | false>;\n readonly hideWhenDetached: Signal<boolean>;\n readonly clipUntilPositioned: Signal<boolean>;\n readonly arrow: Signal<HTMLElement | null>;\n}\n\n/**\n * Builds the `injectOverlayShell` floating-positioner block from an\n * `AnchoredPositioningContext` and the element the overlay anchors against.\n * Each of the three content directives (`ForPopoverContent`,\n * `ForTooltipContent`, `ForHoverCardContent`) built this 13-field block\n * verbatim; the only difference is the `reference` source — popover anchors to\n * its registered `[forPopoverAnchor]` (falling back to the trigger), tooltip\n * and hover-card anchor directly to the trigger — so the caller passes it in.\n */\nexport function toFloatingPositioner(\n ctx: AnchoredPositioningContext,\n reference: Signal<ReferenceElement | null>,\n): { kind: 'floating' } & FloatingConfig {\n return {\n kind: 'floating',\n reference,\n open: ctx.open,\n side: ctx.side,\n align: ctx.align,\n sideOffset: ctx.sideOffset,\n alignOffset: ctx.alignOffset,\n avoidCollisions: ctx.avoidCollisions,\n collisionPadding: ctx.collisionPadding,\n arrowPadding: ctx.arrowPadding,\n sticky: ctx.sticky,\n hideWhenDetached: ctx.hideWhenDetached,\n clipUntilPositioned: ctx.clipUntilPositioned,\n arrow: ctx.arrow,\n };\n}\n","import { booleanAttribute, computed, Directive, input, numberAttribute } from '@angular/core';\n\nimport { FormUiControlBase } from 'forty-cdk/core';\nimport { ANCHORED_POSITIONING_DEFAULTS } from './anchored-positioning-inputs';\nimport type {\n AnchoredPositioningOverride,\n AnchoredPositioningSeedDefaults,\n} from './anchored-overlay-positioning-base';\nimport type { FloatingAlign, FloatingSide } from './floating';\n\n/**\n * `AnchoredOverlayPositioningBase` for the anchored roots that are also form\n * values — `[forSelect]`, `[forCombobox]`, `[forTimePicker]`, and both\n * date-picker roots through `DatePickerBase`. They must extend\n * `FormUiControlBase` for the Signal Forms contract, and TypeScript has single\n * inheritance, so the positioning block cannot reach them by extending the\n * other base as the remaining eight roots do.\n *\n * This class is therefore the **second and last** declaration site of that\n * block, and it is a verbatim copy on purpose:\n * `anchored-positioning-inputs.spec.ts` reads both files and fails when the two\n * regions stop matching character-for-character, so a change to one is a change\n * to both. Everything the block means is documented on\n * {@link AnchoredOverlayPositioningBase}; do not restate it here, and do not add\n * a member to one base without adding it to the other.\n */\n@Directive()\nexport abstract class AnchoredFormValueControlBase extends FormUiControlBase {\n /**\n * The four positioning seeds this root resolves from its own scoped defaults\n * provider. Concrete roots implement it with\n * `protected readonly positioningDefaults = inject(FOR_X_DEFAULTS)`, or with\n * a getter over a `computed` when one seed is derived (writing direction).\n */\n protected abstract readonly positioningDefaults: AnchoredPositioningSeedDefaults;\n\n /**\n * Placement override for the current open, resolved ahead of this root's own\n * inputs. `null` (the default) leaves the inputs in charge; the menu roots\n * override it with the active opener's `[menuPositioning]`.\n */\n protected positioningOverride(): AnchoredPositioningOverride | null {\n return null;\n }\n\n /**\n * Per-instance override for the side the overlay is anchored to. Pair with\n * `align` for the full positioning API. When `undefined` (default), falls\n * back to the scope default. Aliased to `side`; consumers bind `[side]=\"...\"`\n * and read the effective value via the public {@link side} computed.\n */\n readonly _sideInput = input<FloatingSide | undefined>(undefined, { alias: 'side' });\n\n /** Effective anchor side: the per-open override, else the `side` input, else the scope default. */\n readonly side = computed<FloatingSide>(\n () => this.positioningOverride()?.side ?? this._sideInput() ?? this.positioningDefaults.side,\n );\n\n /**\n * Per-instance override for the alignment along the chosen `side`. When\n * `undefined` (default), falls back to the scope default. Aliased to `align`;\n * consumers bind `[align]=\"...\"` and read the effective value via the public\n * {@link align} computed.\n */\n readonly _alignInput = input<FloatingAlign | undefined>(undefined, { alias: 'align' });\n\n /** Effective alignment: the per-open override, else the `align` input, else the scope default. */\n readonly align = computed<FloatingAlign>(\n () => this.positioningOverride()?.align ?? this._alignInput() ?? this.positioningDefaults.align,\n );\n\n /**\n * Per-instance override for the gap (px) between trigger and content along\n * the main axis. When `undefined` (default), falls back to the scope default.\n * Aliased to `sideOffset`; consumers bind `[sideOffset]=\"...\"` and read the\n * effective value via the public {@link sideOffset} computed.\n */\n readonly _sideOffsetInput = input(undefined, {\n alias: 'sideOffset',\n transform: (v: unknown): number | undefined => (v == null ? undefined : numberAttribute(v)),\n });\n\n /** Effective main-axis gap (px): the per-open override, else the input, else the scope default. */\n readonly sideOffset = computed<number>(\n () =>\n this.positioningOverride()?.sideOffset ??\n this._sideOffsetInput() ??\n this.positioningDefaults.sideOffset,\n );\n\n /**\n * Per-instance gap (px) along the cross axis (parallel to `side`). Default\n * `0`. Aliased to `alignOffset`; consumers bind `[alignOffset]=\"...\"` and read\n * the effective value via the public {@link alignOffset} computed.\n */\n readonly _alignOffsetInput = input(ANCHORED_POSITIONING_DEFAULTS.alignOffset, {\n alias: 'alignOffset',\n transform: numberAttribute,\n });\n\n /** Effective cross-axis gap (px): the per-open override, else the `alignOffset` input. */\n readonly alignOffset = computed<number>(\n () => this.positioningOverride()?.alignOffset ?? this._alignOffsetInput(),\n );\n\n /**\n * When `true` (default), `flip` and `shift` keep the overlay inside the\n * viewport. Disable for strict positioning where overflow is acceptable.\n */\n readonly avoidCollisions = input(ANCHORED_POSITIONING_DEFAULTS.avoidCollisions, {\n transform: booleanAttribute,\n });\n\n /**\n * Per-instance override for the padding (px) applied uniformly to the `flip`,\n * `shift`, and `size` middlewares. When `undefined` (default), falls back to\n * the scope default. Aliased to `collisionPadding`; consumers bind\n * `[collisionPadding]=\"...\"` and read the effective value via the public\n * {@link collisionPadding} computed.\n */\n readonly _collisionPaddingInput = input(undefined, {\n alias: 'collisionPadding',\n transform: (v: unknown): number | undefined => (v == null ? undefined : numberAttribute(v)),\n });\n\n /** Effective collision padding (px): the `collisionPadding` input when set, else the scope default. */\n readonly collisionPadding = computed<number>(\n () => this._collisionPaddingInput() ?? this.positioningDefaults.collisionPadding,\n );\n\n /**\n * Stickiness behaviour for `shift`. `'partial'` (default) lets the overlay\n * shift to stay visible. `'always'` keeps the requested placement even\n * off-screen.\n */\n readonly sticky = input<'partial' | 'always' | false>(ANCHORED_POSITIONING_DEFAULTS.sticky);\n\n /**\n * When `true`, sets `data-detached=\"\"` while the trigger has scrolled off all\n * clipping ancestors.\n */\n readonly hideWhenDetached = input(ANCHORED_POSITIONING_DEFAULTS.hideWhenDetached, {\n transform: booleanAttribute,\n });\n\n /**\n * When `true` (default), the content is clipped until floating-ui resolves\n * its first position, preventing a flash at the viewport corner. Set to\n * `false` so a dramatic `animate.enter` plays from its first frame (the\n * surface may flash briefly at the unresolved position while positioning\n * computes).\n */\n readonly clipUntilPositioned = input(ANCHORED_POSITIONING_DEFAULTS.clipUntilPositioned, {\n transform: booleanAttribute,\n });\n}\n","import { booleanAttribute, computed, Directive, input, numberAttribute } from '@angular/core';\n\nimport { ANCHORED_POSITIONING_DEFAULTS } from './anchored-positioning-inputs';\nimport type { FloatingAlign, FloatingSide } from './floating';\n\n/**\n * The four positioning seeds a trigger-anchored overlay root resolves from its\n * own scoped defaults provider (`provideForPopoverDefaults`,\n * `provideForSelectDefaults`, …), rather than from the shared\n * {@link ANCHORED_POSITIONING_DEFAULTS} constant. A root's `ForXDefaults`\n * interface `extends` this whenever all four keys are plain values, so the\n * shared seed contract stays typed identically across roots, and every concrete\n * {@link AnchoredOverlayPositioningBase} subclass supplies an instance of it\n * through its `positioningDefaults` accessor.\n *\n * A root whose library fallback for one seed is *derived* rather than fixed —\n * MenuSub's writing-direction `side` — declares that key nullable on its own\n * defaults interface and resolves it inside `positioningDefaults`, so what the\n * base reads is always a settled value.\n */\nexport interface AnchoredPositioningSeedDefaults {\n /** Side the overlay is anchored to when the `side` input is unset. */\n side: FloatingSide;\n /** Alignment along the chosen `side` when the `align` input is unset. */\n align: FloatingAlign;\n /** Gap (px) between trigger and content along the main axis when the `sideOffset` input is unset. */\n sideOffset: number;\n /** Padding (px) applied uniformly to `flip` / `shift` / `size` when the `collisionPadding` input is unset. */\n collisionPadding: number;\n}\n\n/**\n * Per-open override of the four **placement** values, resolved ahead of the\n * root's own inputs. It exists for the menu roots, where one surface is shared\n * by heterogeneous openers and the opener that fired legitimately decides the\n * placement (`MenuOpenerPositioning` is the shape flowing through\n * `[menuPositioning]`); every other root inherits the base's `null` and\n * resolves its inputs directly.\n *\n * Only the four placement values are overridable. The rest of the surface\n * (`avoidCollisions`, `collisionPadding`, `sticky`, …) is collision / viewport\n * policy for the overlay rather than a property of what opened it.\n */\nexport interface AnchoredPositioningOverride {\n /** Side the overlay is anchored to for this open. */\n readonly side?: FloatingSide;\n /** Alignment along the chosen `side` for this open. */\n readonly align?: FloatingAlign;\n /** Gap (px) along the main axis for this open. */\n readonly sideOffset?: number;\n /** Gap (px) along the cross axis for this open. */\n readonly alignOffset?: number;\n}\n\n/**\n * Abstract base for the trigger-anchored overlay roots. It single-sources the\n * nine shared floating-ui positioning inputs and the five effective computeds\n * over them, so the declarations live in one place instead of being copied per\n * root.\n *\n * Each of the four placement values resolves in the same three steps — the\n * per-open {@link positioningOverride}, then the root's own input, then the\n * scope default read through {@link positioningDefaults}. The five non-placement\n * inputs (`avoidCollisions` / `sticky` / `hideWhenDetached` /\n * `clipUntilPositioned`, plus `alignOffset`'s own library fallback) default from\n * the shared {@link ANCHORED_POSITIONING_DEFAULTS} constant.\n *\n * `arrowPadding` is **not** here: floating-ui installs the `arrow` middleware\n * only when an arrow element is supplied, so it belongs to the three roots that\n * ship one — `[forPopover]`, `[forTooltip]`, `[forHoverCard]` — each declaring\n * the input itself, seeded from its own defaults provider.\n *\n * Roots that must also extend `FormUiControlBase` reach the identical block\n * through `AnchoredFormValueControlBase` instead.\n */\n@Directive()\nexport abstract class AnchoredOverlayPositioningBase {\n /**\n * The four positioning seeds this root resolves from its own scoped defaults\n * provider. Concrete roots implement it with\n * `protected readonly positioningDefaults = inject(FOR_X_DEFAULTS)`, or with\n * a getter over a `computed` when one seed is derived (writing direction).\n */\n protected abstract readonly positioningDefaults: AnchoredPositioningSeedDefaults;\n\n /**\n * Placement override for the current open, resolved ahead of this root's own\n * inputs. `null` (the default) leaves the inputs in charge; the menu roots\n * override it with the active opener's `[menuPositioning]`.\n */\n protected positioningOverride(): AnchoredPositioningOverride | null {\n return null;\n }\n\n /**\n * Per-instance override for the side the overlay is anchored to. Pair with\n * `align` for the full positioning API. When `undefined` (default), falls\n * back to the scope default. Aliased to `side`; consumers bind `[side]=\"...\"`\n * and read the effective value via the public {@link side} computed.\n */\n readonly _sideInput = input<FloatingSide | undefined>(undefined, { alias: 'side' });\n\n /** Effective anchor side: the per-open override, else the `side` input, else the scope default. */\n readonly side = computed<FloatingSide>(\n () => this.positioningOverride()?.side ?? this._sideInput() ?? this.positioningDefaults.side,\n );\n\n /**\n * Per-instance override for the alignment along the chosen `side`. When\n * `undefined` (default), falls back to the scope default. Aliased to `align`;\n * consumers bind `[align]=\"...\"` and read the effective value via the public\n * {@link align} computed.\n */\n readonly _alignInput = input<FloatingAlign | undefined>(undefined, { alias: 'align' });\n\n /** Effective alignment: the per-open override, else the `align` input, else the scope default. */\n readonly align = computed<FloatingAlign>(\n () => this.positioningOverride()?.align ?? this._alignInput() ?? this.positioningDefaults.align,\n );\n\n /**\n * Per-instance override for the gap (px) between trigger and content along\n * the main axis. When `undefined` (default), falls back to the scope default.\n * Aliased to `sideOffset`; consumers bind `[sideOffset]=\"...\"` and read the\n * effective value via the public {@link sideOffset} computed.\n */\n readonly _sideOffsetInput = input(undefined, {\n alias: 'sideOffset',\n transform: (v: unknown): number | undefined => (v == null ? undefined : numberAttribute(v)),\n });\n\n /** Effective main-axis gap (px): the per-open override, else the input, else the scope default. */\n readonly sideOffset = computed<number>(\n () =>\n this.positioningOverride()?.sideOffset ??\n this._sideOffsetInput() ??\n this.positioningDefaults.sideOffset,\n );\n\n /**\n * Per-instance gap (px) along the cross axis (parallel to `side`). Default\n * `0`. Aliased to `alignOffset`; consumers bind `[alignOffset]=\"...\"` and read\n * the effective value via the public {@link alignOffset} computed.\n */\n readonly _alignOffsetInput = input(ANCHORED_POSITIONING_DEFAULTS.alignOffset, {\n alias: 'alignOffset',\n transform: numberAttribute,\n });\n\n /** Effective cross-axis gap (px): the per-open override, else the `alignOffset` input. */\n readonly alignOffset = computed<number>(\n () => this.positioningOverride()?.alignOffset ?? this._alignOffsetInput(),\n );\n\n /**\n * When `true` (default), `flip` and `shift` keep the overlay inside the\n * viewport. Disable for strict positioning where overflow is acceptable.\n */\n readonly avoidCollisions = input(ANCHORED_POSITIONING_DEFAULTS.avoidCollisions, {\n transform: booleanAttribute,\n });\n\n /**\n * Per-instance override for the padding (px) applied uniformly to the `flip`,\n * `shift`, and `size` middlewares. When `undefined` (default), falls back to\n * the scope default. Aliased to `collisionPadding`; consumers bind\n * `[collisionPadding]=\"...\"` and read the effective value via the public\n * {@link collisionPadding} computed.\n */\n readonly _collisionPaddingInput = input(undefined, {\n alias: 'collisionPadding',\n transform: (v: unknown): number | undefined => (v == null ? undefined : numberAttribute(v)),\n });\n\n /** Effective collision padding (px): the `collisionPadding` input when set, else the scope default. */\n readonly collisionPadding = computed<number>(\n () => this._collisionPaddingInput() ?? this.positioningDefaults.collisionPadding,\n );\n\n /**\n * Stickiness behaviour for `shift`. `'partial'` (default) lets the overlay\n * shift to stay visible. `'always'` keeps the requested placement even\n * off-screen.\n */\n readonly sticky = input<'partial' | 'always' | false>(ANCHORED_POSITIONING_DEFAULTS.sticky);\n\n /**\n * When `true`, sets `data-detached=\"\"` while the trigger has scrolled off all\n * clipping ancestors.\n */\n readonly hideWhenDetached = input(ANCHORED_POSITIONING_DEFAULTS.hideWhenDetached, {\n transform: booleanAttribute,\n });\n\n /**\n * When `true` (default), the content is clipped until floating-ui resolves\n * its first position, preventing a flash at the viewport corner. Set to\n * `false` so a dramatic `animate.enter` plays from its first frame (the\n * surface may flash briefly at the unresolved position while positioning\n * computes).\n */\n readonly clipUntilPositioned = input(ANCHORED_POSITIONING_DEFAULTS.clipUntilPositioned, {\n transform: booleanAttribute,\n });\n}\n","/**\n * A single self-clearing debounce timer: the `Math.max(0, delay)` clamp, the\n * `delay === 0` synchronous fast-path, and the lone pending\n * `setTimeout` / `clearTimeout` pair.\n *\n * The hover-driven menus (`[forMenuSub]`, `[forMenubar]`, `[forNavigationMenu]`)\n * each hand-rolled this exact timer arming/clearing under their own divergent\n * open/close policy (chain keep-alive, hover-after-open, per-value cancel\n * guards, skip-delay). This factory owns only the timing mechanics so those\n * policies stay at the call site — the caller arms with `schedule(delay)`,\n * which clears any in-flight timer first, runs `run` immediately when the\n * clamped delay is `0`, else fires it once after the delay.\n *\n * Internal core tier — exported from `forty-cdk/core` for the library's own\n * entry points, with no semver guarantee.\n */\nexport interface DebouncedAction {\n /**\n * Arm the action after `delay` ms (clamped to `>= 0`). Clears any pending\n * timer first; a clamped delay of `0` runs `run` synchronously.\n */\n schedule(delay: number): void;\n /** Cancel a pending action without running it. Safe with no pending timer. */\n cancel(): void;\n /** `true` while an action is armed but not yet fired. */\n isPending(): boolean;\n}\n\n/**\n * Builds a {@link DebouncedAction} around `run`. Framework-free.\n */\nexport function createDebouncedAction(run: () => void): DebouncedAction {\n let timer: ReturnType<typeof setTimeout> | null = null;\n\n function cancel(): void {\n if (timer !== null) {\n clearTimeout(timer);\n timer = null;\n }\n }\n\n function schedule(delay: number): void {\n cancel();\n const clamped = Math.max(0, delay);\n if (clamped === 0) {\n run();\n return;\n }\n timer = setTimeout(() => {\n timer = null;\n run();\n }, clamped);\n }\n\n return {\n schedule,\n cancel,\n isPending: () => timer !== null,\n };\n}\n","import { effect, type Signal, untracked, type WritableSignal } from '@angular/core';\n\n/**\n * Per-injector-scope coordinator the hover-intent scheduler consults to decide\n * whether the open delay should be skipped, and to open the skip-delay window\n * when a primitive finishes closing. Both `TooltipCoordinator` and\n * `HoverCardCoordinator` satisfy this contract structurally.\n */\nexport interface HoverIntentCoordinator {\n /** True while a peer in this scope just closed and the next open is instant. */\n skipDelay(): boolean;\n /** Opens the skip-delay window. Called by the scheduler when it closes. */\n startSkipDelay(): void;\n}\n\n/**\n * Inputs for {@link createHoverIntent}. Delays are passed as accessor\n * functions so the scheduler reads resolved values (per-instance override or\n * scope default) at the moment a timer is armed.\n */\nexport interface HoverIntentOptions {\n /** Writable open-state signal the scheduler flips. */\n open: WritableSignal<boolean>;\n /** Whether all hover / focus interaction is currently ignored. */\n isDisabled: () => boolean;\n /** Resolved open delay (ms) to use when arming an open timer. */\n openDelay: () => number;\n /** Resolved close delay (ms) to use when arming a close timer. */\n closeDelay: () => number;\n /** Skip-delay coordinator shared by peers in the same scope. */\n coordinator: HoverIntentCoordinator;\n}\n\n/**\n * Hover-intent scheduler handle returned by {@link createHoverIntent}.\n */\nexport interface HoverIntentScheduler {\n /** Schedule the open after the resolved open delay (instant when delay is 0 or skipped). */\n scheduleOpen(): void;\n /** Schedule the close after the resolved close delay; `immediate` bypasses the delay. */\n scheduleClose(immediate: boolean): void;\n /** Cancel any pending open / close timer without changing state. */\n cancelPending(): void;\n /** Whether an open or close timer is pending. */\n isPending(): boolean;\n}\n\n/**\n * Shared hover-intent scheduler for Tooltip and Hover-card.\n *\n * Both primitives carry an identical open / close timer with skip-delay\n * coordination and `Math.max(0, …)` guards; this framework-free factory holds\n * the single pending timer and the open / close logic, parameterized by the\n * resolved open / close delays plus a {@link HoverIntentCoordinator}. The\n * directive constructs it once (after its `open` signal exists) and delegates\n * its public scheduling methods to the returned handle.\n *\n * Internal core tier — exported from `forty-cdk/core` for the library's own\n * entry points, with no semver guarantee.\n */\nexport function createHoverIntent(options: HoverIntentOptions): HoverIntentScheduler {\n let pendingTimer: ReturnType<typeof setTimeout> | null = null;\n\n function cancelPending(): void {\n if (pendingTimer !== null) {\n clearTimeout(pendingTimer);\n pendingTimer = null;\n }\n }\n\n function close(): void {\n options.open.set(false);\n options.coordinator.startSkipDelay();\n }\n\n function scheduleOpen(): void {\n cancelPending();\n if (options.isDisabled()) {\n return;\n }\n if (options.open()) {\n return;\n }\n const base = options.coordinator.skipDelay() ? 0 : options.openDelay();\n const delay = Math.max(0, base);\n if (delay === 0) {\n options.open.set(true);\n return;\n }\n pendingTimer = setTimeout(() => {\n pendingTimer = null;\n if (options.isDisabled()) {\n return;\n }\n options.open.set(true);\n }, delay);\n }\n\n function scheduleClose(immediate: boolean): void {\n cancelPending();\n if (!options.open()) {\n return;\n }\n if (immediate) {\n close();\n return;\n }\n const delay = Math.max(0, options.closeDelay());\n if (delay === 0) {\n close();\n return;\n }\n pendingTimer = setTimeout(() => {\n pendingTimer = null;\n close();\n }, delay);\n }\n\n return { scheduleOpen, scheduleClose, cancelPending, isPending: () => pendingTimer !== null };\n}\n\n/**\n * Inputs for {@link forceCloseWhenDisabled}.\n */\nexport interface ForceCloseWhenDisabledOptions {\n /** Open-state signal that is force-closed when `disabled` flips to true. */\n open: WritableSignal<boolean>;\n /** Whether all hover / focus interaction is currently ignored. */\n disabled: Signal<boolean>;\n /** Imperative cleanup run before the force-close (cancel any pending timers). */\n onForceClose: () => void;\n}\n\n/**\n * The single audited place that force-closes a hover-driven overlay when its\n * `disabled` input flips to `true` while open.\n *\n * Tooltip and Hover-card each carried a byte-identical copy of this reaction;\n * it is the **one sanctioned exception** to the project's \"never propagate\n * state inside `effect()`\" rule, so it must live in exactly one place rather\n * than two carve-outs to audit. The hover scheduler already early-returns on\n * `disabled()`, so hover / focus can't open a disabled overlay; this isolated\n * reaction only covers the remaining path — an open overlay being disabled out\n * from under itself.\n *\n * The `open` read is `untracked` so the effect never re-runs as a function of\n * `open` (no read+write cycle on the same signal); it reacts to `disabled`\n * alone. It integrates the disabled gate with the public `model()` instead of\n * wrapping the model in a parallel signal.\n *\n * Must be called from an injection context (registers an `effect`). Internal\n * core tier — no semver guarantee.\n */\nexport function forceCloseWhenDisabled(options: ForceCloseWhenDisabledOptions): void {\n // @sanctioned-effect(untracked-read): the `open` read is untracked, so the\n // effect reacts to `disabled` alone and never cycles on the signal it writes.\n effect(() => {\n if (options.disabled() && untracked(options.open)) {\n options.onForceClose();\n options.open.set(false);\n }\n });\n}\n","import { isHoverCapablePointer } from 'forty-cdk/core';\nimport type { FloatingSide } from '../floating/floating';\n\n/**\n * Pointer-grace (\"safe triangle\") helper.\n *\n * When a mouse leaves a submenu trigger heading toward the submenu content,\n * a naive \"close on pointer-leave\" would dismiss the submenu the moment the\n * cursor crosses the gap between the trigger and the content. The fix native\n * desktop menus use is a *safe triangle*: a polygon drawn\n * from the cursor's exit point to the near edge of the submenu content. While\n * the pointer stays inside that polygon it is assumed to be travelling toward\n * the submenu, so the close is held off.\n *\n * This module keeps no Angular DI surface — the geometry is pure functions\n * (unit-tested in `pointer-grace.spec.ts`) and {@link attachPointerGrace} is a\n * plain `addEventListener` wrapper returning a cleanup, wired by the directive\n * through its `DestroyRef`. The DOM-measured inputs (cursor position, content\n * rect, resolved side) are supplied by the caller, so the geometry stays\n * testable without faking layout.\n */\n\n/** A point in client (viewport) coordinates. */\nexport interface Point {\n readonly x: number;\n readonly y: number;\n}\n\n/** The subset of `DOMRect` the grace polygon needs. */\nexport interface GraceRect {\n readonly top: number;\n readonly right: number;\n readonly bottom: number;\n readonly left: number;\n}\n\n/**\n * Resolves which side a submenu actually rendered on by comparing the\n * geometry of the trigger and content rects, independent of any requested\n * placement. Picks the axis (horizontal vs vertical) with the larger\n * centre-to-centre separation, then the direction along it.\n *\n * This is the load-bearing fix for the safe-triangle: `injectFloating` only\n * writes the resolved `data-side` inside the async `computePosition().then()`,\n * so on the first hover-open it is still `undefined` and a `flip` near a\n * viewport edge would have armed the grace polygon toward the *requested*\n * side. Deriving the side from the live rects at arm time reflects the real\n * placement even before positioning settles.\n *\n * @param trigger Sub-trigger rect (client coords), from `getBoundingClientRect`.\n * @param content Submenu content rect (client coords), from `getBoundingClientRect`.\n */\nexport function resolveGraceSide(trigger: GraceRect, content: GraceRect): FloatingSide {\n const triggerCenterX = (trigger.left + trigger.right) / 2;\n const triggerCenterY = (trigger.top + trigger.bottom) / 2;\n const contentCenterX = (content.left + content.right) / 2;\n const contentCenterY = (content.top + content.bottom) / 2;\n const dx = contentCenterX - triggerCenterX;\n const dy = contentCenterY - triggerCenterY;\n if (Math.abs(dx) >= Math.abs(dy)) {\n return dx >= 0 ? 'right' : 'left';\n }\n return dy >= 0 ? 'bottom' : 'top';\n}\n\n/** An ordered list of vertices describing a simple (non-self-intersecting) polygon. */\nexport type Polygon = readonly Point[];\n\n/**\n * Pixels the cursor apex is pulled *back* (away from the content) when the\n * polygon is built, so the exit point sits reliably inside the polygon even\n * after sub-pixel rounding of the pointer-leave coordinates.\n */\nconst GRACE_BLEED_PX = 5;\n\n/**\n * Standard even-odd ray-casting point-in-polygon test. Returns `true` when\n * {@link point} lies inside {@link polygon}. Points exactly on an edge are\n * reported inconsistently (as with any ray-cast) — that is acceptable here\n * because the bleed keeps the cursor apex strictly inside and the close path\n * is delay-guarded, so a single ambiguous edge sample never decides the\n * outcome.\n */\nexport function isPointInPolygon(point: Point, polygon: Polygon): boolean {\n let inside = false;\n for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {\n const vi = polygon[i]!;\n const vj = polygon[j]!;\n const intersects =\n vi.y > point.y !== vj.y > point.y &&\n point.x < ((vj.x - vi.x) * (point.y - vi.y)) / (vj.y - vi.y) + vi.x;\n if (intersects) {\n inside = !inside;\n }\n }\n return inside;\n}\n\n/**\n * Builds the safe-triangle polygon for a submenu opening on {@link side}.\n *\n * The polygon is a pentagon: the (bleeded) cursor apex plus the four corners\n * of the content rect, ordered so the cursor is adjacent to the two corners of\n * the content edge *nearest* the trigger. That shape covers both the triangle\n * the pointer travels through and the content itself, so the pointer is \"in\n * the grace area\" right up until it reaches the content.\n *\n * @param cursor Pointer position (client coords) captured at pointer-leave.\n * @param rect Submenu content rect (client coords), from `getBoundingClientRect`.\n * @param side Resolved side the content actually rendered on, from {@link resolveGraceSide}.\n */\nexport function buildSubmenuGracePolygon(\n cursor: Point,\n rect: GraceRect,\n side: FloatingSide,\n): Polygon {\n const { top, right, bottom, left } = rect;\n switch (side) {\n // Content to the right; near edge = content's left edge.\n case 'right':\n return [\n { x: cursor.x - GRACE_BLEED_PX, y: cursor.y },\n { x: left, y: top },\n { x: right, y: top },\n { x: right, y: bottom },\n { x: left, y: bottom },\n ];\n // Content to the left; near edge = content's right edge.\n case 'left':\n return [\n { x: cursor.x + GRACE_BLEED_PX, y: cursor.y },\n { x: right, y: top },\n { x: left, y: top },\n { x: left, y: bottom },\n { x: right, y: bottom },\n ];\n // Content below; near edge = content's top edge.\n case 'bottom':\n return [\n { x: cursor.x, y: cursor.y - GRACE_BLEED_PX },\n { x: left, y: top },\n { x: left, y: bottom },\n { x: right, y: bottom },\n { x: right, y: top },\n ];\n // Content above; near edge = content's bottom edge.\n case 'top':\n return [\n { x: cursor.x, y: cursor.y + GRACE_BLEED_PX },\n { x: left, y: bottom },\n { x: left, y: top },\n { x: right, y: top },\n { x: right, y: bottom },\n ];\n }\n}\n\n/** Options for {@link attachPointerGrace}. */\nexport interface PointerGraceOptions {\n /**\n * Which pointer moves the polygon tracks; a move it rejects is ignored.\n * Defaults to `isHoverCapablePointer` (mouse only), the menu family's hover\n * vocabulary. A caller whose trigger also opens on pen hover passes\n * `isNonTouchPointer`, so the pen that opened the surface can close it.\n */\n readonly tracksPointer?: (event: Pick<PointerEvent, 'pointerType'>) => boolean;\n readonly exitsOutOfRange?: boolean;\n}\n\n/**\n * Attaches a document-level `pointermove` listener that calls {@link onExit}\n * on every tracked move outside {@link polygon}, until the returned cleanup\n * disarms it. With {@link PointerGraceOptions.exitsOutOfRange}, a tracked\n * `pointerout` with no `relatedTarget` (the pointer left the document, or a pen\n * left the digitizer's hover range) is an exit too. The caller arms this on a\n * trigger pointer-leave and disarms it once the pointer reaches the content,\n * the grace window elapses, or the surface is otherwise resolved.\n *\n * Moves {@link PointerGraceOptions.tracksPointer} rejects are ignored: touch\n * opens by tap, never by hover, so a touch move has no safe triangle to leave.\n *\n * Static-polygon assumption: {@link polygon} is captured once at arm time and\n * never re-measured for the lifetime of this listener. If the submenu content\n * repositions (a flip, a scroll, a resize) while the grace window is open, the\n * polygon goes stale and no longer matches the content's live rect. This is an\n * accepted trade-off: the grace window is short (a single pointer traversal\n * from trigger to content) and is itself delay-guarded downstream, so a\n * mid-window reposition is out of scope. Callers that need re-measurement\n * should re-arm (call the cleanup, then re-attach with a fresh polygon) rather\n * than expecting this handler to track layout.\n *\n * @returns A cleanup that aborts the listener's `AbortSignal`. Idempotent —\n * safe to store and call from a `DestroyRef` hook after an earlier disarm.\n */\nexport function attachPointerGrace(\n doc: Document,\n polygon: Polygon,\n onExit: () => void,\n options: PointerGraceOptions = {},\n): () => void {\n const tracksPointer = options.tracksPointer ?? isHoverCapablePointer;\n const onMove = (event: PointerEvent): void => {\n if (!tracksPointer(event)) {\n return;\n }\n if (!isPointInPolygon({ x: event.clientX, y: event.clientY }, polygon)) {\n onExit();\n }\n };\n const controller = new AbortController();\n doc.addEventListener('pointermove', onMove, { signal: controller.signal });\n if (options.exitsOutOfRange) {\n const onOut = (event: PointerEvent): void => {\n if (tracksPointer(event) && event.relatedTarget === null) {\n onExit();\n }\n };\n doc.addEventListener('pointerout', onOut, { signal: controller.signal });\n }\n return () => controller.abort();\n}\n","import { isNonTouchPointer } from 'forty-cdk/core';\n\nimport type { FloatingSide } from '../floating/floating';\nimport {\n attachPointerGrace,\n buildSubmenuGracePolygon,\n type Point,\n resolveGraceSide,\n} from '../pointer-grace/pointer-grace';\n\n/**\n * Inputs for {@link createHoverSurfaceState}.\n */\nexport interface HoverSurfaceOptions {\n /** The registered trigger, measured to orient the grace polygon. */\n readonly trigger: () => HTMLElement | null;\n /** The registered content the grace polygon bridges toward. */\n readonly content: () => HTMLElement | null;\n /** Side the grace polygon assumes when no trigger is registered to measure. */\n readonly side: () => FloatingSide;\n /** Closes the surface once no keep-alive source is active. */\n readonly close: () => void;\n}\n\n/**\n * Keep-alive bookkeeping of a hover-scheduled overlay, returned by\n * {@link createHoverSurfaceState}.\n */\nexport interface HoverSurfaceState {\n /** Whether the trigger holds focus. */\n triggerFocused(): boolean;\n /** Whether the trigger or the content holds focus. */\n focused(): boolean;\n /** The pointer entered the trigger: marks it hovered and disarms the grace. */\n enterTrigger(): void;\n /** The pointer left the trigger: clears its hover, leaving the close to the caller. */\n leaveTrigger(): void;\n /** The trigger received focus. */\n focusTrigger(): void;\n /** The trigger lost focus: closes when nothing else keeps the surface alive. */\n blurTrigger(): void;\n /** The pointer entered the content: marks it hovered and disarms the grace. */\n enterContent(): void;\n /** The pointer left the content: closes when nothing else keeps the surface alive. */\n leaveContent(): void;\n /** Focus entered the content. */\n focusContent(): void;\n /** Focus left the content: closes when nothing else keeps the surface alive. */\n blurContent(): void;\n /** The trigger unmounted: clears its hover and focus and disarms the grace. */\n resetTrigger(): void;\n /** The content unmounted: clears its hover and focus and disarms the grace. */\n resetContent(): void;\n /** Closes unless the trigger or the content is hovered or focused. */\n closeIfInactive(): void;\n /**\n * Arms a pointer-grace polygon from `cursor` toward the content, so the\n * pointer can cross the gap without closing. Leaving it disarms the grace and\n * closes when nothing else keeps the surface alive. Without registered\n * content it closes the same way at once.\n */\n armGrace(cursor: Point): void;\n /** Detaches an armed grace polygon. Safe when none is armed. */\n disarmGrace(): void;\n}\n\n/**\n * Shared keep-alive state for Tooltip and Hover-card: which side of the\n * overlay is hovered or focused, and the pointer-grace bridge between them.\n * Each `reset*` clears one side when its element unmounts, since an element\n * removed under the pointer never reports `pointerleave` or `blur`.\n *\n * Internal core tier — exported from `forty-cdk/core-overlay` for the\n * library's own entry points, with no semver guarantee.\n */\nexport function createHoverSurfaceState(options: HoverSurfaceOptions): HoverSurfaceState {\n let triggerHovered = false;\n let triggerFocused = false;\n let contentHovered = false;\n let contentFocused = false;\n let detachGrace: (() => void) | null = null;\n\n function disarmGrace(): void {\n if (detachGrace) {\n detachGrace();\n detachGrace = null;\n }\n }\n\n function closeIfInactive(): void {\n if (triggerHovered || triggerFocused || contentHovered || contentFocused) {\n return;\n }\n options.close();\n }\n\n function armGrace(cursor: Point): void {\n const content = options.content();\n if (!content) {\n closeIfInactive();\n return;\n }\n const rect = content.getBoundingClientRect();\n const trigger = options.trigger();\n const side = trigger ? resolveGraceSide(trigger.getBoundingClientRect(), rect) : options.side();\n const polygon = buildSubmenuGracePolygon(cursor, rect, side);\n disarmGrace();\n detachGrace = attachPointerGrace(\n content.ownerDocument,\n polygon,\n () => {\n disarmGrace();\n closeIfInactive();\n },\n { tracksPointer: isNonTouchPointer, exitsOutOfRange: true },\n );\n }\n\n return {\n triggerFocused: () => triggerFocused,\n focused: () => triggerFocused || contentFocused,\n enterTrigger: () => {\n triggerHovered = true;\n disarmGrace();\n },\n leaveTrigger: () => {\n triggerHovered = false;\n },\n focusTrigger: () => {\n triggerFocused = true;\n },\n blurTrigger: () => {\n triggerFocused = false;\n closeIfInactive();\n },\n enterContent: () => {\n contentHovered = true;\n disarmGrace();\n },\n leaveContent: () => {\n contentHovered = false;\n closeIfInactive();\n },\n focusContent: () => {\n contentFocused = true;\n },\n blurContent: () => {\n contentFocused = false;\n closeIfInactive();\n },\n resetTrigger: () => {\n triggerHovered = false;\n triggerFocused = false;\n disarmGrace();\n },\n resetContent: () => {\n contentHovered = false;\n contentFocused = false;\n disarmGrace();\n },\n closeIfInactive,\n armGrace,\n disarmGrace,\n };\n}\n","import { DOCUMENT, Injectable, PLATFORM_ID, inject } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\n\nimport {\n composedContains,\n composedParentElement,\n MODAL_EXEMPT_ATTRIBUTE,\n MODAL_PEER_ATTRIBUTE,\n} from 'forty-cdk/core';\n\ninterface SnapshotEntry {\n readonly el: HTMLElement;\n readonly hadInert: boolean;\n readonly prevAriaHidden: string | null;\n}\n\nexport interface InertSiblingsHandle {\n /** Pop this owner off the stack and recompute. */\n deactivate(): void;\n /** Whether this handle is still on the stack. */\n readonly isActive: boolean;\n}\n\ninterface RootState {\n readonly root: HTMLElement;\n readonly stack: HTMLElement[];\n appliedSnapshot: SnapshotEntry[];\n observer: MutationObserver | null;\n}\n\ntype PeerAnchors = readonly Element[] | 'always';\n\n/**\n * Marks every direct child of a **root element** (default `document.body`,\n * or a positioned container when a region-scoped modal passes one)\n * other than the topmost active owner (and any peer of that owner) as `inert` and\n * `aria-hidden=\"true\"` while at least one owner is active on that root.\n * Restores each touched element to its exact prior state once the last\n * owner deactivates.\n *\n * `aria-modal=\"true\"` alone is insufficient: Safari with VoiceOver, among other combinations, still\n * announces siblings of an aria-modal node unless the rest of the document is explicitly hidden.\n *\n * **Stacking.** Each root keeps its own owner stack, snapshot and `MutationObserver`, so a\n * `document.body` root and a container root are fully independent. The element-level outcome is\n * recomputed from the current topmost owner whenever the stack changes: the previous outcome is\n * reverted to its snapshot first, then a fresh one is applied. Closing owners out of LIFO order\n * therefore still leaves a coherent document, and full restoration runs when the stack empties.\n *\n * **Portals.** The owner need not be a direct child of the root — the root-level child that is an\n * ancestor of the owner is resolved and its subtree excluded, so an in-place dialog keeps its\n * enclosing app shell interactive. That walk climbs the composed tree, so an owner rendered inside\n * a shadow root still resolves to the root-level child hosting it.\n *\n * **Peers.** An overlay registered through {@link InertSiblingsStack.registerPeer} is excluded from\n * the snapshot only while it belongs to the topmost owner of the root it sits in, so the peer of a\n * background modal is inerted again under a nested one. The stack reflects that state as\n * `data-for-modal-peer` on the registered host. An element carrying the attribute without being\n * registered (a backdrop) is excluded under every owner, as is one carrying\n * {@link MODAL_EXEMPT_ATTRIBUTE}, which additionally opts out of the dismissible layer.\n *\n * **Late siblings.** While any owner is active, a `MutationObserver` inerts each newly added\n * sibling under the same rules, so an element portaled to the root after activation is isolated and\n * restored too.\n *\n * SSR: every operation is a no-op on the server, since `activate()` is only ever called from\n * `afterNextRender`.\n */\n@Injectable({ providedIn: 'root' })\nexport class InertSiblingsStack {\n readonly #document = inject(DOCUMENT);\n readonly #isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n readonly #roots = new Map<HTMLElement, RootState>();\n readonly #peers = new Map<HTMLElement, PeerAnchors>();\n\n /**\n * Push `owner` onto the inert-siblings stack for `root` (default\n * `document.body`) and (re)apply the isolation outcome for the new topmost\n * owner. Returns a handle whose `deactivate()` pops this specific owner —\n * order-safe, so closing out of LIFO order works.\n *\n * When `root` is a positioned container (e.g. a region-scoped modal), only\n * that container's other children are inerted; body siblings outside the\n * container stay fully interactive.\n */\n activate(owner: HTMLElement, root: HTMLElement = this.#document.body): InertSiblingsHandle {\n if (!this.#isBrowser) {\n return {\n deactivate: () => {},\n get isActive(): boolean {\n return false;\n },\n };\n }\n const state = this.#stateFor(root);\n this.#revertAppliedSnapshot(state);\n if (state.stack.length === 0) {\n this.#startObserving(state);\n }\n state.stack.push(owner);\n this.#applyForCurrentTopmost(state);\n this.#syncPeerAttributes();\n\n let active = true;\n return {\n get isActive(): boolean {\n return active;\n },\n deactivate: (): void => {\n if (!active) {\n return;\n }\n active = false;\n const idx = state.stack.indexOf(owner);\n if (idx === -1) {\n return;\n }\n this.#revertAppliedSnapshot(state);\n state.stack.splice(idx, 1);\n if (state.stack.length > 0) {\n this.#applyForCurrentTopmost(state);\n } else {\n this.#stopObserving(state);\n this.#roots.delete(root);\n }\n this.#syncPeerAttributes();\n },\n };\n }\n\n /**\n * Whether an overlay anchored to `anchor` should be left interactive over\n * the active modal — i.e. treated as a peer of the topmost owner instead of\n * inerted. Returns `true` only while at least one owner is active AND\n * `anchor` lives inside the current protected root for any active root, or\n * inside a registered peer that does, which means the overlay was opened\n * from within a modal (e.g. a Select / DropdownMenu opened from a form inside\n * a Dialog, or a submenu opened from that DropdownMenu).\n *\n * Returns `false` when no owner is active — so an overlay opened with no\n * modal present is never pre-marked, and a modal opened later inerts it like\n * any other background sibling — and when `anchor` sits in an already-inerted\n * background subtree (a toast or a tooltip anchored to a backdrop element).\n * SSR-safe: on the server the roots map is always empty (no owner\n * activates), so this returns `false`.\n */\n ownsAnchor(anchor: Element): boolean {\n for (const state of this.#roots.values()) {\n const protectedRoot = this.#currentProtectedRoot(state);\n if (protectedRoot !== null && this.#owns(protectedRoot, [anchor], new Set())) {\n return true;\n }\n }\n return false;\n }\n\n registerPeer(host: HTMLElement, anchors: PeerAnchors): () => void {\n if (!this.#isBrowser) {\n return () => {};\n }\n this.#peers.set(host, anchors);\n this.#reapplyAll();\n return () => {\n if (this.#peers.get(host) !== anchors) {\n return;\n }\n this.#peers.delete(host);\n host.removeAttribute(MODAL_PEER_ATTRIBUTE);\n this.#reapplyAll();\n };\n }\n\n #stateFor(root: HTMLElement): RootState {\n let state = this.#roots.get(root);\n if (!state) {\n state = { root, stack: [], appliedSnapshot: [], observer: null };\n this.#roots.set(root, state);\n }\n return state;\n }\n\n #applyForCurrentTopmost(state: RootState): void {\n const protectedRoot = this.#currentProtectedRoot(state);\n if (!protectedRoot) {\n return;\n }\n\n for (const child of Array.from(state.root.children)) {\n this.#inertChild(child, protectedRoot, state);\n }\n }\n\n #inertChild(child: Element, protectedRoot: HTMLElement, state: RootState): void {\n if (!(child instanceof HTMLElement)) {\n return;\n }\n if (child === protectedRoot || child.hasAttribute(MODAL_EXEMPT_ATTRIBUTE)) {\n return;\n }\n const anchors = this.#peers.get(child);\n const exempt =\n anchors === undefined\n ? child.hasAttribute(MODAL_PEER_ATTRIBUTE)\n : anchors === 'always' || this.#owns(protectedRoot, anchors, new Set());\n if (exempt) {\n return;\n }\n if (state.appliedSnapshot.some((entry) => entry.el === child)) {\n return;\n }\n\n state.appliedSnapshot.push({\n el: child,\n hadInert: child.hasAttribute('inert'),\n prevAriaHidden: child.getAttribute('aria-hidden'),\n });\n\n child.setAttribute('inert', '');\n child.setAttribute('aria-hidden', 'true');\n }\n\n #owns(\n protectedRoot: HTMLElement,\n anchors: readonly Element[],\n visited: Set<HTMLElement>,\n ): boolean {\n return anchors.some((anchor) => {\n if (composedContains(protectedRoot, anchor)) {\n return true;\n }\n for (const [peer, peerAnchors] of this.#peers) {\n if (peerAnchors === 'always' || visited.has(peer) || !composedContains(peer, anchor)) {\n continue;\n }\n visited.add(peer);\n if (this.#owns(protectedRoot, peerAnchors, visited)) {\n return true;\n }\n }\n return false;\n });\n }\n\n #reapplyAll(): void {\n for (const state of this.#roots.values()) {\n this.#revertAppliedSnapshot(state);\n this.#applyForCurrentTopmost(state);\n }\n this.#syncPeerAttributes();\n }\n\n #syncPeerAttributes(): void {\n for (const [peer, anchors] of this.#peers) {\n peer.toggleAttribute(MODAL_PEER_ATTRIBUTE, this.#isLivePeer(peer, anchors));\n }\n }\n\n #isLivePeer(peer: HTMLElement, anchors: PeerAnchors): boolean {\n if (anchors === 'always') {\n return true;\n }\n for (const state of this.#roots.values()) {\n const protectedRoot = this.#currentProtectedRoot(state);\n if (protectedRoot !== null && this.#owns(protectedRoot, anchors, new Set())) {\n return true;\n }\n }\n return false;\n }\n\n #currentProtectedRoot(state: RootState): HTMLElement | null {\n const top = state.stack[state.stack.length - 1];\n if (!top) {\n return null;\n }\n return this.#rootLevelChild(top, state.root) ?? top;\n }\n\n #startObserving(state: RootState): void {\n const win = this.#document.defaultView;\n if (state.observer || !win || typeof win.MutationObserver !== 'function') {\n return;\n }\n state.observer = new win.MutationObserver((records) => {\n const protectedRoot = this.#currentProtectedRoot(state);\n if (!protectedRoot) {\n return;\n }\n let addedPeer = false;\n for (const record of records) {\n for (const node of Array.from(record.addedNodes)) {\n if (node instanceof HTMLElement && node.parentElement === state.root) {\n addedPeer ||= this.#peers.has(node);\n this.#inertChild(node, protectedRoot, state);\n }\n }\n }\n if (addedPeer) {\n this.#syncPeerAttributes();\n }\n });\n state.observer.observe(state.root, { childList: true });\n }\n\n #stopObserving(state: RootState): void {\n state.observer?.disconnect();\n state.observer = null;\n }\n\n #revertAppliedSnapshot(state: RootState): void {\n for (const entry of state.appliedSnapshot) {\n if (!entry.hadInert) {\n entry.el.removeAttribute('inert');\n }\n if (entry.prevAriaHidden === null) {\n entry.el.removeAttribute('aria-hidden');\n } else {\n entry.el.setAttribute('aria-hidden', entry.prevAriaHidden);\n }\n }\n state.appliedSnapshot = [];\n }\n\n #rootLevelChild(el: HTMLElement, root: HTMLElement): HTMLElement | null {\n let cur: HTMLElement = el;\n let parent = composedParentElement(cur);\n while (parent && parent !== root) {\n cur = parent;\n parent = composedParentElement(cur);\n }\n return parent === root ? cur : null;\n }\n}\n","import { computed, inject, type Signal, signal, type WritableSignal } from '@angular/core';\nimport type { ReferenceElement } from '@floating-ui/dom';\n\nimport {\n adoptHostId,\n createSingleSlot,\n IdGenerator,\n type SingleSlot,\n type SingleSlotConfig,\n} from 'forty-cdk/core';\n\n/**\n * A registered overlay element whose aria-wiring id the surface exposes. Backs\n * the trigger / content / list / input slots the overlay controllers used to\n * each hand-copy: the register step adopts a consumer-set static `id` into the\n * seeded id signal (so external `aria-labelledby` / label `for` references keep\n * resolving), the unregister step clears the element only when the same node\n * deregisters.\n *\n * Construct through {@link injectIdentifiedSlot} so the id signal is seeded from\n * the shared {@link IdGenerator} at the controller's construction.\n *\n * @typeParam E Concrete element type registered here (e.g. `HTMLInputElement`\n * for the combobox input). Defaults to `HTMLElement`.\n */\nexport class IdentifiedElementSlot<E extends HTMLElement = HTMLElement> {\n readonly #el = signal<E | null>(null);\n readonly #id: WritableSignal<string>;\n\n /** The registered element, or `null` while nothing is mounted. */\n readonly element: Signal<E | null> = this.#el.asReadonly();\n\n /** The element's aria-wiring id — the generated fallback until a static id is adopted. */\n readonly id: WritableSignal<string>;\n\n constructor(id: WritableSignal<string>) {\n this.#id = id;\n this.id = id;\n }\n\n /** Register the element, adopting a consumer-set static `id` into the id signal. */\n register(el: E): void {\n adoptHostId(el, this.#id);\n this.#el.set(el);\n }\n\n /** Deregister the element (no-op unless the same node registered). */\n unregister(el: E): void {\n if (this.#el() === el) {\n this.#el.set(null);\n }\n }\n}\n\n/**\n * A registered overlay element whose aria-wiring id the controller does not\n * own — the combobox trigger, which host-binds its own. Same register/unregister\n * identity guard as {@link IdentifiedElementSlot}, and it mints nothing, so the\n * shared {@link IdGenerator} counter does not move for the anatomies that never\n * mount here.\n */\nexport class ElementSlot<E extends HTMLElement = HTMLElement> {\n readonly #el = signal<E | null>(null);\n\n /** The registered element, or `null` while nothing is mounted. */\n readonly element: Signal<E | null> = this.#el.asReadonly();\n\n /** Register the element. */\n register(el: E): void {\n this.#el.set(el);\n }\n\n /** Deregister the element (no-op unless the same node registered). */\n unregister(el: E): void {\n if (this.#el() === el) {\n this.#el.set(null);\n }\n }\n}\n\n/**\n * The floating-ui anchor slot shared by the listbox overlays, combobox and the\n * date pickers. An explicit `[for…Anchor]` registers here; the resolved\n * anchor prefers it and otherwise walks the fallback chain (field anchor,\n * trigger, input) so a primitive without an explicit anchor keeps its\n * behaviour.\n *\n * Registrations are stacked like a core `createSingleSlot`: the newest\n * anchor is the one used, unregistering it restores the previous survivor,\n * and a second anchor still registered once the change-detection pass\n * settles warns in dev mode. A structural swap that mounts the replacement\n * anchor before destroying the outgoing one is therefore not reported.\n */\nexport class AnchorSlot {\n readonly #slot: SingleSlot<HTMLElement>;\n\n /** The explicitly-registered anchor element, or `null`. */\n readonly element: Signal<HTMLElement | null>;\n\n constructor(config: SingleSlotConfig) {\n this.#slot = createSingleSlot<HTMLElement>(config);\n this.element = this.#slot.value;\n }\n\n /**\n * Register the explicit anchor, making it the one the overlay positions\n * against. Registering the current anchor again is a no-op.\n */\n register(el: HTMLElement): void {\n if (this.element() === el) {\n return;\n }\n this.#slot.register(el);\n }\n\n /** Deregister the anchor (no-op unless the same node registered). */\n unregister(el: HTMLElement): void {\n this.#slot.unregister(el);\n }\n\n /**\n * Build the resolved-anchor signal: the explicit anchor, otherwise the first\n * non-null fallback in order (field anchor → trigger → input). Decoupled from\n * those elements so they keep driving their own aria-wiring / keyboard\n * interaction regardless of where the surface paints.\n */\n resolve(...fallbacks: Signal<HTMLElement | null>[]): Signal<ReferenceElement | null> {\n return computed<ReferenceElement | null>(() => {\n const explicit = this.element();\n if (explicit !== null) {\n return explicit;\n }\n for (const fallback of fallbacks) {\n const el = fallback();\n if (el !== null) {\n return el;\n }\n }\n return null;\n });\n }\n}\n\n/**\n * A writable `<idPrefix>-<suffix>` id signal off the shared {@link IdGenerator},\n * for a controller that owns the element side itself — the menu overlay's opener\n * registry keeps one seed id across many openers, so it needs the id without a\n * slot's single-element storage.\n *\n * Call it from an injection context — a directive's field initializer, or a\n * controller constructed from one — so the generator resolves and slot id\n * sequences stay deterministic across renders (hydration relies on it).\n */\nexport function injectSlotId(idPrefix: string, suffix: string): WritableSignal<string> {\n return signal(inject(IdGenerator).next(`${idPrefix}-${suffix}`));\n}\n\n/**\n * A slot whose element registration adopts a consumer-set static `id`. Seeds the\n * id signal with `<idPrefix>-<suffix>` off the shared {@link IdGenerator}, so it\n * carries the same injection-context requirement as {@link injectSlotId}.\n *\n * @typeParam E Concrete element type the slot registers. Defaults to\n * `HTMLElement`.\n */\nexport function injectIdentifiedSlot<E extends HTMLElement = HTMLElement>(\n idPrefix: string,\n suffix: string,\n): IdentifiedElementSlot<E> {\n return new IdentifiedElementSlot<E>(injectSlotId(idPrefix, suffix));\n}\n\n/**\n * A slot for an element whose aria-wiring id the controller does not own.\n * Depends on nothing, so it needs no injection context.\n *\n * @typeParam E Concrete element type the slot registers. Defaults to\n * `HTMLElement`.\n */\nexport function elementSlot<E extends HTMLElement = HTMLElement>(): ElementSlot<E> {\n return new ElementSlot<E>();\n}\n\n/**\n * The floating-ui anchor slot with the settled single-anchor warning + fallback\n * chain. Must be called in an injection context, which a directive field\n * initializer is, because the dev-mode duplicate warning runs on an `effect`.\n *\n * @param config Names the root and its anchor piece in the duplicate warning.\n */\nexport function anchorSlot(config: SingleSlotConfig): AnchorSlot {\n return new AnchorSlot(config);\n}\n","import { linkedSignal, type Signal, untracked, type WritableSignal } from '@angular/core';\n\n/**\n * Records the reason of an overlay's most recent close, and clears it whenever the overlay's open\n * source turns `true`, whoever wrote it: an owner's own open path, an APG key, or a consumer's\n * `[(open)]` binding. The shared content pieces read it to skip their return-focus on a `'tab'`\n * close (so Tab advances focus out of the surface instead of snapping back to the trigger).\n *\n * `close` records the reason before running the close, so a synchronous `openChange` handler\n * already reads it, and settles it against the closed state before returning. A later read that\n * finds the source changed but closed again therefore knows an open happened in between, even one\n * nothing read during.\n *\n * Generic over the reason union so every overlay controller shares one implementation —\n * `OverlayController` (and through it `MenuOverlay`, the listbox overlays, combobox and\n * `[forMenubar]`'s multiplexed menu context) and `[forPopover]` compose it. Plain class (no\n * `inject()`) so each composes it instead of hand-copying the signal.\n *\n * @typeParam Reason Close-reason union owned by the controller.\n */\nexport class CloseReasonState<Reason> {\n readonly #reason: WritableSignal<Reason | null>;\n\n /**\n * Reason of the most recent close, or `null` while the overlay is open / has never closed.\n */\n readonly reason: Signal<Reason | null>;\n\n constructor(isOpen: () => boolean) {\n this.#reason = linkedSignal<boolean, Reason | null>({\n source: isOpen,\n computation: (open, previous) => (open || !previous?.source ? null : previous.value),\n });\n this.reason = this.#reason.asReadonly();\n }\n\n close(reason: Reason, apply: () => void): void {\n this.#reason.set(reason);\n apply();\n untracked(this.#reason);\n }\n}\n","import { type Signal, signal } from '@angular/core';\n\n/**\n * Tracks where an overlay's initial focus should land on the next open and\n * whether that one programmatic move should reflect `data-highlighted` on the\n * focused item.\n *\n * `target` is set by triggers before they flip the overlay open (ArrowDown →\n * `'first'`, ArrowUp → `'last'`, or a primitive-specific `'selected'`).\n * `highlightOnNextFocus` is armed per open via {@link prepareOpen}: a keyboard\n * activation highlights the focused item per the APG menu-button pattern; a\n * pointer activation (click, hover-after-open) suppresses the highlight so a\n * mouse-opened surface doesn't read as \"preselected\". {@link consumeHighlight}\n * reads the flag once and re-arms it to `true`, so the suppression applies only\n * to the single initial-focus move that follows an open.\n *\n * Generic over the focus-target union so every overlay controller reuses the\n * same one-shot protocol: `MenuOverlay` / `[forMenubar]`'s multiplexed menu\n * context keep `'first' | 'last'` (the default), while the listbox overlays and\n * combobox widen it with `'selected'`. Plain class (no `inject()`) so each\n * controller composes the same implementation instead of hand-copying it.\n *\n * @typeParam Focus Initial-focus target union. Defaults to `'first' | 'last'`.\n */\nexport class InitialFocusState<Focus = 'first' | 'last'> {\n readonly #target: ReturnType<typeof signal<Focus>>;\n #highlightOnNextFocus = true;\n\n /** Where focus should land when the overlay mounts. */\n readonly target: Signal<Focus>;\n\n /**\n * @param defaultTarget Initial focus target before any open. Defaults to\n * `'first'`, valid for the default `'first' | 'last'` union.\n */\n constructor(defaultTarget: Focus = 'first' as Focus) {\n this.#target = signal<Focus>(defaultTarget);\n this.target = this.#target.asReadonly();\n }\n\n setTarget(target: Focus): void {\n this.#target.set(target);\n }\n\n /**\n * Arms the state for the next open: records the initial-focus target and\n * whether the upcoming initial-focus move should highlight the focused item\n * (`true` for keyboard activation, `false` for pointer activation).\n */\n prepareOpen(target: Focus, highlight: boolean): void {\n this.#target.set(target);\n this.#highlightOnNextFocus = highlight;\n }\n\n /**\n * Returns whether the next initial-focus move should highlight, then re-arms\n * the flag to `true` so the suppression is one-shot.\n */\n consumeHighlight(): boolean {\n const highlight = this.#highlightOnNextFocus;\n this.#highlightOnNextFocus = true;\n return highlight;\n }\n}\n","import type { OutputEmitterRef, Signal, WritableSignal } from '@angular/core';\n\nimport {\n emitVetoableNativeEvent,\n injectVetoableEmitter,\n type VetoableEvent,\n type VetoableNativeEvent,\n} from 'forty-cdk/core';\nimport { CloseReasonState } from './close-reason-state';\nimport { IdentifiedElementSlot, injectSlotId } from './element-registry';\nimport { InitialFocusState } from './initial-focus-state';\n\n/**\n * The dismiss / auto-focus outputs an overlay controller forwards to. Each\n * primitive owns the `output()` instances (they must be declared as class-field\n * initializers for the Angular compiler to detect them); the controller only\n * emits through them, so the shared dismiss pipeline lives in one place.\n */\nexport interface OverlayEmitTargets {\n readonly escapeKeyDown: OutputEmitterRef<VetoableNativeEvent<KeyboardEvent>>;\n readonly pointerDownOutside: OutputEmitterRef<VetoableNativeEvent<PointerEvent>>;\n readonly focusOutside: OutputEmitterRef<VetoableNativeEvent<FocusEvent>>;\n readonly interactOutside: OutputEmitterRef<VetoableNativeEvent<PointerEvent | FocusEvent>>;\n readonly autoFocusOnOpen: OutputEmitterRef<VetoableEvent>;\n readonly autoFocusOnClose: OutputEmitterRef<VetoableEvent>;\n}\n\n/**\n * One of the two element sides a surface has — the trigger focus returns to, and\n * the content that mounts. Both are supplied by the composing controller,\n * because neither is the same object twice in the library: a listbox overlay's\n * trigger is a single {@link IdentifiedElementSlot}, a menu overlay's is a\n * registry of openers resolving one active element and its id, and\n * `[forMenubar]`'s multiplexed context resolves both sides off whichever bar\n * trigger is — or was last — active. All of them answer the same four\n * questions, which is all the shared machine asks of them.\n */\nexport interface OverlaySlot {\n /**\n * The element's aria-wiring id. Non-empty for a slot minting its own; the\n * menubar's multiplexed sources resolve `''` until a trigger has been active,\n * which `[forMenuContent]` emits as no attribute rather than as `id=\"\"`.\n */\n readonly id: Signal<string>;\n /** The registered element, or `null` while none is registered. */\n readonly element: Signal<HTMLElement | null>;\n /** Register the element. */\n register(el: HTMLElement): void;\n /** Deregister the element. */\n unregister(el: HTMLElement): void;\n}\n\n/**\n * Per-transition options forwarded verbatim to the `onOpen` / `onClose` hooks so\n * a host directive can react to *how* a transition was driven without\n * re-deriving it from outside the pipeline.\n */\nexport interface OverlayTransitionOptions {\n /**\n * When `true`, the transition is pointer-driven (hover) and the surface's\n * imperative focus move must be suppressed — an open must not pull focus into\n * the surface, and a close must not return focus to the trigger. Defaults to\n * `false`, so keyboard / click / programmatic transitions move focus as usual.\n */\n readonly suppressFocusMoves?: boolean;\n}\n\n/** Per-call options for {@link OverlayController.open}. */\nexport interface OverlayOpenOptions {\n /**\n * Arms the initial-focus state's one-shot highlight flag for this open —\n * `true` for a keyboard activation, `false` for a pointer one. Omit it\n * entirely on a surface that does not reflect `data-highlighted` on its\n * initial focus, so the flag is left untouched.\n */\n readonly highlight?: boolean;\n /** Transition options handed verbatim to the `onOpen` hook. */\n readonly transition?: OverlayTransitionOptions;\n}\n\n/**\n * What {@link OverlayController.open} did, so a composing controller can run its\n * own tail without re-reading the open model (which the call may just have\n * written).\n *\n * - `'blocked'` — the control is disabled; nothing happened.\n * - `'opened'` — the surface transitioned from closed to open.\n * - `'already-open'` — the surface was already mounted, so no state transition\n * (and therefore no `openChange` emit) happened. The initial-focus target and\n * the close reason were still re-armed.\n */\nexport type OverlayOpenOutcome = 'blocked' | 'opened' | 'already-open';\n\n/**\n * Construction-time wiring for {@link OverlayController}. Plain signals and\n * callbacks only — the controller never imports a primitive's context token,\n * mirroring `injectOverlayShell`, so it stays orthogonal to each root's surface.\n *\n * @typeParam Focus Initial-focus union owned by the composing controller.\n * @typeParam CloseReason Close-reason union owned by the composing controller.\n */\nexport interface OverlayControllerDeps<Focus, CloseReason> {\n /** Id-generator prefix base, e.g. `'for-select'` (suffixed with `-trigger` / `-content`). */\n readonly idPrefix: string;\n /**\n * Builds the trigger side, from a factory minting the seeded\n * `<idPrefix>-trigger` id. Call the factory exactly once for a trigger that\n * owns an id, and **not at all** for one whose id lives elsewhere — the\n * combobox's lives on its input, the menubar's on each bar trigger — because\n * the `IdGenerator` counter is per application, so an id nothing ever emits\n * still shifts every id minted after it.\n *\n * Runs during construction, ahead of {@link createContent}, so the\n * trigger-then-content minting order is fixed here rather than per caller —\n * hydration's id adoption depends on both renders repeating it. It may\n * `inject()`, and so may the factory.\n */\n readonly createTrigger: (mintId: () => WritableSignal<string>) => OverlaySlot;\n /**\n * Builds the content side, same contract as {@link createTrigger} and called\n * immediately after it. Optional: omitted, the controller registers its own\n * {@link IdentifiedElementSlot} over the minted `<idPrefix>-content` id, which\n * is what every surface owning its content id wants. Supply it when the id\n * comes from somewhere else, or when registration does more than adopt a\n * static id — `[forMenubar]` resolves the id off the active trigger and\n * records whether the surface is shared across the bar's triggers.\n */\n readonly createContent?: (mintId: () => WritableSignal<string>) => OverlaySlot;\n /** Default initial-focus target before any open. */\n readonly defaultInitialFocus: Focus;\n /** The control's effective disabled — gates `open` and `toggle`. */\n readonly disabled: Signal<boolean>;\n /** Whether Escape / outside interactions dismiss the surface. */\n readonly dismissible: Signal<boolean>;\n /** Read the control's current open state. */\n readonly isOpen: () => boolean;\n /** Write the control's open state — the open / close machine's only channel. */\n readonly setOpen: (open: boolean) => void;\n /** Dismiss / auto-focus outputs to forward to. */\n readonly emit: OverlayEmitTargets;\n /** Close reason recorded when Escape dismisses the surface. */\n readonly escapeReason: CloseReason;\n /** Close reason recorded when {@link OverlayController.toggle} closes the surface. */\n readonly programmaticReason: CloseReason;\n /**\n * Side effect run after {@link OverlayController.open} resolves an un-blocked\n * open, receiving the resolved initial-focus target and the transition\n * options. Runs on the `'already-open'` outcome too, so a pending hover-close\n * is still cancelled by an open key pressed on a mounted surface.\n */\n readonly onOpen?: (initialFocus: Focus, options: OverlayTransitionOptions) => void;\n /**\n * Side effect run after {@link OverlayController.close} flips the open state\n * to `false`, receiving the close reason and the transition options.\n */\n readonly onClose?: (reason: CloseReason, options: OverlayTransitionOptions) => void;\n /**\n * Side effect run on a user-driven dismissal — an un-vetoed Escape, or the\n * shell's implicit close after an un-vetoed outside interaction — just before\n * the close. Optional: only a form control has touched state to mark, so the\n * menu overlays pass nothing.\n */\n readonly onDismiss?: () => void;\n}\n\n/**\n * The open / close / dismiss machine every trigger-anchored overlay surface\n * runs, composed by `MenuOverlay` (the four menu roots), by\n * `ListboxOverlayController` (`[forSelect]` / `[forTimePicker]`), and by\n * `[forCombobox]` and `[forMenubar]`. It owns the initial-focus and close-reason\n * state, the `disabled`-gated open / close / toggle transitions, the four\n * outside / Escape emit forwarders, the shell's implicit `requestClose`, and the\n * two auto-focus veto pass-throughs — plus the order in which the two supplied\n * element sides mint their ids.\n *\n * It does not own the item **collection**: the menu side composes `MenuItemList`\n * separately, and the two navigate tails differ — the menu suppresses the item\n * highlight and scrolls the surface's own overflow, the listbox runs a\n * per-primitive `onNavigateFocus` and gates the move on `disabled`.\n *\n * Construct it from a directive's field initializer, or from a controller\n * constructed there: it reads that directive's `DestroyRef` for the auto-focus\n * vetoes, and the slot factories' `inject()` calls resolve through the same\n * injector.\n *\n * @typeParam Focus Initial-focus union owned by the composing controller.\n * @typeParam CloseReason Close-reason union owned by the composing controller.\n */\nexport class OverlayController<Focus, CloseReason> {\n readonly #deps: OverlayControllerDeps<Focus, CloseReason>;\n\n readonly #triggerSlot: OverlaySlot;\n readonly #contentSlot: OverlaySlot;\n\n readonly #initialFocusState: InitialFocusState<Focus>;\n readonly #closeReasonState: CloseReasonState<CloseReason>;\n\n readonly #autoFocusOnOpen: () => boolean;\n readonly #autoFocusOnClose: () => boolean;\n\n /** The trigger's stable id, adopted from a consumer-set static id when present. */\n readonly triggerId: Signal<string>;\n\n /** The content surface's stable id, adopted from a consumer-set static id when present. */\n readonly contentId: Signal<string>;\n\n /** The focusable element the surface returns focus to on close. */\n readonly trigger: Signal<HTMLElement | null>;\n\n /** The mounted content element, or `null` while the surface is closed. */\n readonly content: Signal<HTMLElement | null>;\n\n /** Where focus should land when the surface mounts. Set by triggers before flipping open. */\n readonly initialFocus: Signal<Focus>;\n\n /**\n * Reason of the most recent close, or `null` while the surface is open / has\n * never closed. Reset to `null` on every open — the content pieces read it to\n * skip their return-focus on a `'tab'` close.\n */\n readonly lastCloseReason: Signal<CloseReason | null>;\n\n constructor(deps: OverlayControllerDeps<Focus, CloseReason>) {\n this.#deps = deps;\n const mintContentId = () => injectSlotId(deps.idPrefix, 'content');\n this.#triggerSlot = deps.createTrigger(() => injectSlotId(deps.idPrefix, 'trigger'));\n this.#contentSlot = deps.createContent\n ? deps.createContent(mintContentId)\n : new IdentifiedElementSlot(mintContentId());\n this.#initialFocusState = new InitialFocusState<Focus>(deps.defaultInitialFocus);\n this.#closeReasonState = new CloseReasonState<CloseReason>(deps.isOpen);\n this.#autoFocusOnOpen = injectVetoableEmitter(deps.emit.autoFocusOnOpen);\n this.#autoFocusOnClose = injectVetoableEmitter(deps.emit.autoFocusOnClose);\n this.triggerId = this.#triggerSlot.id;\n this.contentId = this.#contentSlot.id;\n this.trigger = this.#triggerSlot.element;\n this.content = this.#contentSlot.element;\n this.initialFocus = this.#initialFocusState.target;\n this.lastCloseReason = this.#closeReasonState.reason;\n }\n\n /** Set the initial-focus target ahead of the next open. */\n setInitialFocus(target: Focus): void {\n this.#initialFocusState.setTarget(target);\n }\n\n /**\n * Reads the initial-focus state's one-shot highlight flag and re-arms it, so\n * the composing controller's initial-focus move can suppress the focused\n * item's `data-highlighted` for a pointer-driven open only.\n */\n consumeInitialHighlight(): boolean {\n return this.#initialFocusState.consumeHighlight();\n }\n\n /** Register the trigger element. */\n registerTrigger(el: HTMLElement): void {\n this.#triggerSlot.register(el);\n }\n\n /** Deregister the trigger element (no-op unless the same node registered). */\n unregisterTrigger(el: HTMLElement): void {\n this.#triggerSlot.unregister(el);\n }\n\n /** Register the mounted content element. */\n registerContent(el: HTMLElement): void {\n this.#contentSlot.register(el);\n }\n\n /** Deregister the content element (no-op unless the same node registered). */\n unregisterContent(el: HTMLElement): void {\n this.#contentSlot.unregister(el);\n }\n\n /**\n * Opens the surface when closed, closes it with the deps' programmatic reason\n * when open. Honours `disabled` on both branches — there is no distinct\n * `'trigger'` close reason for the user-initiated toggle-close path.\n */\n toggle(initialFocus: Focus, options: OverlayOpenOptions = {}): void {\n if (this.#deps.disabled()) {\n return;\n }\n if (this.#deps.isOpen()) {\n this.close(this.#deps.programmaticReason);\n } else {\n this.open(initialFocus, options);\n }\n }\n\n /**\n * Records where the initial focus should land and flips the open state,\n * which clears the close reason. Returns the {@link OverlayOpenOutcome} so a composing\n * controller can branch on an already-open surface — no state transition\n * happened there, so nothing emitted `openChange`, and a re-focus is the only\n * way an APG open key stays live on a mounted surface.\n */\n open(initialFocus: Focus, options: OverlayOpenOptions = {}): OverlayOpenOutcome {\n if (this.#deps.disabled()) {\n return 'blocked';\n }\n const alreadyOpen = this.#deps.isOpen();\n if (options.highlight === undefined) {\n this.#initialFocusState.setTarget(initialFocus);\n } else {\n this.#initialFocusState.prepareOpen(initialFocus, options.highlight);\n }\n if (!alreadyOpen) {\n this.#deps.setOpen(true);\n }\n this.#deps.onOpen?.(initialFocus, options.transition ?? {});\n return alreadyOpen ? 'already-open' : 'opened';\n }\n\n /**\n * Closes the surface, recording `reason` as the {@link lastCloseReason} the\n * content pieces read. Never gated on `disabled`: a control disabled while its\n * surface is open must still be closable.\n */\n close(reason: CloseReason, transition: OverlayTransitionOptions = {}): void {\n this.#closeReasonState.close(reason, () => this.#deps.setOpen(false));\n this.#deps.onClose?.(reason, transition);\n }\n\n /**\n * Escape on the anchored path: emit `(escapeKeyDown)`, then close when\n * un-vetoed and dismissible.\n */\n emitEscapeKeyDown(event: KeyboardEvent): void {\n const vetoed = emitVetoableNativeEvent(this.#deps.emit.escapeKeyDown, event);\n if (!vetoed && this.#deps.dismissible()) {\n // Load-bearing, not redundant: the bubble-phase Escape handler stops the\n // same keydown from reaching an *ancestor* overlay's keydown listener,\n // which is how nested overlays close one layer per Escape (see the\n // listener-phase note in `core-overlay/dismissible-layer/dismissible-layer.ts`).\n event.stopPropagation();\n this.#deps.onDismiss?.();\n this.close(this.#deps.escapeReason);\n }\n }\n\n /** Modal-path Escape forwarder: emit only; the modal shell owns the close. */\n forwardEscapeKeyDown(veto: VetoableNativeEvent<KeyboardEvent>): void {\n this.#deps.emit.escapeKeyDown.emit(veto);\n }\n\n /**\n * Outside-interaction emit forwarders. The shared `#pendingOutsideVeto` reuse\n * between the specific outside channels and the composite `interactOutside`\n * lives in `injectOverlayShell`; these only fire the matching output with the\n * veto the shell built.\n */\n emitPointerDownOutside(veto: VetoableNativeEvent<PointerEvent>): void {\n this.#deps.emit.pointerDownOutside.emit(veto);\n }\n\n /** Focus-outside emit forwarder — see {@link emitPointerDownOutside}. */\n emitFocusOutside(veto: VetoableNativeEvent<FocusEvent>): void {\n this.#deps.emit.focusOutside.emit(veto);\n }\n\n /** Composite outside-interaction emit forwarder — see {@link emitPointerDownOutside}. */\n emitInteractOutside(veto: VetoableNativeEvent<PointerEvent | FocusEvent>): void {\n this.#deps.emit.interactOutside.emit(veto);\n }\n\n /**\n * Implicit close requested by `injectOverlayShell` after an un-vetoed outside\n * interaction. The shell owns the shared `#pendingOutsideVeto` reuse between\n * the specific outside channels and the composite `interactOutside`; this\n * controller only owns the close. The open guard keeps a stale event from\n * re-closing an already-closed surface and clobbering its\n * {@link lastCloseReason} (e.g. a `'tab'` close must survive so the content\n * skips its return-focus).\n */\n requestClose(reason: CloseReason): void {\n if (!this.#deps.isOpen()) {\n return;\n }\n this.#deps.onDismiss?.();\n this.close(reason);\n }\n\n /**\n * Emits `(autoFocusOnOpen)`, returning whether the mount's focus move is\n * vetoed — by a consumer, or by the root's own destruction.\n */\n emitAutoFocusOnOpen(): boolean {\n return this.#autoFocusOnOpen();\n }\n\n /**\n * Emits `(autoFocusOnClose)`, returning whether the return-focus move is\n * vetoed — by a consumer, or by the root's own destruction.\n */\n emitAutoFocusOnClose(): boolean {\n return this.#autoFocusOnClose();\n }\n}\n","import { type Signal } from '@angular/core';\nimport type { ReferenceElement } from '@floating-ui/dom';\n\nimport {\n accessibleTextContent,\n Collection,\n firstEnabledHost,\n injectFieldAnchor,\n injectTypeahead,\n lastEnabledHost,\n type ListNavigationAction,\n nextEnabledHandle,\n resolveActiveElement,\n resolveListTypeahead,\n type SingleSlotConfig,\n type VetoableNativeEvent,\n} from 'forty-cdk/core';\nimport {\n anchorSlot,\n type AnchorSlot,\n IdentifiedElementSlot,\n} from '../overlay-controller/element-registry';\nimport {\n OverlayController,\n type OverlayEmitTargets,\n} from '../overlay-controller/overlay-controller';\nimport type { OverlayShellTabOutConfig } from '../overlay-controller/overlay-shell';\n\n/**\n * Minimal option-handle shape the controller's focus algorithm needs: a host\n * element to focus and a `disabled` signal to skip. Each primitive widens this\n * with its own per-option fields (value, label, id, posInSet, …) and registers\n * the widened handle through {@link ListboxOverlayController.registerOption}.\n */\nexport interface ListboxOverlayOptionHandle {\n readonly host: HTMLElement;\n readonly disabled: Signal<boolean>;\n}\n\n/**\n * Construction-time wiring for {@link ListboxOverlayController}. Plain signals\n * and callbacks only — the controller never imports a primitive's context\n * token, mirroring `injectOverlayShell`, so it stays orthogonal to each root's\n * surface.\n *\n * @typeParam H Primitive option-handle type.\n * @typeParam Focus Initial-focus union (identical `'first' | 'last' | 'selected'`\n * in both primitives, kept generic so each keeps its own named alias).\n * @typeParam CloseReason Close-reason union owned by the primitive.\n */\nexport interface ListboxOverlayControllerDeps<\n H extends ListboxOverlayOptionHandle,\n Focus,\n CloseReason,\n> {\n /** Id-generator prefix base, e.g. `'for-select'` (suffixed with `-trigger` / `-content`). */\n readonly idPrefix: string;\n /** Names the root and its anchor piece in the dev-mode duplicate-anchor warning. */\n readonly anchorSlot: SingleSlotConfig;\n /** Default initial-focus target when none is set explicitly. */\n readonly defaultInitialFocus: Focus;\n /** The control's effective disabled — gates open / navigate / toggle. */\n readonly effectiveDisabled: Signal<boolean>;\n /** The control's two-way `open` model — flipped by the open / close machine. */\n readonly setOpen: (open: boolean) => void;\n /** Read the control's current open state. */\n readonly isOpen: () => boolean;\n /** Dismiss / auto-focus outputs to forward to. */\n readonly emit: OverlayEmitTargets;\n /** Whether keyboard navigation wraps at the ends of the option list. */\n readonly loop: Signal<boolean>;\n /** Whether Escape / outside interactions dismiss the overlay. */\n readonly dismissible: Signal<boolean>;\n /** Close reason set when Escape dismisses the overlay (both primitives use `'escape'`). */\n readonly escapeReason: CloseReason;\n /** Close reason set when {@link ListboxOverlayController.toggle} closes the overlay (both primitives use `'programmatic'`). */\n readonly programmaticReason: CloseReason;\n /** Mark the control touched (mirrors the trigger blur) on Escape / outside dismissal. */\n readonly markTouched: () => void;\n /**\n * Per-primitive close side effect, run after the open model flips to `false`\n * (Select clears the virtualized activedescendant + pending navigation here).\n */\n readonly onClose?: (reason: CloseReason) => void;\n /**\n * Per-option focus side effect, run after `navigate` or a typeahead match focuses the target\n * (Select scrolls the option into view and applies `selectionFollowsFocus`).\n */\n readonly onNavigateFocus?: (target: H) => void;\n /** Per-primitive option-unregister side effect (Select clears a stale activedescendant). */\n readonly onUnregisterOption?: (handle: H) => void;\n}\n\n/**\n * The narrow, typed facade a primitive surfaces on its coordination context\n * (`ctx.overlay`) so child directives read the shared overlay-listbox state and\n * behavior here instead of the root re-forwarding every member. Implemented by\n * {@link ListboxOverlayController}; each primitive's context exposes it as a\n * sub-object, keeping the child-facing surface a single, self-documenting seam.\n *\n * @typeParam H Primitive option-handle type.\n * @typeParam Focus Initial-focus union.\n * @typeParam CloseReason Close-reason union owned by the primitive.\n */\nexport interface ListboxOverlayContext<H extends ListboxOverlayOptionHandle, Focus, CloseReason> {\n /** The trigger's stable id, adopted from a consumer-set static id when present. */\n readonly triggerId: Signal<string>;\n /** The content surface's stable id, adopted from a consumer-set static id when present. */\n readonly contentId: Signal<string>;\n /** Where focus should land after the content mounts. Triggers set this before flipping `open`. */\n readonly initialFocus: Signal<Focus>;\n /** Reason of the most recent close, or `null` while open (or before any close). */\n readonly lastCloseReason: Signal<CloseReason | null>;\n /** The button trigger — exempt from outside-pointer checks and the focus-return target. */\n readonly trigger: Signal<HTMLElement | null>;\n /**\n * Element floating-ui anchors the content against. Prefers a registered\n * anchor, otherwise falls back to the trigger.\n */\n readonly anchor: Signal<ReferenceElement | null>;\n /** The mounted content element. */\n readonly content: Signal<HTMLElement | null>;\n /** All registered options in DOM order. */\n readonly options: Signal<readonly H[]>;\n\n /** Set the initial-focus target ahead of the next open. */\n setInitialFocus(target: Focus): void;\n\n registerTrigger(el: HTMLElement): void;\n unregisterTrigger(el: HTMLElement): void;\n registerAnchor(el: HTMLElement): void;\n unregisterAnchor(el: HTMLElement): void;\n registerContent(el: HTMLElement): void;\n unregisterContent(el: HTMLElement): void;\n registerOption(handle: H): void;\n unregisterOption(handle: H): void;\n\n /** Move focus inside the open content in response to an arrow / Home / End key. */\n navigate(currentOption: HTMLElement, action: ListNavigationAction): void;\n /**\n * Open-state typeahead: focus the first enabled option after the event target whose\n * accessible text matches the buffered prefix. Returns `true` when the key was consumed,\n * so a Space the buffer took must not also activate.\n */\n handleTypeahead(event: KeyboardEvent): boolean;\n focusFirstEnabledOption(): boolean;\n focusLastEnabledOption(): boolean;\n\n toggle(initialFocus: Focus): void;\n openOverlay(initialFocus: Focus): void;\n closeOverlay(reason: CloseReason): void;\n\n /** Escape on the anchored path: emit `(escapeKeyDown)`, then close when un-vetoed and dismissible. */\n emitEscapeKeyDown(event: KeyboardEvent): void;\n emitPointerDownOutside(veto: VetoableNativeEvent<PointerEvent>): void;\n emitFocusOutside(veto: VetoableNativeEvent<FocusEvent>): void;\n emitInteractOutside(veto: VetoableNativeEvent<PointerEvent | FocusEvent>): void;\n /** Modal-path Escape forwarder: emit only; the modal shell owns the close. */\n forwardEscapeKeyDown(veto: VetoableNativeEvent<KeyboardEvent>): void;\n /** Implicit close requested by the shell after an un-vetoed outside interaction. */\n requestClose(reason: CloseReason): void;\n emitAutoFocusOnOpen(): boolean;\n emitAutoFocusOnClose(): boolean;\n}\n\n/**\n * The overlay-listbox state machine shared by `ForSelect` and `ForTimePicker`\n * (the WAI-ARIA select-only combobox and the slot-listbox time picker). It owns\n * the option collection, the anchor slot, the DOM-focus navigation algorithm and\n * the trigger focus move; everything the menu overlays run identically — the\n * trigger / content slots and their ids, the initial-focus and close-reason\n * state, the open / close machine, the dismiss / auto-focus forwarders — is the\n * shared {@link OverlayController}'s, composed here rather than re-declared.\n *\n * Value-specific behaviour (selection equality, `activate`, `focusSelectedOption`,\n * closed-state typeahead, the virtualized activedescendant path, `commitOnTab`'s value set)\n * stays in the root and is threaded through {@link ListboxOverlayControllerDeps}\n * callbacks where it must run as a side effect of a shared transition.\n *\n * Internal core tier — exported from `forty-cdk/core-overlay` for the library's\n * own entry points, with no semver guarantee.\n *\n * Construct it from a directive's field initializer, so the slot factories'\n * `inject()` calls resolve through the directive's injector.\n *\n * @typeParam H Primitive option-handle type.\n * @typeParam Focus Initial-focus union.\n * @typeParam CloseReason Close-reason union.\n */\nexport class ListboxOverlayController<\n H extends ListboxOverlayOptionHandle,\n Focus,\n CloseReason,\n> implements ListboxOverlayContext<H, Focus, CloseReason> {\n readonly #deps: ListboxOverlayControllerDeps<H, Focus, CloseReason>;\n readonly #items = new Collection<H>();\n readonly #typeahead = injectTypeahead();\n\n readonly #anchorSlot: AnchorSlot;\n readonly #controller: OverlayController<Focus, CloseReason>;\n\n /** The trigger's stable id, adopted from a consumer-set static id when present. */\n readonly triggerId: Signal<string>;\n\n /** The content surface's stable id, adopted from a consumer-set static id when present. */\n readonly contentId: Signal<string>;\n\n /** Where focus should land after the content mounts. Triggers set this before flipping `open`. */\n readonly initialFocus: Signal<Focus>;\n\n /** Reason of the most recent close, or `null` while open (or before any close). */\n readonly lastCloseReason: Signal<CloseReason | null>;\n\n /** The button trigger — exempt from outside-pointer checks and the focus-return target. */\n readonly trigger: Signal<HTMLElement | null>;\n\n /**\n * Element floating-ui anchors the listbox against. Prefers an optional\n * registered anchor, then the surrounding field's `[forFieldAnchor]`,\n * otherwise falls back to the trigger so primitives without an anchor keep\n * their behavior.\n */\n readonly anchor: Signal<ReferenceElement | null>;\n\n /** The mounted content element. */\n readonly content: Signal<HTMLElement | null>;\n\n /** All registered options in DOM order. */\n readonly options: Signal<readonly H[]>;\n\n constructor(deps: ListboxOverlayControllerDeps<H, Focus, CloseReason>) {\n this.#deps = deps;\n this.#controller = new OverlayController<Focus, CloseReason>({\n idPrefix: deps.idPrefix,\n createTrigger: (mintId) => new IdentifiedElementSlot(mintId()),\n defaultInitialFocus: deps.defaultInitialFocus,\n disabled: deps.effectiveDisabled,\n dismissible: deps.dismissible,\n isOpen: deps.isOpen,\n setOpen: deps.setOpen,\n emit: deps.emit,\n escapeReason: deps.escapeReason,\n programmaticReason: deps.programmaticReason,\n onClose: deps.onClose,\n onDismiss: deps.markTouched,\n });\n this.#anchorSlot = anchorSlot(deps.anchorSlot);\n this.triggerId = this.#controller.triggerId;\n this.contentId = this.#controller.contentId;\n this.initialFocus = this.#controller.initialFocus;\n this.lastCloseReason = this.#controller.lastCloseReason;\n this.trigger = this.#controller.trigger;\n this.content = this.#controller.content;\n this.anchor = this.#anchorSlot.resolve(injectFieldAnchor(), this.#controller.trigger);\n this.options = this.#items.items;\n }\n\n setInitialFocus(target: Focus): void {\n this.#controller.setInitialFocus(target);\n }\n\n registerTrigger(el: HTMLElement): void {\n this.#controller.registerTrigger(el);\n }\n unregisterTrigger(el: HTMLElement): void {\n this.#controller.unregisterTrigger(el);\n }\n\n registerAnchor(el: HTMLElement): void {\n this.#anchorSlot.register(el);\n }\n unregisterAnchor(el: HTMLElement): void {\n this.#anchorSlot.unregister(el);\n }\n\n registerContent(el: HTMLElement): void {\n this.#controller.registerContent(el);\n }\n unregisterContent(el: HTMLElement): void {\n this.#controller.unregisterContent(el);\n }\n\n registerOption(handle: H): void {\n this.#items.register(handle);\n }\n unregisterOption(handle: H): void {\n this.#items.unregister(handle);\n this.#deps.onUnregisterOption?.(handle);\n }\n\n navigate(currentOption: HTMLElement, action: ListNavigationAction): void {\n if (this.#deps.effectiveDisabled()) {\n return;\n }\n const target = nextEnabledHandle(this.#items.items(), currentOption, action, {\n loop: this.#deps.loop(),\n });\n if (target === null) {\n return;\n }\n target.host.focus();\n this.#deps.onNavigateFocus?.(target);\n }\n\n handleTypeahead(event: KeyboardEvent): boolean {\n const items = this.#items.items();\n const { handled, match } = resolveListTypeahead(this.#typeahead, event, {\n items,\n anchorIndex: items.findIndex((o) => o.host === event.target),\n getText: (o) => accessibleTextContent(o.host),\n isDisabled: (o) => o.disabled(),\n });\n if (match) {\n match.host.focus();\n this.#deps.onNavigateFocus?.(match);\n }\n return handled;\n }\n\n focusFirstEnabledOption(): boolean {\n const host = firstEnabledHost(this.#items.items());\n if (!host) {\n return false;\n }\n host.focus();\n return true;\n }\n\n focusLastEnabledOption(): boolean {\n const host = lastEnabledHost(this.#items.items());\n if (!host) {\n return false;\n }\n host.focus();\n return true;\n }\n\n /**\n * The option an open surface still has to scroll into view: the registered option holding DOM\n * focus, else `fallback()` when focus is on none of them. `null` when that option is the first\n * enabled one, which the surface already shows at its top, or when there is none.\n */\n revealTarget(fallback: () => HTMLElement | null = () => null): HTMLElement | null {\n const content = this.content();\n if (content === null) {\n return null;\n }\n const items = this.#items.items();\n const active = resolveActiveElement(content.ownerDocument);\n const target = items.find((o) => o.host === active)?.host ?? fallback();\n return target === firstEnabledHost(items) ? null : target;\n }\n\n /**\n * The overlay shell's Tab-out wiring: a Tab that leaves the open surface's tab cycle moves focus\n * to the trigger, so the browser advances from there rather than from the body-appended portal,\n * and closes with `reason`. The target resolves only while the overlay is open and `enabled()`\n * holds, so an option that already committed and closed on the same Tab keeps the browser's own\n * advance from the trigger.\n */\n tabOut(reason: CloseReason, enabled: () => boolean = () => true): OverlayShellTabOutConfig {\n return {\n target: () => (this.#deps.isOpen() && enabled() ? this.trigger() : null),\n close: () => this.closeOverlay(reason),\n };\n }\n\n toggle(initialFocus: Focus): void {\n this.#controller.toggle(initialFocus);\n }\n\n openOverlay(initialFocus: Focus): void {\n this.#controller.open(initialFocus);\n }\n\n closeOverlay(reason: CloseReason): void {\n this.#controller.close(reason);\n }\n\n emitEscapeKeyDown(event: KeyboardEvent): void {\n this.#controller.emitEscapeKeyDown(event);\n }\n\n emitPointerDownOutside(veto: VetoableNativeEvent<PointerEvent>): void {\n this.#controller.emitPointerDownOutside(veto);\n }\n emitFocusOutside(veto: VetoableNativeEvent<FocusEvent>): void {\n this.#controller.emitFocusOutside(veto);\n }\n emitInteractOutside(veto: VetoableNativeEvent<PointerEvent | FocusEvent>): void {\n this.#controller.emitInteractOutside(veto);\n }\n\n forwardEscapeKeyDown(veto: VetoableNativeEvent<KeyboardEvent>): void {\n this.#controller.forwardEscapeKeyDown(veto);\n }\n\n /**\n * Implicit close requested by the shell after an un-vetoed outside\n * interaction. The `isOpen` guard keeps a stale event from re-closing an\n * already-closed overlay and clobbering its `lastCloseReason` (e.g. a `'tab'`\n * close must survive so the content skips its return-focus).\n */\n requestClose(reason: CloseReason): void {\n this.#controller.requestClose(reason);\n }\n\n emitAutoFocusOnOpen(): boolean {\n return this.#controller.emitAutoFocusOnOpen();\n }\n\n emitAutoFocusOnClose(): boolean {\n return this.#controller.emitAutoFocusOnClose();\n }\n\n /** Focus the trigger, e.g. on a Tab commit before the content unmounts. */\n focusTrigger(): void {\n this.#controller.trigger()?.focus();\n }\n}\n","import { inject, InjectionToken, type Signal } from '@angular/core';\nimport type { ReferenceElement } from '@floating-ui/dom';\n\nimport {\n type CollectionHandle,\n type ListNavigationAction,\n orphanContextError,\n type VetoableNativeEvent,\n type WritingDirection,\n} from 'forty-cdk/core';\nimport type { DismissibleLayerNesting } from '../dismissible-layer/dismissible-layer';\nimport type {\n FloatingAlign,\n FloatingFallbackAxisSideDirection,\n FloatingSide,\n} from '../floating/floating';\nimport type { MenuActivationModality } from './menu-overlay';\nimport type { Point } from '../pointer-grace/pointer-grace';\n\n/**\n * Minimal upward contract a menu uses to move between sibling menus of an\n * enclosing menubar. Implemented by the menubar root; keeps the generic menu\n * layer free of any concrete-root import.\n */\nexport interface MenuSiblingNavigator {\n /**\n * Move focus/open to the previous or next sibling menu, returning whether the\n * bar actually moved. `false` means there was nowhere to go — the bar is\n * disabled, it has no registered triggers, or no enabled sibling exists in\n * that direction with `loop` off — so a caller must not tear down state (an\n * open submenu chain) it would then be unable to leave.\n */\n switchToSibling(direction: 'next' | 'prev'): boolean;\n}\n\n/**\n * Why a menu requested close. Enumerates the close reasons without the\n * focus-routing decision baked in. `'programmatic'` also\n * covers the user-initiated trigger toggle-close (clicking an open menu's\n * trigger): the toggle path reuses this reason by design rather than\n * exposing a distinct `'trigger'` reason. `'hover'` is a pointer-driven\n * (hover-leave) close and, like `'escape'` / `'programmatic'`, affects only\n * the level that scheduled it — it never propagates up the menu chain.\n */\nexport type ForMenuCloseReason =\n 'escape' | 'pointerDownOutside' | 'focusOutside' | 'select' | 'tab' | 'hover' | 'programmatic';\n\n/**\n * Handle every item type (`menuitem`, `menuitemcheckbox`, `menuitemradio`)\n * registers with the parent menu. The collection orders them by DOM\n * position so groups, separators, and `@for` loops don't affect navigation.\n *\n * `textValue`, when present and non-empty, overrides the item's accessible\n * text for typeahead matching — useful when announced content such as a kbd\n * shortcut, a badge, or an SVG title would otherwise bleed into the match\n * string. Empty / unset means \"fall back to the host's accessible text\", which\n * already excludes any `aria-hidden` subtree.\n */\nexport interface ForMenuItemHandle extends CollectionHandle {\n /**\n * Narrowed from {@link CollectionHandle}'s `Node`: the menu focuses its items\n * and scrolls them into view.\n */\n readonly host: HTMLElement;\n readonly disabled: Signal<boolean>;\n readonly textValue?: Signal<string>;\n /**\n * Tells the item that the next focus it receives is a programmatic move\n * that must not reflect `data-highlighted` (the initial focus of a\n * pointer-driven open). One-shot: the item consumes the suppression on its\n * next `focus` event. Optional — items that don't reflect a highlight\n * (e.g. `[forMenuSubTrigger]`) simply omit it.\n */\n suppressHighlightOnNextFocus?(): void;\n /**\n * Drops the item's `data-highlighted` without moving DOM focus. The menu\n * surface calls this on `pointerleave` so the hover highlight stops once the\n * pointer leaves, while keyboard navigation stays anchored on the item.\n * Optional — items that don't reflect a highlight (e.g.\n * `[forMenuSubTrigger]`) simply omit it.\n */\n clearHighlight?(): void;\n}\n\n/**\n * Coordination contract owned by the root that opens the menu —\n * `[forDropdownMenu]` (button trigger) or `[forContextMenu]`\n * (right-click / `Shift+F10`). Items, content, separators, etc. inject\n * this contract so they don't depend on a specific root flavor.\n */\nexport interface ForMenuContext {\n /**\n * Whether the menu is currently shown. Read-only at the contract level —\n * concrete roots (`[forDropdownMenu]`, `[forContextMenu]`, `[forMenuSub]`)\n * back this with their own `model<boolean>` and write through their own\n * `openMenu` / `closeMenu` plumbing. Pieces consuming this contract\n * (`[forMenuContent]`, the trigger directives) only ever read.\n */\n readonly open: Signal<boolean>;\n readonly disabled: Signal<boolean>;\n readonly dismissible: Signal<boolean>;\n readonly returnFocus: Signal<boolean>;\n /**\n * Writing direction. Drives ArrowLeft / ArrowRight semantics on submenu\n * triggers and items, and the default `side` of submenus (`'right'` in\n * LTR, `'left'` in RTL). On `[forMenuSub]` defaults to the parent menu's\n * `dir` and can be overridden per-submenu.\n */\n readonly dir: Signal<WritingDirection>;\n readonly side: Signal<FloatingSide | undefined>;\n readonly align: Signal<FloatingAlign | undefined>;\n readonly sideOffset: Signal<number>;\n readonly alignOffset: Signal<number>;\n readonly avoidCollisions: Signal<boolean>;\n /**\n * Direction `flip` falls back to on the perpendicular axis when both sides of\n * the preferred axis overflow. `'none'` (default) keeps only the opposite\n * same-axis placement; `'start'` / `'end'` let a submenu drop to a vertical\n * side on a narrow viewport. Threaded through to `injectOverlayShell`'s\n * floating positioner.\n */\n readonly fallbackAxisSideDirection: Signal<FloatingFallbackAxisSideDirection>;\n readonly collisionPadding: Signal<number>;\n readonly sticky: Signal<'partial' | 'always' | false>;\n readonly hideWhenDetached: Signal<boolean>;\n readonly clipUntilPositioned: Signal<boolean>;\n readonly loop: Signal<boolean>;\n\n /** Where focus should land after the menu mounts. Set by triggers before flipping `open`. */\n readonly initialFocus: Signal<'first' | 'last'>;\n setInitialFocus(target: 'first' | 'last'): void;\n\n /**\n * Id of the trigger, used as the surface's `aria-labelledby` fallback. An\n * empty string means the context has no trigger to name the surface with, and\n * `[forMenuContent]` emits no attribute at all — never `aria-labelledby=\"\"`.\n */\n readonly triggerId: Signal<string>;\n /**\n * Id the surface exposes, and the trigger's `aria-controls` target. An empty\n * string means the context has not associated a trigger with the surface yet\n * (only reachable under `[forMenubar]`, whose single context multiplexes over\n * the triggers), and `[forMenuContent]` emits no `id` at all — never `id=\"\"`.\n */\n readonly contentId: Signal<string>;\n readonly ariaLabel: Signal<string | null>;\n\n /**\n * Whether the trigger's own accessible name is a valid name for the menu\n * surface. `true` — the default when a root omits the member entirely — lets\n * `[forMenuContent]` fall back to `aria-labelledby=\"<triggerId>\"` when no\n * `ariaLabel` is set, which is correct for a discrete labelling control (a\n * `[forDropdownMenuTrigger]` button, a `[forMenubarTrigger]` or\n * `[forMenuSubTrigger]` menuitem). `[forContextMenu]` reports `false`: its\n * trigger is the whole right-click region, so an `aria-labelledby` pointing at\n * it would make screen readers announce the entire row / card text as the\n * menu's name. A root that reports `false` must expose `ariaLabel` as the way\n * to name the menu.\n *\n * A `Signal` rather than a plain `boolean` because a multi-opener root\n * (`[forMenu]`) has heterogeneous openers: a button opener *is* a labelling\n * control while a right-click region is not, so the answer is a property of\n * the **active** opener and changes as the menu is opened from a different one. Roots with a\n * single fixed trigger flavour report a constant signal.\n */\n readonly triggerLabelsMenu?: Signal<boolean>;\n\n /** Anchor passed to floating-ui — `HTMLElement` (Dropdown) or `VirtualElement` (Context). */\n readonly anchor: Signal<ReferenceElement | null>;\n\n /**\n * The element the menu was opened from (the trigger button or right-click\n * region). Focus returns here on close, except after a keyboard activation\n * from a focused element inside a right-click region, which returns focus to\n * that element while it is still in the document.\n */\n readonly trigger: Signal<HTMLElement | null>;\n registerTrigger(el: HTMLElement): void;\n unregisterTrigger(el: HTMLElement): void;\n\n /** The mounted `[forMenuContent]` element. Submenus exempt their parent's content. */\n readonly content: Signal<HTMLElement | null>;\n registerContent(el: HTMLElement): void;\n unregisterContent(el: HTMLElement): void;\n\n /**\n * The enclosing menu, when this context is a `[forMenuSub]`. `null` for\n * top-level roots (`[forDropdownMenu]`, `[forContextMenu]`, and the\n * `[forMenubar]`-flavored ctx). Items use it to route ArrowLeft /\n * item-activation upward.\n */\n readonly parentMenu: ForMenuContext | null;\n\n /**\n * The enclosing menubar, when this context is the top-level menu of a\n * `[forMenubar]`. `null` otherwise. `[forMenuItem]` and `[forMenuContent]`\n * route ArrowLeft / ArrowRight up to it for cross-menu navigation when\n * there's no parent submenu. Typed as the minimal `MenuSiblingNavigator`\n * so the generic menu layer stays free of any concrete-root import.\n */\n readonly menubar?: MenuSiblingNavigator | null;\n\n /**\n * Elements treated as \"inside\" by the dismissible layer. DropdownMenu\n * exempts the trigger button (clicks on it toggle via the trigger\n * directive — without exemption they'd also fire pointer-down-outside\n * and double-close). ContextMenu exempts nothing — a left-click on the\n * region while the menu is open should close it.\n */\n readonly dismissibleExemptions: Signal<readonly HTMLElement[]>;\n\n registerItem(handle: ForMenuItemHandle): void;\n unregisterItem(handle: ForMenuItemHandle): void;\n\n /** Move focus inside the menu in response to an arrow / Home / End key. */\n navigate(currentItem: HTMLElement, action: ListNavigationAction): void;\n /**\n * Prefix-match against item text content and focus the first match. Returns\n * `true` when the key was consumed as a typeahead character (a printable\n * char, or Space while the buffer is already non-empty). Items applied on a\n * native `<button>` use this to `preventDefault()` a mid-typeahead Space so\n * it extends the buffer instead of activating the focused item.\n */\n handleTypeahead(event: KeyboardEvent): boolean;\n /**\n * Clear `data-highlighted` from every item without moving focus. Called by\n * `[forMenuContent]` on `pointerleave` so the hover highlight follows the\n * pointer off the surface (hover-follows-pointer).\n */\n clearItemHighlights(): void;\n /**\n * Focuses the first or last enabled item per `target` — the contract-level\n * resolution of {@link initialFocus}, so a piece that reads that signal hands\n * the value straight back instead of re-deriving which of the two granular\n * calls it maps to. `[forMenuContent]` uses it for the mount-time initial\n * focus; the mapping itself is owned once by core's `MenuItemList`. This is\n * the contract's only initial-focus entry point — the granular\n * `focusFirstEnabledItem` / `focusLastEnabledItem` pair stays on the concrete\n * controllers as an imperative escape hatch and is not part of what an\n * implementor owes. Returns `true` if focus moved; `false` when no enabled\n * items exist.\n */\n focusInitialEnabledItem(target: 'first' | 'last'): boolean;\n\n /**\n * Trigger entry points — toggle/open honour `disabled`. `modality`\n * (default `'keyboard'`) records how the open was activated: a `'pointer'`\n * open keeps the programmatic initial focus from reflecting\n * `data-highlighted` on the focused item, while a `'keyboard'` open\n * highlights it per the APG menu-button pattern. The DOM focus move itself\n * is identical in both modalities.\n */\n toggle(initialFocus?: 'first' | 'last', modality?: MenuActivationModality): void;\n openMenu(initialFocus?: 'first' | 'last', modality?: MenuActivationModality): void;\n closeMenu(reason: ForMenuCloseReason): void;\n\n /**\n * Reason of the most recent close, or `null` while the menu is open / has\n * never closed. Reset to `null` on every open. `[forMenuContent]` reads it\n * to skip its return-focus when the close was a `'tab'` — letting Tab move\n * focus out of the menu (per WAI-ARIA APG) instead of snapping it back to\n * the trigger.\n */\n readonly lastCloseReason: Signal<ForMenuCloseReason | null>;\n\n /**\n * Abort a pending pointer-driven (hover) close on this menu, if one is\n * scheduled. A descendant submenu walks up the `parentMenu` chain calling\n * this so the whole open chain stays alive while the pointer travels\n * between levels. Optional — only `[forMenuSub]` schedules hover-closes, so\n * top-level roots (Dropdown / Context / Menubar) need not implement it.\n */\n cancelPendingClose?(): void;\n\n /**\n * Schedule a pointer-driven (hover) open of this menu. Optional — only\n * `[forMenuSub]` opens on hover; top-level roots open on click / right-click.\n * The sub-trigger calls it on `pointerenter` via optional chaining.\n */\n scheduleOpenByPointer?(): void;\n\n /**\n * The pointer left this menu's trigger (client coordinates of the leave).\n * Optional — only `[forMenuSub]` reacts, arming the pointer-grace \"safe\n * triangle\" toward its content. The sub-trigger calls it on `pointerleave`.\n */\n onTriggerPointerLeave?(cursor: Point): void;\n\n /**\n * Escape is consumer-owned (its close emits `(escapeKeyDown)`, stops\n * propagation, and closes with reason `'escape'`); Content forwards the raw\n * `KeyboardEvent`.\n */\n emitEscapeKeyDown(event: KeyboardEvent): void;\n /**\n * Outside-interaction emit forwarders. The specific and composite channels\n * observe the same veto, so `preventDefault()` from either one suppresses the\n * close that otherwise follows.\n */\n emitPointerDownOutside(veto: VetoableNativeEvent<PointerEvent>): void;\n emitFocusOutside(veto: VetoableNativeEvent<FocusEvent>): void;\n emitInteractOutside(veto: VetoableNativeEvent<PointerEvent | FocusEvent>): void;\n /** Implicit close requested by the shell after an un-vetoed outside interaction. */\n requestClose(reason: 'pointerDownOutside' | 'focusOutside'): void;\n\n /**\n * Hooks into the auto-focus pipeline. Content fires these just before\n * its imperative `.focus()` (open) or the trigger return-focus (close);\n * `event.preventDefault()` skips the move. Returns `true` when the\n * consumer vetoed.\n */\n emitAutoFocusOnOpen(): boolean;\n emitAutoFocusOnClose(): boolean;\n}\n\nexport type { MenuActivationModality };\n\n/**\n * Nesting descriptor for a menu level's dismissible layer, derived from the\n * `parentMenu` chain: the chain identity is the outermost menu context and the\n * depth is the number of hops needed to reach it (`0` for a top-level\n * `[forDropdownMenu]` / `[forContextMenu]` / `[forMenubar]` menu, `1` for its\n * first `[forMenuSub]`, and so on).\n *\n * Menu levels are ordered on the layer stack by this depth rather than by the\n * order their `afterNextRender` callbacks ran, because a menu and its submenu\n * mounted in the same render pass activate child-before-parent — which would\n * put the parent above its own submenu and make the submenu's first focus close\n * the whole chain with reason `'focusOutside'`.\n */\nexport function menuLayerNesting(ctx: ForMenuContext): DismissibleLayerNesting {\n let chain: ForMenuContext = ctx;\n let depth = 0;\n while (chain.parentMenu) {\n chain = chain.parentMenu;\n depth++;\n }\n return { chain, depth };\n}\n\nexport const FOR_MENU_CONTEXT = new InjectionToken<ForMenuContext>('FOR_MENU_CONTEXT');\n\nexport function injectMenuContext(piece: string): ForMenuContext {\n const ctx = inject(FOR_MENU_CONTEXT, { optional: true });\n if (!ctx) {\n throw orphanContextError({\n code: 'FORCDK-MENU-001',\n piece,\n root: '[forMenu], [forDropdownMenu], [forContextMenu], [forMenubar], or [forMenuSub]',\n token: 'FOR_MENU_CONTEXT',\n });\n }\n return ctx;\n}\n","import { type Signal } from '@angular/core';\n\nimport {\n accessibleTextContent,\n Collection,\n type CollectionHandle,\n firstEnabledHandle,\n injectTypeahead,\n lastEnabledHandle,\n type ListNavigationAction,\n nextEnabledHandle,\n resolveListTypeahead,\n type Typeahead,\n} from 'forty-cdk/core';\n\n/**\n * Item handle the list's `Collection` registers. Structurally compatible\n * with primitives' `ForMenuItemHandle` — typing is generic so the unit\n * stays orthogonal to `./menu-context` (no cycle into a primitive).\n *\n * Stays exported from `core/src/public-api.ts` — internal tier, not blessed —\n * because it is the default type argument of `MenuOverlay`, which the emitted\n * `.d.ts` names as `MenuOverlay<MenuItemHandle>` for the `protected readonly\n * _overlay` field on `[forDropdownMenu]` / `[forContextMenu]` / `[forMenu]`.\n */\nexport interface MenuItemHandle extends CollectionHandle {\n /**\n * Narrowed from {@link CollectionHandle}'s `Node`: the list focuses its items\n * and scrolls them into view.\n */\n readonly host: HTMLElement;\n readonly disabled: Signal<boolean>;\n readonly textValue?: Signal<string>;\n /**\n * Tells the item that the next focus it receives is a programmatic move\n * that must not reflect `data-highlighted` (the initial focus of a\n * pointer-driven open). One-shot: the item consumes the suppression on its\n * next `focus` event. Optional — items that don't reflect a highlight\n * (e.g. `[forMenuSubTrigger]`) simply omit it.\n */\n suppressHighlightOnNextFocus?(): void;\n /**\n * Drops the item's `data-highlighted` without moving DOM focus. Called when\n * the pointer leaves the menu surface so the hovered item stops reading as\n * the active candidate while keyboard navigation stays anchored on it.\n * Optional — items that don't reflect a highlight omit it.\n */\n clearHighlight?(): void;\n}\n\n/**\n * The keyboard-focus mechanics shared by every menu surface that holds a\n * vertical list of `menuitem`s: the item `Collection`, a typeahead buffer,\n * arrow / Home / End navigation, prefix-match typeahead, and the\n * first/last-enabled focus moves used on mount.\n *\n * Both `MenuOverlay` (for `[forDropdownMenu]` / `[forContextMenu]` /\n * `[forMenuSub]`) and `[forMenubar]`'s multiplexed menu context delegate their\n * navigate / typeahead / focus behaviour to this unit.\n *\n * `loop` is read through an accessor so the owner can forward its own\n * reactive `loop` input without the unit depending on a specific source.\n *\n * Construct via `createMenuItemList` from a directive / helper field\n * initializer so the `injectTypeahead()` `DestroyRef` hookup resolves\n * through the surrounding injector.\n */\nexport class MenuItemList<H extends MenuItemHandle = MenuItemHandle> {\n readonly #items = new Collection<H>();\n readonly #typeahead: Typeahead;\n readonly #loop: () => boolean;\n\n constructor(loop: () => boolean, typeahead: Typeahead) {\n this.#loop = loop;\n this.#typeahead = typeahead;\n }\n\n registerItem(handle: H): void {\n this.#items.register(handle);\n }\n\n unregisterItem(handle: H): void {\n this.#items.unregister(handle);\n }\n\n /** Items registered with the menu, in DOM order. Exposed for tests / sub-menu wiring. */\n items(): readonly H[] {\n return this.#items.items();\n }\n\n /**\n * Moves focus to the next enabled item for an Arrow / Home / End action,\n * honouring the owner's `loop`. The focus move passes `preventScroll` and\n * then scrolls the target into view with `block: 'nearest'`, so a menu with\n * its own overflow scrolls minimally while the page underneath the portaled\n * surface never jumps.\n */\n navigate(currentItem: HTMLElement, action: ListNavigationAction): void {\n const target = nextEnabledHandle(this.#items.items(), currentItem, action, {\n loop: this.#loop(),\n });\n if (!target) {\n return;\n }\n focusMenuItemHost(target.host);\n }\n\n /**\n * Feeds `event` to the typeahead buffer and focuses the first matching item.\n * An item matches on its `textValue` when set, else on its accessible text:\n * an `aria-hidden` subtree (a `[forMenuItemIndicator]` glyph, an icon, a\n * badge) contributes nothing, while visually-hidden but announced content\n * still does. Text and buffer are compared trimmed, case-insensitively and\n * diacritics-insensitively, so `e` reaches `Éditer`.\n * Returns `true` when the key was consumed as a typeahead character (a\n * printable char, or Space while the buffer is already non-empty), `false`\n * otherwise. A consumed Space is `preventDefault()`-ed, so it extends the\n * buffer instead of triggering a native `<button>` item's activation. The\n * focus move passes `preventScroll` and reveals the match with\n * `scrollIntoView({ block: 'nearest' })`.\n */\n handleTypeahead(event: KeyboardEvent): boolean {\n const items = this.#items.items();\n const { handled, match } = resolveListTypeahead(this.#typeahead, event, {\n items,\n anchorIndex: items.findIndex((item) => item.host === event.target),\n getText: (item) => {\n const override = item.textValue?.() ?? '';\n return override !== '' ? override : accessibleTextContent(item.host);\n },\n isDisabled: (item) => item.disabled(),\n });\n if (match) {\n focusMenuItemHost(match.host);\n }\n return handled;\n }\n\n /**\n * Focuses the first enabled item. Pass `highlight: false` when the move is\n * the programmatic initial focus of a pointer-driven open, so the item\n * receives DOM focus without reflecting `data-highlighted`. The move passes\n * `preventScroll`: the menu surface is portaled and `position: fixed`, and\n * floating-ui has not resolved its placement yet when the initial focus\n * runs, so letting the browser scroll for it would move the page (and the\n * anchor) under a pointer-driven open.\n */\n focusFirstEnabledItem(highlight = true): boolean {\n const target = firstEnabledHandle(this.#items.items());\n if (!target) {\n return false;\n }\n this.#focusItem(target, highlight);\n return true;\n }\n\n /**\n * Focuses the last enabled item. Pass `highlight: false` when the move is\n * the programmatic initial focus of a pointer-driven open, so the item\n * receives DOM focus without reflecting `data-highlighted`. Like\n * {@link focusFirstEnabledItem} the move passes `preventScroll` and reveals\n * the item with `scrollIntoView({ block: 'nearest' })`, so a scrollable menu\n * still scrolls its own overflow to the last item.\n */\n focusLastEnabledItem(highlight = true): boolean {\n const target = lastEnabledHandle(this.#items.items());\n if (!target) {\n return false;\n }\n this.#focusItem(target, highlight);\n return true;\n }\n\n /**\n * Focuses the first or last enabled item per `target`. The single owner of the\n * `'first' | 'last'` → focus-call mapping every menu surface resolves its\n * initial focus through — the mount path, the already-open re-focus branch of\n * a `MenuOverlay`, and `[forMenubar]`'s equivalent — so the fallback ordering\n * and any future widening of the target union live in one place instead of one\n * copy per surface. `highlight` behaves exactly as on\n * {@link focusFirstEnabledItem} / {@link focusLastEnabledItem}.\n */\n focusInitialEnabledItem(target: 'first' | 'last', highlight = true): boolean {\n return target === 'last'\n ? this.focusLastEnabledItem(highlight)\n : this.focusFirstEnabledItem(highlight);\n }\n\n #focusItem(item: H, highlight: boolean): void {\n if (!highlight) {\n item.suppressHighlightOnNextFocus?.();\n }\n focusMenuItemHost(item.host);\n }\n\n /**\n * Drops `data-highlighted` from every registered item without touching DOM\n * focus. Used when the pointer leaves the menu surface so no item keeps\n * reading as the active candidate.\n */\n clearHighlights(): void {\n for (const item of this.#items.items()) {\n item.clearHighlight?.();\n }\n }\n}\n\n/**\n * Creates a `MenuItemList` from a directive / helper field initializer.\n * `loop` is the owner's reactive loop accessor; the typeahead instance is\n * created with `injectTypeahead()` so its debounce timer is torn down with\n * the surrounding `DestroyRef`.\n */\nexport function createMenuItemList<H extends MenuItemHandle = MenuItemHandle>(\n loop: () => boolean,\n): MenuItemList<H> {\n return new MenuItemList<H>(loop, injectTypeahead());\n}\n\nfunction focusMenuItemHost(host: HTMLElement): void {\n host.focus({ preventScroll: true });\n host.scrollIntoView?.({ block: 'nearest' });\n}\n","import { computed, signal, type Signal, type WritableSignal } from '@angular/core';\nimport type { ReferenceElement, VirtualElement } from '@floating-ui/dom';\n\nimport type { FloatingAlign, FloatingSide } from '../floating/floating';\nimport { adoptHostId } from 'forty-cdk/core';\nimport type { ForMenuContext } from './menu-context';\n\n/**\n * Builds a floating-ui `VirtualElement` pinned to a by-value rect snapshot, so\n * later layout changes never shift the anchor. A 0×0 box models a pointer\n * position; a real box models the focused element a keyboard activation\n * anchored at.\n */\nfunction menuVirtualAnchor(x: number, y: number, width: number, height: number): VirtualElement {\n return {\n getBoundingClientRect: () => ({\n x,\n y,\n width,\n height,\n top: y,\n left: x,\n right: x + width,\n bottom: y + height,\n toJSON() {\n return this;\n },\n }),\n };\n}\n\n/**\n * Per-opener override of a menu root's **placement** inputs, applied only while\n * that opener is the active one. Every key is optional and an omitted one\n * resolves the root's own input, so an opener that overrides nothing positions\n * exactly as the root does.\n *\n * It carries the four values an opener's own geometry can legitimately decide.\n * The root keeps the rest of the positioning surface (`avoidCollisions`,\n * `collisionPadding`, `sticky`, …), which is collision / viewport policy for the\n * surface rather than a property of the opener that fired.\n *\n * The canonical case is a `[forMenu]` shared by heterogeneous openers: a button\n * opener wants the few pixels of clearance `[forDropdownMenu]` seeds, while a\n * pointer-anchored right-click region wants to sit flush at the cursor.\n */\nexport interface MenuOpenerPositioning {\n /** Side the menu is anchored to for this opener's opens. */\n readonly side?: FloatingSide;\n /** Alignment along the chosen side for this opener's opens. */\n readonly align?: FloatingAlign;\n /** Gap (px) between this opener's anchor and the menu along the main axis. */\n readonly sideOffset?: number;\n /** Gap (px) along the cross axis for this opener's opens. */\n readonly alignOffset?: number;\n}\n\n/** What an opener declares about itself when it registers with a menu root. */\nexport interface MenuOpenerOptions {\n /**\n * The opener's own aria-wiring id. Openers that own an id (`hostId`) pass it\n * so two openers on one root never emit the same `id`; omitting it falls the\n * opener back to the root's seeded trigger id, which is the single-opener\n * shape `[forMenuSubTrigger]` / `[forMenubarTrigger]` still use.\n */\n readonly id?: Signal<string>;\n /**\n * Whether a pointer-down on this opener counts as \"inside\" the menu. A\n * toggle-style opener (a `[forDropdownMenuTrigger]` button) must be exempt,\n * or its own click would also fire pointer-down-outside and double-close. A\n * right-click region must not be, so a left-click on it closes the menu like\n * any other outside click. Defaults to `false`.\n */\n readonly dismissibleExempt?: boolean;\n /**\n * Whether this opener's own accessible name is a valid name for the menu\n * surface. A discrete labelling control (a `[forDropdownMenuTrigger]` button)\n * passes `true`, so the surface can fall back to\n * `aria-labelledby=\"<openerId>\"`; a right-click region\n * (`[forContextMenuTrigger]`) passes `false`, because pointing the menu's name\n * at a whole row would announce the row's entire text. Defaults to `false` —\n * the conservative answer, which is also what a root with no resolvable active\n * opener reports.\n */\n readonly labelsMenu?: boolean;\n /**\n * This opener's placement override, read while it is the active one. Passed as\n * a signal so a bound `[menuPositioning]` flows through without\n * re-registering the element. Omitting it (and emitting `null`) resolves the\n * root's own positioning inputs.\n */\n readonly positioning?: Signal<MenuOpenerPositioning | null>;\n}\n\n/**\n * The opener-registration protocol a multi-opener menu root exposes. Deliberately\n * **not** part of `ForMenuContext`: how openers wire themselves into a root is\n * the piece-registration protocol the library refactors freely, whereas\n * `ForMenuContext` is the blessed consumer read surface. It stays out of every\n * stable entry point's barrel and out of every public signature — the trigger\n * directives resolve it by narrowing their already-resolved root with\n * {@link asMenuOpenerRegistration}.\n */\nexport interface MenuOpenerRegistration {\n /** Registers `element` as an opener of this menu. Re-registering replaces the entry. */\n registerOpener(element: HTMLElement, options?: MenuOpenerOptions): void;\n /** Removes `element` from the opener registry, clearing it as active if it was. */\n unregisterOpener(element: HTMLElement): void;\n /**\n * Marks `element` as the opener driving the current open. Return-focus, the\n * surface's `aria-labelledby` fallback, and the anchor all resolve against it.\n * `returnFocusTarget` records where focus returns for this open instead of\n * `element` — the focused descendant a keyboard activation started from.\n */\n activateOpener(element: HTMLElement, returnFocusTarget?: HTMLElement | null): void;\n /**\n * The element focus returns to when the menu closes: the target the active\n * opener recorded for this open while it is still in the document, else the\n * active opener itself.\n */\n returnFocusTarget(): HTMLElement | null;\n /** Anchors the active opener's next open at a 0×0 point in viewport coordinates. */\n setVirtualAnchor(x: number, y: number): void;\n /** Anchors the active opener's next open at a by-value snapshot of `rect`. */\n setVirtualAnchorFromRect(rect: DOMRect): void;\n}\n\n/**\n * Narrows a resolved menu root to its opener-registration protocol, or `null`\n * when the root does not implement one. Every root built on `MenuOverlayHost`\n * does; `[forMenubar]`'s multiplexed context does not, because the bar owns its\n * own trigger multiplexing. A trigger that gets `null` falls back to the\n * single-opener `registerTrigger` path, which is exactly the behaviour it had\n * before multi-opener support existed.\n */\nexport function asMenuOpenerRegistration(root: object): MenuOpenerRegistration | null {\n const candidate = root as Partial<MenuOpenerRegistration>;\n return typeof candidate.registerOpener === 'function'\n ? (candidate as MenuOpenerRegistration)\n : null;\n}\n\n/**\n * The element a menu returns focus to on close: the opener registry's per-open\n * target on a root that has one, the context's `trigger` otherwise.\n */\nexport function menuReturnFocusTarget(ctx: Pick<ForMenuContext, 'trigger'>): HTMLElement | null {\n const openers = asMenuOpenerRegistration(ctx);\n return openers ? openers.returnFocusTarget() : ctx.trigger();\n}\n\ninterface MenuOpenerEntry {\n readonly element: HTMLElement;\n readonly id: Signal<string>;\n readonly virtualAnchor: WritableSignal<ReferenceElement | null>;\n readonly dismissibleExempt: boolean;\n readonly labelsMenu: boolean;\n readonly positioning: Signal<MenuOpenerPositioning | null> | null;\n}\n\n/**\n * The registry of openers behind a menu root. Several triggers may drive one\n * menu definition, which is what lets `[forMenu]` be declared once and opened\n * from many places.\n *\n * Everything the mounted surface reads resolves against the **active** opener:\n * the element return-focus lands on, the id the surface names itself after,\n * whether that id is a valid name at all, the floating-ui anchor, and the\n * placement override that anchor is measured with. \"Active\" is whichever opener\n * last called {@link activate}, falling back to the sole registered opener — so\n * a single-opener root and a programmatic open resolve unambiguously.\n *\n * Each opener carries its own optional virtual anchor, so switching openers\n * switches the anchor with no clearing step: a pointer-anchored right-click\n * opener keeps its `VirtualElement` while a button opener keeps resolving to its\n * own element.\n */\nexport class MenuOpenerRegistry {\n readonly #seedId: WritableSignal<string>;\n readonly #entries = signal<readonly MenuOpenerEntry[]>([]);\n readonly #activeElement = signal<HTMLElement | null>(null);\n #returnFocusTarget: HTMLElement | null = null;\n\n readonly #active = computed<MenuOpenerEntry | null>(() => {\n const entries = this.#entries();\n const active = this.#activeElement();\n if (active !== null) {\n const match = entries.find((entry) => entry.element === active);\n if (match !== undefined) {\n return match;\n }\n }\n return entries.length === 1 ? (entries[0] ?? null) : null;\n });\n\n /**\n * Id of the opener driving the current open, falling back to the root's seeded\n * trigger id while no single opener is resolvable. Never the empty string, so\n * the surface's `aria-labelledby` fallback keeps the shape it had when the id\n * lived on the root.\n */\n readonly id: Signal<string>;\n\n /**\n * The active opener's element — the return-focus target, unless the open\n * recorded one of its own (see {@link returnFocusTarget}).\n */\n readonly element = computed<HTMLElement | null>(() => this.#active()?.element ?? null);\n\n /**\n * The active opener's floating-ui anchor: its virtual anchor when it set one\n * (a pointer / rect activation), otherwise its own element.\n */\n readonly anchor = computed<ReferenceElement | null>(() => {\n const active = this.#active();\n if (active === null) {\n return null;\n }\n return active.virtualAnchor() ?? active.element;\n });\n\n /**\n * The active opener's virtual anchor only — `null` until an opener sets one.\n * `[forContextMenu]` resolves its anchor through this so a right-click menu\n * with no recorded pointer position stays unanchored rather than falling back\n * to its whole right-click region.\n */\n readonly virtualAnchor = computed<ReferenceElement | null>(\n () => this.#active()?.virtualAnchor() ?? null,\n );\n\n /** Every registered opener that asked to count as \"inside\" the menu. */\n readonly dismissibleExemptions = computed<readonly HTMLElement[]>(() =>\n this.#entries()\n .filter((entry) => entry.dismissibleExempt)\n .map((entry) => entry.element),\n );\n\n /**\n * Whether the **active** opener's accessible name is a valid name for the menu\n * surface, so `[forMenuContent]` may fall back to\n * `aria-labelledby=\"<openerId>\"`. Per-opener rather than per-root because a\n * shared menu's openers are heterogeneous — a button opener is a labelling\n * control, a right-click region is not — and the answer therefore flips as the\n * menu is opened from a different one.\n *\n * `false` while no single opener is resolvable: the surface would otherwise\n * name itself after the root's seeded trigger id, which no element carries\n * once every opener owns an id of its own.\n */\n readonly labelsMenu = computed<boolean>(() => this.#active()?.labelsMenu ?? false);\n\n /**\n * The **active** opener's placement override, or `null` when it declared none\n * (and while no single opener is resolvable). Per-opener for the same reason\n * the anchor is: a shared menu's openers are heterogeneous, so the offsets a\n * button opener wants are not the ones a pointer-anchored region wants. A\n * root resolves each key against its own input — `positioning()?.x ??\n * xInput()` — so an opener that overrides nothing changes nothing.\n */\n readonly positioning = computed<MenuOpenerPositioning | null>(\n () => this.#active()?.positioning?.() ?? null,\n );\n\n constructor(seedId: WritableSignal<string>) {\n this.#seedId = seedId;\n this.id = computed(() => this.#active()?.id() ?? this.#seedId());\n }\n\n /**\n * Registers `element`, adopting a consumer-set static `id` into the seed when\n * the opener owns no id of its own.\n *\n * Reads no signal: openers register from inside their trigger's\n * `effect`, so touching `#entries` here would make that effect depend on the\n * very signal it writes and spin forever.\n */\n register(element: HTMLElement, options: MenuOpenerOptions = {}): void {\n const id = options.id;\n if (id === undefined) {\n adoptHostId(element, this.#seedId);\n }\n const entry: MenuOpenerEntry = {\n element,\n id: id ?? this.#seedId,\n virtualAnchor: signal<ReferenceElement | null>(null),\n dismissibleExempt: options.dismissibleExempt ?? false,\n labelsMenu: options.labelsMenu ?? false,\n positioning: options.positioning ?? null,\n };\n this.#entries.update((entries) => [\n ...entries.filter((existing) => existing.element !== element),\n entry,\n ]);\n }\n\n unregister(element: HTMLElement): void {\n this.#entries.update((entries) => entries.filter((entry) => entry.element !== element));\n if (this.#activeElement() === element) {\n this.#activeElement.set(null);\n this.#returnFocusTarget = null;\n }\n }\n\n activate(element: HTMLElement, returnFocusTarget: HTMLElement | null = null): void {\n this.#activeElement.set(element);\n this.#returnFocusTarget = returnFocusTarget;\n }\n\n /**\n * The return-focus target of the current open: the one {@link activate}\n * recorded while it is still in the document, else the active opener. Read at\n * close time rather than derived, because a menu action may remove the\n * recorded element from the document.\n */\n returnFocusTarget(): HTMLElement | null {\n const target = this.#returnFocusTarget;\n return target !== null && target.isConnected ? target : this.element();\n }\n\n setVirtualAnchor(x: number, y: number): void {\n this.#active()?.virtualAnchor.set(menuVirtualAnchor(x, y, 0, 0));\n }\n\n setVirtualAnchorFromRect(rect: DOMRect): void {\n this.#active()?.virtualAnchor.set(menuVirtualAnchor(rect.x, rect.y, rect.width, rect.height));\n }\n}\n","import type { ModelSignal, Signal } from '@angular/core';\nimport type { ReferenceElement } from '@floating-ui/dom';\n\nimport { type ListNavigationAction, type VetoableNativeEvent } from 'forty-cdk/core';\nimport {\n OverlayController,\n type OverlayEmitTargets,\n type OverlayTransitionOptions,\n} from '../overlay-controller/overlay-controller';\nimport {\n MenuOpenerRegistry,\n type MenuOpenerOptions,\n type MenuOpenerPositioning,\n} from './menu-opener-registry';\nimport type { ForMenuCloseReason } from './menu-context';\nimport { createMenuItemList, type MenuItemHandle, type MenuItemList } from './menu-item-list';\n\n/**\n * How a menu open was activated. `'keyboard'` (the default) highlights the\n * initially focused item per the APG menu-button pattern; `'pointer'` keeps\n * the programmatic initial focus from reflecting `data-highlighted` so a\n * mouse-opened menu doesn't read as \"preselected\". The DOM focus move itself\n * is identical in both modalities.\n */\nexport type MenuActivationModality = 'pointer' | 'keyboard';\n\n/**\n * Wiring the directive forwards into the helper. Inputs / outputs / models\n * stay declared on the directive (Angular needs them as fields for template\n * binding); the helper reads them through these references so the close\n * decisions, navigation, and veto plumbing live in one place.\n */\nexport interface MenuOverlayHooks extends OverlayEmitTargets {\n readonly open: ModelSignal<boolean>;\n readonly disabled: Signal<boolean>;\n readonly dismissible: Signal<boolean>;\n readonly loop: Signal<boolean>;\n\n /**\n * Optional side effect run after `openMenu` resolves the open, receiving the\n * resolved initial-focus target. `[forMenuSub]` uses it to cancel in-flight\n * hover scheduling and set its focus-suppression flags from\n * `options.suppressFocusMoves` (a keyboard / click open supersedes hover).\n * Top-level roots (`[forDropdownMenu]` / `[forContextMenu]`) pass neither\n * hook.\n *\n * It also runs when `openMenu` re-targets an **already-open** menu (no model\n * write, focus moved instead), so a pending hover-close is still cancelled by\n * an open key pressed on a mounted submenu.\n */\n readonly onOpen?: (initialFocus: 'first' | 'last', options: OverlayTransitionOptions) => void;\n\n /**\n * Optional side effect run after `closeMenu` flips `open` to `false`,\n * receiving the close reason and the transition options. `[forMenuSub]` uses\n * it to cancel in-flight hover scheduling, set its focus-suppression flags\n * from `options.suppressFocusMoves`, and propagate the close upward through\n * the menu chain for every reason except `'escape'` / `'hover'` /\n * `'programmatic'`. Top-level roots pass neither hook.\n */\n readonly onClose?: (reason: ForMenuCloseReason, options: OverlayTransitionOptions) => void;\n}\n\n/**\n * Shared coordination behaviour between `ForDropdownMenu` and `ForContextMenu`\n * (and any future menu overlay root with the same item-collection / typeahead /\n * navigate / dismissible shape — Menubar's per-bar menu, a future free-floating\n * SubMenu).\n *\n * The helper owns:\n *\n * - the item list (`MenuItemList`: the item `Collection`, typeahead and the navigate / focus\n * moves), shared with `[forMenubar]`'s multiplexed menu context,\n * - the opener registry: every trigger that can open this menu, which one is driving the current\n * open, and the per-opener id / anchor / labelling policy resolved against it,\n * - the menu vocabulary over the shared {@link OverlayController} — `'first' | 'last'` initial\n * focus, `ForMenuCloseReason`, the `'pointer' | 'keyboard'` activation modality, and\n * `openMenu`'s already-open re-focus branch.\n *\n * Everything below that vocabulary — the trigger / content slots and their ids, the\n * initial-focus and close-reason state, the `disabled`-gated open / close / toggle transitions,\n * the outside / Escape forwarders, `requestClose`, and the auto-focus vetoes — is the shared\n * controller's, declared once and composed here.\n *\n * It does not own:\n *\n * - the resolved `anchor` signal, which each root derives differently — from the trigger element,\n * from a virtual anchor, or from the active opener,\n * - `dismissibleExemptions`, since only some roots exempt their trigger to stop a click toggle\n * double-firing as a pointer-down-outside,\n * - the `input()` / `output()` / `model()` declarations, which must stay on the directive class for\n * Angular's template binding to see them.\n *\n * Construct via `createMenuOverlay` from a directive's field initializer, so the helper's `inject()`\n * calls resolve through the directive's injector.\n */\nexport class MenuOverlay<H extends MenuItemHandle = MenuItemHandle> {\n readonly #itemList: MenuItemList<H>;\n\n readonly #openers: MenuOpenerRegistry;\n readonly #controller: OverlayController<'first' | 'last', ForMenuCloseReason>;\n\n /**\n * Id of the opener driving the current open — the active opener's own id when\n * it owns one, else the seeded `<idPrefix>-trigger-*` fallback. Non-empty from\n * construction, so `[forMenuContent]`'s `aria-labelledby` fallback keeps the\n * shape it had when a single id lived on the root.\n */\n readonly triggerId: Signal<string>;\n\n /** Unique id for the content element. Stable across the menu's lifetime. */\n readonly contentId: Signal<string>;\n\n /** Where focus should land when the menu mounts. Set by triggers before flipping `open`. */\n readonly initialFocus: Signal<'first' | 'last'>;\n\n /**\n * Reason of the most recent close, or `null` while the menu is open / has\n * never closed. Reset to `null` on every open. The shared `[forMenuContent]`\n * reads this to skip its return-focus on `'tab'` so Tab can advance focus\n * out of the menu instead of snapping back to the trigger.\n */\n readonly lastCloseReason: Signal<ForMenuCloseReason | null>;\n\n /**\n * The focusable element the menu should return focus to on close — the opener\n * that actually opened this instance, so a menu shared by several openers\n * hands focus back to the one the user used.\n */\n readonly trigger: Signal<HTMLElement | null>;\n\n /** The mounted `[forMenuContent]` element, or `null` while the menu is closed. */\n readonly content: Signal<HTMLElement | null>;\n\n /**\n * The active opener's floating-ui anchor: its virtual anchor when it recorded\n * one, else its own element. `[forMenu]` resolves its `anchor` through this so\n * the surface follows whichever opener fired.\n */\n readonly openerAnchor: Signal<ReferenceElement | null>;\n\n /**\n * The active opener's virtual anchor only, `null` until one is recorded.\n * `[forContextMenu]` resolves its `anchor` through this so a menu with no\n * recorded pointer position stays unanchored rather than falling back to its\n * whole right-click region.\n */\n readonly openerVirtualAnchor: Signal<ReferenceElement | null>;\n\n /** Registered openers that count as \"inside\" for outside-dismissal. */\n readonly openerExemptions: Signal<readonly HTMLElement[]>;\n\n /**\n * Whether the active opener is a discrete labelling control, so\n * `[forMenuContent]` may name itself `aria-labelledby=\"<triggerId>\"`.\n * `[forMenu]` exposes this as its `ForMenuContext.triggerLabelsMenu` so a\n * shared menu's name follows whichever opener fired.\n */\n readonly openerLabelsMenu: Signal<boolean>;\n\n /**\n * The active opener's placement override, `null` when it declared none. Each\n * root resolves its `side` / `align` / `sideOffset` / `alignOffset` against\n * its own input through this, so a shared menu positions per the opener that\n * fired while an opener with no override keeps the root's values.\n */\n readonly openerPositioning: Signal<MenuOpenerPositioning | null>;\n\n constructor(idPrefix: string, hooks: MenuOverlayHooks) {\n this.#itemList = createMenuItemList<H>(() => hooks.loop());\n let openers!: MenuOpenerRegistry;\n this.#controller = new OverlayController<'first' | 'last', ForMenuCloseReason>({\n idPrefix,\n createTrigger: (mintId) => {\n openers = new MenuOpenerRegistry(mintId());\n return openers;\n },\n defaultInitialFocus: 'first',\n disabled: hooks.disabled,\n dismissible: hooks.dismissible,\n isOpen: () => hooks.open(),\n setOpen: (open) => hooks.open.set(open),\n emit: hooks,\n escapeReason: 'escape',\n programmaticReason: 'programmatic',\n onOpen: hooks.onOpen,\n onClose: hooks.onClose,\n });\n this.#openers = openers;\n this.triggerId = this.#controller.triggerId;\n this.contentId = this.#controller.contentId;\n this.initialFocus = this.#controller.initialFocus;\n this.lastCloseReason = this.#controller.lastCloseReason;\n this.trigger = this.#controller.trigger;\n this.content = this.#controller.content;\n this.openerAnchor = this.#openers.anchor;\n this.openerVirtualAnchor = this.#openers.virtualAnchor;\n this.openerExemptions = this.#openers.dismissibleExemptions;\n this.openerLabelsMenu = this.#openers.labelsMenu;\n this.openerPositioning = this.#openers.positioning;\n }\n\n setInitialFocus(target: 'first' | 'last'): void {\n this.#controller.setInitialFocus(target);\n }\n\n registerTrigger(el: HTMLElement): void {\n this.#controller.registerTrigger(el);\n }\n\n unregisterTrigger(el: HTMLElement): void {\n this.#controller.unregisterTrigger(el);\n }\n\n registerOpener(element: HTMLElement, options?: MenuOpenerOptions): void {\n this.#openers.register(element, options);\n }\n\n unregisterOpener(element: HTMLElement): void {\n this.#openers.unregister(element);\n }\n\n activateOpener(element: HTMLElement, returnFocusTarget: HTMLElement | null = null): void {\n this.#openers.activate(element, returnFocusTarget);\n }\n\n /**\n * The element focus returns to on close: the target the active opener\n * recorded for this open while it is still in the document, else\n * {@link trigger}.\n */\n returnFocusTarget(): HTMLElement | null {\n return this.#openers.returnFocusTarget();\n }\n\n setVirtualAnchor(x: number, y: number): void {\n this.#openers.setVirtualAnchor(x, y);\n }\n\n setVirtualAnchorFromRect(rect: DOMRect): void {\n this.#openers.setVirtualAnchorFromRect(rect);\n }\n\n registerContent(el: HTMLElement): void {\n this.#controller.registerContent(el);\n }\n\n unregisterContent(el: HTMLElement): void {\n this.#controller.unregisterContent(el);\n }\n\n registerItem(handle: H): void {\n this.#itemList.registerItem(handle);\n }\n\n unregisterItem(handle: H): void {\n this.#itemList.unregisterItem(handle);\n }\n\n /** Items registered with the menu, in DOM order. Exposed for tests / sub-menu wiring. */\n items(): readonly H[] {\n return this.#itemList.items();\n }\n\n navigate(currentItem: HTMLElement, action: ListNavigationAction): void {\n this.#itemList.navigate(currentItem, action);\n }\n\n handleTypeahead(event: KeyboardEvent): boolean {\n return this.#itemList.handleTypeahead(event);\n }\n\n /**\n * Clears `data-highlighted` from every item without moving focus. The shared\n * `[forMenuContent]` calls this on `pointerleave` so the hover highlight\n * follows the pointer off the surface.\n */\n clearItemHighlights(): void {\n this.#itemList.clearHighlights();\n }\n\n /**\n * Focuses the first enabled item. When the most recent `openMenu` was\n * pointer-activated, this one move suppresses the item's focus-driven\n * `data-highlighted` (one-shot — later calls highlight normally).\n *\n * An imperative escape hatch for an explicit first / last move, independent of the resolved\n * {@link initialFocus} target. No piece of the library routes through it — they all go through\n * {@link focusInitialEnabledItem} — and `ForMenuContext` does not declare it.\n */\n focusFirstEnabledItem(): boolean {\n return this.#itemList.focusFirstEnabledItem(this.#controller.consumeInitialHighlight());\n }\n\n /**\n * Focuses the last enabled item. When the most recent `openMenu` was\n * pointer-activated, this one move suppresses the item's focus-driven\n * `data-highlighted` (one-shot — later calls highlight normally). The\n * granular counterpart of {@link focusFirstEnabledItem}, and like it an\n * imperative escape hatch rather than a `ForMenuContext` member.\n */\n focusLastEnabledItem(): boolean {\n return this.#itemList.focusLastEnabledItem(this.#controller.consumeInitialHighlight());\n }\n\n /**\n * Focuses the first or last enabled item per `target`, resolving the mapping\n * through the shared `MenuItemList` rather than re-deriving it here. Used by\n * the mount path (through the `ForMenuContext` contract) and by `openMenu`'s\n * already-open re-focus branch. When the most recent `openMenu` was\n * pointer-activated, this one move suppresses the item's focus-driven\n * `data-highlighted` (one-shot — later calls highlight normally).\n */\n focusInitialEnabledItem(target: 'first' | 'last'): boolean {\n return this.#itemList.focusInitialEnabledItem(\n target,\n this.#controller.consumeInitialHighlight(),\n );\n }\n\n /**\n * Toggle the menu open/closed from the trigger. The close branch reuses the\n * `'programmatic'` close reason by design — there is no distinct `'trigger'`\n * reason for the user-initiated toggle-close path.\n */\n toggle(\n initialFocus: 'first' | 'last' = 'first',\n modality: MenuActivationModality = 'keyboard',\n ): void {\n this.#controller.toggle(initialFocus, { highlight: modality === 'keyboard' });\n }\n\n /**\n * Opens the menu, recording where the initial focus should land and how\n * the open was activated. A `'pointer'` modality keeps that one initial\n * focus move from reflecting `data-highlighted` on the focused item.\n * `options` is forwarded verbatim to the `onOpen` hook — `[forMenuSub]`'s\n * hover-open passes `{ suppressFocusMoves: true }` so the mount does not\n * pull focus off whatever the user was on.\n *\n * When the menu is **already open** there is no state transition (and\n * therefore no `(openChange)` emit): focus moves straight to the requested\n * first / last enabled item instead, so an APG open key pressed on a trigger\n * whose menu is already mounted is never a dead key. The menu is never\n * toggled closed — the open keys have no close semantics in the APG patterns\n * — and a menu with no enabled item moves nothing rather than pulling focus\n * onto an item-less surface. The re-focus is not gated on the\n * `(autoFocusOnOpen)` veto: that veto covers the mount's automatic focus\n * move, and honouring it here would silently restore the dead key for\n * consumers who opted out of auto-focus-on-open. It *is* skipped for a\n * `{ suppressFocusMoves: true }` transition, whose whole contract is that no\n * imperative focus move may happen (`[forMenuSub]`'s hover-open).\n *\n * This branch is the menu's own: it stays out of the shared controller, which\n * reports the already-open case as an outcome rather than acting on it.\n */\n openMenu(\n initialFocus: 'first' | 'last' = 'first',\n modality: MenuActivationModality = 'keyboard',\n options: OverlayTransitionOptions = {},\n ): void {\n const outcome = this.#controller.open(initialFocus, {\n highlight: modality === 'keyboard',\n transition: options,\n });\n if (outcome === 'already-open' && !options.suppressFocusMoves) {\n this.focusInitialEnabledItem(initialFocus);\n }\n }\n\n /**\n * Closes the menu, recording `reason` as the `lastCloseReason` the content\n * pieces read. `options` is forwarded verbatim to the `onClose` hook —\n * `[forMenuSub]`'s hover-close passes `{ suppressFocusMoves: true }` so the\n * unmount does not yank focus back to the sub-trigger.\n */\n closeMenu(reason: ForMenuCloseReason, options: OverlayTransitionOptions = {}): void {\n this.#controller.close(reason, options);\n }\n\n emitEscapeKeyDown(event: KeyboardEvent): void {\n this.#controller.emitEscapeKeyDown(event);\n }\n\n emitPointerDownOutside(veto: VetoableNativeEvent<PointerEvent>): void {\n this.#controller.emitPointerDownOutside(veto);\n }\n\n emitFocusOutside(veto: VetoableNativeEvent<FocusEvent>): void {\n this.#controller.emitFocusOutside(veto);\n }\n\n emitInteractOutside(veto: VetoableNativeEvent<PointerEvent | FocusEvent>): void {\n this.#controller.emitInteractOutside(veto);\n }\n\n requestClose(reason: 'pointerDownOutside' | 'focusOutside'): void {\n this.#controller.requestClose(reason);\n }\n\n emitAutoFocusOnOpen(): boolean {\n return this.#controller.emitAutoFocusOnOpen();\n }\n\n emitAutoFocusOnClose(): boolean {\n return this.#controller.emitAutoFocusOnClose();\n }\n}\n\n/**\n * Creates a `MenuOverlay` from a directive field initializer. `idPrefix`\n * is the namespace fed to the shared `IdGenerator` (e.g.\n * `'for-dropdown-menu'`, `'for-context-menu'`); the helper generates\n * `<idPrefix>-trigger` and `<idPrefix>-content` ids off it.\n */\nexport function createMenuOverlay<H extends MenuItemHandle = MenuItemHandle>(\n idPrefix: string,\n hooks: MenuOverlayHooks,\n): MenuOverlay<H> {\n return new MenuOverlay<H>(idPrefix, hooks);\n}\n","import { Directive, type Signal } from '@angular/core';\n\nimport { AnchoredOverlayPositioningBase } from '../floating/anchored-overlay-positioning-base';\nimport { type ListNavigationAction, type VetoableNativeEvent } from 'forty-cdk/core';\nimport type { ForMenuCloseReason } from './menu-context';\nimport type { MenuItemHandle } from './menu-item-list';\nimport type { MenuOpenerOptions } from './menu-opener-registry';\nimport type { MenuActivationModality, MenuOverlay } from './menu-overlay';\n\n/**\n * Abstract base that forwards the `MenuOverlay` coordination slice every menu\n * root re-exposes — `[forDropdownMenu]`, `[forContextMenu]`, and `[forMenuSub]`\n * all extend it. Each subclass owns its own `MenuOverlay` instance (created\n * with its own id prefix and lifecycle hooks) and exposes it through the\n * abstract `_overlay` accessor; the base implements the trigger / content /\n * item registration, navigation, open/close, and veto pass-throughs once.\n *\n * This is the single place to add a member that is a pure pass-through to\n * `MenuOverlay`: declaring it here gives all three directives the method\n * without hand-written `.bind()` forwarding in each. Subclasses override only\n * the members that need extra behaviour (e.g. `[forMenuSub]` wraps\n * `registerContent` to attach pointer listeners and overrides the auto-focus\n * emitters to honour its hover focus-suppression flags).\n *\n * Kept generic over the item handle so the subclass's `MenuOverlay<H>` flows\n * through `registerItem` / `unregisterItem` without a cast.\n *\n * It also carries `AnchoredOverlayPositioningBase` for its subclasses: every\n * menu root is a trigger-anchored overlay, so inheriting the shared positioning\n * block here is what keeps the four of them from redeclaring it. The\n * `@Directive()` decorator is required for that inheritance — Angular only\n * collects signal inputs through a decorated chain.\n */\n@Directive()\nexport abstract class MenuOverlayHost<\n H extends MenuItemHandle = MenuItemHandle,\n> extends AnchoredOverlayPositioningBase {\n /** The subclass's `MenuOverlay` instance the base forwards to. */\n protected abstract readonly _overlay: MenuOverlay<H>;\n\n get triggerId(): Signal<string> {\n return this._overlay.triggerId;\n }\n\n get contentId(): Signal<string> {\n return this._overlay.contentId;\n }\n\n get initialFocus(): Signal<'first' | 'last'> {\n return this._overlay.initialFocus;\n }\n\n get lastCloseReason(): Signal<ForMenuCloseReason | null> {\n return this._overlay.lastCloseReason;\n }\n\n get trigger(): Signal<HTMLElement | null> {\n return this._overlay.trigger;\n }\n\n get content(): Signal<HTMLElement | null> {\n return this._overlay.content;\n }\n\n setInitialFocus(target: 'first' | 'last'): void {\n this._overlay.setInitialFocus(target);\n }\n\n registerTrigger(el: HTMLElement): void {\n this._overlay.registerTrigger(el);\n }\n\n unregisterTrigger(el: HTMLElement): void {\n this._overlay.unregisterTrigger(el);\n }\n\n /**\n * The `MenuOpenerRegistration` protocol, forwarded once for every root. Kept\n * `protected` on purpose: it is the piece-registration protocol, so it\n * must stay out of the roots' emitted `.d.ts` while remaining callable at\n * runtime — which is what the trigger directives' `asMenuOpenerRegistration`\n * narrowing relies on.\n */\n private registerOpener(element: HTMLElement, options?: MenuOpenerOptions): void {\n this._overlay.registerOpener(element, options);\n }\n\n private unregisterOpener(element: HTMLElement): void {\n this._overlay.unregisterOpener(element);\n }\n\n private activateOpener(element: HTMLElement, returnFocusTarget?: HTMLElement | null): void {\n this._overlay.activateOpener(element, returnFocusTarget);\n }\n\n private returnFocusTarget(): HTMLElement | null {\n return this._overlay.returnFocusTarget();\n }\n\n protected setVirtualAnchor(x: number, y: number): void {\n this._overlay.setVirtualAnchor(x, y);\n }\n\n protected setVirtualAnchorFromRect(rect: DOMRect): void {\n this._overlay.setVirtualAnchorFromRect(rect);\n }\n\n registerContent(el: HTMLElement): void {\n this._overlay.registerContent(el);\n }\n\n unregisterContent(el: HTMLElement): void {\n this._overlay.unregisterContent(el);\n }\n\n registerItem(handle: H): void {\n this._overlay.registerItem(handle);\n }\n\n unregisterItem(handle: H): void {\n this._overlay.unregisterItem(handle);\n }\n\n navigate(currentItem: HTMLElement, action: ListNavigationAction): void {\n this._overlay.navigate(currentItem, action);\n }\n\n handleTypeahead(event: KeyboardEvent): boolean {\n return this._overlay.handleTypeahead(event);\n }\n\n clearItemHighlights(): void {\n this._overlay.clearItemHighlights();\n }\n\n focusFirstEnabledItem(): boolean {\n return this._overlay.focusFirstEnabledItem();\n }\n\n focusLastEnabledItem(): boolean {\n return this._overlay.focusLastEnabledItem();\n }\n\n focusInitialEnabledItem(target: 'first' | 'last'): boolean {\n return this._overlay.focusInitialEnabledItem(target);\n }\n\n toggle(\n initialFocus: 'first' | 'last' = 'first',\n modality: MenuActivationModality = 'keyboard',\n ): void {\n this._overlay.toggle(initialFocus, modality);\n }\n\n openMenu(\n initialFocus: 'first' | 'last' = 'first',\n modality: MenuActivationModality = 'keyboard',\n ): void {\n this._overlay.openMenu(initialFocus, modality);\n }\n\n closeMenu(reason: ForMenuCloseReason): void {\n this._overlay.closeMenu(reason);\n }\n\n requestClose(reason: 'pointerDownOutside' | 'focusOutside'): void {\n this._overlay.requestClose(reason);\n }\n\n emitEscapeKeyDown(event: KeyboardEvent): void {\n this._overlay.emitEscapeKeyDown(event);\n }\n\n emitPointerDownOutside(veto: VetoableNativeEvent<PointerEvent>): void {\n this._overlay.emitPointerDownOutside(veto);\n }\n\n emitFocusOutside(veto: VetoableNativeEvent<FocusEvent>): void {\n this._overlay.emitFocusOutside(veto);\n }\n\n emitInteractOutside(veto: VetoableNativeEvent<PointerEvent | FocusEvent>): void {\n this._overlay.emitInteractOutside(veto);\n }\n\n emitAutoFocusOnOpen(): boolean {\n return this._overlay.emitAutoFocusOnOpen();\n }\n\n emitAutoFocusOnClose(): boolean {\n return this._overlay.emitAutoFocusOnClose();\n }\n}\n","import { DestroyRef, ElementRef, inject, type Signal } from '@angular/core';\n\nimport { injectPortal } from 'forty-cdk/core';\n\n/**\n * The members a modal surface's internal context adds for its backdrop piece. `ForDialog` and\n * `ForDrawer` implement them through `ModalSurfaceBase`.\n */\nexport interface ModalSurfaceBackdropContext {\n /**\n * The surface's host element, which the backdrop is portaled immediately before. `null` when no\n * surface host is rendered, and the backdrop is then appended to the container.\n */\n surfaceElement(): HTMLElement | null;\n /**\n * Whether the surface is the topmost layer owning the pointer channel, so a press on its\n * backdrop is not an outside press of a layer stacked above it.\n */\n isTopmostPointerLayer(): boolean;\n /**\n * Registers the backdrop as part of the surface, so the dismissible layer treats a press on it\n * as inside. The newest registration is the surface's backdrop, and a second one still mounted\n * once the render settles warns in dev mode.\n */\n registerBackdrop(el: HTMLElement): void;\n /** Removes a registered backdrop, leaving any newer registration in place. */\n unregisterBackdrop(el: HTMLElement): void;\n}\n\n/** What a backdrop piece reads off the modal surface that owns it. */\nexport interface ModalBackdropSurface extends ModalSurfaceBackdropContext {\n /** Portal target shared with the surface. `null` ⇒ `document.body`. */\n readonly container: Signal<HTMLElement | null>;\n /** Asks the surface to close with reason `'backdrop'`, gated on its `dismissible()`. */\n requestClose(reason: 'backdrop'): void;\n}\n\n/** Host listeners {@link injectModalBackdrop} hands back to the backdrop piece. */\nexport interface ModalBackdropHandle {\n /** Bind to the backdrop host's `(pointerdown)`. */\n readonly pointerDown: () => void;\n /** Bind to the backdrop host's `(click)`. */\n readonly click: (event: MouseEvent) => void;\n}\n\n/**\n * Wires a modal surface's backdrop piece: portals the host to the surface's container, registers\n * it on the surface for the piece's lifetime, and closes the surface with reason `'backdrop'` on a\n * click that lands on the backdrop itself.\n *\n * The backdrop lands immediately before its surface in the container, so two positioned elements\n * with no `z-index` paint the surface on top, and each backdrop of a stacked pair sits directly\n * below its own surface.\n *\n * The click closes the surface only when the surface was the topmost pointer layer as the press\n * began. A press that goes down while another layer is stacked above it (a nested drawer without a\n * backdrop of its own, a popover open inside the dialog) is that layer's outside press, so the\n * click ending it leaves the surface beneath open. A click with no preceding `pointerdown` is\n * judged on the stack as it stands.\n *\n * Must be called from the backdrop directive's injection context.\n */\nexport function injectModalBackdrop(surface: ModalBackdropSurface): ModalBackdropHandle {\n const host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n injectPortal({ target: surface.container, before: () => surface.surfaceElement() });\n surface.registerBackdrop(host);\n inject(DestroyRef).onDestroy(() => surface.unregisterBackdrop(host));\n\n let pressOwned: boolean | null = null;\n return {\n pointerDown: () => {\n pressOwned = surface.isTopmostPointerLayer();\n },\n click: (event) => {\n const owned = pressOwned ?? surface.isTopmostPointerLayer();\n pressOwned = null;\n if (event.target === host && owned) {\n surface.requestClose('backdrop');\n }\n },\n };\n}\n","import type { Signal } from '@angular/core';\n\nimport type {\n DismissibleLayerActivateOptions,\n DismissibleLayerChannel,\n} from '../dismissible-layer/dismissible-layer';\nimport { createVetoableNativeEvent, type VetoableNativeEvent } from 'forty-cdk/core';\n\n/**\n * Emit forwarders + implicit-close wiring for the outside-interaction channels\n * that {@link buildOutsideVetoOptions} folds into self-closing layer handlers.\n * Each wired outside channel builds one veto, emits it through the specific\n * output (if wired) and the composite `interactOutside` output (if wired), then\n * closes itself when un-vetoed and `dismissible()` is `true`. Escape is\n * intentionally absent: it never participates in the outside-close (it is a\n * one-shot channel whose close behaviour differs per shell), so each shell\n * wires its own `onEscapeKeyDown` alongside the object this returns.\n *\n * Every field is optional so a shell can register a layer listener only for the\n * channels its consumer actually forwards — the trigger-anchored overlays opt\n * out of individual channels (an input-focused combobox owns Escape on its\n * input and omits it here), while the modal shell forwards all three.\n */\nexport interface OutsideVetoConfig {\n /**\n * Whether an un-vetoed outside interaction fires the implicit\n * `requestClose`. Read fresh on every outside interaction.\n */\n readonly dismissible?: Signal<boolean>;\n /**\n * Called with the matching reason (`'pointerDownOutside'` / `'focusOutside'`)\n * when the consumer doesn't veto the outside interaction and `dismissible()`\n * is `true`. Each wired outside channel fires its own close.\n */\n readonly requestClose?: (reason: 'pointerDownOutside' | 'focusOutside') => void;\n /** Forwards the pointer-down-outside veto to the directive's `(pointerDownOutside)` output. */\n readonly emitPointerDownOutside?: (veto: VetoableNativeEvent<PointerEvent>) => void;\n /** Forwards the focus-outside veto to the directive's `(focusOutside)` output. */\n readonly emitFocusOutside?: (veto: VetoableNativeEvent<FocusEvent>) => void;\n /** Forwards the composite veto to the directive's `(interactOutside)` output. */\n readonly emitInteractOutside?: (veto: VetoableNativeEvent<PointerEvent | FocusEvent>) => void;\n}\n\n/**\n * Builds the pointer-down-outside / focus-outside entries of a\n * {@link DismissibleLayerActivateOptions}, folding the composite\n * `interactOutside` emit and the implicit close into each specific channel so\n * every wired outside channel closes itself.\n *\n * The protocol: each handler builds a single {@link VetoableNativeEvent} for\n * its physical interaction, hands it to the specific emitter (if wired) and\n * then to the composite `interactOutside` emitter (if wired), and — when\n * neither subscriber vetoed and `dismissible()` is `true` — calls\n * `requestClose(reason)` with the channel's reason (`'pointerDownOutside'` /\n * `'focusOutside'`). A `preventDefault()` from either the specific or the\n * composite subscriber suppresses the close, since both observe the same veto.\n * The pointer handler returns whether it closed, which is what lets an outside\n * press cascade to a lower layer that opted in.\n *\n * `onPointerDownOutside` is registered when either the specific\n * `emitPointerDownOutside` or the composite `emitInteractOutside` is wired, and\n * `onFocusOutside` likewise — matching what {@link outsideVetoChannels}\n * declares — so an interact-only wiring still gets both self-closing handlers.\n * Returns only the channels whose emitter is present, so the caller can spread\n * the result into its `dismissible.activate({...})` call alongside the pieces\n * that stay shell-specific (`exemptElements`, `onEscapeKeyDown`).\n */\nexport function buildOutsideVetoOptions(\n config: OutsideVetoConfig,\n): Pick<DismissibleLayerActivateOptions, 'onPointerDownOutside' | 'onFocusOutside'> {\n const options: Pick<DismissibleLayerActivateOptions, 'onPointerDownOutside' | 'onFocusOutside'> =\n {};\n const {\n dismissible,\n requestClose,\n emitPointerDownOutside,\n emitFocusOutside,\n emitInteractOutside,\n } = config;\n\n if (emitPointerDownOutside || emitInteractOutside) {\n options.onPointerDownOutside = (event) => {\n const veto = createVetoableNativeEvent<PointerEvent | FocusEvent>(event);\n emitPointerDownOutside?.(veto as VetoableNativeEvent<PointerEvent>);\n emitInteractOutside?.(veto);\n if (!veto.defaultPrevented && dismissible?.() && requestClose) {\n requestClose('pointerDownOutside');\n return true;\n }\n return false;\n };\n }\n\n if (emitFocusOutside || emitInteractOutside) {\n options.onFocusOutside = (event) => {\n const veto = createVetoableNativeEvent<PointerEvent | FocusEvent>(event);\n emitFocusOutside?.(veto as VetoableNativeEvent<FocusEvent>);\n emitInteractOutside?.(veto);\n if (!veto.defaultPrevented && dismissible?.() && requestClose) {\n requestClose('focusOutside');\n }\n };\n }\n\n return options;\n}\n\n/**\n * Derives the outside-interaction channels a shell must declare at\n * `dismissible.activate({ channels })` from the same {@link OutsideVetoConfig}\n * passed to {@link buildOutsideVetoOptions}. A layer owns `'pointer'` when it\n * forwards either the specific pointer-down-outside channel or the composite\n * interact-outside channel (which fires for pointer-downs too), and likewise\n * `'focus'` for focus-outside / interact-outside. A shell that forwards no\n * outside channel (an Escape-only surface) gets `[]` and stays transparent to\n * the real dismissible layers beneath it.\n */\nexport function outsideVetoChannels(config: OutsideVetoConfig): DismissibleLayerChannel[] {\n const channels: DismissibleLayerChannel[] = [];\n if (config.emitPointerDownOutside || config.emitInteractOutside) {\n channels.push('pointer');\n }\n if (config.emitFocusOutside || config.emitInteractOutside) {\n channels.push('focus');\n }\n return channels;\n}\n","import { Injectable } from '@angular/core';\n\nimport { composedParentElement } from 'forty-cdk/core';\n\n@Injectable({ providedIn: 'root' })\nexport class ModalActivationOrder {\n readonly #held = new Map<HTMLElement, (() => void)[]>();\n\n hold(host: HTMLElement): void {\n this.#held.set(host, []);\n }\n\n enclosingHeld(node: Element | null): HTMLElement | null {\n let cursor: Element | null = node;\n while (cursor !== null) {\n if (cursor instanceof HTMLElement && this.#held.has(cursor)) {\n return cursor;\n }\n cursor = composedParentElement(cursor);\n }\n return null;\n }\n\n after(enclosing: HTMLElement | null, activate: () => void): void {\n const queue = enclosing === null ? undefined : this.#held.get(enclosing);\n if (queue === undefined) {\n activate();\n } else {\n queue.push(activate);\n }\n }\n\n release(host: HTMLElement): void {\n const queue = this.#held.get(host);\n if (queue === undefined) {\n return;\n }\n this.#held.delete(host);\n for (const activate of queue) {\n activate();\n }\n }\n}\n","import { DestroyRef, DOCUMENT, ElementRef, inject, type Signal } from '@angular/core';\n\nimport {\n afterNextRenderCancellable,\n composedContains,\n composedParentElement,\n createVetoableEvent,\n createVetoableNativeEvent,\n findFirstFocusable,\n injectFocusTrap,\n injectPortal,\n isInitialFocusTarget,\n MODAL_EXEMPT_ATTRIBUTE,\n resolveActiveElement,\n type VetoableEvent,\n type VetoableNativeEvent,\n} from 'forty-cdk/core';\nimport { BodyScrollLock } from '../body-scroll-lock/body-scroll-lock';\nimport { injectDismissibleLayer } from '../dismissible-layer/dismissible-layer';\nimport { type InertSiblingsHandle, InertSiblingsStack } from '../inert-siblings/inert-siblings';\nimport { buildOutsideVetoOptions, outsideVetoChannels } from '../overlay-controller/outside-veto';\nimport { ModalActivationOrder } from './modal-activation-order';\n\n/**\n * Dismissal wiring for a modal surface.\n *\n * Each channel builds one `VetoableNativeEvent` and hands it to both the specific emitter and the\n * composite `interactOutside` one, so a `preventDefault()` from either suppresses the close. When\n * nothing vetoes and `dismissible()` is `true`, the shell calls `requestClose` with the reason\n * matching the channel.\n *\n * `exemptElements` is re-read on every event, so elements portaled after activation are honoured.\n */\nexport interface ModalShellDismissConfig {\n /** Whether dismissals via the layer fire the implicit `requestClose`. */\n readonly dismissible: Signal<boolean>;\n /** Called with the matching reason when the consumer doesn't veto. */\n readonly requestClose: (reason: 'escape' | 'pointerDownOutside' | 'focusOutside') => void;\n /** Forwards the Escape `VetoableNativeEvent` to the directive's `(escapeKeyDown)` output. */\n readonly emitEscapeKeyDown: (veto: VetoableNativeEvent<KeyboardEvent>) => void;\n /** Forwards the pointer-down-outside veto to the directive's `(pointerDownOutside)` output. */\n readonly emitPointerDownOutside: (veto: VetoableNativeEvent<PointerEvent>) => void;\n /** Forwards the focus-outside veto to the directive's `(focusOutside)` output. */\n readonly emitFocusOutside: (veto: VetoableNativeEvent<FocusEvent>) => void;\n /** Forwards the composite veto to the directive's `(interactOutside)` output. */\n readonly emitInteractOutside: (veto: VetoableNativeEvent<PointerEvent | FocusEvent>) => void;\n /**\n * Live \"elements that count as inside\" set — Drawer uses this to exempt\n * its portaled backdrop so a backdrop click routes through the backdrop's\n * own `requestClose('backdrop')` path instead of `pointerDownOutside`.\n *\n * The shell always merges every `MODAL_EXEMPT_ATTRIBUTE` overlay (e.g. toast\n * viewports) on top of whatever this returns, so a primitive only lists its\n * *own* extra exemptions here. It is handed the node being tested.\n */\n readonly exemptElements?: (target: Node) => readonly Element[];\n}\n\n/**\n * Primitive-owned initial-focus algorithm for the surface. The richer\n * alternative to the `'first' | 'container'` literal: the shell sets up the\n * focus trap (Tab cycling + return capture) WITHOUT its own imperative focus\n * move, runs the optional `veto`, and — unless vetoed — calls `move()`. When\n * `move()` returns `false` (no candidate found) focus falls back to the trap\n * container (modal) or the first focusable descendant (non-modal).\n *\n * Mirrors `OverlayShellInitialFocusConfig` so a content directive can hand the\n * same focus algorithm to either shell. Used by Select (selected → first →\n * last option) and available for a future date-picker calendar-cell move.\n */\nexport interface ModalShellInitialFocusConfig {\n /** Primitive focus algorithm. Returns `true` on success, `false` to fall back. */\n readonly move: () => boolean;\n /** `(autoFocusOnOpen)` veto. Returning `true` skips the imperative focus move. */\n readonly veto?: () => boolean;\n}\n\n/**\n * Single config for the free-floating modal-overlay lifecycle. Mirrors the\n * `injectOverlayShell` shape on the trigger-anchored side. Each sub-bundle\n * is individually optional so a primitive can opt out of the channels it\n * doesn't need (e.g. a dismiss-less confirm dialog, though none ship today).\n */\nexport interface ModalShellConfig {\n /** Whether the surface activates focus-trap + scroll-lock + inert siblings. */\n readonly modal: Signal<boolean>;\n /**\n * Whether focus returns to the previously-focused element on destroy. No effect in non-modal\n * mode, where the shell never moves focus on close.\n */\n readonly returnFocus: Signal<boolean>;\n /**\n * Overrides the return-focus target, read at close time instead of captured in the constructor.\n * A `null` value falls back to the construction-time capture.\n *\n * Supply it when the surface may be constructed while focus lives inside another surface that is\n * about to be destroyed — a close→open modal swap in one change-detection pass — where the\n * captured element would be disconnected by close time and focus would fall back to `<body>`.\n *\n * Read only in modal mode, and only under the same gate as the construction-time capture:\n * {@link returnFocus} is `true` and `autoFocusOnClose` did not veto.\n */\n readonly returnFocusTarget?: Signal<HTMLElement | null>;\n /**\n * Where to send focus on mount. Two shapes:\n * - `Signal<'first' | 'container'>` — `'first'` = first focusable descendant\n * (falls back to host); `'container'` = host element. Same vocabulary as\n * `FocusTrap.activate({ initialFocus })`. Used by Dialog / Drawer /\n * date-picker.\n * - {@link ModalShellInitialFocusConfig} — a primitive-owned `move()`\n * algorithm (e.g. Select's selected → first → last option) with its own\n * open-veto, falling back to the container / first focusable on a miss.\n */\n readonly initialFocus: Signal<'first' | 'container'> | ModalShellInitialFocusConfig;\n /**\n * Element the consumer marked as the initial focus target, read once at mount. Honoured with the\n * literal `initialFocus` form only: when it resolves to an element that passes\n * `isInitialFocusTarget`, focus lands there, and otherwise the literal applies.\n */\n readonly initialFocusTarget?: () => HTMLElement | null;\n /**\n * `(autoFocusOnOpen)` veto. Bound as a function reference (not as an\n * Angular `output()`) so the shell can invoke it during the destroy hook\n * without depending on `OutputEmitterRef` lifecycle. Read at every mount;\n * a `preventDefault()` on the emitted event skips the imperative initial\n * focus move while still leaving the focus-trap (Tab cycling, return\n * capture) wired in modal mode.\n */\n readonly autoFocusOnOpen?: () => ((event: VetoableEvent) => void) | undefined;\n /**\n * `(autoFocusOnClose)` veto. Same shape as `autoFocusOnOpen`. Fired\n * synchronously from the `DestroyRef.onDestroy` hook, BEFORE the modal /\n * non-modal teardown so it runs reliably on every close path — including a\n * direct `open.set(false)` from the consumer that bypasses any\n * close-output emission.\n */\n readonly autoFocusOnClose?: () => ((event: VetoableEvent) => void) | undefined;\n /**\n * Portal target for the surface. A signal so it is read once at the first\n * render (the portal moves the host once), after the consumer's input is\n * bound. `undefined` / a signal yielding `null` ⇒ `document.body`.\n */\n readonly container?: Signal<HTMLElement | null>;\n /** Optional dismiss bundle. Absent for primitives that don't dismiss via the layer. */\n readonly dismiss?: ModalShellDismissConfig;\n}\n\n/** Imperative handle returned by `injectModalShell`. */\nexport interface ModalShellHandle {\n /** True while the shell activated focus-trap + scroll-lock + inert (modal mode). */\n readonly isModal: () => boolean;\n /**\n * Whether the surface's dismissible layer is active and no layer owning the pointer channel is\n * stacked above it, so an outside press is the surface's to handle.\n */\n readonly isTopmostPointerLayer: () => boolean;\n}\n\n/**\n * Resolves the live set of independent overlay surfaces that opt out of every\n * modal's dismissible layer via {@link MODAL_EXEMPT_ATTRIBUTE} — today\n * `ForToastViewport`. Queried fresh on each interaction (no snapshot) so a\n * surface mounted *after* the modal opened still counts as \"inside\", which is\n * exactly the toast-over-open-dialog case. An interaction inside any returned\n * element therefore never dismisses the modal.\n */\nexport function resolveModalExemptOverlays(doc: Document): readonly Element[] {\n return Array.from(doc.querySelectorAll(`[${MODAL_EXEMPT_ATTRIBUTE}]`));\n}\n\n/**\n * Owns the lifecycle of a free-floating modal surface — the overlay primitives that mount as their\n * own root, `[forDialog]` and `[forDrawer]` today.\n *\n * The shell captures the return-focus target, portals the host to `document.body` (or to\n * `config.container`), and activates the dismissible layer. In modal mode it additionally inerts\n * the siblings, activates the focus trap and locks scroll, all scoped to `config.container` when\n * one is supplied; in non-modal mode it only performs the initial focus move.\n *\n * Teardown reverses that order on destroy, deactivating inert siblings before focus returns so the\n * target is not blocked by an inert ancestor.\n *\n * Must be called from an injection context. The host's `ElementRef` is forwarded to every\n * collaborator, so the caller never wires them up directly.\n */\nexport function injectModalShell(config: ModalShellConfig): ModalShellHandle {\n const host = inject<ElementRef<HTMLElement>>(ElementRef);\n const document = inject(DOCUMENT);\n const focusTrap = injectFocusTrap();\n const dismissible = injectDismissibleLayer();\n const inertStack = inject(InertSiblingsStack);\n const scrollLock = inject(BodyScrollLock);\n\n // 1. Capture the return-focus target SYNCHRONOUSLY, before any side effect\n // runs. WebKit (#136) blurs the previously-focused element as soon as\n // `inert` is applied to an ancestor, so by the time `afterNextRender`\n // fires the focus trap could no longer read the trigger from\n // `document.activeElement`. Reading it now locks the trigger in.\n //\n // Resolved through open shadow roots (#1586): a raw `document.activeElement`\n // reports the shadow *host* when the trigger lives inside one — a consumer\n // component using `ViewEncapsulation.ShadowDom`, or a design-system web\n // component — and that host is typically not focusable, so return-focus\n // would silently drop to `<body>` on close. Because this target is always\n // passed to `trap.activate()`, the trap's own shadow-aware capture never\n // runs for a modal surface; this is the one that has to resolve.\n const active = resolveActiveElement(document);\n let returnFocusTarget: HTMLElement | null = active instanceof HTMLElement ? active : null;\n\n const order = inject(ModalActivationOrder);\n order.hold(host.nativeElement);\n let origin: Element | null = null;\n let enclosing: HTMLElement | null = null;\n afterNextRenderCancellable(() => {\n origin = composedParentElement(host.nativeElement);\n enclosing = order.enclosingHeld(origin);\n });\n\n // 2. Portal — moves the host to `document.body` after first render and\n // cleans up on destroy. `DestroyRef.onDestroy` callbacks fire in\n // registration order (FIFO), and the portal registers its hook here,\n // before the shell's own destroy hook below — so on teardown the portal\n // removes the host from the DOM FIRST, then the shell runs return-focus.\n // The ordering is harmless either way: return-focus targets the\n // previously-focused element (the trigger, captured synchronously above),\n // which lives OUTSIDE the portaled host, so removing the host first never\n // affects it.\n injectPortal(config.container ? { target: config.container } : {});\n\n // Captured at mount time so the destroy path can mirror the same mode the\n // shell activated, regardless of any `modal()` toggle on a doomed\n // instance.\n let activatedAsModal = false;\n let inertHandle: InertSiblingsHandle | null = null;\n let activatedContainer: HTMLElement | null = null;\n\n const resolveMarkedTarget = (): HTMLElement | null => {\n const target = config.initialFocusTarget?.() ?? null;\n return target !== null && isInitialFocusTarget(target, host.nativeElement) ? target : null;\n };\n\n // 3. Side-effect setup runs after Angular has applied input bindings.\n // Reading `config.modal()` etc. in the constructor would always see the\n // default value because the input writes haven't flowed through yet.\n // `afterNextRenderCancellable` makes the destroy-before-render path safe.\n // On the true-async path (queued render after destroy) the callback is\n // cancelled, so inert siblings / focus trap / scroll lock / dismissible\n // layer are never activated (`activatedAsModal` stays false). On the\n // synchronous-teardown path the callback flushes just before the destroy\n // hook, so it sets `activatedAsModal = true` and the destroy hook below\n // tears the side-effect stack back down. Either way nothing leaks.\n let destroyed = false;\n let releasePeer: (() => void) | null = null;\n const activate = (deferred: boolean): void => {\n if (deferred) {\n const current = resolveActiveElement(document);\n if (\n current instanceof HTMLElement &&\n enclosing !== null &&\n composedContains(enclosing, current)\n ) {\n returnFocusTarget = current;\n }\n }\n const isModal = config.modal();\n activatedAsModal = isModal;\n\n // 3a. Dismissible layer. Pushed onto the stack BEFORE moving focus so\n // focusin events triggered by our own focus management land on this\n // layer, not on whatever lower layer was previously topmost.\n //\n // Outside channels are self-closing: `buildOutsideVetoOptions` builds\n // one veto per physical interaction and hands it to both the specific\n // (pointer-down-outside / focus-outside) and the composite\n // `interactOutside` emitter, so a `preventDefault()` in either handler\n // vetoes the close.\n const dismissCfg = config.dismiss;\n if (dismissCfg !== undefined) {\n dismissible.activate({\n channels: outsideVetoChannels(dismissCfg),\n modal: isModal,\n exemptElements: (target) => [\n ...(dismissCfg.exemptElements?.(target) ?? []),\n ...resolveModalExemptOverlays(document),\n ],\n onEscapeKeyDown: (event) => {\n const veto = createVetoableNativeEvent(event);\n dismissCfg.emitEscapeKeyDown(veto);\n if (!veto.defaultPrevented && dismissCfg.dismissible()) {\n event.stopPropagation();\n dismissCfg.requestClose('escape');\n }\n },\n ...buildOutsideVetoOptions(dismissCfg),\n });\n }\n\n // 3b. Resolve the initial-focus config. The simple form is a\n // `Signal<'first' | 'container'>` (Dialog / Drawer / date-picker); the\n // richer form carries a primitive-owned `move()` algorithm (Select's\n // selected → first → last option) plus its own veto. A `Signal` is\n // callable, so `typeof === 'function'` distinguishes the two shapes;\n // the literal mode is read eagerly only in the simple form.\n const initialFocusCfg = config.initialFocus;\n const moveCfg: ModalShellInitialFocusConfig | null =\n typeof initialFocusCfg === 'function' ? null : initialFocusCfg;\n const literalFocus: 'first' | 'container' | null =\n typeof initialFocusCfg === 'function' ? initialFocusCfg() : null;\n const markedTarget = literalFocus === null ? null : resolveMarkedTarget();\n\n // 3c. `(autoFocusOnOpen)` veto — read once for this mount. The move-config\n // carries its own boolean veto (mirroring `injectOverlayShell`); the\n // simple form routes through the top-level `autoFocusOnOpen` callback.\n let skipInitialFocus: boolean;\n if (moveCfg) {\n skipInitialFocus = moveCfg.veto?.() ?? false;\n } else {\n const autoFocusOpenEvent = createVetoableEvent();\n config.autoFocusOnOpen?.()?.(autoFocusOpenEvent);\n skipInitialFocus = autoFocusOpenEvent.defaultPrevented;\n }\n\n if (isModal) {\n // 3d. Modal mode. Inert + aria-hide siblings BEFORE the focus trap\n // activates so the trap's `focus()` call lands on an\n // already-isolated tree. The return-focus target was captured\n // synchronously above (#136).\n const containerEl = config.container?.() ?? null;\n inertHandle = inertStack.activate(host.nativeElement, containerEl ?? undefined);\n activatedContainer = containerEl;\n if (moveCfg) {\n // The primitive owns the focus move. Set up Tab cycling + return\n // capture WITHOUT the trap's own imperative focus, then run the\n // algorithm; fall back to the container when it finds no candidate.\n focusTrap.activate({\n preventInitialFocus: true,\n returnFocus: returnFocusTarget,\n });\n if (!skipInitialFocus && !moveCfg.move()) {\n focusTrap.container.focus();\n }\n } else {\n focusTrap.activate({\n initialFocus: markedTarget ?? literalFocus ?? 'first',\n preventInitialFocus: skipInitialFocus,\n returnFocus: returnFocusTarget,\n });\n }\n scrollLock.lock(containerEl ?? undefined);\n } else {\n // 3e. Non-modal mode. No trap, no scroll lock, no inert. Still respect\n // the configured initial focus: the primitive's `move()` algorithm\n // (falling back to the first focusable on a miss), the first\n // focusable descendant ('first'), or the host ('container').\n releasePeer = inertStack.registerPeer(\n host.nativeElement,\n [origin, returnFocusTarget].filter((anchor): anchor is Element => anchor !== null),\n );\n if (!skipInitialFocus) {\n const el = focusTrap.container;\n if (moveCfg) {\n if (!moveCfg.move()) {\n (findFirstFocusable(el) ?? el).focus();\n }\n } else if (markedTarget) {\n markedTarget.focus();\n } else if (literalFocus === 'container') {\n el.focus();\n } else {\n (findFirstFocusable(el) ?? el).focus();\n }\n }\n }\n };\n afterNextRenderCancellable(() => {\n let synchronous = true;\n order.after(enclosing, () => {\n if (!destroyed) {\n activate(!synchronous);\n }\n order.release(host.nativeElement);\n });\n synchronous = false;\n });\n\n // 4. Destroy. Hooks fire in registration order; the portal's destroy hook\n // was registered inside `injectPortal()` (above) so it runs BEFORE\n // ours, removing the element from the DOM first. We tear down the\n // side-effect stack here in the inverse order it was activated.\n inject(DestroyRef).onDestroy(() => {\n destroyed = true;\n order.release(host.nativeElement);\n releasePeer?.();\n releasePeer = null;\n dismissible.deactivate();\n // Invoke `(autoFocusOnClose)` synchronously, BEFORE either the modal or\n // non-modal teardown runs. Fires on every close path regardless of mode\n // (the consumer's `(dismiss)` flow AND a direct `open.set(false)` that\n // bypasses any close-output emission). The callback is a plain function\n // reference — input signals stay readable during destroy and there is no\n // dependency on `OutputEmitterRef` lifecycle. Non-modal mode never moves\n // focus on close, so `skipReturnFocus` is only consulted in the modal\n // branch — but the hook still fires for symmetry with the manager and so\n // consumers can wire their own focus moves on close in non-modal mode.\n const autoFocusCloseEvent = createVetoableEvent();\n config.autoFocusOnClose?.()?.(autoFocusCloseEvent);\n const skipReturnFocus = autoFocusCloseEvent.defaultPrevented;\n if (activatedAsModal) {\n // Lift inert + aria-hide BEFORE moving focus back: an `inert` ancestor\n // blocks `.focus()` on its descendants, so the return-focus target\n // needs to be live again first.\n inertHandle?.deactivate();\n inertHandle = null;\n const shouldReturnFocus = config.returnFocus() && !skipReturnFocus;\n const overrideTarget = config.returnFocusTarget?.() ?? null;\n // Suppress the dismissible-layer dispatcher across focus-return so the\n // synthetic `focusin` triggered by `.focus()`-ing the previous element\n // does not cascade-dismiss whatever modal is now topmost (a stacked\n // dialog opened above this one).\n dismissible.suppress(() => {\n if (shouldReturnFocus && overrideTarget?.isConnected) {\n focusTrap.deactivate({ returnFocus: false });\n overrideTarget.focus();\n } else {\n focusTrap.deactivate({ returnFocus: shouldReturnFocus });\n }\n });\n scrollLock.unlock(activatedContainer ?? undefined);\n }\n });\n\n return {\n isModal: () => activatedAsModal,\n isTopmostPointerLayer: () => dismissible.isTopmostFor('pointer'),\n };\n}\n","import { DestroyRef, ElementRef, inject, Injectable, type Signal } from '@angular/core';\n\n/** The trigger state a modal-shell surface reads to recognise its own trigger. */\nexport interface ModalTriggerConfig {\n /** The trigger's open state. */\n readonly open: Signal<boolean>;\n /** The id of the surface the trigger controls, or `null` when unset. */\n readonly controls: Signal<string | null>;\n}\n\ninterface ModalTriggerEntry extends ModalTriggerConfig {\n readonly element: HTMLElement;\n}\n\n/**\n * The mounted triggers that toggle a modal-shell surface. A surface counts its own controlling\n * triggers as inside itself for outside-press and outside-focus dismissal, so the press that\n * precedes a trigger's toggling click never closes the surface the click is about to close.\n */\n@Injectable({ providedIn: 'root' })\nexport class ModalTriggerRegistry {\n readonly #entries = new Set<ModalTriggerEntry>();\n\n /** Adds a trigger and returns the function that removes it. */\n register(entry: ModalTriggerEntry): () => void {\n this.#entries.add(entry);\n return () => this.#entries.delete(entry);\n }\n\n /**\n * The open triggers controlling `surface`: those whose `controls` names the surface's id, and\n * those with no `controls`, which name no surface and so count as controlling any open one.\n */\n controlling(surface: HTMLElement): HTMLElement[] {\n const out: HTMLElement[] = [];\n for (const entry of this.#entries) {\n if (!entry.open()) {\n continue;\n }\n const controls = entry.controls();\n if (controls === null || (controls !== '' && controls === surface.id)) {\n out.push(entry.element);\n }\n }\n return out;\n }\n}\n\n/**\n * Registers the host as a trigger toggling a modal-shell surface, for as long as the host lives.\n * Must be called from an injection context.\n */\nexport function injectModalTrigger(config: ModalTriggerConfig): void {\n const element = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n const release = inject(ModalTriggerRegistry).register({ ...config, element });\n inject(DestroyRef).onDestroy(release);\n}\n","import {\n booleanAttribute,\n computed,\n Directive,\n ElementRef,\n inject,\n input,\n output,\n signal,\n type Signal,\n} from '@angular/core';\n\nimport {\n hostAriaLabel,\n hostDescribedBy,\n hostLabelledBy,\n type SingleSlot,\n type VetoableEvent,\n type VetoableNativeEvent,\n} from 'forty-cdk/core';\nimport { type ModalShellConfig, type ModalShellHandle } from './modal-shell';\nimport { ModalTriggerRegistry } from './modal-trigger';\n\n/**\n * Abstract base for free-floating modal-surface primitives — a directive that\n * mounts a modal surface as its own root, coordinates label / description\n * registration, and drives its lifecycle through {@link injectModalShell}.\n * `ForDialog` and `ForDrawer` extend it; a future modal Toast / full-screen\n * sheet / command palette can too.\n *\n * The base owns everything the two surfaces used to duplicate verbatim: the\n * `aria-labelledby` / `aria-describedby` registry, the backdrop registration,\n * the exemption of the backdrop and of the controlling triggers\n * (`injectModalTrigger`) from outside dismissal,\n * the `requestClose` dismissible gating, the `lastCloseValue` bridge read by\n * the programmatic managers, the seven shared ARIA / state host bindings (`role`, `aria-modal`, `aria-label`,\n * `aria-labelledby`, `aria-describedby`, `data-state=\"open\"`, `tabindex=\"-1\"`),\n * the non-defaults inputs and dismiss outputs, and the {@link modalShellConfig}\n * factory. Anything primitive-specific (Drawer's drag / snap / scale / stack,\n * the four defaults-backed inputs each subclass seeds from its own\n * `FOR_<PRIMITIVE>_DEFAULTS`) stays on the subclass.\n *\n * The base does **not** call {@link injectModalShell} itself —\n * each subclass calls `injectModalShell(this.modalShellConfig())` from its own\n * constructor. A base-owned call would register its `afterNextRender` during\n * `super()`, before a subclass (Drawer) could register its own pre-shell\n * `afterNextRender` (stack push + snap validation), breaking the documented\n * ordering.\n *\n * Implemented as an `@Directive()`-decorated abstract class because Angular\n * recognises signal inputs / outputs and host bindings only when the\n * `input()` / `output()` calls and the `host` block appear on a decorated\n * class; inheritance is the supported mechanism for sharing them across\n * directives.\n *\n * Internal core tier — exported from `forty-cdk/core` for the library's own\n * entry points, with no semver guarantee. Subclassing a library base is not a\n * supported contract, so it is absent from `CORE_PUBLISHERS` and\n * from every primitive's own barrel; the public-types gate ignores\n * `extends`-only heritage, which is why the base may appear in the shipped\n * `.d.ts` as the parent of `[forDialog]` / `[forDrawer]` without being blessed.\n */\n@Directive({\n host: {\n '[attr.role]': 'alert() ? \"alertdialog\" : \"dialog\"',\n '[attr.aria-modal]': 'modal() ? \"true\" : null',\n '[attr.aria-label]': 'resolvedAriaLabel()',\n 'data-state': 'open',\n tabindex: '-1',\n },\n})\nexport abstract class ModalSurfaceBase<Reason extends string> {\n /** When true, role becomes `alertdialog` (interrupts assistive tech). */\n readonly alert = input(false, { transform: booleanAttribute });\n\n /**\n * Explicit element focus returns to on close, read at close time. Overrides\n * the element the shell captures at construction — supply it when this\n * surface can be constructed while focus lives inside a *different, doomed*\n * surface, the canonical case being a close→open swap in one change-detection\n * pass. The programmatic managers thread the true origin through this input\n * automatically; declarative consumers driving such a swap by hand can bind\n * it too. `null` (default) keeps the construction-time capture, so ordinary\n * usage is unaffected. Has no effect in non-modal mode (the shell never moves\n * focus on close then).\n */\n readonly returnFocusTarget = input<HTMLElement | null>(null);\n\n /** Manual `aria-label`. Use this when no visible title element exists. */\n readonly ariaLabel = input<string | null>(null);\n\n /**\n * Resolved `aria-label`: a consumer-set static value on the surface when\n * present, else the {@link ariaLabel} input.\n */\n private readonly resolvedAriaLabel = hostAriaLabel(() => this.ariaLabel() || null);\n\n /**\n * Portal target for the surface. Defaults to `document.body`. Pair with\n * `[modal]=\"false\"` for a surface scoped to a positioned region instead of\n * the viewport. Read once at mount. The backdrop portals to the same\n * container.\n */\n readonly container = input<HTMLElement | null>(null);\n\n /**\n * Callback invoked just before the surface moves focus into itself on mount.\n * Receives a `VetoableEvent`; call `event.preventDefault()` to skip the\n * imperative focus move — useful when opening from an input you want to keep\n * focused. The focus trap (modal mode) still cycles Tab inside the surface\n * once focus enters it.\n *\n * Bound as a function reference (`[autoFocusOnOpen]=\"onOpen\"`), not as an\n * event binding. The callback shape (rather than an `output()`) lets the\n * shell invoke it during the destroy hook without depending on Angular's\n * `OutputEmitterRef` lifecycle.\n */\n readonly autoFocusOnOpen = input<((event: VetoableEvent) => void) | undefined>(undefined);\n\n /**\n * Callback invoked just before focus returns to the previously focused\n * element on unmount. Receives a `VetoableEvent`; call\n * `event.preventDefault()` to skip the return-focus — useful when the\n * consumer wants to send focus elsewhere imperatively. Fires reliably on\n * both close paths: the `(dismiss)` output flow AND a direct\n * `open.set(false)` from the consumer.\n */\n readonly autoFocusOnClose = input<((event: VetoableEvent) => void) | undefined>(undefined);\n\n /**\n * Whether dismiss interactions (Escape, backdrop, outside interaction, and\n * any primitive-specific gesture) close the surface. Implemented by the\n * subclass so its default can be seeded from the primitive's scope defaults.\n */\n abstract readonly dismissible: Signal<boolean>;\n\n /**\n * Whether the surface activates modal semantics (`aria-modal`, focus trap,\n * body scroll lock, inert siblings). Implemented by the subclass so its\n * default can be seeded from the primitive's scope defaults.\n */\n abstract readonly modal: Signal<boolean>;\n\n /**\n * Whether focus returns to the previously focused element on close.\n * Implemented by the subclass so its default can be seeded from the\n * primitive's scope defaults.\n */\n abstract readonly returnFocus: Signal<boolean>;\n\n /**\n * Where to send focus on mount — `'first'` (first focusable descendant) or\n * `'container'` (the surface host). Implemented by the subclass so its\n * default can be seeded from the primitive's scope defaults.\n */\n abstract readonly initialFocus: Signal<'first' | 'container'>;\n\n /**\n * Entry-point name the shared surface errors report under, e.g. `'dialog'`.\n * The subclass supplies it because the shell's checks are shared while the\n * `[forty-cdk/<scope>]` prefix a consumer reads must name the primitive they\n * actually wrote.\n */\n protected abstract readonly entryPoint: string;\n\n /**\n * The element the primitive's initial-focus marker registered inside the surface, or `null`.\n * Implemented by the subclass, which owns the marker's registration slot. The shell focuses it on\n * mount when it is a usable target, and falls back to {@link initialFocus} otherwise.\n */\n protected abstract readonly initialFocusTarget: Signal<HTMLElement | null>;\n\n /**\n * The slot the primitive's backdrop piece registers into. Implemented by the subclass, so the\n * dev-mode duplicate warning names the primitive's own surface and backdrop selectors.\n */\n protected abstract readonly backdropSlot: SingleSlot<HTMLElement>;\n\n /**\n * Emitted when the surface wants to close. Consumers wire this to flip the\n * signal that gates the surrounding `@if`. The reason union is\n * primitive-specific.\n */\n readonly dismiss = output<Reason>();\n\n /**\n * Fires when the user presses Escape while this surface is the topmost\n * dismissible layer. Call `preventDefault()` on the emitted veto to suppress\n * the subsequent `(dismiss)` emission. The original `KeyboardEvent` is on\n * `.event`.\n */\n readonly escapeKeyDown = output<VetoableNativeEvent<KeyboardEvent>>();\n\n /**\n * Fires when a pointer goes down outside the surface. Call `preventDefault()`\n * on the emitted veto to suppress the auto `(dismiss)`. The native\n * `PointerEvent` is on `.event`.\n */\n readonly pointerDownOutside = output<VetoableNativeEvent<PointerEvent>>();\n\n /**\n * Fires when focus moves outside the surface. `preventDefault()` on the veto\n * suppresses the auto `(dismiss)`. The native `FocusEvent` is on `.event`.\n */\n readonly focusOutside = output<VetoableNativeEvent<FocusEvent>>();\n\n /**\n * Composite event: fires alongside `pointerDownOutside` and `focusOutside`\n * and shares their veto state — `preventDefault()` on either one suppresses\n * the auto `(dismiss)`.\n */\n readonly interactOutside = output<VetoableNativeEvent<PointerEvent | FocusEvent>>();\n\n readonly #labelIds = signal<readonly string[]>([]);\n readonly #describedByIds = signal<readonly string[]>([]);\n readonly #lastCloseValue = signal<unknown>(undefined);\n readonly #host = inject<ElementRef<HTMLElement>>(ElementRef);\n readonly #triggers = inject(ModalTriggerRegistry);\n #shell: ModalShellHandle | null = null;\n\n /**\n * Resolved `aria-labelledby`: a consumer-set static value when present, else\n * the space-joined ids of the registered titles, or `null` when none.\n */\n readonly labelledBy = hostLabelledBy(() => {\n const ids = this.#labelIds();\n return ids.length === 0 ? null : ids.join(' ');\n });\n\n /**\n * Resolved `aria-describedby`: a consumer-set static value composed with the\n * space-joined ids of the registered descriptions, or `null` when neither is\n * present.\n */\n readonly describedBy = hostDescribedBy(() => {\n const ids = this.#describedByIds();\n return ids.length === 0 ? null : ids.join(' ');\n });\n\n /** Register a title element's id into `aria-labelledby`. */\n registerLabel(id: string): void {\n this.#labelIds.update((arr) => (arr.includes(id) ? arr : [...arr, id]));\n }\n\n /** Remove a title element's id from `aria-labelledby`. */\n unregisterLabel(id: string): void {\n this.#labelIds.update((arr) => arr.filter((x) => x !== id));\n }\n\n /** Register a description element's id into `aria-describedby`. */\n registerDescription(id: string): void {\n this.#describedByIds.update((arr) => (arr.includes(id) ? arr : [...arr, id]));\n }\n\n /** Remove a description element's id from `aria-describedby`. */\n unregisterDescription(id: string): void {\n this.#describedByIds.update((arr) => arr.filter((x) => x !== id));\n }\n\n private surfaceElement(): HTMLElement {\n return this.#host.nativeElement;\n }\n\n private registerBackdrop(el: HTMLElement): void {\n this.backdropSlot.register(el);\n }\n\n private unregisterBackdrop(el: HTMLElement): void {\n this.backdropSlot.unregister(el);\n }\n\n /**\n * Request that the surface close. `'closeButton'` and `'programmatic'` always\n * emit `(dismiss)`; every other reason is gated on `dismissible()`. `value`\n * is the close result, captured for the programmatic managers' close bridge.\n */\n requestClose(reason: Reason, value?: unknown): void {\n if (reason !== 'closeButton' && reason !== 'programmatic' && !this.dismissible()) {\n return;\n }\n this.#lastCloseValue.set(value);\n this.dismiss.emit(reason);\n }\n\n /**\n * The `value` argument from the most recent `requestClose(reason, value)`\n * call. Read by the programmatic managers to bridge `[for…Close] [closeWith]`\n * into `For…Ref.close(value)`. Part of the internal composition surface with\n * no semver guarantee; declarative consumers never need this.\n */\n readonly lastCloseValue = this.#lastCloseValue.asReadonly();\n\n /**\n * The registered backdrop element, or `null` when none is rendered. Read by\n * the programmatic managers' surface registrar so `beginLeave` drives the\n * backdrop's exit animation by direct reference instead of a document query.\n * Part of the internal composition surface with no semver guarantee;\n * declarative consumers never need this.\n */\n readonly backdropElement = computed(() => this.backdropSlot.value());\n\n /**\n * Keeps the handle the subclass's `injectModalShell(this.modalShellConfig())` call returned, which\n * the backdrop piece reads through {@link isTopmostPointerLayer}. Called once from the subclass\n * constructor.\n */\n protected attachModalShell(shell: ModalShellHandle): void {\n this.#shell = shell;\n }\n\n /**\n * Whether this surface is the topmost layer owning the pointer channel. Read by the backdrop\n * piece through the internal context to decide whether a press on it is this surface's.\n */\n private isTopmostPointerLayer(): boolean {\n return this.#shell?.isTopmostPointerLayer() ?? true;\n }\n\n protected modalShellConfig(): ModalShellConfig {\n return {\n modal: this.modal,\n returnFocus: this.returnFocus,\n returnFocusTarget: this.returnFocusTarget,\n initialFocus: this.initialFocus,\n initialFocusTarget: () => this.initialFocusTarget(),\n container: this.container,\n autoFocusOnOpen: () => this.autoFocusOnOpen(),\n autoFocusOnClose: () => this.autoFocusOnClose(),\n dismiss: {\n dismissible: this.dismissible,\n requestClose: (reason) => this.requestClose(reason as Reason),\n emitEscapeKeyDown: (veto) => this.escapeKeyDown.emit(veto),\n emitPointerDownOutside: (veto) => this.pointerDownOutside.emit(veto),\n emitFocusOutside: (veto) => this.focusOutside.emit(veto),\n emitInteractOutside: (veto) => this.interactOutside.emit(veto),\n exemptElements: () => {\n const backdrop = this.backdropSlot.value();\n const triggers = this.#triggers.controlling(this.#host.nativeElement);\n return backdrop ? [backdrop, ...triggers] : triggers;\n },\n },\n };\n }\n}\n","import { afterNextRender, isDevMode } from '@angular/core';\nimport { fortyWarn } from 'forty-cdk/core';\n\n/**\n * Identifies the piece in the dev-mode mounted-while-closed warning and tells\n * the helper how to read its surface's open state.\n */\nexport interface MountedWhileClosedConfig {\n /** Entry-point name used in the `[forty-cdk/<primitive>]` prefix (e.g. `'select'`). */\n readonly primitive: string;\n /**\n * Selector of the mounted piece (e.g. `'[forSelectContent]'`). A directive\n * with more than one selector resolves the one the consumer actually wrote,\n * so the report names a piece they can find in their template —\n * `[forMenuContent]` serves `[forMenuSubContent]` too.\n */\n readonly piece: string;\n /**\n * The `@if` condition the primitive's README uses, quoted back as the fix\n * (e.g. `'select.open()'`). Keep the two in sync — a consumer following the\n * link should read the same expression there.\n *\n * A thunk is resolved inside the render hook, which is what lets a condition\n * interpolate a bound input: `[forNavigationMenuContent]` quotes its owning\n * item's value, unreadable at construction (see below).\n */\n readonly condition: string | (() => string);\n /** The surface's open state, read once after the first render. */\n readonly open: () => boolean;\n}\n\n/**\n * Warns — dev mode only, once per instance — when an overlay surface is still mounted after its\n * first render while its own open state reports closed, which is the consumer forgetting the `@if`.\n *\n * It is the library's quietest first-use mistake: the surface renders permanently,\n * `data-state=\"closed\"` lands on a visible element, the ARIA stays internally consistent and the\n * primitive keeps working, so it reads as a CSS bug rather than a wiring one.\n *\n * Mount equals open is structural for these surfaces, so the `@if` is the whole contract and no\n * input suppresses the warning. Only pieces whose closed state has no supported mounted shape adopt\n * it, so the always-mounted panel families do not.\n *\n * **The check is mount-time**, reading the open state inside `afterNextRender` and never again,\n * which buys three things:\n *\n * - The exit-animation window stays silent. A closed surface is legitimately mounted for as long as\n * `animate.leave` keeps it, so re-checking on close would report every correct overlay.\n * - Bindings have settled. A piece deriving its open state from an `input.required` its parent has\n * not written yet would throw NG0950 on a construction-time read. `condition` takes a thunk for\n * the same reason, so the quoted fix is built where the input is readable.\n * - It is inert on the server, where `afterNextRender` never fires.\n *\n * The cost is a deliberate false negative: a surface that mounts open and is then left mounted\n * forever goes unreported, since catching it would mean re-checking on close.\n *\n * Must be called from an injection context. A production build registers no render hook at all.\n */\nexport function warnIfMountedWhileClosed(config: MountedWhileClosedConfig): void {\n if (!isDevMode()) {\n return;\n }\n\n afterNextRender(() => {\n if (config.open()) {\n return;\n }\n const condition =\n typeof config.condition === 'function' ? config.condition() : config.condition;\n fortyWarn({\n code: 'FORCDK-CORE-006',\n scope: config.primitive,\n message: `${config.piece} is mounted while the surface is closed.`,\n cause:\n \"Presence in the DOM is the consumer's job, and there is no forceMount input — a surface \" +\n 'kept mounted while closed never runs `animate.enter` / `animate.leave`, and the lifecycle ' +\n 'it sets up on mount stays live while closed.',\n fix: `Wrap it with \\`@if (${condition})\\` so it unmounts on close. See the ${config.primitive} README.`,\n });\n });\n}\n","import { inject } from '@angular/core';\nimport { CssVarNamespacer } from '@angular/platform-browser';\n\nexport interface FloatingCustomProperties {\n readonly anchorWidth: string;\n readonly anchorHeight: string;\n readonly availableWidth: string;\n readonly availableHeight: string;\n readonly contentTransformOrigin: string;\n readonly arrowOffset: string;\n}\n\nexport function injectFloatingCustomProperties(): FloatingCustomProperties {\n const namespacer = inject(CssVarNamespacer);\n return {\n anchorWidth: namespacer.namespace('--for-floating-anchor-width'),\n anchorHeight: namespacer.namespace('--for-floating-anchor-height'),\n availableWidth: namespacer.namespace('--for-floating-available-width'),\n availableHeight: namespacer.namespace('--for-floating-available-height'),\n contentTransformOrigin: namespacer.namespace('--for-floating-content-transform-origin'),\n arrowOffset: namespacer.namespace('--for-floating-arrow-offset'),\n };\n}\n","import { isPlatformBrowser } from '@angular/common';\nimport {\n afterNextRender,\n effect,\n ElementRef,\n inject,\n PLATFORM_ID,\n type Signal,\n} from '@angular/core';\nimport {\n autoUpdate,\n computePosition,\n type ComputePositionReturn,\n type Middleware,\n type Placement,\n type ReferenceElement,\n} from '@floating-ui/dom';\n\nimport { injectPortal } from 'forty-cdk/core';\n\n/**\n * The positioner-specific work for a single open run, returned by\n * {@link PositioningConfig.computeAndApply}. The shared scaffold owns the\n * platform gate, portal, anti-flash baseline, `autoUpdate` loop, the\n * `!open()` / cancelled-run bail, the `translate` write, the `clip-path` drop,\n * the per-open {@link PositioningConfig.onFirstPosition} dispatch, and the\n * `.catch(() => {})`; a run supplies only the parts that genuinely differ\n * between positioners.\n */\nexport interface PositioningRun {\n /**\n * The requested placement handed to `@floating-ui/dom`'s `computePosition`.\n * (The strategy is always `'fixed'`, owned by the scaffold.)\n */\n readonly placement: Placement;\n\n /** The middleware stack handed to `computePosition` for this run. */\n readonly middleware: Middleware[];\n\n /**\n * Applies a resolved position. Runs on every `autoUpdate` frame, after the\n * scaffold has bailed on a mid-frame close, written the resolved `translate`,\n * and dropped the `clip-path` anti-flash baseline. Writes the positioner's\n * own `data-*` attributes and CSS variables (and, for the anchored\n * positioner, the arrow).\n */\n apply(result: ComputePositionReturn): void;\n\n /**\n * Resets everything the run wrote, invoked from the effect's `onCleanup`\n * when `open` flips back to `false`, the config changes while open, or the\n * host is destroyed. What is reset (and what is intentionally retained for\n * `animate.leave`) is the positioner's decision.\n */\n reset(): void;\n}\n\n/**\n * Configuration for {@link runPositioning}. Mirrors the shared shape of the\n * two positioners (`injectFloating`, `injectItemAlignedPositioner`) — the\n * reactive `reference` / `open`, the optional `portal` and anti-flash toggle —\n * and defers the positioner-specific compute + apply + reset to\n * {@link computeAndApply}.\n */\nexport interface PositioningConfig {\n /**\n * The anchor. Reactive — should emit `null` until the anchor is available;\n * positioning is skipped while `null` or `open` is `false`.\n */\n readonly reference: Signal<ReferenceElement | null>;\n\n /**\n * Whether the floating element is currently visible. `autoUpdate` is started\n * when this becomes `true` and torn down when it goes back to `false`.\n */\n readonly open: Signal<boolean>;\n\n /**\n * When `true` (default), the floating element is moved to `document.body` on\n * first render and removed on destroy. Set to `false` to keep it in its\n * declared parent (or when the caller already invokes `injectPortal()`).\n */\n readonly portal?: boolean;\n\n /**\n * When the signal returns anything other than `false` (the default when the\n * signal is omitted), the surface is clipped with `clip-path: inset(50%)`\n * until the first position resolves, so a CSS enter animation never flashes\n * at the viewport corner before the async `computePosition` lands.\n */\n readonly clipUntilPositioned?: Signal<boolean>;\n\n /**\n * Invoked once per **open cycle**, immediately after the first\n * `computePosition` of that cycle resolves and its `run.apply` has run —\n * i.e. after the portal move, after the `clip-path` anti-flash baseline is\n * dropped, and after the positioner has written its `data-*` / CSS vars.\n *\n * The semantics are **per-open, not per-run**: a positioner\n * config change while the surface stays open re-runs the effect (a new\n * positioning run), but this hook does **not** fire again — it fires only on\n * the run that first resolves after `open` transitions to `true`. A run that\n * is superseded (config change while open) or torn down (close / destroy)\n * before its `computePosition` resolves is cancelled: its resolution writes\n * nothing and never fires this hook. This matters because consumers use it to\n * seed one-shot state that a re-fire would corrupt — e.g. scrolling an active\n * option into view inside a freshly portaled listbox, which a per-run re-fire\n * would yank back mid-interaction on every side flip.\n */\n readonly onFirstPosition?: () => void;\n\n /**\n * Builds the per-run controller. Called once per open run, synchronously\n * inside the positioning effect, so its reactive reads (side, align,\n * offsets, selected option, …) register as effect dependencies and a change\n * while open re-runs the effect. Receives the floating element and the\n * resolved (non-null) reference.\n */\n readonly computeAndApply: (el: HTMLElement, reference: ReferenceElement) => PositioningRun;\n}\n\n/**\n * Shared scaffold behind the library's two `@floating-ui/dom` positioners —\n * `injectFloating` (the general anchored positioner) and\n * `injectItemAlignedPositioner` (the macOS-style over-trigger positioner for\n * `[forSelectContent]`). Must be called from an injection context, and takes the `ElementRef` it\n * lives on as the floating element.\n *\n * It owns the portal, the positioning effect and `autoUpdate`, and tears all three down\n * symmetrically so a re-open never inherits stale geometry. While closed the effect tracks only\n * `open` and `reference`, so an offset or side change on a closed overlay re-runs nothing. A\n * `computePosition` that loses its reference mid-frame is swallowed, since `autoUpdate` reschedules\n * on the next live frame.\n *\n * Until the first position resolves the surface wears a `clip-path` anti-flash baseline, re-armed\n * whenever a config change restarts an open run so it stays hidden at the retained stale position.\n * `clip-path` rather than `visibility: hidden` keeps the element focusable, so the overlay shell's\n * initial-focus move still lands while the surface is unpainted.\n *\n * Position is written to `translate`, never `transform`. CSS composes `translate` outside\n * `transform`, so a consumer's `scale` enter animation pivots in place instead of scaling the\n * position offset and dragging the surface in from the viewport corner — leaving `transform` free\n * for the consumer is the point.\n *\n * SSR-safe: `effect()` runs server-side, so the browser gate here is explicit.\n */\nexport function runPositioning(config: PositioningConfig): void {\n const host = inject<ElementRef<HTMLElement>>(ElementRef);\n const el = host.nativeElement;\n\n if (!isPlatformBrowser(inject(PLATFORM_ID))) {\n return;\n }\n\n if (config.portal !== false) {\n injectPortal();\n }\n\n const shouldClip = (): boolean => config.clipUntilPositioned?.() !== false;\n\n afterNextRender(() => {\n Object.assign(el.style, {\n position: 'fixed',\n left: '0',\n top: '0',\n });\n if (shouldClip()) {\n el.style.clipPath = 'inset(50%)';\n }\n });\n\n let openCycleActive = false;\n let firstPositionFired = false;\n\n effect((onCleanup) => {\n const isOpen = config.open();\n const reference = config.reference();\n\n if (!isOpen || !reference) {\n openCycleActive = false;\n return;\n }\n\n if (!openCycleActive) {\n openCycleActive = true;\n firstPositionFired = false;\n }\n\n if (shouldClip()) {\n el.style.clipPath = 'inset(50%)';\n }\n\n const run = config.computeAndApply(el, reference);\n let cancelled = false;\n\n const cleanup = autoUpdate(reference, el, () => {\n computePosition(reference, el, {\n strategy: 'fixed',\n placement: run.placement,\n middleware: run.middleware,\n })\n .then((result) => {\n if (cancelled || !config.open()) {\n return;\n }\n el.style.translate = `${Math.round(result.x)}px ${Math.round(result.y)}px`;\n el.style.clipPath = '';\n run.apply(result);\n if (!firstPositionFired) {\n firstPositionFired = true;\n config.onFirstPosition?.();\n }\n })\n .catch(() => {});\n });\n\n onCleanup(() => {\n cancelled = true;\n cleanup();\n run.reset();\n });\n });\n}\n","import { type Signal } from '@angular/core';\nimport {\n arrow,\n type ComputePositionReturn,\n flip,\n type FlipOptions,\n hide,\n type Middleware,\n offset,\n type Padding,\n type Placement,\n type ReferenceElement,\n shift,\n size,\n} from '@floating-ui/dom';\n\nimport {\n type FloatingCustomProperties,\n injectFloatingCustomProperties,\n} from './floating-custom-properties';\nimport { runPositioning } from './run-positioning';\n\nconst PLACEMENT_OPPOSITE: Record<FloatingSide, FloatingSide> = {\n top: 'bottom',\n right: 'left',\n bottom: 'top',\n left: 'right',\n};\n\n/** The four cardinal sides a floating element can be anchored to. */\nexport type FloatingSide = 'top' | 'right' | 'bottom' | 'left';\n\n/** Alignment along the side axis: at the start edge, centered, or at the end edge. */\nexport type FloatingAlign = 'start' | 'center' | 'end';\n\n/**\n * Direction floating-ui's `flip` middleware falls back to on the *perpendicular*\n * axis when no placement on the preferred axis fits. `'none'` (the default)\n * keeps floating-ui's historical behavior — only the opposite same-axis\n * placement is tried; `'start'` / `'end'` let the surface drop to a\n * perpendicular side (e.g. a right-anchored submenu dropping to `top` / `bottom`)\n * when both sides of the preferred axis overflow.\n */\nexport type FloatingFallbackAxisSideDirection = 'none' | 'start' | 'end';\n\nexport interface FloatingConfig {\n /**\n * The anchor. Either a real DOM element (e.g. a button trigger) or a\n * floating-ui `VirtualElement` (e.g. for context menus that anchor at the\n * pointer position). Reactive — should emit `null` until the anchor is\n * available; positioning is skipped while `null`.\n */\n readonly reference: Signal<ReferenceElement | null>;\n\n /**\n * Whether the floating element is currently visible. `autoUpdate` is\n * started when this becomes `true` and torn down when it goes back to\n * `false`, so consumers don't pay for positioning while closed.\n */\n readonly open: Signal<boolean>;\n\n /**\n * Side the floating element is anchored to (`'top'`/`'right'`/`'bottom'`/\n * `'left'`). When omitted (or the signal returns `undefined`), defaults\n * to `'bottom'`. Pair with `align` for the full positioning\n * API.\n */\n readonly side?: Signal<FloatingSide | undefined>;\n\n /**\n * Alignment along the chosen side. Defaults to `'center'`. With `side`\n * this composes the floating-ui placement (e.g. `side: 'bottom'` +\n * `align: 'start'` → placement `'bottom-start'`).\n */\n readonly align?: Signal<FloatingAlign | undefined>;\n\n /**\n * Distance (px) between reference and floating along the *main* axis\n * (perpendicular to `side`). Forwarded to floating-ui's `offset`\n * middleware. Defaults to `0`.\n */\n readonly sideOffset?: Signal<number | undefined>;\n\n /**\n * Distance (px) along the *cross* axis (parallel to `side`). Useful for\n * shifting an `align: 'start'` popover slightly past the trigger edge.\n */\n readonly alignOffset?: Signal<number | undefined>;\n\n /**\n * Optional arrow element. When non-null, the `arrow` middleware is\n * registered and the helper writes `position: absolute`, the resolved\n * `left` / `top` from floating-ui, and a side-aware\n * `var(--for-floating-arrow-offset, 0px)` on the *opposite* axis once floating-ui\n * resolves a position. Consumers control how far the arrow pokes out of\n * the bubble by setting `--for-floating-arrow-offset` (typically a negative `px`\n * value) on the arrow element or any ancestor — the helper ships no\n * default visual.\n */\n readonly arrow?: Signal<HTMLElement | null>;\n\n /**\n * When `true` (default), the floating element is moved to `document.body`\n * on first render and removed on destroy. Set to `false` to keep it in\n * its declared parent (rare — only for designs where positioning ancestors\n * are guaranteed safe).\n */\n readonly portal?: boolean;\n\n /**\n * When `true` (default), the `flip` and `shift` middlewares are active so\n * the floating element stays inside the viewport. Set to `false` to keep\n * the requested placement even when it overflows — useful for tooltips\n * inside scroll containers where the consumer wants strict positioning.\n */\n readonly avoidCollisions?: Signal<boolean>;\n\n /**\n * Padding (px or per-side rect) applied to both `flip` and `shift`. When\n * unset, `flip` uses padding 0 (legacy behavior) and `shift` uses\n * `shiftPadding` (default 8). Setting this overrides both uniformly.\n */\n readonly collisionPadding?: Signal<number | Padding>;\n\n /**\n * Boundary the collision middlewares (`flip`, `shift`, `size`) measure\n * against. Defaults to the viewport. Pass an element (or list) to keep\n * the floating element inside a scroll container.\n */\n readonly collisionBoundary?: Signal<Element | Element[] | null>;\n\n /**\n * Direction floating-ui's `flip` falls back to on the *perpendicular* axis\n * when no placement on the preferred axis fits. `'none'` (default) keeps the\n * historical behavior — only the opposite same-axis placement is tried; set\n * `'start'` / `'end'` to let a side-anchored surface (e.g. a submenu) drop to\n * a perpendicular side when both sides of the preferred axis overflow. Only\n * consulted when `avoidCollisions` is on.\n */\n readonly fallbackAxisSideDirection?: Signal<FloatingFallbackAxisSideDirection>;\n\n /**\n * Explicit ordered list of fallback placements handed to `flip`. Advanced\n * control; overrides floating-ui's axis-side heuristic when provided. Only\n * consulted when `avoidCollisions` is on.\n */\n readonly fallbackPlacements?: Signal<readonly Placement[] | undefined>;\n\n /** Padding (px) handed to the `arrow` middleware so the arrow stays inside the floating element's rounded corners. */\n readonly arrowPadding?: Signal<number>;\n\n /**\n * Stickiness behaviour for `shift`. `'partial'` (default behavior of\n * `shift`) lets the floating element shift to stay visible. `'always'`\n * disables `shift` so the floating element keeps its requested placement\n * even off-screen. `false` is equivalent to `'partial'`.\n */\n readonly sticky?: Signal<'partial' | 'always' | false>;\n\n /**\n * When `true`, sets `data-detached=\"\"` on the host while the reference\n * element has scrolled off all clipping ancestors (`hide({ strategy:\n * 'escaped' })`). Lets consumers fade out tooltips/popovers tied to\n * scrolled-away triggers.\n */\n readonly hideWhenDetached?: Signal<boolean>;\n\n /**\n * When `true` (default / omitted), the floating element is clipped with\n * `clip-path: inset(50%)` until `@floating-ui/dom` resolves its first\n * position, so a short enter animation never flashes at the viewport\n * corner before placement lands. Set to `false` to paint from the first\n * frame — useful for a dramatic `animate.enter` that would otherwise lose\n * its opening frames while the async `computePosition` resolves, at the\n * cost of a possible first-frame flash at the pre-resolved position.\n */\n readonly clipUntilPositioned?: Signal<boolean>;\n\n /**\n * Invoked once per **open cycle**, on the first resolved position after\n * `open` transitions to `true` — after `@floating-ui/dom`'s async\n * `computePosition` lands, the helper drops the `clip-path` anti-flash\n * baseline, and the positioner has written its `data-*` / CSS vars.\n *\n * The semantics are **per-open, not per-run**: a positioner-config change\n * while the surface stays open re-runs the positioning effect, but this\n * callback does **not** re-fire — it fires only on the run that first\n * resolves after opening, and never while the surface stays closed. A run\n * superseded by a config change (or torn down by a close / destroy) before\n * its `computePosition` resolves is cancelled: its resolution writes nothing\n * and never fires this hook.\n *\n * This per-open guarantee is load-bearing for the seed-once consumers.\n * Because the hook runs strictly after the optional portal's `appendChild`\n * and after `computePosition` (so the `size` middleware's `max-height` is\n * already applied), it is the only moment a consumer can touch the\n * now-portaled, now-sized surface. Combobox uses it to scroll the active\n * descendant into view inside a `max-height`-constrained listbox whose\n * `scrollTop` the portal move reset to 0 — see `[forComboboxContent]`; a\n * per-run re-fire would yank that scroll back on every side flip.\n */\n readonly onFirstPosition?: () => void;\n\n /**\n * Padding (px) handed to the `shift` middleware so the floating element\n * never crowds the viewport edge. Default `8`. Used as the fallback for\n * `collisionPadding` when that signal is not provided.\n */\n readonly shiftPadding?: number;\n}\n\nfunction joinPlacement(side: FloatingSide, align: FloatingAlign): Placement {\n return (align === 'center' ? side : `${side}-${align}`) as Placement;\n}\n\nfunction splitPlacement(p: Placement): { side: FloatingSide; align: FloatingAlign } {\n const [rawSide, rawAlign] = p.split('-') as [FloatingSide, 'start' | 'end' | undefined];\n return { side: rawSide, align: rawAlign ?? 'center' };\n}\n\n/**\n * Compute the CSS `transform-origin` so a CSS scale animates outward from\n * the anchor edge. With `side: 'bottom', align: 'start'` the origin is\n * `left top` — a `scale(0.95)` collapses toward the trigger's bottom-left\n * corner.\n */\nfunction transformOriginFor(side: FloatingSide, align: FloatingAlign): string {\n let x: 'left' | 'right' | 'center';\n let y: 'top' | 'bottom' | 'center';\n if (side === 'top' || side === 'bottom') {\n y = side === 'top' ? 'bottom' : 'top';\n x = align === 'start' ? 'left' : align === 'end' ? 'right' : 'center';\n } else {\n x = side === 'left' ? 'right' : 'left';\n y = align === 'start' ? 'top' : align === 'end' ? 'bottom' : 'center';\n }\n return `${x} ${y}`;\n}\n\n/**\n * Assemble the options handed to floating-ui's `flip` middleware. Kept as a\n * pure function so the collision-fallback wiring (`fallbackAxisSideDirection`,\n * `fallbackPlacements`) is unit-testable without a live DOM — jsdom returns\n * zero rects, so `flip` never actually relocates there.\n *\n * `fallbackAxisSideDirection` is omitted (rather than passed as `'none'`) so the\n * emitted options match floating-ui's own default exactly, and\n * `fallbackPlacements` is omitted when empty / unset.\n */\nexport function buildFlipOptions(options: {\n readonly padding: number | Padding;\n readonly boundary: Element | Element[] | null;\n readonly fallbackAxisSideDirection: FloatingFallbackAxisSideDirection;\n readonly fallbackPlacements: readonly Placement[] | undefined;\n}): FlipOptions {\n const flipOptions: FlipOptions = { padding: options.padding };\n if (options.boundary) {\n flipOptions.boundary = options.boundary;\n }\n if (options.fallbackAxisSideDirection !== 'none') {\n flipOptions.fallbackAxisSideDirection = options.fallbackAxisSideDirection;\n }\n if (options.fallbackPlacements?.length) {\n flipOptions.fallbackPlacements = [...options.fallbackPlacements];\n }\n return flipOptions;\n}\n\n/**\n * Wires a floating UI element (tooltip, popover, menu...) to its anchor.\n * Must be called from an injection context. Delegates the platform gate,\n * portal, anti-flash baseline, `autoUpdate` loop, and symmetric cleanup to\n * the shared {@link runPositioning} scaffold, and supplies the anchored\n * positioner's own per-run body: the `offset` / `flip` / `shift` / `size` /\n * `hide` / `arrow` middleware stack, plus the writes that follow each resolved\n * position — `data-placement`, `data-side`, `data-align`, `data-occluded`\n * (when the `hide` middleware reports the reference is off-screen),\n * `data-detached` (when `hideWhenDetached` is on and the reference escaped its\n * clipping ancestors), the `--for-floating-anchor-width/-height`,\n * `--for-floating-available-width/-height`, and `--for-floating-content-transform-origin` CSS\n * variables, and the optional arrow's position + `--for-floating-arrow-offset`.\n *\n * Once per open cycle, on the first resolved position after opening, it invokes\n * `onFirstPosition` — after the portal move and after `size` applied its\n * `max-height`, so a consumer can touch the now-portaled, now-sized surface. A\n * config change while open does not re-fire it; see\n * {@link FloatingConfig.onFirstPosition}.\n *\n * Cleanup is asymmetric on purpose: {@link resetFloatingStyles} strips the\n * transient sizing vars and occlusion attributes but retains the resolved\n * `translate` and placement outputs so a closing surface stays anchored to its\n * trigger through `animate.leave`; the next mount re-arms the baseline and\n * recomputes everything before painting.\n *\n * Stylistic concerns (which side gets the arrow offset via\n * `--for-floating-arrow-offset`, pointer events, background, animations) stay with the\n * consumer.\n */\nexport function injectFloating(config: FloatingConfig): void {\n const fallbackShiftPadding = config.shiftPadding ?? 8;\n const vars = injectFloatingCustomProperties();\n\n runPositioning({\n reference: config.reference,\n open: config.open,\n portal: config.portal,\n clipUntilPositioned: config.clipUntilPositioned,\n onFirstPosition: config.onFirstPosition,\n computeAndApply: (el, reference) => {\n const arrowEl = config.arrow?.() ?? null;\n\n // Resolve placement from `side` + `align` with sensible defaults.\n const sideInput = config.side?.() ?? 'bottom';\n const alignInput = config.align?.() ?? 'center';\n const requestedPlacement: Placement = joinPlacement(sideInput, alignInput);\n\n const sideOffsetVal = config.sideOffset?.() ?? 0;\n const alignOffsetVal = config.alignOffset?.() ?? 0;\n const avoidCollisions = config.avoidCollisions?.() ?? true;\n // `collisionPadding`, when set, applies uniformly to flip + shift +\n // size. When unset, preserve the historical defaults:\n // `flip` had no padding, `shift` had `shiftPadding ?? 8`.\n const collisionPaddingExplicit = config.collisionPadding?.();\n const flipPaddingValue = collisionPaddingExplicit ?? 0;\n const shiftPaddingValue = collisionPaddingExplicit ?? fallbackShiftPadding;\n const sizePaddingValue = collisionPaddingExplicit ?? fallbackShiftPadding;\n const collisionBoundary = config.collisionBoundary?.() ?? null;\n const arrowPaddingVal = config.arrowPadding?.() ?? 0;\n const stickyVal = config.sticky?.() ?? false;\n const hideOnDetach = config.hideWhenDetached?.() ?? false;\n\n const middleware: Middleware[] = [\n offset({ mainAxis: sideOffsetVal, crossAxis: alignOffsetVal }),\n ];\n\n if (avoidCollisions) {\n middleware.push(\n flip(\n buildFlipOptions({\n padding: flipPaddingValue,\n boundary: collisionBoundary,\n fallbackAxisSideDirection: config.fallbackAxisSideDirection?.() ?? 'none',\n fallbackPlacements: config.fallbackPlacements?.(),\n }),\n ),\n );\n\n if (stickyVal !== 'always') {\n const shiftOptions: Parameters<typeof shift>[0] = { padding: shiftPaddingValue };\n if (collisionBoundary) shiftOptions.boundary = collisionBoundary;\n middleware.push(shift(shiftOptions));\n }\n }\n\n // `size` exposes available width/height as CSS variables so the\n // consumer can `max-height: var(--for-floating-available-height)` etc.\n const sizeOptions: Parameters<typeof size>[0] = {\n padding: sizePaddingValue,\n apply({ availableWidth, availableHeight }) {\n el.style.setProperty(vars.availableWidth, `${Math.max(0, Math.round(availableWidth))}px`);\n el.style.setProperty(\n vars.availableHeight,\n `${Math.max(0, Math.round(availableHeight))}px`,\n );\n },\n };\n if (collisionBoundary) sizeOptions.boundary = collisionBoundary;\n middleware.push(size(sizeOptions));\n\n middleware.push(hide({ strategy: 'referenceHidden' }));\n if (hideOnDetach) {\n middleware.push(hide({ strategy: 'escaped' }));\n }\n\n if (arrowEl) {\n middleware.push(arrow({ element: arrowEl, padding: arrowPaddingVal }));\n }\n\n return {\n placement: requestedPlacement,\n middleware,\n apply({ placement: resolvedPlacement, middlewareData }: ComputePositionReturn) {\n const { side: resolvedSide, align: resolvedAlign } = splitPlacement(\n resolvedPlacement as Placement,\n );\n\n el.dataset['placement'] = resolvedPlacement;\n el.dataset['side'] = resolvedSide;\n el.dataset['align'] = resolvedAlign;\n\n // Anchor box → CSS vars so the consumer can size the floating\n // element relative to the anchor (`width: var(--for-floating-anchor-width)`).\n // Both real `Element`s and floating-ui `VirtualElement`s expose\n // `getBoundingClientRect`, so the call is safe.\n const rect = reference.getBoundingClientRect();\n el.style.setProperty(vars.anchorWidth, `${Math.round(rect.width)}px`);\n el.style.setProperty(vars.anchorHeight, `${Math.round(rect.height)}px`);\n el.style.setProperty(\n vars.contentTransformOrigin,\n transformOriginFor(resolvedSide, resolvedAlign),\n );\n\n // hide() with strategy 'referenceHidden' — anchor scrolled off-screen.\n if (middlewareData.hide?.['referenceHidden']) {\n el.dataset['occluded'] = '';\n } else {\n delete el.dataset['occluded'];\n }\n // hide() with strategy 'escaped' — only registered when\n // `hideWhenDetached` is on.\n if (hideOnDetach && middlewareData.hide?.['escaped']) {\n el.dataset['detached'] = '';\n } else {\n delete el.dataset['detached'];\n }\n\n if (arrowEl && middlewareData.arrow) {\n const { x: ax, y: ay } = middlewareData.arrow;\n const opposite = PLACEMENT_OPPOSITE[resolvedSide];\n Object.assign(arrowEl.style, {\n position: 'absolute',\n left: ax != null ? `${ax}px` : '',\n top: ay != null ? `${ay}px` : '',\n right: '',\n bottom: '',\n [opposite]: `var(${vars.arrowOffset}, 0px)`,\n });\n // `data-placement` on the arrow stores the *side* only, for\n // historical reasons (CSS like `[data-placement=\"top\"]`).\n // `data-side` is the new canonical attribute; both stay in\n // sync until consumers migrate.\n arrowEl.dataset['placement'] = resolvedSide;\n arrowEl.dataset['side'] = resolvedSide;\n }\n },\n reset() {\n resetFloatingStyles(el, vars);\n if (arrowEl) {\n resetArrowStyles(arrowEl);\n }\n },\n };\n },\n });\n}\n\n/**\n * Strip the transient sizing CSS custom properties, the occlusion `data-*`\n * attributes, and the `clip-path` hide baseline `injectFloating` writes to the\n * floating element. The resolved `translate` and the resolved-placement outputs\n * (`--for-floating-content-transform-origin`, `data-placement`, `data-side`,\n * `data-align`) are intentionally retained so a closing surface stays anchored\n * to its trigger — and keeps pivoting its scale leave from the trigger edge —\n * through `animate.leave`; the next mount re-arms the `clip-path` baseline in\n * `afterNextRender` and recomputes all of them before painting, so a retained\n * value never produces a stale-position flash.\n */\nfunction resetFloatingStyles(el: HTMLElement, vars: FloatingCustomProperties): void {\n // Clearing (not re-arming) the hide baseline keeps a closing surface\n // visible for its `animate.leave`; the next mount re-applies the\n // `clip-path` baseline in `afterNextRender`.\n el.style.removeProperty('clip-path');\n el.style.removeProperty(vars.anchorWidth);\n el.style.removeProperty(vars.anchorHeight);\n el.style.removeProperty(vars.availableWidth);\n el.style.removeProperty(vars.availableHeight);\n el.removeAttribute('data-occluded');\n el.removeAttribute('data-detached');\n}\n\n/**\n * Strip every inline style and `data-*` attribute `injectFloating` writes\n * to the optional arrow element. Mirrors `resetFloatingStyles`.\n */\nfunction resetArrowStyles(arrowEl: HTMLElement): void {\n arrowEl.style.removeProperty('position');\n arrowEl.style.removeProperty('left');\n arrowEl.style.removeProperty('top');\n arrowEl.style.removeProperty('right');\n arrowEl.style.removeProperty('bottom');\n arrowEl.removeAttribute('data-placement');\n arrowEl.removeAttribute('data-side');\n}\n","import { type Signal } from '@angular/core';\nimport {\n type Middleware,\n type Padding,\n type Placement,\n type ReferenceElement,\n} from '@floating-ui/dom';\n\nimport {\n type FloatingCustomProperties,\n injectFloatingCustomProperties,\n} from './floating-custom-properties';\nimport { runPositioning } from './run-positioning';\n\nexport interface ItemAlignedConfig {\n /**\n * The anchor (typically a `<button>` trigger). Reactive — should emit\n * `null` until the anchor is available; positioning is skipped while\n * `null` or `open` is `false`.\n */\n readonly reference: Signal<ReferenceElement | null>;\n\n /**\n * Whether the listbox is currently visible. `autoUpdate` is started when\n * this becomes `true` and torn down when it goes back to `false`.\n */\n readonly open: Signal<boolean>;\n\n /**\n * The selected option element to anchor over the trigger. When `null`,\n * the algorithm falls back to the first enabled `[role=\"option\"]` inside\n * the listbox. Reactive — re-running `computePosition` if the selection\n * changes while open.\n */\n readonly selectedOption: Signal<HTMLElement | null>;\n\n /**\n * Padding (px) the listbox keeps from the viewport edge. Default `8`.\n * Drives both the viewport clamp on the listbox top/bottom and the\n * `--for-floating-available-height` CSS variable.\n */\n readonly collisionPadding?: Signal<number | Padding>;\n\n /**\n * Called once per open cycle, on the first resolved position, after the listbox has been\n * portaled and its CSS vars written. When set it replaces the positioner's own first-position\n * scroll of the anchored option, so the caller decides which option to reveal.\n */\n readonly onFirstPosition?: () => void;\n\n /**\n * When `true` (default), the floating element is moved to `document.body`\n * on first render and removed on destroy. Set to `false` when the caller\n * already invokes `injectPortal()` on its own.\n */\n readonly portal?: boolean;\n}\n\nfunction paddingTop(padding: number | Padding | undefined, fallback: number): number {\n if (padding == null) {\n return fallback;\n }\n if (typeof padding === 'number') {\n return padding;\n }\n return padding.top ?? fallback;\n}\n\nfunction findFirstEnabledOption(listbox: HTMLElement): HTMLElement | null {\n const options = listbox.querySelectorAll<HTMLElement>('[role=\"option\"]');\n for (let i = 0; i < options.length; i++) {\n const opt = options[i]!;\n if (opt.getAttribute('aria-disabled') === 'true' || opt.hasAttribute('disabled')) {\n continue;\n }\n return opt;\n }\n return null;\n}\n\nexport interface ItemAlignedGeometry {\n /** Viewport-relative top edge of the anchor. */\n readonly triggerTop: number;\n\n readonly triggerHeight: number;\n\n /** Border-box height of the listbox, excluding any CSS transform. */\n readonly listboxHeight: number;\n\n /**\n * Distance from the listbox's top border edge to the vertical center of the\n * option to anchor over the trigger, or `null` when the listbox holds no\n * anchorable option — the listbox then aligns to the trigger's top edge.\n */\n readonly targetCenter: number | null;\n\n readonly viewportHeight: number;\n\n /** Distance the listbox keeps from the viewport's top and bottom edges. */\n readonly padding: number;\n}\n\n/**\n * Resolves the listbox's vertical offset so the target option's center lines up\n * with the trigger's center, clamped inside the viewport. A listbox taller than\n * the band the padding leaves cannot satisfy both edges and pins to the top.\n */\nexport function resolveItemAlignedY(geometry: ItemAlignedGeometry): number {\n const { triggerTop, triggerHeight, listboxHeight, targetCenter, viewportHeight, padding } =\n geometry;\n const minY = padding;\n const maxY = viewportHeight - listboxHeight - padding;\n\n if (targetCenter == null) {\n return Math.max(minY, Math.min(triggerTop, maxY));\n }\n\n const desiredY = triggerTop + triggerHeight / 2 - targetCenter;\n return maxY > minY ? Math.max(minY, Math.min(desiredY, maxY)) : minY;\n}\n\nfunction offsetTopWithinChain(el: HTMLElement): number {\n const view = el.ownerDocument.defaultView;\n let top = 0;\n let node: HTMLElement | null = el;\n while (node) {\n top += node.offsetTop;\n const parent: Element | null = node.offsetParent;\n node = view && parent instanceof view.HTMLElement ? parent : null;\n }\n return top;\n}\n\n/**\n * Distance from `listbox`'s top border edge to `target`'s vertical center, read\n * from offset geometry so a CSS transform on either element cannot skew it.\n * Offset geometry is integer-rounded, so the result is accurate to about a\n * pixel.\n */\nexport function offsetCenterWithinListbox(target: HTMLElement, listbox: HTMLElement): number {\n return offsetTopWithinChain(target) + target.offsetHeight / 2 - offsetTopWithinChain(listbox);\n}\n\n/**\n * Custom floating-ui middleware. Computes raw `x`/`y` so the *target option's\n * vertical center* lines up with the *trigger's vertical center*, then clamps\n * the listbox inside the viewport with `padding`. Cross-axis: listbox left\n * edge aligned to the trigger left edge.\n *\n * Falls back to the first enabled option inside the listbox when no option\n * is selected — matches the macOS `<select>` behavior.\n */\nfunction itemAligned(\n selectedOption: () => HTMLElement | null,\n paddingFn: () => number,\n): Middleware {\n return {\n name: 'item-aligned',\n fn(state) {\n const reference = state.elements.reference;\n const floating = state.elements.floating;\n const triggerRect = reference.getBoundingClientRect();\n const target = selectedOption() ?? findFirstEnabledOption(floating);\n // Read the viewport height through the floating element's own\n // window so the middleware works in iframes / multiple-document\n // contexts and stays SSR-safe (the middleware itself only runs\n // inside a `computePosition` callback, which is browser-only).\n const viewportHeight = floating.ownerDocument.defaultView?.innerHeight ?? 0;\n\n const y = resolveItemAlignedY({\n triggerTop: triggerRect.top,\n triggerHeight: triggerRect.height,\n listboxHeight: floating.offsetHeight,\n targetCenter: target ? offsetCenterWithinListbox(target, floating) : null,\n viewportHeight,\n padding: paddingFn(),\n });\n\n return { x: triggerRect.left, y };\n },\n };\n}\n\n/**\n * Item-aligned positioner for `[forSelectContent]` (the `position=\"item-aligned\"`\n * mode). The listbox overlays the trigger so the *selected option*'s center\n * lines up with the trigger's center on the cross axis — visually the menu\n * \"snaps over\" the trigger when opened, mirroring macOS native `<select>`\n * dropdowns.\n *\n * Delegates the platform gate, portal, anti-flash baseline, `autoUpdate` loop,\n * `translate` write, `clip-path` drop, and symmetric cleanup to the shared\n * {@link runPositioning} scaffold, and supplies its own per-run body: the\n * custom `itemAligned` middleware plus the writes that follow each resolved\n * position — `data-position=\"item-aligned\"`, the `--for-floating-anchor-width/-height`\n * and `--for-floating-available-height` CSS vars — and, on the first resolved position,\n * `scrollIntoView({ block: 'nearest' })` on the target option so the visual\n * anchor stays correct when the listbox is taller than the viewport, unless\n * `onFirstPosition` is supplied, which then owns that reveal.\n *\n * `--for-floating-available-height` is the same *concept* the anchored positioner\n * publishes (the maximum block-size the surface may occupy before it\n * collides), computed for this algorithm: the surface overlays the trigger\n * rather than sitting beside it, so the band is the full viewport minus\n * `collisionPadding` on both edges (`innerHeight - 2 * collisionPadding`)\n * rather than the anchor-relative space floating-ui's `size` middleware\n * reports. A consumer's `max-height: var(--for-floating-available-height)` therefore\n * works unchanged across `position=\"popper\"` and `position=\"item-aligned\"`.\n * `--for-floating-available-width` is **not** published here: item-aligned\n * pins the cross axis to the trigger's left edge and computes no width budget.\n *\n * `side`, `align`, `sideOffset`, `alignOffset`, `placement`, `flip`, `shift`,\n * and `arrow` are intentionally **not** part of this API — item-aligned mode\n * treats them as no-ops.\n */\nexport function injectItemAlignedPositioner(config: ItemAlignedConfig): void {\n const vars = injectFloatingCustomProperties();\n runPositioning({\n reference: config.reference,\n open: config.open,\n portal: config.portal,\n onFirstPosition: config.onFirstPosition,\n computeAndApply: (el, reference) => {\n const collisionPadding = paddingTop(config.collisionPadding?.(), 8);\n\n let initialScrollDone = config.onFirstPosition !== undefined;\n\n return {\n // Placement is irrelevant — `itemAligned` overrides x/y outright —\n // but `computePosition` requires *some* placement. Pick a stable one\n // so middleware data stays predictable.\n placement: 'bottom-start' satisfies Placement,\n middleware: [\n itemAligned(\n () => config.selectedOption(),\n () => collisionPadding,\n ),\n ],\n apply() {\n el.dataset['position'] = 'item-aligned';\n\n const triggerRect = reference.getBoundingClientRect();\n el.style.setProperty(vars.anchorWidth, `${Math.round(triggerRect.width)}px`);\n el.style.setProperty(vars.anchorHeight, `${Math.round(triggerRect.height)}px`);\n\n const innerHeight = el.ownerDocument.defaultView?.innerHeight ?? 0;\n const availableHeight = Math.max(0, innerHeight - 2 * collisionPadding);\n el.style.setProperty(vars.availableHeight, `${Math.round(availableHeight)}px`);\n\n if (!initialScrollDone) {\n initialScrollDone = true;\n const target = config.selectedOption() ?? findFirstEnabledOption(el);\n // jsdom (test env) doesn't implement scrollIntoView — guard the\n // call so the helper stays usable in non-browser environments.\n target?.scrollIntoView?.({ block: 'nearest' });\n }\n },\n reset() {\n resetItemAlignedStyles(el, vars);\n },\n };\n },\n });\n}\n\n/**\n * Strip the transient sizing vars, CSS custom properties, and `data-*`\n * attributes `injectItemAlignedPositioner` writes to the listbox — including\n * the `clip-path` hide baseline — while **retaining** the resolved `translate`.\n * Mirrors `resetFloatingStyles` in `floating.ts`: the surface is portaled\n * until `getAnimations().finished`, so during an `animate.leave` exit the host\n * keeps `position: fixed; left: 0; top: 0` and the retained `translate` stays\n * anchored over the trigger instead of flashing at the viewport origin. The\n * next mount re-arms the `clip-path` baseline in `afterNextRender` and\n * recomputes the position before painting, so the retained `translate` never\n * produces a stale-position flash.\n */\nfunction resetItemAlignedStyles(el: HTMLElement, vars: FloatingCustomProperties): void {\n el.style.removeProperty('clip-path');\n el.style.removeProperty(vars.anchorWidth);\n el.style.removeProperty(vars.anchorHeight);\n el.style.removeProperty(vars.availableHeight);\n el.removeAttribute('data-position');\n}\n","import { DestroyRef, ElementRef, inject, type Signal } from '@angular/core';\n\nimport {\n afterNextRenderCancellable,\n findFirstFocusable,\n findTabbableEdges,\n isInitialFocusTarget,\n leavesTabSequence,\n resolveActiveElement,\n resolveEventTarget,\n type VetoableNativeEvent,\n} from 'forty-cdk/core';\nimport {\n injectDismissibleLayer,\n type DismissibleLayerActivateOptions,\n type DismissibleLayerNesting,\n} from '../dismissible-layer/dismissible-layer';\nimport { injectFloating, type FloatingConfig } from '../floating/floating';\nimport { InertSiblingsStack } from '../inert-siblings/inert-siblings';\nimport { ModalActivationOrder } from '../modal-shell/modal-activation-order';\nimport { injectItemAlignedPositioner, type ItemAlignedConfig } from '../floating/item-aligned';\nimport { buildOutsideVetoOptions, outsideVetoChannels } from './outside-veto';\n\n/**\n * Tagged-union positioner config. The shell delegates to either\n * `injectFloating` (the standard anchored placement) or\n * `injectItemAlignedPositioner` (the macOS-style overlay used by Select's\n * `position=\"item-aligned\"` mode). Both helpers portal by default, so the\n * shell never calls `injectPortal` itself — that responsibility stays with\n * the positioner.\n */\nexport type OverlayShellPositionerConfig =\n | ({ readonly kind: 'floating' } & FloatingConfig)\n | ({ readonly kind: 'item-aligned' } & ItemAlignedConfig);\n\n/**\n * Outside-interaction wiring for a trigger-anchored overlay.\n *\n * Each wired channel builds one `VetoableNativeEvent` and hands it to both the specific emitter and\n * the composite `interactOutside` one, so a `preventDefault()` from either vetoes the close. When\n * nothing vetoes and `dismissible()` is `true`, the shell calls `requestClose` with the channel's\n * reason. `dismissible` and `requestClose` are required whenever any outside channel is wired.\n *\n * `exemptElements` is re-read on every event, so newly portaled siblings and swapped triggers are\n * honoured.\n *\n * Escape is forwarded verbatim and never participates in the outside-close: its close behaviour\n * differs per primitive, so emitting and closing stay the consumer's decision.\n *\n * Every callback is optional; the shell registers a listener only for the channels supplied.\n */\nexport interface OverlayShellDismissConfig {\n /**\n * Whether an un-vetoed outside interaction fires the implicit\n * `requestClose`. Required when any outside channel\n * (`emitPointerDownOutside` / `emitFocusOutside` / `emitInteractOutside`)\n * is wired.\n */\n readonly dismissible?: Signal<boolean>;\n /**\n * Called with the matching reason when the consumer doesn't veto an outside\n * interaction. The consumer owns the close (and any bookkeeping such as\n * marking the control touched); the shell never touches the directive's\n * close output directly. Required alongside `dismissible`. Each wired outside\n * channel fires its own close, so a specific channel (`emitPointerDownOutside`\n * / `emitFocusOutside`) closes even without `emitInteractOutside` wired. A\n * close requested here never returns focus on destroy.\n */\n readonly requestClose?: (reason: 'pointerDownOutside' | 'focusOutside') => void;\n /** Forwards the raw Escape `KeyboardEvent` to the consumer; close is consumer-owned. */\n readonly emitEscapeKeyDown?: (event: KeyboardEvent) => void;\n /** Forwards the pointer-down-outside veto to the directive's `(pointerDownOutside)` output. */\n readonly emitPointerDownOutside?: (veto: VetoableNativeEvent<PointerEvent>) => void;\n /** Forwards the focus-outside veto to the directive's `(focusOutside)` output. */\n readonly emitFocusOutside?: (veto: VetoableNativeEvent<FocusEvent>) => void;\n /** Forwards the composite veto to the directive's `(interactOutside)` output. */\n readonly emitInteractOutside?: (veto: VetoableNativeEvent<PointerEvent | FocusEvent>) => void;\n /**\n * Extra elements whose subtrees count as \"inside\" for outside-pointer /\n * outside-focus checks (e.g. an anchored trigger that lives outside the\n * portaled content). Recomputed on every event so DOM mutations are\n * picked up, and handed the node being tested.\n */\n readonly exemptElements?: (target: Node) => readonly Element[];\n /**\n * Declared nesting position of this surface inside a chain of structurally\n * nested overlays (a menu and its submenus). Forwarded verbatim to the\n * dismissible layer so the stack orders the chain by depth instead of by the\n * order the levels happened to render in. Omit for a standalone overlay.\n */\n readonly nesting?: DismissibleLayerNesting;\n /**\n * Whether the surface also closes on an outside press the overlay stacked directly above it\n * closed on, instead of leaving that press to the topmost overlay alone. Read on every press.\n */\n readonly cascadeOutsidePress?: () => boolean;\n}\n\n/**\n * Where initial focus should land when the surface mounts.\n *\n * - `'first'` — first focusable descendant of the host (uses the shared\n * `findFirstFocusable` selector). Falls back to the host element itself.\n * - `'container'` — host element (gets `tabindex=\"-1\"` semantics from the\n * primitive's host bindings).\n * - `move()` — primitive-owned focus algorithm (e.g. Menu's\n * `focusInitialEnabledItem`, Select's `focusSelectedOption`). Should return\n * `true` on success and `false` if no candidate was found, so the shell can\n * fall back to focusing the host element.\n */\nexport type OverlayShellInitialFocusMove = 'first' | 'container' | (() => boolean);\n\n/**\n * Optional initial-focus wiring. Absent when the consumer wants focus to\n * stay where it is (Combobox keeps focus in the input; Tooltip / HoverCard\n * have no focus moves).\n *\n * `veto` corresponds to the `(autoFocusOnOpen)` output: returning `true`\n * skips the imperative focus move.\n */\nexport interface OverlayShellInitialFocusConfig {\n readonly move: OverlayShellInitialFocusMove;\n readonly veto?: () => boolean;\n /**\n * Element the consumer marked as the initial focus target, read once at mount. When it resolves\n * to an element that passes `isInitialFocusTarget`, focus lands there instead of running `move`.\n */\n readonly target?: () => HTMLElement | null;\n}\n\n/**\n * Optional return-focus wiring. Absent when the consumer never wants to\n * return focus on destroy (Combobox closes back into the input via its own\n * keydown / blur paths; Tooltip / HoverCard are non-focusing).\n *\n * - `enabled` — the primitive's `[returnFocus]` input. When `false`, the\n * shell skips the return-focus call entirely.\n * - `target` — the element to focus on destroy (typically the trigger).\n * Returning `null` is a safe no-op (the trigger may have unmounted).\n * - `veto` — `(autoFocusOnClose)` veto. Returning `true` skips the focus\n * call.\n * - `skip` — additional opt-out, read before `veto`. The shell already skips\n * the return after a close it requested itself, through an outside channel\n * or a Tab out, since focus is then where the user moved it. `skip` covers\n * the closes that reach the root another way, such as a Tab the root handles\n * or a close propagated from a nested surface.\n */\nexport interface OverlayShellReturnFocusConfig {\n readonly enabled: Signal<boolean>;\n readonly target: () => HTMLElement | null;\n readonly veto?: () => boolean;\n readonly skip?: () => boolean;\n}\n\n/**\n * Optional Tab-out wiring for a non-modal surface portaled away from its trigger. A Tab past the\n * surface's last tabbable lands on the element after `target` in the page's tab order, and a\n * Shift+Tab before its first lands on `target` itself, as if the surface sat right after it.\n *\n * - `target` — the element the surface follows in the tab order (typically the trigger).\n * Returning `null` leaves Tab to the browser.\n * - `close` — closes the surface after the focus move, unless `dismiss.dismissible()` is\n * `false`. Return focus is skipped for that close.\n */\nexport interface OverlayShellTabOutConfig {\n readonly target: () => HTMLElement | null;\n readonly close: () => void;\n}\n\n/**\n * Single config for the overlay-content lifecycle. Each sub-bundle is\n * individually optional so the nine concrete primitives (Popover, Menu,\n * MenuSub, ContextMenu, DropdownMenu, Combobox, Select, Tooltip, HoverCard)\n * can opt in to only the pieces they need.\n *\n * The shell never reads any of the primitive's own context tokens — the\n * caller forwards each piece as plain signals / callbacks so the shell stays\n * orthogonal to the primitive surface and trivially mockable in tests.\n */\nexport interface OverlayShellConfig {\n readonly positioner: OverlayShellPositionerConfig;\n readonly dismiss?: OverlayShellDismissConfig;\n readonly initialFocus?: OverlayShellInitialFocusConfig;\n readonly returnFocus?: OverlayShellReturnFocusConfig;\n readonly tabOut?: OverlayShellTabOutConfig;\n}\n\n/**\n * Owns the lifecycle of a portaled, trigger-anchored overlay surface — the `*-content` directives\n * of Popover, the menu family, Combobox, Select, Tooltip and HoverCard.\n *\n * Positioning is delegated to the configured positioner, which portals the host itself: the caller\n * must not also call `injectPortal`.\n *\n * When configured, the shell activates a dismissible layer after the first render, performs the\n * initial focus move — falling back to the host when the move finds no candidate — and restores\n * focus to the return target on destroy. Both focus moves are skipped when their `veto()` returns\n * truthy, which is how `autoFocusOnOpen` / `autoFocusOnClose` are honoured. The return is also\n * skipped when the surface closed through one of its own outside channels or a Tab out, without\n * consulting `veto`: focus already moved where the user put it.\n *\n * Return focus runs after the portaled node has been detached, so the trigger receives the focus\n * event in a settled layout.\n *\n * Must be called from an injection context. The host's `ElementRef` is forwarded to the dismissible\n * layer and the positioner.\n */\nexport function injectOverlayShell(config: OverlayShellConfig): void {\n const host = inject<ElementRef<HTMLElement>>(ElementRef);\n const el = host.nativeElement;\n const inertStack = inject(InertSiblingsStack);\n const order = inject(ModalActivationOrder);\n\n // 1. Dismissible layer. Created BEFORE the positioner so its\n // `DestroyRef.onDestroy` (dismissible.deactivate) registers first and\n // therefore runs first on teardown — i.e. the layer is removed from\n // the stack before the positioner's portal removes the node from the\n // DOM. That ordering matches every pre-shell *-content directive and\n // avoids a window where a focusin fired during DOM removal could\n // route through `handleFocusIn` and trigger a spurious onFocusOutside.\n const dismissCfg = config.dismiss;\n const layer = dismissCfg !== undefined ? injectDismissibleLayer() : null;\n\n // 2. Positioner. The kind is read once at construction; switching modes\n // at runtime would require unmounting + remounting the directive,\n // which is the expected pattern for primitives whose positioning\n // algorithm is structurally different (Select's two modes).\n if (config.positioner.kind === 'item-aligned') {\n const { kind: _ignored, ...rest } = config.positioner;\n injectItemAlignedPositioner(rest);\n } else {\n const { kind: _ignored, ...rest } = config.positioner;\n injectFloating(rest);\n }\n\n // 3. afterNextRender — activate the layer and run initial focus once\n // input bindings have settled. Both pieces depend on having a\n // fully-rendered host element (exempt-element queries, focus targets).\n // `afterNextRenderCancellable` makes the destroy-before-render path safe.\n // On the true-async path (queued render after destroy) the callback is\n // cancelled, so the dismissible layer is never pushed onto the stack. On\n // the synchronous-teardown path the callback flushes just before the\n // layer's own `DestroyRef.onDestroy` (registered above via\n // `injectDismissibleLayer`, so it runs first among the destroy hooks),\n // which pops the just-pushed layer. Either way the stack is left without\n // a dead topmost entry that would swallow every later Escape /\n // pointer-down-outside.\n let destroyed = false;\n let releasePeer: (() => void) | null = null;\n inject(DestroyRef).onDestroy(() => {\n destroyed = true;\n releasePeer?.();\n releasePeer = null;\n });\n afterNextRenderCancellable(() => {\n const anchor = resolveModalAnchor(config);\n order.after(order.enclosingHeld(anchor), () => {\n if (!destroyed) {\n activate(anchor);\n }\n });\n });\n\n const activate = (anchor: Element | null): void => {\n // Modal-peer registration (#676). The positioner's portal ran in an\n // earlier hook of this same render batch, so the host is already in\n // `body`. Registering it with the anchor lets `InertSiblingsStack` leave it\n // live while the anchor belongs to the topmost modal — opened from inside a\n // Dialog / Drawer (a Select in a form, a context menu on dialog content) —\n // and inert it under any other owner, so a toast / background overlay stays\n // isolated (#388) and a background modal's overlay is inerted under a\n // nested modal. The registration lands before the inert observer's\n // microtask inspects the portaled host.\n if (anchor !== null) {\n releasePeer = inertStack.registerPeer(el, [anchor]);\n }\n\n if (layer && dismissCfg) {\n const requestClose = dismissCfg.requestClose;\n const options: DismissibleLayerActivateOptions = {\n channels: outsideVetoChannels(dismissCfg),\n ...buildOutsideVetoOptions(\n requestClose\n ? {\n ...dismissCfg,\n requestClose: (reason) => {\n closedByOutside = true;\n requestClose(reason);\n },\n }\n : dismissCfg,\n ),\n };\n\n if (dismissCfg.exemptElements) {\n options.exemptElements = dismissCfg.exemptElements;\n }\n if (dismissCfg.nesting) {\n options.nesting = dismissCfg.nesting;\n }\n if (dismissCfg.cascadeOutsidePress) {\n options.cascadeOutsidePress = dismissCfg.cascadeOutsidePress;\n }\n // Escape: forwarded verbatim. The consumer owns the emit + close\n // decision (combobox routes it through its input directive instead and\n // omits this channel; hover-card schedules a timed close).\n if (dismissCfg.emitEscapeKeyDown) {\n options.onEscapeKeyDown = dismissCfg.emitEscapeKeyDown;\n }\n\n layer.activate(options);\n }\n\n const focusCfg = config.initialFocus;\n if (focusCfg) {\n // Veto first — the `(autoFocusOnOpen)` output's `preventDefault`\n // returns true here, mirroring what the per-primitive code did.\n if (focusCfg.veto?.()) {\n return;\n }\n const marked = focusCfg.target?.() ?? null;\n const move = focusCfg.move;\n if (marked !== null && isInitialFocusTarget(marked, el)) {\n marked.focus();\n } else if (move === 'first') {\n (findFirstFocusable(el) ?? el).focus();\n } else if (move === 'container') {\n el.focus();\n } else {\n // Primitive-owned focus algorithm (Menu's first/last item, Select's\n // selected option, etc.). Returns true on success; on miss we fall\n // back to the host so keyboard users land somewhere predictable.\n const moved = move();\n if (!moved) {\n el.focus();\n }\n }\n }\n };\n\n let tabbedOut = false;\n let closedByOutside = false;\n const tabOutCfg = config.tabOut;\n if (tabOutCfg) {\n const onKeyDown = (event: KeyboardEvent): void => {\n if (handleTabOut(event, el, tabOutCfg, dismissCfg?.dismissible?.() ?? true)) {\n tabbedOut = true;\n layer?.deactivate();\n }\n };\n el.addEventListener('keydown', onKeyDown);\n inject(DestroyRef).onDestroy(() => el.removeEventListener('keydown', onKeyDown));\n }\n\n // 4. Return focus on destroy. The hook is registered AFTER the layer's\n // destroy hook (created above) and AFTER the positioner's portal hook\n // (created inside injectFloating / injectItemAlignedPositioner) so it\n // runs last — same ordering as the pre-shell hand-rolled code.\n const rfCfg = config.returnFocus;\n if (rfCfg) {\n inject(DestroyRef).onDestroy(() => {\n if (tabbedOut || closedByOutside || rfCfg.skip?.()) {\n return;\n }\n if (rfCfg.veto?.()) {\n return;\n }\n if (!rfCfg.enabled()) {\n return;\n }\n rfCfg.target()?.focus();\n });\n }\n}\n\n/**\n * Moves focus to the tab-out target when a Tab press would leave the surface's Tab cycle, then\n * closes the surface when `closes`. A forward Tab keeps its default action so the browser advances\n * from the target; a backward one is prevented so focus stays on it. Returns whether it closed.\n */\nfunction handleTabOut(\n event: KeyboardEvent,\n host: HTMLElement,\n config: OverlayShellTabOutConfig,\n closes: boolean,\n): boolean {\n if (\n event.key !== 'Tab' ||\n event.defaultPrevented ||\n event.altKey ||\n event.ctrlKey ||\n event.metaKey\n ) {\n return false;\n }\n const target = config.target();\n if (target === null) {\n return false;\n }\n const from = resolveEventTarget(event);\n const backward = event.shiftKey;\n if (\n !leavesTabSequence(findTabbableEdges(host), from instanceof Element ? from : null, backward)\n ) {\n return false;\n }\n target.focus();\n if (resolveActiveElement(target.ownerDocument) !== target) {\n return false;\n }\n if (backward) {\n event.preventDefault();\n }\n if (!closes) {\n return false;\n }\n config.close();\n return true;\n}\n\n/**\n * Resolves the real DOM element an overlay is anchored to, for the modal-peer ownership check.\n *\n * Falls back to the `VirtualElement`'s `contextElement` and then to the return-focus target for\n * pointer-positioned overlays. Returns `null` when no backing element exists, leaving the overlay\n * unmarked.\n */\nfunction resolveModalAnchor(config: OverlayShellConfig): Element | null {\n const ref = config.positioner.reference();\n if (ref instanceof Element) {\n return ref;\n }\n const contextElement = ref?.contextElement;\n if (contextElement instanceof Element) {\n return contextElement;\n }\n return config.returnFocus?.target() ?? null;\n}\n","import { effect, isDevMode, type Signal } from '@angular/core';\n\n/** The trigger state the dev-mode missing-`[controls]` warning watches, and the warning itself. */\nexport interface UncontrolledTriggerConfig {\n /** The trigger's open state. */\n readonly open: Signal<boolean>;\n /** The id the trigger mirrors to `aria-controls`, or `null` when unset. */\n readonly controls: Signal<string | null>;\n /** Emits the primitive's own `fortyWarn`, so each primitive keeps its own code. */\n readonly warn: () => void;\n}\n\n/**\n * Warns — dev mode only — when a trigger that mirrors `[controls]` to `aria-controls` opens while\n * `controls` is unset, so the missing relationship is visible during development.\n *\n * It warns once per entry into that state: reopening without `controls` stays silent, and setting\n * then clearing it warns again. Must be called from an injection context. A production build\n * creates no effect at all.\n */\nexport function warnIfOpenWithoutControls(config: UncontrolledTriggerConfig): void {\n if (!isDevMode()) {\n return;\n }\n let warned = false;\n effect(() => {\n if (config.controls() !== null) {\n warned = false;\n } else if (config.open() && !warned) {\n warned = true;\n config.warn();\n }\n });\n}\n","import { afterNextRender, ElementRef, inject, isDevMode } from '@angular/core';\nimport { fortyWarn } from 'forty-cdk/core';\n\n/** Identifies the surface and its two naming channels in the dev-mode missing-name warning. */\nexport interface UnnamedDialogConfig {\n /** Entry-point name used in the `[forty-cdk/<primitive>]` prefix (e.g. `'dialog'`). */\n readonly primitive: string;\n /** Selector of the piece carrying the dialog role (e.g. `'[forDialog]'`). */\n readonly piece: string;\n /** Selector of the title piece that names the surface (e.g. `'[forDialogTitle]'`). */\n readonly title: string;\n /**\n * Where the consumer binds `ariaLabel` for this surface, quoted into the fix (e.g.\n * `'[forPopover]'`, whose content reads the root's input).\n */\n readonly ariaLabelOn: string;\n}\n\n/**\n * Warns — dev mode only, once per instance — when a surface carrying the dialog role has no\n * accessible name after its first render: neither an `aria-labelledby` nor a non-empty\n * `aria-label` resolved on its host.\n *\n * The attributes are read from the host inside `afterNextRender`, so a title registered during the\n * first render, a bound `ariaLabel` and a static `aria-label` attribute all count. Must be called\n * from an injection context on the surface's own host. A production build registers no render hook\n * at all, and the check is inert on the server.\n */\nexport function warnIfDialogUnnamed(config: UnnamedDialogConfig): void {\n if (!isDevMode()) {\n return;\n }\n const host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n\n afterNextRender(() => {\n const label = host.getAttribute('aria-label')?.trim() ?? '';\n if (label !== '' || host.hasAttribute('aria-labelledby')) {\n return;\n }\n fortyWarn({\n code: 'FORCDK-CORE-011',\n scope: config.primitive,\n message: `${config.piece} has no accessible name.`,\n cause:\n 'Neither `aria-labelledby` nor a non-empty `aria-label` resolved on its host, so assistive ' +\n 'technology announces the surface as a bare \"dialog\". Automated audits tagged for WCAG ' +\n 'A / AA do not report it.',\n fix: `Render a ${config.title} inside it, or bind \\`ariaLabel\\` on ${config.ariaLabelOn}.`,\n });\n });\n}\n","import {\n ApplicationRef,\n type ComponentRef,\n computed,\n type DestroyableInjector,\n DestroyRef,\n DOCUMENT,\n EnvironmentInjector,\n inject,\n Injector,\n PLATFORM_ID,\n type Provider,\n type ProviderToken,\n type Signal,\n signal,\n} from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\n\nimport {\n composedClosest,\n FOR_FIELD_ANCHOR_CONTEXT,\n FOR_FIELD_CONTEXT,\n IdGenerator,\n resolveActiveElement,\n} from 'forty-cdk/core';\nimport { InertSiblingsStack } from '../inert-siblings/inert-siblings';\nimport type { OverlayRef } from './overlay-ref';\n\n/**\n * Minimal shape every overlay entry must satisfy so the shared core can index,\n * render, and tear it down. Per-primitive entries (`ForDialogEntry`,\n * `ForDrawerEntry`) extend this with their own directive-input fields and\n * narrow `ref` to their concrete `For<Primitive>Ref`. The core closes an\n * entry's ref and reads its `isClosed` flag (to tell a still-open parent apart\n * from one being swapped out during return-focus origin resolution), so the\n * base requires just those two members — both reason-agnostic, so the base\n * stays independent of each ref's close-reason union.\n *\n * Internal core tier — exported from `forty-cdk/core` for the library's own\n * entry points, with no semver guarantee.\n */\nexport interface OverlayManagerEntry {\n readonly id: string;\n readonly ref: Pick<OverlayRef, 'close' | 'isClosed'>;\n}\n\n/**\n * A rendered overlay's exit-animation surface, registered with the core at\n * attach time so `beginLeave` targets the exact host (and its backdrop) by\n * direct reference instead of re-querying the whole document on every close.\n *\n * `host` is the overlay root — the `[forDialog]` / `[forDrawer]` element the\n * outlet stamps. `backdrop()` reads the currently-registered\n * `[for<Primitive>Backdrop]` element **live at close time** (`null` when none\n * is rendered), preserving the \"read the backdrop when it closes\" semantics a\n * registration-time snapshot would lose.\n *\n * Part of the shared core composition surface; carries no semver guarantees.\n */\nexport interface OverlaySurface {\n readonly host: HTMLElement;\n backdrop(): HTMLElement | null;\n}\n\n/**\n * The reactive surface a manager's outlet component is wired with on first\n * `open()`. Mirrors `ForDialogOutletHost` / `ForDrawerOutletHost`.\n *\n * Internal core tier — exported from `forty-cdk/core` for the library's own\n * entry points, with no semver guarantee.\n */\nexport interface OverlayManagerOutletHost<TEntry extends OverlayManagerEntry> {\n readonly entries: Signal<readonly TEntry[]>;\n closeAllForDestroy(): void;\n /**\n * Registers a rendered entry's exit-animation surface under its id so\n * `beginLeave` can drive the leave classes by direct reference. Called from\n * the per-row surface-registrar directive's `afterNextRender` (so it also\n * runs for an entry whose mount was deferred to a later render). The core\n * drops the surface when the entry is removed.\n */\n registerSurface(id: string, surface: OverlaySurface): void;\n}\n\n/**\n * The minimal surface a manager's outlet component exposes so the core can\n * wire it on first `open()`. Mirrors `ForDialogOutlet` / `ForDrawerOutlet`.\n *\n * Internal core tier — exported from `forty-cdk/core` for the library's own\n * entry points, with no semver guarantee.\n */\nexport interface OverlayManagerOutlet<TEntry extends OverlayManagerEntry> {\n init(host: OverlayManagerOutletHost<TEntry>): void;\n}\n\n/**\n * Per-primitive bindings the shared core needs: how to name ids and the\n * exit-animation host / backdrop attributes, and how to create the outlet\n * component that renders the entries.\n *\n * Internal core tier — exported from `forty-cdk/core` for the library's own\n * entry points, with no semver guarantee.\n */\nexport interface OverlayManagerConfig<TEntry extends OverlayManagerEntry> {\n /**\n * Per-instance id prefix passed to `IdGenerator.next` (e.g.\n * `'for-dialog-instance'`).\n */\n readonly idPrefix: string;\n /**\n * Attribute the overlay root + backdrop reflect their per-instance id on\n * (e.g. `'data-for-dialog-id'`), read during return-focus origin resolution.\n */\n readonly idAttribute: string;\n /**\n * Attribute marking the portaled backdrop element (e.g.\n * `'data-for-dialog-backdrop'`), used to exclude the backdrop during\n * return-focus origin resolution.\n */\n readonly backdropAttribute: string;\n /** Creates the manager-owned outlet component (e.g. `ForDialogOutlet`). */\n createOutlet(\n environmentInjector: EnvironmentInjector,\n ): ComponentRef<OverlayManagerOutlet<TEntry>>;\n}\n\n/**\n * Shared imperative-overlay engine behind `ForDialogManager` and\n * `ForDrawerManager`. Owns the entries signal, the reactive `openCount`, the\n * lazily-created outlet, the public `closeAll()` and the destroy-time close-all\n * sweep, the exit-animation `beginLeave` driver, and the parent-cached\n * per-component `Injector` factory.\n *\n * In the browser the outlet host is appended to `document.body` before its\n * first render, as a `display: contents` modal peer, so opened content is\n * connected (and never under an `inert` ancestor) from its first render on\n * rather than only once its row is portaled.\n * The two managers differ only in their entry shape and directive-input\n * mapping; everything structural lives here once.\n *\n * Internal core tier — no semver guarantee; the public surface is\n * `ForDialogManager` / `ForDrawerManager`.\n */\nexport class OverlayManagerCore<TEntry extends OverlayManagerEntry> {\n readonly #appRef = inject(ApplicationRef);\n readonly #envInjector = inject(EnvironmentInjector);\n readonly #document = inject(DOCUMENT);\n readonly #isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n readonly #inertStack = inject(InertSiblingsStack);\n private readonly idGen = inject(IdGenerator);\n\n readonly #entries = signal<readonly TEntry[]>([]);\n readonly #surfaces = new Map<string, OverlaySurface>();\n readonly #config: OverlayManagerConfig<TEntry>;\n\n /**\n * Reactive count of the overlays this manager has open. A closed overlay stops counting once its\n * exit animation finishes.\n */\n readonly openCount = computed(() => this.#entries().length);\n\n #outletRef: ComponentRef<OverlayManagerOutlet<TEntry>> | null = null;\n #destroying = false;\n #lastReturnFocusOrigin: HTMLElement | null = null;\n\n constructor(config: OverlayManagerConfig<TEntry>) {\n this.#config = config;\n }\n\n /**\n * Resolves the element focus should return to when the overlay this `open()`\n * is about to register later closes — the \"true origin\". Threaded to the\n * directive's `returnFocusTarget` so `injectModalShell` restores focus there\n * instead of to whatever it happened to capture at construction (which breaks\n * on a close→open swap, where the incoming surface is built while focus still\n * lives inside the outgoing, doomed one).\n *\n * Read the currently-focused element **synchronously at `open()` time**,\n * before the render tick mounts the new overlay and swaps the DOM, and\n * classify it:\n *\n * - **Genuine outside element** (focus is on the trigger, not inside any\n * managed overlay host) → that element is the origin.\n * - **Inside a still-live managed overlay** (a stacked open on top of an open\n * overlay) → return focus into that live parent, so the origin is the\n * focused element itself.\n * - **Inside an overlay that is closing / already gone** (a close→open swap:\n * its ref is closed, or it has left the entries list but its DOM host is\n * still mounted for this tick) → inherit the chain's origin, i.e. the\n * origin resolved for the most recent open.\n * - **No usable focus** (`<body>` / `documentElement` / none) → inherit the\n * chain's origin too.\n *\n * The resolved origin is remembered so the next swap in the chain can inherit\n * it. Callers may bypass this and thread a caller-chosen element instead.\n *\n * Both halves of the resolution read the composed tree: the capture\n * descends through open shadow roots, so a trigger inside one is the origin\n * rather than its (usually unfocusable) host, and the \"am I inside a managed\n * overlay?\" walk climbs back out of them. The two go together — resolving the\n * deep element while classifying it with a plain `closest` would report every\n * shadow-nested trigger as an outside element.\n */\n protected resolveReturnFocusTarget(): HTMLElement | null {\n const active = resolveActiveElement(this.#document);\n const captured = active instanceof HTMLElement ? active : null;\n const origin = this.#computeReturnFocusOrigin(captured);\n this.#lastReturnFocusOrigin = origin;\n return origin;\n }\n\n #computeReturnFocusOrigin(captured: HTMLElement | null): HTMLElement | null {\n const { body, documentElement } = this.#document;\n if (captured === null || captured === body || captured === documentElement) {\n return this.#lastReturnFocusOrigin;\n }\n const { idAttribute, backdropAttribute } = this.#config;\n const host = composedClosest(captured, `[${idAttribute}]:not([${backdropAttribute}])`);\n if (host === null) {\n return captured;\n }\n const hostId = host.getAttribute(idAttribute);\n const parentStillOpen = this.#entries().some(\n (entry) => entry.id === hostId && !entry.ref.isClosed(),\n );\n return parentStillOpen ? captured : this.#lastReturnFocusOrigin;\n }\n\n /**\n * Generates the next per-instance id and a paired idempotent\n * `remove` that drops the entry. The caller builds the `ref` with a teardown\n * that drives the exit animation before invoking `remove`.\n */\n protected nextId(): { id: string; remove: () => void } {\n const id = this.idGen.next(this.#config.idPrefix);\n let removed = false;\n const remove = (): void => {\n if (removed) {\n return;\n }\n removed = true;\n this.#surfaces.delete(id);\n this.#entries.update((arr) => arr.filter((e) => e.id !== id));\n };\n return { id, remove };\n }\n\n /**\n * Drives the exit animation on the overlay root and, in lockstep,\n * on the portaled backdrop (both resolved from the `OverlaySurface` stored at\n * attach time — the backdrop's template `animate.leave` never fires under the\n * manager's `ngComponentOutlet` mount), then calls `remove`. Runs `remove`\n * immediately when destroying, when `requestAnimationFrame` is unavailable,\n * when no surface was registered (nothing rendered), or when there is nothing\n * to animate.\n */\n protected beginLeave(\n id: string,\n leaveClass: string | undefined,\n backdropLeaveClass: string | undefined,\n remove: () => void,\n ): void {\n if (this.#destroying || typeof requestAnimationFrame === 'undefined') {\n remove();\n return;\n }\n const surface = this.#surfaces.get(id);\n const targets: HTMLElement[] = [];\n if (surface && leaveClass && typeof surface.host.getAnimations === 'function') {\n surface.host.classList.add(leaveClass);\n targets.push(surface.host);\n }\n if (surface && backdropLeaveClass) {\n const backdrop = surface.backdrop();\n if (backdrop && typeof backdrop.getAnimations === 'function') {\n backdrop.classList.add(backdropLeaveClass);\n targets.push(backdrop);\n }\n }\n if (targets.length === 0) {\n remove();\n return;\n }\n requestAnimationFrame(() => {\n const finite = targets\n .flatMap((el) => el.getAnimations({ subtree: true }))\n .filter(isFiniteAnimation);\n if (finite.length === 0) {\n remove();\n return;\n }\n Promise.all(finite.map((animation) => animation.finished.catch(() => undefined))).then(() =>\n remove(),\n );\n });\n }\n\n /**\n * Builds a parent-cached per-component `Injector`. The returned\n * factory recreates the injector only when its parent changes, so re-renders\n * with the same enclosing `[forDialog]` / `[forDrawer]` host reuse it.\n *\n * With no `scope`, the opened component's injector is parented on the\n * declarative host's element injector (`parent`), matching the declarative\n * path. When the caller passed an `injector` on the `open()` config, `scope`\n * re-parents the opened component on that caller scope instead — so DI inside\n * the opened component resolves the scope's providers (a lazy route, a\n * component `providers`). The host's `contextToken` and the field-boundary\n * tokens are copied across as value providers so the primitive's own pieces\n * still resolve `FOR_<PRIMITIVE>_CONTEXT`, and a control in the opened\n * component stays cut off from the caller's `[forField]`, exactly as on the\n * declarative path.\n *\n * Each injector it creates is destroyed when the view owning `parent` is\n * destroyed, after the opened component it served, or when a new parent\n * replaces it, so the services passed in `providers` run their teardown.\n */\n protected createInjectorFactory(\n providers: readonly Provider[],\n scope?: { readonly injector: Injector; readonly contextToken: ProviderToken<unknown> },\n ): (parent: Injector) => Injector {\n let cached: {\n readonly parent: Injector;\n readonly injector: Injector;\n readonly release: () => void;\n } | null = null;\n return (parent: Injector): Injector => {\n if (cached?.parent === parent) {\n return cached.injector;\n }\n cached?.release();\n const injector = scope\n ? Injector.create({\n parent: scope.injector,\n providers: [\n ...[scope.contextToken, ...FIELD_BOUNDARY_TOKENS].map((token) => ({\n provide: token,\n useValue: parent.get(token),\n })),\n ...providers,\n ],\n })\n : Injector.create({ parent, providers: [...providers] });\n cached = { parent, injector, release: bindInjectorLifetime(injector, parent) };\n return injector;\n };\n }\n\n /**\n * Registers a fully-built entry, ensures the outlet exists, and requests a\n * render so the `@for` mounts it.\n *\n * The render is attempted synchronously via `ApplicationRef.tick()` so the\n * overlay DOM is available the moment `open()` returns — the common case.\n * When `open()` is itself called from within change detection (an `effect`,\n * `ngOnInit`, or an `afterNextRender` callback) a tick is already in flight\n * and a nested `tick()` is illegal (NG0101); the synchronous attempt is then\n * skipped and the `#entries` signal write drives the mount on the next\n * scheduled render instead. The entry is registered immediately either way,\n * so the returned overlay ref is usable straight away.\n */\n protected register(entry: TEntry): void {\n this.#ensureOutlet();\n this.#entries.update((arr) => [...arr, entry]);\n this.#renderNow();\n }\n\n #renderNow(): void {\n try {\n this.#appRef.tick();\n } catch (error: unknown) {\n if (isRecursiveTickError(error)) {\n return;\n }\n throw error;\n }\n }\n\n /**\n * Closes every overlay this manager has open, topmost first, with reason `'programmatic'` and\n * `result` as each close result. Each ref's `closed` resolves as it does for `ref.close()`, exit\n * animations still play, and focus ends where the bottom overlay's return focus sends it. A no-op\n * when nothing is open.\n */\n closeAll(result?: unknown): void {\n for (const entry of [...this.#entries()].reverse()) {\n entry.ref.close(result);\n }\n }\n\n #closeAllForDestroy(): void {\n this.#destroying = true;\n for (const entry of this.#entries()) {\n entry.ref.close();\n }\n }\n\n #ensureOutlet(): void {\n if (this.#outletRef) {\n return;\n }\n const outletRef = this.#config.createOutlet(this.#envInjector);\n this.#appRef.attachView(outletRef.hostView);\n if (this.#isBrowser) {\n const outletHost = outletRef.location.nativeElement as HTMLElement;\n outletHost.style.display = 'contents';\n const releasePeer = this.#inertStack.registerPeer(outletHost, 'always');\n this.#document.body.appendChild(outletHost);\n outletRef.onDestroy(() => {\n releasePeer();\n outletHost.remove();\n });\n }\n outletRef.instance.init({\n entries: this.#entries.asReadonly(),\n closeAllForDestroy: () => this.#closeAllForDestroy(),\n registerSurface: (id, surface) => {\n this.#surfaces.set(id, surface);\n },\n });\n this.#outletRef = outletRef;\n }\n}\n\nconst FIELD_BOUNDARY_TOKENS: readonly ProviderToken<unknown>[] = [\n FOR_FIELD_CONTEXT,\n FOR_FIELD_ANCHOR_CONTEXT,\n];\n\n/**\n * Destroys `injector` when the scope `parent` belongs to is destroyed, and\n * returns a release that destroys it early and drops that hook. Either path\n * destroys it once.\n */\nfunction bindInjectorLifetime(injector: DestroyableInjector, parent: Injector): () => void {\n let destroyed = false;\n const destroy = (): void => {\n if (!destroyed) {\n destroyed = true;\n injector.destroy();\n }\n };\n const unregister = parent.get(DestroyRef).onDestroy(destroy);\n return () => {\n unregister();\n destroy();\n };\n}\n\n/**\n * True when `error` is Angular's recursive-`ApplicationRef.tick()` runtime\n * error (`NG0101`), thrown when a change-detection tick is already in flight.\n * Matched by the stable numeric `RuntimeError.code` with a message-prefix\n * fallback so it survives production builds where the message text is stripped.\n */\nfunction isRecursiveTickError(error: unknown): boolean {\n if (error === null || typeof error !== 'object') {\n return false;\n }\n const { code, message } = error as { code?: unknown; message?: unknown };\n return code === 101 || (typeof message === 'string' && message.startsWith('NG0101'));\n}\n\n/**\n * True when `animation` will actually finish — i.e. it does not run forever.\n * An infinite exit animation (a shimmer / pulse with `animation-iteration-count:\n * infinite`) reports `Infinity` iterations, and its `finished` promise never\n * resolves; awaiting it would strand `beginLeave` and leak the overlay entry.\n * Filtering these out before awaiting `finished` lets teardown proceed once the\n * finite animations settle (or immediately, when none remain). Guards for a\n * possibly-null effect and for environments lacking `getComputedTiming`.\n */\nfunction isFiniteAnimation(animation: Animation): boolean {\n const effect = animation.effect;\n if (!effect || typeof effect.getComputedTiming !== 'function') {\n return true;\n }\n return effect.getComputedTiming().iterations !== Infinity;\n}\n","import { signal } from '@angular/core';\n\n/**\n * The awaitable close payload resolved by `OverlayRef.closed` — the reason the\n * overlay closed plus the optional close result. Homogeneous with\n * `ForToastRef.closed` so all three programmatic overlay handles expose the\n * same `{ reason, result }` shape.\n *\n * Internal core tier — exported from `forty-cdk/core` for the library's own\n * entry points, with no semver guarantee.\n */\nexport interface OverlayCloseEvent<R, Reason> {\n /** Why the overlay closed (e.g. `'escape'`, `'closeButton'`, `'programmatic'`). */\n readonly reason: Reason;\n /** The close result passed to `close(result)`, or `undefined`. */\n readonly result: R | undefined;\n}\n\n/**\n * Shared handle returned by an imperative overlay manager's `open()`.\n * `ForDialogRef` / `ForDrawerRef` extend this verbatim to keep their public\n * class identity (and DI token) while the close engine lives here once.\n *\n * Both reactive (`isClosed`, `result`) and awaitable (`closed`) APIs are\n * exposed — pick what fits the call site. `R` is the close-result type and\n * `Reason` the close-reason union (`ForDialogCloseReason` /\n * `ForDrawerCloseReason`).\n *\n * Internal core tier — no semver guarantee; the public surface is\n * `ForDialogRef` / `ForDrawerRef`.\n */\nexport class OverlayRef<R = unknown, Reason = string> {\n readonly #result = signal<R | undefined>(undefined);\n readonly #closed = signal(false);\n\n /** Reactive: `true` once `close()` has been called. */\n readonly isClosed = this.#closed.asReadonly();\n\n /** Reactive: the close result. `undefined` while open. */\n readonly result = this.#result.asReadonly();\n\n /**\n * Awaitable: resolves with `{ reason, result }` the first time `close()`\n * runs. The reason distinguishes an explicit `close(result)` (the manager's\n * default reason, `'programmatic'`) from a dismiss channel (Escape, backdrop,\n * outside-pointer, close button), which a bare result cannot.\n */\n readonly closed: Promise<OverlayCloseEvent<R, Reason>>;\n\n #resolveClosed!: (event: OverlayCloseEvent<R, Reason>) => void;\n readonly #teardown: () => void;\n readonly #defaultReason: Reason;\n\n /** Internal composition surface (no semver guarantees). */\n constructor(teardown: () => void, defaultReason: Reason) {\n this.#teardown = teardown;\n this.#defaultReason = defaultReason;\n this.closed = new Promise((resolve) => {\n this.#resolveClosed = resolve;\n });\n }\n\n /**\n * Close the overlay, optionally returning a result. Idempotent — calling\n * twice is a no-op. `reason` defaults to the manager's default (`'programmatic'`\n * for a direct imperative close); the dismiss channels pass their own reason.\n */\n close(result?: R, reason: Reason = this.#defaultReason): void {\n if (this.#closed()) {\n return;\n }\n this.#result.set(result);\n this.#closed.set(true);\n this.#resolveClosed({ reason, result });\n this.#teardown();\n }\n}\n","import { DestroyRef, DOCUMENT, inject, Injectable, PLATFORM_ID } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\n\nimport { composedContains } from 'forty-cdk/core';\n\n/** Window (ms) hover opens stay suppressed after the last scroll that concerns an overlay. */\nexport const DEFAULT_SCROLL_DISMISS_SUPPRESSION_MS = 200;\n\n/**\n * Which scrolls concern one registered overlay. Both accessors are read when a\n * scroll is dispatched or a suppression is queried, so a trigger or surface\n * registered after the overlay is picked up.\n */\nexport interface ScrollDismissScope {\n /**\n * The element the overlay is anchored to. A scroll of an element that does\n * not contain it moves nothing the overlay is positioned against, so it\n * neither dismisses nor suppresses. `null`, or an anchor no longer in the\n * document, leaves every scroll in scope.\n */\n readonly anchor: () => Element | null;\n /**\n * The overlay's own surface. A scroll inside it (an `overflow: auto` region\n * in the content) neither dismisses nor suppresses.\n */\n readonly surface: () => Element | null;\n}\n\n/** Inputs for {@link ScrollDismissDispatcher.register}. */\nexport interface ScrollDismissOptions {\n /**\n * Closes the overlay and cancels its pending timers. Called synchronously on\n * every scroll in scope while {@link active} holds.\n */\n readonly dismiss: () => void;\n /** Narrows which scrolls dismiss and suppress. Omitted, every scroll does. */\n readonly scope?: ScrollDismissScope;\n /**\n * Whether a scroll has anything to dismiss: the overlay is open, or an open /\n * close timer is pending. Read before the scope, so an idle overlay costs one\n * call per scroll. Omitted, the registration is always active.\n */\n readonly active?: () => boolean;\n}\n\n/** Handle returned by {@link ScrollDismissDispatcher.register}. */\nexport interface ScrollDismissRegistration {\n /**\n * Whether a scroll in this registration's scope happened within the\n * suppression window. Hover opens bail while this returns `true`, so content\n * sliding under a stationary pointer cannot flicker the overlay open.\n * Always `false` on the server and after {@link unregister}.\n */\n isSuppressed(): boolean;\n /** Removes this registration. Idempotent; call it from a `DestroyRef` hook. */\n unregister(): void;\n}\n\ninterface Registration {\n readonly dismiss: () => void;\n readonly scope: ScrollDismissScope | undefined;\n readonly active: () => boolean;\n}\n\nconst ALWAYS_ACTIVE = (): boolean => true;\n\nconst SERVER_REGISTRATION: ScrollDismissRegistration = {\n isSuppressed: () => false,\n unregister: () => {},\n};\n\n/**\n * Application-scoped owner of the single capture-phase document `scroll`\n * listener shared by every hover-driven anchored overlay (Tooltip, HoverCard).\n *\n * When an ancestor scroll container moves its content under a stationary\n * cursor, the browser does not reliably dispatch `pointerleave` /\n * `pointerenter` on the triggers sliding past the pointer. On each scroll the\n * dispatcher therefore dismisses every active registration whose scope the\n * scroll concerns, and records the scrolled element with a timestamp. A\n * registration is suppressed while a recorded scroll within\n * {@link DEFAULT_SCROLL_DISMISS_SUPPRESSION_MS} concerns its own scope, so a\n * scroll elsewhere on the page, or inside the overlay's own surface, never\n * blocks its hover opens.\n *\n * One listener is installed with the first registration and removed with the\n * last. Per scroll the work is one map write plus one `active()` call per\n * registration; the containment walk runs only for active registrations, and\n * for idle ones only when their own hover asks whether it is suppressed.\n *\n * `providedIn: 'root'`, so it is one instance per application injector and is\n * garbage-collected with it. Internal core tier, exported for the tooltip /\n * hover-card entry points, never for consumers.\n */\n@Injectable({ providedIn: 'root' })\nexport class ScrollDismissDispatcher {\n readonly #doc = inject(DOCUMENT);\n readonly #isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n readonly #registrations = new Set<Registration>();\n readonly #recentScrolls = new Map<EventTarget | null, number>();\n #listener: AbortController | null = null;\n\n constructor() {\n inject(DestroyRef).onDestroy(() => {\n this.#listener?.abort();\n this.#listener = null;\n this.#registrations.clear();\n this.#recentScrolls.clear();\n });\n }\n\n /**\n * Registers an overlay for scroll dismissal and per-overlay suppression. Each\n * call is an independent registration, so registering the same callback\n * twice yields two handles that must both be unregistered. A no-op handle on\n * the server.\n */\n register(options: ScrollDismissOptions): ScrollDismissRegistration {\n if (!this.#isBrowser) {\n return SERVER_REGISTRATION;\n }\n const registration: Registration = {\n dismiss: options.dismiss,\n scope: options.scope,\n active: options.active ?? ALWAYS_ACTIVE,\n };\n this.#registrations.add(registration);\n this.#listen();\n return {\n isSuppressed: () =>\n this.#registrations.has(registration) && this.#suppresses(registration.scope),\n unregister: () => this.#unregister(registration),\n };\n }\n\n #listen(): void {\n if (this.#listener) {\n return;\n }\n this.#listener = new AbortController();\n this.#doc.addEventListener('scroll', (event) => this.#onScroll(event), {\n capture: true,\n passive: true,\n signal: this.#listener.signal,\n });\n }\n\n #unregister(registration: Registration): void {\n if (!this.#registrations.delete(registration) || this.#registrations.size > 0) {\n return;\n }\n this.#listener?.abort();\n this.#listener = null;\n this.#recentScrolls.clear();\n }\n\n #onScroll(event: Event): void {\n const now = Date.now();\n this.#recentScrolls.delete(event.target);\n this.#recentScrolls.set(event.target, now + DEFAULT_SCROLL_DISMISS_SUPPRESSION_MS);\n this.#pruneExpired(now);\n for (const registration of this.#registrations) {\n if (\n registration.active() &&\n (!registration.scope || scrollConcerns(event.target, registration.scope))\n ) {\n registration.dismiss();\n }\n }\n }\n\n #pruneExpired(now: number): void {\n for (const [target, until] of this.#recentScrolls) {\n if (until > now) {\n return;\n }\n this.#recentScrolls.delete(target);\n }\n }\n\n #suppresses(scope: ScrollDismissScope | undefined): boolean {\n const now = Date.now();\n this.#pruneExpired(now);\n for (const target of this.#recentScrolls.keys()) {\n if (!scope || scrollConcerns(target, scope)) {\n return true;\n }\n }\n return false;\n }\n}\n\nfunction scrollConcerns(target: EventTarget | null, scope: ScrollDismissScope): boolean {\n if (!(target instanceof Node)) {\n return true;\n }\n const surface = scope.surface();\n if (surface && composedContains(surface, target)) {\n return false;\n }\n const anchor = scope.anchor();\n if (!anchor || !anchor.isConnected) {\n return true;\n }\n return composedContains(target, anchor);\n}\n"],"mappings":"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"}