import type { JSX } from "@solidjs/web"; /** * `` — Solid 2 port of Base UI React's `AlertDialogRoot` * (`packages/react/src/alert-dialog/root/AlertDialogRoot.tsx`). Shares the * shared `useDialogRootInternal` helper with ``; pins * `modal: true`, `disablePointerDismissal: true`, and `role: * "alertdialog"`. */ import { type DialogRootChangeEventDetails, type DialogRootChangeEventReason, useDialogRootContext, } from "../../dialog/dialog-root-context"; import { type DialogPayloadChildRenderFunction, useDialogRootInternal, } from "../../dialog/root/use-dialog-root-internal"; import { createControlledState } from "../../internals/create-controlled-state"; import { FloatingTree, useFloatingParentNodeId, } from "../../internals/floating-ui/components/floating-tree"; import { type MaybeAccessor, readOption } from "../../internals/maybe-accessor"; import { createAlertDialog } from "../create-alert-dialog"; import type { AlertDialogHandle } from "../handle"; export type AlertDialogRootChangeEventDetails = DialogRootChangeEventDetails; export type AlertDialogRootChangeEventReason = DialogRootChangeEventReason; export type AlertDialogPayloadChildRenderFunction = DialogPayloadChildRenderFunction; /** Imperative actions surface written into `actionsRef`. */ export interface AlertDialogRootActions { close: () => void; unmount: () => void; } export interface AlertDialogRootProps { /** * Controlled open state. When provided (resolved value not * `undefined`), the consumer owns the state — pair with * {@link onOpenChange}. When omitted, the alert dialog manages its own * open state (seeded from {@link defaultOpen}). */ open?: MaybeAccessor; /** * Initial open state when uncontrolled. Read once at mount. * @default false */ defaultOpen?: MaybeAccessor; /** Fires on every open/close request. */ onOpenChange?: | ((open: boolean, eventDetails: AlertDialogRootChangeEventDetails) => void) | undefined; /** * Fires once the open/close transition has settled. */ onOpenChangeComplete?: ((open: boolean) => void) | undefined; /** * Ref (callback or `{ current }`) that receives the imperative actions * object on mount. */ actionsRef?: | ((actions: AlertDialogRootActions | null) => void) | { current: AlertDialogRootActions | null } | undefined; /** * Handle to connect with detached triggers or to control the dialog * imperatively. */ handle?: AlertDialogHandle | undefined; /** Controlled active trigger id (multi-trigger setups). */ triggerId?: string | null | undefined; /** * Children — plain JSX or `({ payload }) => JSX.Element` render * function. */ children?: JSX.Element | AlertDialogPayloadChildRenderFunction; } function AlertDialogRootComponent( props: AlertDialogRootProps, ): JSX.Element { // Compose the headless AlertDialog primitive — pins `modal: true` and // `disablePointerDismissal: true` as fixed invariants of the // `alertdialog` role. The wrapper layers floating-UI, focus trap, // scroll lock, portal, and animation on top. `onOpenChange` is NOT // wired into the primitive — the wrapper's own `setOpen` is the sole // writer so it can thread reason/event details through the full // floating-UI pipeline. // Controlled / uncontrolled open state (Base UI `open` / `defaultOpen` // contract) — see `` for the reference wiring. const [resolvedOpen, setUncontrolledOpen] = createControlledState({ controlled: () => { const controlled = readOption(props.open); return controlled === undefined ? undefined : Boolean(controlled); }, default: () => readOption(props.defaultOpen), fallback: false, name: "", state: "open", }); const alertDialogPrimitive = createAlertDialog({ open: resolvedOpen, }); return useDialogRootInternal(props, { role: "alertdialog", // AlertDialog's primitive surfaces `modal` and // `disablePointerDismissal` as literal `true` (fixed invariants). // Adapt to `DialogRootInternalApi`'s accessor shape. api: { open: alertDialogPrimitive.open, modal: () => alertDialogPrimitive.modal, disablePointerDismissal: () => alertDialogPrimitive.disablePointerDismissal, }, setUncontrolledOpen, }); } /** * Groups all parts of the alert dialog. Doesn't render its own HTML * element. */ export function AlertDialogRoot( props: AlertDialogRootProps, ): JSX.Element { if (useDialogRootContext(true) != null || useFloatingParentNodeId() != null) { return ; } return ( ); }