diff --git a/.gitignore b/.gitignore index 0c78dba8c8..7b825fa6d9 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ npm-debug.log* pids *.pid *.seed +tmp # Directory for instrumented libs generated by jscoverage/JSCover lib-cov @@ -25,7 +26,6 @@ lib-cov # Coverage directory used by tools like istanbul coverage - # node-waf configuration .lock-wscript diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9fa5e07d8c..498fc703e9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,51 +1,55 @@ -## Development process - -1. Branch off of `staging`: `git checkout -b username/branch-name`. -1. Commit your changes -1. Make a pull request against the `staging` branch and format your pull request description using the following format: - - **Added:** for new features or components. _Include a screenshot for new visual elements._ - - **Changed:** for changes in existing functionality or design. If the change was visual, _include a comparison screenshot showing the before and after the visual change._ - - **Deprecated:** for once-stable features or components removed in upcoming releases. - - **Removed:** for deprecated features or components removed in this release. - - **Fixed:** for any bug fixes. - ## Running locally -### Package management - This project uses [Yarn](https://yarnpkg.com/) for package management. Yarn helps ensure everyone is using the same package versions. If you've used NPM before, you'll have no trouble using Yarn. [**Install Yarn**](https://yarnpkg.com/docs/install), if you don't have it yet. -#### Install build process dependencies +### Getting started -``` -yarn install -``` +1. `yarn install` +1. `yarn bootstrap:yarn` -#### Install package dependencies - -``` -yarn bootstrap:yarn -``` - -The `bootstrap:yarn` command runs [`yerna`](https://github.com/palantir/yerna) which allows us to have multiple packages within the same repo. Yerna installs all our dependencies and links any cross-dependencies. If you're using `npm` rather than `yarn`, there is also a `bootstrap:npm` command. +The `bootstrap:yarn` command runs [`yerna`](https://github.com/palantir/yerna) which allows us to have multiple packages within the same repo (a monorepo). Yerna installs all our dependencies and links any cross-dependencies. If you're using `npm` rather than `yarn`, there is also a `bootstrap:npm` command. _Note_: `yerna` will become obsolete once [Lerna](https://lernajs.io/) [is merged into Yarn](https://github.com/yarnpkg/yarn/issues/946#issuecomment-264597575). ### Scripts +Additional scripts exist and can all be run from the root level of the repo: + - `yarn run start` - You'll want to run this when you're developing components. It compiles Sass, transpiles JavaScript, and runs a local documentation instance where you can preview changes. - `yarn run build` - compile/transpile/uglify everything and makes things release-ready. - `yarn run bump` - increments package versions. Read "[Versioning](https://github.com/CMSgov/design-system/wiki/Versioning)" for more info. - `yarn run generate` - Generates the necessary files for a new core component -- `yarn run g` - Alias for `yarn run generate` + - `yarn run g` - Alias for `yarn run generate` - `yarn test` - tests and lints the codebase. -### Coding guidelines +## Development process + +1. Branch off of `staging`: `git checkout -b username/branch-name`. +1. Commit your changes +1. Make a pull request against the `staging` branch and format your pull request description using the following format: + - **Added:** for new features or components. _Include a screenshot for new visual elements._ + - **Changed:** for changes in existing functionality or design. If the change was visual, _include a comparison screenshot showing the before and after the visual change._ + - **Deprecated:** for once-stable features or components removed in upcoming releases. + - **Removed:** for deprecated features or components removed in this release. + - **Fixed:** for any bug fixes. + +## Merging pull requests + +#### Staging + +Use the "**Squash and merge**" option when merging pull requests into the `staging` branch. This keeps our history clean and makes it easier on us when it comes time to create a new release. + +#### Master + +Use the "**Create a merge commit**" option when merging `staging` into `master`. If the pull request includes a version bump, set the commit title to the version number and include the PR # in the commit description. -The CSS coding guidelines for this project try to stay as consistent with [those used by 18F](https://github.com/18F/stylelint-rules). In some cases we've made the decision to be more strict than 18F, using some of [GitHub's stylelint guidelines](https://github.com/primer/stylelint-config-primer). You can [view a full list of stylelint rules here](https://stylelint.io/user-guide/rules). +## Additional guidelines -JavaScript coding guidelines are enforced using the [default ESLint ruleset](https://github.com/eslint/eslint/blob/master/conf/eslint.json), along with [Nava's default ruleset](https://github.com/navahq/eslint-config-nava). You can [view a full list of ESLint rules here](http://eslint.org/docs/rules/). +**[Please view the Wiki](https://github.com/CMSgov/design-system/wiki)** for additional information like: -These should be treated as guides — rules can be modified according to project needs. +- Coding guidelines +- Guiding principles +- How to write documentation +- etc. \ No newline at end of file diff --git a/README.md b/README.md index f490cf19b4..2397ce07b3 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,6 @@ This repo contains multile projects in the `packages` directory. View the README - [core](packages/core/) - Core CSS and React components - [docs](packages/docs/) - The documentation website -## Developing +## Contributing -For complete instructions on how setup a local development environment to contribute to the design system, please read [CONTRIBUTING.md](CONTRIBUTING.md) +Please read the [CONTRIBUTING.md](CONTRIBUTING.md) document to learn about setting up a local development environment, contributing to the design system, and our coding guidelines. \ No newline at end of file diff --git a/package.json b/package.json index e95afbeabb..cdbac15416 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,12 @@ "babel-preset-stage-3": "^6.24.1", "babel-register": "^6.24.1", "browser-sync": "^2.18.8", + "bytes": "^2.5.0", + "cli-table": "^0.3.1", + "colors": "^1.1.2", "crypto": "^0.0.3", "cssnano": "^3.10.0", + "cssstats": "^3.0.0", "del": "^2.2.2", "ejs": "^2.5.6", "eslint": "^3.19.0", @@ -54,7 +58,7 @@ "gulp-util": "^3.0.8", "jest": "^19.0.2", "kss": "^3.0.0-beta.18", - "lerna": "^2.0.0-rc.1", + "lerna": "^2.0.0-rc.3", "lodash": "^4.17.4", "marked": "^0.3.6", "matchdep": "^1.0.1", @@ -73,13 +77,16 @@ "through2": "^2.0.3", "tota11y": "^0.1.6", "vinyl-source-stream": "^1.1.0", - "webpack": "^2.3.3", + "webpack": "^2.4.1", "webpack-dev-middleware": "^1.10.1", "webpack-hot-middleware": "^2.18.0", - "yargs": "^7.0.2", - "yernapkg": "^0.5.0", + "yargs": "^7.1.0", + "yernapkg": "^0.5.1", "yo": "^1.8.5" }, + "optionalDependencies": { + "nodegit": "^0.18.0" + }, "engines": { "node": ">=4.0.0" }, diff --git a/packages/core/dist/components/ChoiceList/Choice.css b/packages/core/dist/components/ChoiceList/Choice.css index 180accf51c..c3fb4b8c1c 100644 --- a/packages/core/dist/components/ChoiceList/Choice.css +++ b/packages/core/dist/components/ChoiceList/Choice.css @@ -1 +1 @@ -.ds-c-choice{margin-left:-100%;opacity:0;position:absolute}.ds-c-choice+label{cursor:pointer;display:block;font-weight:400;margin:8px 0}.ds-c-choice+label:before{background-color:#fff;border:2px solid #212121;box-sizing:border-box;content:"\a0";display:inline-block;height:32px;line-height:32px;margin-right:8px;text-indent:.15em;vertical-align:middle;width:32px}.ds-c-choice--inverse+label:before{background-color:#112e51;border-color:#fff}.ds-c-choice:focus+label:before{box-shadow:0 0 0 2px #fff,0 0 2px 4px #3e94cf}.ds-c-choice--inverse:focus+label:before{box-shadow:0 0 0 2px #112e51,0 0 2px 4px #59bcff}.ds-c-choice:checked+label:before{background-color:#0071bc;background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAJCAQAAACssQXfAAAAiklEQVR4AT3PNUFGARAA4MO1AFRgQVrgTEgNXBZ0Z0aLQI0XANf594932LlLROjQHgmhM9mVwlhkMJO/4S7noMjghKEIPcmuUNNyGpa8uzUcYdA1qjjJ+ntwY8Q16jiIBCte0fSmUUr2Mio3W/BJqwQt2xHaZFhXhBnPqFr7D6eRKVMereeIv5++AKLreD06aLBkAAAAAElFTkSuQmCC');background-image:url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2220%22%20height%3D%2220%22%20viewBox%3D%220%200%20216%20146%22%3E%3Cpath%20fill%3D%22%23fff%22%20d%3D%22M168.86%2037.966l-11.08-11.08c-1.52-1.52-3.367-2.28-5.54-2.28-2.172%200-4.02.76-5.54%202.28L93.254%2080.414%2069.3%2056.38c-1.52-1.522-3.367-2.282-5.54-2.282-2.172%200-4.02.76-5.54%202.28L47.14%2067.46c-1.52%201.522-2.28%203.37-2.28%205.542%200%202.172.76%204.02%202.28%205.54l29.493%2029.493%2011.08%2011.08c1.52%201.52%203.368%202.28%205.54%202.28%202.173%200%204.02-.76%205.54-2.28l11.082-11.08L168.86%2049.05c1.52-1.52%202.283-3.37%202.283-5.54%200-2.174-.76-4.02-2.28-5.54z%22%2F%3E%3C%2Fsvg%3E');background-position:50%;background-repeat:no-repeat;background-size:24px;border-color:#0071bc}.ds-c-choice:disabled+label{color:#757575}.ds-c-choice:disabled+label:before{background-color:#d6d7d9;border:1px solid #aeb0b5;cursor:not-allowed}.ds-c-choice--inverse:disabled+label{color:#bac5cf}.ds-c-choice--inverse:disabled+label:before{background-color:rgba(186,197,207,.15);box-shadow:0 0 0 1px #bac5cf}.ds-c-choice[type=radio]+label:before{border-radius:100%} \ No newline at end of file +.ds-c-fieldset{border:0;margin:24px 0 0;min-width:0;padding:0}.ds-c-choice{margin-left:-100%;opacity:0;position:absolute}.ds-c-choice+label{cursor:pointer;display:block;font-weight:400;margin:8px 0}.ds-c-choice+label:before{background-color:#fff;border:2px solid #212121;box-sizing:border-box;content:"\a0";display:inline-block;height:32px;line-height:32px;margin-right:8px;text-indent:.15em;vertical-align:middle;width:32px}.ds-c-choice--inverse+label:before{background-color:#112e51;border-color:#fff}.ds-c-choice:focus+label:before{box-shadow:0 0 0 2px #fff,0 0 2px 4px #3e94cf}.ds-c-choice--inverse:focus+label:before{box-shadow:0 0 0 2px #112e51,0 0 2px 4px #59bcff}.ds-c-choice:checked+label:before{background-color:#0071bc;background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAJCAQAAACssQXfAAAAiklEQVR4AT3PNUFGARAA4MO1AFRgQVrgTEgNXBZ0Z0aLQI0XANf594932LlLROjQHgmhM9mVwlhkMJO/4S7noMjghKEIPcmuUNNyGpa8uzUcYdA1qjjJ+ntwY8Q16jiIBCte0fSmUUr2Mio3W/BJqwQt2xHaZFhXhBnPqFr7D6eRKVMereeIv5++AKLreD06aLBkAAAAAElFTkSuQmCC');background-image:url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2220%22%20height%3D%2220%22%20viewBox%3D%220%200%20216%20146%22%3E%3Cpath%20fill%3D%22%23fff%22%20d%3D%22M168.86%2037.966l-11.08-11.08c-1.52-1.52-3.367-2.28-5.54-2.28-2.172%200-4.02.76-5.54%202.28L93.254%2080.414%2069.3%2056.38c-1.52-1.522-3.367-2.282-5.54-2.282-2.172%200-4.02.76-5.54%202.28L47.14%2067.46c-1.52%201.522-2.28%203.37-2.28%205.542%200%202.172.76%204.02%202.28%205.54l29.493%2029.493%2011.08%2011.08c1.52%201.52%203.368%202.28%205.54%202.28%202.173%200%204.02-.76%205.54-2.28l11.082-11.08L168.86%2049.05c1.52-1.52%202.283-3.37%202.283-5.54%200-2.174-.76-4.02-2.28-5.54z%22%2F%3E%3C%2Fsvg%3E');background-position:50%;background-repeat:no-repeat;background-size:24px;border-color:#0071bc}.ds-c-choice:disabled+label{color:#757575}.ds-c-choice:disabled+label:before{background-color:#d6d7d9;border:1px solid #aeb0b5;cursor:not-allowed}.ds-c-choice--inverse:disabled+label{color:#bac5cf}.ds-c-choice--inverse:disabled+label:before{background-color:rgba(186,197,207,.15);box-shadow:0 0 0 1px #bac5cf}.ds-c-choice[type=radio]+label:before{border-radius:100%} \ No newline at end of file diff --git a/packages/core/dist/components/ChoiceList/Choice.js b/packages/core/dist/components/ChoiceList/Choice.js index 3ab55ea9e2..2a17c3b071 100644 --- a/packages/core/dist/components/ChoiceList/Choice.js +++ b/packages/core/dist/components/ChoiceList/Choice.js @@ -92,7 +92,7 @@ Choice.propTypes = { */ id: _propTypes2.default.string, /** - * Set to `true` to apply the "inverse" theme + * Applies the "inverse" UI theme */ inversed: _propTypes2.default.bool, /** diff --git a/packages/core/dist/components/ChoiceList/ChoiceList.js b/packages/core/dist/components/ChoiceList/ChoiceList.js new file mode 100644 index 0000000000..f3723dbe18 --- /dev/null +++ b/packages/core/dist/components/ChoiceList/ChoiceList.js @@ -0,0 +1,273 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.ChoiceList = undefined; + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _Choice = require('./Choice'); + +var _Choice2 = _interopRequireDefault(_Choice); + +var _FormLabel = require('../FormLabel/FormLabel'); + +var _FormLabel2 = _interopRequireDefault(_FormLabel); + +var _propTypes = require('prop-types'); + +var _propTypes2 = _interopRequireDefault(_propTypes); + +var _react = require('react'); + +var _react2 = _interopRequireDefault(_react); + +var _Select = require('./Select'); + +var _Select2 = _interopRequireDefault(_Select); + +var _classnames = require('classnames'); + +var _classnames2 = _interopRequireDefault(_classnames); + +var _lodash = require('lodash.uniqueid'); + +var _lodash2 = _interopRequireDefault(_lodash); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +/** + * A `ChoiceList` component can be used to render a `select` menu, radio + * button group, or checkbox group, and their corresponding `label` or `legend`. + * + * You can manually pass in the `type` prop, but the real power of this component + * is unleashed when you let it determine the type of fields for you. It takes + * into account accessibility and usability best practices, so you can pass in + * an array of choices and let it determine whether the choices should be + * presented as radio buttons, checkboxes, or a `select` menu. + */ +var ChoiceList = exports.ChoiceList = function (_React$PureComponent) { + _inherits(ChoiceList, _React$PureComponent); + + function ChoiceList() { + _classCallCheck(this, ChoiceList); + + return _possibleConstructorReturn(this, (ChoiceList.__proto__ || Object.getPrototypeOf(ChoiceList)).apply(this, arguments)); + } + + _createClass(ChoiceList, [{ + key: 'field', + + /** + * Creates the field component(s) based on the type of field we've determined + * it should be. + */ + value: function field() { + var _this2 = this; + + var type = this.type(); + var ChoiceComponent = type === 'select' ? 'option' : _Choice2.default; + var selectProps = {}; + + var choices = this.props.choices.map(function (choice) { + var checked = choice.checked, + defaultChecked = choice.defaultChecked, + label = choice.label, + props = _objectWithoutProperties(choice, ['checked', 'defaultChecked', 'label']); + + if (type === 'select') { + if (checked) selectProps.value = props.value; + if (defaultChecked) selectProps.defaultValue = props.value; + } else { + props.checked = checked; + props.defaultChecked = defaultChecked; + // Individual choices can be disabled as well as the entire list. + // We only need to check for both options on checkbox/radio fields, + // since the element, then we need to generate the ID here + * so it can be shared between the FormLabel and Select component + */ + + }, { + key: 'id', + value: function id() { + // ID will be generated by the Choice component + if (this.type() !== 'select') return; + + if (!this._id) { + // Cache the ID so we're not regenerating it on each method call + this._id = (0, _lodash2.default)('select_' + this.props.name + '_'); + } + + return this._id; + } + + /** + * @param {object} selectProps + * @param {array} options -