Skip to content

Commit 93d6c1b

Browse files
committed
fix(vue): presence integration
1 parent ec06999 commit 93d6c1b

File tree

13 files changed

+167
-125
lines changed

13 files changed

+167
-125
lines changed

bun.lock

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,6 @@
342342
"version": "5.26.2",
343343
"dependencies": {
344344
"@internationalized/date": "3.10.0",
345-
"@tanstack/vue-form": "1.23.7",
346345
"@zag-js/accordion": "1.26.3",
347346
"@zag-js/anatomy": "1.26.3",
348347
"@zag-js/angle-slider": "1.26.3",
@@ -425,6 +424,7 @@
425424
"lucide-vue-next": "0.546.0",
426425
"resize-observer-polyfill": "1.5.1",
427426
"typescript": "5.9.3",
427+
"vee-validate": "4.15.1",
428428
"vite": "7.1.11",
429429
"vite-plugin-dts": "4.5.4",
430430
"vitest": "3.2.4",
@@ -1472,10 +1472,6 @@
14721472

14731473
"@tanstack/svelte-store": ["@tanstack/[email protected]", "", { "dependencies": { "@tanstack/store": "0.7.7" }, "peerDependencies": { "svelte": "^5.0.0" } }, "sha512-JeDyY7SxBi6EKzkf2wWoghdaC2bvmwNL9X/dgkx7LKEvJVle+te7tlELI3cqRNGbjXt9sx+97jx9M5dCCHcuog=="],
14741474

1475-
"@tanstack/vue-form": ["@tanstack/[email protected]", "", { "dependencies": { "@tanstack/form-core": "1.24.3", "@tanstack/vue-store": "^0.7.7" }, "peerDependencies": { "vue": "^3.4.0" } }, "sha512-El0UKkXhHf+trz6SYvNzeeonSj5+ARMSMGOJh+ilmzN7hn5VE70wskQTFqE6P46NDETU4T1nxyu7bPiUcQIjZw=="],
1476-
1477-
"@tanstack/vue-store": ["@tanstack/[email protected]", "", { "dependencies": { "@tanstack/store": "0.7.7", "vue-demi": "^0.14.10" }, "peerDependencies": { "@vue/composition-api": "^1.2.1", "vue": "^2.5.0 || ^3.0.0" }, "optionalPeers": ["@vue/composition-api"] }, "sha512-6iv1Odmreff6TgEjQN11xoddsCnpn+/ul7MZ2DadHT3/RSY1YdoFafK8lCa889MEFi/5K0zAhf8psIkgTrRa9A=="],
1478-
14791475
"@testing-library/dom": ["@testing-library/[email protected]", "", { "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", "@types/aria-query": "^5.0.1", "aria-query": "5.3.0", "dom-accessibility-api": "^0.5.9", "lz-string": "^1.5.0", "picocolors": "1.1.1", "pretty-format": "^27.0.2" } }, "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg=="],
14801476

14811477
"@testing-library/jest-dom": ["@testing-library/[email protected]", "", { "dependencies": { "@adobe/css-tools": "^4.4.0", "aria-query": "^5.0.0", "css.escape": "^1.5.1", "dom-accessibility-api": "^0.6.3", "picocolors": "^1.1.1", "redent": "^3.0.0" } }, "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA=="],
@@ -4054,6 +4050,8 @@
40544050

40554051
"vary": ["[email protected]", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="],
40564052

4053+
"vee-validate": ["[email protected]", "", { "dependencies": { "@vue/devtools-api": "^7.5.2", "type-fest": "^4.8.3" }, "peerDependencies": { "vue": "^3.4.26" } }, "sha512-DkFsiTwEKau8VIxyZBGdO6tOudD+QoUBPuHj3e6QFqmbfCRj1ArmYWue9lEp6jLSWBIw4XPlDLjFIZNLdRAMSg=="],
4054+
40574055
"velite": ["[email protected]", "", { "dependencies": { "@mdx-js/mdx": "^3.1.0", "esbuild": "^0.25.9", "sharp": "^0.34.3", "terser": "^5.43.1" }, "bin": { "velite": "bin/velite.js" } }, "sha512-sEqIsdRwVmkkLaizUQy1vhTPukL24l6ggTvhy85zJoHaociBWOOJmbKScNpUuIBq7L55Yk2GxQuTF0glkRQSCA=="],
40584056

40594057
"vercel": ["[email protected]", "", { "dependencies": { "@vercel/blob": "1.0.2", "@vercel/build-utils": "12.1.3", "@vercel/detect-agent": "1.0.0", "@vercel/express": "0.0.26", "@vercel/fun": "1.1.6", "@vercel/go": "3.2.3", "@vercel/h3": "0.1.6", "@vercel/hono": "0.1.7", "@vercel/hydrogen": "1.2.4", "@vercel/next": "4.13.4", "@vercel/node": "5.4.1", "@vercel/python": "5.0.10", "@vercel/redwood": "2.3.6", "@vercel/remix-builder": "5.4.13", "@vercel/ruby": "2.2.1", "@vercel/static-build": "2.7.26", "chokidar": "4.0.0", "jose": "5.9.6" }, "bin": { "vc": "dist/vc.js", "vercel": "dist/vc.js" } }, "sha512-EzunA8iHf55CDM5CUQQYR2+xp+1n8AqJziuOJx19w8Io2aQK1NjsRhmsHsogw9zsQ3xpdofaCs4MTjPHFNhdtA=="],
@@ -4098,8 +4096,6 @@
40984096

40994097
"vue-component-type-helpers": ["[email protected]", "", {}, "sha512-YbGqHZ5/eW4SnkPNR44mKVc6ZKQoRs/Rux1sxC6rdwXb4qpbOSYfDr9DsTHolOTGmIKgM9j141mZbBeg05R1pw=="],
41004098

4101-
"vue-demi": ["[email protected]", "", { "peerDependencies": { "@vue/composition-api": "^1.0.0-rc.1", "vue": "^3.0.0-0 || ^2.6.0" }, "optionalPeers": ["@vue/composition-api"], "bin": { "vue-demi-fix": "bin/vue-demi-fix.js", "vue-demi-switch": "bin/vue-demi-switch.js" } }, "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg=="],
4102-
41034099
"vue-devtools-stub": ["[email protected]", "", {}, "sha512-RutnB7X8c5hjq39NceArgXg28WZtZpGc3+J16ljMiYnFhKvd8hITxSWQSQ5bvldxMDU6gG5mkxl1MTQLXckVSQ=="],
41044100

41054101
"vue-router": ["[email protected]", "", { "dependencies": { "@vue/devtools-api": "^6.6.4" }, "peerDependencies": { "vue": "^3.5.0" } }, "sha512-ARBedLm9YlbvQomnmq91Os7ck6efydTSpRP3nuOKCvgJOHNrhRoJDSKtee8kcL1Vf7nz6U+PMBL+hTvR3bTVQg=="],
@@ -4986,6 +4982,10 @@
49864982

49874983
"update-browserslist-db/escalade": ["[email protected]", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
49884984

4985+
"vee-validate/@vue/devtools-api": ["@vue/[email protected]", "", { "dependencies": { "@vue/devtools-kit": "^7.7.7" } }, "sha512-lwOnNBH2e7x1fIIbVT7yF5D+YWhqELm55/4ZKf45R9T8r9dE2AIOy8HKjfqzGsoTHFbWbr337O4E0A0QADnjBg=="],
4986+
4987+
"vee-validate/type-fest": ["[email protected]", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="],
4988+
49894989
"vinxi/chokidar": ["[email protected]", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
49904990

49914991
"vinxi/h3": ["[email protected]", "", { "dependencies": { "cookie-es": "^1.2.2", "crossws": "^0.3.4", "defu": "^6.1.4", "destr": "^2.0.5", "iron-webcrypto": "^1.2.1", "node-mock-http": "^1.0.0", "radix3": "^1.1.2", "ufo": "^1.6.1", "uncrypto": "^0.1.3" } }, "sha512-z6GknHqyX0h9aQaTx22VZDf6QyZn+0Nh+Ym8O/u0SGSkyF5cuTJYKlc8MkzW3Nzf9LE1ivcpmYC3FUGpywhuUQ=="],

packages/vue/CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
## [Unreleased]
22

3+
### Fixed
4+
5+
- **Dialog**: Fix issue where `Dialog.Backdrop` does not respect exit animations when closing. The backdrop now properly
6+
uses the presence composable to enable CSS transitions and animations on close.
7+
8+
- **Bottom Sheet**: Fix issue where `BottomSheet.Backdrop` does not respect exit animations when closing.
9+
10+
- **Tour**: Fix issue where `Tour.Backdrop` does not respect exit animations when closing.
11+
12+
- **Tabs**: Fix issue where `Tab.Content` does not respect exit animations when switching tabs.
13+
314
## [5.26.2] - 2025-10-18
415

516
### Fixed

packages/vue/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@
8484
"sideEffects": false,
8585
"dependencies": {
8686
"@internationalized/date": "3.10.0",
87-
"@tanstack/vue-form": "1.23.7",
8887
"@zag-js/accordion": "1.26.3",
8988
"@zag-js/anatomy": "1.26.3",
9089
"@zag-js/angle-slider": "1.26.3",
@@ -167,6 +166,7 @@
167166
"lucide-vue-next": "0.546.0",
168167
"resize-observer-polyfill": "1.5.1",
169168
"typescript": "5.9.3",
169+
"vee-validate": "4.15.1",
170170
"vite": "7.1.11",
171171
"vite-plugin-dts": "4.5.4",
172172
"vitest": "3.2.4",

packages/vue/src/components/bottom-sheet/bottom-sheet-backdrop.vue

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,25 +12,33 @@ export interface BottomSheetBackdropProps
1212
</script>
1313

1414
<script setup lang="ts">
15+
import { mergeProps } from '@zag-js/vue'
16+
import { computed } from 'vue'
1517
import { useForwardExpose } from '../../utils/use-forward-expose'
1618
import { useRenderStrategyProps } from '../../utils/use-render-strategy'
17-
import { Presence } from '../presence'
19+
import { usePresence } from '../presence'
20+
import { ark } from '../factory'
1821
import { useBottomSheetContext } from './use-bottom-sheet-context'
1922
2023
defineProps<BottomSheetBackdropProps>()
24+
2125
const bottomSheet = useBottomSheetContext()
2226
const renderStrategy = useRenderStrategyProps()
2327
28+
const presence = usePresence(
29+
computed(() => ({
30+
...renderStrategy.value,
31+
present: bottomSheet.value.open,
32+
})),
33+
)
34+
35+
const mergedProps = computed(() => mergeProps(bottomSheet.value.getBackdropProps(), presence.value.presenceProps))
36+
2437
useForwardExpose()
2538
</script>
2639

2740
<template>
28-
<Presence
29-
v-bind="bottomSheet.getBackdropProps()"
30-
:present="bottomSheet.open"
31-
:lazy-mount="renderStrategy.lazyMount"
32-
:unmount-on-exit="renderStrategy.unmountOnExit"
33-
>
41+
<ark.div v-if="!presence.unmounted" v-bind="mergedProps" :as-child="asChild">
3442
<slot />
35-
</Presence>
43+
</ark.div>
3644
</template>

packages/vue/src/components/dialog/dialog-backdrop.vue

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,25 +12,33 @@ export interface DialogBackdropProps
1212
</script>
1313

1414
<script setup lang="ts">
15+
import { mergeProps } from '@zag-js/vue'
16+
import { computed } from 'vue'
1517
import { useRenderStrategyProps } from '../../utils/use-render-strategy'
1618
import { useForwardExpose } from '../../utils/use-forward-expose'
17-
import { Presence } from '../presence'
19+
import { usePresence } from '../presence'
20+
import { ark } from '../factory'
1821
import { useDialogContext } from './use-dialog-context'
1922
2023
defineProps<DialogBackdropProps>()
24+
2125
const dialog = useDialogContext()
2226
const renderStrategy = useRenderStrategyProps()
2327
28+
const presence = usePresence(
29+
computed(() => ({
30+
...renderStrategy.value,
31+
present: dialog.value.open,
32+
})),
33+
)
34+
35+
const mergedProps = computed(() => mergeProps(dialog.value.getBackdropProps(), presence.value.presenceProps))
36+
2437
useForwardExpose()
2538
</script>
2639

2740
<template>
28-
<Presence
29-
v-bind="dialog.getBackdropProps()"
30-
:present="dialog.open"
31-
:lazy-mount="renderStrategy.lazyMount"
32-
:unmount-on-exit="renderStrategy.unmountOnExit"
33-
>
41+
<ark.div v-if="!presence.unmounted" v-bind="mergedProps" :as-child="asChild">
3442
<slot />
35-
</Presence>
43+
</ark.div>
3644
</template>

packages/vue/src/components/select/examples/form-library.vue

Lines changed: 41 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,59 @@
11
<script setup lang="ts">
22
import { Select, createListCollection } from '@ark-ui/vue/select'
3-
import { useForm } from '@tanstack/vue-form'
3+
import { useForm, useField } from 'vee-validate'
44
import { ChevronDownIcon } from 'lucide-vue-next'
55
66
const collection = createListCollection({
77
items: ['React', 'Solid', 'Vue', 'Svelte'],
88
})
99
10-
const form = useForm({
11-
defaultValues: {
10+
const { handleSubmit, values } = useForm({
11+
initialValues: {
1212
framework: 'Vue',
1313
},
14-
onSubmit: async ({ value }) => {
15-
window.alert(JSON.stringify(value))
16-
},
14+
})
15+
16+
const { value: framework, setValue } = useField<string>('framework')
17+
18+
const onSubmit = handleSubmit((values) => {
19+
window.alert(JSON.stringify(values))
1720
})
1821
</script>
1922

2023
<template>
2124
<div>
22-
<div>Value is {{ form.state.values.framework }}</div>
23-
<form
24-
@submit="
25-
(e) => {
26-
e.preventDefault()
27-
form.handleSubmit()
28-
}
29-
"
30-
>
31-
<form.Field name="framework">
32-
<template #default="{ field }">
33-
<Select.Root
34-
:collection="collection"
35-
:model-value="field.state.value ? [field.state.value] : []"
36-
@value-change="(e) => field.handleChange(e.value[0])"
37-
>
38-
<Select.Label>Framework</Select.Label>
39-
<Select.Control>
40-
<Select.Trigger>
41-
<Select.ValueText placeholder="Select a Framework" />
42-
<Select.Indicator>
43-
<ChevronDownIcon />
44-
</Select.Indicator>
45-
</Select.Trigger>
46-
<Select.ClearTrigger>Clear</Select.ClearTrigger>
47-
</Select.Control>
48-
<Teleport to="body">
49-
<Select.Positioner>
50-
<Select.Content>
51-
<Select.ItemGroup>
52-
<Select.ItemGroupLabel>Frameworks</Select.ItemGroupLabel>
53-
<Select.Item v-for="item in collection.items" :key="item" :item="item">
54-
<Select.ItemText>{{ item }}</Select.ItemText>
55-
<Select.ItemIndicator>✓</Select.ItemIndicator>
56-
</Select.Item>
57-
</Select.ItemGroup>
58-
</Select.Content>
59-
</Select.Positioner>
60-
</Teleport>
61-
<Select.HiddenSelect :name="field.name" />
62-
</Select.Root>
63-
</template>
64-
</form.Field>
25+
<div>Value is {{ values.framework }}</div>
26+
<form @submit="onSubmit">
27+
<Select.Root
28+
:collection="collection"
29+
:model-value="framework ? [framework] : []"
30+
@value-change="(e) => setValue(e.value[0])"
31+
>
32+
<Select.Label>Framework</Select.Label>
33+
<Select.Control>
34+
<Select.Trigger>
35+
<Select.ValueText placeholder="Select a Framework" />
36+
<Select.Indicator>
37+
<ChevronDownIcon />
38+
</Select.Indicator>
39+
</Select.Trigger>
40+
<Select.ClearTrigger>Clear</Select.ClearTrigger>
41+
</Select.Control>
42+
<Teleport to="body">
43+
<Select.Positioner>
44+
<Select.Content>
45+
<Select.ItemGroup>
46+
<Select.ItemGroupLabel>Frameworks</Select.ItemGroupLabel>
47+
<Select.Item v-for="item in collection.items" :key="item" :item="item">
48+
<Select.ItemText>{{ item }}</Select.ItemText>
49+
<Select.ItemIndicator>✓</Select.ItemIndicator>
50+
</Select.Item>
51+
</Select.ItemGroup>
52+
</Select.Content>
53+
</Select.Positioner>
54+
</Teleport>
55+
<Select.HiddenSelect name="framework" />
56+
</Select.Root>
6557
<button type="submit">Submit</button>
6658
</form>
6759
</div>

packages/vue/src/components/tabs/tab-content.vue

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,36 @@ export interface TabContentProps
1313
</script>
1414

1515
<script setup lang="ts">
16+
import { mergeProps } from '@zag-js/vue'
17+
import { computed } from 'vue'
1618
import { useForwardExpose } from '../../utils/use-forward-expose'
1719
import { useRenderStrategyProps } from '../../utils/use-render-strategy'
1820
import { useTabsContext } from './use-tabs-context'
19-
import { Presence } from '../presence'
21+
import { PresenceProvider, usePresence } from '../presence'
22+
import { ark } from '../factory'
2023
2124
const props = defineProps<TabContentProps>()
25+
2226
const tabs = useTabsContext()
2327
const renderStrategy = useRenderStrategyProps()
2428
29+
const presence = usePresence(
30+
computed(() => ({
31+
...renderStrategy.value,
32+
present: tabs.value.value === props.value,
33+
immediate: true,
34+
})),
35+
)
36+
37+
PresenceProvider(presence)
38+
39+
const mergedProps = computed(() => mergeProps(tabs.value.getContentProps(props), presence.value.presenceProps))
40+
2541
useForwardExpose()
2642
</script>
2743

2844
<template>
29-
<Presence
30-
v-bind="tabs.getContentProps(props)"
31-
:present="tabs.value === props.value"
32-
:lazy-mount="renderStrategy.lazyMount"
33-
:unmount-on-exit="renderStrategy.unmountOnExit"
34-
:immediate="true"
35-
>
45+
<ark.div v-if="!presence.unmounted" v-bind="mergedProps" :as-child="asChild">
3646
<slot />
37-
</Presence>
47+
</ark.div>
3848
</template>

packages/vue/src/components/tour/tour-backdrop.vue

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,27 +12,33 @@ export interface TourBackdropProps
1212
</script>
1313

1414
<script setup lang="ts">
15+
import { mergeProps } from '@zag-js/vue'
16+
import { computed } from 'vue'
1517
import { useRenderStrategyProps } from '../../utils/use-render-strategy'
1618
import { useForwardExpose } from '../../utils/use-forward-expose'
17-
import { Presence } from '../presence'
19+
import { usePresence } from '../presence'
20+
import { ark } from '../factory'
1821
import { useTourContext } from './use-tour-context'
1922
2023
defineProps<TourBackdropProps>()
24+
2125
const tour = useTourContext()
2226
const renderStrategy = useRenderStrategyProps()
2327
28+
const presence = usePresence(
29+
computed(() => ({
30+
...renderStrategy.value,
31+
present: tour.value.open,
32+
})),
33+
)
34+
35+
const mergedProps = computed(() => mergeProps(tour.value.getBackdropProps(), presence.value.presenceProps))
36+
2437
useForwardExpose()
2538
</script>
2639

2740
<template>
28-
<Presence
29-
v-if="tour.step?.backdrop"
30-
v-bind="tour.getBackdropProps()"
31-
:hidden="!tour.open"
32-
:present="tour.open"
33-
:lazy-mount="renderStrategy.lazyMount"
34-
:unmount-on-exit="renderStrategy.unmountOnExit"
35-
>
41+
<ark.div v-if="tour.step?.backdrop && !presence.unmounted" v-bind="mergedProps" :as-child="asChild">
3642
<slot />
37-
</Presence>
43+
</ark.div>
3844
</template>

templates/nuxt/app/app.vue

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
<script setup lang="ts">
2-
import Avatar from './components/avatar.vue'
3-
import FieldDemo from './components/field-demo.vue'
2+
import '../../../.storybook/styles.css'
43
</script>
54

65
<template>
76
<h1>Welcome to Ark UI!</h1>
8-
<Avatar name="Christian Schröter" src="https://avatars3.githubusercontent.com/u/1846056" />
9-
<FieldDemo />
7+
<NuxtPage />
108
</template>

0 commit comments

Comments
 (0)