import * as _angular_core from '@angular/core'; import { InjectionToken, Signal, Provider } from '@angular/core'; import * as forty_cdk_popover from 'forty-cdk/popover'; import { VetoableNativeEvent, VetoableEvent } from 'forty-cdk/core'; import { AnchoredPositioningContext, AnchoredOverlayPositioningBase, AnchoredPositioningSeedDefaults, FloatingSide, FloatingAlign } from 'forty-cdk/core-overlay'; /** * Why a popover requested close. The popover is non-modal, so there is no * `'tab'` reason (Tab is allowed to leave the surface and surfaces as * `'focusOutside'`) and no selection reason. `'programmatic'` covers * `[forPopoverClose]` and the trigger toggle-close. */ type ForPopoverCloseReason = 'escape' | 'pointerDownOutside' | 'focusOutside' | 'programmatic'; /** * Coordination contract owned by `ForPopover`. Trigger / Content register * their elements (for floating-ui positioning, dismissible-layer exemptions, * and focus return). Title / Description register their generated ids so * the content wires `aria-labelledby` / `aria-describedby` reactively. * * The popover's "openness" lives on the root directive (`open` model) and * is published here so descendant pieces can react without each subscribing * to the directive instance directly. */ interface ForPopoverContext extends AnchoredPositioningContext { /** * Whether the popover is open, as a read-only signal. Mutate it through * `toggle` / `close` / `requestClose` or the root's `[(open)]` binding — a * direct write would bypass the root's `disabled` guard. */ readonly open: Signal; readonly disabled: Signal; readonly dismissible: Signal; readonly returnFocus: Signal; readonly initialFocus: Signal<'first' | 'container'>; /** * Reason of the most recent close, or `null` while the popover is open / has * never closed. Reset to `null` on open. `[forPopoverContent]` reads it to * skip its trigger return-focus when the close came from an outside * interaction (`'pointerDownOutside'` / `'focusOutside'`) — leaving focus * where the user just clicked / focused instead of ripping it back to the * trigger (matching `[forDropdownMenu]`). */ readonly lastCloseReason: Signal; readonly triggerId: Signal; readonly contentId: Signal; readonly ariaLabel: Signal; /** Whether `prefers-reduced-motion: reduce` is active — reflected as `data-reduced-motion`. */ readonly reducedMotion: Signal; readonly labelledBy: Signal; readonly describedBy: Signal; readonly trigger: Signal; readonly anchor: Signal; /** * Element used as the floating-ui reference. When `[forPopoverAnchor]` * is registered, this is the anchor; otherwise it falls back to the * trigger. Decoupled from `trigger` so the trigger can keep driving * `aria-controls`, click toggle, and focus return regardless of where * the popover paints. */ readonly reference: Signal; registerTrigger(el: HTMLElement): void; unregisterTrigger(el: HTMLElement): void; /** Adopts a consumer-set static `id` on the content host into `contentId`. */ adoptContentId(el: HTMLElement): void; registerAnchor(el: HTMLElement): void; unregisterAnchor(el: HTMLElement): void; registerArrow(el: HTMLElement): void; unregisterArrow(el: HTMLElement): void; registerLabel(id: string): void; unregisterLabel(id: string): void; registerDescription(id: string): void; unregisterDescription(id: string): void; /** Toggle from a trigger click. Honours `disabled`. */ toggle(): void; /** * Close the popover. Honored regardless of `dismissible` — used by * `[forPopoverClose]` and available to custom close pieces. Prefer this over * writing `open` directly so the close routes through the root. */ close(): void; /** * Escape is consumer-owned (its close differs per primitive); Content * forwards the raw `KeyboardEvent` so the root emits `(escapeKeyDown)` and * runs its own close decision. */ emitEscapeKeyDown(event: KeyboardEvent): void; /** * Outside-interaction emit forwarders. The specific and composite channels * observe the same veto, so `preventDefault()` from either one suppresses the * close that otherwise follows. */ emitPointerDownOutside(veto: VetoableNativeEvent): void; emitFocusOutside(veto: VetoableNativeEvent): void; emitInteractOutside(veto: VetoableNativeEvent): void; /** * Implicit close requested by the shell after an un-vetoed outside * interaction. Records the channel's reason as `lastCloseReason` so the * content can skip its trigger return-focus, then closes. */ requestClose(reason: 'pointerDownOutside' | 'focusOutside'): void; /** * Hooks into the auto-focus pipeline. Content fires these just before * its imperative `.focus()` (open) or the trigger return-focus (close); * `event.preventDefault()` skips the move. Returns `true` when the * consumer vetoed. */ emitAutoFocusOnOpen(): boolean; emitAutoFocusOnClose(): boolean; } declare const FOR_POPOVER_CONTEXT: InjectionToken; /** * Headless implementation of the [WAI-ARIA Modeless Dialog pattern](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/), * positioned against an internal trigger via `@floating-ui/dom`. * * Apply `[forPopover]` on a wrapper (the trigger and the content's `@if` * live inside it). The directive owns open state, ids, and the registries * that wire trigger / content / title / description / arrow together. * * Mount/unmount of the visible content is the consumer's responsibility — * wrap `[forPopoverContent]` with `@if (open())` and let `animate.enter` / * `animate.leave` handle transitions: * * ```html *
* * @if (isOpen()) { *
…
* } *
* ``` * * Non-modal: focus is sent into the popover on open and returned to the * trigger on close, but Tab is allowed to leave the surface (use Dialog * if you need a focus trap). */ declare class ForPopover extends AnchoredOverlayPositioningBase implements ForPopoverContext { #private; protected readonly positioningDefaults: forty_cdk_popover.ForPopoverDefaults; /** * Two-way bindable. Whether the popover is currently shown. The `model()` * change emitter (`(openChange)`) fires only on internal transitions * (trigger click, Escape, outside dismissal), never on consumer writes * via `[(open)]` — observe state changes without binding back. */ readonly open: _angular_core.ModelSignal; /** * Padding (px) keeping `[forPopoverArrow]` that far from the edges of the * content. Only consulted when an arrow is registered, since floating-ui * installs the `arrow` middleware only then — which is why the input is * declared here rather than on the shared positioning base. The default is * read from `provideForPopoverDefaults` for the surrounding scope, since arrow * geometry is a design-system-wide decision rather than a per-popover one. */ readonly arrowPadding: _angular_core.InputSignalWithTransform; /** * When true, trigger interaction is ignored and any open popover stays * open until the consumer flips `open` themselves. Disable on the trigger * side; the content side keeps its dismissible behavior unaffected. */ readonly disabled: _angular_core.InputSignalWithTransform; /** * When true (default), Escape, pointer-down outside, and focus outside * close the popover. Disable for confirm flows that must be answered * via `[forPopoverClose]` (or by setting `open` programmatically). */ readonly dismissible: _angular_core.InputSignalWithTransform; /** When true (default), focus returns to the trigger on close. */ readonly returnFocus: _angular_core.InputSignalWithTransform; /** * Where to send focus when content mounts. `'first'` (default) finds * the first focusable descendant; `'container'` focuses the content * box itself (useful when there's nothing focusable inside). */ readonly initialFocus: _angular_core.InputSignal<"first" | "container">; /** Manual `aria-label` on the content. Use this when no visible title element exists. */ readonly ariaLabel: _angular_core.InputSignal; /** * Whether the user has requested reduced motion via the OS * `prefers-reduced-motion: reduce` media query. Reflected as the boolean * `data-reduced-motion` attribute on the root and content so consumers can * disable their own `animate.enter` / `animate.leave` and CSS transitions * without re-deriving the media query. The popover toggles open / closed * synchronously on trigger click, so it has no JS-coordinated timing to skip. */ readonly reducedMotion: _angular_core.Signal; /** * Fires when the user presses Escape while this popover is the topmost * dismissible layer. Call `preventDefault()` on the emitted veto to * suppress the automatic close. The native `KeyboardEvent` is * available on `.event`. */ readonly escapeKeyDown: _angular_core.OutputEmitterRef>; /** * Fires when a pointer goes down outside the popover (and outside the * trigger). Call `preventDefault()` on the veto to suppress the * automatic close. The native `PointerEvent` is on `.event`. */ readonly pointerDownOutside: _angular_core.OutputEmitterRef>; /** * Fires when focus moves outside the popover and trigger. Call * `preventDefault()` on the veto to suppress the automatic close. */ readonly focusOutside: _angular_core.OutputEmitterRef>; /** * Composite event: fires alongside `pointerDownOutside` and * `focusOutside` and shares their veto state — `preventDefault()` on * either one suppresses the automatic close. */ readonly interactOutside: _angular_core.OutputEmitterRef>; /** * Fires just before the popover sends focus into itself on mount. * Call `preventDefault()` on the veto to skip the imperative focus * move — useful when opening a popover from an input you want to * keep focused. */ readonly autoFocusOnOpen: _angular_core.OutputEmitterRef; /** * Fires just before focus returns to the trigger on unmount. Call * `preventDefault()` on the veto to suppress the return-focus. */ readonly autoFocusOnClose: _angular_core.OutputEmitterRef; readonly triggerId: _angular_core.WritableSignal; readonly contentId: _angular_core.WritableSignal; readonly trigger: _angular_core.Signal; readonly anchor: _angular_core.Signal; /** * The element floating-ui anchors against. Prefers `[forPopoverAnchor]` * when registered, otherwise falls back to the trigger so existing * popovers without an anchor keep their behavior. */ readonly reference: _angular_core.Signal; readonly arrow: _angular_core.Signal; readonly labelledBy: _angular_core.Signal; readonly describedBy: _angular_core.Signal; /** * Reason of the most recent close, or `null` while open / before any close. * Reset on open, set on every close path — the content reads it to skip its * trigger return-focus on an outside-interaction close. */ readonly lastCloseReason: _angular_core.Signal; registerTrigger(el: HTMLElement): void; unregisterTrigger(el: HTMLElement): void; /** * Adopts a consumer-set static `id` on the `[forPopoverContent]` host into * `contentId` (preserving anchors / external `aria-labelledby` references) * instead of letting the `[id]` host binding clobber it. */ adoptContentId(el: HTMLElement): void; registerAnchor(el: HTMLElement): void; unregisterAnchor(el: HTMLElement): void; registerArrow(el: HTMLElement): void; unregisterArrow(el: HTMLElement): void; registerLabel(id: string): void; unregisterLabel(id: string): void; registerDescription(id: string): void; unregisterDescription(id: string): void; toggle(): void; /** * Close the popover. Honored regardless of `dismissible` — an explicit close * is always applied. Used by `[forPopoverClose]`. */ close(): void; emitEscapeKeyDown(event: KeyboardEvent): void; /** * Outside-interaction emit forwarders. The specific and composite channels * observe the same veto, so `preventDefault()` from either one suppresses the * close that otherwise follows. */ emitPointerDownOutside(veto: VetoableNativeEvent): void; emitFocusOutside(veto: VetoableNativeEvent): void; emitInteractOutside(veto: VetoableNativeEvent): void; /** * Implicit close requested by the shell after an un-vetoed outside * interaction. Records the channel's reason so the content skips its trigger * return-focus, then closes. */ requestClose(reason: 'pointerDownOutside' | 'focusOutside'): void; emitAutoFocusOnOpen(): boolean; emitAutoFocusOnClose(): boolean; static ɵfac: _angular_core.ɵɵFactoryDeclaration; static ɵdir: _angular_core.ɵɵDirectiveDeclaration; } /** * Button that toggles the popover when clicked. Apply on a focusable * element — preferably a ` * Anchored phrase * @if (open()) { *
…
* } * * ``` */ declare class ForPopoverAnchor { #private; constructor(); static ɵfac: _angular_core.ɵɵFactoryDeclaration; static ɵdir: _angular_core.ɵɵDirectiveDeclaration; } /** * The popover surface. Carries `role="dialog"` (non-modal — `aria-modal` is absent per APG), is * portaled to `document.body`, and is positioned by `@floating-ui/dom` * against the registered `[forPopoverTrigger]`. * * The directive does not manage DOM presence — wrap with * `@if (popoverOpen())` so `animate.enter` / `animate.leave` fire on * the natural mount / unmount cycle. While mounted the directive * dismisses on Escape, pointer-down outside or focus outside, and sends * focus to the configured `initialFocus` target; on unmount it returns * focus to the trigger if `returnFocus` is on. * * The trigger is exempt from the outside checks, so clicking * it again just toggles via the trigger directive — no double-close * race. * */ declare class ForPopoverContent { protected readonly ctx: forty_cdk_popover.ForPopoverContext; protected readonly resolvedAriaLabel: _angular_core.Signal; protected readonly labelledBy: _angular_core.Signal; protected readonly describedBy: _angular_core.Signal; constructor(); static ɵfac: _angular_core.ɵɵFactoryDeclaration; static ɵdir: _angular_core.ɵɵDirectiveDeclaration; } /** * Convenience: gives the host element a stable id and registers it as the * popover's accessible name (`aria-labelledby`). Apply on a heading element * (`

`, `

`...) inside `[forPopoverContent]`. * * If you don't render a visible title, omit this and pass `ariaLabel` on * the popover root instead. */ declare class ForPopoverTitle { protected readonly id: string; static ɵfac: _angular_core.ɵɵFactoryDeclaration; static ɵdir: _angular_core.ɵɵDirectiveDeclaration; } /** * Convenience: gives the host element a stable id and registers it as the * popover's accessible description (`aria-describedby`). Apply on a paragraph * or similar text element inside `[forPopoverContent]`. */ declare class ForPopoverDescription { protected readonly id: string; static ɵfac: _angular_core.ɵɵFactoryDeclaration; static ɵdir: _angular_core.ɵɵDirectiveDeclaration; } /** * Button that closes the surrounding popover when clicked. Apply on a * `