/** * The screen-initiated approval modal. * * THE DEFECT this exists for: a money-moving button on a generated screen that * parked on the guard had no UI anywhere — only a badge count somewhere else on * the page — so the person who pressed it waited forever for something that was * never going to happen without them. This is that press's answer: the ask, * centered over the page, decided or dismissed on the spot. * * Its own composition rather than `` in a box. The card is a ROW * — one item in a thread or a queue — and this is the confirmation moment a * deliberate press earned, so it wears the ask at hero size. The WORDS still * come from the one shared ladder (`toolPresentation` → `consentAsk`, ruling * 14), so a modal and a thread card can never say different things about one * ask, and the inputs still ride `CardFields` — the honesty law's one body. * * Three rules the surface is built around: * · Esc and the scrim CLOSE, they never decide. An approval is spent by * pressing Approve or Deny and by nothing else; dismissed, it stays pending * and comes back from the badge or the next press. * · While a decision is in flight there is no exit. `approvals.decide` does not * return until the approved action has actually RUN server-side (~25s in * production today), so the modal shows that plainly instead of freezing a * button or pretending it finished. * · Focus lands on the DIALOG, never on Approve — the keystroke that opened * this modal must not be able to spend the decision it came here to ask for. */ import type { ApprovalId } from "../../core/index.js"; import type { ParkedPress } from "../tree/renderer.js"; import { type ReactNode } from "react"; /** A press inside a generated view that parked on the guard — the tree's own shape for it (`ParkedPress`), under the name this surface asks the question in. */ export type ParkedApproval = ParkedPress; /** * The mount seam: one call gives a surface the park handler and the modal to * render. Deliberately not a provider or a registry — a slot owns the presses * inside it, so it owns the questions they raise. * * A QUEUE, because presses arrive in bursts: pressing Send on two payee rows * back to back parks two approvals, and two modals over one screen (let alone * two stacked scrims) is not a question anybody can answer. Exactly one is on * screen; the next presents itself once that one has left. */ export declare function useApprovalModal(): { onParked(parked: ParkedApproval): void; modal: ReactNode; }; export declare function ApprovalModal({ approvalId, onClose }: { approvalId: ApprovalId; /** Fires once the exit has played — the caller unmounts here. */ onClose(): void; }): import("react").ReactPortal | null;