diff --git a/.changeset/dialog-backdrop-containment.md b/.changeset/dialog-backdrop-containment.md
deleted file mode 100644
index f2f57d2..0000000
--- a/.changeset/dialog-backdrop-containment.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-'@dunky.dev/react-dialog': patch
----
-
-A modal dialog no longer marks its own backdrop `aria-hidden` + `inert`. The
-assistive-tech containment walks up from the dialog window and hides every
-sibling along the way — and the backdrop is portalled alongside the viewport,
-outside the window's subtree yet part of the same layer, so the topmost
-dialog was hiding its own backdrop. `inert` blocks pointer hit-testing, so
-pressing the backdrop to dismiss silently did nothing in a real browser
-(test-runner `.click()` bypasses hit-testing, which is why suites never
-caught it). A dialog's layer now excepts its own backdrop from the
-containment; everything beneath the topmost layer — lower dialogs' backdrops
-included — stays hidden and inert as before.
diff --git a/.changeset/dialog-close-on-back.md b/.changeset/dialog-close-on-back.md
deleted file mode 100644
index b38ed08..0000000
--- a/.changeset/dialog-close-on-back.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-'@dunky.dev/dialog': minor
-'@dunky.dev/react-dialog': minor
-'@dunky.dev/dom-navigation': minor
----
-
-Add `closeOnBack` — the host's Back navigation closes the open dialog instead
-of leaving the page, the pattern mobile users expect from a full-screen
-overlay. Off by default.
-
-```tsx
-
-```
-
-It follows the shared dismissal contract: `onBackNavigation` fires first and
-`preventDefault()` vetoes, a controlled dialog only records the intent (close
-it from your own state as usual), a nested stack unwinds one layer per Back
-press, and it composes with `animated` (Back plays the exit animation). The
-decision — gate, veto, controlled — lives once in the core's `backNavigate`;
-substrates only wire their host's mechanics to it.
-
-The web mechanics ship as their own framework-free util,
-`@dunky.dev/dom-navigation` (`interceptBackNavigation`) — a session
-history guard any overlaid layer can use, not just the dialog: opening
-plants a guard entry in the session history and Back consumes it. A dialog
-closed any other way consumes its own entry too, so no leftover ever swallows
-a later Back press — including across reopen races (React StrictMode's
-double-invoked effects adopt the entry in place rather than queueing a
-history traversal, which browsers don't reliably deliver once another entry
-is pushed).
diff --git a/.changeset/dialog-exit-animation.md b/.changeset/dialog-exit-animation.md
deleted file mode 100644
index e89e242..0000000
--- a/.changeset/dialog-exit-animation.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-'@dunky.dev/dialog': minor
-'@dunky.dev/react-dialog': minor
-'@dunky.dev/dom-overlay': minor
----
-
-Add exit-animation support via a new `animated` option. An animated dialog
-closes through a `closing` state — every part carries it as
-`data-state="closing"`, the styling hook for the exit — and unmounts when its
-transition or animation on Content ends (with a fallback ceiling, and skipped
-entirely under `prefers-reduced-motion`).
-
-```tsx
-
-```
-
-```css
-[data-state='closing'] {
- opacity: 0;
- transition: opacity 150ms;
-}
-```
-
-The exit window lives in the core machine, not in per-substrate unmount
-deferral, so reopening mid-exit is a named transition instead of a timing
-race, and every substrate inherits identical behavior. The exit is cosmetic
-by design: the close is reported, focus returns, and the page becomes
-interactive the moment closing starts — the still-painting layer is made
-`inert` until it leaves. Enter animations need no option: parts mount
-straight into `data-state="open"`, so CSS animations (or transitions via
-`@starting-style`) play from mount. Default (`animated: false`) behavior is
-unchanged.
diff --git a/.changeset/overlay-packages.md b/.changeset/overlay-packages.md
deleted file mode 100644
index f5f4d1d..0000000
--- a/.changeset/overlay-packages.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-'@dunky.dev/overlay': minor
-'@dunky.dev/dom-overlay': minor
-'@dunky.dev/react-dialog': patch
----
-
-Add `@dunky.dev/overlay` and `@dunky.dev/dom-overlay` — the shared overlay
-coordination the whole overlay family (dialog, drawer, alert-dialog, popover,
-menu, combobox) builds on, so the behavior is implemented once instead of
-forked per primitive.
-
-- `@dunky.dev/overlay` is the agnostic half: a stack of open layers and the
- rule for which is topmost (deepest nesting, open order breaking ties). No
- DOM, no framework — a future native substrate reuses it.
-- `@dunky.dev/dom-overlay` is the DOM realization on top of it: the layer
- stack wired to assistive-tech containment (`aria-hidden` + `inert`), the
- exit window (`hideExitingLayer` / `watchExitAnimation`), and initial focus
- (`getInitialFocus`).
-
-```ts
-import { createLayerStack, type OverlayLayer } from '@dunky.dev/overlay'
-import { registerLayer, isTopmostLayer } from '@dunky.dev/dom-overlay'
-```
-
-This replaces `@dunky.dev/dom-dialog`, which is removed — its behavior was
-never dialog-specific, only its name was. `@dunky.dev/react-dialog` now
-consumes `@dunky.dev/dom-overlay`; its public API and behavior are unchanged
-(`registerDialog` / `isTopmostDialog` become `registerLayer` /
-`isTopmostLayer` internally).
diff --git a/packages/core/dialog/CHANGELOG.md b/packages/core/dialog/CHANGELOG.md
index c2e7565..50a2bd9 100644
--- a/packages/core/dialog/CHANGELOG.md
+++ b/packages/core/dialog/CHANGELOG.md
@@ -1,5 +1,63 @@
# @dunky.dev/dialog
+## 0.2.0
+
+### Minor Changes
+
+- [#27](https://github.com/dunky-dev/ui/pull/27) [`f0d5ca4`](https://github.com/dunky-dev/ui/commit/f0d5ca4432774f5f88c1f0cc54ad7410a3c7d2fb) Thanks [@ivanbanov](https://github.com/ivanbanov)! - Add `closeOnBack` — the host's Back navigation closes the open dialog instead
+ of leaving the page, the pattern mobile users expect from a full-screen
+ overlay. Off by default.
+
+ ```tsx
+
+ ```
+
+ It follows the shared dismissal contract: `onBackNavigation` fires first and
+ `preventDefault()` vetoes, a controlled dialog only records the intent (close
+ it from your own state as usual), a nested stack unwinds one layer per Back
+ press, and it composes with `animated` (Back plays the exit animation). The
+ decision — gate, veto, controlled — lives once in the core's `backNavigate`;
+ substrates only wire their host's mechanics to it.
+
+ The web mechanics ship as their own framework-free util,
+ `@dunky.dev/dom-navigation` (`interceptBackNavigation`) — a session
+ history guard any overlaid layer can use, not just the dialog: opening
+ plants a guard entry in the session history and Back consumes it. A dialog
+ closed any other way consumes its own entry too, so no leftover ever swallows
+ a later Back press — including across reopen races (React StrictMode's
+ double-invoked effects adopt the entry in place rather than queueing a
+ history traversal, which browsers don't reliably deliver once another entry
+ is pushed).
+
+- [#26](https://github.com/dunky-dev/ui/pull/26) [`f4628e7`](https://github.com/dunky-dev/ui/commit/f4628e733f657695099b54991bd29c0487293557) Thanks [@ivanbanov](https://github.com/ivanbanov)! - Add exit-animation support via a new `animated` option. An animated dialog
+ closes through a `closing` state — every part carries it as
+ `data-state="closing"`, the styling hook for the exit — and unmounts when its
+ transition or animation on Content ends (with a fallback ceiling, and skipped
+ entirely under `prefers-reduced-motion`).
+
+ ```tsx
+
+ ```
+
+ ```css
+ [data-state='closing'] {
+ opacity: 0;
+ transition: opacity 150ms;
+ }
+ ```
+
+ The exit window lives in the core machine, not in per-substrate unmount
+ deferral, so reopening mid-exit is a named transition instead of a timing
+ race, and every substrate inherits identical behavior. The exit is cosmetic
+ by design: the close is reported, focus returns, and the page becomes
+ interactive the moment closing starts — the still-painting layer is made
+ `inert` until it leaves. Enter animations need no option: parts mount
+ straight into `data-state="open"`, so CSS animations (or transitions via
+ `@starting-style`) play from mount. Default (`animated: false`) behavior is
+ unchanged.
+
## 0.1.0
### Minor Changes
diff --git a/packages/core/dialog/package.json b/packages/core/dialog/package.json
index a17ec59..357ead8 100644
--- a/packages/core/dialog/package.json
+++ b/packages/core/dialog/package.json
@@ -1,6 +1,6 @@
{
"name": "@dunky.dev/dialog",
- "version": "0.1.0",
+ "version": "0.2.0",
"description": "Framework-agnostic dialog interaction, modeled as a state machine.",
"license": "MIT",
"repository": {
diff --git a/packages/core/utils/overlay/CHANGELOG.md b/packages/core/utils/overlay/CHANGELOG.md
new file mode 100644
index 0000000..7c1944f
--- /dev/null
+++ b/packages/core/utils/overlay/CHANGELOG.md
@@ -0,0 +1,28 @@
+# @dunky.dev/overlay
+
+## 0.1.0
+
+### Minor Changes
+
+- [#29](https://github.com/dunky-dev/ui/pull/29) [`89ed3f7`](https://github.com/dunky-dev/ui/commit/89ed3f7f9c1e5c6909ff2cfaa4c5ed952846518e) Thanks [@ivanbanov](https://github.com/ivanbanov)! - Add `@dunky.dev/overlay` and `@dunky.dev/dom-overlay` — the shared overlay
+ coordination the whole overlay family (dialog, drawer, alert-dialog, popover,
+ menu, combobox) builds on, so the behavior is implemented once instead of
+ forked per primitive.
+ - `@dunky.dev/overlay` is the agnostic half: a stack of open layers and the
+ rule for which is topmost (deepest nesting, open order breaking ties). No
+ DOM, no framework — a future native substrate reuses it.
+ - `@dunky.dev/dom-overlay` is the DOM realization on top of it: the layer
+ stack wired to assistive-tech containment (`aria-hidden` + `inert`), the
+ exit window (`hideExitingLayer` / `watchExitAnimation`), and initial focus
+ (`getInitialFocus`).
+
+ ```ts
+ import { createLayerStack, type OverlayLayer } from '@dunky.dev/overlay'
+ import { registerLayer, isTopmostLayer } from '@dunky.dev/dom-overlay'
+ ```
+
+ This replaces `@dunky.dev/dom-dialog`, which is removed — its behavior was
+ never dialog-specific, only its name was. `@dunky.dev/react-dialog` now
+ consumes `@dunky.dev/dom-overlay`; its public API and behavior are unchanged
+ (`registerDialog` / `isTopmostDialog` become `registerLayer` /
+ `isTopmostLayer` internally).
diff --git a/packages/core/utils/overlay/package.json b/packages/core/utils/overlay/package.json
index 3c47e11..ebe012a 100644
--- a/packages/core/utils/overlay/package.json
+++ b/packages/core/utils/overlay/package.json
@@ -1,6 +1,6 @@
{
"name": "@dunky.dev/overlay",
- "version": "0.0.0",
+ "version": "0.1.0",
"description": "Agnostic overlay-layer stack: registration and topmost resolution, shared by every overlay primitive across substrates.",
"license": "MIT",
"repository": {
diff --git a/packages/dom/utils/navigation/CHANGELOG.md b/packages/dom/utils/navigation/CHANGELOG.md
new file mode 100644
index 0000000..09405d7
--- /dev/null
+++ b/packages/dom/utils/navigation/CHANGELOG.md
@@ -0,0 +1,32 @@
+# @dunky.dev/dom-navigation
+
+## 0.1.0
+
+### Minor Changes
+
+- [#27](https://github.com/dunky-dev/ui/pull/27) [`f0d5ca4`](https://github.com/dunky-dev/ui/commit/f0d5ca4432774f5f88c1f0cc54ad7410a3c7d2fb) Thanks [@ivanbanov](https://github.com/ivanbanov)! - Add `closeOnBack` — the host's Back navigation closes the open dialog instead
+ of leaving the page, the pattern mobile users expect from a full-screen
+ overlay. Off by default.
+
+ ```tsx
+
+ ```
+
+ It follows the shared dismissal contract: `onBackNavigation` fires first and
+ `preventDefault()` vetoes, a controlled dialog only records the intent (close
+ it from your own state as usual), a nested stack unwinds one layer per Back
+ press, and it composes with `animated` (Back plays the exit animation). The
+ decision — gate, veto, controlled — lives once in the core's `backNavigate`;
+ substrates only wire their host's mechanics to it.
+
+ The web mechanics ship as their own framework-free util,
+ `@dunky.dev/dom-navigation` (`interceptBackNavigation`) — a session
+ history guard any overlaid layer can use, not just the dialog: opening
+ plants a guard entry in the session history and Back consumes it. A dialog
+ closed any other way consumes its own entry too, so no leftover ever swallows
+ a later Back press — including across reopen races (React StrictMode's
+ double-invoked effects adopt the entry in place rather than queueing a
+ history traversal, which browsers don't reliably deliver once another entry
+ is pushed).
diff --git a/packages/dom/utils/navigation/package.json b/packages/dom/utils/navigation/package.json
index 06af306..2c9769a 100644
--- a/packages/dom/utils/navigation/package.json
+++ b/packages/dom/utils/navigation/package.json
@@ -1,6 +1,6 @@
{
"name": "@dunky.dev/dom-navigation",
- "version": "0.0.0",
+ "version": "0.1.0",
"description": "Framework-free browser-navigation helpers: a session-history guard so the host's Back dismisses a layer instead of leaving the page.",
"license": "MIT",
"repository": {
diff --git a/packages/dom/utils/overlay/CHANGELOG.md b/packages/dom/utils/overlay/CHANGELOG.md
new file mode 100644
index 0000000..8074c19
--- /dev/null
+++ b/packages/dom/utils/overlay/CHANGELOG.md
@@ -0,0 +1,60 @@
+# @dunky.dev/dom-overlay
+
+## 0.1.0
+
+### Minor Changes
+
+- [#26](https://github.com/dunky-dev/ui/pull/26) [`f4628e7`](https://github.com/dunky-dev/ui/commit/f4628e733f657695099b54991bd29c0487293557) Thanks [@ivanbanov](https://github.com/ivanbanov)! - Add exit-animation support via a new `animated` option. An animated dialog
+ closes through a `closing` state — every part carries it as
+ `data-state="closing"`, the styling hook for the exit — and unmounts when its
+ transition or animation on Content ends (with a fallback ceiling, and skipped
+ entirely under `prefers-reduced-motion`).
+
+ ```tsx
+
+ ```
+
+ ```css
+ [data-state='closing'] {
+ opacity: 0;
+ transition: opacity 150ms;
+ }
+ ```
+
+ The exit window lives in the core machine, not in per-substrate unmount
+ deferral, so reopening mid-exit is a named transition instead of a timing
+ race, and every substrate inherits identical behavior. The exit is cosmetic
+ by design: the close is reported, focus returns, and the page becomes
+ interactive the moment closing starts — the still-painting layer is made
+ `inert` until it leaves. Enter animations need no option: parts mount
+ straight into `data-state="open"`, so CSS animations (or transitions via
+ `@starting-style`) play from mount. Default (`animated: false`) behavior is
+ unchanged.
+
+- [#29](https://github.com/dunky-dev/ui/pull/29) [`89ed3f7`](https://github.com/dunky-dev/ui/commit/89ed3f7f9c1e5c6909ff2cfaa4c5ed952846518e) Thanks [@ivanbanov](https://github.com/ivanbanov)! - Add `@dunky.dev/overlay` and `@dunky.dev/dom-overlay` — the shared overlay
+ coordination the whole overlay family (dialog, drawer, alert-dialog, popover,
+ menu, combobox) builds on, so the behavior is implemented once instead of
+ forked per primitive.
+ - `@dunky.dev/overlay` is the agnostic half: a stack of open layers and the
+ rule for which is topmost (deepest nesting, open order breaking ties). No
+ DOM, no framework — a future native substrate reuses it.
+ - `@dunky.dev/dom-overlay` is the DOM realization on top of it: the layer
+ stack wired to assistive-tech containment (`aria-hidden` + `inert`), the
+ exit window (`hideExitingLayer` / `watchExitAnimation`), and initial focus
+ (`getInitialFocus`).
+
+ ```ts
+ import { createLayerStack, type OverlayLayer } from '@dunky.dev/overlay'
+ import { registerLayer, isTopmostLayer } from '@dunky.dev/dom-overlay'
+ ```
+
+ This replaces `@dunky.dev/dom-dialog`, which is removed — its behavior was
+ never dialog-specific, only its name was. `@dunky.dev/react-dialog` now
+ consumes `@dunky.dev/dom-overlay`; its public API and behavior are unchanged
+ (`registerDialog` / `isTopmostDialog` become `registerLayer` /
+ `isTopmostLayer` internally).
+
+### Patch Changes
+
+- Updated dependencies [[`89ed3f7`](https://github.com/dunky-dev/ui/commit/89ed3f7f9c1e5c6909ff2cfaa4c5ed952846518e)]:
+ - @dunky.dev/overlay@0.1.0
diff --git a/packages/dom/utils/overlay/package.json b/packages/dom/utils/overlay/package.json
index 01d08b5..151860c 100644
--- a/packages/dom/utils/overlay/package.json
+++ b/packages/dom/utils/overlay/package.json
@@ -1,6 +1,6 @@
{
"name": "@dunky.dev/dom-overlay",
- "version": "0.0.0",
+ "version": "0.1.0",
"description": "Framework-free DOM behavior for overlay substrates: the shared layer stack with assistive-tech containment, the exit window, and initial focus.",
"license": "MIT",
"repository": {
diff --git a/packages/react/dialog/CHANGELOG.md b/packages/react/dialog/CHANGELOG.md
index c2e169e..b495c61 100644
--- a/packages/react/dialog/CHANGELOG.md
+++ b/packages/react/dialog/CHANGELOG.md
@@ -1,5 +1,104 @@
# @dunky.dev/react-dialog
+## 0.2.0
+
+### Minor Changes
+
+- [#27](https://github.com/dunky-dev/ui/pull/27) [`f0d5ca4`](https://github.com/dunky-dev/ui/commit/f0d5ca4432774f5f88c1f0cc54ad7410a3c7d2fb) Thanks [@ivanbanov](https://github.com/ivanbanov)! - Add `closeOnBack` — the host's Back navigation closes the open dialog instead
+ of leaving the page, the pattern mobile users expect from a full-screen
+ overlay. Off by default.
+
+ ```tsx
+
+ ```
+
+ It follows the shared dismissal contract: `onBackNavigation` fires first and
+ `preventDefault()` vetoes, a controlled dialog only records the intent (close
+ it from your own state as usual), a nested stack unwinds one layer per Back
+ press, and it composes with `animated` (Back plays the exit animation). The
+ decision — gate, veto, controlled — lives once in the core's `backNavigate`;
+ substrates only wire their host's mechanics to it.
+
+ The web mechanics ship as their own framework-free util,
+ `@dunky.dev/dom-navigation` (`interceptBackNavigation`) — a session
+ history guard any overlaid layer can use, not just the dialog: opening
+ plants a guard entry in the session history and Back consumes it. A dialog
+ closed any other way consumes its own entry too, so no leftover ever swallows
+ a later Back press — including across reopen races (React StrictMode's
+ double-invoked effects adopt the entry in place rather than queueing a
+ history traversal, which browsers don't reliably deliver once another entry
+ is pushed).
+
+- [#26](https://github.com/dunky-dev/ui/pull/26) [`f4628e7`](https://github.com/dunky-dev/ui/commit/f4628e733f657695099b54991bd29c0487293557) Thanks [@ivanbanov](https://github.com/ivanbanov)! - Add exit-animation support via a new `animated` option. An animated dialog
+ closes through a `closing` state — every part carries it as
+ `data-state="closing"`, the styling hook for the exit — and unmounts when its
+ transition or animation on Content ends (with a fallback ceiling, and skipped
+ entirely under `prefers-reduced-motion`).
+
+ ```tsx
+
+ ```
+
+ ```css
+ [data-state='closing'] {
+ opacity: 0;
+ transition: opacity 150ms;
+ }
+ ```
+
+ The exit window lives in the core machine, not in per-substrate unmount
+ deferral, so reopening mid-exit is a named transition instead of a timing
+ race, and every substrate inherits identical behavior. The exit is cosmetic
+ by design: the close is reported, focus returns, and the page becomes
+ interactive the moment closing starts — the still-painting layer is made
+ `inert` until it leaves. Enter animations need no option: parts mount
+ straight into `data-state="open"`, so CSS animations (or transitions via
+ `@starting-style`) play from mount. Default (`animated: false`) behavior is
+ unchanged.
+
+### Patch Changes
+
+- [#26](https://github.com/dunky-dev/ui/pull/26) [`0e259c6`](https://github.com/dunky-dev/ui/commit/0e259c6a7e6fa0e032ecce094820db6dc4319734) Thanks [@ivanbanov](https://github.com/ivanbanov)! - A modal dialog no longer marks its own backdrop `aria-hidden` + `inert`. The
+ assistive-tech containment walks up from the dialog window and hides every
+ sibling along the way — and the backdrop is portalled alongside the viewport,
+ outside the window's subtree yet part of the same layer, so the topmost
+ dialog was hiding its own backdrop. `inert` blocks pointer hit-testing, so
+ pressing the backdrop to dismiss silently did nothing in a real browser
+ (test-runner `.click()` bypasses hit-testing, which is why suites never
+ caught it). A dialog's layer now excepts its own backdrop from the
+ containment; everything beneath the topmost layer — lower dialogs' backdrops
+ included — stays hidden and inert as before.
+
+- [#29](https://github.com/dunky-dev/ui/pull/29) [`89ed3f7`](https://github.com/dunky-dev/ui/commit/89ed3f7f9c1e5c6909ff2cfaa4c5ed952846518e) Thanks [@ivanbanov](https://github.com/ivanbanov)! - Add `@dunky.dev/overlay` and `@dunky.dev/dom-overlay` — the shared overlay
+ coordination the whole overlay family (dialog, drawer, alert-dialog, popover,
+ menu, combobox) builds on, so the behavior is implemented once instead of
+ forked per primitive.
+ - `@dunky.dev/overlay` is the agnostic half: a stack of open layers and the
+ rule for which is topmost (deepest nesting, open order breaking ties). No
+ DOM, no framework — a future native substrate reuses it.
+ - `@dunky.dev/dom-overlay` is the DOM realization on top of it: the layer
+ stack wired to assistive-tech containment (`aria-hidden` + `inert`), the
+ exit window (`hideExitingLayer` / `watchExitAnimation`), and initial focus
+ (`getInitialFocus`).
+
+ ```ts
+ import { createLayerStack, type OverlayLayer } from '@dunky.dev/overlay'
+ import { registerLayer, isTopmostLayer } from '@dunky.dev/dom-overlay'
+ ```
+
+ This replaces `@dunky.dev/dom-dialog`, which is removed — its behavior was
+ never dialog-specific, only its name was. `@dunky.dev/react-dialog` now
+ consumes `@dunky.dev/dom-overlay`; its public API and behavior are unchanged
+ (`registerDialog` / `isTopmostDialog` become `registerLayer` /
+ `isTopmostLayer` internally).
+
+- Updated dependencies [[`f0d5ca4`](https://github.com/dunky-dev/ui/commit/f0d5ca4432774f5f88c1f0cc54ad7410a3c7d2fb), [`f4628e7`](https://github.com/dunky-dev/ui/commit/f4628e733f657695099b54991bd29c0487293557), [`89ed3f7`](https://github.com/dunky-dev/ui/commit/89ed3f7f9c1e5c6909ff2cfaa4c5ed952846518e)]:
+ - @dunky.dev/dialog@0.2.0
+ - @dunky.dev/dom-navigation@0.1.0
+ - @dunky.dev/dom-overlay@0.1.0
+
## 0.1.0
### Minor Changes
diff --git a/packages/react/dialog/package.json b/packages/react/dialog/package.json
index 1b2ef19..d9c035e 100644
--- a/packages/react/dialog/package.json
+++ b/packages/react/dialog/package.json
@@ -1,6 +1,6 @@
{
"name": "@dunky.dev/react-dialog",
- "version": "0.1.0",
+ "version": "0.2.0",
"description": "React binding for @dunky.dev/dialog.",
"license": "MIT",
"repository": {