Skip to content

feat(vue): the Vue substrate, opening with Dialog - #38

Draft
ivanbanov wants to merge 2 commits into
mainfrom
vue-dialog
Draft

feat(vue): the Vue substrate, opening with Dialog#38
ivanbanov wants to merge 2 commits into
mainfrom
vue-dialog

Conversation

@ivanbanov

Copy link
Copy Markdown
Member

🚧 Blocked on dunky-dev/state-machine#33@dunky.dev/vue-state-machine must publish first. The lockfile is deliberately not committed; once the adapter is on npm, run pnpm install and commit the refreshed pnpm-lock.yaml (until then CI's install step will fail on the 404).

What

The third web-facing substrate: packages/vue, opening with Dialog. One core machine, a new host — behavior and a11y come from @dunky.dev/dialog; this binding only renders and wires the DOM concerns, per the architecture.

@dunky.dev/vue-dialog

The compound component (Dialog + Trigger / Portal / Backdrop / Viewport / Content / Title / Description / Close), hanging off the root so <script setup>'s dot-notation brings the whole compound with one import. The surface is Vue's native shape:

  • Core options are props; core callbacks are emits. onOpenChange is update:open, so v-model:open is the controlled contract. Dismissal emits (@escape-key-down, @interact-outside, @back-navigation) carry preventDefault() — listeners run synchronously, so the veto contract holds unchanged.
  • Content's initialFocus is a MaybeRefOrGetter<HTMLElement | null>, resolved at open time — the Vue idiom for template refs that fill after setup.
  • Portal is a Teleport gated on the core's mounted (so animated exits play through closing); scoped containers redirect the scroll lock, same as React.

@dunky.dev/vue-use-focus-trap / @dunky.dev/vue-use-scroll-lock

The Vue lifecycle wrappers over the framework-free DOM utils. The trap follows the target ref (template refs fill after setup, so binding follows the element, not the call site); the lock takes MaybeRefOrGetter for both parameters.

Substrate infra

  • @dunky-dev/vue private harness: Storybook (vue3-vite) on port 6007 via pnpm dev:vue, stories written with h() so no SFC tooling enters the build chain.
  • The story set mirrors the React scenarios one-for-one: standard, alertDialog, longContent, loginForm, trigger, controlled, scoped, nested, closeOnBack.
  • scripts/templates/packages/vuepnpm scaffold <name> now stamps the Vue substrate too.
  • Root wiring: tsconfig paths, tsdown workspace, knip stories entry, minimumReleaseAgeExclude for the adapter's first publish.

Verification

  • The full React dialog behavior suite ported: 35 dialog tests (dismissal gating + vetoes, controlled contract, ARIA wiring, focus management, layer-stack containment, scroll-lock scoping, back navigation, exit animation, nesting) plus the two hook suites — 190 vitest + 13 native jest, all green locally against a packed tarball of the adapter from state-machine#33.
  • pnpm typecheck, pnpm lint, pnpm format:check, pnpm build (publint clean for all three new packages), and the Vue Storybook build all pass.
  • pnpm knip still reports the pre-existing native/expo noise from main; the new entries are the same mechanical class (jest moduleNameMapper paths, harness runtime dep) — left untouched since knip isn't a CI check.

🤖 Generated with Claude Code

ivanbanov and others added 2 commits August 14, 2026 12:23
A new substrate under packages/vue, delivering the dialog machine to Vue 3
with the same anatomy and behavior contract as the React binding:

- @dunky.dev/vue-dialog — the compound component (Trigger, Portal, Backdrop,
  Viewport, Content, Title, Description, Close) in Vue's native shape: core
  options as props, core callbacks as emits, v-model:open as the controlled
  contract. Content's initialFocus takes a MaybeRefOrGetter, resolved at
  open time so late-filling template refs work.
- @dunky.dev/vue-use-focus-trap / vue-use-scroll-lock — the Vue lifecycle
  wrappers over the framework-free DOM utils.
- @dunky-dev/vue — the private substrate harness (Storybook vue3-vite,
  pnpm dev:vue), with the story set mirroring the React scenarios.
- scripts/templates/packages/vue — the scaffold stamps future primitives
  into this substrate too.

The full React dialog behavior suite is ported (35 tests): dismissal
gating and vetoes, controlled contract, ARIA wiring, focus management,
layer stack containment, scroll lock scoping, back navigation, exit
animations, nesting.

Blocked on dunky-dev/state-machine#33: @dunky.dev/vue-state-machine is not
on npm yet, so the lockfile is not committed here — refresh it once the
adapter publishes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ster

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant