Skip to content

Commit 5baad98

Browse files
authored
Update README.md
1 parent 401f5cb commit 5baad98

File tree

1 file changed

+181
-123
lines changed

1 file changed

+181
-123
lines changed

README.md

Lines changed: 181 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -1,160 +1,218 @@
1-
# TSDX React User Guide
1+
<h1>react-three-a11y👩‍🦯</h1>
22

3-
Congrats! You just saved yourself hours of work by bootstrapping this project with TSDX. Let’s get you oriented with what’s here and how to use it.
3+
An easy to use package designed to bring accessibility features to [react-three-fiber](https://github.com/pmndrs/react-three-fiber) such as focus indication, keyboard tab navigation, and screen reader support.
44

5-
> This TSDX setup is meant for developing React component libraries (not apps!) that can be published to NPM. If you’re looking to build a React-based app, you should use `create-react-app`, `razzle`, `nextjs`, `gatsby`, or `react-static`.
5+
# How to use
66

7-
> If you’re new to TypeScript and React, checkout [this handy cheatsheet](https://github.com/sw-yx/react-typescript-cheatsheet/)
7+
## Initial setup
88

9-
## Commands
10-
11-
TSDX scaffolds your new library inside `/src`, and also sets up a [Parcel-based](https://parceljs.org) playground for it inside `/example`.
12-
13-
The recommended workflow is to run TSDX in one terminal:
9+
Install the @react-three/a11y package
1410

11+
with npm :
1512
```bash
16-
npm start # or yarn start
13+
npm install @react-three/a11y
1714
```
18-
19-
This builds to `/dist` and runs the project in watch mode so any edits you save inside `src` causes a rebuild to `/dist`.
20-
21-
Then run the example inside another:
22-
15+
with yarn
2316
```bash
24-
cd example
25-
npm i # or yarn to install dependencies
26-
npm start # or yarn start
17+
yarn add @react-three/a11y
2718
```
2819

29-
The default example imports and live reloads whatever is in `/dist`, so if you are seeing an out of date component, make sure TSDX is running in watch mode like we recommend above. **No symlinking required**, we use [Parcel's aliasing](https://parceljs.org/module_resolution.html#aliases).
30-
31-
To do a one-off build, use `npm run build` or `yarn build`.
32-
33-
To run tests, use `npm test` or `yarn test`.
34-
35-
## Configuration
36-
37-
Code quality is set up for you with `prettier`, `husky`, and `lint-staged`. Adjust the respective fields in `package.json` accordingly.
20+
Now, you'll have to import the A11yAnnouncer component. We usually place it next to the R3F Canvas component.
3821

39-
### Jest
40-
41-
Jest tests are set up to run with `npm test` or `yarn test`.
42-
43-
### Bundle analysis
44-
45-
Calculates the real cost of your library using [size-limit](https://github.com/ai/size-limit) with `npm run size` and visulize it with `npm run analyze`.
46-
47-
#### Setup Files
48-
49-
This is the folder structure we set up for you:
50-
51-
```txt
52-
/example
53-
index.html
54-
index.tsx # test your component here in a demo app
55-
package.json
56-
tsconfig.json
57-
/src
58-
index.tsx # EDIT THIS
59-
/test
60-
blah.test.tsx # EDIT THIS
61-
.gitignore
62-
package.json
63-
README.md # EDIT THIS
64-
tsconfig.json
22+
```jsx
23+
import { A11yAnnouncer } from "@react-three/a11y"
24+
{...}
25+
<Canvas>
26+
{...}
27+
</Canvas>
6528
```
6629

67-
#### React Testing Library
68-
69-
We do not set up `react-testing-library` for you yet, we welcome contributions and documentation on this.
70-
71-
### Rollup
72-
73-
TSDX uses [Rollup](https://rollupjs.org) as a bundler and generates multiple rollup configs for various module formats and build settings. See [Optimizations](#optimizations) for details.
74-
75-
### TypeScript
76-
77-
`tsconfig.json` is set up to interpret `dom` and `esnext` types, as well as `react` for `jsx`. Adjust according to your needs.
30+
This will both help us emulate focus inside the canvas and provide some text to screen readers when nescessary.
31+
32+
Then to add some accessibility features to your 3D Objects / Groups of 3D object you'll have to import the A11y component too.
33+
Then you wrap the 3D objects you want to make focusable like so
34+
35+
```jsx
36+
import { A11yAnnouncer, A11y } from "@react-three/a11y"
37+
38+
<A11yDom >
39+
<Canvas>
40+
{...}
41+
<A11y>
42+
<My3DComponent />
43+
</A11y>
44+
{...}
45+
<A11y>
46+
<AGroupOf3DComponent />
47+
</A11y>
48+
{...}
49+
</Canvas>
50+
</A11yDom>
51+
```
7852

79-
## Continuous Integration
53+
At this point both My3DComponent and AGroupOf3DComponent can receive focus.
54+
More presciesly, the emulated "focus" will be on the parent A11y that will act as a provider and give the possibility to it's children to access the state.
55+
But even if they're focusable, nothing will be displayed / read etc without a few more attributes.
8056

81-
### GitHub Actions
57+
## accessing the hover / focused / pressed state
8258

83-
Two actions are added by default:
59+
For each child wrapped in a A11y component, you can access the focus / hover / pressed state like so
8460

85-
- `main` which installs deps w/ cache, lints, tests, and builds on all pushes against a Node and OS matrix
86-
- `size` which comments cost comparison of your library on every pull request using [`size-limit`](https://github.com/ai/size-limit)
61+
import useA11y from '@react-three/a11y' then
8762

88-
## Optimizations
63+
```jsx
64+
import { A11yAnnouncer, A11y, useA11y } from "@react-three/a11y"
65+
66+
{...}
8967

90-
Please see the main `tsdx` [optimizations docs](https://github.com/palmerhq/tsdx#optimizations). In particular, know that you can take advantage of development-only optimizations:
68+
const My3DComponent = (props) {
9169

92-
```js
93-
// ./types/index.d.ts
94-
declare var __DEV__: boolean;
70+
//call useA11yContext to get the A11yContext from the provider
71+
const a11yContext = useA11yContext();
72+
//now you have access to a11yContext.hover, a11yContext.focus and a11yContext.pressed
9573

96-
// inside your code...
97-
if (__DEV__) {
98-
console.log('foo');
74+
return (
75+
<mesh
76+
{...props}
77+
<boxBufferGeometry args={[1, 1, 1]} />
78+
//here we'll change the material color depending on the a11yContext state
79+
<meshStandardMaterial color={a11yContext.hover || a11yContext.focus ? 'hotpink' : 'orange'} />
80+
</mesh>
81+
)
9982
}
10083
```
10184

102-
You can also choose to install and use [invariant](https://github.com/palmerhq/tsdx#invariant) and [warning](https://github.com/palmerhq/tsdx#warning) functions.
103-
104-
## Module Formats
105-
106-
CJS, ESModules, and UMD module formats are supported.
107-
108-
The appropriate paths are configured in `package.json` and `dist/index.js` accordingly. Please report if any issues are found.
109-
110-
## Deploying the Example Playground
111-
112-
The Playground is just a simple [Parcel](https://parceljs.org) app, you can deploy it anywhere you would normally deploy that. Here are some guidelines for **manually** deploying with the Netlify CLI (`npm i -g netlify-cli`):
113-
114-
```bash
115-
cd example # if not already in the example folder
116-
npm run build # builds to dist
117-
netlify deploy # deploy the dist folder
85+
In this example, the meshStandardMaterial of the component My3DComponent will change color if he is either focused or hovered.
86+
How you display the focus / hover information to the user is up to you ! Just make sure it's intuitive for your user !
87+
88+
## The role attribute
89+
90+
Like in HTML, you can focus different kind of element and expect different things depending on what you're focusing.
91+
That's why the A11y component is divided in 3 categories.
92+
93+
- role="content" ( default )
94+
This role is meant to provide information to screen readers or to serve as a step for a user to navigate your site using Tab for instance.
95+
It's not meant to trigger anything on click or to be activable with the Keyboard.
96+
More on this role <a href="/#content"> below </a>
97+
- role="button"
98+
This role is meant to emulate the behaviour of a button or a togglable button.
99+
It will display a cursor pointer when your cursor is over the linked 3D object.
100+
It will call a function on click but also on any kind of action that would trigger a focused button ( Enter, Double-Tap .. )
101+
It is also actionnable by user using a screen reader.
102+
More on this role <a href="/#button"> below </a>
103+
- role="link"
104+
This role is meant to emulate the behaviour of a regular html link.
105+
It should be used in combination with something that will trigger navigation on click.
106+
Just like the button one, it is accessible to all kind of user.
107+
More on this role <a href="/#link"> below </a>
108+
109+
## Call function on focus
110+
111+
The A11y attribute focusCall will be called each time this component receive focus ( Usually through tab navigation )
112+
You can for instance use it in order to make sure the currently focused element is in view by adjusting it position or the camera position.
113+
114+
```jsx
115+
import { A11yAnnouncer, A11y } from "@react-three/a11y"
116+
117+
<A11yDom >
118+
<Canvas>
119+
{...}
120+
<A11y role="content" focusCall={()=>{
121+
//rotate camera to show the focused element
122+
}}>
123+
<My3DComponent />
124+
</A11y>
125+
{...}
126+
</Canvas>
127+
</A11yDom>
118128
```
119129

120-
Alternatively, if you already have a git repo connected, you can set up continuous deployment with Netlify:
121-
122-
```bash
123-
netlify init
124-
# build command: yarn build && cd example && yarn && yarn build
125-
# directory to deploy: example/dist
126-
# pick yes for netlify.toml
130+
## Call function on click / keyboard Click
131+
132+
The A11y attribute actionCall will call the associated function each time this component gets clicked / focused then keyboard activated etc..
133+
134+
```jsx
135+
import { A11yAnnouncer, A11y } from "@react-three/a11y"
136+
137+
<A11yDom >
138+
<Canvas>
139+
{...}
140+
<A11y role="button" actionCall={()=>{
141+
alert('This button have been clicked')
142+
}}>
143+
<My3DComponent />
144+
</A11y>
145+
{...}
146+
</Canvas>
147+
</A11yDom>
127148
```
128149

129-
## Named Exports
130-
131-
Per Palmer Group guidelines, [always use named exports.](https://github.com/palmerhq/typescript#exports) Code split inside your React app instead of your React library.
132-
133-
## Including Styles
134-
135-
There are many ways to ship styles, including with CSS-in-JS. TSDX has no opinion on this, configure how you like.
150+
## Provide a description of the currenlty focused / hovered element
151+
152+
Your A11y component will provide a description to the screen reader users on focus / hover as long as you provide it to the description attribute.
153+
Optionnaly, you can also show the description to the user when he hover it by setting showAltText={true}.
154+
155+
```jsx
156+
import { A11yAnnouncer, A11y } from "@react-three/a11y"
157+
158+
<A11yDom >
159+
<Canvas>
160+
{...}
161+
<A11y role="content" description="A rotating red square">
162+
//will read "A rotating red square" to screen readers on focus / hover
163+
<My3DSquare />
164+
</A11y>
165+
{...}
166+
<A11y role="content" description="A bouncing blue sphere" showAltText={true}>
167+
//will read "A bouncing blue sphere" to screen readers on focus / hover while also showing it on mouseover
168+
<My3DSphere />
169+
</A11y>
170+
{...}
171+
</Canvas>
172+
</A11yDom>
173+
```
136174

137-
For vanilla CSS, you can include it at the root directory and add it to the `files` section in your `package.json`, so that it can be imported separately by your users and run through their bundler's loader.
175+
If your A11y component have the role="button", you can use two more attributes :
176+
- activationMsg : When the user will click / activate the "button" the screen reader will read what you wrote in activationMsg
177+
- desactivationMsg : When set, it turns your button in a togglable button. Which means he now has a on/off state. Screen readers will read the state of the button as well as the desactivation message / activation message that you set when toggling it.
178+
179+
```jsx
180+
import { A11yAnnouncer, A11y } from "@react-three/a11y"
181+
182+
<A11yDom >
183+
<Canvas>
184+
{...}
185+
<A11y role="button" description="This button will send a thank you email to the team" activationMsg="Email is sending">
186+
//will read the description on hover / focus then will read activationMsg if clicked / pressed
187+
<My3DSquare />
188+
</A11y>
189+
{...}
190+
<A11y
191+
role="button"
192+
description="This button can enable and disable dark theme"
193+
activationMsg="Dark theme enabled"
194+
desactivationMsg="Dark theme disabled"
195+
>
196+
//will read the description on hover / focus then will read activationMsg if turned on or desactivationMsg if tuned off
197+
<My3DSphere />
198+
</A11y>
199+
{...}
200+
</Canvas>
201+
</A11yDom>
202+
```
138203

139-
## Publishing to NPM
204+
####content
140205

141-
We recommend using [np](https://github.com/sindresorhus/np).
206+
####button
142207

143-
## Usage with Lerna
208+
####link
144209

145-
When creating a new package with TSDX within a project set up with Lerna, you might encounter a `Cannot resolve dependency` error when trying to run the `example` project. To fix that you will need to make changes to the `package.json` file _inside the `example` directory_.
210+
## Screen reader support
146211

147-
The problem is that due to the nature of how dependencies are installed in Lerna projects, the aliases in the example project's `package.json` might not point to the right place, as those dependencies might have been installed in the root of your Lerna project.
212+
## Next steps
148213

149-
Change the `alias` to point to where those packages are actually installed. This depends on the directory structure of your Lerna project, so the actual path might be different from the diff below.
214+
- [ ] Improve the accessibility for mobile screen readers such as Voice Over and Talk Back
150215

151-
```diff
152-
"alias": {
153-
- "react": "../node_modules/react",
154-
- "react-dom": "../node_modules/react-dom"
155-
+ "react": "../../../node_modules/react",
156-
+ "react-dom": "../../../node_modules/react-dom"
157-
},
158-
```
216+
### Maintainers :
159217

160-
An alternative to fixing this problem would be to remove aliases altogether and define the dependencies referenced as aliases as dev dependencies instead. [However, that might cause other problems.](https://github.com/palmerhq/tsdx/issues/64)
218+
- [`twitter 👋 @AlaricBaraou`](https://twitter.com/AlaricBaraou)

0 commit comments

Comments
 (0)