-
Notifications
You must be signed in to change notification settings - Fork 122
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
675cf47
commit 511d7ab
Showing
14 changed files
with
272 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
22 changes: 22 additions & 0 deletions
22
packages/vue/src/components/focus-trap/examples/autofocus.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<script setup lang="ts"> | ||
import { ref } from 'vue' | ||
import { FocusTrap } from '@ark-ui/vue/focus-trap' | ||
const trapped = ref(false) | ||
const buttonRef = ref<HTMLButtonElement>() | ||
</script> | ||
|
||
<template> | ||
<div> | ||
<button ref="buttonRef" @click="trapped = !trapped"> | ||
{{ trapped ? 'End Trap' : 'Start Trap' }} | ||
</button> | ||
<FocusTrap v-if="trapped" :disabled="!trapped" :set-return-focus="buttonRef"> | ||
<div style="display: flex; flex-direction: column; gap: 1rem; padding-block: 1rem"> | ||
<input type="text" placeholder="Regular input" /> | ||
<input type="text" placeholder="Autofocused input" autofocus /> | ||
<button @click="trapped = false">End Trap</button> | ||
</div> | ||
</FocusTrap> | ||
</div> | ||
</template> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<script setup lang="ts"> | ||
import { ref } from 'vue' | ||
import { FocusTrap } from '@ark-ui/vue/focus-trap' | ||
const trapped = ref(false) | ||
</script> | ||
|
||
<template> | ||
<button @click="trapped = true">Start Trap</button> | ||
<FocusTrap :return-focus-on-deactivate="false" :disabled="!trapped"> | ||
<div style="display: flex; flex-direction: column; gap: 1rem; padding-block: 1rem"> | ||
<input type="text" placeholder="input" /> | ||
<textarea placeholder="textarea" /> | ||
<button @click="trapped = false">End Trap</button> | ||
</div> | ||
</FocusTrap> | ||
</template> |
24 changes: 24 additions & 0 deletions
24
packages/vue/src/components/focus-trap/examples/initial-focus.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<script setup lang="ts"> | ||
import { ref } from 'vue' | ||
import { FocusTrap } from '@ark-ui/vue/focus-trap' | ||
const trapped = ref(false) | ||
const inputRef = ref<HTMLInputElement>() | ||
const toggle = () => { | ||
trapped.value = !trapped.value | ||
} | ||
</script> | ||
|
||
<template> | ||
<div> | ||
<button @click="toggle">{{ trapped ? 'End Trap' : 'Start Trap' }}</button> | ||
<FocusTrap :disabled="!trapped" :initial-focus="() => inputRef"> | ||
<div style="display: flex; flex-direction: column; gap: 1rem; padding-block: 1rem"> | ||
<input type="text" placeholder="First input" /> | ||
<input ref="inputRef" type="text" placeholder="Second input (initial focus)" /> | ||
<textarea placeholder="textarea" /> | ||
<button @click="trapped = false">End Trap</button> | ||
</div> | ||
</FocusTrap> | ||
</div> | ||
</template> |
19 changes: 19 additions & 0 deletions
19
packages/vue/src/components/focus-trap/focus-trap.stories.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<script setup lang="ts"> | ||
import Basic from './examples/basic.vue' | ||
import InitialFocus from './examples/initial-focus.vue' | ||
import Autofocus from './examples/autofocus.vue' | ||
</script> | ||
|
||
<template> | ||
<Story title="Focus Trap"> | ||
<Variant title="Basic"> | ||
<Basic /> | ||
</Variant> | ||
<Variant title="Initial Focus"> | ||
<InitialFocus /> | ||
</Variant> | ||
<Variant title="Autofocus"> | ||
<Autofocus /> | ||
</Variant> | ||
</Story> | ||
</template> |
99 changes: 99 additions & 0 deletions
99
packages/vue/src/components/focus-trap/focus-trap.types.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
export interface BaseProps { | ||
/** | ||
* Whether the focus trap is disabled | ||
* @default false | ||
*/ | ||
disabled?: boolean | ||
/** | ||
* Function called before focus trap activation to ensure it can be properly trapped | ||
*/ | ||
checkCanFocusTrap?: () => Promise<void> | void | ||
/** | ||
* Function called before focus trap deactivation to ensure focus can be returned | ||
*/ | ||
checkCanReturnFocus?: () => Promise<void> | void | ||
/** | ||
* Element to focus when trap is activated. By default, focuses on first tabbable element | ||
*/ | ||
initialFocus?: HTMLElement | string | (() => HTMLElement) | false | ||
/** | ||
* Element to focus if initialFocus is not found. By default, focuses on container element | ||
*/ | ||
fallbackFocus?: HTMLElement | string | (() => HTMLElement) | ||
/** | ||
* Whether to return focus to the element that had focus when trap was activated | ||
* @default true | ||
*/ | ||
returnFocusOnDeactivate?: boolean | ||
/** | ||
* Custom element to return focus to when trap is deactivated | ||
*/ | ||
setReturnFocus?: HTMLElement | string | (() => HTMLElement) | false | ||
/** | ||
* Whether pressing Escape deactivates the focus trap | ||
* @default true | ||
*/ | ||
escapeDeactivates?: boolean | ||
/** | ||
* Whether clicking outside the trap deactivates it | ||
* @default false | ||
*/ | ||
clickOutsideDeactivates?: boolean | ||
/** | ||
* Custom handler for clicks outside the trap | ||
*/ | ||
allowOutsideClick?: boolean | ((event: MouseEvent) => boolean) | ||
/** | ||
* Whether to prevent scrolling when trap is activated | ||
* @default true | ||
*/ | ||
preventScroll?: boolean | ||
/** | ||
* Whether to delay initial focus | ||
* @default true | ||
*/ | ||
delayInitialFocus?: boolean | ||
/** | ||
* Custom function to determine forward tab navigation | ||
*/ | ||
isKeyForward?: (event: KeyboardEvent) => boolean | ||
/** | ||
* Custom function to determine backward tab navigation | ||
*/ | ||
isKeyBackward?: (event: KeyboardEvent) => boolean | ||
} | ||
|
||
export interface BaseEmits { | ||
/** | ||
* Function called when the focus trap is activated | ||
*/ | ||
activate: [] | ||
/** | ||
* Function called after the focus trap is activated | ||
*/ | ||
'post-activate': [] | ||
/** | ||
* Function called when the focus trap is paused | ||
*/ | ||
pause: [] | ||
/** | ||
* Function called after the focus trap is paused | ||
*/ | ||
'post-pause': [] | ||
/** | ||
* Function called when the focus trap is unpaused | ||
*/ | ||
unpause: [] | ||
/** | ||
* Function called after the focus trap is unpaused | ||
*/ | ||
'post-unpause': [] | ||
/** | ||
* Function called when the focus trap is deactivated | ||
*/ | ||
deactivate: [] | ||
/** | ||
* Function called after the focus trap is deactivated | ||
*/ | ||
'post-deactivate': [] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
<script lang="ts"> | ||
import type { FocusTrapOptions } from '@zag-js/focus-trap' | ||
import type { HTMLProps, PolymorphicProps } from '../factory' | ||
import type { Assign } from '../../types' | ||
import type { BaseProps, BaseEmits } from './focus-trap.types' | ||
export interface FocusTrapBaseProps extends BaseProps, PolymorphicProps {} | ||
export interface FocusTrapProps | ||
extends FocusTrapBaseProps, | ||
/** | ||
* @vue-ignore | ||
*/ | ||
HTMLAttributes {} | ||
export interface FocusTrapEmits extends BaseEmits {} | ||
</script> | ||
|
||
<script setup lang="ts"> | ||
import { trapFocus } from '@zag-js/focus-trap' | ||
import { watchEffect, ref, onWatcherCleanup, onBeforeUnmount } from 'vue' | ||
import { createSplitProps } from '../create-split-props' | ||
import { ark } from '../factory' | ||
import { useForwardExpose, cleanProps } from '../../utils' | ||
const props = withDefaults(defineProps<FocusTrapProps>(), { | ||
disabled: undefined, | ||
allowOutsideClick: undefined, | ||
returnFocusOnDeactivate: undefined, | ||
escapeDeactivates: undefined, | ||
clickOutsideDeactivates: undefined, | ||
preventScroll: undefined, | ||
delayInitialFocus: undefined, | ||
initialFocus: undefined, | ||
fallbackFocus: undefined, | ||
setReturnFocus: undefined, | ||
checkCanFocusTrap: undefined, | ||
checkCanReturnFocus: undefined, | ||
isKeyForward: undefined, | ||
isKeyBackward: undefined, | ||
}) | ||
const emits = defineEmits<BaseEmits>() | ||
const localRef = ref<HTMLDivElement>() | ||
let cleanup: (() => void) | undefined | ||
watchEffect(() => { | ||
if (props.disabled) return | ||
const node = localRef.value?.$el | ||
if (!node) return | ||
const autoFocusNode = node.querySelector<HTMLElement>('[autofocus], [data-autofocus]') | ||
const trapProps = cleanProps(props) | ||
trapProps.initialFocus ||= autoFocusNode ?? undefined | ||
cleanup = trapFocus(node, trapProps) | ||
onWatcherCleanup(() => cleanup?.()) | ||
}) | ||
onBeforeUnmount(() => { | ||
cleanup?.() | ||
}) | ||
useForwardExpose() | ||
</script> | ||
|
||
<template> | ||
<ark.div ref="localRef" :as-child="asChild"> | ||
<slot /> | ||
</ark.div> | ||
</template> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export { default as FocusTrap } from './focus-trap.vue' | ||
export type { FocusTrapBaseProps, FocusTrapProps } from './focus-trap.vue' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters