Skip to content

Commit

Permalink
feat(Dialog): support focus external trigger when close (#922)
Browse files Browse the repository at this point in the history
* feat: triggerElement prop for DialogRoot

* feat: improved logic

* feat: set triggerElement on content mount

* feat: cleanup

* feat: test

* chore: add story

* refactor: prevent body being set as triggerElement

* test: make sure trigger element is focus on close

* chore: fix typo

---------

Co-authored-by: zernonia <[email protected]>
  • Loading branch information
enkot and zernonia authored May 17, 2024
1 parent fd92219 commit bcf3a6c
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 3 deletions.
6 changes: 5 additions & 1 deletion packages/radix-vue/src/Dialog/Dialog.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const NoLabelDialogTest = defineComponent({

const UndefinedDescribedByDialog = defineComponent({
components: { DialogRoot, DialogTrigger, DialogOverlay, DialogContent, DialogClose, DialogTitle },
template: ` <DialogRoot>
template: `<DialogRoot>
<DialogTrigger>${OPEN_TEXT}</DialogTrigger>
<DialogOverlay />
<DialogContent :aria-describedby="undefined">
Expand Down Expand Up @@ -128,6 +128,10 @@ describe('given a default Dialog', () => {
it('should close the content', () => {
expect(document.body.innerHTML).not.toContain(closeButton.innerHTML)
})

it('should focus trigger', async () => {
expect(document.activeElement).toBe(trigger.element)
})
})
})
})
4 changes: 4 additions & 0 deletions packages/radix-vue/src/Dialog/DialogContentImpl.vue
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ rootContext.descriptionId ||= useId(undefined, 'radix-vue-dialog-description')
onMounted(() => {
rootContext.contentElement = contentElement
// Preserve the `DialogTrigger` element in case it was triggered programmatically
if (document.activeElement !== document.body)
rootContext.triggerElement.value = document.activeElement as HTMLElement
})
if (process.env.NODE_ENV !== 'production')
Expand Down
2 changes: 1 addition & 1 deletion packages/radix-vue/src/Dialog/DialogTrigger.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const { forwardRef, currentElement } = useForwardExpose()
rootContext.contentId ||= useId(undefined, 'radix-vue-dialog-content')
onMounted(() => {
rootContext.triggerElement = currentElement
rootContext.triggerElement.value = currentElement.value
})
</script>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<script setup lang="ts">
import { Icon } from '@iconify/vue'
import {
DialogClose,
DialogContent,
DialogDescription,
DialogOverlay,
DialogPortal,
DialogRoot,
DialogTitle,
DialogTrigger,
} from '..'
import { ref } from 'vue'
const open = ref(false)
</script>

<template>
<Story title="Dialog/External Trigger" :layout="{ type: 'single', iframe: false }">
<Variant title="default">
<div>
<button
class="mr-2 text-violet11 shadow-blackA7 hover:bg-mauve3 inline-flex h-[35px] items-center justify-center rounded-[4px] bg-white px-[15px] font-medium leading-none shadow-[0_2px_10px] focus:shadow-[0_0_0_2px] focus:shadow-black focus:outline-none"
@click="open = true"
>
External Trigger
</button>
<DialogRoot v-model:open="open">
<DialogTrigger
class="text-violet11 shadow-blackA7 hover:bg-mauve3 inline-flex h-[35px] items-center justify-center rounded-[4px] bg-white px-[15px] font-medium leading-none shadow-[0_2px_10px] focus:shadow-[0_0_0_2px] focus:shadow-black focus:outline-none"
>
Main Trigger
</DialogTrigger>
<DialogPortal>
<Transition name="fade">
<DialogOverlay class="bg-blackA9 fixed inset-0" />
</Transition>
<Transition name="fade">
<DialogContent
class="fixed top-[50%] left-[50%] max-h-[85vh] w-[90vw] max-w-[450px] translate-x-[-50%] translate-y-[-50%] rounded-[6px] bg-white p-[25px] shadow-[hsl(206_22%_7%_/_35%)_0px_10px_38px_-10px,_hsl(206_22%_7%_/_20%)_0px_10px_20px_-15px] focus:outline-none"
>
<DialogTitle class="text-mauve12 m-0 text-[17px] font-medium">
Edit profile
</DialogTitle>
<DialogDescription class="text-mauve11 mt-[10px] mb-5 text-[15px] leading-normal">
Make changes to your
profile here. Click save when you're done.
</DialogDescription>
<DialogClose
class="text-violet11 hover:bg-violet4 focus:shadow-violet7 absolute top-[10px] right-[10px] inline-flex h-[25px] w-[25px] appearance-none items-center justify-center rounded-full focus:shadow-[0_0_0_2px] focus:outline-none"
aria-label="Close"
>
<Icon icon="lucide:x" />
</DialogClose>
</DialogContent>
</Transition>
</DialogPortal>
</DialogRoot>
</div>
</Variant>
</Story>
</template>
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import DropdownMenu from '../../DropdownMenu/story/_DropdownMenu.vue'
</script>

<template>
<Story title="Dialog/WithDropdown" :layout="{ type: 'single', iframe: false }">
<Story title="Dialog/With Dropdown" :layout="{ type: 'single', iframe: false }">
<Variant title="default">
<DialogRoot>
<DialogTrigger
Expand Down

0 comments on commit bcf3a6c

Please sign in to comment.