Skip to content

Commit

Permalink
refactor: streamline props
Browse files Browse the repository at this point in the history
  • Loading branch information
segunadebayo committed Jan 9, 2025
1 parent 159a36b commit 846d043
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 117 deletions.
39 changes: 19 additions & 20 deletions packages/react/src/components/focus-trap/focus-trap.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
import { type FocusTrapOptions, trapFocus } from '@zag-js/focus-trap'
import { forwardRef, useRef } from 'react'
import { type HTMLProps, type PolymorphicProps, ark } from '../factory'
import { trapFocus, type FocusTrapOptions } from '@zag-js/focus-trap'
import { useSafeLayoutEffect } from '../../utils/use-safe-layout-effect'
import { composeRefs } from '../../utils/compose-refs'
import type { Assign } from '../../types'
import { composeRefs } from '../../utils/compose-refs'
import { createSplitProps } from '../../utils/create-split-props'
import { useSafeLayoutEffect } from '../../utils/use-safe-layout-effect'
import { type HTMLProps, type PolymorphicProps, ark } from '../factory'

export interface TrapOptions extends Omit<FocusTrapOptions, 'document' | 'trapStack'> {
export interface TrapOptions
extends Pick<
FocusTrapOptions,
| 'onActivate'
| 'onDeactivate'
| 'initialFocus'
| 'fallbackFocus'
| 'returnFocusOnDeactivate'
| 'setReturnFocus'
> {
/**
* Whether the focus trap is disabled.
*/
disabled?: boolean
}

Expand All @@ -19,26 +31,11 @@ export const FocusTrap = forwardRef<HTMLDivElement, FocusTrapProps>((props, ref)
const [trapProps, localProps] = createSplitProps<TrapOptions>()(props, [
'disabled',
'onActivate',
'onPostActivate',
'onPause',
'onPostPause',
'onUnpause',
'onPostUnpause',
'checkCanFocusTrap',
'onDeactivate',
'onPostDeactivate',
'checkCanReturnFocus',
'initialFocus',
'fallbackFocus',
'returnFocusOnDeactivate',
'setReturnFocus',
'escapeDeactivates',
'clickOutsideDeactivates',
'allowOutsideClick',
'preventScroll',
'delayInitialFocus',
'isKeyForward',
'isKeyBackward',
])

useSafeLayoutEffect(() => {
Expand All @@ -49,3 +46,5 @@ export const FocusTrap = forwardRef<HTMLDivElement, FocusTrapProps>((props, ref)

return <ark.div ref={composeRefs(localRef, ref)} {...localProps} />
})

FocusTrap.displayName = 'FocusTrap'
30 changes: 14 additions & 16 deletions packages/solid/src/components/focus-trap/focus-trap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,24 @@ import { composeRefs } from '../../utils/compose-refs'
import { createSplitProps } from '../../utils/create-split-props'
import { type HTMLProps, type PolymorphicProps, ark } from '../factory'

export interface TrapOptions extends Omit<FocusTrapOptions, 'document' | 'trapStack'> {
export interface TrapOptions
extends Pick<
FocusTrapOptions,
| 'onActivate'
| 'onDeactivate'
| 'initialFocus'
| 'fallbackFocus'
| 'returnFocusOnDeactivate'
| 'setReturnFocus'
> {
/**
* Whether the focus trap is disabled.
*/
disabled?: boolean
}

export interface FocusTrapBaseProps extends PolymorphicProps<'div'>, TrapOptions {}

export interface FocusTrapProps extends Assign<HTMLProps<'div'>, FocusTrapBaseProps> {}

export const FocusTrap = (props: FocusTrapProps) => {
Expand All @@ -18,26 +31,11 @@ export const FocusTrap = (props: FocusTrapProps) => {
const [trapProps, localProps] = createSplitProps<TrapOptions>()(props, [
'disabled',
'onActivate',
'onPostActivate',
'onPause',
'onPostPause',
'onUnpause',
'onPostUnpause',
'checkCanFocusTrap',
'onDeactivate',
'onPostDeactivate',
'checkCanReturnFocus',
'initialFocus',
'fallbackFocus',
'returnFocusOnDeactivate',
'setReturnFocus',
'escapeDeactivates',
'clickOutsideDeactivates',
'allowOutsideClick',
'preventScroll',
'delayInitialFocus',
'isKeyForward',
'isKeyBackward',
])

createEffect(() => {
Expand Down
78 changes: 11 additions & 67 deletions packages/vue/src/components/focus-trap/focus-trap.types.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
type FocusableElement = HTMLElement | SVGElement

type FocusTargetValue = FocusableElement | string
type FocusTarget = FocusTargetValue | (() => FocusTargetValue)

type FocusTargetValueOrFalse = FocusTargetValue | false
type FocusTargetOrFalse = FocusTargetValueOrFalse | (() => FocusTargetValueOrFalse)

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
initialFocus?: FocusTargetOrFalse | undefined | VoidFunction
/**
* Element to focus if initialFocus is not found. By default, focuses on container element
*/
fallbackFocus?: HTMLElement | string | (() => HTMLElement)
fallbackFocus?: FocusTarget
/**
* Whether to return focus to the element that had focus when trap was activated
* @default true
Expand All @@ -28,72 +28,16 @@ export interface BaseProps {
/**
* 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
setReturnFocus?: FocusTargetValueOrFalse | ((node: FocusableElement) => FocusTargetValueOrFalse)
}

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': []
}
14 changes: 0 additions & 14 deletions packages/vue/src/components/focus-trap/focus-trap.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,9 @@ 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>()
Expand All @@ -55,12 +47,6 @@ watchEffect(() => {
...trapProps,
onActivate: () => emits('activate'),
onDeactivate: () => emits('deactivate'),
onPause: () => emits('pause'),
onUnpause: () => emits('unpause'),
onPostActivate: () => emits('post-activate'),
onPostDeactivate: () => emits('post-deactivate'),
onPostPause: () => emits('post-pause'),
onPostUnpause: () => emits('post-unpause'),
})
onWatcherCleanup(() => cleanup?.())
Expand Down

0 comments on commit 846d043

Please sign in to comment.