import { Canvas, Controls, Meta } from "@storybook/addon-docs/blocks";

import * as PopoverStories from "./Popover.stories";

<Meta of={PopoverStories} />

# Popover

Replaces mux-magic's `@radix-ui/react-popover` re-export — a rewrite rather than a swap,
for one reason: **Radix owns `open`.** Wrapping it leaves `useVisibility` and Radix both
believing they hold the state, which is the conflict the whole state layer exists to
avoid.

<Canvas of={PopoverStories.Playground} />

## Props

<Controls />

## floating-ui, and only for what it is good at

`@floating-ui/react` is the layer Radix, Base UI, and Ark UI are all *built on*, and it is
**controlled by construction**: you pass state in and it never stores any.

```tsx
useFloating({
  open: isVisible,          // ← read-only. Charcuterie stays the owner.
  onOpenChange: (isNext) => { if (!isNext) hide() },
  middleware: [offset(8), flip(), shift({ padding: 8 })],
  strategy: "fixed",
})
```

It is used for the three things only it can do — collision handling, a real dismiss layer,
and focus management — all consolidated in `useAnchoredOverlay`. The positioning strategy
and the ARIA wiring come from the platform and from `useRole`.

Passing `open:` *into* floating-ui does not violate the `is`/`has` rule; the adapter
boundary is exactly the carve-out that rule already has
([decision](../../../docs/decisions/2026-07-29-is-has-rule-has-no-external-api-carve-out.md)).

## Portalled, not the top layer

The panel renders in a `FloatingPortal` at `document.body`. `popover="manual"` was reached
for first — no `z-index` contest, no portal — but the top layer does not escape an
`overflow: hidden` ancestor's *clipping* in every case the fleet hit, and a portal does
([decision](../../../docs/decisions/2026-08-03-overlays-portal-to-the-body-not-the-top-layer.md)).

The objection a portal used to raise — that it moves the panel out of a scoped `canvas`
query — is answered:

> `useRole` writes `aria-controls` on the trigger pointing at the panel `id`, so
> trigger→panel stays followable across the boundary (the test asserts it). And the story
> scopes panel queries to `within(document.body)` while `expectAgentDrivable` — structural
> — needs no change.

`useDismiss` owns Escape and outside-press through our callback, so Charcuterie stays the
only thing that decides `isVisible`. `strategy: "fixed"` keeps the coordinates
viewport-relative; `AllVariants` asserts the panel is positioned at all, for exactly this
reason.

<Canvas of={PopoverStories.AllVariants} />

## The name is required

`role="dialog"` takes **no accessible name from its content**, so `heading` is required and
becomes `aria-label`. An unnamed panel is announced as "dialog" and is unfindable by
`getByRole("dialog", { name })` — the same trap `Spinner` walked into in M3 with
`role="status"`
([decision](../../../docs/decisions/2026-07-29-status-regions-carry-an-aria-label.md)).

`aria-expanded`, `aria-haspopup`, and `aria-controls` on the trigger, and `id` and `role`
on the panel, all come from `useRole` — one source for both ends of the link, because a
hand-written `aria-controls` pointing at an id that moved renders identically and
announces nothing.

<Canvas of={PopoverStories.AllStates} />

## The trigger is cloned, not wrapped

`useClonedChild` injects the reference props and the ref into whatever button you already
have. An extra `<div>` around it is how a toolbar's layout quietly changes, and it is why
this is the pattern v1 chose and M2 ported.

It **composes** rather than overwrites: your button's own `ref` and its own `onClick` are
still called, with the popover's added. Until 1.0.1 they were replaced — silently, because a
ref that is never called and a handler that never runs both look exactly like nothing
happening.

## Escape *is* pressable here

Unlike `Modal`'s. `useDismiss` listens for a keydown rather than relying on a UA default
action, and a synthetic keydown is a real keydown as far as a listener is concerned — so
the `Interactive` story presses it for real, and also dismisses by pressing the page
behind the panel.

<Canvas of={PopoverStories.Responsive} />

A popover is positioned against the **viewport**, so `Responsive` is three triggers pinned
to three edges rather than a `ContainerBoard`. The assertion is that the panel stays
inside the viewport — which is all `flip` and `shift` actually promise; asserting a
specific side would be asserting the collision did not happen.

<Canvas of={PopoverStories.Interactive} />
