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

All components reviewed and simplified #23

Merged
merged 30 commits into from
Feb 4, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
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
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ npm i boundless --save
npm i boundless-button --save
```

## Philosophy

Boundless is a UI toolkit that was conceived to abstract away difficult interface patterns. It follows three main guidelines:

1. Performance is mandatory, not a nice-to-have.
2. Components should be as customizable as possible.
3. Components should be as accessible as possible (falling back to WAI-ARIA attributes when necessary.)

The general idea of this library is to provide ready-to-go solutions for things you really wouldn't want to build yourself, not because they're hard... but because they're hard to design _right_. We are always open to suggestions and strive to keep Boundless as concise and useful as possible.

## Reference styles

A precompiled base "skin" is available to use as a base when customizing Boundless for your own project. Some of the components do rely on the reference layout in their styles to function properly. It is designed to be very unopinionated.
Expand Down
1 change: 0 additions & 1 deletion docs/assets/main.159a10f9b42af8481872d01de41d3843.css

This file was deleted.

1 change: 1 addition & 0 deletions docs/assets/main.1dfbb66fb4e71c52deeb0db1a4874f0b.css

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion docs/assets/main.43845874a5c82028fdc1651762dcd428.css

This file was deleted.

7 changes: 0 additions & 7 deletions docs/assets/main.6bac49c905ae80ce62cf.js

This file was deleted.

1 change: 0 additions & 1 deletion docs/assets/main.a74a61b98a81eeaaffdc77339f30dc53.css

This file was deleted.

1 change: 0 additions & 1 deletion docs/assets/main.aaf146b3cc7c46785633b39be52934f8.css

This file was deleted.

7 changes: 0 additions & 7 deletions docs/assets/main.c3772b0c546e02a25ca7.js

This file was deleted.

1 change: 0 additions & 1 deletion docs/assets/main.c91334ddc26f9f827b5c1bf158a43d87.css

This file was deleted.

7 changes: 7 additions & 0 deletions docs/assets/main.fd7cb6cd1964b3451765.js

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion docs/assets/manifest.bbf41c4e98726cb08ea9.js

This file was deleted.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/index.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Boundless</title><link rel="shortcut icon" href="sparkles.png"><link href="assets/main.159a10f9b42af8481872d01de41d3843.css" rel="stylesheet"></head><body><div id="root"></div><script>!function(){var e=sessionStorage.redirect;delete sessionStorage.redirect,e&&e!=location.href&&history.replaceState(null,null,e)}();</script><script src="//cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react.js"></script><script src="//cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react-dom.js"></script><script src="//cdnjs.cloudflare.com/ajax/libs/prism/1.6.0/prism.min.js"></script><script src="//cdnjs.cloudflare.com/ajax/libs/prism/1.6.0/components/prism-javascript.min.js"></script><script src="//cdnjs.cloudflare.com/ajax/libs/prism/1.6.0/components/prism-bash.min.js"></script><script src="//cdnjs.cloudflare.com/ajax/libs/prism/1.6.0/components/prism-jsx.min.js"></script><script src="//cdnjs.cloudflare.com/ajax/libs/prism/1.6.0/components/prism-stylus.min.js"></script><script src="//cdn.polyfill.io/v2/polyfill.js?features=fetch,promise"></script><script type="text/javascript" src="assets/manifest.5c8442895c093ca30793.js"></script><script type="text/javascript" src="assets/vendor.da82ea67d72ece811fe7.js"></script><script type="text/javascript" src="assets/main.6bac49c905ae80ce62cf.js"></script></body></html><!-- Built from SHA: 8984be97a765607b2ba208c99fead683b068fa42 -->
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>boundless</title><link rel="shortcut icon" href="sparkles.png"><link href="assets/main.1dfbb66fb4e71c52deeb0db1a4874f0b.css" rel="stylesheet"></head><body><div id="root"></div><script>!function(){var e=sessionStorage.redirect;delete sessionStorage.redirect,e&&e!=location.href&&history.replaceState(null,null,e)}();</script><script src="//cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react.js"></script><script src="//cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react-dom.js"></script><script src="//cdnjs.cloudflare.com/ajax/libs/prism/1.6.0/prism.min.js"></script><script src="//cdnjs.cloudflare.com/ajax/libs/prism/1.6.0/components/prism-javascript.min.js"></script><script src="//cdnjs.cloudflare.com/ajax/libs/prism/1.6.0/components/prism-bash.min.js"></script><script src="//cdnjs.cloudflare.com/ajax/libs/prism/1.6.0/components/prism-jsx.min.js"></script><script src="//cdnjs.cloudflare.com/ajax/libs/prism/1.6.0/components/prism-stylus.min.js"></script><script src="//cdn.polyfill.io/v2/polyfill.js?features=fetch,promise"></script><script type="text/javascript" src="assets/manifest.bc64d07f3b4a084a255c.js"></script><script type="text/javascript" src="assets/vendor.b1e0f6db10e73f6b156d.js"></script><script type="text/javascript" src="assets/main.fd7cb6cd1964b3451765.js"></script></body></html><!-- Built from SHA: a28a233bba441de5f75d7ac861ae0fce7636a9e9 -->
2 changes: 1 addition & 1 deletion docs/sitemap.xml
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"><url><loc>http://boundless.js.org/ArrowKeyNavigation</loc><lastmod>2017-01-30</lastmod></url><url><loc>http://boundless.js.org/Async</loc><lastmod>2017-01-30</lastmod></url><url><loc>http://boundless.js.org/Button</loc><lastmod>2017-01-30</lastmod></url><url><loc>http://boundless.js.org/Checkbox</loc><lastmod>2017-01-30</lastmod></url><url><loc>http://boundless.js.org/CheckboxGroup</loc><lastmod>2017-01-30</lastmod></url><url><loc>http://boundless.js.org/Dialog</loc><lastmod>2017-01-30</lastmod></url><url><loc>http://boundless.js.org/FittedText</loc><lastmod>2017-01-30</lastmod></url><url><loc>http://boundless.js.org/Image</loc><lastmod>2017-01-30</lastmod></url><url><loc>http://boundless.js.org/Input</loc><lastmod>2017-01-30</lastmod></url><url><loc>http://boundless.js.org/Modal</loc><lastmod>2017-01-30</lastmod></url><url><loc>http://boundless.js.org/Pagination</loc><lastmod>2017-01-30</lastmod></url><url><loc>http://boundless.js.org/Popover</loc><lastmod>2017-01-30</lastmod></url><url><loc>http://boundless.js.org/Portal</loc><lastmod>2017-01-30</lastmod></url><url><loc>http://boundless.js.org/Progress</loc><lastmod>2017-01-30</lastmod></url><url><loc>http://boundless.js.org/ProgressiveDisclosure</loc><lastmod>2017-01-30</lastmod></url><url><loc>http://boundless.js.org/Radio</loc><lastmod>2017-01-30</lastmod></url><url><loc>http://boundless.js.org/SegmentedControl</loc><lastmod>2017-01-30</lastmod></url><url><loc>http://boundless.js.org/TokenizedInput</loc><lastmod>2017-01-30</lastmod></url><url><loc>http://boundless.js.org/Typeahead</loc><lastmod>2017-01-30</lastmod></url><url><loc>http://boundless.js.org/objectIntersection</loc><lastmod>2017-01-30</lastmod></url><url><loc>http://boundless.js.org/omitKeys</loc><lastmod>2017-01-30</lastmod></url><url><loc>http://boundless.js.org/transformProperty</loc><lastmod>2017-01-30</lastmod></url><url><loc>http://boundless.js.org/uuid</loc><lastmod>2017-01-30</lastmod></url><url><loc>http://boundless.js.org/webNotification</loc><lastmod>2017-01-30</lastmod></url><url><loc>http://boundless.js.org/quickstart</loc><lastmod>2017-01-30</lastmod></url></urlset>
<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"><url><loc>http://boundless.js.org/ArrowKeyNavigation</loc><lastmod>2017-02-03</lastmod></url><url><loc>http://boundless.js.org/Async</loc><lastmod>2017-02-03</lastmod></url><url><loc>http://boundless.js.org/Button</loc><lastmod>2017-02-03</lastmod></url><url><loc>http://boundless.js.org/Checkbox</loc><lastmod>2017-02-03</lastmod></url><url><loc>http://boundless.js.org/CheckboxGroup</loc><lastmod>2017-02-03</lastmod></url><url><loc>http://boundless.js.org/Dialog</loc><lastmod>2017-02-03</lastmod></url><url><loc>http://boundless.js.org/FittedText</loc><lastmod>2017-02-03</lastmod></url><url><loc>http://boundless.js.org/Image</loc><lastmod>2017-02-03</lastmod></url><url><loc>http://boundless.js.org/Input</loc><lastmod>2017-02-03</lastmod></url><url><loc>http://boundless.js.org/Modal</loc><lastmod>2017-02-03</lastmod></url><url><loc>http://boundless.js.org/Pagination</loc><lastmod>2017-02-03</lastmod></url><url><loc>http://boundless.js.org/Popover</loc><lastmod>2017-02-03</lastmod></url><url><loc>http://boundless.js.org/Portal</loc><lastmod>2017-02-03</lastmod></url><url><loc>http://boundless.js.org/Progress</loc><lastmod>2017-02-03</lastmod></url><url><loc>http://boundless.js.org/ProgressiveDisclosure</loc><lastmod>2017-02-03</lastmod></url><url><loc>http://boundless.js.org/Radio</loc><lastmod>2017-02-03</lastmod></url><url><loc>http://boundless.js.org/SegmentedControl</loc><lastmod>2017-02-03</lastmod></url><url><loc>http://boundless.js.org/TokenizedInput</loc><lastmod>2017-02-03</lastmod></url><url><loc>http://boundless.js.org/Typeahead</loc><lastmod>2017-02-03</lastmod></url><url><loc>http://boundless.js.org/objectIntersection</loc><lastmod>2017-02-03</lastmod></url><url><loc>http://boundless.js.org/omitKeys</loc><lastmod>2017-02-03</lastmod></url><url><loc>http://boundless.js.org/transformProperty</loc><lastmod>2017-02-03</lastmod></url><url><loc>http://boundless.js.org/uuid</loc><lastmod>2017-02-03</lastmod></url><url><loc>http://boundless.js.org/webNotification</loc><lastmod>2017-02-03</lastmod></url><url><loc>http://boundless.js.org/quickstart</loc><lastmod>2017-02-03</lastmod></url></urlset>
15 changes: 14 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
{
"name": "boundless",
"description": "Intuitive, accessible solutions for common UI needs in React.",
"description": "accessible, battle-tested, infinitely composable react components",
"version": "1.0.0-beta.6",
"author": "Evan Scott <[email protected]> (http://yaycmyk.com)",
"contributors": [
"Abe Rubenstein <[email protected]>",
"Jenn Creighton <[email protected]>"
],
"license": "MIT",
"keywords": [
"react",
"component",
"library",
"toolkit",
"ui"
],
"main": "public/boundless.js",
"dependencies": {
"classnames": "^2.1.5"
Expand Down Expand Up @@ -58,6 +65,12 @@
},
"jest": {
"cacheDirectory": "node_modules/.cache/jest-cli",
"coveragePathIgnorePatterns": [
"/build/",
"/docs/",
"/node_modules/",
"/packages/boundless-utils-test-helpers/"
],
"coverageReporters": [
"text",
"cobertura",
Expand Down
8 changes: 7 additions & 1 deletion packages/boundless-arrow-key-navigation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,19 @@ There are no required props.

### Optional Props

- __`*`__ ・ any [React-supported attribute](https://facebook.github.io/react/docs/tags-and-attributes.html#html-attributes)

Expects | Default Value
- | -
`any` | `n/a`

- __`component`__ ・ any valid HTML tag name or a React component factory, anything that can be passed as the first argument to `React.createElement`

Expects | Default Value
- | -
`string or function` | `'div'`

- __`defaultActiveChildIndex`__ ・ allows for a particular child to be initially reachable via tabbing
- __`defaultActiveChildIndex`__ ・ allows for a particular child to be initially reachable via tabbing; only applied during first render

Expects | Default Value
- | -
Expand Down
51 changes: 27 additions & 24 deletions packages/boundless-arrow-key-navigation/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import React, {PropTypes} from 'react';
import React, {Children, PropTypes} from 'react';
import {findDOMNode} from 'react-dom';

import omit from 'boundless-utils-omit-keys';
import uuid from 'boundless-utils-uuid';

const DATA_ATTRIBUTE_INDEX = 'data-focus-index';
const DATA_ATTRIBUTE_SKIP = 'data-focus-skip';

/**
__A higher-order component for arrow key navigation on a grouping of children.__

Expand All @@ -19,6 +22,11 @@ export default class ArrowKeyNavigation extends React.PureComponent {
}

static propTypes = {
/**
* any [React-supported attribute](https://facebook.github.io/react/docs/tags-and-attributes.html#html-attributes)
*/
'*': PropTypes.any,

/**
Any valid HTML tag name or a React component factory, anything that can be passed as the first argument to `React.createElement`
*/
Expand All @@ -28,7 +36,7 @@ export default class ArrowKeyNavigation extends React.PureComponent {
]),

/**
Allows for a particular child to be initially reachable via tabbing
Allows for a particular child to be initially reachable via tabbing; only applied during first render
*/
defaultActiveChildIndex: PropTypes.number,

Expand Down Expand Up @@ -71,9 +79,7 @@ export default class ArrowKeyNavigation extends React.PureComponent {

componentWillReceiveProps(nextProps) {
if (this.state.activeChildIndex !== 0) {
const numChildren = nextProps.children
? React.Children.count(nextProps.children)
: 0;
const numChildren = nextProps.children ? Children.count(nextProps.children) : 0;

if (numChildren === 0) {
this.setState({activeChildIndex: 0});
Expand All @@ -84,13 +90,9 @@ export default class ArrowKeyNavigation extends React.PureComponent {
}

setFocus(index) {
const childNode = (
this.refs.wrapper instanceof HTMLElement
? this.refs.wrapper
: findDOMNode(this.refs.wrapper)
).children[index];
const childNode = this.$wrapper.children[index];

if (childNode && childNode.hasAttribute('data-skip')) {
if (childNode && childNode.hasAttribute(DATA_ATTRIBUTE_SKIP)) {
this.moveFocus(
childNode.compareDocumentPosition(document.activeElement) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1
);
Expand All @@ -100,10 +102,7 @@ export default class ArrowKeyNavigation extends React.PureComponent {
}

moveFocus(delta) {
const numChildren = this.props.children
? React.Children.count(this.props.children)
: 0;

const numChildren = this.props.children ? Children.count(this.props.children) : 0;
let nextIndex = this.state.activeChildIndex + delta;

if (nextIndex >= numChildren) {
Expand Down Expand Up @@ -160,9 +159,9 @@ export default class ArrowKeyNavigation extends React.PureComponent {
}

handleFocus = (event) => {
if (event.target.hasAttribute('data-focus-index')) {
const index = parseInt(event.target.getAttribute('data-focus-index'), 10);
const child = React.Children.toArray(this.props.children)[index];
if (event.target.hasAttribute(DATA_ATTRIBUTE_INDEX)) {
const index = parseInt(event.target.getAttribute(DATA_ATTRIBUTE_INDEX), 10);
const child = Children.toArray(this.props.children)[index];

this.setState({activeChildIndex: index});

Expand All @@ -172,25 +171,29 @@ export default class ArrowKeyNavigation extends React.PureComponent {
}
}

children() {
return React.Children.map(this.props.children, (child, index) => {
renderChildren() {
return Children.map(this.props.children, (child, index) => {
return React.cloneElement(child, {
'data-focus-index': index,
'data-skip': parseInt(child.props.tabIndex, 10) === -1 || undefined,
[DATA_ATTRIBUTE_INDEX]: index,
[DATA_ATTRIBUTE_SKIP]: parseInt(child.props.tabIndex, 10) === -1 || undefined,
key: child.key || index,
tabIndex: this.state.activeChildIndex === index ? 0 : -1,
});
});
}

persistWrapperElementReference = (unknownType) => {
this.$wrapper = unknownType instanceof HTMLElement ? unknownType : findDOMNode(unknownType);
}

render() {
return (
<this.props.component
{...omit(this.props, ArrowKeyNavigation.internalKeys)}
ref='wrapper'
ref={this.persistWrapperElementReference}
onFocus={this.handleFocus}
onKeyDown={this.handleKeyDown}>
{this.children()}
{this.renderChildren()}
</this.props.component>
);
}
Expand Down
Loading