Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 31 additions & 131 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# react-spectrum
# react-spectrum v3

[Spectrum](http://spectrum.corp.adobe.com) UI components in React.

Expand All @@ -19,48 +19,42 @@ If you are manually managing your version of Node, then refer to `.nvmrc` for th
Add the following to your `~/.npmrc`:

```
registry=https://artifactory-uw2.adobeitc.com/artifactory/api/npm/npm-react-release/

_auth = [AUTH KEY]
always-auth = true
email = [ADOBE EMAIL]

@react:registry=https://artifactory-uw2.adobeitc.com/artifactory/api/npm/npm-react-release/
//artifactory-uw2.adobeitc.com/artifactory/api/npm/npm-react-release/:always-auth=false
```

The auth key can be obtained by following the steps listed [here](https://www.jfrog.com/confluence/display/RTF/Npm+Registry#npmRegistry-UsingBasicAuthentication). Sample cURL:
```
curl -u <ARTIFACTORY USERNAME>:<API KEY> https://artifactory-uw2.adobeitc.com:443/artifactory/api/npm/auth
@react-aria:registry=https://artifactory-uw2.adobeitc.com/artifactory/api/npm/npm-rsp-tmp-release/
@react-spectrum:registry=https://artifactory-uw2.adobeitc.com/artifactory/api/npm/npm-rsp-tmp-release/
@react-stately:registry=https://artifactory-uw2.adobeitc.com/artifactory/api/npm/npm-rsp-tmp-release/
@react-types:registry=https://artifactory-uw2.adobeitc.com/artifactory/api/npm/npm-rsp-tmp-release/
@spectrum-icons:registry=https://artifactory-uw2.adobeitc.com/artifactory/api/npm/npm-rsp-tmp-release/
//artifactory-uw2.adobeitc.com/artifactory/api/npm/npm-rsp-tmp-release/:_password=YOUR_PASSWORD_HERE
//artifactory-uw2.adobeitc.com/artifactory/api/npm/npm-rsp-tmp-release/:username=YOUR_USERNAME_HERE
//artifactory-uw2.adobeitc.com/artifactory/api/npm/npm-rsp-tmp-release/:email=YOUR_USERNAME_HERE@adobe.com
//artifactory-uw2.adobeitc.com/artifactory/api/npm/npm-rsp-tmp-release/:always-auth=true
```

Then you should be able to install with npm:
Eventually we'll support a single package with all of them, but for now you must install individual ones

```
npm install @react-spectrum/dialog --save
npm install @react-spectrum/provider @react-spectrum/theme-default @react-spectrum/button --save
```

### Example

```javascript
// Import root provider at the top level, it brings global page styles (CSS reset, fonts, icons, etc.)
import Provider from '@react-spectrum/provider';
// Import root provider and theme
import {Provider} from '@react-spectrum/provider';
import {theme} from '@react-spectrum/theme-default';

// Import the component you want to use
import Button from '@react-spectrum/button';
import {Button} from '@react-spectrum/button';

// Render it!
ReactDOM.render(<Provider theme='light'><Button>Hello World</Button></Provider>, dom);
ReactDOM.render(
<Provider theme={theme}>
<Button variant="cta">Hello World</Button>
</Provider>
, dom);
```

A few community members have created example apps to help you get started:
- Using Webpack / react-scripts: https://git.corp.adobe.com/timk/react-spectrum-template
- Using Webpack / react-scripts: https://git.corp.adobe.com/acevedoc/react-spectrum-app-example
- Using Parcel: https://git.corp.adobe.com/pfahler/react-spectrum-template

Be sure to [check if your team is already using it](https://wiki.corp.adobe.com/display/RSP/Teams+using+react+spectrum)! It could save you time!

### Webpack

To use react-spectrum, you'll need [css-loader](https://github.com/webpack-contrib/css-loader) and either
Expand All @@ -85,55 +79,6 @@ module.exports = {

No additional configuration is needed to use react-spectrum with Parcel. 😇

### Specify themes which you want to include

You can specify the themes which you want to be included/excluded in build by passing enviroment variables to your application's build process, for example: `THEME_LIGHT=true THEME_DARK=true make build`. If you don't pass anything, all themes are imported.

In webpack, you can use `DefinePlugin` to specify environment variables. Unfortunately, you must explicitly set all of the environment variables, including the ones for themes/scales you are not using.

```javascript
module.exports = {
plugins: [
new webpack.DefinePlugin({
'process.env.SCALE_MEDIUM': 'true',
'process.env.SCALE_LARGE': 'false',
'process.env.THEME_LIGHT': 'true',
'process.env.THEME_LIGHTEST': 'false',
'process.env.THEME_DARK': 'false',
'process.env.THEME_DARKEST': 'false'
})
]
}
```

You can specify what theme to use at runtime using the `Provider` component which wraps your app.

```javascript
<Provider theme="dark">
{/* YOUR APP HERE */}
</Provider>
```

### Scale support for mobile

For mobile, Spectrum has a larger scale that enables larger tap targets on all controls. By default, this scale is not built into react-spectrum's CSS. However, you can enable it using some additional environment variables, similar to the ones for themes described above. There are three cases:

* To get only the default (medium) scale, you do not need to specify any environment variables.
* To get only the large scale for mobile, specify `SCALE_LARGE=true` when building.
* To get both medium and large scale, specify `SCALE_MEDIUM=true SCALE_LARGE=true` when building.

Once you have built in the required themes into your CSS, you can switch between scales using the `Provider` component.

```javascript
<Provider theme="dark" scale="large">
{/* YOUR APP HERE */}
</Provider>
```

### Manifest

React Spectrum allows you to import only the components you need rather than bloating your application with unused components. If you would like to import multiple components in one import statement, you can add a manifest to your own application.

## Development

### Contributing
Expand All @@ -145,83 +90,38 @@ Please read the [CONTRIBUTING](CONTRIBUTING.md) guide for an overview of how to
We use Yarn, please run `yarn install` instead of `npm install` to get started. If you do not have yarn, you can follow these [instructions](https://yarnpkg.com/lang/en/docs/install/#mac-stable)

#### Storybook
We use [Storybooks](https://storybooks.js.org) for local development. Run `npm start` and open [http://localhost:9002](http://localhost:9002) in your browser to play around with the components and test your changes.

#### Gatsby Documentation
Follow these steps to run documentation locally.

```
yarn install
make docs_local
```

`make docs_local` will run a pre-install (documentation project) that will build the react-spectrum project.
It will the create a file link to the build output so that gatsby can use it for imports.
To update the documentation while working on both the component and documentation, you can use a new terminal to run `make build` after updates which will update in gatsby (you can quickly restart the documentation with `npm run develop` from the documentation project root if an error occurs)
We use [Storybooks](https://storybooks.js.org) for local development. Run `yarn start` and open [http://localhost:9003](http://localhost:9003) in your browser to play around with the components and test your changes.

### File Layout

Each component lives in a directory under `src/`. The JavaScript lives in `src/{component}/js` and the styles
(written in [Stylus](http://stylus-lang.com)) live in `src/{component}/style`. When we build in preparation
for publishing to npm, the JavaScript is pre-compiled with [Babel](http://babeljs.io), and the stylus is
compiled to a single CSS file for each component. The directory structure is also flattened so e.g.
`import '@react/react-spectrum/Button'` works.
**Note**: For local development linking you'll need to run build. Then `cd` into the dist folder
and run `npm link` from there. That way, the import statements stay the same.
React Spectrum v3 is organized into many npm packages in a monorepo, managed by [Lerna](http://lerna.js.org). Our architecture splits each component into three parts: @react-stately (state management), @react-aria (behavior + accessibility), and @react-spectrum (spectrum themed components).

### Testing

We use [mocha](https://mochajs.org/) for unit tests and [enzyme](https://github.com/airbnb/enzyme#basic-usage) +
[assert](http://nodejs.org/api/assert.html) for writing assertions. In general, we prefer enzyme's
[shallow rendering](https://github.com/airbnb/enzyme/blob/master/docs/api/shallow.md) for tests because they are
fast and easy to maintain. In cases where shallow rendering doesn't make sense, we use
[jsdom](https://github.com/tmpvar/jsdom) to mock the DOM and use enzyme's
[full rendering](https://github.com/airbnb/enzyme/blob/master/docs/api/mount.md) tools.
We use [jest](https://jestjs.io/) for unit tests and [react-testing-library](https://testing-library.com/docs/react-testing-library/intro) for rendering and writing assertions.

We split the tests into 2 groups.
1. Visual tests
- A Storybook story should be written for any visual breakage of a component.
2. Unit tests
- (Props) Anything that should be changed by a prop should be tested via enzyme.
- (Events) Anything that should trigger an event should be tested via enzyme.
- (Props) Anything that should be changed by a prop should be tested via react-testing-library.
- (Events) Anything that should trigger an event should be tested via react-testing-library.

You can run the tests with:

```bash
npm test
yarn jest
```

You can also get a code coverage report by running:

```bash
make cover
```
#### Clocks
We are attempting to make more use of the mocked out clock to improve run time of tests and remove our dependency on the clock.
This also decouples our tests from our implementation. Things like requestAnimationFrame no longer need to be explicitly waited for in the tests.
Mocking the clock in this fashion can turn an async test into a synchronous test increasing readability and maintainability.
Since components are being opted into this, this needs to be added to any test suite that wants to migrate over:
mocking of the clock object
```js
let clock;

before(() => {
clock = sinon.useFakeTimers();
});

after(() => {
clock.runAll();
clock.restore();
});
yarn jest --coverage
```
Once the clock is mocked, there are three things to use to trigger updates and events:
- clock.tick(x)
This function is to be used where the code in the project actually relies on real time, for instance, the `OpenTransition` component relies on the actual clock. It's also useful in tests when you want an async helper function but you want to control when it will resolve.
A handy way to tell when this should be used: if `await sleep(x)` where x > 1, then clock.tick(x) should be used instead.
- clock.runAll()
This function is useful when waiting for requestAnimationFrame, even if there are nested ones, it only takes this one call, as anything added to the clock during the course of runAll will also be run.
- tree.update()
This function is useful when state has changed in a component and the lifecycle methods need to be activated. This is not dependent on the clock and must be called sometimes in addition to clock.runAll().

### TypeScript

The code for React Spectrum v3 is written in [TypeScript](https://www.typescriptlang.org/). The type checker will usually run in your editor, but also runs when you run `make lint`.

### Linting

Expand Down