Clean up FocusScope native impl
This commit is contained in:
@@ -1,20 +1,20 @@
|
|||||||
import {
|
import {
|
||||||
Children,
|
Children,
|
||||||
cloneElement,
|
cloneElement,
|
||||||
ReactNode,
|
isValidElement,
|
||||||
useRef,
|
type ReactElement,
|
||||||
useMemo,
|
type ReactNode,
|
||||||
useCallback,
|
useCallback,
|
||||||
useEffect,
|
useEffect,
|
||||||
isValidElement,
|
useMemo,
|
||||||
FunctionComponentElement,
|
useRef,
|
||||||
} from 'react'
|
} from 'react'
|
||||||
import {
|
import {
|
||||||
AccessibilityInfo,
|
AccessibilityInfo,
|
||||||
Pressable,
|
|
||||||
View,
|
|
||||||
Text,
|
|
||||||
findNodeHandle,
|
findNodeHandle,
|
||||||
|
Pressable,
|
||||||
|
Text,
|
||||||
|
type View,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import {msg} from '@lingui/macro'
|
import {msg} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
@@ -31,10 +31,22 @@ function FocusTrap({children}: {children: ReactNode}) {
|
|||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const child = useRef<View>(null)
|
const child = useRef<View>(null)
|
||||||
|
|
||||||
const content = useMemo(() => {
|
/*
|
||||||
|
* Here we add a ref to the first child of this component. This currently
|
||||||
|
* overrides any ref already on that first child, so we throw an error here
|
||||||
|
* to prevent us from ever accidentally doing this.
|
||||||
|
*/
|
||||||
|
const decoratedChildren = useMemo(() => {
|
||||||
return Children.toArray(children).map((node, i) => {
|
return Children.toArray(children).map((node, i) => {
|
||||||
if (i === 0 && isValidElement(node)) {
|
if (i === 0 && isValidElement(node)) {
|
||||||
return cloneElement(node as FunctionComponentElement<any>, {
|
const n = node as ReactElement<any>
|
||||||
|
if (n.props.ref !== undefined) {
|
||||||
|
throw new Error(
|
||||||
|
'FocusScope needs to override the ref on its first child.',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return cloneElement(n, {
|
||||||
|
...n.props,
|
||||||
ref: child,
|
ref: child,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -42,7 +54,7 @@ function FocusTrap({children}: {children: ReactNode}) {
|
|||||||
})
|
})
|
||||||
}, [children])
|
}, [children])
|
||||||
|
|
||||||
const focus = useCallback((ref: View | null) => {
|
const focusNode = useCallback((ref: View | null) => {
|
||||||
if (!ref) return
|
if (!ref) return
|
||||||
const node = findNodeHandle(ref)
|
const node = findNodeHandle(ref)
|
||||||
if (node) {
|
if (node) {
|
||||||
@@ -52,37 +64,43 @@ function FocusTrap({children}: {children: ReactNode}) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
focus(child.current)
|
focusNode(child.current)
|
||||||
}, 1e3)
|
}, 1e3)
|
||||||
}, [focus])
|
}, [focusNode])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Pressable
|
<Pressable
|
||||||
accessible
|
accessible
|
||||||
accessibilityLabel={_(
|
accessibilityLabel={_(
|
||||||
msg`You've reached the start of the active content. Please go back, or activate to focus the first item.`,
|
msg`You've reached the start of the active content.`,
|
||||||
|
)}
|
||||||
|
accessibilityHint={_(
|
||||||
|
msg`Please go back, or activate this element to return to the start of the active content.`,
|
||||||
)}
|
)}
|
||||||
accessibilityActions={[{name: 'activate', label: 'activate'}]}
|
accessibilityActions={[{name: 'activate', label: 'activate'}]}
|
||||||
onAccessibilityAction={event => {
|
onAccessibilityAction={event => {
|
||||||
switch (event.nativeEvent.actionName) {
|
switch (event.nativeEvent.actionName) {
|
||||||
case 'activate': {
|
case 'activate': {
|
||||||
focus(child.current)
|
focusNode(child.current)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}}>
|
}}>
|
||||||
<Noop />
|
<Noop />
|
||||||
</Pressable>
|
</Pressable>
|
||||||
{content}
|
{decoratedChildren}
|
||||||
<Pressable
|
<Pressable
|
||||||
accessibilityLabel={_(
|
accessibilityLabel={_(
|
||||||
msg`You've reached the end of the active content. Please go back, or activate to go back to the beginning.`,
|
msg`You've reached the end of the active content.`,
|
||||||
|
)}
|
||||||
|
accessibilityHint={_(
|
||||||
|
msg`Please go back, or activate this element to return to the start of the active content.`,
|
||||||
)}
|
)}
|
||||||
accessibilityActions={[{name: 'activate', label: 'activate'}]}
|
accessibilityActions={[{name: 'activate', label: 'activate'}]}
|
||||||
onAccessibilityAction={event => {
|
onAccessibilityAction={event => {
|
||||||
switch (event.nativeEvent.actionName) {
|
switch (event.nativeEvent.actionName) {
|
||||||
case 'activate': {
|
case 'activate': {
|
||||||
focus(child.current)
|
focusNode(child.current)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}}>
|
}}>
|
||||||
|
|||||||
Reference in New Issue
Block a user