kerfjs 5.0.0-beta.95 → 5.0.0-beta.97

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.
package/CHANGELOG.md CHANGED
@@ -8,6 +8,26 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
8
8
 
9
9
  ### Fixed
10
10
 
11
+ - In a divided list, `ListItem`, `ListItemLink`, and `ListActionRow` corners now follow the row's position. A corner is flat wherever a divider line meets it, whether the row draws that line or its neighbor does, so with lines between rows the first row rounds only its top, middle rows are flat, and the last row rounds only its bottom. Previously each row squared only the edges it drew itself, so in a `divider="after"` list every hovered or selected row was rounded on top and flat on the bottom, including the last. A single divided row is unchanged (`KF-AQN4H7`).
12
+
13
+ - A collapsible `TokenSearchField` in a `ToolbarControlGroup` with `content="search"` and `sizing="grow"` now opens and closes as one surface. The group snapped straight to its grown width (its `width: auto` cannot transition) while the field animated its own width inside it, so for about 250ms the pill showed an empty band and the query wrapped onto several lines. The group now animates its flex size, and the field fills it on every frame, laid out at least basis-wide while the group clips it. In a toolbar 480px wide or narrower, where the grown group takes its own row, and under reduced motion, both open in one frame (`KF-50K0JM`). A plain collapsible search group (no `sizing="grow"`) had the same defect in a milder form: its field ran a second width transition that lagged the group's by up to 90px, and the query wrapped onto as many as 19 lines for about 100ms. The group now owns that motion too. The field follows it on every frame and keeps the query on one line until the opening ends, then wraps normally again (`KF-CXQB30`).
14
+
15
+ - A tooltip or popover outside a Web Awesome `wa-dialog` / `wa-drawer` is no longer painted beneath it. Those elements keep their modal `<dialog>` in a shadow root, which kerf's modal checks never saw: a surface opened while one was open was not lifted into the top layer, and surfaces already showing were not re-hosted above one that opened later (its `toggle` event stays inside the shadow root). kerf now also checks the open shadow roots when a surface opens, and watches them for `toggle` while any surface is open; a surface hosted inside the dialog stays where it is. A closed shadow root remains invisible (`KF-1FGTX1`).
16
+
17
+ - A `ToolbarControlGroup` now dims a native button marked `aria-disabled="true"` (one kept focusable while unavailable) exactly as it dims a `disabled` one: half opacity, a `not-allowed` cursor, and no hover surface, including a lone group's whole-group hover. It used to look and hover like an enabled control. A disabled raw `wa-button` in a group also no longer paints the group's hover surface (`KF-Y3ZZ10`).
18
+
19
+ - A focused `scrollable` `List` now draws the theme focus ring inset by the ring width and rounded with the standard control radius. Chromium makes a scroller without focusable rows keyboard-focusable, and a dialog may focus it first. It used to show the UA's square outline outside its box, which a rounded or `overflow: hidden` parent clipped (`KF-AJNFTT`).
20
+
21
+ - Typing quickly into a `TokenSearchField` whose app commits typed grammar to chips from `onEdit` (or removes a chip from `keyboard.onRemoveToken`) no longer loses keys. The token change re-keys the editor, so the controlled render replaced the focused element, and keys typed before the app refocused it went nowhere: `site:north site:annex` became `[site:north] ite:annex`. `wireTokenSearchFields` now hands focus and caret to the replacement at the same mutation checkpoint, as it already did for Clear and native deletion. A caret at the end stays at the end, and any other caret keeps its place in the remaining text (`KF-96TEF4`).
22
+
23
+ - `DialogSurface` no longer names a `wa-dialog`'s native panel when the host is itself an explicit, named dialog (`role="dialog"` or `"alertdialog"`). Both used to carry the same name, so the accessibility tree had two dialogs with one name and role queries such as Playwright's `getByRole('dialog', { name })` failed in strict mode. Removing or changing the host role restores the panel name (`KF-A0NF2S`).
24
+
25
+ - A nested `PopupMenu` submenu's pointer "safe triangle" now spans the gap to the placed submenu. Web Awesome measured the submenu for that triangle before its asynchronous placement landed, so the triangle kept the submenu's pre-placement edge (often the viewport origin): its fixed, viewport-sized hit region fanned away from the submenu and could cover the parent menu's rows, swallowing their hover and clicks. PopupMenu now re-measures once the placement lands and again when the submenu's show animation settles, so applications need no `::part(submenu)::before` override (`KF-YAHAZK`).
26
+
27
+ - A `scrollable` `List` bounded by a `max-height` ancestor now scrolls its rows instead of compressing them. Its children kept the default `flex-shrink: 1`, and a `ListItem` clips its own overflow, so multiline rows shrank into one another and their descriptions overlapped the next row. A scrollable List's direct children no longer shrink, and `docs/layout.md` documents bounding one with `flex` inside a max-height flex column (`KF-93GZC1`).
28
+
29
+ - A `popover()`, `tooltip()`, or `openAnchoredSurface()` opened from inside a Web Awesome `wa-dialog` or `wa-drawer` is now interactive. Those elements keep their modal `<dialog>` in a shadow root, so kerf found no dialog above the slotted trigger and appended the surface to `document.body`, where the modal made it inert: it painted above the dialog, but its controls took no focus or input. kerf now resolves the modal context across shadow boundaries: a shadow host whose slot renders the trigger inside an open modal `<dialog>` counts as that dialog, and kerf creates the overlay host slot in the host's light DOM, so the surface is slotted inside the dialog. A surface inside a modal context, through its host slot or an explicit `container`, now also closes when that dialog closes. Escape still closes only the surface. `openAnchoredSurface()` accepts a `container` for any other modal context, and `openAnchoredSurfaceAt()`'s `context` resolves a `wa-dialog` / `wa-drawer` too (`KF-F52T5D`).
30
+
11
31
  - Re-renders of a large page whose rows come from a memoized `each()` now scale with the change instead of the row count. The change-scoped morph now also runs on renders that contain `each()` lists: a change beside the list, such as a details pane that follows the selection, is re-parsed and morphed without visiting the rows, and kerf falls back to the full diff when the change sits in the element that holds the rows. After such a render, the scan for list markers skips the bound rows. `SafeHtml` also builds its HTML string on first read instead of at construction, so each element above a list no longer copies every row's markup. A one-row selection on a 300-row memoized keyed page drops from about 3.7 ms to 0.3 ms per render in Chromium (about 29 ms to 3 ms in happy-dom). An attribute set imperatively on an element outside the changed markup now survives such a render, as it already did on list-free pages (`KF-03KWNV`).
12
32
 
13
33
  - On the same kind of page, a mount that also has a fine-grained binding outside the list (for example `class={signal}` on a page wrapper) no longer searches every row for binding markers after a render that changed the page. Rows carry only their own row-scoped markers, so kerf now skips them. A selection flip on the 300-row keyed fixture with one such binding drops from about 3.7 ms to 0.4 ms in Chromium (about 66 ms to 6 ms in happy-dom) (`KF-5S9XPH`).
@@ -44,12 +64,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
44
64
 
45
65
  - Inspector TabBars use the shared rounded rectangle radius on the strip and inset tabs while ordinary segmented TabBars retain their pill geometry (`KF-K3RDN1`).
46
66
 
67
+ - **`KUI-L103` no longer flags a component's classes inside its own source.** `ui-public-boundaries` treats a catalog entry's `source` file as the owner of that entry's public classes, so an app component writing its own root class is not reported as recreating itself. Apps no longer need to mark those classes `placeableClasses` to silence it. Any other file, including another component's source, is still checked (`KF-G6FR6V`).
68
+
47
69
  ### Documentation
48
70
 
49
71
  - New recipe in the `kerfjs/async` API reference: move heavy app compute (fuzzy search, CSV or markdown parsing, aggregation) into a Worker by having a `resource()` fetcher post a message to the worker and resolve with its reply. It covers request/reply ids, dropping superseded results, worker errors, transferring `ArrayBuffer`s, and keeping the render on the main thread (`KF-04KHT9`).
50
72
 
51
73
  - Clarify for AI consumers that sunken/lowered token names resolve to a translucent tint, and explain intentional nested layers versus duplicate surface paint (`KF-9CM6D8`).
52
74
 
75
+ - **`layout.roles` vocabulary for app components.** The component-packages guide documents the eleven roles `@kerfjs/ui` uses, what each covers, and how to map application dialogs, rows, status indicators, and composed views onto them. The `kerf.components.json` schema description lists them, and the `create-kerf-component` template now uses `controls` instead of a one-off `counter` role (`KF-4E04HF`).
76
+
53
77
  ### Removed
54
78
 
55
79
  - **Breaking (`@kerfjs/ui`, 5.0 beta):** remove the Catalog geometry highlight overlay, its `geometryOverlay` prop, `wireCatalogGeometryOverlay` helper, and specimen skip marker. Catalog previews retain their component borders, outlines, and focus states (`KF-E3WKA5`).
@@ -58,6 +82,65 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
58
82
 
59
83
  ### Added
60
84
 
85
+ - **Chat-bubble `ContentItem`s.** `bubble="start" | "end"` lays a `ContentItem` out as a transcript bubble: it fits its message up to 80% of the row, sits at the start (other participants) or end (the person's own messages), and wraps long unbroken text. The new `appearance="brand-loud"` paints the solid brand fill with its on-loud foreground for the person's own messages (`KF-M3HJK8`).
86
+
87
+ - **`DialogSurface rootAttributes`.** `DialogSurface` takes safe `data-*` `rootAttributes`, such as a `data-key`, on its root; its own configuration attributes stay protected. Sibling dialogs that render conditionally then morph by identity rather than by position. Before, a re-render could reuse one open dialog's element for another, swapping its accessible name and suppressing `wa-after-hide`. Apps no longer wrap each dialog in a keyed `div` (`KF-D7H0WN`).
88
+
89
+ - **Heading supporting text.** A read-only `ToolbarText` takes `description`: quiet, single-line, truncating copy under the title ("Changes save automatically."). It starts at the title's text whether or not a leading icon group is present, and shares the control band so trailing actions stay aligned. `descriptionId` gives it an id for `aria-describedby`. With a description, `id` and `headingLevel` apply to the title span alone, so `aria-labelledby` names only the title. Apps no longer recompute the title inset from toolbar tokens (`KF-DXVMBN`).
90
+
91
+ - **Drag-to-reorder list rows in `@kerfjs/ui`.** `ListItem`, `ListItemLink`, and `ListActionRow` take `draggable`, `dragging`, and `dropPosition: 'before' | 'after'`: a draggable row is a native HTML drag source (never while it is a loading placeholder), a dragging row dims, and a drop position draws a 2px brand insertion line on that edge of the row (`--kui-list-item-drop-indicator` / `--kui-list-action-row-drop-indicator` and matching width and dragging-opacity tokens; system `Highlight` in forced colors). The new `@kerfjs/ui/wire-list-reorder` subpath adds `wireListReorder(root, { onReorder })`, which paints those states during a pointer drag, moves rows with Alt+Shift+ArrowUp/ArrowDown and restores focus after the re-render, and reports `{ listId, sourceIds, target: { id, position }, source }`; dragging a selected or pressed row moves every selected row of its `List`. `reorderListItems` applies the change to an array. Apps no longer hand-style dragged rows and insertion lines (`KF-HWYE11`).
92
+
93
+ - **Compact `Toolbar` density.** `Toolbar density="compact"` makes a 40px header for a panel embedded in a card or inspector: a 34px control band (the compact `ToolbarControlGroup` size) with 3px block insets, keeping the 8px inline insets and zone gap. Fill it with `size="compact"` groups. `--kui-toolbar-inset` still overrides the block inset Composite toolbars forward `density` from their `ToolbarConfig` (Workbench panel, main, and bottom toolbars, CollapsiblePanel, NavStack, SplitView) and size the groups they compose (panel and relocated toggles, the back button) to match; `CollapsiblePanelRelocated` takes `density` for its destination toolbar (`KF-0QDF0V`, `KF-QPSTTA`).
94
+
95
+ - **`ChoiceChips` for a wrapping exclusive choice.** `@kerfjs/ui/choice-chips` renders one choice from a visible set too large for a `SegmentedControl` track, such as a nine-color palette in a 560px dialog, as separate pills that wrap with the standard 8px gap at any width. Each pill is backed by a native radio in a named `role="radiogroup"`, so the group is one Tab stop, arrow keys move the selection, and the checked radio submits under `name`. A choice may lead with a `swatch` (a `CssColor`, or `'transparent'` for an outlined dot struck through diagonally) or a decorative `icon`; the group takes `label` or `labelledBy`, a controlled `value`, a delegated `action` for `change`, `size="compact"`, `required`, and group or per-choice `disabled`. Use it instead of wrapping a segmented control or button-appearance `wa-radio` set, whose joined borders turn ragged across rows (`KF-EJPYWD`).
96
+
97
+ - **Viewport-locked app root.** In the opt-in `@kerfjs/ui/document.css` baseline, `data-viewport="locked"` on a body-child `.kui-app-root` gives `html`, `body`, and the root `height: 100dvh` and `overflow: clip`. Mobile browser toolbars can then never leave the root taller than the visible area, and the document itself never scrolls; only the shell's panes do. `docs/document-baseline.md` covers the on-screen keyboard (`KF-1XNQYP`).
98
+
99
+ - **Semantic cursors in `document.css`.** The opt-in `@kerfjs/ui/document.css` baseline now gives native controls semantic cursors with zero specificity: `pointer` on enabled buttons, links, `role="button"`, `summary`, selects, checkbox/radio/button-type inputs, and labels around checkboxes or radios; `not-allowed` on disabled controls, `aria-disabled` role buttons, and a disabled `wa-button`'s `base` part (Web Awesome 3.12 leaves a pointer there); and `text` on text-like inputs and textareas. Components and applications keep their own cursors (`KF-C336VV`).
100
+
101
+ - **`Badge maxWidth`.** A text `Badge` takes `maxWidth` (a `CssLength`). Longer text truncates with an ellipsis inside a new `kui-badge__label`, the badge may shrink below the cap in a tight row, and string or number content becomes the native `title` tooltip unless `title` is supplied (`KF-0WKZY2`).
102
+
103
+ - **`Text align`.** `Text` takes `align="start" | "center" | "end"` (default `start`), so centered status copy that wraps in a narrow surface, or an end-aligned value, uses `Text` directly instead of an app rule on `.kui-text`. Start and middle truncation align their single line to match (`KF-MMAWEG`).
104
+
105
+ - **`SummaryRow`.** `@kerfjs/ui/summary-row` is a selectable, focusable summary of one item (`role="option"`) as a list `row` (bottom divider, `listEdge` rounding for rounded sections) or a board `card`. It has a leading glyph, a semantic `rail`, an identity `title` clamped to `titleLines` (two for rows, four for cards) with `trailingMeta` floated at its end, and a wrapping `metadata` line. Kerf owns hover, focus, `selected`, `dimmed`, narrow compaction, and optional `deferRendering` for long lists (`KF-XCFMX8`).
106
+ - **`Combobox`.** `@kerfjs/ui/combobox` is a free-text field with filtered suggestions that can also create a new value (tags, labels): a native input with the themed field chrome and a 16px font floor on touch devices, on the ARIA combobox pattern (`role="combobox"`, `aria-activedescendant`, a listbox of options). `wireComboboxes(root, { onCommit })` from `@kerfjs/ui/wire-comboboxes` filters as people type, moves the active option with the arrow keys, and reports `{ id, value, created, input }` on Enter, a comma, or a click; `createLabel={false}` allows only suggestions (`KF-XDVAMR`).
107
+ - **File picking and dropping.** `@kerfjs/ui/file-picker` adds `FilePickerTrigger` (a compact, link-toned browse control) and `FileDropZone` (a dashed target that also opens the chooser), both around visually hidden native file inputs with visible focus rings. `wireFilePickers(root, { onFiles })` from `@kerfjs/ui/wire-file-pickers` reports browsed and dropped files, filters drops by `accept` (exported as `fileMatchesAccept`), marks a zone `data-dragging` while files are over it, and resets the input so the same file can be chosen again (`KF-RDV6V9`).
108
+ - **`ContentSwap`.** `@kerfjs/ui/content-swap` swaps two contents in one shared cell (a dialog's two steps, a footer's changing actions) with a `push` (forward or backward, mirrored in right-to-left documents), a `crossfade`, or no motion. Kerf owns the keyframes, the reduced-motion fade, and the inactive side's `inert` and `aria-hidden`; `label` makes it a named region and `slot`/`fill` place it in a dialog label or footer (`KF-V7MZY9`).
109
+ - **`ColumnTrack` for boards.** `@kerfjs/ui/column-track` is a horizontal scroll owner for columns that share the width equally but never narrow below `minColumnWidth` (250px), so a narrow board scrolls instead of crushing them. `layout="paged"` shows one near-full-width column per page with a `peek` of the next, mandatory start snapping, a hidden scrollbar, and smooth scrolling unless reduced motion is preferred (`KF-9WEWRF`).
110
+ - **`EdgeActivityIndicator`.** `@kerfjs/ui/edge-activity-indicator` is a layout-free, pointer-inert activity strip pinned below the top safe area (or flush). While `busy` its thin bars ripple in a traveling wave, drawn by one gradient and an animated mask with no per-bar elements or resize script, and an optional `message` hangs from the edge as a polite status pill. It takes a semantic `tone`, scales in from the edge, and only fades under reduced motion (`KF-CS729Y`).
111
+ - **`ValueTable` layout props.** `labelWidth` (a typed length) gives labels a minimum column and the value the rest of the row; `presentation="stacked"` puts each value under its label, starting at the label's text; and `stackBelow="compact" | "narrow"` stacks only while the table itself is narrower than 512px or 576px (a stacking table fills its container's width). Apps no longer override `--kui-value-table-row-columns` and the row gap/padding tokens for this (`KF-BTMDH5`).
112
+ - **`SplitButton`.** `@kerfjs/ui/split-button` renders a primary action and an attached options trigger on one loud semantic fill (`tone`: brand, neutral, success, warning, danger) with `fill` for full width, `busy` (a spinner and `aria-busy`), and separate `disabled`/`optionsDisabled`. Both halves are native buttons, so the options trigger's `aria-expanded`, `aria-haspopup`, and name reach assistive technology, which a `wa-button-group` could not (`KF-KFC7C2`).
113
+ - **`IconToggleButton` for standalone icon toggles.** `@kerfjs/ui/icon-toggle-button` renders a native `aria-pressed` button with a single contained `ToolbarControlGroup`'s 44px geometry and raised pressed face (pill or rounded), for content and pane footers where a `Toolbar` does not belong and `ToolbarControlGroup`'s toolbar-parent rule (`KUI-L201`) applies. Its required `label` names it and, with help tags registered, shows on hover and focus (`KF-HBWDHE`).
114
+ - **Selected-chrome opt-out for icon-state toggles.** `ToolbarControlGroup` `selectedChrome="none"` keeps pressed controls looking like their neighbors, and `data-selected-chrome="none"` on one button opts out just that control, for a toggle whose glyph already shows its state (an empty or filled star). Hover and focus treatment are unchanged (`KF-GGDABA`).
115
+ - **`FramedList` for inset-grouped rows.** `@kerfjs/ui/framed-list` draws `ValueTable`'s rounded, bordered frame (lowered or base surface) around `FramedListRow`s of arbitrary content, with each row owning its 8px inset, a 44px minimum height, the inset divider above it, and an optional `highlighted` tint. Settings, account, and shortcut lists no longer need a hand-rolled `ul` stylesheet (`KF-2HB7RT`).
116
+ - **ARIA root attributes and a document inset for `List`/`Row`.** `rootAttributes` on a `List` or `Row` now also accepts `aria-*` attributes and a structural `role` (`region`, `group`, `list`, `status`, landmarks, …), so a labeled drop-target region or an `aria-busy` stack needs no wrapper; widget roles are dropped, and a multi-select List keeps owning its grid role and name. `List` `inset="document"` adds a reading inset (24px block, 32px inline, 16px inline below 576px) for reader views (`KF-DNZJCG`).
117
+ - **`Badge` icon, title, and identity.** A text `Badge` takes a decorative leading `icon` (4px before its text, like `Chip`), and every Badge takes a `title` tooltip and safe `data-*` `rootAttributes`, so apps no longer wrap a Badge for status identity or nest a `Row` inside it for icon spacing. A text Badge with a `label` is now a labeled image (`role="img"`), so that name is actually exposed in place of its abbreviated visible text (`KF-2YKKK5`).
118
+ - **`IconButton` for icon-only Lucide buttons.** Web Awesome gives a `wa-button` its square icon-button geometry only when its label holds a lone `wa-icon`, so a button whose only child was a `LucideIcon` kept text-button padding and did not match an adjacent field. `IconButton` (`@kerfjs/ui/icon-button`) renders a `wa-button` with a `LucideIcon` as a square one form-control height on each side, takes a required `label` that names it, and keeps that square beside a field in a `ListInsetControl` (`KF-1315VN`).
119
+ - **`List` surface.** `surface="base"` or `"raised"` paints `--kui-color-surface` or `--kui-color-surface-raised` behind a List and its insets, so a banner strip above a sunken work area no longer needs an app wrapper whose only CSS is a background. A lowered region remains a `SunkenPanel` (`KF-ZKYYH1`).
120
+ - **`CornerStatus` for non-dismissible app-level progress.** The new `@kerfjs/ui/corner-status` component hosts one or more `StateBanner`s at a viewport corner (`placement`: `bottom-end` by default, `bottom-start`, `top-end`, or `top-start`, RTL-aware) with a 16px gutter plus device safe-area insets. It is a native `popover="manual"` in the top layer, so it sits above fixed and z-indexed page chrome, and it has no close button, light dismiss, Escape handling, or focus change. `wireCornerStatus` (`@kerfjs/ui/wire-corner-status`) opens each host as renders insert it; the app removes the host when the work ends. Inside it, a banner drops its inline margin, gains elevation, and paints its tone fill over the opaque surface. `presentation="embedded"` renders the same stack in flow. This replaces fixed-position app CSS around a `StateBanner` and hiding a toast's close button (`KF-PZCPHQ`).
121
+ - **`StateBanner` strip presentation.** `presentation="strip"` renders a full-width status band for a layout edge, such as above a workspace: flush (no inline margin), square, with its copy on the shared content-text column and only tone-colored `dividerSides` edges (bottom by default; `''` draws none). Apps no longer zero the card's margin, radius, padding, and border tokens and draw their own per-tone rule. The default `card` presentation is unchanged (`KF-JQ8FB0`).
122
+ - **Dialogs that fill, and a non-modal dialog surface.**
123
+ - `DialogSurface` gains `height`: a definite modal height bounded by the dynamic viewport minus both gutters, like `maxHeight`. It also gains `bodyLayout="fill"`, which gives the body's whole height to one child (a `SplitView` or `Pane`) that owns its scrolling.
124
+ - The new `PopoverDialogSurface` in `@kerfjs/ui/surface-scaffold` is the non-modal counterpart. It is a native `popover="auto"` `role="dialog"` section that light-dismisses on Escape or an outside press and leaves the page interactive.
125
+ - It owns Kerf's dialog chrome and takes the same `size` / `preferredWidth` / `viewportGutter` / `height` / `maxHeight` / `bodyLayout` props, and it centers in the top layer whatever alignment its host sets. `presentation="embedded"` renders it in flow for catalogs and inline previews.
126
+ - Apps no longer hand-build popovers with their own chrome, viewport math, `:popover-open` grid, and embedded resets (`KF-XHECB9`).
127
+
128
+ - **Sunken surfaces have a fine grain texture.** Every sunken surface paints the new `--kui-sunken-surface`: a seeded 100px monochrome Gaussian grain tile at 4% maximum opacity, over the lowered color. That covers `SunkenPanel`, sunken `Pane`, Workbench regions, TabNavigator scenes, Web Awesome `appearance="sunken"`, and the catalog's lowered specimen viewport. The tile is generated once per page at runtime by the first sunken surface that renders, so no asset ships. `ensureSunkenTexture()` (exported from `@kerfjs/ui` and `@kerfjs/ui/sunken-panel`) covers pages with only Web Awesome sunken surfaces. Set `--kui-sunken-texture: none` at `:root` for the previous flat surface. An app's `--kui-sunken-panel-background` / `--kui-wa-sunken-background` override still wins (`KF-GMAK3H`).
129
+
130
+ - **Required wiring can be root-delegated actions.** Composition catalogs and `kerf.components.json` accept `wiring.actions`, the `data-action` values the app must handle with its own root `delegate()` / `delegateActions()` listener. Required wiring now names at least one helper _or_ action, so an app no longer has to mark such wiring `required: false` and weaken the check. `eslint-plugin-kerfjs`'s `ui-wiring` reports each unhandled action as `KUI-L401`. An action counts as handled when a reachable module imports a Kerf delegation API and names it as a string, selector, or table key. Comments and the component's own source do not count (`KF-AF5KD5`).
131
+
132
+ - **`kerf.components.json` declares where app-owned wiring helpers live.** `composition.wiring.sources` lists each application helper's `{ export, source }`. The generator verifies that the helper is in `helpers`, that the file exists, and that the file exports it. `ui-wiring` then resolves the app's relative imports of that helper, so page-root wiring with helpers such as `wireTicketSearchFields` no longer raises `KUI-L401`. `composition.wiring.scope` (`application` or `module`) is now authorable too. Both fields were previously expressible only in a hand-written catalog (`KF-YZE3DP`).
133
+
134
+ - **`kerf.components.json` zones can name their JSX prop.** A zone may declare `jsx: { prop }` (`children` for the default slot). The prop must be unique per component, and the generated composition catalog keeps it, so `ui-composition` maps a prop's value to its zone exactly as it does for `@kerfjs/ui`'s own catalog (`KF-99Z95S`).
135
+
136
+ - **Context `PopupMenu` owns its anchor.** A context-mode menu takes an `anchor: { x, y }` prop in viewport pixels and renders the point into its own template, so the point survives re-renders and a menu rebuilt with changed items. Open it with the new `openPopupMenu(menu)`; `openPopupMenuAt` still works for menus without `anchor`. The menu's root is now out of flow (`position: fixed`, 0×0). Previously its 0×0 `inline-block` added a line box in block layout and an extra gap slot in a flex row. Apps no longer need a fixed, 1px, z-indexed wrapper, and no z-index is needed because the open menu is in the top layer (`KF-FXGW0C`).
137
+
138
+ - **`SplitView` `listWidth`.** Size the fixed list column with a prop instead of a raw token: a number of CSS pixels, or `{ size, maxFraction }` to cap it at that share of the split's own width (`{ size: 432, maxFraction: 0.5 }` is 432px until the split is narrower than 864px). A narrow dialog then always leaves the detail in view. It is validated, and it throws when combined with `resizable`, which already sizes the list. The guide now states, and browser tests pin, that a SplitView fills any container with a definite height: a block box, a fixed-size popover, a flex column below a header, or a grid. Apps do not need a `display: grid` / `minmax(0, 1fr)` wrapper (`KF-7R5NWM`).
139
+
140
+ - **`Text` truncates at the start or in the middle.** With `wrap="truncate"`, the new `truncate` prop places the ellipsis at the `end` (default), the `start` (keeping the tail, for branch names), or the `middle` (keeping a suffix, for file paths). `truncateKeep` chooses that suffix: the last path segment (default) or a number of trailing characters. Start truncation uses an isolated left-to-right run instead of a bare `direction: rtl`, so punctuation stays in place. Both positions keep the whole value in the DOM and show it as the `title` unless the app sets one. Apps no longer need split spans or rtl CSS for this (`KF-XYA6VR`).
141
+
142
+ - **A trailing overflow menu for `ListActionRow`.** Pass `trailingMenu: { label, icon, items, placement?, disabled? }` instead of the `trailingAction*` props and the row renders a real `PopupMenu` (icon-only, no caret, opening `bottom-end` by default) as its sibling trailing control, so a command row with a "…" menu of Edit and Delete no longer needs a control inside dormant content or an override. The types accept exactly one trailing control. `trailingActionVisibility="interaction"` reveals the menu trigger on hover or focus and keeps it visible while the menu is open; a placeholder row disables it. `openPopupMenuAt` now also opens a button-triggered `PopupMenu` at a pointer position: for that opening the menu anchors at the point and opens `bottom-start`, then returns to its trigger and placement once it closes. A row can therefore open its trailing menu from its own `contextmenu` handler (`KF-VWTCYB`).
143
+
61
144
  - **UX Review capture for catalogs served without Vite.** `@kerfjs/ui/vite-ux-review` now also exports the endpoint behind the catalog's **Capture region** link in server-neutral forms: `resolveUxReviewProject({ root?, projectDirectory? })`, `uxReviewProjectResponse(request, projectDirectory)` for Fetch API servers (Hono, Bun, Deno), and `uxReviewMiddleware(projectDirectory)` for Node/connect servers (Express, `node:http`). An app that serves its UX catalog from its own backend mounts one on its development server instead of hand-rolling the route. `uxReviewPlugin()` is now built on the same middleware, with unchanged behavior (`KF-PFF721`).
62
145
 
63
146
  - **A per-entry settings pane in `@kerfjs/ui/catalog`.** Pass an entry's variant and state controls as `Catalog`'s new `settings` prop and the Catalog renders a **Settings** pane beside the stage, with the standard collapse toggle: in the pane's header while open, at the end of the entry toolbar while collapsed. Entries without settings render neither the pane nor the toggle. The app owns `settingsCollapsed`; hand the same signal to `wireCatalog`'s new `settingsCollapsed` option and it flips the signal from the toggle (`onToggleSettings` reports it) and wires the pane as a Workbench rail, so below the `narrow` breakpoint it starts collapsed and opens as an overlay that Escape or an outside press closes, exclusive with the sidebar overlay. `settingsPanel` sets the title, width, resizing, and overlay options (`settingsSize` / `settingsStorageKey` remember a resized width). The UX catalog's Badge entry demonstrates it with a playground. Consumers no longer build their own settings aside and toggle (`KF-0AY6AE`).
package/ai/manifest.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "kerfjsVersion": "5.0.0-beta.95",
2
+ "kerfjsVersion": "5.0.0-beta.97",
3
3
  "files": [
4
4
  {
5
5
  "name": "skill",
package/dist/overlay.d.ts CHANGED
@@ -9,7 +9,12 @@ type DismissTrigger = 'escape' | 'backdrop' | 'outside';
9
9
  type OverlayContent = SafeHtml | (() => MountResult);
10
10
  /** Options for {@link overlay}. */
11
11
  interface OverlayOptions {
12
- /** Where to append the overlay wrapper. Default `document.body`. */
12
+ /**
13
+ * Where to append the overlay wrapper. Default `document.body`. A container
14
+ * inside an open modal `<dialog>` (including one slotted into a shadow-root
15
+ * modal such as Web Awesome's `wa-dialog`) is already interactive, so the
16
+ * surface is not lifted, and it closes when that dialog closes.
17
+ */
13
18
  container?: Element;
14
19
  /** Class on the wrapper element (you style it — kerf ships no CSS). Default `'kerf-overlay'`. */
15
20
  className?: string;
@@ -244,7 +249,11 @@ interface PopoverOptions {
244
249
  * Where to append the popover wrapper. Default: when `anchor` sits inside an
245
250
  * open modal `<dialog>`, that dialog's `[data-kerf-overlay-host]` element (a
246
251
  * dialog kerf opened gets one automatically), so the popover is part of the
247
- * modal subtree and stays interactive; otherwise `document.body`.
252
+ * modal subtree and stays interactive; otherwise `document.body`. A modal
253
+ * `<dialog>` in a shadow root counts when `anchor` is slotted into it (Web
254
+ * Awesome's `wa-dialog` / `wa-drawer`): the slot is created on demand in the
255
+ * shadow host's light DOM. A popover inside a modal closes when that dialog
256
+ * closes.
248
257
  */
249
258
  container?: Element;
250
259
  /** Class on the wrapper. Default `'kerf-popover'`. */
package/dist/overlay.js CHANGED
@@ -39,12 +39,40 @@ function overlayArbitration(doc) {
39
39
  const arbitration = arbitrated[OVERLAY_ARBITRATION];
40
40
  if (dialog.tagName === "DIALOG" && !arbitration.stack.some(({ el }) => el === dialog) && isOpenModal(dialog, arbitration))
41
41
  rehostAbove(arbitration, dialog);
42
- }
42
+ },
43
+ shadowRoots: /* @__PURE__ */ new Set()
43
44
  };
44
45
  }
46
+ function openShadowRoots(root, found = []) {
47
+ const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
48
+ for (let node = walker.nextNode(); node !== null; node = walker.nextNode()) {
49
+ const shadow = node.shadowRoot;
50
+ if (shadow !== null) {
51
+ found.push(shadow);
52
+ openShadowRoots(shadow, found);
53
+ }
54
+ }
55
+ return found;
56
+ }
57
+ function watchShadowRoots(arbitration, roots) {
58
+ for (const root of roots)
59
+ if (!arbitration.shadowRoots.has(root)) {
60
+ arbitration.shadowRoots.add(root);
61
+ root.addEventListener("toggle", arbitration.onToggle, true);
62
+ }
63
+ }
64
+ function renderedInside(el, dialog) {
65
+ for (let node = el; node !== null; ) {
66
+ if (node === dialog) return true;
67
+ const root = node.getRootNode();
68
+ node = node.assignedSlot ?? node.parentElement ?? (root instanceof ShadowRoot ? root.host : null);
69
+ }
70
+ return false;
71
+ }
45
72
  function rehostAbove(arbitration, dialog) {
46
73
  for (const { el, liftAbove } of arbitration.stack)
47
- if (el !== dialog && el.isConnected && !dialog.contains(el)) liftAbove?.();
74
+ if (el !== dialog && el.isConnected && !renderedInside(el, dialog))
75
+ liftAbove?.();
48
76
  }
49
77
  function isOpenModal(dialog, arbitration) {
50
78
  if (!dialog.isConnected || dialog.open !== true)
@@ -57,24 +85,39 @@ function isOpenModal(dialog, arbitration) {
57
85
  return false;
58
86
  }
59
87
  }
60
- function modalDialogOpen(doc, arbitration) {
61
- return arbitration.stack.some(({ el }) => isOpenModal(el, arbitration)) || Array.from(doc.querySelectorAll("dialog[open]")).some(
62
- (dialog) => isOpenModal(dialog, arbitration)
88
+ function modalDialogOpen(doc, arbitration, shadowRoots) {
89
+ return arbitration.stack.some(({ el }) => isOpenModal(el, arbitration)) || [doc, ...shadowRoots].some(
90
+ (root) => Array.from(root.querySelectorAll("dialog[open]")).some(
91
+ (dialog) => isOpenModal(dialog, arbitration)
92
+ )
63
93
  );
64
94
  }
95
+ function modalContext(el, arbitration) {
96
+ let child;
97
+ for (let node = el; node !== null; ) {
98
+ const dialog = node.localName === "dialog" ? node : child?.assignedSlot?.closest("dialog");
99
+ if (dialog != null)
100
+ return isOpenModal(dialog, arbitration) ? { dialog, root: node } : void 0;
101
+ child = node;
102
+ const root = node.getRootNode();
103
+ node = node.parentElement ?? (root instanceof ShadowRoot ? root.host : null);
104
+ }
105
+ return void 0;
106
+ }
65
107
  function overlayHost(anchor) {
66
108
  const arbitration = overlayArbitration(document);
67
- const dialog = anchor.closest("dialog");
68
- if (dialog === null || !isOpenModal(dialog, arbitration)) return void 0;
69
- let host = Array.from(dialog.querySelectorAll(OVERLAY_HOST_SELECTOR)).find(
70
- (el) => el.closest("dialog") === dialog
109
+ const context = modalContext(anchor, arbitration);
110
+ if (context === void 0) return void 0;
111
+ const { dialog, root } = context;
112
+ let host = Array.from(root.querySelectorAll(OVERLAY_HOST_SELECTOR)).find(
113
+ (el) => modalContext(el, arbitration)?.root === root
71
114
  );
72
- if (host === void 0 && arbitration.stack.some(({ el }) => el === dialog)) {
73
- dialog.insertAdjacentHTML(
115
+ if (host === void 0 && (root !== dialog || arbitration.stack.some(({ el }) => el === dialog))) {
116
+ root.insertAdjacentHTML(
74
117
  "beforeend",
75
118
  '<div data-kerf-overlay-host data-morph-skip data-morph-preserve style="display:contents"></div>'
76
119
  );
77
- host = dialog.lastElementChild;
120
+ host = root.lastElementChild;
78
121
  }
79
122
  return host;
80
123
  }
@@ -112,8 +155,9 @@ function overlay(content, options = {}) {
112
155
  assertInitialFocusSelector(initialFocus);
113
156
  const triggers = dismiss === false ? [] : Array.isArray(dismiss) ? dismiss : [dismiss];
114
157
  const arbitration = overlayArbitration(document);
115
- const containerDialog = container.closest("dialog");
116
- const liftOverModal = !native && !(containerDialog !== null && isOpenModal(containerDialog, arbitration)) && modalDialogOpen(document, arbitration);
158
+ const containerContext = modalContext(container, arbitration);
159
+ const shadowRoots = openShadowRoots(document);
160
+ const liftOverModal = !native && containerContext === void 0 && modalDialogOpen(document, arbitration, shadowRoots);
117
161
  const topLayer = native || liftOverModal;
118
162
  const useDialog = topLayer && trap && supportsDialog();
119
163
  const usePopover = topLayer && !trap && supportsPopover();
@@ -162,8 +206,12 @@ function overlay(content, options = {}) {
162
206
  const { stack } = arbitration;
163
207
  const stackIndex = stack.indexOf(surface);
164
208
  if (stackIndex !== -1) stack.splice(stackIndex, 1);
165
- if (stack.length === 0)
209
+ if (stack.length === 0) {
166
210
  document.removeEventListener("toggle", arbitration.onToggle, true);
211
+ for (const root of arbitration.shadowRoots)
212
+ root.removeEventListener("toggle", arbitration.onToggle, true);
213
+ arbitration.shadowRoots.clear();
214
+ }
167
215
  for (const other of stack)
168
216
  if (other.restoreTo !== null && wrapper.contains(other.restoreTo))
169
217
  other.restoreTo = surface.restoreTo;
@@ -200,6 +248,7 @@ function overlay(content, options = {}) {
200
248
  );
201
249
  if (arbitration.stack.push(surface) === 1)
202
250
  document.addEventListener("toggle", arbitration.onToggle, true);
251
+ watchShadowRoots(arbitration, shadowRoots);
203
252
  if (useDialog) {
204
253
  wrapper.showModal();
205
254
  nativeOpened = true;
@@ -214,6 +263,12 @@ function overlay(content, options = {}) {
214
263
  makeTabReachable();
215
264
  removers.push(attach(wrapper, () => close));
216
265
  }
266
+ if (containerContext !== void 0) {
267
+ const { dialog } = containerContext;
268
+ const onDialogClose = () => close();
269
+ dialog.addEventListener("close", onDialogClose);
270
+ removers.push(() => dialog.removeEventListener("close", onDialogClose));
271
+ }
217
272
  applyInitialFocus();
218
273
  } catch (error) {
219
274
  close();
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/overlay-core.ts","../src/overlay-choice.ts","../src/overlay-confirm.ts","../src/overlay-prompt.ts","../src/overlay-form.ts","../src/overlay-position.ts","../src/overlay-popover.ts","../src/overlay-toast.ts","../src/overlay-tooltip.ts"],"names":["options"],"mappings":"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","file":"overlay.js","sourcesContent":["/**\n * Shared overlay lifecycle and document arbitration implementation.\n *\n * Every real kerf app hand-rolls this: `toElement → body.appendChild → mount →\n * wire dismissal → remove`, plus the fiddly parts (Escape, backdrop / outside\n * click, focus trap, restoring focus on close). `window.confirm` is a no-op in\n * Tauri WKWebViews, so a hand-built overlay is mandatory there. This subpath\n * blesses the pattern through `overlay()`, with anchored surfaces and dialog\n * helpers building on it. No per-instance framework state: each call owns its\n * DOM + listeners in a closure and returns a handle.\n *\n * import { overlay, confirm, toast } from 'kerfjs/overlay';\n *\n * const ok = await confirm('Delete this file?', { danger: true });\n * toast('Saved');\n * const dialog = overlay(<Settings />, { dismiss: ['escape', 'backdrop'] });\n * // …later: dialog.close(); or await dialog.result;\n *\n * Structural only — kerf ships no CSS. The wrapper gets your `className`; style\n * the backdrop / centering / animation yourself.\n */\nimport { attach } from './attach.js';\nimport { devHooks } from './dev-hooks.js';\nimport type { SafeHtml } from './jsx-runtime.js';\nimport { mount, type MountResult } from './mount.js';\nimport { OVERLAY_HOST_SELECTOR } from './utils/overlay-host.js';\n\n/** A user-initiated dismissal trigger. */\nexport type DismissTrigger = 'escape' | 'backdrop' | 'outside';\n\n/** Content for an overlay: static `SafeHtml`, or a render function `mount()` drives reactively. */\nexport type OverlayContent = SafeHtml | (() => MountResult);\n\n/** Options for {@link overlay}. */\nexport interface OverlayOptions {\n /** Where to append the overlay wrapper. Default `document.body`. */\n container?: Element;\n /** Class on the wrapper element (you style it — kerf ships no CSS). Default `'kerf-overlay'`. */\n className?: string;\n /**\n * Which user actions dismiss the overlay. Default `['escape', 'backdrop']`.\n * `'backdrop'` = a click on the wrapper itself (not its content); `'outside'`\n * = a click anywhere outside the wrapper (for anchored popovers). `false`\n * disables user dismissal (close it programmatically).\n */\n dismiss?: DismissTrigger | DismissTrigger[] | false;\n /**\n * Where focus lands on open: a selector, `true` (first focusable element, or\n * the wrapper if none), or `false` (leave focus alone). Default `true`.\n */\n initialFocus?: string | boolean;\n /**\n * Trap Tab / Shift+Tab within the overlay while open and mark it\n * `role=\"dialog\"` / `aria-modal=\"true\"`. Default `true`. Set `false` for a\n * non-modal popover.\n */\n trap?: boolean;\n /** ARIA role for the wrapper when `trap` is on. Default `'dialog'`. */\n role?: string;\n /** Called on any user-initiated dismissal (before `close()` runs). */\n onDismiss?: () => void;\n /** For `'outside'` dismissal: clicks on these elements do NOT count as outside (e.g. the trigger button). */\n outsideIgnore?: Element | readonly Element[];\n /**\n * Opt into the browser **top layer** (`docs/19-native-overlay-backing.md`).\n * When `true` and the engine supports it, a modal overlay (`trap: true`) is\n * hosted in a `<dialog>` opened with `.showModal()` — real inerting of the rest\n * of the document + guaranteed stacking above any `z-index` — and a non-modal\n * one (`trap: false`) uses the Popover API (`[popover]` + `showPopover()`).\n * Feature-detected; falls back to today's plain `<div>` where unsupported.\n *\n * The `render` slot + promise API are unchanged — kerf just hosts your markup\n * in a `<dialog>` / `[popover]` instead of a `<div>`. Two caveats: native\n * `<dialog>` / `[popover]` carry **UA default styles** (a `::backdrop`,\n * centering, border, padding) that kerf does not reset — style the element (and\n * its `::backdrop`) via `className`; and `container` is effectively a **no-op**\n * for visual position, since the top layer ignores where the element lives in\n * the DOM. Default `false`.\n */\n native?: boolean;\n}\n\n/** Handle returned by {@link overlay}. Holds no framework state — it's a closure. */\nexport interface OverlayHandle {\n /** The wrapper element (mounted into, appended to `container`). */\n el: HTMLElement;\n /** Tear down: dispose the mount, remove listeners + the node, restore focus, resolve `result`. Idempotent. */\n close(result?: unknown): void;\n /** Resolves with the value passed to `close()` (or `undefined` on user dismissal). */\n result: Promise<unknown>;\n}\n\nconst FOCUSABLE =\n 'a[href],area[href],button:not([disabled]),input:not([disabled]),' +\n 'select:not([disabled]),textarea:not([disabled]),iframe,' +\n '[tabindex]:not([tabindex=\"-1\"]),[contenteditable=\"true\"]';\n\nfunction focusable(root: Element): HTMLElement[] {\n const items = Array.from(\n root.querySelectorAll<HTMLElement>(FOCUSABLE),\n ).filter((el) => !el.hasAttribute('hidden') && el.tabIndex >= 0);\n // WebKit on macOS follows the system's keyboard-navigation preference and\n // may omit implicitly tabbable controls from sequential focus navigation.\n // A focus trap promises stable traversal through every eligible control, so\n // make those implicit stops explicit while preserving authored tabindexes.\n for (const el of items) if (!el.hasAttribute('tabindex')) el.tabIndex = 0;\n return items;\n}\n\n// Native top-layer feature detection (KF-526). Modal → `<dialog>.showModal()`;\n// non-modal → the Popover API. Each is independent — an engine may ship one\n// without the other — and both fall back to the plain `<div>` where absent.\nfunction supportsDialog(): boolean {\n return (\n typeof HTMLDialogElement !== 'undefined' &&\n typeof HTMLDialogElement.prototype.showModal === 'function'\n );\n}\nfunction supportsPopover(): boolean {\n return (\n typeof HTMLElement !== 'undefined' &&\n typeof HTMLElement.prototype.showPopover === 'function'\n );\n}\n\n// Stacked-surface arbitration (KF-CW7GJ8: a tooltip inside a modal used to\n// become \"topmost\" and disable the modal's Escape, backdrop, and focus trap).\n// Every open overlay — native or fallback — is recorded, in open order, on a\n// per-document stack. An input kind (Escape, a backdrop / outside click, Tab\n// for the trap) belongs to the topmost surface that HANDLES that kind; a\n// surface that doesn't handle it is transparent, except that a modal surface\n// is a barrier nothing beneath it sees past. A tooltip (or any overlay with no\n// dismiss trigger and no trap) handles nothing, so it never intercepts. The\n// `handled` set marks an event a surface already acted on, so one click that is\n// both \"outside\" a popover and on the modal backdrop closes only the popover.\nconst OVERLAY_ARBITRATION = Symbol('kerf.overlayArbitration');\n\n/** An arbitration input: a dismiss trigger, or Tab for the focus trap. */\ntype ArbitrationKind = DismissTrigger | 'trap';\n\ninterface OverlaySurface {\n el: HTMLElement;\n triggers: readonly DismissTrigger[];\n modal: boolean;\n /** Where focus returns on close; re-pointed when the surface holding it closes first. */\n restoreTo: Element | null;\n /** Non-modal only: move (or re-show) into the top layer above a newly opened modal `<dialog>`. */\n liftAbove?: () => void;\n}\n\ninterface OverlayArbitration {\n stack: OverlaySurface[];\n handled: WeakSet<Event>;\n /** Document capture listener, installed only while the stack is non-empty. */\n onToggle: (event: Event) => void;\n}\n\ntype ArbitratedDocument = Document & {\n [OVERLAY_ARBITRATION]?: OverlayArbitration;\n};\n\nfunction overlayArbitration(doc: Document): OverlayArbitration {\n const arbitrated = doc as ArbitratedDocument;\n return (arbitrated[OVERLAY_ARBITRATION] ??= {\n stack: [],\n handled: new WeakSet(),\n // KF-AHY6H4: an app-owned modal `<dialog>` opened outside kerf would leave\n // the kerf surfaces already showing inert beneath it. A dialog fires\n // `toggle` after it opens (it does not bubble, so listen in the capture\n // phase); re-host above it exactly as kerf does for its own dialogs, which\n // are skipped here because `overlay()` already re-hosted synchronously.\n onToggle: (event) => {\n const dialog = event.target as Element;\n const arbitration = arbitrated[OVERLAY_ARBITRATION] as OverlayArbitration;\n if (\n dialog.tagName === 'DIALOG' &&\n !arbitration.stack.some(({ el }) => el === dialog) &&\n isOpenModal(dialog, arbitration)\n )\n rehostAbove(arbitration, dialog);\n },\n });\n}\n\n// Every non-modal kerf surface already open is blocked beneath a modal\n// `<dialog>` that just opened: lift (or re-show) it above (KF-FJ9VD8). One\n// inside that dialog is part of its subtree already.\nfunction rehostAbove(arbitration: OverlayArbitration, dialog: Element): void {\n for (const { el, liftAbove } of arbitration.stack)\n if (el !== dialog && el.isConnected && !dialog.contains(el)) liftAbove?.();\n}\n\n// Is `dialog` an open modal `<dialog>`? kerf's own are known from the stack;\n// an app-owned one is found through `:modal`, which an older engine may not\n// parse (then only kerf's own count).\nfunction isOpenModal(\n dialog: Element,\n arbitration: OverlayArbitration,\n): boolean {\n if (!dialog.isConnected || (dialog as HTMLDialogElement).open !== true)\n return false;\n if (arbitration.stack.some(({ el, modal }) => modal && el === dialog))\n return true;\n try {\n return dialog.matches(':modal');\n } catch {\n return false; // `:modal` unsupported\n }\n}\n\n// Is a modal `<dialog>` open (KF-0V9RTE: a plain surface opened in that state\n// is inert and painted beneath the dialog's top layer)?\nfunction modalDialogOpen(\n doc: Document,\n arbitration: OverlayArbitration,\n): boolean {\n return (\n arbitration.stack.some(({ el }) => isOpenModal(el, arbitration)) ||\n Array.from(doc.querySelectorAll('dialog[open]')).some((dialog) =>\n isOpenModal(dialog, arbitration),\n )\n );\n}\n\n// The in-dialog host slot (KF-FBHQEP: a surface lifted over a modal\n// `<dialog>` is visible but inert, because every engine inerts content outside\n// the modal). A `popover()` / `tooltip()` whose anchor sits inside an open\n// modal `<dialog>` renders into that dialog's `[data-kerf-overlay-host]`\n// element instead, so it is part of the modal subtree and fully interactive.\n// An app-owned dialog opts in by marking an element; a dialog kerf opened\n// itself gets one on demand — `display: contents` so it adds no layout box,\n// and `data-morph-skip` + `data-morph-preserve` so the dialog content's own\n// `mount()` neither re-renders nor removes it (`utils/overlay-host.ts` makes\n// the slot a nested-mount boundary).\nexport function overlayHost(anchor: Element): Element | undefined {\n const arbitration = overlayArbitration(document);\n const dialog = anchor.closest('dialog');\n if (dialog === null || !isOpenModal(dialog, arbitration)) return undefined;\n let host = Array.from(dialog.querySelectorAll(OVERLAY_HOST_SELECTOR)).find(\n (el) => el.closest('dialog') === dialog,\n );\n if (host === undefined && arbitration.stack.some(({ el }) => el === dialog)) {\n dialog.insertAdjacentHTML(\n 'beforeend',\n '<div data-kerf-overlay-host data-morph-skip data-morph-preserve style=\"display:contents\"></div>',\n );\n host = dialog.lastElementChild as Element;\n }\n return host;\n}\n\n// `self` is on the stack and handles `kind` (its callers are exactly the\n// handlers it installed for that kind), so it owns `kind` unless some surface\n// above it handles `kind` too or is modal.\nfunction ownsInput(\n stack: readonly OverlaySurface[],\n self: OverlaySurface,\n kind: ArbitrationKind,\n): boolean {\n for (let i = stack.indexOf(self) + 1; i < stack.length; i++) {\n const above = stack[i];\n if (above.modal || (kind !== 'trap' && above.triggers.includes(kind)))\n return false;\n }\n return true;\n}\n\n// Validate a string `initialFocus` BEFORE any DOM mutation: `querySelector`\n// throws a generic `SyntaxError` DOMException on a malformed selector, and the\n// focus pass runs last — after the wrapper, mount, listeners, and stack entry\n// already exist — so an unvalidated selector would strand all of them with no\n// handle to close. An inert fragment parses the selector without matching.\nfunction assertInitialFocusSelector(selector: string): void {\n try {\n document.createDocumentFragment().querySelector(selector);\n } catch (cause) {\n throw new Error(\n `overlay(): invalid initialFocus selector ${JSON.stringify(selector)}`,\n { cause },\n );\n }\n}\n\n/**\n * Open an overlay: append a wrapper to `container`, `mount()` `content` inside\n * it, wire the requested dismissals + (optionally) a focus trap, and return a\n * handle. Concurrent fallback overlays dismiss from the top down. See\n * {@link OverlayOptions}.\n *\n * Construction is transactional: a malformed `initialFocus` selector throws a\n * descriptive error before anything is touched, and if a later setup phase\n * throws (the content's first render, `showModal()` / `showPopover()`), every\n * piece already installed — wrapper node, mount, listeners, fallback-stack\n * entry, top-layer state, moved focus — is rolled back before the original\n * error is rethrown.\n */\nexport function overlay(\n content: OverlayContent,\n options: OverlayOptions = {},\n): OverlayHandle {\n const {\n container = document.body,\n className = 'kerf-overlay',\n dismiss = ['escape', 'backdrop'],\n initialFocus = true,\n trap = true,\n role = 'dialog',\n onDismiss,\n outsideIgnore,\n native = false,\n } = options;\n\n if (typeof initialFocus === 'string')\n assertInitialFocusSelector(initialFocus);\n\n const triggers: readonly DismissTrigger[] =\n dismiss === false ? [] : Array.isArray(dismiss) ? dismiss : [dismiss];\n\n // Native top-layer backing (KF-526), feature-detected: a modal overlay\n // (`trap`) → `<dialog>.showModal()`; a non-modal one → `[popover]`. Each falls\n // back to the plain `<div>` where the API is missing, so behavior is unchanged\n // on unsupporting engines. A surface opened while a modal `<dialog>` is open\n // is lifted the same way even without `native` (KF-0V9RTE), because a plain\n // `<div>` would be inert and painted beneath the dialog.\n const arbitration = overlayArbitration(document);\n // A surface placed inside an open modal `<dialog>` (its host slot, or an\n // explicit `container` there) is already part of the modal subtree: no lift.\n const containerDialog = container.closest('dialog');\n const liftOverModal =\n !native &&\n !(containerDialog !== null && isOpenModal(containerDialog, arbitration)) &&\n modalDialogOpen(document, arbitration);\n const topLayer = native || liftOverModal;\n const useDialog = topLayer && trap && supportsDialog();\n const usePopover = topLayer && !trap && supportsPopover();\n\n const wrapper: HTMLElement = useDialog\n ? document.createElement('dialog')\n : document.createElement('div');\n wrapper.className = className;\n if (usePopover) wrapper.setAttribute('popover', 'manual');\n // `<dialog>.showModal()` conveys modality natively (role + inert), so the ARIA\n // attributes are only needed on the plain-`<div>` fallback.\n if (trap && !useDialog) {\n wrapper.setAttribute('role', role);\n wrapper.setAttribute('aria-modal', 'true');\n }\n const surface: OverlaySurface = {\n el: wrapper,\n triggers,\n modal: trap,\n restoreTo: document.activeElement,\n };\n\n // Does this surface own `kind` right now (and has no surface acted on `event`)?\n const owns = (kind: ArbitrationKind, event?: Event): boolean =>\n !(event !== undefined && arbitration.handled.has(event)) &&\n ownsInput(arbitration.stack, surface, kind);\n\n const removers: Array<() => void> = [];\n const resultBox: { resolve?: (value: unknown) => void } = {};\n const result = new Promise<unknown>((resolve) => {\n resultBox.resolve = resolve;\n });\n const state = { closed: false };\n let disposeMount: (() => void) | undefined;\n let nativeOpened = false;\n\n // KF-FJ9VD8: a modal `<dialog>` kerf opens later would leave this non-modal\n // surface inert beneath it, so the opener calls this to move it into the top\n // layer — or, if it is already a `[popover]`, re-show it so it stacks above\n // the new dialog (the top layer orders by most recent show).\n if (!trap)\n surface.liftAbove = () => {\n if (!supportsPopover()) {\n devHooks.overlayBlockedByModal?.('hidden');\n return;\n }\n const el = wrapper as HTMLElement & {\n showPopover(): void;\n hidePopover(): void;\n };\n if (nativeOpened) el.hidePopover();\n else {\n wrapper.setAttribute('popover', 'manual');\n wrapper.style.inset = 'auto';\n }\n el.showPopover();\n nativeOpened = true;\n if (wrapper.querySelector(FOCUSABLE) !== null)\n devHooks.overlayBlockedByModal?.('inert');\n };\n\n // Also the construction rollback (see the transaction below): every step\n // tolerates a phase that never ran — no mount yet, no stack entry, never\n // appended, never shown.\n function close(value?: unknown): void {\n if (state.closed) return;\n state.closed = true;\n const { stack } = arbitration;\n const stackIndex = stack.indexOf(surface);\n if (stackIndex !== -1) stack.splice(stackIndex, 1);\n if (stack.length === 0)\n document.removeEventListener('toggle', arbitration.onToggle, true);\n // A surface opened from inside this one would restore focus into a node\n // that is about to be detached: hand it this surface's own restore target.\n for (const other of stack)\n if (other.restoreTo !== null && wrapper.contains(other.restoreTo))\n other.restoreTo = surface.restoreTo;\n const active = document.activeElement;\n for (const remove of removers) remove();\n disposeMount?.();\n // Exit the top layer before removing the node, so the native close steps run\n // (restore inert, fire the dialog's `close`). `<dialog>` also restores focus\n // itself; kerf's manual restore below stays as the fallback path's behavior.\n if (nativeOpened) {\n nativeOpened = false;\n if (useDialog) (wrapper as HTMLDialogElement).close();\n else (wrapper as HTMLElement & { hidePopover(): void }).hidePopover();\n }\n wrapper.remove();\n restoreFocus(active);\n resultBox.resolve?.(value);\n }\n\n // Closing a surface that doesn't hold focus (an out-of-order close beneath\n // another open surface) must not pull focus out of the surface that does;\n // otherwise focus returns to where it was when this surface opened.\n function restoreFocus(active: Element | null): void {\n if (\n active instanceof HTMLElement &&\n active.isConnected &&\n arbitration.stack.some((other) => other.el.contains(active))\n ) {\n if (document.activeElement !== active) active.focus();\n return;\n }\n const { restoreTo } = surface;\n if (restoreTo instanceof HTMLElement && restoreTo.isConnected)\n restoreTo.focus();\n }\n\n function userDismiss(): void {\n onDismiss?.();\n close();\n }\n\n // One transaction: if any phase below throws (the content's first render,\n // `showModal()` / `showPopover()`, …), roll back whatever the earlier phases\n // installed via `close()` and rethrow the original error. No handle is\n // returned on failure, so nothing may outlive the call.\n try {\n container.appendChild(wrapper);\n disposeMount = mount(\n wrapper,\n typeof content === 'function' ? content : () => content,\n );\n // Watch for app-owned modal dialogs while any kerf surface is open.\n if (arbitration.stack.push(surface) === 1)\n document.addEventListener('toggle', arbitration.onToggle, true);\n\n // Enter the top layer after the content is mounted + connected.\n // `showModal()` moves focus into the dialog by default; kerf's\n // `initialFocus` pass below runs afterward and wins.\n if (useDialog) {\n (wrapper as HTMLDialogElement).showModal();\n nativeOpened = true;\n rehostAbove(arbitration, wrapper);\n } else if (usePopover) {\n (wrapper as HTMLElement & { showPopover(): void }).showPopover();\n nativeOpened = true;\n // Neutralize the UA `[popover] { inset: 0; margin: auto }` anchoring so\n // `positionAnchored` (which sets `top`/`left`) controls placement —\n // otherwise the retained `right`/`bottom` insets would stretch/center it.\n wrapper.style.inset = 'auto';\n }\n\n installDismissal();\n if (container.closest(OVERLAY_HOST_SELECTOR) !== null) {\n makeTabReachable();\n // KF-WZ9KQM: a slot-hosted surface leaves with its dialog even when its\n // anchor (moved out of the dialog) stays connected, so the anchor watch\n // never fires. Watch the wrapper itself: close as cleanup (no\n // `onDismiss`) and leave the open-order stack.\n removers.push(attach(wrapper, () => close));\n }\n applyInitialFocus();\n } catch (error) {\n close();\n throw error;\n }\n\n // What the lift cannot repair: no top-layer API at all, or a lifted\n // non-modal surface whose controls the modal still inerts.\n if (liftOverModal) {\n if (!useDialog && !usePopover) devHooks.overlayBlockedByModal?.('hidden');\n else if (usePopover && wrapper.querySelector(FOCUSABLE) !== null)\n devHooks.overlayBlockedByModal?.('inert');\n }\n\n return { el: wrapper, close, result };\n\n function installDismissal(): void {\n const wantEscape = triggers.includes('escape');\n if (useDialog) {\n // A native modal `<dialog>` confines Tab focus itself and surfaces Escape as\n // a `cancel` event. Take that over: `preventDefault` so kerf owns teardown\n // (and so Escape is swallowed when it isn't a dismiss trigger), then dismiss.\n // A surface stacked above that handles Escape (or is modal) owns it; a\n // stray `cancel` then leaves this dialog open.\n const onCancel = (event: Event): void => {\n event.preventDefault();\n if (wantEscape && owns('escape')) userDismiss();\n };\n wrapper.addEventListener('cancel', onCancel);\n removers.push(() => wrapper.removeEventListener('cancel', onCancel));\n } else if (wantEscape || trap) {\n const onKeydown = (event: KeyboardEvent): void => {\n if (wantEscape && event.key === 'Escape') {\n if (!owns('escape', event)) return;\n // `preventDefault` also withholds the close request from a native\n // `<dialog>` beneath, so one Escape closes exactly one surface.\n event.stopPropagation();\n event.preventDefault();\n arbitration.handled.add(event);\n userDismiss();\n return;\n }\n if (trap && event.key === 'Tab' && owns('trap')) {\n const items = focusable(wrapper);\n if (items.length === 0) {\n event.preventDefault();\n return;\n }\n const first = items[0];\n const last = items[items.length - 1];\n const active = document.activeElement;\n const outside = !wrapper.contains(active);\n if (event.shiftKey && (active === first || outside)) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && (active === last || outside)) {\n event.preventDefault();\n first.focus();\n }\n }\n };\n document.addEventListener('keydown', onKeydown, true);\n removers.push(() =>\n document.removeEventListener('keydown', onKeydown, true),\n );\n }\n\n if (triggers.includes('backdrop')) {\n const onClick = (event: Event): void => {\n if (event.target !== wrapper || !owns('backdrop', event)) return;\n arbitration.handled.add(event);\n userDismiss();\n };\n wrapper.addEventListener('click', onClick);\n removers.push(() => wrapper.removeEventListener('click', onClick));\n }\n\n if (triggers.includes('outside')) {\n const ignore =\n outsideIgnore === undefined\n ? []\n : Array.isArray(outsideIgnore)\n ? outsideIgnore\n : [outsideIgnore];\n // Capture phase: the click that opened this overlay already passed\n // document's capture phase, so this never fires for that opening click.\n const onDocClick = (event: Event): void => {\n const target = event.target as Node | null;\n if (target === null) return;\n if (wrapper.contains(target)) return;\n if (ignore.some((el) => el === target || el.contains(target))) return;\n if (!owns('outside', event)) return;\n arbitration.handled.add(event);\n userDismiss();\n };\n document.addEventListener('click', onDocClick, true);\n removers.push(() =>\n document.removeEventListener('click', onDocClick, true),\n );\n }\n }\n\n // KF-QZ9SFG (slot-hosted controls unreachable by Tab in macOS WebKit): a\n // surface in an overlay host slot sits in the modal dialog's own Tab order,\n // not behind a kerf trap, so WebKit's system keyboard-navigation preference\n // would skip its implicitly tabbable controls. Make those stops explicit, as\n // the trap does — now, and again before each Tab so a control a re-render\n // added (or whose tabindex the morph dropped) is reachable too.\n function makeTabReachable(): void {\n focusable(wrapper);\n const onTab = (event: KeyboardEvent): void => {\n if (event.key === 'Tab') focusable(wrapper);\n };\n document.addEventListener('keydown', onTab, true);\n removers.push(() => document.removeEventListener('keydown', onTab, true));\n }\n\n function applyInitialFocus(): void {\n if (initialFocus !== false) {\n if (typeof initialFocus === 'string') {\n wrapper.querySelector<HTMLElement>(initialFocus)?.focus();\n } else {\n const first = focusable(wrapper)[0];\n if (first !== undefined) {\n first.focus();\n } else {\n wrapper.tabIndex = -1;\n wrapper.focus();\n }\n }\n }\n }\n}\n\n/**\n * Internal: run a promise-dialog helper's post-open wiring (required-slot\n * lookups, `delegate()` handlers, key listeners) as the tail of `overlay()`'s\n * construction transaction. `wire` registers a disposer for every listener it\n * installs via `track`; if any step throws, those listeners are removed, the\n * just-opened overlay is closed (node, mount, dismissal listeners, stack\n * entry, top-layer state, focus), and the original error is rethrown — so a\n * failed helper call returns no promise and leaves no open overlay behind.\n *\n * After construction, `guard` wraps a user-action handler (OK click, Enter).\n * KF-B0CFQP (a throwing `validate` callback): a throw inside a guarded action\n * is a programming error, so it closes the dialog (full teardown, focus\n * restored) and the returned promise REJECTS with the original error, instead\n * of the error escaping the event handler and stranding an open dialog whose\n * OK can never succeed. Otherwise the returned promise settles with\n * `settle(handle.result's value)`. Not re-exported from `kerfjs/overlay`.\n */\nexport function wireDialog<T>(\n handle: OverlayHandle,\n wire: (\n track: (dispose: () => void) => void,\n guard: (action: () => void) => () => void,\n ) => void,\n settle: (value: unknown) => T,\n): Promise<T> {\n const disposers: Array<() => void> = [];\n // Holds a guarded action's error AND is the close() value that marks the\n // failure, so only a throw that actually settles the dialog rejects it.\n const failure: unknown[] = [];\n try {\n wire(\n (dispose) => void disposers.push(dispose),\n (action) => () => {\n try {\n action();\n } catch (error) {\n failure[0] = error;\n handle.close(failure);\n }\n },\n );\n } catch (error) {\n disposers.forEach((dispose) => dispose());\n handle.close();\n throw error;\n }\n // One hop, not a chain: `settle` maps the value in the same reaction, so a\n // helper's promise settles as soon after `close()` as it always has.\n return handle.result.then((value) => {\n if (value === failure) throw failure[0];\n return settle(value);\n });\n}\n","/** `choice()` implementation and public option types. */\nimport { delegate } from './delegate.js';\nimport { jsx } from './jsx-runtime.js';\nimport { overlay, type OverlayContent, wireDialog } from './overlay-core.js';\n\n/** One choosable action in a {@link choice} dialog. */\nexport interface ChoiceAction<R> {\n value: R;\n label: string;\n className?: string;\n}\n\n/** Wiring slots for a {@link ChoiceOptions.render}. */\nexport interface ChoiceRenderSlots {\n message: string;\n actions: Array<Record<string, string>>;\n}\n\n/** Options for {@link choice}. */\nexport interface ChoiceOptions<R> {\n container?: Element;\n className?: string;\n title?: string;\n defaultValue?: R;\n native?: boolean;\n render?: (slots: ChoiceRenderSlots) => OverlayContent;\n}\n\n/** The N-way sibling of {@link confirm}. */\nexport function choice<R>(\n message: string,\n actions: ReadonlyArray<ChoiceAction<R>>,\n options: ChoiceOptions<R> = {},\n): Promise<R | null> {\n const {\n container,\n className = 'kerf-overlay',\n title,\n defaultValue,\n native = false,\n render,\n } = options;\n const hasDefault = 'defaultValue' in options;\n const actionAttrs = actions.map((_, i) => ({ 'data-choice': String(i) }));\n\n const body: OverlayContent =\n render !== undefined\n ? render({ message, actions: actionAttrs })\n : jsx('div', {\n class: 'kerf-choice',\n children: [\n title !== undefined\n ? jsx('h2', { class: 'kerf-choice__title', children: title })\n : '',\n jsx('p', { class: 'kerf-choice__message', children: message }),\n jsx('div', {\n class: 'kerf-choice__actions',\n children: actions.map((action, i) =>\n jsx('button', {\n type: 'button',\n class:\n action.className !== undefined\n ? `kerf-choice__action ${action.className}`\n : 'kerf-choice__action',\n ...actionAttrs[i],\n children: action.label,\n }),\n ),\n }),\n ],\n });\n\n let resolveChoice!: (result: R | null) => void;\n const result = new Promise<R | null>((resolve) => {\n resolveChoice = resolve;\n });\n\n const handle = overlay(body, {\n container,\n className,\n dismiss: ['escape', 'backdrop'],\n initialFocus: '[data-choice]',\n trap: true,\n native,\n });\n\n // Post-open wiring is still construction: a throw closes the overlay. Any\n // close settles a still-pending choice as a dismissal (`null`).\n void wireDialog(\n handle,\n (track) => {\n track(\n delegate(handle.el, 'click', '[data-choice]', (_event, el) => {\n resolveChoice(actions[Number(el.getAttribute('data-choice'))].value);\n handle.close();\n }),\n );\n\n if (hasDefault) {\n const onKeydown = (event: KeyboardEvent): void => {\n if (event.key === 'Enter') {\n event.preventDefault();\n resolveChoice(defaultValue as R);\n handle.close();\n }\n };\n // Last wiring step: nothing after it can throw, so it needs no rollback.\n handle.el.addEventListener('keydown', onKeydown);\n }\n },\n () => resolveChoice(null),\n );\n return result;\n}\n","/** `confirm()` implementation and public option types. */\nimport { delegate } from './delegate.js';\nimport { jsx } from './jsx-runtime.js';\nimport { overlay, type OverlayContent, wireDialog } from './overlay-core.js';\n\n/** Wiring slots passed to a {@link ConfirmOptions.render}. */\nexport interface ConfirmRenderSlots {\n message: string;\n /** Spread onto the confirm control. */\n ok: Record<string, string>;\n /** Spread onto the cancel control. */\n cancel: Record<string, string>;\n}\n\n/** Options for {@link confirm}. */\nexport interface ConfirmOptions {\n /** Where to append the overlay. Default `document.body`. */\n container?: Element;\n /** Wrapper class. Default `'kerf-overlay'`. */\n className?: string;\n /** Optional heading above the message. */\n title?: string;\n /** Confirm button label. Default `'OK'`. */\n okText?: string;\n /** Cancel button label. Default `'Cancel'`. */\n cancelText?: string;\n /** Add a `kerf-confirm--danger` class to the wrapper for destructive actions. */\n danger?: boolean;\n /** Host the dialog in the browser top layer where supported. */\n native?: boolean;\n /** Bring your own body while retaining kerf's dialog wiring. */\n render?: (slots: ConfirmRenderSlots) => OverlayContent;\n}\n\n/** A promise-based `window.confirm` replacement. */\nexport function confirm(\n message: string,\n options: ConfirmOptions = {},\n): Promise<boolean> {\n const {\n container,\n className = 'kerf-overlay',\n title,\n okText = 'OK',\n cancelText = 'Cancel',\n danger = false,\n native = false,\n render,\n } = options;\n\n const body: OverlayContent =\n render !== undefined\n ? render({\n message,\n ok: { 'data-confirm': 'ok' },\n cancel: { 'data-confirm': 'cancel' },\n })\n : jsx('div', {\n class: 'kerf-confirm',\n children: [\n title !== undefined\n ? jsx('h2', { class: 'kerf-confirm__title', children: title })\n : '',\n jsx('p', { class: 'kerf-confirm__message', children: message }),\n jsx('div', {\n class: 'kerf-confirm__actions',\n children: [\n jsx('button', {\n type: 'button',\n 'data-confirm': 'cancel',\n children: cancelText,\n }),\n jsx('button', {\n type: 'button',\n 'data-confirm': 'ok',\n class: 'kerf-confirm__ok',\n children: okText,\n }),\n ],\n }),\n ],\n });\n\n const handle = overlay(body, {\n container,\n className: danger ? `${className} kerf-confirm--danger` : className,\n dismiss: ['escape', 'backdrop'],\n initialFocus: '[data-confirm=\"ok\"]',\n trap: true,\n native,\n });\n\n // Post-open wiring is still construction: a throw closes the overlay. The\n // click table is the only (and so the last) step, so it needs no rollback.\n return wireDialog(\n handle,\n () => {\n delegate(handle.el, 'click', '[data-confirm]', (_event, el) => {\n handle.close(el.getAttribute('data-confirm') === 'ok');\n });\n },\n (value) => value === true,\n );\n}\n","/** `prompt()` implementation and public option types. */\nimport { delegate } from './delegate.js';\nimport { jsx } from './jsx-runtime.js';\nimport { overlay, type OverlayContent, wireDialog } from './overlay-core.js';\n\n/**\n * Validate a single field's value, synchronously: return a non-empty message\n * to block OK, anything else to accept. A validator that throws is treated as\n * a programming error — the dialog closes and the returned promise rejects\n * with that error.\n */\nexport type FieldValidator = (\n value: string,\n) => string | null | undefined | void;\n\n/** Options for {@link prompt}. */\n/**\n * Run a {@link FieldValidator}: the message it reports, or `undefined` when the\n * value is valid. Validators are synchronous — a promise result is a\n * programming error that closes the dialog and rejects its promise (the stray\n * promise's own rejection is silenced so it is not reported twice).\n * Internal to the dialog helpers.\n */\nexport function runValidator(\n validate: FieldValidator | undefined,\n value: string,\n owner: string,\n): string | undefined {\n const result: unknown = validate?.(value);\n if (typeof (result as PromiseLike<unknown> | null)?.then === 'function') {\n (result as PromiseLike<unknown>).then(undefined, () => undefined);\n throw new TypeError(`${owner}: validate returned a promise.`);\n }\n return typeof result === 'string' && result.length > 0 ? result : undefined;\n}\n\nexport interface PromptOptions {\n container?: Element;\n className?: string;\n title?: string;\n defaultValue?: string;\n placeholder?: string;\n inputType?: string;\n okText?: string;\n cancelText?: string;\n validate?: FieldValidator;\n native?: boolean;\n render?: (slots: PromptRenderSlots) => OverlayContent;\n}\n\n/** Wiring slots for a {@link PromptOptions.render}. */\nexport interface PromptRenderSlots {\n message: string;\n input: Record<string, string>;\n error: Record<string, string>;\n ok: Record<string, string>;\n cancel: Record<string, string>;\n}\n\n/** A promise-based `window.prompt` replacement. */\nexport function prompt(\n message: string,\n options: PromptOptions = {},\n): Promise<string | null> {\n const {\n container,\n className = 'kerf-overlay',\n title,\n defaultValue = '',\n placeholder,\n inputType = 'text',\n okText = 'OK',\n cancelText = 'Cancel',\n validate,\n native = false,\n render,\n } = options;\n\n const inputAttrs: Record<string, string> = {\n 'data-prompt-input': '',\n type: inputType,\n value: defaultValue,\n ...(placeholder !== undefined ? { placeholder } : {}),\n };\n\n const body: OverlayContent =\n render !== undefined\n ? render({\n message,\n input: inputAttrs,\n error: { 'data-prompt-error': '' },\n ok: { 'data-prompt': 'ok' },\n cancel: { 'data-prompt': 'cancel' },\n })\n : jsx('div', {\n class: 'kerf-prompt',\n children: [\n title !== undefined\n ? jsx('h2', { class: 'kerf-prompt__title', children: title })\n : '',\n jsx('label', { class: 'kerf-prompt__message', children: message }),\n jsx('input', { class: 'kerf-prompt__input', ...inputAttrs }),\n jsx('p', {\n class: 'kerf-prompt__error',\n 'data-prompt-error': '',\n children: '',\n }),\n jsx('div', {\n class: 'kerf-prompt__actions',\n children: [\n jsx('button', {\n type: 'button',\n 'data-prompt': 'cancel',\n children: cancelText,\n }),\n jsx('button', {\n type: 'button',\n 'data-prompt': 'ok',\n class: 'kerf-prompt__ok',\n children: okText,\n }),\n ],\n }),\n ],\n });\n\n const handle = overlay(body, {\n container,\n className,\n dismiss: ['escape', 'backdrop'],\n initialFocus: '[data-prompt-input]',\n trap: true,\n native,\n });\n\n // Post-open wiring is still construction: a missing required input or any\n // other throw below removes what was wired, closes the overlay, and rethrows.\n return wireDialog(\n handle,\n (track, guard) => {\n // Looked up again at OK: a reactive re-render may have replaced the\n // input, and a detached node would report a stale value. Missing at\n // construction is a render bug (rolls back, throws); missing at OK\n // rejects the promise through `guard`.\n const inputFor = (problem = 'render missing'): HTMLInputElement => {\n const input = handle.el.querySelector<HTMLInputElement>(\n 'input[data-prompt-input]',\n );\n if (input !== null) return input;\n throw new Error(`prompt(): ${problem} <input data-prompt-input>.`);\n };\n inputFor();\n const errorEl = handle.el.querySelector<HTMLElement>(\n '[data-prompt-error]',\n );\n if (errorEl !== null) errorEl.hidden = true;\n\n // A throwing (or promise-returning) `validate` closes the dialog and\n // rejects the promise (guard).\n const attemptOk = guard((): void => {\n const input = inputFor('removed after open:');\n const value = input.value;\n const error = runValidator(validate, value, 'prompt()');\n if (error !== undefined) {\n if (errorEl !== null) {\n errorEl.textContent = error;\n errorEl.hidden = false;\n }\n input.focus();\n return;\n }\n handle.close(value);\n });\n\n track(\n delegate(handle.el, 'click', '[data-prompt]', (_event, el) => {\n if (el.getAttribute('data-prompt') === 'ok') attemptOk();\n else handle.close(null);\n }),\n );\n\n const onKeydown = (event: KeyboardEvent): void => {\n if (\n event.key === 'Enter' &&\n (event.target as Element | null)?.matches('input[data-prompt-input]')\n ) {\n event.preventDefault();\n attemptOk();\n }\n };\n // Last wiring step: nothing after it can throw, so it needs no rollback.\n handle.el.addEventListener('keydown', onKeydown);\n },\n (value) => (typeof value === 'string' ? value : null),\n );\n}\n","/** `form()` implementation and public option types. */\nimport { delegate } from './delegate.js';\nimport { jsx } from './jsx-runtime.js';\nimport { overlay, type OverlayContent, wireDialog } from './overlay-core.js';\nimport { type FieldValidator, runValidator } from './overlay-prompt.js';\n\n/** A single field in a {@link form}. */\nexport interface FormField {\n name: string;\n label?: string;\n defaultValue?: string;\n placeholder?: string;\n type?: string;\n validate?: FieldValidator;\n}\n\n/** One field's wiring in a {@link FormRenderSlots}. */\nexport interface FormRenderField {\n name: string;\n label: string;\n input: Record<string, string>;\n error: Record<string, string>;\n}\n\n/** Wiring slots for a {@link FormOptions.render}. */\nexport interface FormRenderSlots {\n fields: FormRenderField[];\n ok: Record<string, string>;\n cancel: Record<string, string>;\n}\n\n/** Options for {@link form}. */\nexport interface FormOptions {\n container?: Element;\n className?: string;\n title?: string;\n okText?: string;\n cancelText?: string;\n native?: boolean;\n render?: (slots: FormRenderSlots) => OverlayContent;\n}\n\n/** A promise-based multi-field dialog. */\nexport function form(\n fields: readonly FormField[],\n options: FormOptions = {},\n): Promise<Record<string, string> | null> {\n const {\n container,\n className = 'kerf-overlay',\n title,\n okText = 'OK',\n cancelText = 'Cancel',\n native = false,\n render,\n } = options;\n\n const fieldAttrs = (field: FormField): Record<string, string> => ({\n 'data-field': field.name,\n name: field.name,\n type: field.type ?? 'text',\n value: field.defaultValue ?? '',\n ...(field.placeholder !== undefined\n ? { placeholder: field.placeholder }\n : {}),\n });\n\n const body: OverlayContent =\n render !== undefined\n ? render({\n fields: fields.map((field) => ({\n name: field.name,\n label: field.label ?? field.name,\n input: fieldAttrs(field),\n error: { 'data-field-error': field.name },\n })),\n ok: { 'data-form': 'ok' },\n cancel: { 'data-form': 'cancel' },\n })\n : jsx('div', {\n class: 'kerf-form',\n children: [\n title !== undefined\n ? jsx('h2', { class: 'kerf-form__title', children: title })\n : '',\n ...fields.map((field) =>\n jsx('div', {\n class: 'kerf-form__field',\n children: [\n jsx('label', {\n class: 'kerf-form__label',\n children: field.label ?? field.name,\n }),\n jsx('input', {\n class: 'kerf-form__input',\n ...fieldAttrs(field),\n }),\n jsx('p', {\n class: 'kerf-form__error',\n 'data-field-error': field.name,\n children: '',\n }),\n ],\n }),\n ),\n jsx('div', {\n class: 'kerf-form__actions',\n children: [\n jsx('button', {\n type: 'button',\n 'data-form': 'cancel',\n children: cancelText,\n }),\n jsx('button', {\n type: 'button',\n 'data-form': 'ok',\n class: 'kerf-form__ok',\n children: okText,\n }),\n ],\n }),\n ],\n });\n\n const handle = overlay(body, {\n container,\n className,\n dismiss: ['escape', 'backdrop'],\n initialFocus: '[data-field]',\n trap: true,\n native,\n });\n\n // Post-open wiring is still construction: a missing required field input or\n // any other throw below removes what was wired, closes the overlay, and\n // rethrows.\n return wireDialog(\n handle,\n (track, guard) => {\n const errorFor = (name: string): HTMLElement | null =>\n Array.from(\n handle.el.querySelectorAll<HTMLElement>('[data-field-error]'),\n ).find((el) => el.getAttribute('data-field-error') === name) ?? null;\n // KF-HRNJ4T (a field input removed after open by a reactive re-render):\n // at construction a missing input is a render bug that rolls back and\n // throws synchronously; at OK time it throws inside `guard`, so the\n // dialog closes and the promise rejects naming the field — never a\n // `null` that reads as a user Cancel.\n const inputFor = (\n name: string,\n problem = 'render missing',\n ): HTMLInputElement => {\n const input = Array.from(\n handle.el.querySelectorAll<HTMLInputElement>('input[data-field]'),\n ).find((el) => el.getAttribute('data-field') === name);\n if (input !== undefined) return input;\n throw new Error(`form(): ${problem} <input data-field=\"${name}\">.`);\n };\n\n for (const field of fields) {\n inputFor(field.name);\n const errorEl = errorFor(field.name);\n if (errorEl !== null) errorEl.hidden = true;\n }\n\n // A throwing `field.validate` closes the dialog and rejects the promise.\n const attemptOk = guard((): void => {\n const record: Record<string, string> = {};\n let firstInvalid: HTMLInputElement | null = null;\n for (const field of fields) {\n const el = inputFor(field.name, 'removed after open:');\n const value = el.value;\n record[field.name] = value;\n const error = runValidator(field.validate, value, 'form()');\n const errorEl = errorFor(field.name);\n if (error !== undefined) {\n if (errorEl !== null) {\n errorEl.textContent = error;\n errorEl.hidden = false;\n }\n if (firstInvalid === null) firstInvalid = el;\n } else if (errorEl !== null) {\n errorEl.hidden = true;\n }\n }\n if (firstInvalid !== null) {\n firstInvalid.focus();\n return;\n }\n handle.close(record);\n });\n\n track(\n delegate(handle.el, 'click', '[data-form]', (_event, el) => {\n if (el.getAttribute('data-form') === 'ok') attemptOk();\n else handle.close(null);\n }),\n );\n\n const onKeydown = (event: KeyboardEvent): void => {\n if (\n event.key === 'Enter' &&\n (event.target as Element | null)?.matches('[data-field]')\n ) {\n event.preventDefault();\n attemptOk();\n }\n };\n // Last wiring step: nothing after it can throw, so it needs no rollback.\n handle.el.addEventListener('keydown', onKeydown);\n },\n (value) =>\n value !== null && typeof value === 'object'\n ? (value as Record<string, string>)\n : null,\n );\n}\n","/**\n * Anchored positioning primitives for `kerfjs/overlay` — position an element\n * relative to an anchor, with viewport flip + clamp. These are standalone: they\n * take any element and have no overlay lifecycle, so `popover()` / `tooltip()`\n * build on them but you can also position your own element (an inline hint, a\n * custom menu). Re-exported from `src/overlay.ts` so the public `kerfjs/overlay`\n * surface is unchanged (KF-511 split out of overlay.ts's dialog + toast code).\n */\n\n/** Vertical placement relative to an anchor (used by `popover`, {@link positionAnchored}, `tooltip`). */\nexport type PopoverPlacement = 'bottom' | 'top';\n\n/** Placement options for {@link positionAnchored} / {@link autoReposition}. */\nexport interface AnchorPositionOptions {\n /** Preferred side of the anchor; flips to the other side if it would overflow the viewport. Default `'bottom'`. */\n placement?: PopoverPlacement;\n /** Horizontal edge to line up with the anchor: `'start'` (left edges) or `'end'` (right edges). Default `'start'`. */\n align?: 'start' | 'end';\n /** Gap in px between the anchor and the element. Default `4`. */\n gap?: number;\n}\n\n/**\n * One-shot: position `el` relative to `anchor` — below by default, flipping above\n * if it would overflow the viewport, aligned to a horizontal edge and clamped into\n * view. Sets `el.style` `position: fixed`, `margin: 0`, `left`, and `top` (fixed so\n * `left`/`top` are viewport coordinates, matching `getBoundingClientRect`). When an\n * ancestor makes itself the containing block for fixed descendants (a\n * `transform`, `filter`, `perspective`, or `contain` on a wrapping `<dialog>`),\n * `left`/`top` are translated (and unscaled) into that box's coordinates so `el`\n * still lands next to the anchor. This is\n * `popover()`'s placement core, usable on any element (an inline hint, a tooltip) —\n * no overlay lifecycle. Pair with {@link autoReposition} to keep it glued while open.\n */\nexport function positionAnchored(\n el: HTMLElement,\n anchor: Element,\n options: AnchorPositionOptions = {},\n): void {\n const { placement = 'bottom', align = 'start', gap = 4 } = options;\n // Fix `el` FIRST, then measure it. Measuring a still-`display:block` wrapper\n // reports the full body-content width (≈ viewport minus body margins), which\n // collapses the horizontal clamp below and lands the element at the body's left\n // edge. As a fixed, shrink-to-fit box its `width`/`height` are its real size.\n el.style.position = 'fixed';\n el.style.margin = '0';\n const anchorRect = anchor.getBoundingClientRect();\n const elementRect = el.getBoundingClientRect();\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n\n // Vertical: preferred side, flipped only if it overflows and the other side fits.\n const belowTop = anchorRect.bottom + gap;\n const aboveTop = anchorRect.top - gap - elementRect.height;\n let below = placement !== 'top';\n if (below && belowTop + elementRect.height > viewportHeight && aboveTop >= 0)\n below = false;\n else if (\n !below &&\n aboveTop < 0 &&\n belowTop + elementRect.height <= viewportHeight\n )\n below = true;\n\n // Horizontal: align to an anchor edge, then clamp into the viewport.\n let left =\n align === 'end' ? anchorRect.right - elementRect.width : anchorRect.left;\n left = Math.max(0, Math.min(left, viewportWidth - elementRect.width));\n\n // `left`/`top` so far are viewport coordinates. They are only the CSS values\n // too when `el`'s fixed-position containing block is the viewport; an\n // ancestor with a `transform`, `filter`, `perspective`, `contain`, … (say a\n // modal `<dialog>` holding an overlay host slot) captures fixed descendants,\n // so map the coordinates into that box's space.\n const [originX, originY, scaleX, scaleY] = fixedOrigin(el);\n el.style.left = `${(left - originX) / scaleX}px`;\n el.style.top = `${((below ? belowTop : aboveTop) - originY) / scaleY}px`;\n}\n\n/**\n * Where `left: 0; top: 0` actually lands for a fixed-position child of `el`'s\n * parent, plus that containing block's scale — `[x, y, scaleX, scaleY]`, which\n * is `[0, 0, 1, 1]` when the viewport is the containing block. Measured with a\n * 1px probe rather than `el` itself so `el`'s own transform or running entrance\n * animation cannot skew it. The probe is inserted and removed synchronously, so\n * it is never painted. Translation and scale are compensated; a rotated or\n * skewed containing block is not.\n */\nfunction fixedOrigin(el: HTMLElement): [number, number, number, number] {\n const parent = el.parentNode;\n if (!parent) return [0, 0, 1, 1];\n const probe = el.ownerDocument.createElement('div');\n probe.style.cssText =\n 'position:fixed;left:0;top:0;width:1px;height:1px;margin:0;padding:0;border:0';\n parent.insertBefore(probe, el);\n const rect = probe.getBoundingClientRect();\n probe.remove();\n // A zero size (a containing block mid `scale(0)` animation, or a DOM without\n // layout) would divide by zero; treat it as unscaled.\n return [rect.left, rect.top, rect.width || 1, rect.height || 1];\n}\n\n/**\n * Keep `el` positioned against `anchor` (via {@link positionAnchored}) as the page\n * scrolls or resizes. Positions once immediately, then re-runs on `scroll`\n * (capture phase — catches scrolls in any inner container, not just `window`) and\n * `resize`. Returns a disposer that removes the listeners.\n */\nexport function autoReposition(\n el: HTMLElement,\n anchor: Element,\n options: AnchorPositionOptions = {},\n): () => void {\n const reposition = (): void => positionAnchored(el, anchor, options);\n reposition();\n window.addEventListener('scroll', reposition, true);\n window.addEventListener('resize', reposition);\n return () => {\n window.removeEventListener('scroll', reposition, true);\n window.removeEventListener('resize', reposition);\n };\n}\n","/** Anchored popover lifecycle built on the shared overlay transaction. */\nimport { attach } from './attach.js';\nimport {\n type DismissTrigger,\n overlay,\n type OverlayContent,\n type OverlayHandle,\n overlayHost,\n} from './overlay-core.js';\nimport { autoReposition, type PopoverPlacement } from './overlay-position.js';\n\n/** Options for {@link popover}. */\nexport interface PopoverOptions {\n /**\n * Where to append the popover wrapper. Default: when `anchor` sits inside an\n * open modal `<dialog>`, that dialog's `[data-kerf-overlay-host]` element (a\n * dialog kerf opened gets one automatically), so the popover is part of the\n * modal subtree and stays interactive; otherwise `document.body`.\n */\n container?: Element;\n /** Class on the wrapper. Default `'kerf-popover'`. */\n className?: string;\n /** Preferred side of the anchor. Flips to the other side if it would overflow the viewport. Default `'bottom'`. */\n placement?: PopoverPlacement;\n /** Horizontal edge to line up with the anchor: `'start'` (left edges) or `'end'` (right edges). Default `'start'`. */\n align?: 'start' | 'end';\n /** Gap in px between the anchor and the popover. Default `4`. */\n gap?: number;\n /**\n * Which user actions dismiss the popover. Default `['outside']` (a click\n * outside the popover, the anchor exempt). Pass `false` to close only via `close()`.\n */\n dismiss?: DismissTrigger | DismissTrigger[] | false;\n /** Focus behavior on open. Default `false` (non-modal — leave focus alone). */\n initialFocus?: string | boolean;\n /** Extra elements (besides the anchor) whose clicks do NOT count as outside. */\n outsideIgnore?: Element | readonly Element[];\n /** Called on any user-initiated dismissal. */\n onDismiss?: () => void;\n /**\n * Host the popover in the browser top layer (the Popover API — `[popover]` +\n * `showPopover()`) where supported, so it stacks above any `z-index` without a\n * z-index war. Falls back to today's plain `<div>` where unsupported. kerf keeps\n * owning positioning + its own dismiss wiring; the popover is `popover=\"manual\"`.\n * See {@link OverlayOptions.native}. Default `false`.\n */\n native?: boolean;\n}\n\n/**\n * Anchored, non-modal overlay: positions `content` relative to `anchor` (below by\n * default, flipping above if it would overflow, and clamped horizontally to the\n * viewport) and repositions on scroll / resize while open. A thin wrapper over\n * {@link overlay} with non-modal defaults — `trap: false`, `dismiss: ['outside']`,\n * and the anchor added to `outsideIgnore` so the trigger click doesn't self-close.\n * Returns the same {@link OverlayHandle}; `close()` also drops the reposition\n * listeners. `position: fixed` is set inline (you style everything else).\n */\nexport function popover(\n anchor: Element,\n content: OverlayContent,\n options: PopoverOptions = {},\n): OverlayHandle {\n const {\n container,\n className = 'kerf-popover',\n placement = 'bottom',\n align = 'start',\n gap = 4,\n dismiss = ['outside'],\n initialFocus = false,\n outsideIgnore,\n onDismiss,\n native = false,\n } = options;\n\n const extraIgnore =\n outsideIgnore === undefined\n ? []\n : Array.isArray(outsideIgnore)\n ? [...outsideIgnore]\n : [outsideIgnore];\n\n const handle = overlay(content, {\n container: container ?? overlayHost(anchor),\n className,\n dismiss,\n trap: false,\n initialFocus,\n onDismiss,\n outsideIgnore: [anchor, ...extraIgnore],\n native,\n });\n\n // Position + keep it glued while open; drop the listeners on close. A throw\n // while positioning (e.g. an anchor whose geometry read fails) is still part\n // of construction: close the just-opened overlay before rethrowing.\n let stopReposition: () => void;\n try {\n stopReposition = autoReposition(handle.el, anchor, {\n placement,\n align,\n gap,\n });\n } catch (error) {\n handle.close();\n throw error;\n }\n void handle.result.then(stopReposition);\n\n // KF-BAVCEV: never outlive the anchor. When it leaves the document (e.g. the\n // modal holding it closes) close the popover as cleanup — not a user\n // dismissal, so no `onDismiss`. A move within the document keeps it open.\n void handle.result.then(attach(anchor, () => handle.close));\n\n return handle;\n}\n","/**\n * `toast()` for `kerfjs/overlay` — a non-modal, auto-dismissing notification that\n * stacks in a shared body-level region. Split out of `overlay.ts` (KF-513) since\n * it's a distinct transient-UI concern from the modal dialogs; re-exported from\n * `overlay.ts` so the public `kerfjs/overlay` surface is unchanged. Structural\n * only — kerf ships no CSS; you style the region / toast / animations.\n */\nimport { type SafeHtml } from './jsx-runtime.js';\nimport { mount, type MountResult } from './mount.js';\nimport { escapeHtml } from './utils/escapeHtml.js';\n\n/** Content for a {@link toast}: an escaped text string, trusted `SafeHtml`, or a render function. */\nexport type ToastContent = string | SafeHtml | (() => MountResult);\n\n/** Accent variant for a {@link toast} — mapped to a `${className}--${variant}` class. */\nexport type ToastVariant = 'info' | 'success' | 'warning';\n\n/** Options for {@link toast}. */\nexport interface ToastOptions {\n /** Where toasts stack. Default: a lazily-created `<div class=\"kerf-toasts\">` on `document.body`. */\n container?: Element;\n /** Class on the toast element. Default `'kerf-toast'`. */\n className?: string;\n /** Auto-dismiss after this many ms. `0` keeps it until dismissed by hand. Default `4000`. */\n duration?: number;\n /** ARIA role. Default `'status'`. */\n role?: string;\n /**\n * `'stack'` (default) shows toasts stacked in the region; `'replace'` dismisses\n * the region's current toast(s) first (collapse-to-latest for a rapid sequence).\n */\n mode?: 'stack' | 'replace';\n /**\n * How `mode: 'replace'` drops the prior toast(s): `'fade'` (default) runs their\n * full exit transition (nice for a STACKING region), or `'instant'` removes them\n * synchronously with no exit — what a single, exactly-centered toast slot wants,\n * so the outgoing and incoming messages never cross-fade in the same spot.\n */\n collapse?: 'fade' | 'instant';\n /** Accent variant — adds a `${className}--${variant}` class (kerf ships no CSS; you style it). */\n variant?: ToastVariant;\n /** Class added on the next animation frame after mount, so a CSS **entrance** transition can run. */\n enterClass?: string;\n /**\n * Class added when dismissing, so CSS owns the **exit**. On dismiss the\n * `enterClass` (if any) is also REMOVED, so `exitClass` doesn't have to\n * out-specify it — and a symmetric single-class fade (entrance = add\n * `enterClass`, exit = remove it) works by setting only `enterClass` +\n * `exitDuration`. The node is removed `exitDuration` ms later.\n */\n exitClass?: string;\n /** ms to wait before removing the node on dismiss — applies when `exitClass` is set OR when it's > 0 (to let a removed `enterClass` transition out). Default `0`. */\n exitDuration?: number;\n}\n\n/** Handle returned by {@link toast}. */\nexport interface ToastHandle {\n /** The toast element — inspect it, or run your own entrance/exit transitions. */\n el: HTMLElement;\n /**\n * Dismiss it early. Default runs the `exitClass` transition (removed after\n * `exitDuration`); pass `{ instant: true }` to remove it **synchronously** with\n * no exit — for an action button that immediately shows a replacement toast in a\n * single centered slot (no cross-fade). Idempotent.\n */\n dismiss(options?: { instant?: boolean }): void;\n}\n\n/** The region's active toasts live on the region element (in the DOM), not in module state. */\nconst TOAST_SET = Symbol('kerf.toasts');\n/** A dismiss function with an `.removeNow()` for instant (no-exit) teardown. */\ntype Dismisser = (() => void) & { removeNow: () => void };\ntype ToastCarrier = Element & { [TOAST_SET]?: Set<Dismisser> };\n\n/** The singleton toast region lives in the DOM (queried, not held in a module variable). */\nfunction toastRegion(container?: Element): Element {\n if (container !== undefined) return container;\n const existing = document.querySelector('.kerf-toasts');\n if (existing !== null) return existing;\n const region = document.createElement('div');\n region.className = 'kerf-toasts';\n region.setAttribute('aria-live', 'polite');\n document.body.appendChild(region);\n return region;\n}\n\n/**\n * Show a non-modal, auto-dismissing notification. Stacks in a shared body-level\n * region (or your `container`). Returns a {@link ToastHandle} (`{ el, dismiss }`)\n * so you can run entrance/exit transitions, wire an action button, or inspect the\n * node. `mode: 'replace'` collapses a rapid sequence to the latest; `variant`\n * adds an accent class; `enterClass`/`exitClass` let CSS own the animation.\n */\nexport function toast(\n content: ToastContent,\n options: ToastOptions = {},\n): ToastHandle {\n const {\n container,\n className = 'kerf-toast',\n duration = 4000,\n role = 'status',\n mode = 'stack',\n collapse = 'fade',\n variant,\n enterClass,\n exitClass,\n exitDuration = 0,\n } = options;\n\n const region = toastRegion(container) as ToastCarrier;\n const active = (region[TOAST_SET] ??= new Set<Dismisser>());\n // collapse-to-latest: 'instant' removes priors synchronously (no cross-fade in a\n // centered single slot); 'fade' runs their exit transition (nice for a stack).\n if (mode === 'replace') {\n for (const d of [...active]) {\n if (collapse === 'instant') d.removeNow();\n else d();\n }\n }\n\n const el = document.createElement('div');\n el.className = className;\n if (variant !== undefined) el.classList.add(`${className}--${variant}`);\n el.setAttribute('role', role);\n region.appendChild(el);\n\n const render =\n typeof content === 'function'\n ? content\n : () => (typeof content === 'string' ? escapeHtml(content) : content);\n const disposeMount = mount(el, render);\n const state: {\n dismissed: boolean;\n removed: boolean;\n timer: ReturnType<typeof setTimeout> | undefined;\n exitTimer: ReturnType<typeof setTimeout> | undefined;\n } = {\n dismissed: false,\n removed: false,\n timer: undefined,\n exitTimer: undefined,\n };\n\n if (enterClass !== undefined) {\n globalThis.requestAnimationFrame(() => {\n if (!state.dismissed) el.classList.add(enterClass);\n });\n }\n\n const remove = (): void => {\n if (state.removed) return;\n state.removed = true;\n state.dismissed = true; // once removed, a later dismiss() is a clean no-op\n if (state.exitTimer !== undefined) clearTimeout(state.exitTimer);\n disposeMount();\n el.remove();\n active.delete(dismiss as Dismisser);\n };\n\n // Force synchronous teardown NOW, with no exit transition — even if a fade is\n // already in flight (so `mode:'replace'` collapse can clean up a mid-exit toast,\n // and `dismiss({ instant: true })` drops it immediately).\n const removeNow = (): void => {\n if (state.timer !== undefined) clearTimeout(state.timer);\n remove();\n };\n\n const fadeOut = (): void => {\n if (state.dismissed) return;\n state.dismissed = true;\n if (state.timer !== undefined) clearTimeout(state.timer);\n // Reverse the entrance (drop enterClass so exitClass needn't out-specify it),\n // add exitClass, and delay removal for the transition — including the\n // single-class idiom (enterClass removed + exitDuration, no exitClass).\n if (enterClass !== undefined) el.classList.remove(enterClass);\n if (exitClass !== undefined) el.classList.add(exitClass);\n if (exitClass !== undefined || exitDuration > 0) {\n state.exitTimer = setTimeout(remove, exitDuration);\n } else {\n remove();\n }\n };\n\n function dismiss(options?: { instant?: boolean }): void {\n if (options?.instant === true) removeNow();\n else fadeOut();\n }\n (dismiss as Dismisser).removeNow = removeNow;\n\n active.add(dismiss as Dismisser);\n if (duration > 0) state.timer = setTimeout(fadeOut, duration);\n return { el, dismiss };\n}\n","/** Hover and focus tooltip lifecycle built on the shared overlay transaction. */\nimport { attach } from './attach.js';\nimport { jsx, type SafeHtml } from './jsx-runtime.js';\nimport type { MountResult } from './mount.js';\nimport {\n overlay,\n type OverlayContent,\n type OverlayHandle,\n overlayHost,\n} from './overlay-core.js';\nimport {\n type AnchorPositionOptions,\n autoReposition,\n} from './overlay-position.js';\n\n/** Content for a {@link tooltip}: text (auto-escaped), `SafeHtml`, or a render function. */\nexport type TooltipContent = string | SafeHtml | (() => MountResult);\n\n/** Options for {@link tooltip}. */\nexport interface TooltipOptions extends AnchorPositionOptions {\n /** Where to append the tooltip wrapper. Default: the anchor's modal-dialog host slot (see {@link PopoverOptions.container}), else `document.body`. */\n container?: Element;\n /** Class on the wrapper. Default `'kerf-tooltip'`. */\n className?: string;\n /** Delay in ms before showing after hover/focus enters. Default `400`. */\n delay?: number;\n /** Delay in ms before hiding after hover/focus leaves. Default `100`. */\n hideDelay?: number;\n /** ARIA role on the wrapper. Default `'tooltip'`. */\n role?: string;\n /** Host the tooltip in the browser top layer (the Popover API) where supported. See {@link OverlayOptions.native}. Default `false`. */\n native?: boolean;\n}\n\n/**\n * A hover/focus-triggered, non-modal, auto-hiding tooltip anchored to `anchor`.\n * Shows after `delay` on `pointerenter`/`focus`, hides after `hideDelay` on\n * `pointerleave`/`blur`, and positions itself with {@link autoReposition} (above\n * the anchor by default). Unlike {@link popover} there is no click-dismiss model —\n * it follows the pointer/focus. Returns a disposer that removes the anchor\n * listeners and hides any shown tooltip. Structural only (kerf ships no CSS).\n */\nexport function tooltip(\n anchor: Element,\n content: TooltipContent,\n options: TooltipOptions = {},\n): () => void {\n const {\n container,\n className = 'kerf-tooltip',\n delay = 400,\n hideDelay = 100,\n role = 'tooltip',\n placement = 'top',\n align = 'start',\n gap = 4,\n native = false,\n } = options;\n\n const body: OverlayContent =\n typeof content === 'function'\n ? content\n : typeof content === 'string'\n ? jsx('span', { class: `${className}__text`, children: content })\n : content;\n\n const timers: {\n show?: ReturnType<typeof setTimeout>;\n hide?: ReturnType<typeof setTimeout>;\n } = {};\n let current:\n | { handle: OverlayHandle; stop: () => void; unwatch: () => void }\n | undefined;\n let presence = 0;\n\n // Runs from the `delay` timer, so there is no caller to throw to. A failed\n // show (a throwing render fn, `native` `showPopover()`, or positioning) is\n // rolled back before `current` is set — nothing stays on screen and the\n // next pointerenter / focus schedules a fresh attempt — and the original\n // error then escapes the timer callback for the host to report as uncaught\n // (a window `error` event in browsers), the same way kerf's other deferred\n // callbacks (debounce / throttle timers, attach teardown) surface errors.\n function show(): void {\n // The anchor left the document while the show was pending (KF-BAVCEV).\n if (!anchor.isConnected) return;\n const handle = overlay(body, {\n container: container ?? overlayHost(anchor),\n className,\n dismiss: false,\n trap: false,\n initialFocus: false,\n native,\n });\n handle.el.setAttribute('role', role);\n let stop: () => void;\n try {\n stop = autoReposition(handle.el, anchor, { placement, align, gap });\n } catch (error) {\n // Not yet tracked in `current`, so `hide()` could never reach it.\n handle.close();\n throw error;\n }\n // KF-BAVCEV: an anchor removed from the document (e.g. with the modal that\n // held it) fires no pointerleave / blur, so hide when it leaves and forget\n // its presence; a move within the document keeps the tooltip shown.\n const unwatch = attach(anchor, () => () => {\n presence = 0;\n if (timers.hide !== undefined) clearTimeout(timers.hide);\n hide();\n });\n current = { handle, stop, unwatch };\n // A surface that closed itself (its host slot left the document with the\n // dialog) must not stay `current`, or the next hover would never show.\n void handle.result.then(() => {\n if (current?.handle === handle) hide();\n });\n }\n\n function hide(): void {\n const shown = current;\n if (shown === undefined) return;\n // Cleared first: `unwatch()` runs the anchor teardown, which re-enters here.\n current = undefined;\n shown.unwatch();\n shown.stop();\n shown.handle.close();\n }\n\n const onEnter = (event: Event): void => {\n presence |= event.type === 'focus' ? 2 : 1;\n if (timers.hide !== undefined) clearTimeout(timers.hide);\n if (current !== undefined) return;\n if (timers.show !== undefined) clearTimeout(timers.show); // debounce: one pending show at a time\n timers.show = setTimeout(show, delay);\n };\n const onLeave = (event: Event): void => {\n presence &= event.type === 'blur' ? ~2 : ~1;\n if (presence) return;\n if (timers.show !== undefined) clearTimeout(timers.show);\n if (current === undefined) return;\n timers.hide = setTimeout(hide, hideDelay);\n };\n\n anchor.addEventListener('pointerenter', onEnter);\n anchor.addEventListener('pointerleave', onLeave);\n anchor.addEventListener('focus', onEnter);\n anchor.addEventListener('blur', onLeave);\n\n return () => {\n anchor.removeEventListener('pointerenter', onEnter);\n anchor.removeEventListener('pointerleave', onLeave);\n anchor.removeEventListener('focus', onEnter);\n anchor.removeEventListener('blur', onLeave);\n if (timers.show !== undefined) clearTimeout(timers.show);\n if (timers.hide !== undefined) clearTimeout(timers.hide);\n hide();\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/overlay-core.ts","../src/overlay-choice.ts","../src/overlay-confirm.ts","../src/overlay-prompt.ts","../src/overlay-form.ts","../src/overlay-position.ts","../src/overlay-popover.ts","../src/overlay-toast.ts","../src/overlay-tooltip.ts"],"names":["options"],"mappings":"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","file":"overlay.js","sourcesContent":["/**\n * Shared overlay lifecycle and document arbitration implementation.\n *\n * Every real kerf app hand-rolls this: `toElement → body.appendChild → mount →\n * wire dismissal → remove`, plus the fiddly parts (Escape, backdrop / outside\n * click, focus trap, restoring focus on close). `window.confirm` is a no-op in\n * Tauri WKWebViews, so a hand-built overlay is mandatory there. This subpath\n * blesses the pattern through `overlay()`, with anchored surfaces and dialog\n * helpers building on it. No per-instance framework state: each call owns its\n * DOM + listeners in a closure and returns a handle.\n *\n * import { overlay, confirm, toast } from 'kerfjs/overlay';\n *\n * const ok = await confirm('Delete this file?', { danger: true });\n * toast('Saved');\n * const dialog = overlay(<Settings />, { dismiss: ['escape', 'backdrop'] });\n * // …later: dialog.close(); or await dialog.result;\n *\n * Structural only — kerf ships no CSS. The wrapper gets your `className`; style\n * the backdrop / centering / animation yourself.\n */\nimport { attach } from './attach.js';\nimport { devHooks } from './dev-hooks.js';\nimport type { SafeHtml } from './jsx-runtime.js';\nimport { mount, type MountResult } from './mount.js';\nimport { OVERLAY_HOST_SELECTOR } from './utils/overlay-host.js';\n\n/** A user-initiated dismissal trigger. */\nexport type DismissTrigger = 'escape' | 'backdrop' | 'outside';\n\n/** Content for an overlay: static `SafeHtml`, or a render function `mount()` drives reactively. */\nexport type OverlayContent = SafeHtml | (() => MountResult);\n\n/** Options for {@link overlay}. */\nexport interface OverlayOptions {\n /**\n * Where to append the overlay wrapper. Default `document.body`. A container\n * inside an open modal `<dialog>` (including one slotted into a shadow-root\n * modal such as Web Awesome's `wa-dialog`) is already interactive, so the\n * surface is not lifted, and it closes when that dialog closes.\n */\n container?: Element;\n /** Class on the wrapper element (you style it — kerf ships no CSS). Default `'kerf-overlay'`. */\n className?: string;\n /**\n * Which user actions dismiss the overlay. Default `['escape', 'backdrop']`.\n * `'backdrop'` = a click on the wrapper itself (not its content); `'outside'`\n * = a click anywhere outside the wrapper (for anchored popovers). `false`\n * disables user dismissal (close it programmatically).\n */\n dismiss?: DismissTrigger | DismissTrigger[] | false;\n /**\n * Where focus lands on open: a selector, `true` (first focusable element, or\n * the wrapper if none), or `false` (leave focus alone). Default `true`.\n */\n initialFocus?: string | boolean;\n /**\n * Trap Tab / Shift+Tab within the overlay while open and mark it\n * `role=\"dialog\"` / `aria-modal=\"true\"`. Default `true`. Set `false` for a\n * non-modal popover.\n */\n trap?: boolean;\n /** ARIA role for the wrapper when `trap` is on. Default `'dialog'`. */\n role?: string;\n /** Called on any user-initiated dismissal (before `close()` runs). */\n onDismiss?: () => void;\n /** For `'outside'` dismissal: clicks on these elements do NOT count as outside (e.g. the trigger button). */\n outsideIgnore?: Element | readonly Element[];\n /**\n * Opt into the browser **top layer** (`docs/19-native-overlay-backing.md`).\n * When `true` and the engine supports it, a modal overlay (`trap: true`) is\n * hosted in a `<dialog>` opened with `.showModal()` — real inerting of the rest\n * of the document + guaranteed stacking above any `z-index` — and a non-modal\n * one (`trap: false`) uses the Popover API (`[popover]` + `showPopover()`).\n * Feature-detected; falls back to today's plain `<div>` where unsupported.\n *\n * The `render` slot + promise API are unchanged — kerf just hosts your markup\n * in a `<dialog>` / `[popover]` instead of a `<div>`. Two caveats: native\n * `<dialog>` / `[popover]` carry **UA default styles** (a `::backdrop`,\n * centering, border, padding) that kerf does not reset — style the element (and\n * its `::backdrop`) via `className`; and `container` is effectively a **no-op**\n * for visual position, since the top layer ignores where the element lives in\n * the DOM. Default `false`.\n */\n native?: boolean;\n}\n\n/** Handle returned by {@link overlay}. Holds no framework state — it's a closure. */\nexport interface OverlayHandle {\n /** The wrapper element (mounted into, appended to `container`). */\n el: HTMLElement;\n /** Tear down: dispose the mount, remove listeners + the node, restore focus, resolve `result`. Idempotent. */\n close(result?: unknown): void;\n /** Resolves with the value passed to `close()` (or `undefined` on user dismissal). */\n result: Promise<unknown>;\n}\n\nconst FOCUSABLE =\n 'a[href],area[href],button:not([disabled]),input:not([disabled]),' +\n 'select:not([disabled]),textarea:not([disabled]),iframe,' +\n '[tabindex]:not([tabindex=\"-1\"]),[contenteditable=\"true\"]';\n\nfunction focusable(root: Element): HTMLElement[] {\n const items = Array.from(\n root.querySelectorAll<HTMLElement>(FOCUSABLE),\n ).filter((el) => !el.hasAttribute('hidden') && el.tabIndex >= 0);\n // WebKit on macOS follows the system's keyboard-navigation preference and\n // may omit implicitly tabbable controls from sequential focus navigation.\n // A focus trap promises stable traversal through every eligible control, so\n // make those implicit stops explicit while preserving authored tabindexes.\n for (const el of items) if (!el.hasAttribute('tabindex')) el.tabIndex = 0;\n return items;\n}\n\n// Native top-layer feature detection (KF-526). Modal → `<dialog>.showModal()`;\n// non-modal → the Popover API. Each is independent — an engine may ship one\n// without the other — and both fall back to the plain `<div>` where absent.\nfunction supportsDialog(): boolean {\n return (\n typeof HTMLDialogElement !== 'undefined' &&\n typeof HTMLDialogElement.prototype.showModal === 'function'\n );\n}\nfunction supportsPopover(): boolean {\n return (\n typeof HTMLElement !== 'undefined' &&\n typeof HTMLElement.prototype.showPopover === 'function'\n );\n}\n\n// Stacked-surface arbitration (KF-CW7GJ8: a tooltip inside a modal used to\n// become \"topmost\" and disable the modal's Escape, backdrop, and focus trap).\n// Every open overlay — native or fallback — is recorded, in open order, on a\n// per-document stack. An input kind (Escape, a backdrop / outside click, Tab\n// for the trap) belongs to the topmost surface that HANDLES that kind; a\n// surface that doesn't handle it is transparent, except that a modal surface\n// is a barrier nothing beneath it sees past. A tooltip (or any overlay with no\n// dismiss trigger and no trap) handles nothing, so it never intercepts. The\n// `handled` set marks an event a surface already acted on, so one click that is\n// both \"outside\" a popover and on the modal backdrop closes only the popover.\nconst OVERLAY_ARBITRATION = Symbol('kerf.overlayArbitration');\n\n/** An arbitration input: a dismiss trigger, or Tab for the focus trap. */\ntype ArbitrationKind = DismissTrigger | 'trap';\n\ninterface OverlaySurface {\n el: HTMLElement;\n triggers: readonly DismissTrigger[];\n modal: boolean;\n /** Where focus returns on close; re-pointed when the surface holding it closes first. */\n restoreTo: Element | null;\n /** Non-modal only: move (or re-show) into the top layer above a newly opened modal `<dialog>`. */\n liftAbove?: () => void;\n}\n\ninterface OverlayArbitration {\n stack: OverlaySurface[];\n handled: WeakSet<Event>;\n /** Document capture listener, installed only while the stack is non-empty. */\n onToggle: (event: Event) => void;\n /** Open shadow roots carrying `onToggle` too (a shadow `toggle` never reaches the document). */\n shadowRoots: Set<ShadowRoot>;\n}\n\ntype ArbitratedDocument = Document & {\n [OVERLAY_ARBITRATION]?: OverlayArbitration;\n};\n\nfunction overlayArbitration(doc: Document): OverlayArbitration {\n const arbitrated = doc as ArbitratedDocument;\n return (arbitrated[OVERLAY_ARBITRATION] ??= {\n stack: [],\n handled: new WeakSet(),\n // KF-AHY6H4: an app-owned modal `<dialog>` opened outside kerf would leave\n // the kerf surfaces already showing inert beneath it. A dialog fires\n // `toggle` after it opens (it does not bubble, so listen in the capture\n // phase); re-host above it exactly as kerf does for its own dialogs, which\n // are skipped here because `overlay()` already re-hosted synchronously.\n onToggle: (event) => {\n const dialog = event.target as Element;\n const arbitration = arbitrated[OVERLAY_ARBITRATION] as OverlayArbitration;\n if (\n dialog.tagName === 'DIALOG' &&\n !arbitration.stack.some(({ el }) => el === dialog) &&\n isOpenModal(dialog, arbitration)\n )\n rehostAbove(arbitration, dialog);\n },\n shadowRoots: new Set(),\n });\n}\n\n// Every open shadow root in `root`, nested ones included (KF-1FGTX1: Web\n// Awesome's `wa-dialog` / `wa-drawer` keep their modal `<dialog>` in one, where\n// neither `querySelectorAll` nor a document `toggle` listener can see it). A\n// closed shadow root is invisible by design. One element walk per `overlay()`\n// open — a user-paced event — so the cost stays off every render path.\nfunction openShadowRoots(\n root: Document | ShadowRoot,\n found: ShadowRoot[] = [],\n): ShadowRoot[] {\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);\n for (let node = walker.nextNode(); node !== null; node = walker.nextNode()) {\n const shadow = (node as Element).shadowRoot;\n if (shadow !== null) {\n found.push(shadow);\n openShadowRoots(shadow, found);\n }\n }\n return found;\n}\n\n// Install the `toggle` watch on every open shadow root not yet watched, so an\n// app-owned modal `<dialog>` opening inside one re-hosts the surfaces showing.\nfunction watchShadowRoots(\n arbitration: OverlayArbitration,\n roots: readonly ShadowRoot[],\n): void {\n for (const root of roots)\n if (!arbitration.shadowRoots.has(root)) {\n arbitration.shadowRoots.add(root);\n root.addEventListener('toggle', arbitration.onToggle, true);\n }\n}\n\n// Is `el` inside `dialog` in the flat tree — the rendered tree, where content\n// slotted into a shadow host renders inside the host's shadow `<dialog>`?\nfunction renderedInside(el: Element, dialog: Element): boolean {\n for (let node: Element | null = el; node !== null;) {\n if (node === dialog) return true;\n const root = node.getRootNode();\n node =\n node.assignedSlot ??\n node.parentElement ??\n (root instanceof ShadowRoot ? root.host : null);\n }\n return false;\n}\n\n// Every non-modal kerf surface already open is blocked beneath a modal\n// `<dialog>` that just opened: lift (or re-show) it above (KF-FJ9VD8). One\n// rendered inside that dialog — including a slot-hosted one in a shadow\n// host's light DOM — is part of its subtree already.\nfunction rehostAbove(arbitration: OverlayArbitration, dialog: Element): void {\n for (const { el, liftAbove } of arbitration.stack)\n if (el !== dialog && el.isConnected && !renderedInside(el, dialog))\n liftAbove?.();\n}\n\n// Is `dialog` an open modal `<dialog>`? kerf's own are known from the stack;\n// an app-owned one is found through `:modal`, which an older engine may not\n// parse (then only kerf's own count).\nfunction isOpenModal(\n dialog: Element,\n arbitration: OverlayArbitration,\n): boolean {\n if (!dialog.isConnected || (dialog as HTMLDialogElement).open !== true)\n return false;\n if (arbitration.stack.some(({ el, modal }) => modal && el === dialog))\n return true;\n try {\n return dialog.matches(':modal');\n } catch {\n return false; // `:modal` unsupported\n }\n}\n\n// Is a modal `<dialog>` open (KF-0V9RTE: a plain surface opened in that state\n// is inert and painted beneath the dialog's top layer)?\n// The open shadow roots count too (KF-1FGTX1: a `wa-dialog`'s modal).\nfunction modalDialogOpen(\n doc: Document,\n arbitration: OverlayArbitration,\n shadowRoots: readonly ShadowRoot[],\n): boolean {\n return (\n arbitration.stack.some(({ el }) => isOpenModal(el, arbitration)) ||\n [doc, ...shadowRoots].some((root) =>\n Array.from(root.querySelectorAll('dialog[open]')).some((dialog) =>\n isOpenModal(dialog, arbitration),\n ),\n )\n );\n}\n\n// The modal context `el` renders in, resolved across shadow boundaries\n// (KF-F52T5D: Web Awesome's `wa-dialog` / `wa-drawer` keep their modal\n// `<dialog>` in a shadow root, so `closest('dialog')` from slotted light-DOM\n// content found nothing and the surface landed, inert, in `document.body`).\n// Walks the light-DOM ancestors, continuing from a shadow tree to its host.\n// The nearest `<dialog>` decides, as before; so does a shadow host whose slot\n// for the walked-from child sits inside a `<dialog>` in its shadow root. Only\n// an OPEN MODAL dialog yields a context: `dialog` is that element, `root` the\n// light-DOM element a host slot belongs in — the dialog itself, or the shadow\n// host (content appended to it is slotted into the dialog).\ninterface ModalContext {\n dialog: Element;\n root: Element;\n}\nfunction modalContext(\n el: Element,\n arbitration: OverlayArbitration,\n): ModalContext | undefined {\n let child: Element | undefined;\n for (let node: Element | null = el; node !== null;) {\n const dialog =\n node.localName === 'dialog'\n ? node\n : child?.assignedSlot?.closest('dialog');\n if (dialog != null)\n return isOpenModal(dialog, arbitration)\n ? { dialog, root: node }\n : undefined;\n child = node;\n const root = node.getRootNode();\n node =\n node.parentElement ?? (root instanceof ShadowRoot ? root.host : null);\n }\n return undefined;\n}\n\n// The in-dialog host slot (KF-FBHQEP: a surface lifted over a modal\n// `<dialog>` is visible but inert, because every engine inerts content outside\n// the modal). A `popover()` / `tooltip()` whose anchor renders inside an open\n// modal `<dialog>` (see `modalContext`) renders into that context's\n// `[data-kerf-overlay-host]` element instead, so it is part of the modal\n// subtree and fully interactive. An app-owned native dialog opts in by marking\n// an element; a dialog kerf opened itself, and a shadow-hosted modal (whose\n// author cannot reach inside the shadow root), get one on demand —\n// `display: contents` so it adds no layout box, and `data-morph-skip` +\n// `data-morph-preserve` so the content's own `mount()` neither re-renders nor\n// removes it (`utils/overlay-host.ts` makes the slot a nested-mount boundary).\nexport function overlayHost(anchor: Element): Element | undefined {\n const arbitration = overlayArbitration(document);\n const context = modalContext(anchor, arbitration);\n if (context === undefined) return undefined;\n const { dialog, root } = context;\n let host = Array.from(root.querySelectorAll(OVERLAY_HOST_SELECTOR)).find(\n (el) => modalContext(el, arbitration)?.root === root,\n );\n if (\n host === undefined &&\n (root !== dialog || arbitration.stack.some(({ el }) => el === dialog))\n ) {\n root.insertAdjacentHTML(\n 'beforeend',\n '<div data-kerf-overlay-host data-morph-skip data-morph-preserve style=\"display:contents\"></div>',\n );\n host = root.lastElementChild as Element;\n }\n return host;\n}\n\n// `self` is on the stack and handles `kind` (its callers are exactly the\n// handlers it installed for that kind), so it owns `kind` unless some surface\n// above it handles `kind` too or is modal.\nfunction ownsInput(\n stack: readonly OverlaySurface[],\n self: OverlaySurface,\n kind: ArbitrationKind,\n): boolean {\n for (let i = stack.indexOf(self) + 1; i < stack.length; i++) {\n const above = stack[i];\n if (above.modal || (kind !== 'trap' && above.triggers.includes(kind)))\n return false;\n }\n return true;\n}\n\n// Validate a string `initialFocus` BEFORE any DOM mutation: `querySelector`\n// throws a generic `SyntaxError` DOMException on a malformed selector, and the\n// focus pass runs last — after the wrapper, mount, listeners, and stack entry\n// already exist — so an unvalidated selector would strand all of them with no\n// handle to close. An inert fragment parses the selector without matching.\nfunction assertInitialFocusSelector(selector: string): void {\n try {\n document.createDocumentFragment().querySelector(selector);\n } catch (cause) {\n throw new Error(\n `overlay(): invalid initialFocus selector ${JSON.stringify(selector)}`,\n { cause },\n );\n }\n}\n\n/**\n * Open an overlay: append a wrapper to `container`, `mount()` `content` inside\n * it, wire the requested dismissals + (optionally) a focus trap, and return a\n * handle. Concurrent fallback overlays dismiss from the top down. See\n * {@link OverlayOptions}.\n *\n * Construction is transactional: a malformed `initialFocus` selector throws a\n * descriptive error before anything is touched, and if a later setup phase\n * throws (the content's first render, `showModal()` / `showPopover()`), every\n * piece already installed — wrapper node, mount, listeners, fallback-stack\n * entry, top-layer state, moved focus — is rolled back before the original\n * error is rethrown.\n */\nexport function overlay(\n content: OverlayContent,\n options: OverlayOptions = {},\n): OverlayHandle {\n const {\n container = document.body,\n className = 'kerf-overlay',\n dismiss = ['escape', 'backdrop'],\n initialFocus = true,\n trap = true,\n role = 'dialog',\n onDismiss,\n outsideIgnore,\n native = false,\n } = options;\n\n if (typeof initialFocus === 'string')\n assertInitialFocusSelector(initialFocus);\n\n const triggers: readonly DismissTrigger[] =\n dismiss === false ? [] : Array.isArray(dismiss) ? dismiss : [dismiss];\n\n // Native top-layer backing (KF-526), feature-detected: a modal overlay\n // (`trap`) → `<dialog>.showModal()`; a non-modal one → `[popover]`. Each falls\n // back to the plain `<div>` where the API is missing, so behavior is unchanged\n // on unsupporting engines. A surface opened while a modal `<dialog>` is open\n // is lifted the same way even without `native` (KF-0V9RTE), because a plain\n // `<div>` would be inert and painted beneath the dialog.\n const arbitration = overlayArbitration(document);\n // A surface placed inside an open modal `<dialog>` (its host slot, or an\n // explicit `container` there, including one slotted into a shadow-root\n // modal) is already part of the modal subtree: no lift.\n const containerContext = modalContext(container, arbitration);\n const shadowRoots = openShadowRoots(document);\n const liftOverModal =\n !native &&\n containerContext === undefined &&\n modalDialogOpen(document, arbitration, shadowRoots);\n const topLayer = native || liftOverModal;\n const useDialog = topLayer && trap && supportsDialog();\n const usePopover = topLayer && !trap && supportsPopover();\n\n const wrapper: HTMLElement = useDialog\n ? document.createElement('dialog')\n : document.createElement('div');\n wrapper.className = className;\n if (usePopover) wrapper.setAttribute('popover', 'manual');\n // `<dialog>.showModal()` conveys modality natively (role + inert), so the ARIA\n // attributes are only needed on the plain-`<div>` fallback.\n if (trap && !useDialog) {\n wrapper.setAttribute('role', role);\n wrapper.setAttribute('aria-modal', 'true');\n }\n const surface: OverlaySurface = {\n el: wrapper,\n triggers,\n modal: trap,\n restoreTo: document.activeElement,\n };\n\n // Does this surface own `kind` right now (and has no surface acted on `event`)?\n const owns = (kind: ArbitrationKind, event?: Event): boolean =>\n !(event !== undefined && arbitration.handled.has(event)) &&\n ownsInput(arbitration.stack, surface, kind);\n\n const removers: Array<() => void> = [];\n const resultBox: { resolve?: (value: unknown) => void } = {};\n const result = new Promise<unknown>((resolve) => {\n resultBox.resolve = resolve;\n });\n const state = { closed: false };\n let disposeMount: (() => void) | undefined;\n let nativeOpened = false;\n\n // KF-FJ9VD8: a modal `<dialog>` kerf opens later would leave this non-modal\n // surface inert beneath it, so the opener calls this to move it into the top\n // layer — or, if it is already a `[popover]`, re-show it so it stacks above\n // the new dialog (the top layer orders by most recent show).\n if (!trap)\n surface.liftAbove = () => {\n if (!supportsPopover()) {\n devHooks.overlayBlockedByModal?.('hidden');\n return;\n }\n const el = wrapper as HTMLElement & {\n showPopover(): void;\n hidePopover(): void;\n };\n if (nativeOpened) el.hidePopover();\n else {\n wrapper.setAttribute('popover', 'manual');\n wrapper.style.inset = 'auto';\n }\n el.showPopover();\n nativeOpened = true;\n if (wrapper.querySelector(FOCUSABLE) !== null)\n devHooks.overlayBlockedByModal?.('inert');\n };\n\n // Also the construction rollback (see the transaction below): every step\n // tolerates a phase that never ran — no mount yet, no stack entry, never\n // appended, never shown.\n function close(value?: unknown): void {\n if (state.closed) return;\n state.closed = true;\n const { stack } = arbitration;\n const stackIndex = stack.indexOf(surface);\n if (stackIndex !== -1) stack.splice(stackIndex, 1);\n if (stack.length === 0) {\n document.removeEventListener('toggle', arbitration.onToggle, true);\n for (const root of arbitration.shadowRoots)\n root.removeEventListener('toggle', arbitration.onToggle, true);\n arbitration.shadowRoots.clear();\n }\n // A surface opened from inside this one would restore focus into a node\n // that is about to be detached: hand it this surface's own restore target.\n for (const other of stack)\n if (other.restoreTo !== null && wrapper.contains(other.restoreTo))\n other.restoreTo = surface.restoreTo;\n const active = document.activeElement;\n for (const remove of removers) remove();\n disposeMount?.();\n // Exit the top layer before removing the node, so the native close steps run\n // (restore inert, fire the dialog's `close`). `<dialog>` also restores focus\n // itself; kerf's manual restore below stays as the fallback path's behavior.\n if (nativeOpened) {\n nativeOpened = false;\n if (useDialog) (wrapper as HTMLDialogElement).close();\n else (wrapper as HTMLElement & { hidePopover(): void }).hidePopover();\n }\n wrapper.remove();\n restoreFocus(active);\n resultBox.resolve?.(value);\n }\n\n // Closing a surface that doesn't hold focus (an out-of-order close beneath\n // another open surface) must not pull focus out of the surface that does;\n // otherwise focus returns to where it was when this surface opened.\n function restoreFocus(active: Element | null): void {\n if (\n active instanceof HTMLElement &&\n active.isConnected &&\n arbitration.stack.some((other) => other.el.contains(active))\n ) {\n if (document.activeElement !== active) active.focus();\n return;\n }\n const { restoreTo } = surface;\n if (restoreTo instanceof HTMLElement && restoreTo.isConnected)\n restoreTo.focus();\n }\n\n function userDismiss(): void {\n onDismiss?.();\n close();\n }\n\n // One transaction: if any phase below throws (the content's first render,\n // `showModal()` / `showPopover()`, …), roll back whatever the earlier phases\n // installed via `close()` and rethrow the original error. No handle is\n // returned on failure, so nothing may outlive the call.\n try {\n container.appendChild(wrapper);\n disposeMount = mount(\n wrapper,\n typeof content === 'function' ? content : () => content,\n );\n // Watch for app-owned modal dialogs while any kerf surface is open.\n // Shadow roots are refreshed on every open; one attached after the latest\n // open is not watched until the next.\n if (arbitration.stack.push(surface) === 1)\n document.addEventListener('toggle', arbitration.onToggle, true);\n watchShadowRoots(arbitration, shadowRoots);\n\n // Enter the top layer after the content is mounted + connected.\n // `showModal()` moves focus into the dialog by default; kerf's\n // `initialFocus` pass below runs afterward and wins.\n if (useDialog) {\n (wrapper as HTMLDialogElement).showModal();\n nativeOpened = true;\n rehostAbove(arbitration, wrapper);\n } else if (usePopover) {\n (wrapper as HTMLElement & { showPopover(): void }).showPopover();\n nativeOpened = true;\n // Neutralize the UA `[popover] { inset: 0; margin: auto }` anchoring so\n // `positionAnchored` (which sets `top`/`left`) controls placement —\n // otherwise the retained `right`/`bottom` insets would stretch/center it.\n wrapper.style.inset = 'auto';\n }\n\n installDismissal();\n if (container.closest(OVERLAY_HOST_SELECTOR) !== null) {\n makeTabReachable();\n // KF-WZ9KQM: a slot-hosted surface leaves with its dialog even when its\n // anchor (moved out of the dialog) stays connected, so the anchor watch\n // never fires. Watch the wrapper itself: close as cleanup (no\n // `onDismiss`) and leave the open-order stack.\n removers.push(attach(wrapper, () => close));\n }\n // KF-F52T5D: a surface inside a modal context leaves when that dialog\n // closes, as cleanup (no `onDismiss`). Closing an app-owned or\n // shadow-hosted dialog removes nothing, and a shadow dialog's `close`\n // never reaches a light-DOM listener, so a caller could not watch it.\n if (containerContext !== undefined) {\n const { dialog } = containerContext;\n const onDialogClose = (): void => close();\n dialog.addEventListener('close', onDialogClose);\n removers.push(() => dialog.removeEventListener('close', onDialogClose));\n }\n applyInitialFocus();\n } catch (error) {\n close();\n throw error;\n }\n\n // What the lift cannot repair: no top-layer API at all, or a lifted\n // non-modal surface whose controls the modal still inerts.\n if (liftOverModal) {\n if (!useDialog && !usePopover) devHooks.overlayBlockedByModal?.('hidden');\n else if (usePopover && wrapper.querySelector(FOCUSABLE) !== null)\n devHooks.overlayBlockedByModal?.('inert');\n }\n\n return { el: wrapper, close, result };\n\n function installDismissal(): void {\n const wantEscape = triggers.includes('escape');\n if (useDialog) {\n // A native modal `<dialog>` confines Tab focus itself and surfaces Escape as\n // a `cancel` event. Take that over: `preventDefault` so kerf owns teardown\n // (and so Escape is swallowed when it isn't a dismiss trigger), then dismiss.\n // A surface stacked above that handles Escape (or is modal) owns it; a\n // stray `cancel` then leaves this dialog open.\n const onCancel = (event: Event): void => {\n event.preventDefault();\n if (wantEscape && owns('escape')) userDismiss();\n };\n wrapper.addEventListener('cancel', onCancel);\n removers.push(() => wrapper.removeEventListener('cancel', onCancel));\n } else if (wantEscape || trap) {\n const onKeydown = (event: KeyboardEvent): void => {\n if (wantEscape && event.key === 'Escape') {\n if (!owns('escape', event)) return;\n // `preventDefault` also withholds the close request from a native\n // `<dialog>` beneath, so one Escape closes exactly one surface.\n event.stopPropagation();\n event.preventDefault();\n arbitration.handled.add(event);\n userDismiss();\n return;\n }\n if (trap && event.key === 'Tab' && owns('trap')) {\n const items = focusable(wrapper);\n if (items.length === 0) {\n event.preventDefault();\n return;\n }\n const first = items[0];\n const last = items[items.length - 1];\n const active = document.activeElement;\n const outside = !wrapper.contains(active);\n if (event.shiftKey && (active === first || outside)) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && (active === last || outside)) {\n event.preventDefault();\n first.focus();\n }\n }\n };\n document.addEventListener('keydown', onKeydown, true);\n removers.push(() =>\n document.removeEventListener('keydown', onKeydown, true),\n );\n }\n\n if (triggers.includes('backdrop')) {\n const onClick = (event: Event): void => {\n if (event.target !== wrapper || !owns('backdrop', event)) return;\n arbitration.handled.add(event);\n userDismiss();\n };\n wrapper.addEventListener('click', onClick);\n removers.push(() => wrapper.removeEventListener('click', onClick));\n }\n\n if (triggers.includes('outside')) {\n const ignore =\n outsideIgnore === undefined\n ? []\n : Array.isArray(outsideIgnore)\n ? outsideIgnore\n : [outsideIgnore];\n // Capture phase: the click that opened this overlay already passed\n // document's capture phase, so this never fires for that opening click.\n const onDocClick = (event: Event): void => {\n const target = event.target as Node | null;\n if (target === null) return;\n if (wrapper.contains(target)) return;\n if (ignore.some((el) => el === target || el.contains(target))) return;\n if (!owns('outside', event)) return;\n arbitration.handled.add(event);\n userDismiss();\n };\n document.addEventListener('click', onDocClick, true);\n removers.push(() =>\n document.removeEventListener('click', onDocClick, true),\n );\n }\n }\n\n // KF-QZ9SFG (slot-hosted controls unreachable by Tab in macOS WebKit): a\n // surface in an overlay host slot sits in the modal dialog's own Tab order,\n // not behind a kerf trap, so WebKit's system keyboard-navigation preference\n // would skip its implicitly tabbable controls. Make those stops explicit, as\n // the trap does — now, and again before each Tab so a control a re-render\n // added (or whose tabindex the morph dropped) is reachable too.\n function makeTabReachable(): void {\n focusable(wrapper);\n const onTab = (event: KeyboardEvent): void => {\n if (event.key === 'Tab') focusable(wrapper);\n };\n document.addEventListener('keydown', onTab, true);\n removers.push(() => document.removeEventListener('keydown', onTab, true));\n }\n\n function applyInitialFocus(): void {\n if (initialFocus !== false) {\n if (typeof initialFocus === 'string') {\n wrapper.querySelector<HTMLElement>(initialFocus)?.focus();\n } else {\n const first = focusable(wrapper)[0];\n if (first !== undefined) {\n first.focus();\n } else {\n wrapper.tabIndex = -1;\n wrapper.focus();\n }\n }\n }\n }\n}\n\n/**\n * Internal: run a promise-dialog helper's post-open wiring (required-slot\n * lookups, `delegate()` handlers, key listeners) as the tail of `overlay()`'s\n * construction transaction. `wire` registers a disposer for every listener it\n * installs via `track`; if any step throws, those listeners are removed, the\n * just-opened overlay is closed (node, mount, dismissal listeners, stack\n * entry, top-layer state, focus), and the original error is rethrown — so a\n * failed helper call returns no promise and leaves no open overlay behind.\n *\n * After construction, `guard` wraps a user-action handler (OK click, Enter).\n * KF-B0CFQP (a throwing `validate` callback): a throw inside a guarded action\n * is a programming error, so it closes the dialog (full teardown, focus\n * restored) and the returned promise REJECTS with the original error, instead\n * of the error escaping the event handler and stranding an open dialog whose\n * OK can never succeed. Otherwise the returned promise settles with\n * `settle(handle.result's value)`. Not re-exported from `kerfjs/overlay`.\n */\nexport function wireDialog<T>(\n handle: OverlayHandle,\n wire: (\n track: (dispose: () => void) => void,\n guard: (action: () => void) => () => void,\n ) => void,\n settle: (value: unknown) => T,\n): Promise<T> {\n const disposers: Array<() => void> = [];\n // Holds a guarded action's error AND is the close() value that marks the\n // failure, so only a throw that actually settles the dialog rejects it.\n const failure: unknown[] = [];\n try {\n wire(\n (dispose) => void disposers.push(dispose),\n (action) => () => {\n try {\n action();\n } catch (error) {\n failure[0] = error;\n handle.close(failure);\n }\n },\n );\n } catch (error) {\n disposers.forEach((dispose) => dispose());\n handle.close();\n throw error;\n }\n // One hop, not a chain: `settle` maps the value in the same reaction, so a\n // helper's promise settles as soon after `close()` as it always has.\n return handle.result.then((value) => {\n if (value === failure) throw failure[0];\n return settle(value);\n });\n}\n","/** `choice()` implementation and public option types. */\nimport { delegate } from './delegate.js';\nimport { jsx } from './jsx-runtime.js';\nimport { overlay, type OverlayContent, wireDialog } from './overlay-core.js';\n\n/** One choosable action in a {@link choice} dialog. */\nexport interface ChoiceAction<R> {\n value: R;\n label: string;\n className?: string;\n}\n\n/** Wiring slots for a {@link ChoiceOptions.render}. */\nexport interface ChoiceRenderSlots {\n message: string;\n actions: Array<Record<string, string>>;\n}\n\n/** Options for {@link choice}. */\nexport interface ChoiceOptions<R> {\n container?: Element;\n className?: string;\n title?: string;\n defaultValue?: R;\n native?: boolean;\n render?: (slots: ChoiceRenderSlots) => OverlayContent;\n}\n\n/** The N-way sibling of {@link confirm}. */\nexport function choice<R>(\n message: string,\n actions: ReadonlyArray<ChoiceAction<R>>,\n options: ChoiceOptions<R> = {},\n): Promise<R | null> {\n const {\n container,\n className = 'kerf-overlay',\n title,\n defaultValue,\n native = false,\n render,\n } = options;\n const hasDefault = 'defaultValue' in options;\n const actionAttrs = actions.map((_, i) => ({ 'data-choice': String(i) }));\n\n const body: OverlayContent =\n render !== undefined\n ? render({ message, actions: actionAttrs })\n : jsx('div', {\n class: 'kerf-choice',\n children: [\n title !== undefined\n ? jsx('h2', { class: 'kerf-choice__title', children: title })\n : '',\n jsx('p', { class: 'kerf-choice__message', children: message }),\n jsx('div', {\n class: 'kerf-choice__actions',\n children: actions.map((action, i) =>\n jsx('button', {\n type: 'button',\n class:\n action.className !== undefined\n ? `kerf-choice__action ${action.className}`\n : 'kerf-choice__action',\n ...actionAttrs[i],\n children: action.label,\n }),\n ),\n }),\n ],\n });\n\n let resolveChoice!: (result: R | null) => void;\n const result = new Promise<R | null>((resolve) => {\n resolveChoice = resolve;\n });\n\n const handle = overlay(body, {\n container,\n className,\n dismiss: ['escape', 'backdrop'],\n initialFocus: '[data-choice]',\n trap: true,\n native,\n });\n\n // Post-open wiring is still construction: a throw closes the overlay. Any\n // close settles a still-pending choice as a dismissal (`null`).\n void wireDialog(\n handle,\n (track) => {\n track(\n delegate(handle.el, 'click', '[data-choice]', (_event, el) => {\n resolveChoice(actions[Number(el.getAttribute('data-choice'))].value);\n handle.close();\n }),\n );\n\n if (hasDefault) {\n const onKeydown = (event: KeyboardEvent): void => {\n if (event.key === 'Enter') {\n event.preventDefault();\n resolveChoice(defaultValue as R);\n handle.close();\n }\n };\n // Last wiring step: nothing after it can throw, so it needs no rollback.\n handle.el.addEventListener('keydown', onKeydown);\n }\n },\n () => resolveChoice(null),\n );\n return result;\n}\n","/** `confirm()` implementation and public option types. */\nimport { delegate } from './delegate.js';\nimport { jsx } from './jsx-runtime.js';\nimport { overlay, type OverlayContent, wireDialog } from './overlay-core.js';\n\n/** Wiring slots passed to a {@link ConfirmOptions.render}. */\nexport interface ConfirmRenderSlots {\n message: string;\n /** Spread onto the confirm control. */\n ok: Record<string, string>;\n /** Spread onto the cancel control. */\n cancel: Record<string, string>;\n}\n\n/** Options for {@link confirm}. */\nexport interface ConfirmOptions {\n /** Where to append the overlay. Default `document.body`. */\n container?: Element;\n /** Wrapper class. Default `'kerf-overlay'`. */\n className?: string;\n /** Optional heading above the message. */\n title?: string;\n /** Confirm button label. Default `'OK'`. */\n okText?: string;\n /** Cancel button label. Default `'Cancel'`. */\n cancelText?: string;\n /** Add a `kerf-confirm--danger` class to the wrapper for destructive actions. */\n danger?: boolean;\n /** Host the dialog in the browser top layer where supported. */\n native?: boolean;\n /** Bring your own body while retaining kerf's dialog wiring. */\n render?: (slots: ConfirmRenderSlots) => OverlayContent;\n}\n\n/** A promise-based `window.confirm` replacement. */\nexport function confirm(\n message: string,\n options: ConfirmOptions = {},\n): Promise<boolean> {\n const {\n container,\n className = 'kerf-overlay',\n title,\n okText = 'OK',\n cancelText = 'Cancel',\n danger = false,\n native = false,\n render,\n } = options;\n\n const body: OverlayContent =\n render !== undefined\n ? render({\n message,\n ok: { 'data-confirm': 'ok' },\n cancel: { 'data-confirm': 'cancel' },\n })\n : jsx('div', {\n class: 'kerf-confirm',\n children: [\n title !== undefined\n ? jsx('h2', { class: 'kerf-confirm__title', children: title })\n : '',\n jsx('p', { class: 'kerf-confirm__message', children: message }),\n jsx('div', {\n class: 'kerf-confirm__actions',\n children: [\n jsx('button', {\n type: 'button',\n 'data-confirm': 'cancel',\n children: cancelText,\n }),\n jsx('button', {\n type: 'button',\n 'data-confirm': 'ok',\n class: 'kerf-confirm__ok',\n children: okText,\n }),\n ],\n }),\n ],\n });\n\n const handle = overlay(body, {\n container,\n className: danger ? `${className} kerf-confirm--danger` : className,\n dismiss: ['escape', 'backdrop'],\n initialFocus: '[data-confirm=\"ok\"]',\n trap: true,\n native,\n });\n\n // Post-open wiring is still construction: a throw closes the overlay. The\n // click table is the only (and so the last) step, so it needs no rollback.\n return wireDialog(\n handle,\n () => {\n delegate(handle.el, 'click', '[data-confirm]', (_event, el) => {\n handle.close(el.getAttribute('data-confirm') === 'ok');\n });\n },\n (value) => value === true,\n );\n}\n","/** `prompt()` implementation and public option types. */\nimport { delegate } from './delegate.js';\nimport { jsx } from './jsx-runtime.js';\nimport { overlay, type OverlayContent, wireDialog } from './overlay-core.js';\n\n/**\n * Validate a single field's value, synchronously: return a non-empty message\n * to block OK, anything else to accept. A validator that throws is treated as\n * a programming error — the dialog closes and the returned promise rejects\n * with that error.\n */\nexport type FieldValidator = (\n value: string,\n) => string | null | undefined | void;\n\n/** Options for {@link prompt}. */\n/**\n * Run a {@link FieldValidator}: the message it reports, or `undefined` when the\n * value is valid. Validators are synchronous — a promise result is a\n * programming error that closes the dialog and rejects its promise (the stray\n * promise's own rejection is silenced so it is not reported twice).\n * Internal to the dialog helpers.\n */\nexport function runValidator(\n validate: FieldValidator | undefined,\n value: string,\n owner: string,\n): string | undefined {\n const result: unknown = validate?.(value);\n if (typeof (result as PromiseLike<unknown> | null)?.then === 'function') {\n (result as PromiseLike<unknown>).then(undefined, () => undefined);\n throw new TypeError(`${owner}: validate returned a promise.`);\n }\n return typeof result === 'string' && result.length > 0 ? result : undefined;\n}\n\nexport interface PromptOptions {\n container?: Element;\n className?: string;\n title?: string;\n defaultValue?: string;\n placeholder?: string;\n inputType?: string;\n okText?: string;\n cancelText?: string;\n validate?: FieldValidator;\n native?: boolean;\n render?: (slots: PromptRenderSlots) => OverlayContent;\n}\n\n/** Wiring slots for a {@link PromptOptions.render}. */\nexport interface PromptRenderSlots {\n message: string;\n input: Record<string, string>;\n error: Record<string, string>;\n ok: Record<string, string>;\n cancel: Record<string, string>;\n}\n\n/** A promise-based `window.prompt` replacement. */\nexport function prompt(\n message: string,\n options: PromptOptions = {},\n): Promise<string | null> {\n const {\n container,\n className = 'kerf-overlay',\n title,\n defaultValue = '',\n placeholder,\n inputType = 'text',\n okText = 'OK',\n cancelText = 'Cancel',\n validate,\n native = false,\n render,\n } = options;\n\n const inputAttrs: Record<string, string> = {\n 'data-prompt-input': '',\n type: inputType,\n value: defaultValue,\n ...(placeholder !== undefined ? { placeholder } : {}),\n };\n\n const body: OverlayContent =\n render !== undefined\n ? render({\n message,\n input: inputAttrs,\n error: { 'data-prompt-error': '' },\n ok: { 'data-prompt': 'ok' },\n cancel: { 'data-prompt': 'cancel' },\n })\n : jsx('div', {\n class: 'kerf-prompt',\n children: [\n title !== undefined\n ? jsx('h2', { class: 'kerf-prompt__title', children: title })\n : '',\n jsx('label', { class: 'kerf-prompt__message', children: message }),\n jsx('input', { class: 'kerf-prompt__input', ...inputAttrs }),\n jsx('p', {\n class: 'kerf-prompt__error',\n 'data-prompt-error': '',\n children: '',\n }),\n jsx('div', {\n class: 'kerf-prompt__actions',\n children: [\n jsx('button', {\n type: 'button',\n 'data-prompt': 'cancel',\n children: cancelText,\n }),\n jsx('button', {\n type: 'button',\n 'data-prompt': 'ok',\n class: 'kerf-prompt__ok',\n children: okText,\n }),\n ],\n }),\n ],\n });\n\n const handle = overlay(body, {\n container,\n className,\n dismiss: ['escape', 'backdrop'],\n initialFocus: '[data-prompt-input]',\n trap: true,\n native,\n });\n\n // Post-open wiring is still construction: a missing required input or any\n // other throw below removes what was wired, closes the overlay, and rethrows.\n return wireDialog(\n handle,\n (track, guard) => {\n // Looked up again at OK: a reactive re-render may have replaced the\n // input, and a detached node would report a stale value. Missing at\n // construction is a render bug (rolls back, throws); missing at OK\n // rejects the promise through `guard`.\n const inputFor = (problem = 'render missing'): HTMLInputElement => {\n const input = handle.el.querySelector<HTMLInputElement>(\n 'input[data-prompt-input]',\n );\n if (input !== null) return input;\n throw new Error(`prompt(): ${problem} <input data-prompt-input>.`);\n };\n inputFor();\n const errorEl = handle.el.querySelector<HTMLElement>(\n '[data-prompt-error]',\n );\n if (errorEl !== null) errorEl.hidden = true;\n\n // A throwing (or promise-returning) `validate` closes the dialog and\n // rejects the promise (guard).\n const attemptOk = guard((): void => {\n const input = inputFor('removed after open:');\n const value = input.value;\n const error = runValidator(validate, value, 'prompt()');\n if (error !== undefined) {\n if (errorEl !== null) {\n errorEl.textContent = error;\n errorEl.hidden = false;\n }\n input.focus();\n return;\n }\n handle.close(value);\n });\n\n track(\n delegate(handle.el, 'click', '[data-prompt]', (_event, el) => {\n if (el.getAttribute('data-prompt') === 'ok') attemptOk();\n else handle.close(null);\n }),\n );\n\n const onKeydown = (event: KeyboardEvent): void => {\n if (\n event.key === 'Enter' &&\n (event.target as Element | null)?.matches('input[data-prompt-input]')\n ) {\n event.preventDefault();\n attemptOk();\n }\n };\n // Last wiring step: nothing after it can throw, so it needs no rollback.\n handle.el.addEventListener('keydown', onKeydown);\n },\n (value) => (typeof value === 'string' ? value : null),\n );\n}\n","/** `form()` implementation and public option types. */\nimport { delegate } from './delegate.js';\nimport { jsx } from './jsx-runtime.js';\nimport { overlay, type OverlayContent, wireDialog } from './overlay-core.js';\nimport { type FieldValidator, runValidator } from './overlay-prompt.js';\n\n/** A single field in a {@link form}. */\nexport interface FormField {\n name: string;\n label?: string;\n defaultValue?: string;\n placeholder?: string;\n type?: string;\n validate?: FieldValidator;\n}\n\n/** One field's wiring in a {@link FormRenderSlots}. */\nexport interface FormRenderField {\n name: string;\n label: string;\n input: Record<string, string>;\n error: Record<string, string>;\n}\n\n/** Wiring slots for a {@link FormOptions.render}. */\nexport interface FormRenderSlots {\n fields: FormRenderField[];\n ok: Record<string, string>;\n cancel: Record<string, string>;\n}\n\n/** Options for {@link form}. */\nexport interface FormOptions {\n container?: Element;\n className?: string;\n title?: string;\n okText?: string;\n cancelText?: string;\n native?: boolean;\n render?: (slots: FormRenderSlots) => OverlayContent;\n}\n\n/** A promise-based multi-field dialog. */\nexport function form(\n fields: readonly FormField[],\n options: FormOptions = {},\n): Promise<Record<string, string> | null> {\n const {\n container,\n className = 'kerf-overlay',\n title,\n okText = 'OK',\n cancelText = 'Cancel',\n native = false,\n render,\n } = options;\n\n const fieldAttrs = (field: FormField): Record<string, string> => ({\n 'data-field': field.name,\n name: field.name,\n type: field.type ?? 'text',\n value: field.defaultValue ?? '',\n ...(field.placeholder !== undefined\n ? { placeholder: field.placeholder }\n : {}),\n });\n\n const body: OverlayContent =\n render !== undefined\n ? render({\n fields: fields.map((field) => ({\n name: field.name,\n label: field.label ?? field.name,\n input: fieldAttrs(field),\n error: { 'data-field-error': field.name },\n })),\n ok: { 'data-form': 'ok' },\n cancel: { 'data-form': 'cancel' },\n })\n : jsx('div', {\n class: 'kerf-form',\n children: [\n title !== undefined\n ? jsx('h2', { class: 'kerf-form__title', children: title })\n : '',\n ...fields.map((field) =>\n jsx('div', {\n class: 'kerf-form__field',\n children: [\n jsx('label', {\n class: 'kerf-form__label',\n children: field.label ?? field.name,\n }),\n jsx('input', {\n class: 'kerf-form__input',\n ...fieldAttrs(field),\n }),\n jsx('p', {\n class: 'kerf-form__error',\n 'data-field-error': field.name,\n children: '',\n }),\n ],\n }),\n ),\n jsx('div', {\n class: 'kerf-form__actions',\n children: [\n jsx('button', {\n type: 'button',\n 'data-form': 'cancel',\n children: cancelText,\n }),\n jsx('button', {\n type: 'button',\n 'data-form': 'ok',\n class: 'kerf-form__ok',\n children: okText,\n }),\n ],\n }),\n ],\n });\n\n const handle = overlay(body, {\n container,\n className,\n dismiss: ['escape', 'backdrop'],\n initialFocus: '[data-field]',\n trap: true,\n native,\n });\n\n // Post-open wiring is still construction: a missing required field input or\n // any other throw below removes what was wired, closes the overlay, and\n // rethrows.\n return wireDialog(\n handle,\n (track, guard) => {\n const errorFor = (name: string): HTMLElement | null =>\n Array.from(\n handle.el.querySelectorAll<HTMLElement>('[data-field-error]'),\n ).find((el) => el.getAttribute('data-field-error') === name) ?? null;\n // KF-HRNJ4T (a field input removed after open by a reactive re-render):\n // at construction a missing input is a render bug that rolls back and\n // throws synchronously; at OK time it throws inside `guard`, so the\n // dialog closes and the promise rejects naming the field — never a\n // `null` that reads as a user Cancel.\n const inputFor = (\n name: string,\n problem = 'render missing',\n ): HTMLInputElement => {\n const input = Array.from(\n handle.el.querySelectorAll<HTMLInputElement>('input[data-field]'),\n ).find((el) => el.getAttribute('data-field') === name);\n if (input !== undefined) return input;\n throw new Error(`form(): ${problem} <input data-field=\"${name}\">.`);\n };\n\n for (const field of fields) {\n inputFor(field.name);\n const errorEl = errorFor(field.name);\n if (errorEl !== null) errorEl.hidden = true;\n }\n\n // A throwing `field.validate` closes the dialog and rejects the promise.\n const attemptOk = guard((): void => {\n const record: Record<string, string> = {};\n let firstInvalid: HTMLInputElement | null = null;\n for (const field of fields) {\n const el = inputFor(field.name, 'removed after open:');\n const value = el.value;\n record[field.name] = value;\n const error = runValidator(field.validate, value, 'form()');\n const errorEl = errorFor(field.name);\n if (error !== undefined) {\n if (errorEl !== null) {\n errorEl.textContent = error;\n errorEl.hidden = false;\n }\n if (firstInvalid === null) firstInvalid = el;\n } else if (errorEl !== null) {\n errorEl.hidden = true;\n }\n }\n if (firstInvalid !== null) {\n firstInvalid.focus();\n return;\n }\n handle.close(record);\n });\n\n track(\n delegate(handle.el, 'click', '[data-form]', (_event, el) => {\n if (el.getAttribute('data-form') === 'ok') attemptOk();\n else handle.close(null);\n }),\n );\n\n const onKeydown = (event: KeyboardEvent): void => {\n if (\n event.key === 'Enter' &&\n (event.target as Element | null)?.matches('[data-field]')\n ) {\n event.preventDefault();\n attemptOk();\n }\n };\n // Last wiring step: nothing after it can throw, so it needs no rollback.\n handle.el.addEventListener('keydown', onKeydown);\n },\n (value) =>\n value !== null && typeof value === 'object'\n ? (value as Record<string, string>)\n : null,\n );\n}\n","/**\n * Anchored positioning primitives for `kerfjs/overlay` — position an element\n * relative to an anchor, with viewport flip + clamp. These are standalone: they\n * take any element and have no overlay lifecycle, so `popover()` / `tooltip()`\n * build on them but you can also position your own element (an inline hint, a\n * custom menu). Re-exported from `src/overlay.ts` so the public `kerfjs/overlay`\n * surface is unchanged (KF-511 split out of overlay.ts's dialog + toast code).\n */\n\n/** Vertical placement relative to an anchor (used by `popover`, {@link positionAnchored}, `tooltip`). */\nexport type PopoverPlacement = 'bottom' | 'top';\n\n/** Placement options for {@link positionAnchored} / {@link autoReposition}. */\nexport interface AnchorPositionOptions {\n /** Preferred side of the anchor; flips to the other side if it would overflow the viewport. Default `'bottom'`. */\n placement?: PopoverPlacement;\n /** Horizontal edge to line up with the anchor: `'start'` (left edges) or `'end'` (right edges). Default `'start'`. */\n align?: 'start' | 'end';\n /** Gap in px between the anchor and the element. Default `4`. */\n gap?: number;\n}\n\n/**\n * One-shot: position `el` relative to `anchor` — below by default, flipping above\n * if it would overflow the viewport, aligned to a horizontal edge and clamped into\n * view. Sets `el.style` `position: fixed`, `margin: 0`, `left`, and `top` (fixed so\n * `left`/`top` are viewport coordinates, matching `getBoundingClientRect`). When an\n * ancestor makes itself the containing block for fixed descendants (a\n * `transform`, `filter`, `perspective`, or `contain` on a wrapping `<dialog>`),\n * `left`/`top` are translated (and unscaled) into that box's coordinates so `el`\n * still lands next to the anchor. This is\n * `popover()`'s placement core, usable on any element (an inline hint, a tooltip) —\n * no overlay lifecycle. Pair with {@link autoReposition} to keep it glued while open.\n */\nexport function positionAnchored(\n el: HTMLElement,\n anchor: Element,\n options: AnchorPositionOptions = {},\n): void {\n const { placement = 'bottom', align = 'start', gap = 4 } = options;\n // Fix `el` FIRST, then measure it. Measuring a still-`display:block` wrapper\n // reports the full body-content width (≈ viewport minus body margins), which\n // collapses the horizontal clamp below and lands the element at the body's left\n // edge. As a fixed, shrink-to-fit box its `width`/`height` are its real size.\n el.style.position = 'fixed';\n el.style.margin = '0';\n const anchorRect = anchor.getBoundingClientRect();\n const elementRect = el.getBoundingClientRect();\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n\n // Vertical: preferred side, flipped only if it overflows and the other side fits.\n const belowTop = anchorRect.bottom + gap;\n const aboveTop = anchorRect.top - gap - elementRect.height;\n let below = placement !== 'top';\n if (below && belowTop + elementRect.height > viewportHeight && aboveTop >= 0)\n below = false;\n else if (\n !below &&\n aboveTop < 0 &&\n belowTop + elementRect.height <= viewportHeight\n )\n below = true;\n\n // Horizontal: align to an anchor edge, then clamp into the viewport.\n let left =\n align === 'end' ? anchorRect.right - elementRect.width : anchorRect.left;\n left = Math.max(0, Math.min(left, viewportWidth - elementRect.width));\n\n // `left`/`top` so far are viewport coordinates. They are only the CSS values\n // too when `el`'s fixed-position containing block is the viewport; an\n // ancestor with a `transform`, `filter`, `perspective`, `contain`, … (say a\n // modal `<dialog>` holding an overlay host slot) captures fixed descendants,\n // so map the coordinates into that box's space.\n const [originX, originY, scaleX, scaleY] = fixedOrigin(el);\n el.style.left = `${(left - originX) / scaleX}px`;\n el.style.top = `${((below ? belowTop : aboveTop) - originY) / scaleY}px`;\n}\n\n/**\n * Where `left: 0; top: 0` actually lands for a fixed-position child of `el`'s\n * parent, plus that containing block's scale — `[x, y, scaleX, scaleY]`, which\n * is `[0, 0, 1, 1]` when the viewport is the containing block. Measured with a\n * 1px probe rather than `el` itself so `el`'s own transform or running entrance\n * animation cannot skew it. The probe is inserted and removed synchronously, so\n * it is never painted. Translation and scale are compensated; a rotated or\n * skewed containing block is not.\n */\nfunction fixedOrigin(el: HTMLElement): [number, number, number, number] {\n const parent = el.parentNode;\n if (!parent) return [0, 0, 1, 1];\n const probe = el.ownerDocument.createElement('div');\n probe.style.cssText =\n 'position:fixed;left:0;top:0;width:1px;height:1px;margin:0;padding:0;border:0';\n parent.insertBefore(probe, el);\n const rect = probe.getBoundingClientRect();\n probe.remove();\n // A zero size (a containing block mid `scale(0)` animation, or a DOM without\n // layout) would divide by zero; treat it as unscaled.\n return [rect.left, rect.top, rect.width || 1, rect.height || 1];\n}\n\n/**\n * Keep `el` positioned against `anchor` (via {@link positionAnchored}) as the page\n * scrolls or resizes. Positions once immediately, then re-runs on `scroll`\n * (capture phase — catches scrolls in any inner container, not just `window`) and\n * `resize`. Returns a disposer that removes the listeners.\n */\nexport function autoReposition(\n el: HTMLElement,\n anchor: Element,\n options: AnchorPositionOptions = {},\n): () => void {\n const reposition = (): void => positionAnchored(el, anchor, options);\n reposition();\n window.addEventListener('scroll', reposition, true);\n window.addEventListener('resize', reposition);\n return () => {\n window.removeEventListener('scroll', reposition, true);\n window.removeEventListener('resize', reposition);\n };\n}\n","/** Anchored popover lifecycle built on the shared overlay transaction. */\nimport { attach } from './attach.js';\nimport {\n type DismissTrigger,\n overlay,\n type OverlayContent,\n type OverlayHandle,\n overlayHost,\n} from './overlay-core.js';\nimport { autoReposition, type PopoverPlacement } from './overlay-position.js';\n\n/** Options for {@link popover}. */\nexport interface PopoverOptions {\n /**\n * Where to append the popover wrapper. Default: when `anchor` sits inside an\n * open modal `<dialog>`, that dialog's `[data-kerf-overlay-host]` element (a\n * dialog kerf opened gets one automatically), so the popover is part of the\n * modal subtree and stays interactive; otherwise `document.body`. A modal\n * `<dialog>` in a shadow root counts when `anchor` is slotted into it (Web\n * Awesome's `wa-dialog` / `wa-drawer`): the slot is created on demand in the\n * shadow host's light DOM. A popover inside a modal closes when that dialog\n * closes.\n */\n container?: Element;\n /** Class on the wrapper. Default `'kerf-popover'`. */\n className?: string;\n /** Preferred side of the anchor. Flips to the other side if it would overflow the viewport. Default `'bottom'`. */\n placement?: PopoverPlacement;\n /** Horizontal edge to line up with the anchor: `'start'` (left edges) or `'end'` (right edges). Default `'start'`. */\n align?: 'start' | 'end';\n /** Gap in px between the anchor and the popover. Default `4`. */\n gap?: number;\n /**\n * Which user actions dismiss the popover. Default `['outside']` (a click\n * outside the popover, the anchor exempt). Pass `false` to close only via `close()`.\n */\n dismiss?: DismissTrigger | DismissTrigger[] | false;\n /** Focus behavior on open. Default `false` (non-modal — leave focus alone). */\n initialFocus?: string | boolean;\n /** Extra elements (besides the anchor) whose clicks do NOT count as outside. */\n outsideIgnore?: Element | readonly Element[];\n /** Called on any user-initiated dismissal. */\n onDismiss?: () => void;\n /**\n * Host the popover in the browser top layer (the Popover API — `[popover]` +\n * `showPopover()`) where supported, so it stacks above any `z-index` without a\n * z-index war. Falls back to today's plain `<div>` where unsupported. kerf keeps\n * owning positioning + its own dismiss wiring; the popover is `popover=\"manual\"`.\n * See {@link OverlayOptions.native}. Default `false`.\n */\n native?: boolean;\n}\n\n/**\n * Anchored, non-modal overlay: positions `content` relative to `anchor` (below by\n * default, flipping above if it would overflow, and clamped horizontally to the\n * viewport) and repositions on scroll / resize while open. A thin wrapper over\n * {@link overlay} with non-modal defaults — `trap: false`, `dismiss: ['outside']`,\n * and the anchor added to `outsideIgnore` so the trigger click doesn't self-close.\n * Returns the same {@link OverlayHandle}; `close()` also drops the reposition\n * listeners. `position: fixed` is set inline (you style everything else).\n */\nexport function popover(\n anchor: Element,\n content: OverlayContent,\n options: PopoverOptions = {},\n): OverlayHandle {\n const {\n container,\n className = 'kerf-popover',\n placement = 'bottom',\n align = 'start',\n gap = 4,\n dismiss = ['outside'],\n initialFocus = false,\n outsideIgnore,\n onDismiss,\n native = false,\n } = options;\n\n const extraIgnore =\n outsideIgnore === undefined\n ? []\n : Array.isArray(outsideIgnore)\n ? [...outsideIgnore]\n : [outsideIgnore];\n\n const handle = overlay(content, {\n container: container ?? overlayHost(anchor),\n className,\n dismiss,\n trap: false,\n initialFocus,\n onDismiss,\n outsideIgnore: [anchor, ...extraIgnore],\n native,\n });\n\n // Position + keep it glued while open; drop the listeners on close. A throw\n // while positioning (e.g. an anchor whose geometry read fails) is still part\n // of construction: close the just-opened overlay before rethrowing.\n let stopReposition: () => void;\n try {\n stopReposition = autoReposition(handle.el, anchor, {\n placement,\n align,\n gap,\n });\n } catch (error) {\n handle.close();\n throw error;\n }\n void handle.result.then(stopReposition);\n\n // KF-BAVCEV: never outlive the anchor. When it leaves the document (e.g. the\n // modal holding it closes) close the popover as cleanup — not a user\n // dismissal, so no `onDismiss`. A move within the document keeps it open.\n void handle.result.then(attach(anchor, () => handle.close));\n\n return handle;\n}\n","/**\n * `toast()` for `kerfjs/overlay` — a non-modal, auto-dismissing notification that\n * stacks in a shared body-level region. Split out of `overlay.ts` (KF-513) since\n * it's a distinct transient-UI concern from the modal dialogs; re-exported from\n * `overlay.ts` so the public `kerfjs/overlay` surface is unchanged. Structural\n * only — kerf ships no CSS; you style the region / toast / animations.\n */\nimport { type SafeHtml } from './jsx-runtime.js';\nimport { mount, type MountResult } from './mount.js';\nimport { escapeHtml } from './utils/escapeHtml.js';\n\n/** Content for a {@link toast}: an escaped text string, trusted `SafeHtml`, or a render function. */\nexport type ToastContent = string | SafeHtml | (() => MountResult);\n\n/** Accent variant for a {@link toast} — mapped to a `${className}--${variant}` class. */\nexport type ToastVariant = 'info' | 'success' | 'warning';\n\n/** Options for {@link toast}. */\nexport interface ToastOptions {\n /** Where toasts stack. Default: a lazily-created `<div class=\"kerf-toasts\">` on `document.body`. */\n container?: Element;\n /** Class on the toast element. Default `'kerf-toast'`. */\n className?: string;\n /** Auto-dismiss after this many ms. `0` keeps it until dismissed by hand. Default `4000`. */\n duration?: number;\n /** ARIA role. Default `'status'`. */\n role?: string;\n /**\n * `'stack'` (default) shows toasts stacked in the region; `'replace'` dismisses\n * the region's current toast(s) first (collapse-to-latest for a rapid sequence).\n */\n mode?: 'stack' | 'replace';\n /**\n * How `mode: 'replace'` drops the prior toast(s): `'fade'` (default) runs their\n * full exit transition (nice for a STACKING region), or `'instant'` removes them\n * synchronously with no exit — what a single, exactly-centered toast slot wants,\n * so the outgoing and incoming messages never cross-fade in the same spot.\n */\n collapse?: 'fade' | 'instant';\n /** Accent variant — adds a `${className}--${variant}` class (kerf ships no CSS; you style it). */\n variant?: ToastVariant;\n /** Class added on the next animation frame after mount, so a CSS **entrance** transition can run. */\n enterClass?: string;\n /**\n * Class added when dismissing, so CSS owns the **exit**. On dismiss the\n * `enterClass` (if any) is also REMOVED, so `exitClass` doesn't have to\n * out-specify it — and a symmetric single-class fade (entrance = add\n * `enterClass`, exit = remove it) works by setting only `enterClass` +\n * `exitDuration`. The node is removed `exitDuration` ms later.\n */\n exitClass?: string;\n /** ms to wait before removing the node on dismiss — applies when `exitClass` is set OR when it's > 0 (to let a removed `enterClass` transition out). Default `0`. */\n exitDuration?: number;\n}\n\n/** Handle returned by {@link toast}. */\nexport interface ToastHandle {\n /** The toast element — inspect it, or run your own entrance/exit transitions. */\n el: HTMLElement;\n /**\n * Dismiss it early. Default runs the `exitClass` transition (removed after\n * `exitDuration`); pass `{ instant: true }` to remove it **synchronously** with\n * no exit — for an action button that immediately shows a replacement toast in a\n * single centered slot (no cross-fade). Idempotent.\n */\n dismiss(options?: { instant?: boolean }): void;\n}\n\n/** The region's active toasts live on the region element (in the DOM), not in module state. */\nconst TOAST_SET = Symbol('kerf.toasts');\n/** A dismiss function with an `.removeNow()` for instant (no-exit) teardown. */\ntype Dismisser = (() => void) & { removeNow: () => void };\ntype ToastCarrier = Element & { [TOAST_SET]?: Set<Dismisser> };\n\n/** The singleton toast region lives in the DOM (queried, not held in a module variable). */\nfunction toastRegion(container?: Element): Element {\n if (container !== undefined) return container;\n const existing = document.querySelector('.kerf-toasts');\n if (existing !== null) return existing;\n const region = document.createElement('div');\n region.className = 'kerf-toasts';\n region.setAttribute('aria-live', 'polite');\n document.body.appendChild(region);\n return region;\n}\n\n/**\n * Show a non-modal, auto-dismissing notification. Stacks in a shared body-level\n * region (or your `container`). Returns a {@link ToastHandle} (`{ el, dismiss }`)\n * so you can run entrance/exit transitions, wire an action button, or inspect the\n * node. `mode: 'replace'` collapses a rapid sequence to the latest; `variant`\n * adds an accent class; `enterClass`/`exitClass` let CSS own the animation.\n */\nexport function toast(\n content: ToastContent,\n options: ToastOptions = {},\n): ToastHandle {\n const {\n container,\n className = 'kerf-toast',\n duration = 4000,\n role = 'status',\n mode = 'stack',\n collapse = 'fade',\n variant,\n enterClass,\n exitClass,\n exitDuration = 0,\n } = options;\n\n const region = toastRegion(container) as ToastCarrier;\n const active = (region[TOAST_SET] ??= new Set<Dismisser>());\n // collapse-to-latest: 'instant' removes priors synchronously (no cross-fade in a\n // centered single slot); 'fade' runs their exit transition (nice for a stack).\n if (mode === 'replace') {\n for (const d of [...active]) {\n if (collapse === 'instant') d.removeNow();\n else d();\n }\n }\n\n const el = document.createElement('div');\n el.className = className;\n if (variant !== undefined) el.classList.add(`${className}--${variant}`);\n el.setAttribute('role', role);\n region.appendChild(el);\n\n const render =\n typeof content === 'function'\n ? content\n : () => (typeof content === 'string' ? escapeHtml(content) : content);\n const disposeMount = mount(el, render);\n const state: {\n dismissed: boolean;\n removed: boolean;\n timer: ReturnType<typeof setTimeout> | undefined;\n exitTimer: ReturnType<typeof setTimeout> | undefined;\n } = {\n dismissed: false,\n removed: false,\n timer: undefined,\n exitTimer: undefined,\n };\n\n if (enterClass !== undefined) {\n globalThis.requestAnimationFrame(() => {\n if (!state.dismissed) el.classList.add(enterClass);\n });\n }\n\n const remove = (): void => {\n if (state.removed) return;\n state.removed = true;\n state.dismissed = true; // once removed, a later dismiss() is a clean no-op\n if (state.exitTimer !== undefined) clearTimeout(state.exitTimer);\n disposeMount();\n el.remove();\n active.delete(dismiss as Dismisser);\n };\n\n // Force synchronous teardown NOW, with no exit transition — even if a fade is\n // already in flight (so `mode:'replace'` collapse can clean up a mid-exit toast,\n // and `dismiss({ instant: true })` drops it immediately).\n const removeNow = (): void => {\n if (state.timer !== undefined) clearTimeout(state.timer);\n remove();\n };\n\n const fadeOut = (): void => {\n if (state.dismissed) return;\n state.dismissed = true;\n if (state.timer !== undefined) clearTimeout(state.timer);\n // Reverse the entrance (drop enterClass so exitClass needn't out-specify it),\n // add exitClass, and delay removal for the transition — including the\n // single-class idiom (enterClass removed + exitDuration, no exitClass).\n if (enterClass !== undefined) el.classList.remove(enterClass);\n if (exitClass !== undefined) el.classList.add(exitClass);\n if (exitClass !== undefined || exitDuration > 0) {\n state.exitTimer = setTimeout(remove, exitDuration);\n } else {\n remove();\n }\n };\n\n function dismiss(options?: { instant?: boolean }): void {\n if (options?.instant === true) removeNow();\n else fadeOut();\n }\n (dismiss as Dismisser).removeNow = removeNow;\n\n active.add(dismiss as Dismisser);\n if (duration > 0) state.timer = setTimeout(fadeOut, duration);\n return { el, dismiss };\n}\n","/** Hover and focus tooltip lifecycle built on the shared overlay transaction. */\nimport { attach } from './attach.js';\nimport { jsx, type SafeHtml } from './jsx-runtime.js';\nimport type { MountResult } from './mount.js';\nimport {\n overlay,\n type OverlayContent,\n type OverlayHandle,\n overlayHost,\n} from './overlay-core.js';\nimport {\n type AnchorPositionOptions,\n autoReposition,\n} from './overlay-position.js';\n\n/** Content for a {@link tooltip}: text (auto-escaped), `SafeHtml`, or a render function. */\nexport type TooltipContent = string | SafeHtml | (() => MountResult);\n\n/** Options for {@link tooltip}. */\nexport interface TooltipOptions extends AnchorPositionOptions {\n /** Where to append the tooltip wrapper. Default: the anchor's modal-dialog host slot (see {@link PopoverOptions.container}), else `document.body`. */\n container?: Element;\n /** Class on the wrapper. Default `'kerf-tooltip'`. */\n className?: string;\n /** Delay in ms before showing after hover/focus enters. Default `400`. */\n delay?: number;\n /** Delay in ms before hiding after hover/focus leaves. Default `100`. */\n hideDelay?: number;\n /** ARIA role on the wrapper. Default `'tooltip'`. */\n role?: string;\n /** Host the tooltip in the browser top layer (the Popover API) where supported. See {@link OverlayOptions.native}. Default `false`. */\n native?: boolean;\n}\n\n/**\n * A hover/focus-triggered, non-modal, auto-hiding tooltip anchored to `anchor`.\n * Shows after `delay` on `pointerenter`/`focus`, hides after `hideDelay` on\n * `pointerleave`/`blur`, and positions itself with {@link autoReposition} (above\n * the anchor by default). Unlike {@link popover} there is no click-dismiss model —\n * it follows the pointer/focus. Returns a disposer that removes the anchor\n * listeners and hides any shown tooltip. Structural only (kerf ships no CSS).\n */\nexport function tooltip(\n anchor: Element,\n content: TooltipContent,\n options: TooltipOptions = {},\n): () => void {\n const {\n container,\n className = 'kerf-tooltip',\n delay = 400,\n hideDelay = 100,\n role = 'tooltip',\n placement = 'top',\n align = 'start',\n gap = 4,\n native = false,\n } = options;\n\n const body: OverlayContent =\n typeof content === 'function'\n ? content\n : typeof content === 'string'\n ? jsx('span', { class: `${className}__text`, children: content })\n : content;\n\n const timers: {\n show?: ReturnType<typeof setTimeout>;\n hide?: ReturnType<typeof setTimeout>;\n } = {};\n let current:\n | { handle: OverlayHandle; stop: () => void; unwatch: () => void }\n | undefined;\n let presence = 0;\n\n // Runs from the `delay` timer, so there is no caller to throw to. A failed\n // show (a throwing render fn, `native` `showPopover()`, or positioning) is\n // rolled back before `current` is set — nothing stays on screen and the\n // next pointerenter / focus schedules a fresh attempt — and the original\n // error then escapes the timer callback for the host to report as uncaught\n // (a window `error` event in browsers), the same way kerf's other deferred\n // callbacks (debounce / throttle timers, attach teardown) surface errors.\n function show(): void {\n // The anchor left the document while the show was pending (KF-BAVCEV).\n if (!anchor.isConnected) return;\n const handle = overlay(body, {\n container: container ?? overlayHost(anchor),\n className,\n dismiss: false,\n trap: false,\n initialFocus: false,\n native,\n });\n handle.el.setAttribute('role', role);\n let stop: () => void;\n try {\n stop = autoReposition(handle.el, anchor, { placement, align, gap });\n } catch (error) {\n // Not yet tracked in `current`, so `hide()` could never reach it.\n handle.close();\n throw error;\n }\n // KF-BAVCEV: an anchor removed from the document (e.g. with the modal that\n // held it) fires no pointerleave / blur, so hide when it leaves and forget\n // its presence; a move within the document keeps the tooltip shown.\n const unwatch = attach(anchor, () => () => {\n presence = 0;\n if (timers.hide !== undefined) clearTimeout(timers.hide);\n hide();\n });\n current = { handle, stop, unwatch };\n // A surface that closed itself (its host slot left the document with the\n // dialog) must not stay `current`, or the next hover would never show.\n void handle.result.then(() => {\n if (current?.handle === handle) hide();\n });\n }\n\n function hide(): void {\n const shown = current;\n if (shown === undefined) return;\n // Cleared first: `unwatch()` runs the anchor teardown, which re-enters here.\n current = undefined;\n shown.unwatch();\n shown.stop();\n shown.handle.close();\n }\n\n const onEnter = (event: Event): void => {\n presence |= event.type === 'focus' ? 2 : 1;\n if (timers.hide !== undefined) clearTimeout(timers.hide);\n if (current !== undefined) return;\n if (timers.show !== undefined) clearTimeout(timers.show); // debounce: one pending show at a time\n timers.show = setTimeout(show, delay);\n };\n const onLeave = (event: Event): void => {\n presence &= event.type === 'blur' ? ~2 : ~1;\n if (presence) return;\n if (timers.show !== undefined) clearTimeout(timers.show);\n if (current === undefined) return;\n timers.hide = setTimeout(hide, hideDelay);\n };\n\n anchor.addEventListener('pointerenter', onEnter);\n anchor.addEventListener('pointerleave', onLeave);\n anchor.addEventListener('focus', onEnter);\n anchor.addEventListener('blur', onLeave);\n\n return () => {\n anchor.removeEventListener('pointerenter', onEnter);\n anchor.removeEventListener('pointerleave', onLeave);\n anchor.removeEventListener('focus', onEnter);\n anchor.removeEventListener('blur', onLeave);\n if (timers.show !== undefined) clearTimeout(timers.show);\n if (timers.hide !== undefined) clearTimeout(timers.hide);\n hide();\n };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kerfjs",
3
- "version": "5.0.0-beta.95",
3
+ "version": "5.0.0-beta.97",
4
4
  "description": "Tiny reactive UI framework — fine-grained signals + DOM morphing + JSX. Apply the smallest possible cut to update your DOM.",
5
5
  "type": "module",
6
6
  "sideEffects": [