Skip to content

Commit

Permalink
feat: introduce forceMount props
Browse files Browse the repository at this point in the history
  • Loading branch information
zernonia committed Oct 19, 2023
1 parent b6c1815 commit 3d51633
Show file tree
Hide file tree
Showing 25 changed files with 207 additions and 58 deletions.
13 changes: 11 additions & 2 deletions docs/content/components/accordion.md
Original file line number Diff line number Diff line change
Expand Up @@ -256,13 +256,22 @@ Toggles the collapsed state of its associated item. It should be nested inside o

Contains the collapsible content for an item.

<PropsTable :data="[{
<PropsTable :data="[
{
name: 'asChild',
required: false,
type: 'boolean',
default: 'false',
description: 'Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our <a href=&quot;/guides/composition&quot;>Composition</a> guide for more details.',
}]" />
},
{
name: 'forceMount',
type: 'boolean',
description: `
Used to force mounting when more control is needed. Useful when controlling animation with Vue.js animation libraries.
`,
},
]" />

<DataAttributesTable :data="[
{
Expand Down
32 changes: 24 additions & 8 deletions docs/content/components/alert-dialog.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,13 +155,22 @@ When used, portals your overlay and content parts into the <code>body</code>.

A layer that covers the inert portion of the view when the dialog is open.

<PropsTable :data="[{
name: 'asChild',
required: false,
type: 'boolean',
default: 'false',
description: 'Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our <a href=&quot;/guides/composition&quot;>Composition</a> guide for more details.',
}]" />
<PropsTable :data="[
{
name: 'asChild',
required: false,
type: 'boolean',
default: 'false',
description: 'Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our <a href=&quot;/guides/composition&quot;>Composition</a> guide for more details.',
},
{
name: 'forceMount',
type: 'boolean',
description: `
Used to force mounting when more control is needed. Useful when controlling animation with Vue.js animation libraries.
`,
},
]" />

<DataAttributesTable :data="[{
attribute: '[data-state]',
Expand All @@ -180,7 +189,14 @@ Contains content to be rendered when the dialog is open.
type: 'boolean',
default: 'false',
description: 'Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our <a href=&quot;/guides/composition&quot;>Composition</a> guide for more details.',
}
},
{
name: 'forceMount',
type: 'boolean',
description: `
Used to force mounting when more control is needed. Useful when controlling animation with Vue.js animation libraries.
`,
},
]"
/>

Expand Down
7 changes: 7 additions & 0 deletions docs/content/components/checkbox.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,13 @@ Renders when the checkbox is in a checked or indeterminate state. You can style
default: 'false',
description: 'Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our <a href=&quot;/guides/composition&quot;>Composition</a> guide for more details.',
},
{
name: 'forceMount',
type: 'boolean',
description: `
Used to force mounting when more control is needed. Useful when controlling animation with Vue.js animation libraries.
`,
},
]"
/>

Expand Down
16 changes: 15 additions & 1 deletion docs/content/components/dialog.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,13 @@ A layer that covers the inert portion of the view when the dialog is open.
default: 'false',
description: 'Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our <a href=&quot;/guides/composition&quot;>Composition</a> guide for more details.',
},
{
name: 'forceMount',
type: 'boolean',
description: `
Used to force mounting when more control is needed. Useful when controlling animation with Vue.js animation libraries.
`,
},
]"
/>

Expand All @@ -202,7 +209,14 @@ Contains content to be rendered in the open dialog
type: 'boolean',
default: 'false',
description: 'Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our <a href=&quot;/guides/composition&quot;>Composition</a> guide for more details.',
}
},
{
name: 'forceMount',
type: 'boolean',
description: `
Used to force mounting when more control is needed. Useful when controlling animation with Vue.js animation libraries.
`,
},
]"
/>

Expand Down
7 changes: 7 additions & 0 deletions docs/content/components/hover-card.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,13 @@ The component that pops out when the hover card is open.
default: 'false',
description: 'Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our <a href=&quot;/guides/composition&quot;>Composition</a> guide for more details.',
},
{
name: 'forceMount',
type: 'boolean',
description: `
Used to force mounting when more control is needed. Useful when controlling animation with Vue.js animation libraries.
`,
},
{
name: 'side',
type: '&quot;top&quot; | &quot;right&quot; | &quot;bottom&quot; | &quot;left&quot;',
Expand Down
7 changes: 7 additions & 0 deletions docs/content/components/popover.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,13 @@ The component that pops out when the popover is open.

<PropsTable
:data="[
{
name: 'forceMount',
type: 'boolean',
description: `
Used to force mounting when more control is needed. Useful when controlling animation with Vue.js animation libraries.
`,
},
{
name: 'side',
type: '&quot;top&quot; | &quot;right&quot; | &quot;bottom&quot; | &quot;left&quot;',
Expand Down
7 changes: 7 additions & 0 deletions docs/content/components/scroll-area.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,13 @@ The vertical scrollbar. Add a second `Scrollbar` with an `orientation` prop to e
default: 'false',
description: 'Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our <a href=&quot;/guides/composition&quot;>Composition</a> guide for more details.',
},
{
name: 'forceMount',
type: 'boolean',
description: `
Used to force mounting when more control is needed. Useful when controlling animation with Vue.js animation libraries.
`,
},
{
name: 'orientation',
required: false,
Expand Down
9 changes: 8 additions & 1 deletion docs/content/components/tooltip.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,11 +190,18 @@ The component that pops out when the tooltip is open.
<PropsTable
:data="[
{
name: 'aria-label',
name: 'ariaLabel',
required: false,
type: 'string',
description: 'By default, screenreaders will announce the content inside the component. If this is not descriptive enough, or you have content that cannot be announced, use <code>aria-label</code> as a more descriptive label.',
},
{
name: 'forceMount',
type: 'boolean',
description: `
Used to force mounting when more control is needed. Useful when controlling animation with Vue.js animation libraries.
`,
},
{
name: 'side',
type: '&quot;top&quot; | &quot;right&quot; | &quot;bottom&quot; | &quot;left&quot;',
Expand Down
38 changes: 19 additions & 19 deletions docs/content/guides/animation.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
---

title: Animation
description: Animate Radix Primitives with CSS keyframes or the JavaScript animation library of your choice.
title: Animation/Transition
description: Animate Radix Primitives with CSS keyframes, JavaScript animation library of your choice or Native Vue Transition.
---



# Animation

<Description>
Animate Radix Primitives with CSS keyframes or the JavaScript animation
library of your choice.
Animate Radix Primitives with CSS keyframes, JavaScript animation library of your choice or Native Vue Transition.
</Description>

Adding animation to Radix Primitives should feel similar to any other component, but there are some caveats noted here in regards to exiting animations with JS animation libraries.
Expand Down Expand Up @@ -51,34 +49,36 @@ You can use CSS animation to animate both mount and unmount phases. The latter i
}
```

::: info
<!-- ::: info
Source: [Radix UI](https://www.radix-ui.com/)
:::
::: -->

<!-- hide away for the moment, as we yet to support forceMount props
<EmbedIframe src="https://stackblitz.com/edit/vitejs-vite-y8mdxg?embed=1&file=index.html&view=preview" />

## Delegating unmounting for JavaScript Animation

When many stateful Primitives are hidden from view, they are actually removed from the React Tree, and their elements removed from the DOM. JavaScript animation libraries need control of the unmounting phase, so we provide the `forceMount` prop on many components to allow consumers to delegate the mounting and unmounting of children based on the animation state determined by those libraries.
When many stateful Primitives are hidden from view, they are actually removed from the DOM (similar to `v-if`). JavaScript animation libraries need control of the unmounting phase, so we provide the `forceMount` prop on many components to allow consumers to delegate the mounting and unmounting of children based on the animation state determined by those libraries.

For example, if you want to use React Spring to animate a `Dialog`, you would do so by conditionally rendering the dialog `Overlay` and `Content` parts based on the animation state from one of its hooks like `useTransition`:
For example, if you want to use [@vueuse/motion](https://motion.vueuse.org/) to animate a `Dialog`, you would do so by conditionally rendering the dialog `Overlay` and `Content` parts based on the animation state from one of its hooks like `useTransition`:

```jsx
import * as Dialog from '@radix-ui/react-dialog';
import { useTransition, animated, config } from 'react-spring';
import * as Dialog from '@radix-ui/react-dialog'
import { animated, config, useTransition } from 'react-spring'

function Example() {
const [open, setOpen] = React.useState(false);
const [open, setOpen] = React.useState(false)
const transitions = useTransition(open, {
from: { opacity: 0, y: -10 },
enter: { opacity: 1, y: 0 },
leave: { opacity: 0, y: 10 },
config: config.stiff,
});
})
return (
<Dialog.Root open={open} onOpenChange={setOpen}>
<Dialog.Trigger>Open Dialog</Dialog.Trigger>
{transitions((styles, item) =>
item ? (
item
? (
<>
<Dialog.Overlay forceMount asChild>
<animated.div
Expand All @@ -94,10 +94,10 @@ function Example() {
</animated.div>
</Dialog.Content>
</>
) : null
)
: null
)}
</Dialog.Root>
);
)
}
```
-->
```
4 changes: 4 additions & 0 deletions packages/radix-vue/src/Checkbox/CheckboxIndicator.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
<script lang="ts">
export interface CheckboxIndicatorProps extends PrimitiveProps {
/**
* Used to force mounting when more control is needed. Useful when
* controlling animation with Vue animation libraries.
*/
forceMount?: boolean
}
</script>
Expand Down
10 changes: 8 additions & 2 deletions packages/radix-vue/src/Collapsible/CollapsibleContent.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
<script lang="ts">
export interface CollapsibleContentProps extends PrimitiveProps {}
export interface CollapsibleContentProps extends PrimitiveProps {
/**
* Used to force mounting when more control is needed. Useful when
* controlling animation with Vue animation libraries.
*/
forceMount?: boolean
}
export default {
inheritAttrs: false,
}
Expand Down Expand Up @@ -72,7 +78,7 @@ onMounted(() => {
<template>
<Presence
ref="presentRef"
:present="rootContext.open.value"
:present="forceMount || rootContext.open.value"
:force-mount="true"
>
<Primitive
Expand Down
10 changes: 8 additions & 2 deletions packages/radix-vue/src/Combobox/ComboboxContent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ import ComboboxContentImpl, { type ComboboxContentImplEmits, type ComboboxConten
import { Presence } from '@/Presence'
import { useForwardPropsEmits } from '@/shared'
export interface ComboboxContentProps extends ComboboxContentImplProps {}
export interface ComboboxContentProps extends ComboboxContentImplProps {
/**
* Used to force mounting when more control is needed. Useful when
* controlling animation with Vue animation libraries.
*/
forceMount?: boolean
}
export type ComboboxContentEmits = ComboboxContentImplEmits
const props = defineProps<ComboboxContentProps>()
Expand All @@ -15,7 +21,7 @@ const rootContext = injectComboboxRootContext()
</script>

<template>
<Presence :present="rootContext.open.value">
<Presence :present="forceMount || rootContext.open.value">
<ComboboxContentImpl v-bind="{ ...forwarded, ...$attrs }">
<slot />
</ComboboxContentImpl>
Expand Down
10 changes: 8 additions & 2 deletions packages/radix-vue/src/Dialog/DialogContent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,20 @@ const emits = defineEmits<DialogContentEmits>()
const rootContext = injectDialogRootContext()
export interface DialogContentProps extends DialogContentImplProps {}
export interface DialogContentProps extends DialogContentImplProps {
/**
* Used to force mounting when more control is needed. Useful when
* controlling animation with Vue animation libraries.
*/
forceMount?: boolean
}
export type DialogContentEmits = DialogContentImplEmits
const emitsAsProps = useEmitAsProps(emits)
</script>

<template>
<Presence :present="rootContext.open.value">
<Presence :present="forceMount || rootContext.open.value">
<DialogContentModal
v-if="rootContext.modal.value"
v-bind="{ ...props, ...emitsAsProps, ...$attrs }"
Expand Down
2 changes: 1 addition & 1 deletion packages/radix-vue/src/Dialog/DialogOverlay.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { useBodyScrollLock } from '@/shared'
export interface DialogOverlayProps extends PrimitiveProps {
/**
* Used to force mounting when more control is needed. Useful when
* controlling transntion with Vue native transition or other animation libraries.
* controlling animation with Vue animation libraries.
*/
forceMount?: boolean
}
Expand Down
10 changes: 8 additions & 2 deletions packages/radix-vue/src/HoverCard/HoverCardContent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@ import { Presence } from '@/Presence'
import HoverCardContentImpl, { type HoverCardContentImplEmits, type HoverCardContentImplProps } from './HoverCardContentImpl.vue'
import { useForwardPropsEmits } from '@/shared'
export interface HoverCardContentProps extends HoverCardContentImplProps {}
export interface HoverCardContentProps extends HoverCardContentImplProps {
/**
* Used to force mounting when more control is needed. Useful when
* controlling animation with Vue animation libraries.
*/
forceMount?: boolean
}
export type HoverCardContentEmits = HoverCardContentImplEmits
const props = defineProps<HoverCardContentProps>()
Expand All @@ -19,7 +25,7 @@ const rootContext = injectHoverCardRootContext()

<template>
<Presence
:present="rootContext.open.value"
:present="forceMount || rootContext.open.value"
>
<HoverCardContentImpl
v-bind="forwarded"
Expand Down
10 changes: 8 additions & 2 deletions packages/radix-vue/src/Menu/MenuContent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@ import {
import { Presence } from '@/Presence'
import { useEmitAsProps } from '@/shared'
export interface MenuContentProps extends MenuRootContentProps {}
export interface MenuContentProps extends MenuRootContentProps {
/**
* Used to force mounting when more control is needed. Useful when
* controlling animation with Vue animation libraries.
*/
forceMount?: boolean
}
export type MenuContentEmits = MenuContentImplEmits
const props = defineProps<MenuContentProps>()
Expand All @@ -22,7 +28,7 @@ const emitsAsProps = useEmitAsProps(emits)
</script>

<template>
<Presence :present="menuContext.open.value">
<Presence :present="forceMount || menuContext.open.value">
<MenuRootContentModal
v-if="rootContext.modal.value"
v-bind="{ ...$attrs, ...props, ...emitsAsProps }"
Expand Down
Loading

0 comments on commit 3d51633

Please sign in to comment.