diff --git a/.babelrc b/.babelrc deleted file mode 100644 index 420173781..000000000 --- a/.babelrc +++ /dev/null @@ -1,19 +0,0 @@ -{ - "presets": ["es2015", "stage-0", "react"], - "env": { - "development": { - "plugins": [ - ["react-transform", { - "transforms": [{ - "transform": "react-transform-hmr", - "imports": ["react"], - "locals": ["module"] - }, { - "transform": "react-transform-catch-errors", - "imports": ["react", "redbox-react"] - }] - }] - ] - } - } -} diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index 5cd336d3e..000000000 --- a/.eslintrc +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parser": "babel-eslint", - "extends": "airbnb", - "env": { - "browser": true, - "node": true, - "jest": true, - "es6": true - }, - "plugins": ["compat"], - "rules": { - "compat/compat": 2, - "func-names": "off", - "global-require": "off", - "no-use-before-define": 0, - "no-underscore-dangle": 0, - "react/sort-prop-types": 2, - "react/jsx-no-bind": 2, - "react/require-default-props": 0, - "react/no-find-dom-node": 0, - "react/jsx-filename-extension": 0, - "import/prefer-default-export": 0, - "jsx-a11y/no-noninteractive-tabindex": 0, - "jsx-a11y/no-noninteractive-element-interactions": 0, - "jsx-a11y/no-static-element-interactions": 0, - "jsx-a11y/label-has-for": 0, - "import/no-extraneous-dependencies": [ - "error", { - "devDependencies": true, - "optionalDependencies": false, - "peerDependencies": false - } - ] - } -} diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 000000000..268379270 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,52 @@ +module.exports = { + parser: 'babel-eslint', + parserOptions: { + ecmaVersion: 6 + }, + extends: 'airbnb', + env: { + browser: true, + es6: true, + jest: true, + node: true + }, + plugins: [ + 'compat', + 'import', + 'jest', + 'jsx-a11y', + 'react' + ], + rules: { + 'compat/compat': 'error', + 'func-names': 'off', + 'global-require': 'off', + 'import/prefer-default-export': 'off', + 'import/no-extraneous-dependencies': [ + 'error', + { + devDependencies: true, + optionalDependencies: false, + peerDependencies: false + } + ], + 'jsx-a11y/click-events-have-key-events': 'off', + 'jsx-a11y/label-has-for': 'off', + 'jsx-a11y/label-has-associated-control': [ + 'error', { + depth: 3, + }, + ], + 'jsx-a11y/no-noninteractive-element-interactions': 'off', + 'jsx-a11y/no-noninteractive-tabindex': 'off', + 'jsx-a11y/no-static-element-interactions': 'off', + 'no-underscore-dangle': 'off', + 'no-use-before-define': 'off', + 'react/destructuring-assignment': 'off', + 'react/jsx-filename-extension': 'off', + 'react/jsx-no-bind': 'error', + 'react/no-find-dom-node': 'off', + 'react/require-default-props': 'off', + 'react/sort-prop-types': 'error' + } +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 6be2ae859..6a870dda2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,43 @@ -lib +# See https://help.github.com/ignore-files/ for more about ignoring files. +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +deploy.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Production build -node_modules -npm-debug.log -.idea +dist +out +lib + +# Dependency directories +node_modules/ + +# App directories +public/styles +public/js/* +!public/js/plugins + +# OS files .DS_Store +._* + +# Config files +.env + +# IDE files +.idea .vscode + +# Test coverage folder +.coverage +/coverage \ No newline at end of file diff --git a/.lintstagedrc b/.lintstagedrc deleted file mode 100644 index 8a2904f4d..000000000 --- a/.lintstagedrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "*.js": [ - "eslint --fix", - "git add" - ], - "*.scss": "sass-lint --max-warnings 0 -v" -} diff --git a/.stylelintrc b/.stylelintrc deleted file mode 100644 index 78537f057..000000000 --- a/.stylelintrc +++ /dev/null @@ -1,33 +0,0 @@ -{ - "extends": "stylelint-config-standard", - "plugins": [ - "stylelint-order" - ], - "rules": { - "at-rule-no-unknown": [true, { - ignoreAtRules: ["define-mixin", "mixin", "each"] - }], - "property-no-unknown": [ true, { - "ignoreProperties": [ - "composes", - "font-smoothing" - ] - }], - "color-hex-case": "lower", - "order/order": [ - "custom-properties", - "declarations" - ], - "order/properties-alphabetical-order": true, - "font-family-name-quotes": "always-where-recommended", - "string-quotes": "single", - "selector-pseudo-class-no-unknown": [ - true, - { - "ignorePseudoClasses": [ - "global" - ] - } - ] - } -} diff --git a/CHANGELOG.md b/CHANGELOG.md index ec1afa6c0..8be3d3899 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,114 @@ + +## 2.0.0-beta.12 (2018-06-02) + +* Add `accept` property to `BrowseButton` (#1533) ([934ffd2](https://github.com/react-toolbox/react-toolbox/commit/934ffd2)), closes [#1533](https://github.com/react-toolbox/react-toolbox/issues/1533) +* Add `multiple` property to `BrowseButton` (#1656) ([071a4d3](https://github.com/react-toolbox/react-toolbox/commit/071a4d3)), closes [#1656](https://github.com/react-toolbox/react-toolbox/issues/1656) +* Add default export TypeScript type to IconButton (#1577) ([79e031e](https://github.com/react-toolbox/react-toolbox/commit/79e031e)), closes [#1577](https://github.com/react-toolbox/react-toolbox/issues/1577) +* Add falsy key example to AutocompleteTest ([f24d128](https://github.com/react-toolbox/react-toolbox/commit/f24d128)) +* Add missing Input import ([51a335b](https://github.com/react-toolbox/react-toolbox/commit/51a335b)), closes [#1792](https://github.com/react-toolbox/react-toolbox/issues/1792) +* Add onEscKeyDown and onOverlayClick fallbacks ([4347125](https://github.com/react-toolbox/react-toolbox/commit/4347125)) +* Add postcss-apply to buid task and to webpack ([82f7118](https://github.com/react-toolbox/react-toolbox/commit/82f7118)) +* Add support for treeshaking (#1423) ([d2eee5a](https://github.com/react-toolbox/react-toolbox/commit/d2eee5a)), closes [#1423](https://github.com/react-toolbox/react-toolbox/issues/1423) +* Add ThemeProvider Typescript type (#1576) ([7403d5d](https://github.com/react-toolbox/react-toolbox/commit/7403d5d)), closes [#1576](https://github.com/react-toolbox/react-toolbox/issues/1576) +* Add title to image ([f815fb5](https://github.com/react-toolbox/react-toolbox/commit/f815fb5)) +* Add transition to hover effect in list items ([d9a0d7e](https://github.com/react-toolbox/react-toolbox/commit/d9a0d7e)) +* Add variables for the App Bar's font size and weight. (#1518) ([f93040e](https://github.com/react-toolbox/react-toolbox/commit/f93040e)), closes [#1518](https://github.com/react-toolbox/react-toolbox/issues/1518) +* Add workaround to `is-component-of-type` for `react-hot-loader@^3` (#1569) ([431abb1](https://github.com/react-toolbox/react-toolbox/commit/431abb1)), closes [#1569](https://github.com/react-toolbox/react-toolbox/issues/1569) +* Added label to InputTheme interface (#1501) ([6290cf5](https://github.com/react-toolbox/react-toolbox/commit/6290cf5)), closes [#1501](https://github.com/react-toolbox/react-toolbox/issues/1501) +* Added missing `|` (#1403) ([8df122a](https://github.com/react-toolbox/react-toolbox/commit/8df122a)), closes [#1403](https://github.com/react-toolbox/react-toolbox/issues/1403) +* Added required?: boolean; (#1491) ([27caadb](https://github.com/react-toolbox/react-toolbox/commit/27caadb)), closes [#1491](https://github.com/react-toolbox/react-toolbox/issues/1491) +* adds a span wrapper to the component button in case of its disabled and have mouse enter and mouse l ([0286630](https://github.com/react-toolbox/react-toolbox/commit/0286630)) +* Allow autoFocus on Autocomplete component ([a828091](https://github.com/react-toolbox/react-toolbox/commit/a828091)) +* Allow pass inverse to IconMenu (#1490) ([4722904](https://github.com/react-toolbox/react-toolbox/commit/4722904)), closes [#1490](https://github.com/react-toolbox/react-toolbox/issues/1490) +* Allow to change FontIcon for Tab by passing it into the factory (#1439) ([d6bdf20](https://github.com/react-toolbox/react-toolbox/commit/d6bdf20)), closes [#1439](https://github.com/react-toolbox/react-toolbox/issues/1439) +* allows the Portal HOC root element to receive a style props. This allows coordinate runtime position ([0e299a6](https://github.com/react-toolbox/react-toolbox/commit/0e299a6)), closes [#1502](https://github.com/react-toolbox/react-toolbox/issues/1502) +* Apply padding 0 to everything but buttons in ListItemAction (#1571) ([f44833a](https://github.com/react-toolbox/react-toolbox/commit/f44833a)), closes [#1571](https://github.com/react-toolbox/react-toolbox/issues/1571) +* Avoid undefined className when ProgressBar mode is determinate ([7db3e34](https://github.com/react-toolbox/react-toolbox/commit/7db3e34)) +* Change tab style for ripple to work with Tabs (#1519) ([cd6a130](https://github.com/react-toolbox/react-toolbox/commit/cd6a130)), closes [#1519](https://github.com/react-toolbox/react-toolbox/issues/1519) +* Check whether the query key has a value rather than whether it's truthy ([f79aaff](https://github.com/react-toolbox/react-toolbox/commit/f79aaff)) +* Disabled input should be dashed not dotted ([a46f095](https://github.com/react-toolbox/react-toolbox/commit/a46f095)) +* Do not show scrollbar on autocomplete component IE11 (#1515) ([f8f528c](https://github.com/react-toolbox/react-toolbox/commit/f8f528c)), closes [#1515](https://github.com/react-toolbox/react-toolbox/issues/1515) +* Docs/Install: Fix typos, clarify language (#1566) ([2124c8c](https://github.com/react-toolbox/react-toolbox/commit/2124c8c)), closes [#1566](https://github.com/react-toolbox/react-toolbox/issues/1566) +* Document usage with Create React App (#1482) ([d5b49a2](https://github.com/react-toolbox/react-toolbox/commit/d5b49a2)), closes [#1482](https://github.com/react-toolbox/react-toolbox/issues/1482) +* Don't handle key events if slider is disabled ([6925570](https://github.com/react-toolbox/react-toolbox/commit/6925570)) +* Enable onKeyDown and onKeyUp props on Autocomplete component ([2c92c37](https://github.com/react-toolbox/react-toolbox/commit/2c92c37)) +* Event passed for Radiogroup (#1544) ([6fd1421](https://github.com/react-toolbox/react-toolbox/commit/6fd1421)), closes [#1544](https://github.com/react-toolbox/react-toolbox/issues/1544) +* Feature/tabs a11y (#1513) ([94f6493](https://github.com/react-toolbox/react-toolbox/commit/94f6493)), closes [#1513](https://github.com/react-toolbox/react-toolbox/issues/1513) +* fix #1611 (#1612) ([df175e7](https://github.com/react-toolbox/react-toolbox/commit/df175e7)), closes [#1611](https://github.com/react-toolbox/react-toolbox/issues/1611) [#1612](https://github.com/react-toolbox/react-toolbox/issues/1612) +* Fix AppBar doc (#1407) ([06cbc41](https://github.com/react-toolbox/react-toolbox/commit/06cbc41)), closes [#1407](https://github.com/react-toolbox/react-toolbox/issues/1407) +* Fix bug where dropdowns don't close (#1548) ([13520e3](https://github.com/react-toolbox/react-toolbox/commit/13520e3)), closes [#1548](https://github.com/react-toolbox/react-toolbox/issues/1548) +* Fix compatibility with typescript 2.4+ (#1615) ([b381db4](https://github.com/react-toolbox/react-toolbox/commit/b381db4)), closes [#1615](https://github.com/react-toolbox/react-toolbox/issues/1615) +* Fix date-picker animation in IE11 (#1586) ([54d0cb5](https://github.com/react-toolbox/react-toolbox/commit/54d0cb5)), closes [#1586](https://github.com/react-toolbox/react-toolbox/issues/1586) +* Fix eslint errors ([f006708](https://github.com/react-toolbox/react-toolbox/commit/f006708)) +* Fix lint issue (#1624) ([6d43f88](https://github.com/react-toolbox/react-toolbox/commit/6d43f88)), closes [#1624](https://github.com/react-toolbox/react-toolbox/issues/1624) +* Fix media queries panel height calculations (#1467) ([4a13ff2](https://github.com/react-toolbox/react-toolbox/commit/4a13ff2)), closes [#1467](https://github.com/react-toolbox/react-toolbox/issues/1467) +* Fix mismatch between NPM published version and package.json version ([ecbdb12](https://github.com/react-toolbox/react-toolbox/commit/ecbdb12)) +* Fix mixed up type definitions for Dropdown ([47d2f18](https://github.com/react-toolbox/react-toolbox/commit/47d2f18)) +* Fix Mobile Safari issues. (#1282) ([e15ee8e](https://github.com/react-toolbox/react-toolbox/commit/e15ee8e)), closes [#1282](https://github.com/react-toolbox/react-toolbox/issues/1282) +* Fix package.json ([e1f320c](https://github.com/react-toolbox/react-toolbox/commit/e1f320c)) +* Fix README on example project description (#1497) ([eb04045](https://github.com/react-toolbox/react-toolbox/commit/eb04045)), closes [#1497](https://github.com/react-toolbox/react-toolbox/issues/1497) [/github.com/react-toolbox/react-toolbox/pull/1251#issuecomment-302403914](https://github.com//github.com/react-toolbox/react-toolbox/pull/1251/issues/issuecomment-302403914) +* Fix tests ([9a9396f](https://github.com/react-toolbox/react-toolbox/commit/9a9396f)) +* Fix travis ([32e4096](https://github.com/react-toolbox/react-toolbox/commit/32e4096)) +* Fix travis ([71341d9](https://github.com/react-toolbox/react-toolbox/commit/71341d9)) +* Fix tsc errors ([6357bed](https://github.com/react-toolbox/react-toolbox/commit/6357bed)) +* Fix typescript bindings. (#1564) ([de69a14](https://github.com/react-toolbox/react-toolbox/commit/de69a14)), closes [#1564](https://github.com/react-toolbox/react-toolbox/issues/1564) [#1407](https://github.com/react-toolbox/react-toolbox/issues/1407) +* fixed browser button fires onChange event twice (#1557) ([c1a2dba](https://github.com/react-toolbox/react-toolbox/commit/c1a2dba)), closes [#1557](https://github.com/react-toolbox/react-toolbox/issues/1557) +* Fixes #1452 (#1454) ([9619d85](https://github.com/react-toolbox/react-toolbox/commit/9619d85)), closes [#1452](https://github.com/react-toolbox/react-toolbox/issues/1452) [#1454](https://github.com/react-toolbox/react-toolbox/issues/1454) [#1452](https://github.com/react-toolbox/react-toolbox/issues/1452) +* Handle onChange in errored input in docs ([c6a7b5b](https://github.com/react-toolbox/react-toolbox/commit/c6a7b5b)) +* Importing PropTypes from prop-types rather than react (#1413) ([ae09770](https://github.com/react-toolbox/react-toolbox/commit/ae09770)), closes [#1413](https://github.com/react-toolbox/react-toolbox/issues/1413) +* Issue 1459: Replace onClick handler in Dropdown component to onMouseDown (#1521) ([736f23e](https://github.com/react-toolbox/react-toolbox/commit/736f23e)), closes [#1521](https://github.com/react-toolbox/react-toolbox/issues/1521) +* Link text has text-transform: capitalize, contrary to Material specs, is removed. ([470ffae](https://github.com/react-toolbox/react-toolbox/commit/470ffae)) +* ListItem component theme prop extends ListItemTextTheme. ([11c3fb1](https://github.com/react-toolbox/react-toolbox/commit/11c3fb1)) +* ListItem legend may be a node as well (#1496) ([a6eb5c5](https://github.com/react-toolbox/react-toolbox/commit/a6eb5c5)), closes [#1496](https://github.com/react-toolbox/react-toolbox/issues/1496) +* Made role on input field a property (#1553) ([fc9c180](https://github.com/react-toolbox/react-toolbox/commit/fc9c180)), closes [#1553](https://github.com/react-toolbox/react-toolbox/issues/1553) +* Make checkbox border color according to spec ([4670098](https://github.com/react-toolbox/react-toolbox/commit/4670098)) +* Make checkbox centered between table edge and next column start ([b660bcc](https://github.com/react-toolbox/react-toolbox/commit/b660bcc)) +* Move Input#validPresent to utils#isValuePresent ([1dafc56](https://github.com/react-toolbox/react-toolbox/commit/1dafc56)) +* Move tsd task to gulpfile ([a9518b6](https://github.com/react-toolbox/react-toolbox/commit/a9518b6)) +* onchange ([4d64c73](https://github.com/react-toolbox/react-toolbox/commit/4d64c73)) +* Pass the theme prop to TableRow child components ([73b2594](https://github.com/react-toolbox/react-toolbox/commit/73b2594)), closes [#1805](https://github.com/react-toolbox/react-toolbox/issues/1805) +* Remove box-shadow on required inputs ([14eb6ca](https://github.com/react-toolbox/react-toolbox/commit/14eb6ca)) +* Remove discord link in README.md (#1593) ([16ae9bf](https://github.com/react-toolbox/react-toolbox/commit/16ae9bf)), closes [#1593](https://github.com/react-toolbox/react-toolbox/issues/1593) [#107](https://github.com/react-toolbox/react-toolbox/issues/107) +* Remove max-height from dialog along with hidden overflow ([2eb27c7](https://github.com/react-toolbox/react-toolbox/commit/2eb27c7)) +* Remove unknown prop multilineHint which React reports as passed to textarea ([478c9ae](https://github.com/react-toolbox/react-toolbox/commit/478c9ae)) +* requestAnimationFrame will only trigger if the browser window is visible. If the browser tab is put ([fb5d0e1](https://github.com/react-toolbox/react-toolbox/commit/fb5d0e1)), closes [#1604](https://github.com/react-toolbox/react-toolbox/issues/1604) +* Revert "Update components to use css-transition-group 2" ([752cdd3](https://github.com/react-toolbox/react-toolbox/commit/752cdd3)) +* small typo error corrected. ([f78c084](https://github.com/react-toolbox/react-toolbox/commit/f78c084)) +* solve #1444 and #1359. (#1587) ([843b88a](https://github.com/react-toolbox/react-toolbox/commit/843b88a)), closes [#1444](https://github.com/react-toolbox/react-toolbox/issues/1444) [#1359](https://github.com/react-toolbox/react-toolbox/issues/1359) [#1587](https://github.com/react-toolbox/react-toolbox/issues/1587) +* Typescript definitions validation (#1163) ([91cb46d](https://github.com/react-toolbox/react-toolbox/commit/91cb46d)), closes [#1163](https://github.com/react-toolbox/react-toolbox/issues/1163) +* Update Autocomplete TypeScript declaration file and readme with key callbacks ([b79c3da](https://github.com/react-toolbox/react-toolbox/commit/b79c3da)) +* Update CHANGELOG.md (#1399) ([0d21c02](https://github.com/react-toolbox/react-toolbox/commit/0d21c02)), closes [#1399](https://github.com/react-toolbox/react-toolbox/issues/1399) +* Update DatePicker.d.ts (#1411) ([e572dd7](https://github.com/react-toolbox/react-toolbox/commit/e572dd7)), closes [#1411](https://github.com/react-toolbox/react-toolbox/issues/1411) +* update defaults in input component config.css ([25172c5](https://github.com/react-toolbox/react-toolbox/commit/25172c5)) +* Update dependencies ([be80e0b](https://github.com/react-toolbox/react-toolbox/commit/be80e0b)) +* Update enzyme config files ([d313e11](https://github.com/react-toolbox/react-toolbox/commit/d313e11)) +* Update readme for Autocomplete (#1657) ([4ca6747](https://github.com/react-toolbox/react-toolbox/commit/4ca6747)), closes [#1657](https://github.com/react-toolbox/react-toolbox/issues/1657) [/github.com/react-toolbox/react-toolbox/blob/8e2b688954d4b413a602bb59a89254e752f20b0f/components/autocomplete/Autocomplete.d.ts#L54](https://github.com//github.com/react-toolbox/react-toolbox/blob/8e2b688954d4b413a602bb59a89254e752f20b0f/components/autocomplete/Autocomplete.d.ts/issues/L54) +* Update README.md ([afb6532](https://github.com/react-toolbox/react-toolbox/commit/afb6532)) +* Update README.md ([3d8cd66](https://github.com/react-toolbox/react-toolbox/commit/3d8cd66)) +* Update readme.md (#1478) ([f90958d](https://github.com/react-toolbox/react-toolbox/commit/f90958d)), closes [#1478](https://github.com/react-toolbox/react-toolbox/issues/1478) +* Update tests to use css-transition-group 2 ([ab2e789](https://github.com/react-toolbox/react-toolbox/commit/ab2e789)) +* Update tests to use Enzyme 3 ([c510029](https://github.com/react-toolbox/react-toolbox/commit/c510029)) +* Update tests to use react-dom/test-utils ([08ca837](https://github.com/react-toolbox/react-toolbox/commit/08ca837)) +* Update URLs to new .io domain ([b0a7533](https://github.com/react-toolbox/react-toolbox/commit/b0a7533)) +* Update versions ([7e4c12e](https://github.com/react-toolbox/react-toolbox/commit/7e4c12e)) +* Updated dependencies (#1448) ([2981da4](https://github.com/react-toolbox/react-toolbox/commit/2981da4)), closes [#1448](https://github.com/react-toolbox/react-toolbox/issues/1448) +* Upgrade react-transition-group ([ced94a4](https://github.com/react-toolbox/react-toolbox/commit/ced94a4)) +* Upgrade to node 7 ([66a47bb](https://github.com/react-toolbox/react-toolbox/commit/66a47bb)) +* Use code instead of keyCode ([f8a7e88](https://github.com/react-toolbox/react-toolbox/commit/f8a7e88)) +* Use hover effect on selected table row as well ([889e9ca](https://github.com/react-toolbox/react-toolbox/commit/889e9ca)) +* Use innerRef to blur input ([a7d0c5b](https://github.com/react-toolbox/react-toolbox/commit/a7d0c5b)) +* Use proper code values in KEYS constant 🤦🏻‍♂️ ([6fa13f1](https://github.com/react-toolbox/react-toolbox/commit/6fa13f1)) +* Use window.requestAnimationFrame in Tabs.js ([bc05c69](https://github.com/react-toolbox/react-toolbox/commit/bc05c69)) +* TypeScript: snack-bar label accepts element ([40aa354](https://github.com/react-toolbox/react-toolbox/commit/40aa354)) +* Portal: Fix Invalid "style" PropType (#1664) ([8b7fc07](https://github.com/react-toolbox/react-toolbox/commit/8b7fc07)), closes [#1664](https://github.com/react-toolbox/react-toolbox/issues/1664) +* IconMenu: active prop (#1662). ([0103d95](https://github.com/react-toolbox/react-toolbox/commit/0103d95)), closes [#1662](https://github.com/react-toolbox/react-toolbox/issues/1662) +* IconMenu: active prop (#1662). ([74bd2dc](https://github.com/react-toolbox/react-toolbox/commit/74bd2dc)), closes [#1662](https://github.com/react-toolbox/react-toolbox/issues/1662) +* IconMenu: active prop (#1662). more tests. ([bf790d7](https://github.com/react-toolbox/react-toolbox/commit/bf790d7)), closes [#1662](https://github.com/react-toolbox/react-toolbox/issues/1662) +* IconMenu: active prop (fixes #1662). ([0f51c06](https://github.com/react-toolbox/react-toolbox/commit/0f51c06)), closes [#1662](https://github.com/react-toolbox/react-toolbox/issues/1662) +* fix: of -> or in documentation ([31fac7b](https://github.com/react-toolbox/react-toolbox/commit/31fac7b)) + + + # 2.0.0-beta.8 (2017-04-06) diff --git a/README.md b/README.md index 6287e2da9..55d0d8c55 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# +# [![npm version](https://img.shields.io/npm/v/react-toolbox.svg?style=flat-square)](https://www.npmjs.com/package/react-toolbox) [![Build Status](http://img.shields.io/travis/react-toolbox/react-toolbox/master.svg?style=flat-square)](https://travis-ci.org/react-toolbox/react-toolbox) [![NPM Status](http://img.shields.io/npm/dm/react-toolbox.svg?style=flat-square)](https://www.npmjs.org/package/react-toolbox) [![Donate](https://img.shields.io/badge/donate-paypal-blue.svg?style=flat-square)](https://paypal.me/javivelasco) [![OpenCollective](https://opencollective.com/react-toolbox/backers/badge.svg)](#backers) [![OpenCollective](https://opencollective.com/react-toolbox/sponsors/badge.svg)](#sponsors) @@ -17,7 +17,7 @@ $ npm install --save react-toolbox ## Prerequisites -React Toolbox uses [CSS Modules](https://github.com/css-modules/css-modules) by default to import stylesheets written using PostCSS/[cssnext](http://cssnext.io/) features. In case you want to import the components already bundled with CSS, your module bundler should be able to require these PostCSS modules. +React Toolbox uses [CSS Modules](https://github.com/css-modules/css-modules) by default to import stylesheets written using [PostCSS](https://github.com/postcss/postcss) & [postcss-preset-env](https://preset-env.cssdb.org/) features. In case you want to import the components already bundled with CSS, your module bundler should be able to require these PostCSS modules. Although we recommend [webpack](https://webpack.github.io/), you are free to use whatever module bundler you want as long as it can compile and require PostCSS files located in your `node_modules`. If you are experiencing require errors, make sure your configuration satisfies this requirement. @@ -33,8 +33,7 @@ Follow [these instructions](https://github.com/react-toolbox/react-toolbox-themr ```bash npm install postcss-loader --save-dev -npm install postcss --save -npm install postcss-cssnext --save +npm install postcss postcss-preset-env postcss-calc --save ``` Configure webpack 1.x loader for .css files to use postcss: @@ -49,10 +48,20 @@ Configure webpack 1.x loader for .css files to use postcss: ``` Declare plugins to be used by postcss (as part of webpack's config object): ```js + // webpack.config.js postcss: () => { return [ /* eslint-disable global-require */ - require('postcss-cssnext'), + require('postcss-preset-env')({ + stage: 0, // required to get all features that were from cssnext without enabling them one by one + features: { + 'custom-properties': { + preserve: false, // required to output values instead of variables + }, + 'color-mod-function': true, // required to use color-mod() + } + }), + require('postcss-calc'), // required as postcss-preset-env doesn't have a reduce calc() funtion that cssnext did /* eslint-enable global-require */ ]; }, @@ -60,22 +69,23 @@ Declare plugins to be used by postcss (as part of webpack's config object): Configure webpack 2.x or 3.x loader for .css files to use postcss: ```js + // webpack.config.js + { + test: /\.css$/, + use: [ + "style-loader", { - test: /\.css$/, - use: [ - "style-loader", - { - loader: "css-loader", - options: { - modules: true, // default is false - sourceMap: true, - importLoaders: 1, - localIdentName: "[name]--[local]--[hash:base64:8]" - } - }, - "postcss-loader" - ] - } + loader: "css-loader", + options: { + modules: true, // default is false + sourceMap: true, + importLoaders: 1, + localIdentName: "[name]--[local]--[hash:base64:8]" + } + }, + "postcss-loader" + ] + } ``` ## Basic usage @@ -115,7 +125,7 @@ First let's take a look on how the components are structured in the project. The |---- theme.css ``` -As you can see in the previous block, each folder includes: a Javascript file for each component/subcomponent; a README with documentation, an index Javascript file that imports and injects styles and dependencies for you, a default theme PostCSS/cssnext stylesheet and a config.css with configuration variables (CSS Custom Properties). Depending on whether you want the styles to be directly bundled or not, you can import components in **two** different ways. +As you can see in the previous block, each folder includes: a Javascript file for each component/subcomponent; a README with documentation, an index Javascript file that imports and injects styles and dependencies for you, a default theme PostCSS/preset-env stylesheet and a config.css with configuration variables (CSS Custom Properties). Depending on whether you want the styles to be directly bundled or not, you can import components in **two** different ways. ### Bundled component @@ -212,14 +222,13 @@ export default App; ## Theming (configuration variables) -You can apply theming in multiple ways. First of all, you have to understand that React Toolbox stylesheets are written using PostCSS with cssnext features and use CSS Custom Properties from the **config** files we saw earlier. In addition, there are some global CSS Properties imported by each component: [colors](https://github.com/react-toolbox/react-toolbox/blob/dev/components/colors.css) and [variables](https://github.com/react-toolbox/react-toolbox/blob/dev/components/variables.css). You can override both the global and component-specific **variables** to get the results you want using one of the methods below. +You can apply theming in multiple ways. First of all, you have to understand that React Toolbox stylesheets are written using PostCSS with postcss-preset-env features and use CSS Custom Properties from the **config** files we saw earlier. In addition, there are some global CSS Properties imported by each component: [colors](https://github.com/react-toolbox/react-toolbox/blob/dev/components/colors.module.css) and [variables](https://github.com/react-toolbox/react-toolbox/blob/dev/components/variables.module.css). You can override both the global and component-specific **variables** to get the results you want using one of the methods below. ### Settings configuration variables in JavaScript -You can override both the global and component-specific CSS Custom Properties at build-time by supplying an object with these variable names and your desired values to the PostCSS customProperties plugin. i.e. if using postcss-next in webpack: +You can override both the global and component-specific CSS Custom Properties at build-time by supplying an object with these variable names and your desired values to the PostCSS `custom-properties` plugin. i.e. if using [postcss-preset-env](https://github.com/csstools/postcss-preset-env) in webpack: ```js - // This can also be stored in a separate file: const reactToolboxVariables = { 'color-text': '#444548', @@ -228,31 +237,34 @@ const reactToolboxVariables = { 'button-height': '30px', }; -// webpack's config object: +// webpack's config object: (webpack.config.js) const config = { ... postcss: () => { return [ /* eslint-disable global-require */ - require('postcss-cssnext')({ + require('postcss-preset-env')({ + stage: 0, // required to get all features that were from cssnext without enabling them one by one features: { - customProperties: { - variables: reactToolboxVariables, + 'custom-properties': { + preserve: false, // required to output values instead of variables + importFrom: reactToolboxVariables, // see postcss-preset-env for config options }, - }, + 'color-mod-function': true, // required to use color-mod() + } }), + require('postcss-calc'), // required as postcss-preset-env doesn't have a reduce calc() funtion that cssnext did /* optional - see next section */ require('postcss-modules-values'), /* eslint-enable global-require */ ]; }, } - ``` ### Settings configuration variables using CSS Module Values -Instead of using a JavaScript object for variables, you can use [CSS Module Values](https://github.com/css-modules/css-modules/blob/master/docs/values-variables.md) (`npm install postcss-modules-values --save`) and the [modules-values-extract](https://github.com/alexhisen/modules-values-extract) utility to declare these variables in component-specific theme .css files, where you would typically store additional style overrides. +Instead of using a JavaScript object for variables, you can use [CSS Module Values](https://github.com/css-modules/css-modules/blob/master/docs/values-variables.md) (`npm install postcss-modules-values --save`) and the [modules-values-extract](https://github.com/alexhisen/modules-values-extract) utility to declare these variables in component-specific theme `.css` files, where you would typically store additional style overrides. CSS Module Values also offer the advantage that importing a css file with @value declarations makes these values properties of the imported style object, i.e.: @@ -268,7 +280,7 @@ import styleVariables from './css/variables.css'; styleVariables.buttonPrimaryBackgroundColor ``` -In [this demo project](https://github.com/alexhisen/mobx-forms-demo), modules-values-extract utility is used to extract all @values with dashes in their name from all css files in the /css folder and to feed them to customProperties in [webpack](https://github.com/alexhisen/mobx-forms-demo/blob/master/webpack.config.js). In the demo project, variables that are not specific to a particular component are in [variables.css](https://github.com/alexhisen/mobx-forms-demo/blob/master/src/css/variables.css) and button-specific variables are in [button.css](https://github.com/alexhisen/mobx-forms-demo/blob/master/src/css/button.css). Note that button.css also imports certain values from variables.css just to demonstrate this capability \(the import can also be used in a @value declaration\) and it uses CSS overrides instead of color variables that exist in the React-Toolbox Button component to show an alternative method if the variables are not sufficient. +In [this demo project](https://github.com/alexhisen/mobx-forms-demo), modules-values-extract utility is used to extract all @values with dashes in their name from all css files in the `/css` folder and to feed them to customProperties in [webpack](https://github.com/alexhisen/mobx-forms-demo/blob/master/webpack.config.js). In the demo project, variables that are not specific to a particular component are in [variables.css](https://github.com/alexhisen/mobx-forms-demo/blob/master/src/css/variables.css) and button-specific variables are in [button.css](https://github.com/alexhisen/mobx-forms-demo/blob/master/src/css/button.css). Note that button.css also imports certain values from variables.css just to demonstrate this capability \(the import can also be used in a @value declaration\) and it uses CSS overrides instead of color variables that exist in the React-Toolbox Button component to show an alternative method if the variables are not sufficient. > **IMPORTANT: Changes to the module values do not take effect immediately with Webpack Hot-Module-Reload - webpack / webpack-dev-server must be restarted!** diff --git a/ROADMAP.md b/ROADMAP.md index 8e9821217..2b1ff11af 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,4 +1,4 @@ -This document defines a manifesto and the main Roadmap 🚵 ideas for [React Toolbox](www.react-toolbox.com). It's not a fixed document and of course it's open to change. You can leave your feedback in [this gist](https://gist.github.com/javivelasco/259d2087c2a8c3e8f2c5c720d1fd3f2e) or you can also do it [through an issue](https://github.com/react-toolbox/react-toolbox/issues/new). +This document defines a manifesto and the main Roadmap 🚵 ideas for [React Toolbox](www.react-toolbox.io). It's not a fixed document and of course it's open to change. You can leave your feedback in [this gist](https://gist.github.com/javivelasco/259d2087c2a8c3e8f2c5c720d1fd3f2e) or you can also do it [through an issue](https://github.com/react-toolbox/react-toolbox/issues/new). ## The Manifesto @@ -68,7 +68,7 @@ There is no fixed date, sorry. Being an open source project, it depends on contr ### Is there any migration guide to 2.0? -Not really. At the end we are just providing components and there are no big changes on them apart from huge refactors of some specific components that will be coming. If should be enough by checking changelogs and new documentation. In any case if you feel like a migration guide is needed, feel free to leave for feedback. +There is a [migration guide](https://github.com/react-toolbox/react-toolbox/wiki/Migrating-from-version-1.3-to-2.0) in the wiki. ### When will be released the new playground? diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 000000000..0b2856212 --- /dev/null +++ b/babel.config.js @@ -0,0 +1,35 @@ +module.exports = function (api) { + const env = api.env(); + api.cache.using(() => env === 'development'); + + return { + presets: ['@babel/preset-env', '@babel/preset-react'], + plugins: [ + '@babel/plugin-transform-runtime', + // Stage 0 + '@babel/plugin-proposal-function-bind', + + // Stage 1 + '@babel/plugin-proposal-export-default-from', + '@babel/plugin-proposal-logical-assignment-operators', + ['@babel/plugin-proposal-optional-chaining', { loose: false }], + ['@babel/plugin-proposal-pipeline-operator', { proposal: 'minimal' }], + ['@babel/plugin-proposal-nullish-coalescing-operator', { loose: false }], + '@babel/plugin-proposal-do-expressions', + + // Stage 2 + ['@babel/plugin-proposal-decorators', { legacy: true }], + '@babel/plugin-proposal-function-sent', + '@babel/plugin-proposal-export-namespace-from', + '@babel/plugin-proposal-numeric-separator', + '@babel/plugin-proposal-throw-expressions', + + // Stage 3 + '@babel/plugin-syntax-dynamic-import', + '@babel/plugin-syntax-import-meta', + ['@babel/plugin-proposal-class-properties', { loose: false }], + '@babel/plugin-proposal-json-strings', + 'react-hot-loader/babel', + ], + }; +}; diff --git a/components/__mocks__/react-css-themr.js b/components/__mocks__/react-css-themr.js index 0db02aaf4..749303b52 100644 --- a/components/__mocks__/react-css-themr.js +++ b/components/__mocks__/react-css-themr.js @@ -1,6 +1,6 @@ export function themr() { return (Component) => { - Component.defaultProps = Component.defaultProps || {}; // eslint-disable-line no-param-reassign + Component.defaultProps = Component.defaultProps || {}; // eslint-disable-line no-param-reassign Component.defaultProps.theme = {}; // eslint-disable-line no-param-reassign return Component; }; diff --git a/components/app_bar/AppBar.js b/components/app_bar/AppBar.js index d4421b87d..93627fc07 100644 --- a/components/app_bar/AppBar.js +++ b/components/app_bar/AppBar.js @@ -25,9 +25,9 @@ const factory = (IconButton) => { scrollHide: PropTypes.bool, theme: PropTypes.shape({ appBar: PropTypes.string, - inner: PropTypes.string, fixed: PropTypes.string, flat: PropTypes.string, + inner: PropTypes.string, leftIcon: PropTypes.string, rightIcon: PropTypes.string, scrollHide: PropTypes.string, @@ -46,7 +46,7 @@ const factory = (IconButton) => { scrollHide: false, }; - state = { hidden: false, height: 0 }; + state = { hidden: false, height: 0 }; // eslint-disable-line react/no-unused-state componentDidMount() { if (this.props.scrollHide) { @@ -70,26 +70,27 @@ const factory = (IconButton) => { } } - initializeScroll() { + handleScroll = () => { + const scrollDiff = this.curScroll - window.scrollY; + this.setState(state => ({ + hidden: scrollDiff < 0 + && window.scrollY !== undefined + && window.scrollY > state.height, + })); + this.curScroll = window.scrollY; + }; + + initializeScroll = () => { window.addEventListener('scroll', this.handleScroll); const { height } = this.rootNode.getBoundingClientRect(); this.curScroll = window.scrollY; - this.setState({ height }); + this.setState({ height }); // eslint-disable-line react/no-unused-state } endScroll() { window.removeEventListener('scroll', this.handleScroll); } - handleScroll = () => { - const scrollDiff = this.curScroll - window.scrollY; - const hidden = scrollDiff < 0 - && window.scrollY !== undefined - && window.scrollY > this.state.height; - this.setState({ hidden }); - this.curScroll = window.scrollY; - }; - render() { const { children, diff --git a/components/app_bar/config.css b/components/app_bar/config.module.css similarity index 100% rename from components/app_bar/config.css rename to components/app_bar/config.module.css diff --git a/components/app_bar/index.js b/components/app_bar/index.js index ac09b55cc..2fd50cbbd 100644 --- a/components/app_bar/index.js +++ b/components/app_bar/index.js @@ -2,7 +2,7 @@ import { themr } from 'react-css-themr'; import { APP_BAR } from '../identifiers'; import { appBarFactory } from './AppBar'; import { IconButton } from '../button'; -import theme from './theme.css'; +import theme from './theme.module.css'; const AppBar = appBarFactory(IconButton); const ThemedAppBar = themr(APP_BAR, theme)(AppBar); diff --git a/components/app_bar/theme.css b/components/app_bar/theme.module.css similarity index 90% rename from components/app_bar/theme.css rename to components/app_bar/theme.module.css index 3f1836817..fe8986f4e 100644 --- a/components/app_bar/theme.css +++ b/components/app_bar/theme.module.css @@ -1,7 +1,7 @@ -@import 'http://github.com/colors.css'; -@import 'http://github.com/media.css'; -@import 'http://github.com/variables.css'; -@import 'http://github.com/config.css'; +@import 'http://github.com/colors.module.css'; +@import 'http://github.com/media.module.css'; +@import 'http://github.com/variables.module.css'; +@import 'http://github.com/config.module.css'; .appBar { background: var(--appbar-color); diff --git a/components/autocomplete/Autocomplete.d.ts b/components/autocomplete/Autocomplete.d.ts index b7d98d82e..9eddafa1c 100644 --- a/components/autocomplete/Autocomplete.d.ts +++ b/components/autocomplete/Autocomplete.d.ts @@ -88,6 +88,14 @@ export interface AutocompleteProps extends InputProps { * Callback function that is fired when component is focused. */ onFocus?: Function; + /** + * Callback function that is fired when a key is pressed down. + */ + onKeyDown?: Function; + /** + * Callback function that is fired when a key is lifted up. + */ + onKeyUp?: Function; /** * Callback function that is fired when the components's query value changes. */ diff --git a/components/autocomplete/Autocomplete.js b/components/autocomplete/Autocomplete.js index 099a03378..ab0ad3096 100644 --- a/components/autocomplete/Autocomplete.js +++ b/components/autocomplete/Autocomplete.js @@ -4,6 +4,7 @@ import PropTypes from 'prop-types'; import ReactDOM from 'react-dom'; import classnames from 'classnames'; import { themr } from 'react-css-themr'; +import { isValuePresent } from '../utils/utils'; import { AUTOCOMPLETE } from '../identifiers.js'; import InjectChip from '../chip/Chip.js'; import InjectInput from '../input/Input.js'; @@ -35,6 +36,8 @@ const factory = (Chip, Input) => { onBlur: PropTypes.func, onChange: PropTypes.func, onFocus: PropTypes.func, + onKeyDown: PropTypes.func, + onKeyUp: PropTypes.func, onQueryChange: PropTypes.func, query: PropTypes.string, selectedPosition: PropTypes.oneOf(['above', 'below', 'none']), @@ -132,7 +135,7 @@ const factory = (Chip, Input) => { }; handleQueryFocus = (event) => { - this.suggestionsNode.scrollTop = 0; + event.target.scrollTop = 0; this.setState({ active: '', focus: true }); if (this.props.onFocus) this.props.onFocus(event); }; @@ -148,6 +151,8 @@ const factory = (Chip, Input) => { if (event.which === 13) { this.selectOrCreateActiveItem(event); } + + if(this.props.onKeyDown) this.props.onKeyDown(event); }; handleQueryKeyUp = (event) => { @@ -160,6 +165,8 @@ const factory = (Chip, Input) => { if (index >= suggestionsKeys.length) index = 0; this.setState({ active: suggestionsKeys[index] }); } + + if(this.props.onKeyUp) this.props.onKeyUp(event); }; handleSuggestionHover = (event) => { @@ -178,7 +185,7 @@ const factory = (Chip, Input) => { query(key) { let query_value = ''; - if (!this.props.multiple && key) { + if (!this.props.multiple && isValuePresent(key)) { const source_value = this.source().get(`${key}`); query_value = source_value || key; } @@ -375,7 +382,6 @@ const factory = (Chip, Input) => { return ( diff --git a/components/autocomplete/config.css b/components/autocomplete/config.module.css similarity index 100% rename from components/autocomplete/config.css rename to components/autocomplete/config.module.css diff --git a/components/autocomplete/index.js b/components/autocomplete/index.js index 52e3bc568..4acb3accd 100644 --- a/components/autocomplete/index.js +++ b/components/autocomplete/index.js @@ -3,7 +3,7 @@ import { AUTOCOMPLETE } from '../identifiers'; import { autocompleteFactory } from './Autocomplete'; import { Chip } from '../chip'; import { Input } from '../input'; -import theme from './theme.css'; +import theme from './theme.module.css'; const Autocomplete = autocompleteFactory(Chip, Input); const ThemedAutocomplete = themr(AUTOCOMPLETE, theme, { withRef: true })(Autocomplete); diff --git a/components/autocomplete/readme.md b/components/autocomplete/readme.md index 9b2e925e1..0a2abcbe4 100644 --- a/components/autocomplete/readme.md +++ b/components/autocomplete/readme.md @@ -47,21 +47,23 @@ If you want to provide a theme via context, the component key is `RTAutocomplete | `className` | `String` | `''` | Sets a class to style of the Component.| | `direction` | `String` | `auto` | Determines the opening direction. It can be `auto`, `up` or `down`. | | `disabled` | `Bool` | `false` | If true, component will be disabled. | -| `error` | `String` or `Node` | | Sets the error string for the internal input element. | +| `error` | `String` or `Node` |   | Sets the error string for the internal input element. | | `keepFocusOnChange` | `Bool` | `false` | Whether component should keep focus after value change. | -| `label` | `String` or `Node` | | The text string to use for the floating label element. | +| `label` | `String` or `Node` |   | The text string to use for the floating label element. | | `multiple` | `Bool` | `true` | If true, component can hold multiple values. | -| `onBlur` | `Function` | | Callback function that is fired when component is blurred. | -| `onChange` | `Function` | | Callback function that is fired when the components's value changes. | -| `onQueryChange` | `Function` | | Callback function that is fired when the components's query input value changes. | -| `onFocus` | `Function` | | Callback function that is fired when component is focused. | -| `query` | `String` | | This property has to be used in case the `source` is not static and will be changing during search for `multiple={false}` autocomplete, content of the `query` has to be managed by the `onQueryChange` callback. | -| `source` | `Object` or `Array` | | Object of key/values or array representing all items suggested. | +| `onBlur` | `Function` |   | Callback function that is fired when component is blurred. | +| `onChange` | `Function` |   | Callback function that is fired when the components's value changes. | +| `onFocus` | `Function` |   | Callback function that is fired when component is focused. | +| `onKeyDown` | `Function` |   | Callback function that is fired when a key is pressed down. | +| `onKeyUp` | `Function` |   | Callback function that is fired when a key is lifted up. | +| `onQueryChange` | `Function` |   | Callback function that is fired when the components's query input value changes. | +| `query` | `String` |   | This property has to be used in case the `source` is not static and will be changing during search for `multiple={false}` autocomplete, content of the `query` has to be managed by the `onQueryChange` callback. | +| `source` | `Object` or `Array` |   | Object of key/values or array representing all items suggested. | | `selectedPosition` | `String` | `above` | Determines if the selected list is shown above or below input. It can be `above`, `below` or `none`. | | `showSelectedWhenNotInSource` | `Bool` | `false` | Determines if the selected list is shown if the `value` keys don't exist in the source. Only works if passing the `value` prop as an Object. | | `showSuggestionsWhenValueIsSet` | `Bool` | `false` | If true, the list of suggestions will not be filtered when a value is selected, until the query is modified. | | `suggestionMatch` | `String` | `start` | Determines how suggestions are supplied. It can be `start` (query matches the start of a suggestion), `anywhere` (query matches anywhere inside the suggestion), `word` (query matches the start of a word in the suggestion) or `disabled` (disable filtering of provided source, all items are shown). | -| `value` | `String`, `Array` or `Object` | | Value or array of values currently selected component. | +| `value` | `String`, `Array` or `Object` |   | Value or array of values currently selected component. | Additional properties will be passed to the Input Component so you can use `hint`, `name` ... etc. diff --git a/components/autocomplete/theme.css b/components/autocomplete/theme.module.css similarity index 92% rename from components/autocomplete/theme.css rename to components/autocomplete/theme.module.css index 5b175727d..069e1e4f1 100644 --- a/components/autocomplete/theme.css +++ b/components/autocomplete/theme.module.css @@ -1,7 +1,36 @@ -@import 'http://github.com/colors.css'; -@import 'http://github.com/variables.css'; -@import 'http://github.com/input/config.css'; -@import 'http://github.com/config.css'; +@import 'http://github.com/colors.module.css'; +@import 'http://github.com/variables.module.css'; +@import 'http://github.com/input/config.module.css'; +@import 'http://github.com/config.module.css'; + +.suggestions { + background-color: var(--autocomplete-suggestions-background); + list-style: none; + max-height: 0; + overflow-x: hidden; + overflow-y: auto; + padding: 0; + position: absolute; + transition-duration: var(--animation-duration); + transition-property: max-height, box-shadow; + transition-timing-function: var(--animation-curve-default); + visibility: hidden; + width: 100%; + z-index: var(--z-index-high); + + &::-webkit-scrollbar { + height: 0; + width: 0; + } + + &:not(.up) { + margin-top: calc(-1 * var(--input-padding)); + } + + &.up { + bottom: 0; + } +} .autocomplete { padding: var(--unit) 0; @@ -31,35 +60,6 @@ margin: var(--autocomplete-value-margin); } -.suggestions { - background-color: var(--autocomplete-suggestions-background); - list-style: none; - max-height: 0; - overflow-x: hidden; - overflow-y: auto; - padding: 0; - position: absolute; - transition-duration: var(--animation-duration); - transition-property: max-height, box-shadow; - transition-timing-function: var(--animation-curve-default); - visibility: hidden; - width: 100%; - z-index: var(--z-index-high); - - &:not(.up) { - margin-top: calc(-1 * var(--input-padding)); - } - - &.up { - bottom: 0; - } - - &::-webkit-scrollbar { - height: 0; - width: 0; - } -} - .suggestion { cursor: pointer; font-size: var(--input-field-font-size); diff --git a/components/avatar/Avatar.js b/components/avatar/Avatar.js index 9d9dd9448..7dfbfc0fb 100644 --- a/components/avatar/Avatar.js +++ b/components/avatar/Avatar.js @@ -6,11 +6,13 @@ import { AVATAR } from '../identifiers'; import InjectFontIcon from '../font_icon/FontIcon'; const factory = (FontIcon) => { - const Avatar = ({ alt, children, className, cover, icon, image, theme, title, ...other }) => ( + const Avatar = ({ + alt, children, className, cover, icon, image, theme, title, ...other + }) => (
{children} {cover && typeof image === 'string' && } - {!cover && (typeof image === 'string' ? {alt} : image)} + {!cover && (typeof image === 'string' ? {alt} : image)} {typeof icon === 'string' ? : icon} {title ? {title[0]} : null}
diff --git a/components/avatar/config.css b/components/avatar/config.module.css similarity index 100% rename from components/avatar/config.css rename to components/avatar/config.module.css diff --git a/components/avatar/index.js b/components/avatar/index.js index 1bb9d9bc6..50f902cdc 100644 --- a/components/avatar/index.js +++ b/components/avatar/index.js @@ -2,7 +2,7 @@ import { themr } from 'react-css-themr'; import { AVATAR } from '../identifiers'; import { avatarFactory } from './Avatar'; import { FontIcon } from '../font_icon/FontIcon'; -import theme from './theme.css'; +import theme from './theme.module.css'; const Avatar = avatarFactory(FontIcon); const ThemedAvatar = themr(AVATAR, theme)(Avatar); diff --git a/components/avatar/readme.md b/components/avatar/readme.md index b8b27e77b..f81776607 100644 --- a/components/avatar/readme.md +++ b/components/avatar/readme.md @@ -31,11 +31,11 @@ If you want to provide a theme via context, the component key is `RTAvatar`. | Name | Type | Default | Description| |:-----|:-----|:-----|:-----| | `alt` | `String` | `''` | An alternative text for the image or icon.| -| `children` | `Node` | | Children for the avatar. You can pass an SVG for a custom icon or, for example, an image.| +| `children` | `Node` |   | Children for the avatar. You can pass an SVG for a custom icon or, for example, an image.| | `className` | `String` | `''` | Set a class to style the Component.| | `cover` | `Boolean` | `''` | Set to true if your image is not squared so it will be used as a cover for the element.| -| `icon` | `String` or `Element` | | A key to identify an Icon from Material Design Icons or a custom Icon Element.| -| `image` | `String` or `Element` | | An image source or an image element. | +| `icon` | `String` or `Element` |   | A key to identify an Icon from Material Design Icons or a custom Icon Element.| +| `image` | `String` or `Element` |   | An image source or an image element. | | `title` | `String` | `''` | A title for the image. If no image is provided, the first letter will be displayed as the avatar. | | `theme` | `Object` | `null` | Classnames object defining the component style.| diff --git a/components/avatar/theme.css b/components/avatar/theme.module.css similarity index 88% rename from components/avatar/theme.css rename to components/avatar/theme.module.css index ce5653ca8..4921b333a 100644 --- a/components/avatar/theme.css +++ b/components/avatar/theme.module.css @@ -1,6 +1,6 @@ -@import 'http://github.com/colors.css'; -@import 'http://github.com/variables.css'; -@import 'http://github.com/config.css'; +@import 'http://github.com/colors.module.css'; +@import 'http://github.com/variables.module.css'; +@import 'http://github.com/config.module.css'; .avatar { background-color: var(--avatar-background); diff --git a/components/button/BrowseButton.d.ts b/components/button/BrowseButton.d.ts index d1d2bb40b..1485e8049 100644 --- a/components/button/BrowseButton.d.ts +++ b/components/button/BrowseButton.d.ts @@ -37,6 +37,8 @@ export interface BrowseButtonProps extends ButtonBaseProps { * Classnames object defining the component style. */ theme?: BrowseButtonTheme; + + onChange?: Function; } export class BrowseButton extends React.Component { } diff --git a/components/button/BrowseButton.js b/components/button/BrowseButton.js index dbbfd0dc0..bf0584528 100644 --- a/components/button/BrowseButton.js +++ b/components/button/BrowseButton.js @@ -127,7 +127,7 @@ const factory = (ripple, FontIcon) => { }; return React.createElement(element, props, - icon ? : null, + icon ? : null, {label}, { multiple={multiple} onChange={this.handleFileChange} />, - children, - ); + children); } } diff --git a/components/button/Button.js b/components/button/Button.js index 90634ea87..e23d7b0e5 100644 --- a/components/button/Button.js +++ b/components/button/Button.js @@ -101,6 +101,10 @@ const factory = (ripple, FontIcon) => { const element = href ? 'a' : 'button'; const level = this.getLevel(); const shape = this.getShape(); + const mouseEvents = { + onMouseUp: this.handleMouseUp, + onMouseLeave: this.handleMouseLeave, + }; const classes = classnames(theme.button, [theme[shape]], { [theme[level]]: neutral, @@ -110,21 +114,23 @@ const factory = (ripple, FontIcon) => { const props = { ...others, + ...mouseEvents, href, ref: (node) => { this.buttonNode = node; }, className: classes, disabled: this.props.disabled, - onMouseUp: this.handleMouseUp, - onMouseLeave: this.handleMouseLeave, type: !href ? type : null, 'data-react-toolbox': 'button', }; - return React.createElement(element, props, + const buttonElement = React.createElement(element, props, icon ? : null, label, - children, - ); + children); + + return others.onMouseEnter && this.props.disabled + ? {buttonElement} + : buttonElement; } } diff --git a/components/button/IconButton.js b/components/button/IconButton.js index dde3d4787..8c18b4fe2 100644 --- a/components/button/IconButton.js +++ b/components/button/IconButton.js @@ -101,7 +101,9 @@ const factory = (ripple, FontIcon) => { ? : icon; - return React.createElement(element, props, + return React.createElement( + element, + props, icon && iconElement, children, ); diff --git a/components/button/__test__/index.spec.js b/components/button/__test__/index.spec.js index 21fb11540..bb41e3498 100644 --- a/components/button/__test__/index.spec.js +++ b/components/button/__test__/index.spec.js @@ -1,7 +1,7 @@ import React from 'react'; import { mount } from 'enzyme'; import { Button } from '../Button'; -import theme from '../theme.css'; +import theme from '../theme.module.css'; describe('Button', () => { describe('#render', () => { diff --git a/components/button/config.css b/components/button/config.module.css similarity index 63% rename from components/button/config.css rename to components/button/config.module.css index 18865745d..1df08fb27 100644 --- a/components/button/config.css +++ b/components/button/config.module.css @@ -3,22 +3,22 @@ --button-height: calc(3.6 * var(--unit)); --button-toggle-font-size: calc(2 * var(--unit)); --button-primary-color: var(--color-primary); - --button-primary-color-hover: color(var(--color-primary) a(20%)); + --button-primary-color-hover: color-mod(var(--color-primary) a(20%)); --button-primary-color-contrast: var(--color-primary-contrast); --button-accent-color-contrast: var(--color-primary-contrast); - --button-accent-color-hover: color(var(--color-accent) a(20%)); + --button-accent-color-hover: color-mod(var(--color-accent) a(20%)); --button-accent-color: var(--color-accent); --button-neutral-color: var(--color-white); --button-neutral-color-contrast: var(--palette-grey-900); - --button-neutral-color-hover: color(var(--palette-grey-900) a(20%)); + --button-neutral-color-hover: color-mod(var(--palette-grey-900) a(20%)); --button-floating-font-size: calc(2.4 * var(--unit)); --button-floating-height: calc(5.6 * var(--unit)); --button-floating-mini-height: calc(4 * var(--unit)); --button-floating-mini-font-size: calc(var(--button-floating-mini-height) / 2.25); - --button-disabled-text-color: color(var(--color-black) a(26%)); - --button-disabled-background-color: color(var(--color-black) a(12%)); - --button-disabled-text-color-inverse: color(var(--color-black) a(54%)); - --button-disabled-background-inverse: color(var(--color-black) a(8%)); + --button-disabled-text-color: color-mod(var(--color-black) a(26%)); + --button-disabled-background-color: color-mod(var(--color-black) a(12%)); + --button-disabled-text-color-inverse: color-mod(var(--color-black) a(54%)); + --button-disabled-background-inverse: color-mod(var(--color-black) a(8%)); --button-squared-icon-margin: calc(0.6 * var(--unit)); --button-squared-min-width: calc(9 * var(--unit)); --button-squared-padding: 0 calc(1.2 * var(--unit)); diff --git a/components/button/index.js b/components/button/index.js index 003bc3555..c506d01c6 100644 --- a/components/button/index.js +++ b/components/button/index.js @@ -5,7 +5,7 @@ import { browseButtonFactory } from './BrowseButton'; import { iconButtonFactory } from './IconButton'; import { FontIcon } from '../font_icon/FontIcon'; import themedRippleFactory from '../ripple'; -import theme from './theme.css'; +import theme from './theme.module.css'; const Button = buttonFactory(themedRippleFactory({ centered: false }), FontIcon); const IconButton = iconButtonFactory(themedRippleFactory({ centered: true }), FontIcon); diff --git a/components/button/readme.md b/components/button/readme.md index 623b4e91d..4dd1ca251 100644 --- a/components/button/readme.md +++ b/components/button/readme.md @@ -42,19 +42,19 @@ If you want to provide a theme via context, the component key is `RTButton`. | `disabled` | `Boolean` | `false` | If true, component will be disabled.| | `flat` | `Boolean` | `false` | If true, the button will have a flat look. | | `floating` | `Boolean` | `false` | If true, the button will have a floating look. | -| `href` | `String` | | Creates a link for the button. | -| `icon` | `String` or `Element` | | Value of the icon (See Font Icon Component). | -| `inverse` | `Boolean` | | If true, the neutral colors are inverted. Useful to put a button over a dark background. | -| `label` | `String` | | The text string to use for the name of the button.| +| `href` | `String` |   | Creates a link for the button. | +| `icon` | `String` or `Element` |   | Value of the icon (See Font Icon Component). | +| `inverse` | `Boolean` |   | If true, the neutral colors are inverted. Useful to put a button over a dark background. | +| `label` | `String` |   | The text string to use for the name of the button.| | `mini` | `Boolean` | `false` | To be used with floating button. If true, the button will be smaller.| | `neutral` | `Boolean` | `true` | Set it to `false` if you don't want the neutral styles to be included.| -| `onMouseEnter` | `Function` | | Fires after the mouse enters the Component.| -| `onMouseLeave` | `Function` | | Fires after the mouse leaves the Component.| -| `onMouseUp` | `Function` | | Fires after the mouse is released from the Component.| +| `onMouseEnter` | `Function` |   | Fires after the mouse enters the Component.| +| `onMouseLeave` | `Function` |   | Fires after the mouse leaves the Component.| +| `onMouseUp` | `Function` |   | Fires after the mouse is released from the Component.| | `primary` | `Boolean` | `false` | Indicates if the button should have primary color.| | `raised` | `Boolean` | `false` | If true, the button will have a raised look. | | `ripple` | `Boolean` | `true` | If true, component will have a ripple effect on click.| -| `theme` | `Object` | | Theme object with classnames that will be used to style the component.| +| `theme` | `Object` |   | Theme object with classnames that will be used to style the component.| | `type` | `String` | `button` | Component root container type.| By default it will have neutral colors and a flat aspect even though the `flat` property is `false` by default. Also, some properties exclude others, for example a button cannot be `flat` and `raised` at the same time. diff --git a/components/button/theme.css b/components/button/theme.module.css similarity index 89% rename from components/button/theme.css rename to components/button/theme.module.css index 1f31d5ab7..05faf005f 100644 --- a/components/button/theme.css +++ b/components/button/theme.module.css @@ -1,6 +1,6 @@ -@import 'http://github.com/colors.css'; -@import 'http://github.com/variables.css'; -@import 'http://github.com/config.css'; +@import 'http://github.com/colors.module.css'; +@import 'http://github.com/variables.module.css'; +@import 'http://github.com/config.module.css'; .button { align-content: center; @@ -120,6 +120,25 @@ composes: squared; } +.toggle { + background: transparent; + border-radius: 50%; + composes: button; + vertical-align: middle; + width: var(--button-height); + + & > .icon, + & svg { + font-size: var(--button-toggle-font-size); + line-height: var(--button-height); + vertical-align: top; + } + + & > .rippleWrapper { + border-radius: 50%; + } +} + .floating { border-radius: 50%; box-shadow: @@ -150,25 +169,6 @@ } } -.toggle { - background: transparent; - border-radius: 50%; - composes: button; - vertical-align: middle; - width: var(--button-height); - - & > .icon, - & svg { - font-size: var(--button-toggle-font-size); - line-height: var(--button-height); - vertical-align: top; - } - - & > .rippleWrapper { - border-radius: 50%; - } -} - .primary:not([disabled]) { &.raised, &.floating { @@ -176,17 +176,20 @@ color: var(--button-primary-color-contrast); } - &.flat, - &.toggle { + &.flat { color: var(--button-primary-color); - &:focus:not(:active) { + &:hover { background: var(--button-primary-color-hover); } } - &.flat:hover { - background: var(--button-primary-color-hover); + &.toggle { + color: var(--button-primary-color); + + &:focus:not(:active) { + background: var(--button-primary-color-hover); + } } } @@ -197,17 +200,20 @@ color: var(--button-accent-color-contrast); } - &.flat, - &.toggle { + &.flat { color: var(--button-accent-color); - &:focus:not(:active) { + &:hover { background: var(--button-accent-color-hover); } } - &.flat:hover { - background: var(--button-accent-color-hover); + &.toggle { + color: var(--button-accent-color); + + &:focus:not(:active) { + background: var(--button-accent-color-hover); + } } } @@ -218,17 +224,20 @@ color: var(--button-neutral-color-contrast); } - &.flat, - &.toggle { + &.flat { color: var(--button-neutral-color-contrast); - &:focus:not(:active) { + &:hover { background: var(--button-neutral-color-hover); } } - &.flat:hover { - background: var(--button-neutral-color-hover); + &.toggle { + color: var(--button-neutral-color-contrast); + + &:focus:not(:active) { + background: var(--button-neutral-color-hover); + } } &.inverse { @@ -238,17 +247,20 @@ color: var(--button-neutral-color); } - &.flat, - &.toggle { + &.flat { color: var(--button-neutral-color); - &:focus:not(:active) { + &:hover { background: var(--button-neutral-color-hover); } } - &.flat:hover { - background: var(--button-neutral-color-hover); + &.toggle { + color: var(--button-neutral-color); + + &:focus:not(:active) { + background: var(--button-neutral-color-hover); + } } } } diff --git a/components/card/Card.js b/components/card/Card.js index 6f22b7138..246c09299 100644 --- a/components/card/Card.js +++ b/components/card/Card.js @@ -4,7 +4,9 @@ import { themr } from 'react-css-themr'; import classnames from 'classnames'; import { CARD } from '../identifiers'; -const Card = ({ children, className, raised, theme, ...other }) => { +const Card = ({ + children, className, raised, theme, ...other +}) => { const classes = classnames(theme.card, { [theme.raised]: raised, }, className); diff --git a/components/card/CardActions.js b/components/card/CardActions.js index 385550830..3fb2c0894 100644 --- a/components/card/CardActions.js +++ b/components/card/CardActions.js @@ -4,7 +4,9 @@ import { themr } from 'react-css-themr'; import classnames from 'classnames'; import { CARD } from '../identifiers'; -const CardActions = ({ children, className, theme, ...other }) => ( +const CardActions = ({ + children, className, theme, ...other +}) => (
{children}
diff --git a/components/card/CardText.js b/components/card/CardText.js index f0f8a847d..47a5713c0 100644 --- a/components/card/CardText.js +++ b/components/card/CardText.js @@ -4,7 +4,9 @@ import { themr } from 'react-css-themr'; import classnames from 'classnames'; import { CARD } from '../identifiers'; -const CardText = ({ children, className, theme, ...other }) => ( +const CardText = ({ + children, className, theme, ...other +}) => (
{typeof children === 'string' ?

{children}

: children}
diff --git a/components/card/CardTitle.js b/components/card/CardTitle.js index 1aa74a58a..863ae8509 100644 --- a/components/card/CardTitle.js +++ b/components/card/CardTitle.js @@ -6,7 +6,9 @@ import { CARD } from '../identifiers'; import InjectAvatar from '../avatar/Avatar'; const factory = (Avatar) => { - const CardTitle = ({ avatar, children, className, subtitle, theme, title, ...other }) => { + const CardTitle = ({ + avatar, children, className, subtitle, theme, title, ...other + }) => { const classes = classnames(theme.cardTitle, { [theme.small]: avatar, [theme.large]: !avatar, @@ -44,9 +46,9 @@ const factory = (Avatar) => { ]), theme: PropTypes.shape({ large: PropTypes.string, - title: PropTypes.string, small: PropTypes.string, subtitle: PropTypes.string, + title: PropTypes.string, }), title: PropTypes.oneOfType([ PropTypes.string, diff --git a/components/card/config.css b/components/card/config.module.css similarity index 82% rename from components/card/config.css rename to components/card/config.module.css index 34715f54a..1b5979fc0 100644 --- a/components/card/config.css +++ b/components/card/config.module.css @@ -1,6 +1,6 @@ :root { --card-color-white: var(--color-white); - --card-text-overlay: color(var(--color-black) a(35%)); + --card-text-overlay: color-mod(var(--color-black) a(35%)); --card-background-color: var(--card-color-white); --card-padding-sm: calc(0.8 * var(--unit)); --card-padding: calc(1.6 * var(--unit)); diff --git a/components/card/index.js b/components/card/index.js index 3e8265103..309df8dc9 100644 --- a/components/card/index.js +++ b/components/card/index.js @@ -6,7 +6,7 @@ import { CardMedia } from './CardMedia'; import { CardText } from './CardText'; import { cardTitleFactory } from './CardTitle'; import { Avatar } from '../avatar'; -import theme from './theme.css'; +import theme from './theme.module.css'; const CardTitle = cardTitleFactory(Avatar); const ThemedCard = themr(CARD, theme)(Card); diff --git a/components/card/readme.md b/components/card/readme.md index 292d8a492..ff49a2070 100644 --- a/components/card/readme.md +++ b/components/card/readme.md @@ -47,9 +47,9 @@ that all subcomponents are placed within. ### Properties | Name | Type | Default | Description | |:-----|:-----|:-----|:-----| -| `children` | `Any` | | Child components, usually Card subcomponents. | -| `className` | `String` | | Additional class(es) for custom styling. | -| `raised` | `Boolean` | | Increases the shadow depth to appear elevated. | +| `children` | `Any` |   | Child components, usually Card subcomponents. | +| `className` | `String` |   | Additional class(es) for custom styling. | +| `raised` | `Boolean` |   | Increases the shadow depth to appear elevated. | ### Theme @@ -64,11 +64,11 @@ A versatile title block that can be used in various places on the card, includin ### Properties | Name | Type | Default | Description | |:-----|:-----|:-----|:-----| -| `avatar` | `String` or `Element` | | A string URL or Element to specify an avatar in the left side of the title. | -| `children` | `String`, `Element` or `Array` | | Children to pass through the component. | -| `className` | `String` | | Additional class(es) for custom styling. | -| `subtitle` | `String` | | Text used for the sub header of the card. | -| `title` | `String` | | Text used for the title of the card. | +| `avatar` | `String` or `Element` |   | A string URL or Element to specify an avatar in the left side of the title. | +| `children` | `String`, `Element` or `Array` |   | Children to pass through the component. | +| `className` | `String` |   | Additional class(es) for custom styling. | +| `subtitle` | `String` |   | Text used for the sub header of the card. | +| `title` | `String` |   | Text used for the title of the card. | ### Theme @@ -87,12 +87,12 @@ Used for displaying media such as images or videos on a card. Can also be used w ### Properties | Name | Type | Default | Description | |:-----|:-----|:-----|:-----| -| `aspectRatio` | `enum`(`'wide'`,`'square'`) | | Forces a 16:9 or 1:1 aspect ratio respectively. Unset, the media area will have a flexible height. | -| `children` | `Any` | | Usually an image/video element or a `` component. | -| `className` | `String` | | Additional class(es) for custom styling. | -| `color` | `String` | | Sets the background color. | -| `contentOverlay` | `Boolean` | | Creates a dark overlay underneath the child components. | -| `image` | `String`, `Element` | | Can be used instead of children. Accepts an element or a URL string. | +| `aspectRatio` | `enum`(`'wide'`,`'square'`) |   | Forces a 16:9 or 1:1 aspect ratio respectively. Unset, the media area will have a flexible height. | +| `children` | `Any` |   | Usually an image/video element or a `` component. | +| `className` | `String` |   | Additional class(es) for custom styling. | +| `color` | `String` |   | Sets the background color. | +| `contentOverlay` | `Boolean` |   | Creates a dark overlay underneath the child components. | +| `image` | `String`, `Element` |   | Can be used instead of children. Accepts an element or a URL string. | ### Theme @@ -110,8 +110,8 @@ Basic card content container. Good for small descriptions or other supplementary ### Properties | Name | Type | Default | Description | |:-----|:-----|:-----|:-----| -| `children` | `Any` | | Children to pass through the component. | -| `className` | `String` | | Additional class(es) for custom styling. | +| `children` | `Any` |   | Children to pass through the component. | +| `className` | `String` |   | Additional class(es) for custom styling. | ### Theme @@ -127,8 +127,8 @@ This component is used as a container for supplemental card actions. Supplementa | Name | Type | Default | Description | |:-----|:-----|:-----|:-----| -| `children` | `Any` | | Children to pass through the component. | -| `className` | `String` | | Additional class(es) for custom styling. | +| `children` | `Any` |   | Children to pass through the component. | +| `className` | `String` |   | Additional class(es) for custom styling. | ### Theme diff --git a/components/card/theme.css b/components/card/theme.module.css similarity index 96% rename from components/card/theme.css rename to components/card/theme.module.css index 82608e40b..be0f69ba9 100644 --- a/components/card/theme.css +++ b/components/card/theme.module.css @@ -1,6 +1,6 @@ -@import 'http://github.com/colors.css'; -@import 'http://github.com/variables.css'; -@import 'http://github.com/config.css'; +@import 'http://github.com/colors.module.css'; +@import 'http://github.com/variables.module.css'; +@import 'http://github.com/config.module.css'; .card { background: var(--card-background-color); @@ -19,69 +19,6 @@ } } -.cardMedia { - background-position: center center; - background-repeat: no-repeat; - background-size: cover; - position: relative; - - &.wide, - &.square { - width: 100%; - - & .content { - height: 100%; - position: absolute; - } - - & .content > iframe, - & .content > video, - & .content > img { - max-width: 100%; - } - } - - &::after { - content: ''; - display: block; - height: 0; - } - - &.wide::after { - padding-top: 56.25%; - } - - &.square::after { - padding-top: 100%; - } - - & .content { - display: flex; - flex-direction: column; - justify-content: flex-end; - left: 0; - overflow: hidden; - position: relative; - top: 0; - width: 100%; - } - - & .contentOverlay { - & .cardTitle, - & .cardActions, - & .cardText { - background-color: var(--card-text-overlay); - } - } - - & .cardTitle { - & .title, - & .subtitle { - color: var(--card-color-white); - } - } -} - .cardTitle { align-items: center; display: flex; @@ -177,3 +114,66 @@ } } } + +.cardMedia { + background-position: center center; + background-repeat: no-repeat; + background-size: cover; + position: relative; + + & .content { + display: flex; + flex-direction: column; + justify-content: flex-end; + left: 0; + overflow: hidden; + position: relative; + top: 0; + width: 100%; + } + + &.wide, + &.square { + width: 100%; + + & .content { + height: 100%; + position: absolute; + } + + & .content > iframe, + & .content > video, + & .content > img { + max-width: 100%; + } + } + + &::after { + content: ''; + display: block; + height: 0; + } + + &.wide::after { + padding-top: 56.25%; + } + + &.square::after { + padding-top: 100%; + } + + & .cardTitle { + & .title, + & .subtitle { + color: var(--card-color-white); + } + } + + & .contentOverlay { + & .cardTitle, + & .cardActions, + & .cardText { + background-color: var(--card-text-overlay); + } + } +} diff --git a/components/checkbox/Check.js b/components/checkbox/Check.js index 2274594c9..1d5cb4ace 100644 --- a/components/checkbox/Check.js +++ b/components/checkbox/Check.js @@ -4,7 +4,9 @@ import classnames from 'classnames'; import styleShape from 'react-style-proptype'; const factory = (ripple) => { - const Check = ({ checked, children, onMouseDown, theme, style }) => ( + const Check = ({ + checked, children, onMouseDown, theme, style, + }) => (
{ render() { const { checked, children, disabled, label, name, style, onChange, // eslint-disable-line - onMouseEnter, onMouseLeave, theme, ...others } = this.props; + onMouseEnter, onMouseLeave, theme, ...others + } = this.props; const className = classnames(theme.field, { [theme.disabled]: this.props.disabled, }, this.props.className); diff --git a/components/checkbox/config.css b/components/checkbox/config.module.css similarity index 63% rename from components/checkbox/config.css rename to components/checkbox/config.module.css index fe33d1e88..01edeede6 100644 --- a/components/checkbox/config.css +++ b/components/checkbox/config.module.css @@ -1,13 +1,14 @@ :root { --checkbox-color: var(--color-primary); - --checkbox-disabled-color: color(var(--color-black) a(26%)); + --checkbox-disabled-color: color-mod(var(--color-black) a(26%)); --checkbox-field-margin-bottom: calc(1.5 * var(--unit)); - --checkbox-focus-checked-color: color(var(--color-primary) a(26%)); + --checkbox-focus-checked-color: color-mod(var(--color-primary) a(26%)); --checkbox-ripple-duration: 650ms; --checkbox-size: calc(1.8 * var(--unit)); - --checkbox-focus-color: color(var(--color-black) a(1%)); + --checkbox-focus-color: color-mod(var(--color-black) a(1%)); --checkbox-focus-size: calc(var(--checkbox-size) * 2.3); --checkbox-text-color: var(--color-black); + --checkbox-border-color: var(--palette-grey-600); --checkbox-text-font-size: var(--font-size-small); --checkbox-total-height: calc(1.8 * var(--unit)); --checkbox-transition-duration: 0.2s; diff --git a/components/checkbox/index.js b/components/checkbox/index.js index 5fad61cdd..9135b8ef7 100644 --- a/components/checkbox/index.js +++ b/components/checkbox/index.js @@ -3,7 +3,7 @@ import { CHECKBOX } from '../identifiers'; import themedRippleFactory from '../ripple'; import { checkboxFactory } from './Checkbox'; import checkFactory from './Check'; -import theme from './theme.css'; +import theme from './theme.module.css'; const ThemedCheck = checkFactory(themedRippleFactory({ centered: true, spread: 2.6 })); const ThemedCheckbox = themr(CHECKBOX, theme)(checkboxFactory(ThemedCheck)); diff --git a/components/checkbox/readme.md b/components/checkbox/readme.md index 5f7e21f62..b77bcde9d 100644 --- a/components/checkbox/readme.md +++ b/components/checkbox/readme.md @@ -44,14 +44,14 @@ If you want to provide a theme via context, the component key is `RTCheckbox`. | Name | Type | Default | Description| |:-----|:-----|:-----|:-----| | `checked` | `Boolean` | `false` | Value for the checkbox, can be `true` or `false`. | -| `children` | `String`, `Element` or `Array` | | Children to pass through the component. | +| `children` | `String`, `Element` or `Array` |   | Children to pass through the component. | | `className` | `String` | `''` | Sets a class to give customized styles to the checkbox field.| | `disabled` | `Boolean` | `false` | If true, the checkbox shown as disabled and cannot be modified.| -| `label` | `String` of `node` | | Text label to attach next to the checkbox element.| +| `label` | `String` or `node` |   | Text label to attach next to the checkbox element.| | `name` | `String` | `false` | The name of the field to set in the input checkbox.| -| `onBlur` | `Function` | | Callback called when the checkbox is blurred.| -| `onChange` | `Function` | | Callback called when the checkbox value is changed.| -| `onFocus` | `Function` | | Callback called when the checkbox is focused | +| `onBlur` | `Function` |   | Callback called when the checkbox is blurred.| +| `onChange` | `Function` |   | Callback called when the checkbox value is changed.| +| `onFocus` | `Function` |   | Callback called when the checkbox is focused | ## Theme diff --git a/components/checkbox/theme.css b/components/checkbox/theme.module.css similarity index 95% rename from components/checkbox/theme.css rename to components/checkbox/theme.module.css index 748c09265..97e120719 100644 --- a/components/checkbox/theme.css +++ b/components/checkbox/theme.module.css @@ -1,6 +1,6 @@ -@import 'http://github.com/colors.css'; -@import 'http://github.com/variables.css'; -@import 'http://github.com/config.css'; +@import 'http://github.com/colors.module.css'; +@import 'http://github.com/variables.module.css'; +@import 'http://github.com/config.module.css'; .field { display: block; @@ -28,36 +28,8 @@ white-space: nowrap; } -.input { - height: 0; - opacity: 0; - overflow: hidden; - position: absolute; - width: 0; - - &:focus ~ .check { - &::before { - background-color: var(--checkbox-focus-color); - border-radius: 50%; - content: ''; - height: var(--checkbox-focus-size); - left: 50%; - margin-left: calc(-1 * var(--checkbox-focus-size) / 2); - margin-top: calc(-1 * var(--checkbox-focus-size) / 2); - pointer-events: none; - position: absolute; - top: 50%; - width: var(--checkbox-focus-size); - } - - &.checked::before { - background-color: var(--checkbox-focus-checked-color); - } - } -} - .check { - border-color: var(--checkbox-text-color); + border-color: var(--checkbox-border-color); border-radius: 2px; border-style: solid; border-width: 2px; @@ -113,6 +85,34 @@ } } +.input { + height: 0; + opacity: 0; + overflow: hidden; + position: absolute; + width: 0; + + &:focus ~ .check { + &::before { + background-color: var(--checkbox-focus-color); + border-radius: 50%; + content: ''; + height: var(--checkbox-focus-size); + left: 50%; + margin-left: calc(-1 * var(--checkbox-focus-size) / 2); + margin-top: calc(-1 * var(--checkbox-focus-size) / 2); + pointer-events: none; + position: absolute; + top: 50%; + width: var(--checkbox-focus-size); + } + + &.checked::before { + background-color: var(--checkbox-focus-checked-color); + } + } +} + @keyframes checkmark-expand { 0% { height: 0; diff --git a/components/chip/Chip.js b/components/chip/Chip.js index bb60a1053..2852fd1d9 100644 --- a/components/chip/Chip.js +++ b/components/chip/Chip.js @@ -6,7 +6,9 @@ import { CHIP } from '../identifiers'; import InjectAvatar from '../avatar/Avatar'; const factory = (Avatar) => { - const Chip = ({ children, className, deletable, onDeleteClick, theme, ...other }) => { + const Chip = ({ + children, className, deletable, onDeleteClick, theme, ...other + }) => { let hasAvatar = false; if (React.Children.count(children)) { const flatChildren = React.Children.toArray(children); diff --git a/components/chip/__test__/index.spec.js b/components/chip/__test__/index.spec.js index fa427433b..78178f0ff 100644 --- a/components/chip/__test__/index.spec.js +++ b/components/chip/__test__/index.spec.js @@ -17,7 +17,7 @@ describe('Chip', () => { Test , ); - const chipNode = wrapper.find('div').node; + const chipNode = wrapper.find('div').instance(); expect(chipNode.className).toMatch(/\bavatar-class\b/); }); @@ -29,7 +29,7 @@ describe('Chip', () => { Test , ); - const chipNode = wrapper.find('div').node; + const chipNode = wrapper.find('div').instance(); expect(chipNode.className).toMatch(/\bavatar-class\b/); }); }); @@ -41,7 +41,7 @@ describe('Chip', () => { Test , ); - const chipNode = wrapper.find('div').node; + const chipNode = wrapper.find('div').instance(); expect(chipNode.className).not.toMatch(/\bavatar-class\b/); }); }); diff --git a/components/chip/config.css b/components/chip/config.module.css similarity index 100% rename from components/chip/config.css rename to components/chip/config.module.css diff --git a/components/chip/index.js b/components/chip/index.js index 6777f33cb..426c69cec 100644 --- a/components/chip/index.js +++ b/components/chip/index.js @@ -2,7 +2,7 @@ import { themr } from 'react-css-themr'; import { CHIP } from '../identifiers'; import { chipFactory } from './Chip'; import { Avatar } from '../avatar'; -import theme from './theme.css'; +import theme from './theme.module.css'; const Chip = chipFactory(Avatar); const ThemedChip = themr(CHIP, theme)(Chip); diff --git a/components/chip/readme.md b/components/chip/readme.md index e8ab3a876..650bac1df 100644 --- a/components/chip/readme.md +++ b/components/chip/readme.md @@ -40,10 +40,10 @@ If you want to provide a theme via context, the component key is `RTChip`. | Name | Type | Default | Description| |:----------------|:------------|:----------------|:-----------| -| `children` | `Node` | | Child components, usually `Avatar` and inline elements. | +| `children` | `Node` |   | Child components, usually `Avatar` and inline elements. | | `className` | `String` | `''` | Additional class name to provide custom styling.| | `deletable` | `Boolean` | `false` | If true, the chip will be rendered with a delete icon.| -| `onDeleteClick` | `Function` | | Callback to be invoked when the delete icon is clicked. | +| `onDeleteClick` | `Function` |   | Callback to be invoked when the delete icon is clicked. | ## Theme diff --git a/components/chip/theme.css b/components/chip/theme.module.css similarity index 93% rename from components/chip/theme.css rename to components/chip/theme.module.css index c0a5f37fd..8f27ab7e0 100644 --- a/components/chip/theme.css +++ b/components/chip/theme.module.css @@ -1,6 +1,6 @@ -@import 'http://github.com/colors.css'; -@import 'http://github.com/variables.css'; -@import 'http://github.com/config.css'; +@import 'http://github.com/colors.module.css'; +@import 'http://github.com/variables.module.css'; +@import 'http://github.com/config.module.css'; .chip { background-color: var(--chip-background); @@ -51,10 +51,6 @@ width: var(--chip-remove-size); } -.delete:hover .deleteIcon { - background: var(--chip-remove-background-hover); -} - .deleteIcon { background: var(--chip-remove-background); border-radius: var(--chip-remove-size); @@ -66,3 +62,7 @@ stroke-width: var(--chip-remove-stroke-width); } } + +.delete:hover .deleteIcon { + background: var(--chip-remove-background-hover); +} diff --git a/components/colors.css b/components/colors.module.css similarity index 100% rename from components/colors.css rename to components/colors.module.css diff --git a/components/date_picker/Calendar.js b/components/date_picker/Calendar.js index 2be228719..599f18977 100644 --- a/components/date_picker/Calendar.js +++ b/components/date_picker/Calendar.js @@ -1,6 +1,6 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import CssTransitionGroup from 'react-transition-group/CSSTransitionGroup'; +import { CSSTransition, TransitionGroup } from 'react-transition-group'; import { range, getAnimationModule } from '../utils/utils'; import time from '../utils/time'; import CalendarMonth from './CalendarMonth'; @@ -55,11 +55,6 @@ const factory = (IconButton) => { document.body.removeEventListener('keydown', this.handleKeys); } - scrollToActive() { - const offset = (this.yearsNode.offsetHeight / 2) + (this.activeYearNode.offsetHeight / 2); - this.yearsNode.scrollTop = this.activeYearNode.offsetTop - offset; - } - handleDayClick = (day) => { this.props.onChange(time.setDay(this.state.viewDate, day), true); }; @@ -95,12 +90,17 @@ const factory = (IconButton) => { changeViewMonth = (event) => { const direction = event.currentTarget.id; - this.setState({ + this.setState(state => ({ direction, - viewDate: time.addMonths(this.state.viewDate, DIRECTION_STEPS[direction]), - }); + viewDate: time.addMonths(state.viewDate, DIRECTION_STEPS[direction]), + })); }; + scrollToActive() { + const offset = (this.yearsNode.offsetHeight / 2) + (this.activeYearNode.offsetHeight / 2); + this.yearsNode.scrollTop = this.activeYearNode.offsetTop - offset; + } + renderYears() { return (
    { const { theme } = this.props; const animation = this.state.direction === 'left' ? 'slideLeft' : 'slideRight'; const animationModule = getAnimationModule(animation, theme); + const currentMonth = this.state.viewDate.getMonth(); + return (
    - React.cloneElement( + child, + { classNames: animationModule }, + )} > - - + + + +
    ); } diff --git a/components/date_picker/CalendarDay.js b/components/date_picker/CalendarDay.js index e4257a125..a7e514760 100644 --- a/components/date_picker/CalendarDay.js +++ b/components/date_picker/CalendarDay.js @@ -18,6 +18,12 @@ class Day extends Component { viewDate: PropTypes.instanceOf(Date), }; + handleClick = () => { + if (!this.props.disabled && this.props.onClick) { + this.props.onClick(this.props.day); + } + }; + dayStyle() { if (this.props.day === 1) { const e = (this.props.sundayFirstDayOfWeek) ? 0 : 1; @@ -36,12 +42,6 @@ class Day extends Component { return sameYear && sameMonth && sameDay; } - handleClick = () => { - if (!this.props.disabled && this.props.onClick) { - this.props.onClick(this.props.day); - } - }; - render() { const className = classnames(this.props.theme.day, { [this.props.theme.active]: this.isSelected(), diff --git a/components/date_picker/CalendarMonth.js b/components/date_picker/CalendarMonth.js index fdd9625a5..68a779b2e 100644 --- a/components/date_picker/CalendarMonth.js +++ b/components/date_picker/CalendarMonth.js @@ -36,7 +36,9 @@ class Month extends Component { }; isDayDisabled(date) { - const { minDate, maxDate, enabledDates, disabledDates } = this.props; + const { + minDate, maxDate, enabledDates, disabledDates, + } = this.props; const compareDate = compDate => date.getTime() === compDate.getTime(); const dateInDisabled = disabledDates.filter(compareDate).length > 0; const dateInEnabled = enabledDates.filter(compareDate).length > 0; @@ -75,7 +77,7 @@ class Month extends Component { return (
    - {fullMonth} {fullYear} + {`${fullMonth} ${fullYear}`}
    {this.renderWeeks()}
    {this.renderDays()}
    diff --git a/components/date_picker/DatePicker.js b/components/date_picker/DatePicker.js index 58211e8da..b0be55162 100644 --- a/components/date_picker/DatePicker.js +++ b/components/date_picker/DatePicker.js @@ -111,7 +111,8 @@ const factory = (Input, DatePickerDialog) => { const { active, onDismiss,// eslint-disable-line autoOk, cancelLabel, enabledDates, disabledDates, inputClassName, inputFormat, locale, maxDate, minDate, okLabel, onEscKeyDown, onOverlayClick, readonly, - sundayFirstDayOfWeek, value, ...others } = this.props; + sundayFirstDayOfWeek, value, ...others + } = this.props; const finalInputFormat = inputFormat || time.formatDate; const date = Object.prototype.toString.call(value) === '[object Date]' ? value : undefined; const formattedDate = date === undefined ? '' : finalInputFormat(value, locale); diff --git a/components/date_picker/DatePickerDialog.js b/components/date_picker/DatePickerDialog.js index 869572ed5..f77daca44 100644 --- a/components/date_picker/DatePickerDialog.js +++ b/components/date_picker/DatePickerDialog.js @@ -51,6 +51,17 @@ const factory = (Dialog, Calendar) => { date: this.props.value, }; + actions = [{ + label: this.props.cancelLabel, + className: this.props.theme.button, + onClick: this.props.onDismiss, + }, { + label: this.props.okLabel, + className: this.props.theme.button, + name: this.props.name, + onClick: this.handleSelect, + }]; + componentWillMount() { this.updateStateDate(this.props.value); } @@ -88,17 +99,6 @@ const factory = (Dialog, Calendar) => { } }; - actions = [{ - label: this.props.cancelLabel, - className: this.props.theme.button, - onClick: this.props.onDismiss, - }, { - label: this.props.okLabel, - className: this.props.theme.button, - name: this.props.name, - onClick: this.handleSelect, - }]; - render() { const { theme } = this.props; const display = `${this.state.display}Display`; @@ -122,7 +122,7 @@ const factory = (Dialog, Calendar) => { {this.state.date.getFullYear()}

    - {shortDayOfWeek}, {shortMonth} {date} + {`${shortDayOfWeek}, ${shortMonth} ${date}`}

    diff --git a/components/date_picker/__test__/index.spec.js b/components/date_picker/__test__/index.spec.js index 7ef335f86..fa952c7fb 100644 --- a/components/date_picker/__test__/index.spec.js +++ b/components/date_picker/__test__/index.spec.js @@ -1,6 +1,6 @@ import React from 'react'; import { shallow } from 'enzyme'; -import theme from '../theme.css'; +import theme from '../theme.module.css'; import { DatePickerDialog, Calendar } from '../DatePicker'; describe('DatePickerDialog', () => { diff --git a/components/date_picker/config.css b/components/date_picker/config.module.css similarity index 90% rename from components/date_picker/config.css rename to components/date_picker/config.module.css index 92480b399..52f65426f 100644 --- a/components/date_picker/config.css +++ b/components/date_picker/config.module.css @@ -3,7 +3,7 @@ --datepicker-primary-contrast: var(--color-primary-contrast); --datepicker-primary-dark: var(--color-primary-dark); --datepicker-primary-color: var(--datepicker-primary); - --datepicker-primary-hover-color: color(var(--datepicker-primary) a(0.2)); + --datepicker-primary-hover-color: color-mod(var(--datepicker-primary) a(0.2)); --datepicker-primary-contrast-color: var(--datepicker-primary-contrast); --datepicker-primary-dark-color: var(--datepicker-primary-dark); --datepicker-dialog-width: calc(33 * var(--unit)); @@ -18,7 +18,7 @@ --calendar-primary-contrast: var(--color-primary-contrast); --calendar-primary-color: var(--calendar-primary); --calendar-primary-contrast-color: var(--calendar-primary-contrast); - --calendar-primary-hover-color: color(var(--calendar-primary) a(0.21)); + --calendar-primary-hover-color: color-mod(var(--calendar-primary) a(0.21)); --calendar-arrows-color: var(--palette-grey-600); --calendar-arrows-font-size: calc(2 * var(--unit)); --calendar-year-font-size: 2.4; diff --git a/components/date_picker/index.js b/components/date_picker/index.js index 2a7f36b60..5e72c5988 100644 --- a/components/date_picker/index.js +++ b/components/date_picker/index.js @@ -7,7 +7,7 @@ import calendarFactory from './Calendar'; import { IconButton } from '../button'; import { Input } from '../input'; import { Dialog } from '../dialog'; -import theme from './theme.css'; +import theme from './theme.module.css'; const Calendar = calendarFactory(IconButton); const DatePickerDialog = datePickerDialogFactory(Dialog, Calendar); diff --git a/components/date_picker/readme.md b/components/date_picker/readme.md index a62da27e0..2e4943ba6 100644 --- a/components/date_picker/readme.md +++ b/components/date_picker/readme.md @@ -49,25 +49,25 @@ If you want to provide a theme via context, the component key is `RTDatePicker`. | `active` | `Boolean` | `false` | Allows to control if the picker should be shown from outside. Beware you should update the prop when the Dialog is closed. | | `autoOk` | `Boolean` | `false` | Automatically selects a date upon clicking on a day. | | `cancelLabel` | `String` | `'Cancel'` | Label used for cancel button on date picker dialog. | -| `className` | `String` | | This class will be placed at the top of the `DatePickerDialog` component so you can provide custom styles.| -| `disabledDates` | `Array` | | An array of date objects which will be disabled in the calendar. All other dates will be enabled.| -| `enabledDates` | `Array` | | An array of date objects which will be enabled in the calendar. All other dates will be disabled.| -| `error` | `String` | | Give an error message to display under the field.| -| `inputClassName`| `String` | | This class will be applied to `Input` component of `DatePicker`. | -| `inputFormat` | `Function` | | Function to format the date displayed on the input. | -| `label` | `String` | | The text string to use for the floating label element in the input component.| +| `className` | `String` |   | This class will be placed at the top of the `DatePickerDialog` component so you can provide custom styles.| +| `disabledDates` | `Array` |   | An array of date objects which will be disabled in the calendar. All other dates will be enabled.| +| `enabledDates` | `Array` |   | An array of date objects which will be enabled in the calendar. All other dates will be disabled.| +| `error` | `String` |   | Give an error message to display under the field.| +| `inputClassName`| `String` |   | This class will be applied to `Input` component of `DatePicker`. | +| `inputFormat` | `Function` |   | Function to format the date displayed on the input. | +| `label` | `String` |   | The text string to use for the floating label element in the input component.| | `locale` | `String` or `Object` | `'en'` | Set the locale for the date picker dialog ('de','no','en','es','af','ar','be','bg','bn','bo','br','bs','ca','gl','eu','pt','it','fr','ru','ua'). Object is supported too (see example above). | -| `maxDate` | `Date` | | Date object with the maximum selectable date. | -| `minDate` | `Date` | | Date object with the minimum selectable date. | -| `onChange` | `Function` | | Callback called when the picker value is changed.| -| `onClick` | `Function` | | Callback fired on Input click.| -| `onDismiss` | `Function` | | Callback fired after dismissing the Dialog.| -| `onEscKeyDown` | `Function` | | Callback called when the ESC key is pressed with the overlay active. | -| `onKeyPress` | `Function` | | Callback invoked on Input key press. -| `onOverlayClick`| `Function` | | Callback to be invoked when the dialog overlay is clicked.| -| `readonly` | `Boolean` | | The input element will be readonly and look like disabled.| +| `maxDate` | `Date` |   | Date object with the maximum selectable date. | +| `minDate` | `Date` |   | Date object with the minimum selectable date. | +| `onChange` | `Function` |   | Callback called when the picker value is changed.| +| `onClick` | `Function` |   | Callback fired on Input click.| +| `onDismiss` | `Function` |   | Callback fired after dismissing the Dialog.| +| `onEscKeyDown` | `Function` |   | Callback called when the ESC key is pressed with the overlay active. | +| `onKeyPress` | `Function` |   | Callback invoked on Input key press. +| `onOverlayClick`| `Function` |   | Callback to be invoked when the dialog overlay is clicked.| +| `readonly` | `Boolean` |   | The input element will be readonly and look like disabled.| | `sundayFirstDayOfWeek` | `Boolean`| `false` | Set week's first day to Sunday. Default week's first day is Monday ([ISO 8601](https://en.wikipedia.org/wiki/ISO_8601#Week_dates)). | -| `value` | `Date` | | Date object with the currently selected date. | +| `value` | `Date` |   | Date object with the currently selected date. | ## Theme diff --git a/components/date_picker/theme.css b/components/date_picker/theme.module.css similarity index 92% rename from components/date_picker/theme.css rename to components/date_picker/theme.module.css index bfac22efe..28920559e 100644 --- a/components/date_picker/theme.css +++ b/components/date_picker/theme.module.css @@ -1,6 +1,6 @@ -@import 'http://github.com/colors.css'; -@import 'http://github.com/variables.css'; -@import 'http://github.com/config.css'; +@import 'http://github.com/colors.module.css'; +@import 'http://github.com/variables.module.css'; +@import 'http://github.com/config.module.css'; .input:not(.disabled) > .inputElement { cursor: pointer; @@ -70,6 +70,19 @@ } } +.week { + display: flex; + flex-wrap: wrap; + font-size: var(--calendar-day-font-size); + height: var(--calendar-row-height); + line-height: var(--calendar-row-height); + opacity: 0.5; + + & > span { + flex: 0 0 calc(100% / 7); + } +} + .calendar { background: var(--calendar-primary-contrast-color); font-size: var(--font-size-small); @@ -102,6 +115,39 @@ } } +.day { + flex: 0 0 calc(100% / 7); + padding: var(--calendar-day-padding-topbottom) var(--calendar-day-padding-leftright); + + /* stylelint-disable */ + & > span { + border-radius: 50%; + display: inline-block; + height: var(--calendar-row-height); + line-height: var(--calendar-row-height); + width: var(--calendar-row-height); + } + /* stylelint-enable */ + + &.active > span { + background: var(--calendar-primary-color); + color: var(--calendar-primary-contrast-color); + } + + &:hover:not(.disabled) > span { + cursor: pointer; + } + + &:hover:not(.active):not(.disabled) > span { + background: var(--calendar-primary-hover-color); + color: var(--calendar-primary-contrast-color); + } + + &.disabled { + opacity: var(--calendar-day-disable-opacity); + } +} + .title { display: inline-block; font-weight: 500; @@ -128,68 +174,24 @@ } } -.week { - display: flex; - flex-wrap: wrap; - font-size: var(--calendar-day-font-size); - height: var(--calendar-row-height); - line-height: var(--calendar-row-height); - opacity: 0.5; - - & > span { - flex: 0 0 calc(100% / 7); - } -} - .days { display: flex; flex-wrap: wrap; font-size: var(--calendar-day-font-size); } -.day { - flex: 0 0 calc(100% / 7); - padding: var(--calendar-day-padding-topbottom) var(--calendar-day-padding-leftright); - - & > span { - border-radius: 50%; - display: inline-block; - height: var(--calendar-row-height); - line-height: var(--calendar-row-height); - width: var(--calendar-row-height); - } - - &:hover:not(.active):not(.disabled) > span { - background: var(--calendar-primary-hover-color); - color: var(--calendar-primary-contrast-color); - } - - &.active > span { - background: var(--calendar-primary-color); - color: var(--calendar-primary-contrast-color); - } - - &:hover:not(.disabled) > span { - cursor: pointer; - } - - &.disabled { - opacity: var(--calendar-day-disable-opacity); - } -} - .month { background-color: var(--calendar-primary-contrast-color); width: 100%; } .slideRightEnter, -.slideRightLeave { +.slideRightExit { position: absolute; } .slideRightEnterActive, -.slideRightLeaveActive { +.slideRightExitActive { transition-duration: 350ms; transition-property: transform, opacity; transition-timing-function: ease-in-out; @@ -205,20 +207,24 @@ } } -.slideRightLeave { +.slideRightExit { opacity: 1; transform: translateX(0); - &.slideRightLeaveActive { + &.slideRightExitActive { opacity: 0; transform: translateX(-100%); } } .slideLeftEnter, -.slideLeftLeave { +.slideLeftExit { position: absolute; - transition-duration: 0.35s; +} + +.slideLeftEnterActive, +.slideLeftExitActive { + transition-duration: 350ms; transition-property: transform, opacity; transition-timing-function: ease-in-out; } @@ -233,11 +239,11 @@ } } -.slideLeftLeave { +.slideLeftExit { opacity: 1; transform: translate3d(0, 0, 0); - &.slideLeftLeaveActive { + &.slideLeftExitActive { opacity: 0; transform: translate3d(100%, 0, 0); } diff --git a/components/dialog/Dialog.js b/components/dialog/Dialog.js index 7687c23cc..4167b18cf 100644 --- a/components/dialog/Dialog.js +++ b/components/dialog/Dialog.js @@ -39,9 +39,11 @@ const factory = (Overlay, Button) => { {props.children} {actions.length - ? + ? ( + + ) : null }
    @@ -51,9 +53,9 @@ const factory = (Overlay, Button) => { Dialog.propTypes = { actions: PropTypes.arrayOf(PropTypes.shape({ + children: PropTypes.node, className: PropTypes.string, label: PropTypes.string, - children: PropTypes.node, })), active: PropTypes.bool, children: PropTypes.node, diff --git a/components/dialog/config.css b/components/dialog/config.module.css similarity index 100% rename from components/dialog/config.css rename to components/dialog/config.module.css diff --git a/components/dialog/index.js b/components/dialog/index.js index 132144562..66fce6919 100644 --- a/components/dialog/index.js +++ b/components/dialog/index.js @@ -3,7 +3,7 @@ import { DIALOG } from '../identifiers'; import { dialogFactory } from './Dialog'; import { Overlay } from '../overlay'; import { Button } from '../button'; -import theme from './theme.css'; +import theme from './theme.module.css'; const Dialog = dialogFactory(Overlay, Button); const ThemedDialog = themr(DIALOG, theme)(Dialog); diff --git a/components/dialog/readme.md b/components/dialog/readme.md index a1a7ab72f..b00f2f118 100644 --- a/components/dialog/readme.md +++ b/components/dialog/readme.md @@ -48,12 +48,12 @@ If you want to provide a theme via context, the component key is `RTDialog`. | `actions` | `Array` | `[]` | A array of objects representing the buttons for the dialog navigation area. The properties will be transferred to the buttons.| | `active` | `Boolean` | `false` | If true, the dialog will be active.| | `className` | `String` | `''` | Sets a class to give customized styles to the dialog.| -| `onEscKeyDown` | `Function` | | Callback called when the ESC key is pressed with the overlay active. | -| `onOverlayClick` | `Function` | | Callback to be invoked when the dialog overlay is clicked.| -| `onOverlayMouseDown` | `Function` | | Callback called when the mouse button is pressed on the overlay. | -| `onOverlayMouseMove` | `Function` | | Callback called when the mouse is moving over the overlay. | -| `onOverlayMouseUp` | `Function` | | Callback called when the mouse button is released over the overlay. | -| `title` | `String` | | The text string to use as standar title of the dialog.| +| `onEscKeyDown` | `Function` |   | Callback called when the ESC key is pressed with the overlay active. | +| `onOverlayClick` | `Function` |   | Callback to be invoked when the dialog overlay is clicked.| +| `onOverlayMouseDown` | `Function` |   | Callback called when the mouse button is pressed on the overlay. | +| `onOverlayMouseMove` | `Function` |   | Callback called when the mouse is moving over the overlay. | +| `onOverlayMouseUp` | `Function` |   | Callback called when the mouse button is released over the overlay. | +| `title` | `String` |   | The text string to use as standar title of the dialog.| | `type` | `String` | `normal` | Used to determine the size of the dialog. It can be `small`, `normal`, `large` or `fullscreen`. | Notice that the `fullscreen` option only applies on mobile devices with small screens (i.e. cellphones), and on other devices it behaves as a `large` dialog. diff --git a/components/dialog/theme.css b/components/dialog/theme.module.css similarity index 93% rename from components/dialog/theme.css rename to components/dialog/theme.module.css index 083b74feb..84aa589f0 100644 --- a/components/dialog/theme.css +++ b/components/dialog/theme.module.css @@ -1,7 +1,7 @@ -@import 'http://github.com/colors.css'; -@import 'http://github.com/variables.css'; -@import 'http://github.com/media.css'; -@import 'http://github.com/config.css'; +@import 'http://github.com/colors.module.css'; +@import 'http://github.com/variables.module.css'; +@import 'http://github.com/media.module.css'; +@import 'http://github.com/config.module.css'; .wrapper { align-items: center; diff --git a/components/drawer/config.css b/components/drawer/config.module.css similarity index 100% rename from components/drawer/config.css rename to components/drawer/config.module.css diff --git a/components/drawer/index.js b/components/drawer/index.js index 7c8909317..71d03180a 100644 --- a/components/drawer/index.js +++ b/components/drawer/index.js @@ -2,7 +2,7 @@ import { themr } from 'react-css-themr'; import { DRAWER } from '../identifiers'; import { Overlay } from '../overlay'; import { drawerFactory } from './Drawer'; -import theme from './theme.css'; +import theme from './theme.module.css'; const Drawer = drawerFactory(Overlay); const ThemedDrawer = themr(DRAWER, theme)(Drawer); diff --git a/components/drawer/readme.md b/components/drawer/readme.md index 159fc80a4..5a05628ce 100644 --- a/components/drawer/readme.md +++ b/components/drawer/readme.md @@ -38,7 +38,7 @@ If you want to provide a theme via context, the component key is `RTDrawer`. | `active` | `Boolean` | `false` | If true, the drawer will be visible.| | `className` | `String` | `''` | Sets a class to give customized styles to the drawer.| | `insideTree` | `Boolean` | `false` | If true the Drawer is rendered inside the normal tree.| -| `onOverlayClick` | `Function` | | Callback function to be invoked when the overlay is clicked.| +| `onOverlayClick` | `Function` |   | Callback function to be invoked when the overlay is clicked.| | `type` | `String` | `left` | Type of drawer. It can be `left` or `right` to display the drawer on the left or right side of the screen.| | `withOverlay` | `String` | `true` | If true display an Overlay that locks the scroll when the Drawer is active.| diff --git a/components/drawer/theme.css b/components/drawer/theme.module.css similarity index 89% rename from components/drawer/theme.css rename to components/drawer/theme.module.css index fc8152f79..a0a3e3c62 100644 --- a/components/drawer/theme.css +++ b/components/drawer/theme.module.css @@ -1,7 +1,7 @@ -@import 'http://github.com/colors.css'; -@import 'http://github.com/variables.css'; -@import 'http://github.com/media.css'; -@import 'http://github.com/config.css'; +@import 'http://github.com/colors.module.css'; +@import 'http://github.com/variables.module.css'; +@import 'http://github.com/media.module.css'; +@import 'http://github.com/config.module.css'; .wrapper { position: relative; diff --git a/components/dropdown/Dropdown.d.ts b/components/dropdown/Dropdown.d.ts index 4d14eeb79..3ed678170 100644 --- a/components/dropdown/Dropdown.d.ts +++ b/components/dropdown/Dropdown.d.ts @@ -30,10 +30,6 @@ export interface DropdownTheme { * Used for the the label element. */ label?: string; - /** - * Used for setting the label from source - */ - labelKey?: string; /** * Used when dropdown has required attribute. */ @@ -58,10 +54,6 @@ export interface DropdownTheme { * Used for the list of values. */ values?: string; - /** - * Used for setting the value from source - */ - valueKey: string; } export interface DropdownProps extends ReactToolbox.Props { @@ -88,6 +80,10 @@ export interface DropdownProps extends ReactToolbox.Props { * The text string to use for the floating label element. */ label?: string; + /** + * Used for setting the label from source + */ + labelKey?: string; /** * Name for the input field. */ @@ -104,6 +100,11 @@ export interface DropdownProps extends ReactToolbox.Props { * Callback function that is fired when the component is focused. */ onFocus?: Function; + /** + * If true, the dropdown has a required attribute. + * @default false + */ + required?: boolean; /** * Array of data objects with the data to represent in the dropdown. */ @@ -121,10 +122,9 @@ export interface DropdownProps extends ReactToolbox.Props { */ value?: string | number; /** - * If true, the dropdown has a required attribute. - * @default false + * Used for setting the value from source */ - required?: boolean; + valueKey?: string; } export class Dropdown extends React.Component { } diff --git a/components/dropdown/Dropdown.js b/components/dropdown/Dropdown.js index dce8e6485..5cdad85dc 100644 --- a/components/dropdown/Dropdown.js +++ b/components/dropdown/Dropdown.js @@ -180,7 +180,7 @@ const factory = (Input) => {
  • {this.props.template ? this.props.template(item) : item[labelKey]}
  • diff --git a/components/dropdown/config.css b/components/dropdown/config.module.css similarity index 85% rename from components/dropdown/config.css rename to components/dropdown/config.module.css index fa0a790e0..3a80db2fb 100644 --- a/components/dropdown/config.css +++ b/components/dropdown/config.module.css @@ -3,7 +3,7 @@ --dropdown-color-white: var(--color-white); --dropdown-color-primary: var(--color-primary); --dropdown-color-primary-contrast: var(--color-primary-contrast); - --dropdown-color-disabled: color(var(--color-black) a(26%)); + --dropdown-color-disabled: color-mod(var(--color-black) a(26%)); --dropdown-value-hover-background: var(--palette-grey-200); --dropdown-overflow-max-height: 45vh; --dropdown-value-border-radius: calc(0.2 * var(--unit)); diff --git a/components/dropdown/index.js b/components/dropdown/index.js index 419b264af..0c8349a81 100644 --- a/components/dropdown/index.js +++ b/components/dropdown/index.js @@ -2,7 +2,7 @@ import { themr } from 'react-css-themr'; import { DROPDOWN } from '../identifiers'; import { dropdownFactory } from './Dropdown'; import { Input } from '../input'; -import theme from './theme.css'; +import theme from './theme.module.css'; const Dropdown = dropdownFactory(Input); const ThemedDropdown = themr(DROPDOWN, theme)(Dropdown); diff --git a/components/dropdown/readme.md b/components/dropdown/readme.md index 7d7870a4c..14be8dfac 100644 --- a/components/dropdown/readme.md +++ b/components/dropdown/readme.md @@ -43,14 +43,14 @@ If you want to provide a theme via context, the component key is `RTDropdown`. | `auto` | `Boolean` | `true` | If true, the dropdown will open up or down depending on the position in the screen.| | `className` | `String` | `''` | Set the class to give custom styles to the dropdown.| | `disabled` | `Boolean` | `false` | Set the component as disabled.| -| `error` | `String` | | Give an error string to display under the field.| -| `label` | `String` | | The text string to use for the floating label element.| -| `onBlur` | `Function` | | Callback function that is fired when the component is blurred.| -| `onChange` | `Function` | | Callback function that is fired when the component's value changes.| -| `onFocus` | `Function` | | Callback function that is fired when the component is focused.| -| `source` | `Array` | | Array of data objects with the data to represent in the dropdown.| -| `template` | `Function` | | Callback function that returns a JSX template to represent the element.| -| `value` | `String` | | Default value using JSON data.| +| `error` | `String` |   | Give an error string to display under the field.| +| `label` | `String` |   | The text string to use for the floating label element.| +| `onBlur` | `Function` |   | Callback function that is fired when the component is blurred.| +| `onChange` | `Function` |   | Callback function that is fired when the component's value changes.| +| `onFocus` | `Function` |   | Callback function that is fired when the component is focused.| +| `source` | `Array` |   | Array of data objects with the data to represent in the dropdown.| +| `template` | `Function` |   | Callback function that returns a JSX template to represent the element.| +| `value` | `String` |   | Default value using JSON data.| | `required` | `Boolean` | `false` | If true, the dropdown has a required attribute.| ## Theming diff --git a/components/dropdown/theme.css b/components/dropdown/theme.module.css similarity index 95% rename from components/dropdown/theme.css rename to components/dropdown/theme.module.css index 02f068e68..fe45f05a2 100644 --- a/components/dropdown/theme.css +++ b/components/dropdown/theme.module.css @@ -1,7 +1,80 @@ -@import 'http://github.com/colors.css'; -@import 'http://github.com/variables.css'; -@import 'http://github.com/input/config.css'; -@import 'http://github.com/config.css'; +@import 'http://github.com/colors.module.css'; +@import 'http://github.com/variables.module.css'; +@import 'http://github.com/input/config.module.css'; +@import 'http://github.com/config.module.css'; + +.value { + & > input { + cursor: pointer; + } + + &::after { + border-left: var(--dropdown-value-border-size) solid transparent; + border-right: var(--dropdown-value-border-size) solid transparent; + border-top: var(--dropdown-value-border-size) solid var(--input-text-bottom-border-color); + content: ''; + height: 0; + pointer-events: none; + position: absolute; + right: var(--input-chevron-offset); + top: 50%; + transition: transform var(--animation-duration) var(--animation-curve-default); + width: 0; + } +} + +.label { + color: var(--input-text-label-color); + font-size: var(--input-label-font-size); + left: 0; + line-height: var(--input-field-font-size); + position: absolute; + top: var(--input-focus-label-top); + + & .required { + color: var(--input-text-error-color); + } +} + +.values { + background-color: var(--dropdown-color-white); + border-radius: var(--dropdown-value-border-radius); + list-style: none; + margin: 0; + overflow-y: auto; + padding: 0; + position: absolute; + transition-duration: var(--animation-duration); + transition-property: max-height, box-shadow; + transition-timing-function: var(--animation-curve-default); + width: 100%; + z-index: var(--z-index-high); + + & > * { + cursor: pointer; + overflow: hidden; + padding: var(--unit); + position: relative; + + &:hover:not(.disabled) { + background-color: var(--dropdown-value-hover-background); + } + + &.selected { + color: var(--dropdown-color-primary); + } + + &.disabled { + color: var(--dropdown-color-disabled); + cursor: not-allowed; + } + } + + &::-webkit-scrollbar { + height: 0; + width: 0; + } +} .dropdown { position: relative; @@ -44,24 +117,13 @@ } } -.value { - & > input { - cursor: pointer; - } - - &::after { - border-left: var(--dropdown-value-border-size) solid transparent; - border-right: var(--dropdown-value-border-size) solid transparent; - border-top: var(--dropdown-value-border-size) solid var(--input-text-bottom-border-color); - content: ''; - height: 0; - pointer-events: none; - position: absolute; - right: var(--input-chevron-offset); - top: 50%; - transition: transform var(--animation-duration) var(--animation-curve-default); - width: 0; - } +.templateValue { + background-color: var(--input-text-background-color); + border-bottom: 1px solid var(--input-text-bottom-border-color); + color: var(--color-text); + min-height: var(--input-field-height); + padding: var(--input-field-padding) 0; + position: relative; } .field { @@ -96,71 +158,9 @@ } } -.templateValue { - background-color: var(--input-text-background-color); - border-bottom: 1px solid var(--input-text-bottom-border-color); - color: var(--color-text); - min-height: var(--input-field-height); - padding: var(--input-field-padding) 0; - position: relative; -} - -.label { - color: var(--input-text-label-color); - font-size: var(--input-label-font-size); - left: 0; - line-height: var(--input-field-font-size); - position: absolute; - top: var(--input-focus-label-top); - - & .required { - color: var(--input-text-error-color); - } -} - .error { color: var(--input-text-error-color); font-size: var(--input-label-font-size); line-height: var(--input-underline-height); margin-bottom: calc(-1 * var(--input-underline-height)); } - -.values { - background-color: var(--dropdown-color-white); - border-radius: var(--dropdown-value-border-radius); - list-style: none; - margin: 0; - overflow-y: auto; - padding: 0; - position: absolute; - transition-duration: var(--animation-duration); - transition-property: max-height, box-shadow; - transition-timing-function: var(--animation-curve-default); - width: 100%; - z-index: var(--z-index-high); - - & > * { - cursor: pointer; - overflow: hidden; - padding: var(--unit); - position: relative; - - &:hover:not(.disabled) { - background-color: var(--dropdown-value-hover-background); - } - - &.selected { - color: var(--dropdown-color-primary); - } - - &.disabled { - color: var(--dropdown-color-disabled); - cursor: not-allowed; - } - } - - &::-webkit-scrollbar { - height: 0; - width: 0; - } -} diff --git a/components/font_icon/readme.md b/components/font_icon/readme.md index 4b0fee55d..cab39c81d 100644 --- a/components/font_icon/readme.md +++ b/components/font_icon/readme.md @@ -22,4 +22,4 @@ const FontIcons = () => ( |:-----|:-----|:-----|:-----| | `alt` | `String` | `''` | The text used to set the `aria-label` attribute. | `className` | `String` | `''` | The class name to give custom styles such as sizing.| -| `value` | `String` or `Element` | | The key string for the icon you want be displayed.| +| `value` | `String` or `Element` |   | The key string for the icon you want be displayed.| diff --git a/components/hoc/ActivableRenderer.js b/components/hoc/ActivableRenderer.js index edb6455c8..fd116c39b 100644 --- a/components/hoc/ActivableRenderer.js +++ b/components/hoc/ActivableRenderer.js @@ -1,8 +1,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; -const ActivableRendererFactory = (options = { delay: 500 }) => - ActivableComponent => class ActivableRenderer extends Component { +const ActivableRendererFactory = (options = { delay: 500 }) => ActivableComponent => class ActivableRenderer extends Component { // eslint-disable-line max-len static propTypes = { active: PropTypes.bool.isRequired, children: PropTypes.node, @@ -28,13 +27,6 @@ const ActivableRendererFactory = (options = { delay: 500 }) => clearTimeout(this.unrenderTimeout); } - renderAndActivate() { - if (this.unrenderTimeout) clearTimeout(this.unrenderTimeout); - this.setState({ rendered: true, active: false }, () => { - this.activateTimeout = setTimeout(() => this.setState({ active: true }), 20); - }); - } - deactivateAndUnrender() { this.setState({ rendered: true, active: false }, () => { this.unrenderTimeout = setTimeout(() => { @@ -44,6 +36,13 @@ const ActivableRendererFactory = (options = { delay: 500 }) => }); } + renderAndActivate() { + if (this.unrenderTimeout) clearTimeout(this.unrenderTimeout); + this.setState({ rendered: true, active: false }, () => { + this.activateTimeout = setTimeout(() => this.setState({ active: true }), 20); + }); + } + render() { const { delay, ...others } = this.props; // eslint-disable-line no-unused-vars const { active, rendered } = this.state; @@ -51,6 +50,6 @@ const ActivableRendererFactory = (options = { delay: 500 }) => ? : null; } - }; +}; export default ActivableRendererFactory; diff --git a/components/hoc/Portal.js b/components/hoc/Portal.js index 1a9a5357d..cdd55036f 100644 --- a/components/hoc/Portal.js +++ b/components/hoc/Portal.js @@ -103,7 +103,6 @@ class Portal extends Component { render() { return null; } - } function getContainer(container) { diff --git a/components/index.d.ts b/components/index.d.ts index 9b0f4da49..4d7246877 100644 --- a/components/index.d.ts +++ b/components/index.d.ts @@ -1,4 +1,5 @@ import * as React from "react"; +import { ThemeProviderProps } from "react-css-themr"; export declare namespace ReactToolbox { interface Props extends React.Attributes { /** @@ -46,6 +47,7 @@ export declare namespace ReactToolbox { * Set inline style for the root component. */ style?: React.CSSProperties; + innerRef?: ThemeProviderProps["innerRef"]; } } diff --git a/components/index.js b/components/index.js index f753885bb..6dbe5f4bb 100644 --- a/components/index.js +++ b/components/index.js @@ -21,11 +21,11 @@ export * from './menu'; export { default as Navigation } from './navigation'; export { default as ProgressBar } from './progress_bar'; export * from './radio'; -export Ripple from './ripple'; +export { default as Ripple } from './ripple'; export { default as Slider } from './slider'; export { default as Snackbar } from './snackbar'; export { default as Switch } from './switch'; export * from './table'; export * from './tabs'; -export Tooltip from './tooltip'; +export { default as Tooltip } from './tooltip'; export { default as TimePicker } from './time_picker'; diff --git a/components/input/Input.js b/components/input/Input.js index 0ff8e1903..6d642916c 100644 --- a/components/input/Input.js +++ b/components/input/Input.js @@ -2,6 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; import { themr } from 'react-css-themr'; +import { isValuePresent } from '../utils/utils'; import { INPUT } from '../identifiers'; import InjectedFontIcon from '../font_icon/FontIcon'; @@ -112,9 +113,9 @@ const factory = (FontIcon) => { handleAutoresize = () => { const element = this.inputNode; - const rows = this.props.rows; + const { rows } = this.props; - if (typeof rows === 'number' && !isNaN(rows)) { + if (typeof rows === 'number' && !Number.isNaN(rows)) { element.style.height = null; } else { // compute the height difference between inner height and outer height @@ -138,7 +139,7 @@ const factory = (FontIcon) => { // replace the selected characters, so the length of value doesn't actually // increase. const isReplacing = event.target.selectionEnd - event.target.selectionStart; - const value = event.target.value; + const { value } = event.target; if (!isReplacing && value.length === maxLength) { event.preventDefault(); @@ -159,17 +160,12 @@ const factory = (FontIcon) => { this.inputNode.focus(); } - valuePresent = value => ( - value !== null - && value !== undefined - && value !== '' - && !(typeof value === 'number' && isNaN(value)) - ) - render() { - const { children, defaultValue, disabled, error, floating, hint, icon, - name, label: labelText, maxLength, multiline, required, role, - theme, type, value, onKeyPress, rows = 1, ...others } = this.props; + const { + children, defaultValue, disabled, error, floating, hint, icon, + name, label: labelText, maxLength, multiline, required, role, + theme, type, value, onKeyPress, rows = 1, ...others + } = this.props; const length = maxLength && value ? value.length : 0; const labelClassName = classnames(theme.label, { [theme.fixed]: !floating }); @@ -180,7 +176,7 @@ const factory = (FontIcon) => { [theme.withIcon]: icon, }, this.props.className); - const valuePresent = this.valuePresent(value) || this.valuePresent(defaultValue); + const valuePresent = isValuePresent(value) || isValuePresent(defaultValue); const inputElementProps = { ...others, @@ -209,14 +205,20 @@ const factory = (FontIcon) => { {icon ? : null} {labelText - ? + ? ( + + ) : null} {hint ? : null} {error ? {error} : null} - {maxLength ? {length}/{maxLength} : null} + {maxLength ? ( + + {`${length}/${maxLength}`} + + ) : null} {children}
); diff --git a/components/input/config.css b/components/input/config.module.css similarity index 84% rename from components/input/config.css rename to components/input/config.module.css index 58e389e5e..25b263fd8 100644 --- a/components/input/config.css +++ b/components/input/config.module.css @@ -6,8 +6,9 @@ --input-label-font-size: calc(1.2 * var(--unit)); --input-focus-label-top: calc(0.6 * var(--unit)); --input-text-background-color: transparent; - --input-text-label-color: color(var(--color-black) a(26%)); - --input-text-bottom-border-color: color(var(--color-black) a(12%)); + --input-text-label-color: color-mod(var(--color-text) a(26%)); + --input-text-input-element-color: var(--color-text); + --input-text-bottom-border-color: color-mod(var(--color-text) a(12%)); --input-text-highlight-color: var(--color-primary); --input-text-disabled-color: var(--input-text-bottom-border-color); --input-text-disabled-text-color: var(--input-text-label-color); diff --git a/components/input/index.js b/components/input/index.js index 062dbebb5..aeb5bfe25 100644 --- a/components/input/index.js +++ b/components/input/index.js @@ -2,7 +2,7 @@ import { themr } from 'react-css-themr'; import { INPUT } from '../identifiers'; import { inputFactory } from './Input'; import { FontIcon } from '../font_icon/FontIcon'; -import theme from './theme.css'; +import theme from './theme.module.css'; const Input = inputFactory(FontIcon); const ThemedInput = themr(INPUT, theme, { withRef: true })(Input); diff --git a/components/input/readme.md b/components/input/readme.md index d5e4a9984..a0c99afec 100644 --- a/components/input/readme.md +++ b/components/input/readme.md @@ -35,21 +35,21 @@ If you want to provide a theme via context, the component key is `RTInput`. |:-----|:-----|:-----|:-----| | `className` | `String` | `''` | Sets a class name to give custom styles.| | `disabled` | `Boolean` | `false` | If true, component will be disabled.| -| `error` | `String` or `Node` | | Give an error node to display under the field.| +| `error` | `String` or `Node` |   | Give an error node to display under the field.| | `floating` | `Boolean` | `true` | Indicates if the label is floating in the input field or not.| | `hint` | `String` or `Node` | `''` | The text string to use for hint text element.| -| `icon` | `String` or `Element` | | Name of an icon to use as a label for the input.| -| `label` | `String` or `Node` | | The text string to use for the floating label element.| -| `maxLength` | `Number` | | Specifies the maximum number of characters allowed in the component.| +| `icon` | `String` or `Element` |   | Name of an icon to use as a label for the input.| +| `label` | `String` or `Node` |   | The text string to use for the floating label element.| +| `maxLength` | `Number` |   | Specifies the maximum number of characters allowed in the component.| | `multiline` | `Boolean` | `false` | If true, a textarea element will be rendered. The textarea also grows and shrinks according to the number of lines.| -| `rows` | `Number` | | The number of rows the multiline input field has.| -| `onBlur` | `Function` | | Callback function that is fired when component is blurred.| -| `onChange` | `Function` | | Callback function that is fired when the component's value changes.| -| `onFocus` | `Function` | | Callback function that is fired when component is focused.| -| `onKeyPress` | `Function` | | Callback function that is fired when a key is pressed.| +| `rows` | `Number` |   | The number of rows the multiline input field has.| +| `onBlur` | `Function` |   | Callback function that is fired when component is blurred.| +| `onChange` | `Function` |   | Callback function that is fired when the component's value changes.| +| `onFocus` | `Function` |   | Callback function that is fired when component is focused.| +| `onKeyPress` | `Function` |   | Callback function that is fired when a key is pressed.| | `required` | `Boolean` | `false` | If true, the html input has a required attribute.| | `type` | `String` | `text` | Type of the input element. It can be a valid HTML5 input type| -| `value` | `Any` | | Current value of the input element.| +| `value` | `Any` |   | Current value of the input element.| ## Theming @@ -71,7 +71,7 @@ If you want to provide a theme via context, the component key is `RTInput`. ## Methods -The `Input` component has some imperative methods that are used as a bypass to the native rendered DOM element. To call this methods you will need to retrieve the instance of the component. Check the [Install](http://react-toolbox.com/#/install) section for details on how to do this. The methods included for the `Input` are: +The `Input` component has some imperative methods that are used as a bypass to the native rendered DOM element. To call this methods you will need to retrieve the instance of the component. Check the [Install](http://react-toolbox.io/#/install) section for details on how to do this. The methods included for the `Input` are: - `blur` used to blur the `input` element. - `focus` used to focus the `input` element. diff --git a/components/input/theme.css b/components/input/theme.module.css similarity index 90% rename from components/input/theme.css rename to components/input/theme.module.css index a39cb8741..fc60c1841 100644 --- a/components/input/theme.css +++ b/components/input/theme.module.css @@ -1,6 +1,6 @@ -@import 'http://github.com/colors.css'; -@import 'http://github.com/variables.css'; -@import 'http://github.com/config.css'; +@import 'http://github.com/colors.module.css'; +@import 'http://github.com/variables.module.css'; +@import 'http://github.com/config.module.css'; .input { padding: var(--input-padding) 0; @@ -27,93 +27,49 @@ width: var(--input-icon-size); } -.inputElement { - background-color: var(--input-text-background-color); - border-bottom: 1px solid var(--input-text-bottom-border-color); - border-left: 0; - border-radius: 0; - border-right: 0; - border-top: 0; - color: var(--color-text); - display: block; - font-size: var(--input-field-font-size); - outline: none; - padding: var(--input-field-padding) 0; - width: 100%; - - &:focus:not([disabled]):not([readonly]) { - & ~ .bar::before, - & ~ .bar::after { - width: 50%; - } - - & ~ .label:not(.fixed) { - color: var(--input-text-highlight-color); - } - - & ~ .label > .required { - color: var(--input-text-required-color); - } - - & ~ .hint { - display: block; - opacity: var(--input-hint-opacity); - } - - & ~ .icon { - color: var(--input-text-highlight-color); - } - - &.filled ~ .hint { - opacity: 0; - } - } - - &:focus:not([disabled]):not([readonly]), - &.filled, - &[type='date'], - &[type='time'] { - & ~ .label:not(.fixed) { - font-size: var(--input-label-font-size); - top: var(--input-focus-label-top); - } - } +.counter { + color: var(--input-text-label-color); + position: absolute; + right: 0; +} - &.filled ~ .label.fixed, - &.filled ~ .hint { - display: none; - } +.counter, +.error { + color: var(--input-text-error-color); + font-size: var(--input-label-font-size); + line-height: var(--input-underline-height); + margin-bottom: calc(-1 * var(--input-underline-height)); } -.label { +.hint { color: var(--input-text-label-color); font-size: var(--input-field-font-size); left: 0; line-height: var(--input-field-font-size); + opacity: var(--input-hint-opacity); pointer-events: none; position: absolute; top: calc(var(--input-padding) + 1.5 * var(--input-field-padding)); transition-duration: var(--animation-duration); - transition-property: top, font-size, color; + transition-property: opacity; transition-timing-function: var(--animation-curve-default); - - &.fixed ~ .hint { - display: none; - } } -.hint { +.label { color: var(--input-text-label-color); font-size: var(--input-field-font-size); left: 0; line-height: var(--input-field-font-size); - opacity: var(--input-hint-opacity); pointer-events: none; position: absolute; top: calc(var(--input-padding) + 1.5 * var(--input-field-padding)); transition-duration: var(--animation-duration); - transition-property: opacity; + transition-property: top, font-size, color; transition-timing-function: var(--animation-curve-default); + + &.fixed ~ .hint { + display: none; + } } .bar { @@ -143,23 +99,8 @@ } } -.error, -.counter { - color: var(--input-text-error-color); - font-size: var(--input-label-font-size); - line-height: var(--input-underline-height); - margin-bottom: calc(-1 * var(--input-underline-height)); -} - -.counter { - color: var(--input-text-label-color); - position: absolute; - right: 0; -} - -.disabled > .inputElement { - border-bottom-style: dotted; - color: var(--input-text-disabled-text-color); +.hidden { + display: none; } .errored { @@ -180,6 +121,70 @@ } } -.hidden { - display: none; +.disabled > .inputElement { + border-bottom-style: dashed; + color: var(--input-text-disabled-text-color); +} + +/* stylelint-disable */ +.inputElement { + background-color: var(--input-text-background-color); + border-bottom: 1px solid var(--input-text-bottom-border-color); + border-left: 0; + border-radius: 0; + border-right: 0; + border-top: 0; + color: var(--input-text-input-element-color); + display: block; + font-size: var(--input-field-font-size); + outline: none; + padding: var(--input-field-padding) 0; + width: 100%; + + &:required { + box-shadow: none; + } + + &.filled ~ .hint, + &.filled ~ .label.fixed { + display: none; + } + + &.filled, + &[type='date'], + &[type='time'], + &:focus:not([disabled]):not([readonly]) { + & ~ .label:not(.fixed) { + font-size: var(--input-label-font-size); + top: var(--input-focus-label-top); + } + } + + &:focus:not([disabled]):not([readonly]) { + & ~ .bar::before, + & ~ .bar::after { + width: 50%; + } + + & ~ .label:not(.fixed) { + color: var(--input-text-highlight-color); + } + + & ~ .label > .required { + color: var(--input-text-required-color); + } + + & ~ .hint { + display: block; + opacity: var(--input-hint-opacity); + } + + & ~ .icon { + color: var(--input-text-highlight-color); + } + + &.filled ~ .hint { + opacity: 0; + } + } } diff --git a/components/layout/Layout.js b/components/layout/Layout.js index 8c540436c..4806c6759 100644 --- a/components/layout/Layout.js +++ b/components/layout/Layout.js @@ -63,7 +63,9 @@ const factory = (AppBar, NavDrawer, Sidebar) => { } render() { - const { children, className, theme, ...rest } = this.props; + const { + children, className, theme, ...rest + } = this.props; const appBar = filterReactChildren(children, isAppBar)[0]; const navDrawer = filterReactChildren(children, isNavDrawer)[0]; const sidebar = filterReactChildren(children, isSidebar)[0]; diff --git a/components/layout/Panel.js b/components/layout/Panel.js index 244104054..432d554c3 100644 --- a/components/layout/Panel.js +++ b/components/layout/Panel.js @@ -4,7 +4,9 @@ import cn from 'classnames'; import { themr } from 'react-css-themr'; import { LAYOUT } from '../identifiers'; -const Panel = ({ bodyScroll, children, className, theme, ...other }) => { +const Panel = ({ + bodyScroll, children, className, theme, ...other +}) => { const _className = cn(theme.panel, { [theme.bodyScroll]: bodyScroll }, className); return (
diff --git a/components/layout/Sidebar.js b/components/layout/Sidebar.js index 562dde224..8a161e3d6 100644 --- a/components/layout/Sidebar.js +++ b/components/layout/Sidebar.js @@ -41,6 +41,7 @@ const factory = (Drawer) => { clipped: PropTypes.bool, permanentAt: PropTypes.oneOf(['sm', 'smTablet', 'md', 'lg', 'lgTablet', 'xl', 'xxl', 'xxxl']), pinned: PropTypes.bool, + right: PropTypes.bool, theme: PropTypes.shape({ clipped: PropTypes.string, pinned: PropTypes.string, diff --git a/components/layout/index.js b/components/layout/index.js index 18b9ad55c..c2921bff8 100644 --- a/components/layout/index.js +++ b/components/layout/index.js @@ -6,7 +6,7 @@ import { navDrawerFactory } from './NavDrawer'; import { Panel } from './Panel'; import { AppBar } from '../app_bar'; import { Drawer } from '../drawer'; -import theme from './theme.css'; +import theme from './theme.module.css'; const injectTheme = component => themr(LAYOUT, theme)(component); const ThemedNavDrawer = injectTheme(navDrawerFactory(Drawer)); diff --git a/components/layout/readme.md b/components/layout/readme.md index 3ad0e6681..97359613d 100644 --- a/components/layout/readme.md +++ b/components/layout/readme.md @@ -137,8 +137,8 @@ If the column layout does not suit your needs, simply fill the content area with ### Properties | Name | Type | Default | Description | |:-----|:-----|:-----|:-----| -| `children` | `Nodes` | | Can hold a `Panel`, along with a `NavDrawer`, a `Sidebar` and an `AppBar` | -| `className` | `string` | | Additional class(es) for custom styling. | +| `children` | `Nodes` |   | Can hold a `Panel`, along with a `NavDrawer`, a `Sidebar` and an `AppBar` | +| `className` | `string` |   | Additional class(es) for custom styling. | ### Theme The themed key the `Layout` in general is `ToolboxLayout`. We add classes to the root element depending on the parsed children: @@ -162,7 +162,7 @@ The [navigation drawer](https://material.google.com/patterns/navigation-drawer.h | Breakpoint | Drawer Width | Notes | |:-----|:-----|:-----| | < `xs` | 280px or (Screen width - 85px) | whichever is smaller | -| > `xs` | 320px | | +| > `xs` | 320px |   | | > `xs` | 400px | If property `width` is set to `wide` | The drawer can be docked to the left side of the screen or can float temporarily as an overlay. You can control the drawer's display manually `active` and `pinned` properties, and can also specify a breakpoint at which the drawer automatically becomes permanently docked. You can also use a `clipped` property when it's pinned so the `AppBar` would stick over the Drawer. @@ -171,11 +171,11 @@ The drawer can be docked to the left side of the screen or can float temporarily | Name | Type | Default | Description | |:-----|:-----|:-----|:-----| | `active` | `bool` | `false` | If true, the drawer will be shown as an overlay. | -| `className` | `string` | | Additional class(es) for custom styling. | +| `className` | `string` |   | Additional class(es) for custom styling. | | `clipped` | `bool` | `false` | If true, when the `AppBar` gets pinned, it will stand over the `Drawer`. | -| `permanentAt` | `enum`(`'sm'`,`'smTablet'`,`'md'`,`'lg'`,`'lgTablet'`,`'xl'`,`'xxl'`,`'xxxl'`) | | The breakpoint at which the drawer is automatically pinned. | +| `permanentAt` | `enum`(`'sm'`,`'smTablet'`,`'md'`,`'lg'`,`'lgTablet'`,`'xl'`,`'xxl'`,`'xxxl'`) |   | The breakpoint at which the drawer is automatically pinned. | | `pinned` | `bool` | `false` | If true, the drawer will be pinned open. `pinned` takes precedence over `active`. | -| `onOverlayClick` | `Function` | | Callback function to be invoked when the overlay is clicked. It only works if the `Drawer` is actually displaying and Overlay| +| `onOverlayClick` | `Function` |   | Callback function to be invoked when the overlay is clicked. It only works if the `Drawer` is actually displaying and Overlay| ### Theme @@ -193,8 +193,8 @@ The `Panel` is the main content area within a `Layout`. By default we assume it ### Properties | Name | Type | Default | Description | |:-----|:-----|:-----|:-----| -| `bodyScroll` | `Boolean` | | You can set it to true in case you are using a pinned Sidebar so it takes an scrolled `div` instead of using the document scroll. | -| `className` | `string` | | Additional class(es) for custom styling. | +| `bodyScroll` | `Boolean` |   | You can set it to true in case you are using a pinned Sidebar so it takes an scrolled `div` instead of using the document scroll. | +| `className` | `string` |   | Additional class(es) for custom styling. | ### Theme | Name | Description| @@ -212,7 +212,7 @@ The `Sidebar` is an extra drawer that docks to the right side of the `Layout`. T | `width` | `enum`(`1`,`2`,`3`,`4`,`5`,`6`,`7`,`8`,`9`,`10`,`11`,`12`,`25`,`33`,`50`,`66`,`75`,`100`) | `5` | Width in standard increments (1-12) or percentage (25, 33, 50, 66, 75, 100) | | `pinned` | `bool` | `false` | If true, the sidebar will be pinned open. | | `scrollY` | `bool` | `false` | If true, the sidebar will vertically scroll all content. | -| `className` | `string` | | Additional class(es) for custom styling. | +| `className` | `string` |   | Additional class(es) for custom styling. | ### Theme diff --git a/components/layout/theme.css b/components/layout/theme.module.css similarity index 96% rename from components/layout/theme.css rename to components/layout/theme.module.css index db483ac71..054a61263 100644 --- a/components/layout/theme.css +++ b/components/layout/theme.module.css @@ -1,24 +1,16 @@ -@import 'http://github.com/colors.css'; -@import 'http://github.com/media.css'; -@import 'http://github.com/variables.css'; -@import 'http://github.com/app_bar/config.css'; -@import 'http://github.com/drawer/config.css'; +@import 'http://github.com/colors.module.css'; +@import 'http://github.com/media.module.css'; +@import 'http://github.com/variables.module.css'; +@import 'http://github.com/app_bar/config.module.css'; +@import 'http://github.com/drawer/config.module.css'; :root { --layout-side-transition: all var(--animation-duration) var(--animation-curve-default); } -.layout { - align-items: stretch; - display: flex; - flex: 1; - flex-direction: column; - justify-content: space-between; - min-height: 100vh; - min-width: 100%; - position: relative; - - @apply --reset; +.panel, +.appbarInner { + transition: var(--layout-side-transition); } .panel { @@ -34,6 +26,19 @@ } } +.layout { + align-items: stretch; + display: flex; + flex: 1; + flex-direction: column; + justify-content: space-between; + min-height: 100vh; + min-width: 100%; + position: relative; + + @apply --reset; +} + .sidebarDrawer, .navDrawerDrawer { z-index: var(--z-index-high); @@ -59,39 +64,6 @@ } } -.appbarInner, -.panel { - transition: var(--layout-side-transition); -} - -.appbarFixed { - &.appbarAppBar { - z-index: var(--z-index-high); - } - - & .panel { - height: calc(100vh - var(--appbar-height)); - max-height: calc(100vh - var(--appbar-height)); - top: var(--appbar-height); - - &:not(.bodyScroll) { - overflow-y: scroll; - } - - @media screen and (--xxs-viewport) and (--portrait) { - height: calc(100vh - var(--appbar-height-m-portrait)); - max-height: calc(100vh - var(--appbar-height-m-portrait)); - top: var(--appbar-height-m-portrait); - } - - @media screen and (--xs-viewport) and (--landscape) { - height: calc(100vh - var(--appbar-height-m-landscape)); - max-height: calc(100vh - var(--appbar-height-m-landscape)); - top: var(--appbar-height-m-landscape); - } - } -} - .navDrawerPinned { & .appbarLeftIcon { display: none; @@ -120,13 +92,6 @@ } } -.navDrawerClipped { - & .navDrawerWrapper { - position: relative; - z-index: var(--z-index-normal); - } -} - .sidebarPinned { & .appbarLeftIcon { display: none; @@ -155,6 +120,41 @@ } } +.appbarFixed { + &.appbarAppBar { + z-index: var(--z-index-high); + } + + & .panel { + height: calc(100vh - var(--appbar-height)); + max-height: calc(100vh - var(--appbar-height)); + top: var(--appbar-height); + + &:not(.bodyScroll) { + overflow-y: scroll; + } + + @media screen and (--xxs-viewport) and (--portrait) { + height: calc(100vh - var(--appbar-height-m-portrait)); + max-height: calc(100vh - var(--appbar-height-m-portrait)); + top: var(--appbar-height-m-portrait); + } + + @media screen and (--xs-viewport) and (--landscape) { + height: calc(100vh - var(--appbar-height-m-landscape)); + max-height: calc(100vh - var(--appbar-height-m-landscape)); + top: var(--appbar-height-m-landscape); + } + } +} + +.navDrawerClipped { + & .navDrawerWrapper { + position: relative; + z-index: var(--z-index-normal); + } +} + .sidebarClipped { & .sidebarWrapper { position: relative; diff --git a/components/link/Link.js b/components/link/Link.js index 7097759b9..3ca251621 100644 --- a/components/link/Link.js +++ b/components/link/Link.js @@ -5,7 +5,9 @@ import { themr } from 'react-css-themr'; import { LINK } from '../identifiers'; import { FontIcon } from '../font_icon/FontIcon'; -const Link = ({ active, children, className, count, icon, label, theme, ...others }) => { +const Link = ({ + active, children, className, count, icon, label, theme, ...others +}) => { const _className = classnames(theme.link, { [theme.active]: active, }, className); diff --git a/components/link/index.js b/components/link/index.js index 73c91ba15..df8a571e1 100644 --- a/components/link/index.js +++ b/components/link/index.js @@ -1,7 +1,7 @@ import { themr } from 'react-css-themr'; import { LINK } from '../identifiers'; import { Link } from './Link'; -import theme from './theme.css'; +import theme from './theme.module.css'; const ThemedLink = themr(LINK, theme)(Link); diff --git a/components/link/readme.md b/components/link/readme.md index 1de725eb1..38861960f 100644 --- a/components/link/readme.md +++ b/components/link/readme.md @@ -25,9 +25,9 @@ You can add as many properties as you want to be directly transferred to the out |:-----|:-----|:-----|:-----| | `active` | `Boolean` | `false` | If true, adds active style to link.| | `className` | `String` | `''` | Sets a custom class name to add styles to the link.| -| `count` | `Number` | | Sets a count number.| -| `icon` | `String` or `Element` | | An icon key string to include a `FontIcon` component in front of the text.| -| `label` | `String` | | The text string used for the text content of the link.| +| `count` | `Number` |   | Sets a count number.| +| `icon` | `String` or `Element` |   | An icon key string to include a `FontIcon` component in front of the text.| +| `label` | `String` |   | The text string used for the text content of the link.| ## Theme diff --git a/components/link/theme.css b/components/link/theme.module.css similarity index 85% rename from components/link/theme.css rename to components/link/theme.module.css index b7af696fb..ba016e1c8 100644 --- a/components/link/theme.css +++ b/components/link/theme.module.css @@ -1,5 +1,5 @@ -@import 'http://github.com/colors.css'; -@import 'http://github.com/variables.css'; +@import 'http://github.com/colors.module.css'; +@import 'http://github.com/variables.module.css'; .icon { font-size: calc(1.8 * var(--unit)); @@ -32,10 +32,6 @@ vertical-align: middle; } - & > abbr { - text-transform: capitalize; - } - & > small { font-size: var(--font-size-tiny); margin-left: calc(0.8 * var(--unit)); diff --git a/components/list/List.js b/components/list/List.js index a9a14f69c..8609fc2a8 100644 --- a/components/list/List.js +++ b/components/list/List.js @@ -7,8 +7,8 @@ import InjectListItem from './ListItem'; const mergeProp = (propName, child, parent) => ( child[propName] !== undefined - ? child[propName] - : parent[propName] + ? child[propName] + : parent[propName] ); const factory = (ListItem) => { @@ -16,6 +16,8 @@ const factory = (ListItem) => { static propTypes = { children: PropTypes.node, className: PropTypes.string, + ripple: PropTypes.bool, // eslint-disable-line react/no-unused-prop-types + selectable: PropTypes.bool, // eslint-disable-line react/no-unused-prop-types theme: PropTypes.shape({ list: PropTypes.string, }), @@ -31,7 +33,7 @@ const factory = (ListItem) => { return React.Children.map(this.props.children, (item) => { if (item === null || item === undefined) { return item; - } else if (item.type === ListItem) { + } if (item.type === ListItem) { const selectable = mergeProp('selectable', item.props, this.props); const ripple = mergeProp('ripple', item.props, this.props); return React.cloneElement(item, { selectable, ripple }); diff --git a/components/list/ListItem.d.ts b/components/list/ListItem.d.ts index eb8cf0669..c1e7739f0 100644 --- a/components/list/ListItem.d.ts +++ b/components/list/ListItem.d.ts @@ -3,6 +3,7 @@ import ReactToolbox from '../index'; import { ListItemContentTheme } from './ListItemContent'; import { ListItemActionsTheme } from './ListItemActions'; import { ListItemLayoutProps, ListItemLayoutTheme } from './ListItemLayout'; +import { ListItemTextTheme } from './ListItemText'; export interface ListItemTheme { /** @@ -29,7 +30,7 @@ export interface ListItemProps extends ReactToolbox.Props { * Classnames object defining the component style. * @default false */ - theme?: ListItemTheme & ListItemActionsTheme & ListItemContentTheme & ListItemLayoutTheme; + theme?: ListItemTheme & ListItemActionsTheme & ListItemContentTheme & ListItemLayoutTheme & ListItemTextTheme; /** * In case you want to provide the item as a link, you can pass this property to specify the href. */ diff --git a/components/list/ListItem.js b/components/list/ListItem.js index f2e836b03..be1a161e3 100644 --- a/components/list/ListItem.js +++ b/components/list/ListItem.js @@ -69,9 +69,9 @@ const factory = (ripple, ListItemLayout, ListItemContent) => { render() { const { className, - ripple: hasRipple, // eslint-disable-line no-unused-vars - onClick, // eslint-disable-line no-unused-vars - onMouseDown, // eslint-disable-line no-unused-vars + ripple: hasRipple, // eslint-disable-line no-unused-vars + onClick, // eslint-disable-line no-unused-vars + onMouseDown, // eslint-disable-line no-unused-vars onTouchStart, // eslint-disable-line no-unused-vars theme, to, diff --git a/components/list/ListItemAction.js b/components/list/ListItemAction.js index c74bc44c5..ccfa261cc 100644 --- a/components/list/ListItemAction.js +++ b/components/list/ListItemAction.js @@ -8,7 +8,11 @@ const ListItemAction = ({ action, theme }) => { const stopRipple = onClick && !onMouseDown; const stop = e => e.stopPropagation(); return ( - + {action} ); diff --git a/components/list/ListItemContent.js b/components/list/ListItemContent.js index 60e38293c..e24652c75 100644 --- a/components/list/ListItemContent.js +++ b/components/list/ListItemContent.js @@ -29,7 +29,9 @@ const factory = (ListItemText) => { }; getType() { - const { type, children, caption, legend } = this.props; + const { + type, children, caption, legend, + } = this.props; let count = React.Children.count(children); [caption, legend].forEach((s) => { count += s ? 1 : 0; }); @@ -39,7 +41,9 @@ const factory = (ListItemText) => { } render() { - const { children, caption, legend, theme } = this.props; + const { + children, caption, legend, theme, + } = this.props; const contentType = this.getType(); const className = classnames(theme.itemContentRoot, { [theme[contentType]]: theme[contentType], diff --git a/components/list/ListItemText.js b/components/list/ListItemText.js index 20bfb6110..f015c1e25 100644 --- a/components/list/ListItemText.js +++ b/components/list/ListItemText.js @@ -4,7 +4,9 @@ import classnames from 'classnames'; import { themr } from 'react-css-themr'; import { LIST } from '../identifiers'; -const ListItemText = ({ className, primary, children, theme, ...other }) => { +const ListItemText = ({ + className, primary, children, theme, ...other +}) => { const _className = classnames(theme.itemText, { [theme.primary]: primary }, className); return ( diff --git a/components/list/config.css b/components/list/config.module.css similarity index 100% rename from components/list/config.css rename to components/list/config.module.css diff --git a/components/list/index.js b/components/list/index.js index f13c94ec3..de147707f 100644 --- a/components/list/index.js +++ b/components/list/index.js @@ -13,7 +13,7 @@ import { listItemActionsFactory } from './ListItemActions'; import { listItemContentFactory } from './ListItemContent'; import { listItemLayoutFactory } from './ListItemLayout'; import themedRippleFactory from '../ripple'; -import theme from './theme.css'; +import theme from './theme.module.css'; const applyTheme = Component => themr(LIST, theme)(Component); const ripple = themedRippleFactory({ centered: false, listItemIgnore: true }); diff --git a/components/list/readme.md b/components/list/readme.md index 54b5a1acc..34954cddd 100644 --- a/components/list/readme.md +++ b/components/list/readme.md @@ -63,20 +63,20 @@ Represents a list item that can have avatar, icons, title, subtitle, etc. Note: ### Properties | Name | Type | Default | Description| |:-----|:-----|:-----|:-----| -| `avatar` | `String` or `Element` | | A string URL to specify an avatar in the left side of the item.| -| `caption` | `String` or `Element` | | Main text of the item.| +| `avatar` | `String` or `Element` |   | A string URL to specify an avatar in the left side of the item.| +| `caption` | `String` or `Element` |   | Main text of the item.| | `className` | `String` | `''` | Set a class to give custom styles to the list item.| | `disabled` | `String` | `false` | If true, the item is displayed as disabled and is not clickable.| -| `itemContent` | `Element` | | An element that will be displayed as the item. If set, this will override `caption` and `legend`.| -| `leftActions` | `Array of Elements` | | A list of elements that are placed on the left side of the item and after the avatar attribute.| -| `leftIcon` | `String` or `Element` | | A string key of a font icon or element to display an icon in the left side of the item. | -| `legend` | `String` or `Element` | | Secondary text to display under the caption.| -| `onClick` | `Function` | | Callback the is invoked when the item is clicked if it's not disabled. | -| `rightIcon` | `String` or `Element` | | The same as the `leftIcon` but in this case the icon is displayed in the right side.| -| `rightActions` | `Array of Elements` | | A list of elements that are placed on the right side of the item and after the rightIcon attribute.| +| `itemContent` | `Element` |   | An element that will be displayed as the item. If set, this will override `caption` and `legend`.| +| `leftActions` | `Array of Elements` |   | A list of elements that are placed on the left side of the item and after the avatar attribute.| +| `leftIcon` | `String` or `Element` |   | A string key of a font icon or element to display an icon in the left side of the item. | +| `legend` | `String` or `Element` |   | Secondary text to display under the caption.| +| `onClick` | `Function` |   | Callback that is invoked when the item is clicked if it's not disabled. | +| `rightIcon` | `String` or `Element` |   | The same as the `leftIcon` but in this case the icon is displayed in the right side.| +| `rightActions` | `Array of Elements` |   | A list of elements that are placed on the right side of the item and after the rightIcon attribute.| | `ripple` | `Boolean` | `false` | If true, the item displays a ripple effect on click. By default it's inherited from the parent element.| | `selectable` | `Boolean` | `false` | If true, the elements in the list will display a hover effect and a pointer cursor. Inherited from the parent.| -| `to` | `String` | | In case you want to provide the item as a link, you can pass this property to specify the href. | +| `to` | `String` |   | In case you want to provide the item as a link, you can pass this property to specify the href. | ### Theme | Name | Description| @@ -101,15 +101,15 @@ A special type of item that has a checkbox control on the left side. It implemen ### Properties | Name | Type | Default | Description| |:-----|:-----|:-----|:-----| -| `caption` | `String` | | Main text of the item. Required.| -| `className` | `String` | | Set a class to give custom styles to Component.| +| `caption` | `String` |   | Main text of the item. Required.| +| `className` | `String` |   | Set a class to give custom styles to Component.| | `checked` | `Boolean` | `false` | If true the checkbox appears checked by default.| | `disabled` | `String` | `false` | If true, the item is displayed as disabled and it's not clickable.| -| `legend` | `String` | | Secondary text to display under the caption.| -| `name` | `String` | | Name for the checkbox input item.| -| `onBlur` | `Function` | | Callback called when the input element is blurred.| -| `onChange` | `Function` | | Callback called when the input element is changed.| -| `onFocus` | `Function` | | Callback called when the input element is focused.| +| `legend` | `String` |   | Secondary text to display under the caption.| +| `name` | `String` |   | Name for the checkbox input item.| +| `onBlur` | `Function` |   | Callback called when the input element is blurred.| +| `onChange` | `Function` |   | Callback called when the input element is changed.| +| `onFocus` | `Function` |   | Callback called when the input element is focused.| ### Theme | Name | Description| @@ -131,7 +131,7 @@ Simple subcomponent used to give a title to a list area. ### Properties | Name | Type | Default | Description| |:-----|:-----|:-----|:-----| -| `caption` | `String` | | Text that will be displayed.| +| `caption` | `String` |   | Text that will be displayed.| | `className` | `String` | `''` | Set a class to give custom styles to the list subheader.| ### Theme diff --git a/components/list/theme.css b/components/list/theme.module.css similarity index 93% rename from components/list/theme.css rename to components/list/theme.module.css index 862ff19eb..b8fc2af8b 100644 --- a/components/list/theme.css +++ b/components/list/theme.module.css @@ -1,6 +1,18 @@ -@import 'http://github.com/colors.css'; -@import 'http://github.com/variables.css'; -@import 'http://github.com/config.css'; +@import 'http://github.com/colors.module.css'; +@import 'http://github.com/variables.module.css'; +@import 'http://github.com/config.module.css'; + +.divider { + background-color: var(--color-divider); + border: 0; + height: var(--list-divider-height); + margin: calc(-1 * var(--list-divider-height)) 0 0; + + &.inset { + margin-left: var(--list-content-left-spacing); + margin-right: var(--list-horizontal-padding); + } +} .list { display: inline-block; @@ -28,18 +40,6 @@ padding-left: var(--list-horizontal-padding); } -.divider { - background-color: var(--color-divider); - border: 0; - height: var(--list-divider-height); - margin: calc(-1 * var(--list-divider-height)) 0 0; - - &.inset { - margin-left: var(--list-content-left-spacing); - margin-right: var(--list-horizontal-padding); - } -} - .listItem { position: relative; @@ -57,6 +57,24 @@ } } +.checkbox { + align-items: center; + cursor: pointer; + display: flex; + height: 100%; + margin: 0; + min-height: var(--list-item-min-height); + width: 100%; + + & > [data-react-toolbox='check'] { + margin-right: var(--list-item-right-checkbox-margin); + } + + & > [data-react-toolbox='label'] { + padding-left: 0; + } +} + .item { align-items: center; color: var(--color-text); @@ -64,6 +82,9 @@ min-height: var(--list-item-min-height); padding: 0 var(--list-horizontal-padding); position: relative; + transition-duration: 0.28s; + transition-property: background-color; + transition-timing-function: var(--animation-curve-default); &.selectable:not(.disabled):hover { background-color: var(--list-item-hover-color); @@ -83,6 +104,20 @@ } } +.itemAction { + display: flex; + margin: var(--list-item-child-margin) var(--list-horizontal-padding) var(--list-item-child-margin) 0; + + & > :not(button) { + padding: 0; + } + + & > [data-react-toolbox='font-icon'] { + color: var(--color-text-secondary); + font-size: var(--list-item-icon-font-size); + } +} + .left { & [data-react-toolbox='font-icon'] { width: var(--list-item-icon-size); @@ -112,20 +147,6 @@ flex: 0 0 auto; } -.itemAction { - display: flex; - margin: var(--list-item-child-margin) var(--list-horizontal-padding) var(--list-item-child-margin) 0; - - & > :not(button) { - padding: 0; - } - - & > [data-react-toolbox='font-icon'] { - color: var(--color-text-secondary); - font-size: var(--list-item-icon-font-size); - } -} - .itemContentRoot { display: block; flex-grow: 1; @@ -138,24 +159,6 @@ } } -.checkbox { - align-items: center; - cursor: pointer; - display: flex; - height: 100%; - margin: 0; - min-height: var(--list-item-min-height); - width: 100%; - - & > [data-react-toolbox='check'] { - margin-right: var(--list-item-right-checkbox-margin); - } - - & > [data-react-toolbox='label'] { - padding-left: 0; - } -} - .itemText { display: block; diff --git a/components/media.css b/components/media.module.css similarity index 100% rename from components/media.css rename to components/media.module.css diff --git a/components/menu/IconMenu.d.ts b/components/menu/IconMenu.d.ts index 931bcfe02..f7140965d 100644 --- a/components/menu/IconMenu.d.ts +++ b/components/menu/IconMenu.d.ts @@ -13,6 +13,11 @@ export interface IconMenuTheme { } export interface IconMenuProps extends ReactToolbox.Props { + /** + * If true, the inner Menu component will be active. + * @default false + */ + active?: boolean; /** * Children to pass through the component. */ diff --git a/components/menu/IconMenu.js b/components/menu/IconMenu.js index e82e7fd47..865b7457c 100644 --- a/components/menu/IconMenu.js +++ b/components/menu/IconMenu.js @@ -9,6 +9,7 @@ import InjectMenu from './Menu'; const factory = (IconButton, Menu) => { class IconMenu extends Component { static propTypes = { + active: PropTypes.bool, children: PropTypes.node, className: PropTypes.string, icon: PropTypes.oneOfType([ @@ -32,6 +33,7 @@ const factory = (IconButton, Menu) => { }; static defaultProps = { + active: false, className: '', icon: 'more_vert', iconRipple: true, @@ -41,11 +43,17 @@ const factory = (IconButton, Menu) => { }; state = { - active: false, + active: this.props.active, + } + + componentWillReceiveProps(nextProps) { + if (this.state.active !== nextProps.active) { + this.setState({ active: nextProps.active }); + } } handleButtonClick = (event) => { - this.setState({ active: !this.state.active }); + this.setState(state => ({ active: !state.active })); if (this.props.onClick) this.props.onClick(event); }; @@ -56,7 +64,7 @@ const factory = (IconButton, Menu) => { render() { const { - children, className, icon, iconRipple, inverse, menuRipple, onHide, // eslint-disable-line + active, children, className, icon, iconRipple, inverse, menuRipple, onHide, // eslint-disable-line onSelect, onShow, position, selectable, selected, theme, ...other } = this.props; return ( diff --git a/components/menu/Menu.js b/components/menu/Menu.js index 77333ac3b..c3cdaa5f6 100644 --- a/components/menu/Menu.js +++ b/components/menu/Menu.js @@ -142,13 +142,21 @@ const factory = (MenuItem) => { if (position !== POSITION.STATIC) { if (this.state.active) { return { clip: `rect(0 ${width}px ${height}px 0)` }; - } else if (position === POSITION.TOP_RIGHT) { + } + + if (position === POSITION.TOP_RIGHT) { return { clip: `rect(0 ${width}px 0 ${width}px)` }; - } else if (position === POSITION.BOTTOM_RIGHT) { + } + + if (position === POSITION.BOTTOM_RIGHT) { return { clip: `rect(${height}px ${width}px ${height}px ${width}px)` }; - } else if (position === POSITION.BOTTOM_LEFT) { + } + + if (position === POSITION.BOTTOM_LEFT) { return { clip: `rect(${height}px 0 ${height}px 0)` }; - } else if (position === POSITION.TOP_LEFT) { + } + + if (position === POSITION.TOP_LEFT) { return { clip: 'rect(0 0 0 0)' }; } } @@ -162,16 +170,6 @@ const factory = (MenuItem) => { : undefined; } - calculatePosition() { - const parentNode = ReactDOM.findDOMNode(this).parentNode; - if (!parentNode) return undefined; - const { top, left, height, width } = parentNode.getBoundingClientRect(); - const { height: wh, width: ww } = getViewport(); - const toTop = top < ((wh / 2) - (height / 2)); - const toLeft = left < ((ww / 2) - (width / 2)); - return `${toTop ? 'top' : 'bottom'}${toLeft ? 'Left' : 'Right'}`; - } - handleDocumentClick = (event) => { if (this.state.active && !events.targetIsDescendant(event, ReactDOM.findDOMNode(this))) { this.setState({ active: false, rippled: false }); @@ -187,6 +185,18 @@ const factory = (MenuItem) => { }); }; + calculatePosition() { + const { parentNode } = ReactDOM.findDOMNode(this); + if (!parentNode) return undefined; + const { + top, left, height, width, + } = parentNode.getBoundingClientRect(); + const { height: wh, width: ww } = getViewport(); + const toTop = top < ((wh / 2) - (height / 2)); + const toLeft = left < ((ww / 2) - (width / 2)); + return `${toTop ? 'top' : 'bottom'}${toLeft ? 'Left' : 'Right'}`; + } + show() { const { width, height } = this.menuNode.getBoundingClientRect(); this.setState({ active: true, width, height }); diff --git a/components/menu/__test__/index.spec.js b/components/menu/__test__/index.spec.js index be98b9437..59624fcf7 100644 --- a/components/menu/__test__/index.spec.js +++ b/components/menu/__test__/index.spec.js @@ -1,8 +1,60 @@ import React from 'react'; -import { shallow } from 'enzyme'; +import { mount, shallow } from 'enzyme'; +import { IconMenu } from '../IconMenu'; import { Menu } from '../Menu'; import { MenuItem } from '../MenuItem'; +describe('IconMenu', () => { + describe('#on mount', () => { + describe('when \'active\' prop is not set', () => { + it('sets \'active\' Menu prop correctly', () => { + const wrapper = shallow(); + expect(wrapper.find('Menu').props().active).toBe(false); + }); + }); + + describe('when \'active\' prop is set to false', () => { + it('sets \'active\' Menu prop correctly', () => { + const wrapper = shallow(); + expect(wrapper.find('Menu').props().active).toBe(false); + }); + + it('sets \'active\' Menu prop correctly after IconButton click', () => { + const wrapper = mount(); + wrapper.find('IconButton').simulate('click'); + expect(wrapper.find('Menu').props().active).toBe(true); + }); + + it('sets \'active\' Menu prop correctly when prop is set after IconButton click', () => { + const wrapper = mount(); + wrapper.find('IconButton').simulate('click'); + wrapper.setProps({ active: false }); + expect(wrapper.find('Menu').props().active).toBe(false); + }); + }); + + describe('when \'active\' prop is set to true', () => { + it('sets \'active\' Menu prop correctly', () => { + const wrapper = shallow(); + expect(wrapper.find('Menu').props().active).toBe(true); + }); + + it('sets \'active\' Menu prop correctly after IconButton click', () => { + const wrapper = mount(); + wrapper.find('IconButton').simulate('click'); + expect(wrapper.find('Menu').props().active).toBe(false); + }); + + it('sets \'active\' Menu prop correctly when prop is set after IconButton click', () => { + const wrapper = mount(); + wrapper.find('IconButton').simulate('click'); + wrapper.setProps({ active: true }); + expect(wrapper.find('Menu').props().active).toBe(true); + }); + }); + }); +}); + describe('MenuItem', () => { describe('#onClick', () => { it('passes to listener the event', () => { diff --git a/components/menu/config.css b/components/menu/config.module.css similarity index 100% rename from components/menu/config.css rename to components/menu/config.module.css diff --git a/components/menu/index.js b/components/menu/index.js index a62675ab7..13b37347c 100644 --- a/components/menu/index.js +++ b/components/menu/index.js @@ -6,7 +6,7 @@ import { menuItemFactory } from './MenuItem'; import { menuFactory } from './Menu'; import { iconMenuFactory } from './IconMenu'; import themedRippleFactory from '../ripple'; -import theme from './theme.css'; +import theme from './theme.module.css'; const applyTheme = Component => themr(MENU, theme)(Component); const ThemedMenuDivider = applyTheme(MenuDivider); diff --git a/components/menu/readme.md b/components/menu/readme.md index 8bf58b993..69561f2a6 100644 --- a/components/menu/readme.md +++ b/components/menu/readme.md @@ -29,14 +29,14 @@ This subcomponent is the default wrapper for a menu and is responsible for the o |:-----|:-----|:-----|:-----| | `active` | `Boolean` | `false` | If true, the menu will be displayed as opened by default.| | `className` | `String` | `''` | Set a class to give custom styles to the menu wrapper.| -| `onHide` | `Function` | | Callback that will be called when the menu is being hidden. | -| `onSelect` | `Function` | | Callback that will be invoked when a menu item is selected. | -| `onShow` | `Function` | | Callback that will be invoked when the menu is being shown. | +| `onHide` | `Function` |   | Callback that will be called when the menu is being hidden. | +| `onSelect` | `Function` |   | Callback that will be invoked when a menu item is selected. | +| `onShow` | `Function` |   | Callback that will be invoked when the menu is being shown. | | `outline` | `Boolean` | `true` | If true the menu wrapper will show an outline with a soft shadow. | | `position` | `String` | `static` | Determine the position of the menu. With `static` value the menu will be always shown, `auto` means that the it will decide the opening direction based on the current position. To force a position use `topLeft`, `topRight`, `bottomLeft`, `bottomRight`. | | `ripple` | `Boolean` | `true` | If true, the menu items will show a ripple effect on click. | | `selectable` | `Boolean` | `false` | If true, the menu will keep a value to highlight the active child item. | -| `selected` | `Any` | | Used for selectable menus. Indicates the current selected value so the child item with this value can be highlighted. | +| `selected` | `Any` |   | Used for selectable menus. Indicates the current selected value so the child item with this value can be highlighted. | ### Theming @@ -61,18 +61,19 @@ As the most usual scenario will be to open the menu from a click in an Icon, we | Name | Type | Default | Description| |:-----|:-----|:-----|:-----| +| `active` | `Boolean` | `false` | If true, the inner `Menu` component will be active. | | `className` | `String` | `''` | Set a class to give custom styles to the icon wrapper.| | `icon` | `String` or `Element` | `more_vert` | Icon font key string or Element to display the opener icon. | | `iconRipple` | `Boolean` | `true` | If true, the icon will show a ripple when is clicked. | | `inverse` | `Boolean` | `false` | If true, the neutral colors are inverted. Useful if the icon is over a dark background. | | `menuRipple` | `Boolean` | `true` | Transferred to the `Menu` component. | -| `onClick` | `Function` | | Callback that will be called when the icon is clicked. | -| `onHide` | `Function` | | Callback that will be called when the menu is being hidden. | -| `onSelect` | `Function` | | Callback that will be invoked when a menu item is selected. | -| `onShow` | `Function` | | Callback that will be invoked when the menu is being shown. | +| `onClick` | `Function` |   | Callback that will be called when the icon is clicked. | +| `onHide` | `Function` |   | Callback that will be called when the menu is being hidden. | +| `onSelect` | `Function` |   | Callback that will be invoked when a menu item is selected. | +| `onShow` | `Function` |   | Callback that will be invoked when the menu is being shown. | | `position` | `String` | `auto` | Determines the position of the menu. This property is transferred to the inner `Menu` component. | | `selectable` | `Boolean` | `false` | If true, the menu will keep a value to highlight the active child item. | -| `selected` | `Any` | | Used for selectable menus. Indicates the current selected value so the child item with this value can be highlighted. | +| `selected` | `Any` |   | Used for selectable menus. Indicates the current selected value so the child item with this value can be highlighted. | ### Theming @@ -89,11 +90,11 @@ The inner component for menus and describes the content of each option. It behav | Name | Type | Default | Description| |:-----|:-----|:-----|:-----| -| `caption` | `String` | | The text to include in the menu item. Required.| +| `caption` | `String` |   | The text to include in the menu item. Required.| | `className` | `String` | `''` | Set a class to give custom styles to the item.| | `disabled` | `Boolean` | `false` | If true, the item will be displayed as disabled and is not selectable.| -| `icon` | `String` or `Element` | | Icon font key string or Element to display in the right side of the option. | -| `onClick` | `Function` | | Callback that will be called when Component is clicked. | +| `icon` | `String` or `Element` |   | Icon font key string or Element to display in the right side of the option. | +| `onClick` | `Function` |   | Callback that will be called when Component is clicked. | | `selected` | `Boolean` | `false` | Transferred from the `Menu` component for selectable menus. Indicates if it's the current active option. | | `shortcut` | `String` | `''` | Displays shortcut text on the right side of the `caption` attribute. | diff --git a/components/menu/theme.css b/components/menu/theme.module.css similarity index 96% rename from components/menu/theme.css rename to components/menu/theme.module.css index 13e1e7276..57e410a89 100644 --- a/components/menu/theme.css +++ b/components/menu/theme.module.css @@ -1,6 +1,6 @@ -@import 'http://github.com/colors.css'; -@import 'http://github.com/variables.css'; -@import 'http://github.com/config.css'; +@import 'http://github.com/colors.module.css'; +@import 'http://github.com/variables.module.css'; +@import 'http://github.com/config.module.css'; .iconMenu { display: inline-block; @@ -14,6 +14,25 @@ } } +.outline { + background-color: var(--menu-background-color); + border-radius: var(--menu-outline-border-radius); + box-shadow: var(--shadow-2p); + display: block; + left: 0; + position: absolute; + top: 0; +} + +.menuInner { + display: block; + list-style: none; + padding: var(--menu-padding); + position: relative; + text-align: left; + white-space: nowrap; +} + .menu { display: inline-block; position: relative; @@ -79,16 +98,6 @@ top: 0; } - &.rippled:not(.active) { - & > .outline { - transition-delay: var(--menu-ripple-delay); - } - - & > .menuInner { - transition-delay: var(--menu-ripple-delay); - } - } - &.active { pointer-events: all; @@ -104,26 +113,17 @@ clip var(--menu-expand-duration) var(--animation-curve-default); } } - } -} -.outline { - background-color: var(--menu-background-color); - border-radius: var(--menu-outline-border-radius); - box-shadow: var(--shadow-2p); - display: block; - left: 0; - position: absolute; - top: 0; -} + &.rippled:not(.active) { + & > .outline { + transition-delay: var(--menu-ripple-delay); + } -.menuInner { - display: block; - list-style: none; - padding: var(--menu-padding); - position: relative; - text-align: left; - white-space: nowrap; + & > .menuInner { + transition-delay: var(--menu-ripple-delay); + } + } + } } .menuItem { diff --git a/components/navigation/Navigation.js b/components/navigation/Navigation.js index 8a364c98f..d752b997c 100644 --- a/components/navigation/Navigation.js +++ b/components/navigation/Navigation.js @@ -7,7 +7,9 @@ import InjectButton from '../button/Button'; import InjectLink from '../link/Link'; const factory = (Button, Link) => { - const Navigation = ({ actions, children, className, routes, theme, type }) => { + const Navigation = ({ + actions, children, className, routes, theme, type, + }) => { const _className = classnames(theme[type], className); const buttons = actions.map((action, index) => (