Skip to content
This repository was archived by the owner on Mar 4, 2020. It is now read-only.

Commit 35da256

Browse files
authored
feat(useAccessibility): add support for FocusZone (#2275)
* feat(useAccessibility): add support for FocusZone * remove only * improve types
1 parent f16bf46 commit 35da256

File tree

3 files changed

+93
-6
lines changed

3 files changed

+93
-6
lines changed

packages/react-bindings/src/FocusZone/FocusZone.types.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,7 @@ export interface IFocusZone {
3838
/**
3939
* FocusZone component props.
4040
*/
41-
export interface FocusZoneProps
42-
extends FocusZoneProperties,
43-
React.HTMLAttributes<HTMLElement | FocusZone> {
41+
export interface FocusZoneProps extends FocusZoneProperties, React.HTMLAttributes<HTMLElement> {
4442
/** @docSiteIgnore */
4543
as?: React.ReactType
4644
/**

packages/react-bindings/src/hooks/useAccessibility.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as React from 'react'
33

44
import getAccessibility from '../accessibility/getAccessibility'
55
import { ReactAccessibilityBehavior, AccessibilityActionHandlers } from '../accessibility/types'
6+
import FocusZone from '../FocusZone/FocusZone'
67

78
type UseAccessibilityOptions<Props> = {
89
actionHandlers?: AccessibilityActionHandlers
@@ -11,6 +12,13 @@ type UseAccessibilityOptions<Props> = {
1112
rtl?: boolean
1213
}
1314

15+
type UseAccessibilityResult = (<SlotProps extends Record<string, any>>(
16+
slotName: string,
17+
slotProps: SlotProps,
18+
) => MergedProps<SlotProps>) & {
19+
unstable_wrapWithFocusZone: (children: React.ReactElement) => React.ReactElement
20+
}
21+
1422
type MergedProps<SlotProps extends Record<string, any>> = SlotProps &
1523
Partial<AccessibilityAttributesBySlot> & {
1624
onKeyDown?: (e: React.KeyboardEvent, ...args: any[]) => void
@@ -62,8 +70,30 @@ const useAccessibility = <Props>(
6270
actionHandlers,
6371
)
6472

65-
return <SlotProps extends Record<string, any>>(slotName: string, slotProps: SlotProps) =>
73+
const getA11Props: UseAccessibilityResult = (slotName, slotProps) =>
6674
mergeProps(slotName, slotProps, definition)
75+
76+
// Provides an experimental handling for FocusZone definition in behaviors
77+
getA11Props.unstable_wrapWithFocusZone = (element: React.ReactElement) => {
78+
if (definition.focusZone) {
79+
let child: React.ReactElement = element
80+
81+
if (process.env.NODE_ENV !== 'production') {
82+
child = React.Children.only(element)
83+
}
84+
85+
return React.createElement(FocusZone, {
86+
...definition.focusZone.props,
87+
...child.props,
88+
as: child.type,
89+
isRtl: rtl,
90+
})
91+
}
92+
93+
return element
94+
}
95+
96+
return getA11Props
6797
}
6898

6999
export default useAccessibility

packages/react-bindings/test/hooks/useAccessibility-test.tsx

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,15 @@ const testBehavior: Accessibility<TestBehaviorProps> = props => ({
2929
},
3030
})
3131

32+
const focusZoneBehavior: Accessibility<never> = () => ({
33+
focusZone: {
34+
props: {
35+
disabled: true,
36+
shouldFocusOnMount: true,
37+
},
38+
},
39+
})
40+
3241
type TestComponentProps = {
3342
disabled?: boolean
3443
onClick?: (e: React.KeyboardEvent<HTMLDivElement>, slotName: string) => void
@@ -48,14 +57,28 @@ const TestComponent: React.FunctionComponent<TestComponentProps> = props => {
4857
},
4958
})
5059

51-
return (
60+
return getA11Props.unstable_wrapWithFocusZone(
5261
<div {...getA11Props('root', { onKeyDown, ...rest })}>
5362
<img
5463
{...getA11Props('img', {
5564
src: 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==',
5665
})}
5766
/>
58-
</div>
67+
</div>,
68+
)
69+
}
70+
71+
type FocusZoneComponentProps = {
72+
as?: React.ElementType
73+
rtl?: boolean
74+
}
75+
76+
const FocusZoneComponent: React.FunctionComponent<FocusZoneComponentProps> = props => {
77+
const { as: ElementType = 'div', children, rtl = false } = props
78+
const getA11Props = useAccessibility(focusZoneBehavior, { rtl })
79+
80+
return getA11Props.unstable_wrapWithFocusZone(
81+
<ElementType {...getA11Props('root', {})}>{children}</ElementType>,
5982
)
6083
}
6184

@@ -115,4 +138,40 @@ describe('useAccessibility', () => {
115138
'root',
116139
)
117140
})
141+
142+
describe('FocusZone', () => {
143+
it('do not render FocusZone without the definition in a behavior', () => {
144+
expect(shallow(<TestComponent />).find('FocusZone')).toHaveLength(0)
145+
})
146+
147+
it('renders FocusZone with the definition in a behavior', () => {
148+
expect(shallow(<FocusZoneComponent />).find('FocusZone')).toHaveLength(1)
149+
})
150+
151+
it('applies props from the behavior to a FocusZone component', () => {
152+
expect(
153+
shallow(<FocusZoneComponent />)
154+
.find('FocusZone')
155+
.props(),
156+
).toEqual(
157+
expect.objectContaining({
158+
disabled: true,
159+
shouldFocusOnMount: true,
160+
}),
161+
)
162+
})
163+
164+
it('passes "rtl" value', () => {
165+
expect(
166+
shallow(<FocusZoneComponent />)
167+
.find('FocusZone')
168+
.prop('isRtl'),
169+
).toBe(false)
170+
expect(
171+
shallow(<FocusZoneComponent rtl />)
172+
.find('FocusZone')
173+
.prop('isRtl'),
174+
).toBe(true)
175+
})
176+
})
118177
})

0 commit comments

Comments
 (0)