├── .babelrc
├── .eslintignore
├── .eslintrc
├── .gitignore
├── .npmignore
├── .npmrc
├── .travis.yml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── no-important.js
├── package.json
├── src
├── aphroditeInterface.js
├── aphroditeInterfaceFactory.js
├── no-important.js
└── utils
│ ├── resolveLTR.js
│ ├── resolveRTL.js
│ └── separateStyles.js
└── test
├── .eslintrc
├── aphroditeInterfaceFactory_test.js
├── aphroditeInterface_test.js
├── mocha.opts
├── no-important_test.js
└── utils
├── resolveLTR_test.js
└── resolveRTL_test.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["airbnb"],
3 | "plugins": [
4 | ["transform-replace-object-assign", { "moduleSpecifier": "object.assign" }],
5 | ],
6 | }
7 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | lib/
2 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 | "env": {
4 | "browser": true,
5 | "node": true
6 | },
7 |
8 | "rules": {
9 | "no-underscore-dangle": 0
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 |
6 | # Runtime data
7 | pids
8 | *.pid
9 | *.seed
10 |
11 | # Directory for instrumented libs generated by jscoverage/JSCover
12 | lib-cov
13 |
14 | # Coverage directory used by tools like istanbul
15 | coverage
16 |
17 | # nyc test coverage
18 | .nyc_output
19 |
20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
21 | .grunt
22 |
23 | # node-waf configuration
24 | .lock-wscript
25 |
26 | # Compiled binary addons (http://nodejs.org/api/addons.html)
27 | build/Release
28 |
29 | # Dependency directories
30 | node_modules
31 | jspm_packages
32 |
33 | # Optional npm cache directory
34 | .npm
35 |
36 | # Optional REPL history
37 | .node_repl_history
38 |
39 | # Built files
40 | /lib
41 |
42 | # Only apps should have lockfiles
43 | npm-shrinkwrap.json
44 | package-lock.json
45 | yarn.lock
46 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 |
6 | # Runtime data
7 | pids
8 | *.pid
9 | *.seed
10 |
11 | # Directory for instrumented libs generated by jscoverage/JSCover
12 | lib-cov
13 |
14 | # Coverage directory used by tools like istanbul
15 | coverage
16 |
17 | # nyc test coverage
18 | .nyc_output
19 |
20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
21 | .grunt
22 |
23 | # node-waf configuration
24 | .lock-wscript
25 |
26 | # Compiled binary addons (http://nodejs.org/api/addons.html)
27 | build/Release
28 |
29 | # Dependency directories
30 | node_modules
31 | jspm_packages
32 |
33 | # Optional npm cache directory
34 | .npm
35 |
36 | # Optional REPL history
37 | .node_repl_history
38 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=false
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | sudo: false
3 | node_js:
4 | - "10"
5 | - "8"
6 | - "6"
7 | before_install:
8 | - 'nvm install-latest-npm'
9 | install:
10 | - 'if [ "${TRAVIS_NODE_VERSION}" = "0.6" ] || [ "${TRAVIS_NODE_VERSION}" = "0.9" ]; then nvm install --latest-npm 0.8 && npm install && nvm use "${TRAVIS_NODE_VERSION}"; else npm install; fi;'
11 | script:
12 | - 'if [ -n "${PRETEST-}" ]; then npm run pretest ; fi'
13 | - 'if [ -n "${POSTTEST-}" ]; then npm run posttest ; fi'
14 | - 'if [ -n "${COVERAGE-}" ]; then npm run coverage ; fi'
15 | - 'if [ -n "${TEST-}" ]; then npm run tests-only ; fi'
16 | sudo: false
17 | env:
18 | - TEST=true
19 | matrix:
20 | fast_finish: true
21 | include:
22 | - node_js: "lts/*"
23 | env: PRETEST=true
24 | - node_js: "lts/*"
25 | env: COVERAGE=true
26 | allow_failures:
27 | - os: osx
28 | - env: TEST=true ALLOW_FAILURE=true
29 | - env: COVERAGE=true
30 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## v6.0.1
4 |
5 | - [fix] Update rtl-css-js ^1.13.0 -> ^1.13.1
6 |
7 | ## v6.0.0
8 |
9 | - [Deps] Include `react-with-styles v4.0.0` in peer deps
10 | - [breaking] [Dev Deps] Update `@babel*`, `airbnb-js-shims`, `aphrodite`, `babel-plugin-transform-replace-object-assign`, `babel-preset-airbnb`, `chai`, `eslint*`, `prop-types`, `react`, `react-dom`, `sinon-sandbox` and drop support for node < 6
11 | - [Deps] update `object.entries`, `rtl-css-js`
12 | - [Dev Deps] update `eslint`, `eslint-config-airbnb`, `eslint-plugin-import`, `eslint-plugin-jsx-a11y`, `eslint-plugin-react`, `rimraf`, `safe-publish-latest`, `airbnb-js-shims`
13 |
14 | ## v5.0.1
15 |
16 | - [Deps] Replace `array-flatten` with `array.prototype.flat`
17 | - [Deps] Update `has` and `rtl-css-js`
18 | - [Dev] Update devDependencies
19 |
20 | ## v5.0.0
21 |
22 | - Remove support for Aphrodite v1 and earlier
23 |
24 | ## v4.0.2
25 |
26 | - Add support for Aphrodite v2
27 |
28 | ## v4.0.1
29 |
30 | - Fix `this` reference in create and resolve methods
31 |
32 | ## v4.0.0
33 |
34 | - Remove with-rtl interface in favor of separate LTR/RTL create and resolve methods
35 |
36 | ## v3.1.1
37 |
38 | - Allow boolean values for styles to run without failure
39 |
40 | ## v3.1.0
41 |
42 | - Add RTL support for `linear-gradient`
43 |
44 | ## v3.0.1
45 |
46 | - Fix for `with-rtl` interface when an aphrodite style is called multiple times
47 |
48 | ## v3.0.0
49 |
50 | - Revert default export to v1 version and export `with-rtl` interface in addition
51 |
52 | ## v2.1.0
53 |
54 | - Add RTL support for `borderLeftWidth`, `translateX`, `translate`, and `translate3d`
55 |
56 | ## v2.0.1
57 |
58 | - Fix RTL support for pseudoselectors and match media queries
59 |
60 | ## v2.0.0
61 |
62 | - Add RTL support in the `resolve` method
63 |
64 | ## v1.2.0
65 |
66 | - Add support for using Aphrodite in no-important mode, which disables adding
67 | `!important` to every style.
68 |
69 | ## v1.1.1
70 |
71 | - This release reverts all of the changes from 1.1.0, so inline styles no longer
72 | include vendor prefixes.
73 |
74 | ## v1.1.0
75 |
76 | - Inline styles will now automatically include vendor prefixes.
77 |
78 | ## v1.0.0
79 |
80 | - Initial release.
81 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Airbnb
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-with-styles-interface-aphrodite [![Version Badge][npm-version-svg]][package-url]
2 |
3 | [![Build Status][travis-svg]][travis-url]
4 | [![dependency status][deps-svg]][deps-url]
5 | [![dev dependency status][dev-deps-svg]][dev-deps-url]
6 | [![License][license-image]][license-url]
7 | [![Downloads][downloads-image]][downloads-url]
8 |
9 | [![npm badge][npm-badge-png]][package-url]
10 |
11 | Interface to use [react-with-styles][react-with-styles] with [Aphrodite][aphrodite].
12 |
13 | [package-url]: https://npmjs.org/package/react-with-styles-interface-aphrodite
14 | [npm-version-svg]: http://versionbadg.es/airbnb/react-with-styles-interface-aphrodite.svg
15 | [travis-svg]: https://travis-ci.org/airbnb/react-with-styles-interface-aphrodite.svg
16 | [travis-url]: https://travis-ci.org/airbnb/react-with-styles-interface-aphrodite
17 | [deps-svg]: https://david-dm.org/airbnb/react-with-styles-interface-aphrodite.svg
18 | [deps-url]: https://david-dm.org/airbnb/react-with-styles-interface-aphrodite
19 | [dev-deps-svg]: https://david-dm.org/airbnb/react-with-styles-interface-aphrodite/dev-status.svg
20 | [dev-deps-url]: https://david-dm.org/airbnb/react-with-styles-interface-aphrodite#info=devDependencies
21 | [npm-badge-png]: https://nodei.co/npm/react-with-styles-interface-aphrodite.png?downloads=true&stars=true
22 | [license-image]: http://img.shields.io/npm/l/react-with-styles-interface-aphrodite.svg
23 | [license-url]: LICENSE
24 | [downloads-image]: http://img.shields.io/npm/dm/react-with-styles-interface-aphrodite.svg
25 | [downloads-url]: http://npm-stat.com/charts.html?package=react-with-styles-interface-aphrodite
26 |
27 | [react-with-styles]: https://github.com/airbnb/react-with-styles
28 | [aphrodite]: https://github.com/khan/aphrodite
29 |
30 | ## Import
31 |
32 | ```js
33 | import aphroditeInterface from 'react-with-styles-interface-aphrodite';
34 | ```
35 |
36 | or when you need to [disable `!important`](https://github.com/Khan/aphrodite#disabling-important):
37 |
38 | ```js
39 | import aphroditeInterface from 'react-with-styles-interface-aphrodite/no-important';
40 | ```
41 |
42 | ## Built-in RTL support
43 |
44 | `react-with-styles-interface-aphrodite` has built-in LTR/RTL context support. Specifically, it uses [rtl-css-js](https://github.com/kentcdodds/rtl-css-js) to automatically flip styles (`margin`, `padding`, `float`, `textAlign`, etc.) that were written for an LTR page when your app is wrapped in [react-with-direction](https://github.com/airbnb/react-with-direction)'s `DirectionProvider` with direction set to `DIRECTIONS.RTL`.
45 |
46 | It accomplishes this by providing a directional `create` and `resolve` method. `react-with-styles` automatically uses the correct create method based on the direction value set in context and then passes down the appropriate `resolve` method as a prop named `css`.
47 |
48 | For instance, if you were to write your styles as follows:
49 |
50 | ```jsx
51 | import ThemedStyleSheet from 'react-with-styles/lib/ThemedStyleSheet';
52 | import aphroditeInterface from 'react-with-styles-interface-aphrodite';
53 | import { withStyles, css } from 'react-with-styles';
54 |
55 | ThemedStyleSheet.registerInterface(aphroditeInterface);
56 |
57 | ...
58 |
59 | function MyComponent({ css }) {
60 | return
Hello World
;
61 | }
62 |
63 | export default withStyles(() => ({
64 | container: {
65 | background: '#fff',
66 | float: 'left',
67 | },
68 | }))(MyComponent);
69 | ```
70 |
71 | The generated css for an app where you set `` at the top would look like:
72 |
73 | ```css
74 | .container_r5r4of {
75 | background: #fff !important;
76 | float: 'left' !important;
77 | }
78 | ```
79 |
80 | whereas if you had set ``, the generated css would be:
81 | ```css
82 | .container_kui6s4 {
83 | background: #fff !important;
84 | float: 'right' !important;
85 | }
86 | ```
87 |
88 | If you used an inline style instead:
89 |
90 | ```jsx
91 | import { css } from 'react-with-styles';
92 |
93 | export default function MyComponent() {
94 | return Hello World
;
95 | }
96 | ```
97 |
98 | In the case where `` is wrapping your component, this would map to a `style={{ background: '#fff', float: 'left' }}` on the div in question. If `` is present instead, this would simply apply `style={{ background: '#fff', float: 'right' }}` to the div.
99 |
--------------------------------------------------------------------------------
/no-important.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./lib/no-important.js'); // eslint-disable-line import/no-unresolved
2 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-with-styles-interface-aphrodite",
3 | "version": "6.0.1",
4 | "description": "react-with-styles interface for Aphrodite",
5 | "main": "lib/aphroditeInterface.js",
6 | "directories": {
7 | "test": "test"
8 | },
9 | "scripts": {
10 | "prebuild": "npm run clean",
11 | "build": "babel src -d lib",
12 | "check-changelog": "expr $(git status --porcelain 2>/dev/null| grep \"^\\s*M.*CHANGELOG.md\" | wc -l) >/dev/null || (echo 'Please edit CHANGELOG.md' && exit 1)",
13 | "check-only-changelog-changed": "(expr $(git status --porcelain 2>/dev/null| grep -v \"CHANGELOG.md\" | wc -l) >/dev/null && echo 'Only CHANGELOG.md may have uncommitted changes' && exit 1) || exit 0",
14 | "clean": "rimraf lib",
15 | "lint": "eslint .",
16 | "mocha": "mocha",
17 | "postversion": "git commit package.json CHANGELOG.md -m \"Version $npm_package_version\" && npm run tag && git push && git push --tags && npm publish",
18 | "prepublish": "in-publish && safe-publish-latest && npm run build || not-in-publish",
19 | "pretest": "npm run --silent lint",
20 | "preversion": "npm run test && npm run check-changelog && npm run check-only-changelog-changed",
21 | "tag": "git tag v$npm_package_version",
22 | "test": "npm run tests-only",
23 | "tests-only": "npm run --silent mocha test",
24 | "version:major": "npm --no-git-tag-version version major",
25 | "version:minor": "npm --no-git-tag-version version minor",
26 | "version:patch": "npm --no-git-tag-version version patch"
27 | },
28 | "repository": {
29 | "type": "git",
30 | "url": "git+https://github.com/airbnb/react-with-styles-interface-aphrodite.git"
31 | },
32 | "keywords": [
33 | "react-with-styles",
34 | "aphrodite"
35 | ],
36 | "author": "Joe Lencioni ",
37 | "license": "MIT",
38 | "bugs": {
39 | "url": "https://github.com/airbnb/react-with-styles-interface-aphrodite/issues"
40 | },
41 | "homepage": "https://github.com/airbnb/react-with-styles-interface-aphrodite#readme",
42 | "devDependencies": {
43 | "@babel/cli": "^7.5.5",
44 | "@babel/core": "^7.5.5",
45 | "@babel/register": "^7.5.5",
46 | "airbnb-js-shims": "^2.2.0",
47 | "aphrodite": "^2.3.1",
48 | "babel-plugin-transform-replace-object-assign": "^2.0.0",
49 | "babel-preset-airbnb": "^4.0.1",
50 | "chai": "^4.2.0",
51 | "eslint": "^5.16.0",
52 | "eslint-config-airbnb": "^17.1.1",
53 | "eslint-plugin-import": "^2.18.2",
54 | "eslint-plugin-jsx-a11y": "^6.2.3",
55 | "eslint-plugin-react": "^7.14.3",
56 | "in-publish": "^2.0.0",
57 | "mocha": "^5.2.0",
58 | "prop-types": "^15.7.2",
59 | "react": "^16.8.6",
60 | "react-dom": "^16.8.6",
61 | "rimraf": "^2.6.3",
62 | "safe-publish-latest": "^1.1.2",
63 | "sinon": "^6.3.5",
64 | "sinon-sandbox": "^2.0.5"
65 | },
66 | "peerDependencies": {
67 | "aphrodite": "^2.1.0",
68 | "react-with-styles": "^3.0.0 || ^4.0.0"
69 | },
70 | "dependencies": {
71 | "array.prototype.flat": "^1.2.1",
72 | "has": "^1.0.3",
73 | "object.assign": "^4.1.0",
74 | "object.entries": "^1.1.0",
75 | "rtl-css-js": "^1.13.1"
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/aphroditeInterface.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet, css, flushToStyleTag } from 'aphrodite';
2 | import aphroditeInterfaceFactory from './aphroditeInterfaceFactory';
3 |
4 | export default aphroditeInterfaceFactory({
5 | StyleSheet,
6 | css,
7 | flushToStyleTag,
8 | });
9 |
--------------------------------------------------------------------------------
/src/aphroditeInterfaceFactory.js:
--------------------------------------------------------------------------------
1 | import rtlCSSJS from 'rtl-css-js';
2 | import entries from 'object.entries';
3 |
4 | import resolveLTR from './utils/resolveLTR';
5 | import resolveRTL from './utils/resolveRTL';
6 |
7 | export default ({ StyleSheet, css, flushToStyleTag }/* aphrodite */) => ({
8 | create(styleHash) {
9 | return StyleSheet.create(styleHash);
10 | },
11 |
12 | createLTR(styleHash) {
13 | return StyleSheet.create(styleHash);
14 | },
15 |
16 | createRTL(styleHash) {
17 | const styleHashRTL = {};
18 | entries(styleHash).forEach(([styleKey, styleDef]) => {
19 | styleHashRTL[styleKey] = rtlCSSJS(styleDef);
20 | });
21 |
22 | return StyleSheet.create(styleHashRTL);
23 | },
24 |
25 | resolve(styles) {
26 | return resolveLTR(css, styles);
27 | },
28 |
29 | resolveLTR(styles) {
30 | return resolveLTR(css, styles);
31 | },
32 |
33 | resolveRTL(styles) {
34 | return resolveRTL(css, styles);
35 | },
36 |
37 | // Flushes all buffered styles to a style tag. Required for components
38 | // that depend upon previous styles in the component tree (i.e.
39 | // for calculating container width, including padding/margin).
40 | flush() {
41 | flushToStyleTag();
42 | },
43 | });
44 |
--------------------------------------------------------------------------------
/src/no-important.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet, css, flushToStyleTag } from 'aphrodite/no-important';
2 | import aphroditeInterfaceFactory from './aphroditeInterfaceFactory';
3 |
4 | export default aphroditeInterfaceFactory({
5 | StyleSheet,
6 | css,
7 | flushToStyleTag,
8 | });
9 |
--------------------------------------------------------------------------------
/src/utils/resolveLTR.js:
--------------------------------------------------------------------------------
1 | import flat from 'array.prototype.flat';
2 |
3 | import separateStyles from './separateStyles';
4 |
5 | // Styles is an array of properties returned by `create()`, a POJO, or an
6 | // array thereof. POJOs are treated as inline styles. This version of the
7 | // resolve function explicitly does no work to flip styles for an RTL context.
8 | // This function returns an object to be spread onto an element.
9 | export default function resolveLTR(css, styles) {
10 | const flattenedStyles = flat(styles, Infinity);
11 |
12 | const {
13 | aphroditeStyles,
14 | hasInlineStyles,
15 | inlineStyles,
16 | } = separateStyles(flattenedStyles);
17 |
18 | const result = {};
19 | if (aphroditeStyles.length > 0) {
20 | result.className = css(...aphroditeStyles);
21 | }
22 |
23 | if (hasInlineStyles) {
24 | result.style = inlineStyles;
25 | }
26 |
27 | return result;
28 | }
29 |
--------------------------------------------------------------------------------
/src/utils/resolveRTL.js:
--------------------------------------------------------------------------------
1 | import flat from 'array.prototype.flat';
2 | import rtlCSSJS from 'rtl-css-js';
3 |
4 | import separateStyles from './separateStyles';
5 |
6 | // Styles is an array of properties returned by `create()`, a POJO, or an
7 | // array thereof. POJOs are treated as inline styles. This version of the
8 | // resolve function explicitly flips inline styles for an RTL context.
9 | // This function returns an object to be spread onto an element.
10 | export default function resolveRTL(css, styles) {
11 | const flattenedStyles = flat(styles, Infinity);
12 |
13 | const {
14 | aphroditeStyles,
15 | hasInlineStyles,
16 | inlineStyles,
17 | } = separateStyles(flattenedStyles);
18 |
19 | const result = {};
20 | if (aphroditeStyles.length > 0) {
21 | result.className = css(...aphroditeStyles);
22 | }
23 |
24 | if (hasInlineStyles) {
25 | result.style = rtlCSSJS(inlineStyles);
26 | }
27 |
28 | return result;
29 | }
30 |
--------------------------------------------------------------------------------
/src/utils/separateStyles.js:
--------------------------------------------------------------------------------
1 | import has from 'has';
2 |
3 | // This function takes the array of styles and separates them into styles that
4 | // are handled by Aphrodite and inline styles.
5 | export default function separateStyles(stylesArray) {
6 | const aphroditeStyles = [];
7 |
8 | // Since determining if an Object is empty requires collecting all of its
9 | // keys, and we want the best performance in this code because we are in the
10 | // render path, we are going to do a little bookkeeping ourselves.
11 | let hasInlineStyles = false;
12 | const inlineStyles = {};
13 |
14 | // This is run on potentially every node in the tree when rendering, where
15 | // performance is critical. Normally we would prefer using `forEach`, but
16 | // old-fashioned for loops are faster so that's what we have chosen here.
17 | for (let i = 0; i < stylesArray.length; i += 1) {
18 | const style = stylesArray[i];
19 |
20 | // If this style is falsey, we just want to disregard it. This allows for
21 | // syntax like:
22 | //
23 | // css(isFoo && styles.foo)
24 | if (style) {
25 | if (has(style, '_name') && has(style, '_definition')) {
26 | aphroditeStyles.push(style);
27 | } else {
28 | Object.assign(inlineStyles, style);
29 | hasInlineStyles = true;
30 | }
31 | }
32 | }
33 |
34 | return {
35 | aphroditeStyles,
36 | hasInlineStyles,
37 | inlineStyles,
38 | };
39 | }
40 |
--------------------------------------------------------------------------------
/test/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "mocha": true
4 | },
5 | "rules": {
6 | "import/no-extraneous-dependencies": [2, {
7 | "devDependencies": true
8 | }]
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/test/aphroditeInterfaceFactory_test.js:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai';
2 | import sinon from 'sinon-sandbox';
3 | import {
4 | StyleSheet,
5 | css,
6 | flushToStyleTag,
7 | StyleSheetTestUtils,
8 | } from 'aphrodite';
9 | import aphroditeInterfaceFactory from '../src/aphroditeInterfaceFactory';
10 |
11 | import * as resolveLTR from '../src/utils/resolveLTR';
12 | import * as resolveRTL from '../src/utils/resolveRTL';
13 |
14 | describe('aphroditeInterfaceFactory', () => {
15 | const aphroditeInterface = aphroditeInterfaceFactory({
16 | StyleSheet,
17 | css,
18 | flushToStyleTag,
19 | });
20 |
21 | let resolveLTRSpy;
22 | let resolveRTLSpy;
23 |
24 | beforeEach(() => {
25 | StyleSheetTestUtils.suppressStyleInjection();
26 | resolveLTRSpy = sinon.spy(resolveLTR, 'default');
27 | resolveRTLSpy = sinon.spy(resolveRTL, 'default');
28 | });
29 |
30 | afterEach(() => {
31 | StyleSheetTestUtils.clearBufferAndResumeStyleInjection();
32 | sinon.restore();
33 | });
34 |
35 | describe('.create()', () => {
36 | it('processes the styles with Aphrodite', () => {
37 | expect(aphroditeInterface.create({
38 | foo: {
39 | color: 'red',
40 | },
41 | })).to.eql({
42 | foo: {
43 | _definition: {
44 | color: 'red',
45 | },
46 | _len: 15,
47 | _name: 'foo_137u7ef',
48 | },
49 | });
50 | });
51 | });
52 |
53 | describe('.createLTR()', () => {
54 | it('processes the styles with Aphrodite', () => {
55 | expect(aphroditeInterface.createLTR({
56 | foo: {
57 | left: 10,
58 | },
59 | })).to.eql({
60 | foo: {
61 | _definition: {
62 | left: 10,
63 | },
64 | _len: 11,
65 | _name: 'foo_lg4jz7',
66 | },
67 | });
68 | });
69 | });
70 |
71 | describe('.createRTL()', () => {
72 | it('processes the styles with Aphrodite', () => {
73 | expect(aphroditeInterface.createRTL({
74 | foo: {
75 | left: 10,
76 | },
77 | })).to.eql({
78 | foo: {
79 | _definition: {
80 | right: 10,
81 | },
82 | _len: 12,
83 | _name: 'foo_6eoou0',
84 | },
85 | });
86 | });
87 | });
88 |
89 | describe('.resolve()', () => {
90 | it('calls resolveLTR method', () => {
91 | aphroditeInterface.resolve([]);
92 | expect(resolveLTRSpy.callCount).to.equal(1);
93 | });
94 | });
95 |
96 | describe('.resolveLTR()', () => {
97 | it('calls resolveLTR method', () => {
98 | aphroditeInterface.resolveLTR([]);
99 | expect(resolveLTRSpy.callCount).to.equal(1);
100 | });
101 | });
102 |
103 | describe('.resolveRTL()', () => {
104 | it('calls resolveRTL method', () => {
105 | aphroditeInterface.resolveRTL([]);
106 | expect(resolveRTLSpy.callCount).to.equal(1);
107 | });
108 | });
109 | });
110 |
--------------------------------------------------------------------------------
/test/aphroditeInterface_test.js:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai';
2 | import React from 'react';
3 | import { css, StyleSheetServer, StyleSheetTestUtils } from 'aphrodite';
4 | import ReactDOMServer from 'react-dom/server';
5 | import aphroditeInterface from '../src/aphroditeInterface';
6 |
7 | describe('aphroditeInterface', () => {
8 | beforeEach(() => {
9 | StyleSheetTestUtils.suppressStyleInjection();
10 | });
11 |
12 | afterEach(() => {
13 | StyleSheetTestUtils.clearBufferAndResumeStyleInjection();
14 | });
15 |
16 | it('is an interface', () => {
17 | expect(typeof aphroditeInterface.create).to.equal('function');
18 | expect(typeof aphroditeInterface.createLTR).to.equal('function');
19 | expect(typeof aphroditeInterface.createRTL).to.equal('function');
20 | expect(typeof aphroditeInterface.resolve).to.equal('function');
21 | expect(typeof aphroditeInterface.resolveLTR).to.equal('function');
22 | expect(typeof aphroditeInterface.resolveRTL).to.equal('function');
23 | });
24 |
25 | it('uses !important', () => {
26 | const styles = aphroditeInterface.create({
27 | foo: {
28 | color: 'red',
29 | },
30 | });
31 | const result = StyleSheetServer.renderStatic(() => (
32 | ReactDOMServer.renderToString(React.createElement('div', { className: css(styles.foo) }))
33 | ));
34 | expect(result.css.content.includes('!important')).to.equal(true);
35 | });
36 | });
37 |
--------------------------------------------------------------------------------
/test/mocha.opts:
--------------------------------------------------------------------------------
1 | --require @babel/register test/**/*.{js,jsx}
2 | --require airbnb-js-shims
3 | --recursive
4 |
--------------------------------------------------------------------------------
/test/no-important_test.js:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai';
2 | import React from 'react';
3 | import { css, StyleSheetServer, StyleSheetTestUtils } from 'aphrodite/no-important';
4 | import ReactDOMServer from 'react-dom/server';
5 | import aphroditeInterface from '../src/no-important';
6 |
7 | describe('no-important', () => {
8 | beforeEach(() => {
9 | StyleSheetTestUtils.suppressStyleInjection();
10 | });
11 |
12 | afterEach(() => {
13 | StyleSheetTestUtils.clearBufferAndResumeStyleInjection();
14 | });
15 |
16 | it('is an interface', () => {
17 | expect(typeof aphroditeInterface.create).to.equal('function');
18 | expect(typeof aphroditeInterface.createLTR).to.equal('function');
19 | expect(typeof aphroditeInterface.createRTL).to.equal('function');
20 | expect(typeof aphroditeInterface.resolve).to.equal('function');
21 | expect(typeof aphroditeInterface.resolveLTR).to.equal('function');
22 | expect(typeof aphroditeInterface.resolveRTL).to.equal('function');
23 | });
24 |
25 | it('does not use !important', () => {
26 | const styles = aphroditeInterface.create({
27 | foo: {
28 | color: 'red',
29 | },
30 | });
31 | const result = StyleSheetServer.renderStatic(() => (
32 | ReactDOMServer.renderToString(React.createElement('div', { className: css(styles.foo) }))
33 | ));
34 | expect(result.css.content.includes('!important')).to.equal(false);
35 | });
36 | });
37 |
--------------------------------------------------------------------------------
/test/utils/resolveLTR_test.js:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai';
2 | import { StyleSheetTestUtils, StyleSheet, css } from 'aphrodite';
3 |
4 | import resolveLTR from '../../src/utils/resolveLTR';
5 |
6 | describe('#resolveLTR', () => {
7 | beforeEach(() => {
8 | StyleSheetTestUtils.suppressStyleInjection();
9 | });
10 |
11 | afterEach(() => {
12 | StyleSheetTestUtils.clearBufferAndResumeStyleInjection();
13 | });
14 |
15 | it('turns a processed style into a className', () => {
16 | const styles = StyleSheet.create({
17 | foo: {
18 | color: 'red',
19 | },
20 | });
21 |
22 | expect(resolveLTR(css, [styles.foo]))
23 | .to.eql({ className: 'foo_137u7ef' });
24 | });
25 |
26 | it('turns multiple processed styles into a className', () => {
27 | const styles = StyleSheet.create({
28 | foo: {
29 | color: 'red',
30 | },
31 |
32 | bar: {
33 | display: 'inline-block',
34 | },
35 | });
36 |
37 | expect(resolveLTR(css, [styles.foo, styles.bar]))
38 | .to.eql({ className: 'foo_137u7ef-o_O-bar_36rlri' });
39 | });
40 |
41 | it('handles an object with inline styles', () => {
42 | const style = {
43 | color: 'red',
44 | marginLeft: 10,
45 | };
46 |
47 | expect(resolveLTR(css, [style]))
48 | .to.eql({
49 | style: {
50 | color: 'red',
51 | marginLeft: 10,
52 | },
53 | });
54 | });
55 |
56 | it('handles multiple objects with inline styles', () => {
57 | const styleA = {
58 | color: 'red',
59 | };
60 |
61 | const styleB = {
62 | display: 'inline-block',
63 | };
64 |
65 | expect(resolveLTR(css, [styleA, styleB]))
66 | .to.eql({
67 | style: {
68 | color: 'red',
69 | display: 'inline-block',
70 | },
71 | });
72 | });
73 |
74 | it('prefers inline styles from later arguments', () => {
75 | const styleA = {
76 | color: 'red',
77 | };
78 |
79 | const styleB = {
80 | color: 'blue',
81 | };
82 |
83 | expect(resolveLTR(css, [styleA, styleB]))
84 | .to.eql({
85 | style: {
86 | color: 'blue',
87 | },
88 | });
89 | });
90 |
91 | it('handles a mix of Aphrodite and inline styles', () => {
92 | const styles = StyleSheet.create({
93 | foo: {
94 | color: 'red',
95 | },
96 | });
97 |
98 | const style = {
99 | display: 'inline-block',
100 | };
101 |
102 | expect(resolveLTR(css, [styles.foo, style]))
103 | .to.eql({
104 | className: 'foo_137u7ef',
105 | style: {
106 | display: 'inline-block',
107 | },
108 | });
109 | });
110 |
111 | it('handles nested arrays', () => {
112 | const styles = StyleSheet.create({
113 | foo: {
114 | color: 'red',
115 | },
116 | });
117 |
118 | const styleA = {
119 | display: 'inline-block',
120 | };
121 |
122 | const styleB = {
123 | padding: 1,
124 | };
125 |
126 | expect(resolveLTR(css, [[styles.foo], [[styleA, styleB]]]))
127 | .to.eql({
128 | className: 'foo_137u7ef',
129 | style: {
130 | display: 'inline-block',
131 | padding: 1,
132 | },
133 | });
134 | });
135 |
136 | it('handles multiple calls to the same style definition', () => {
137 | const styles = StyleSheet.create({
138 | container: {
139 | textAlign: 'left',
140 | },
141 | });
142 |
143 | resolveLTR(css, [styles.container]);
144 | const definition = { ...styles.container._definition };
145 |
146 | resolveLTR(css, [styles.container]);
147 | const newDefinition = styles.container._definition;
148 | expect(definition).to.eql(newDefinition);
149 | });
150 | });
151 |
--------------------------------------------------------------------------------
/test/utils/resolveRTL_test.js:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai';
2 | import { StyleSheetTestUtils, StyleSheet, css } from 'aphrodite';
3 |
4 | import resolveRTL from '../../src/utils/resolveRTL';
5 |
6 | describe('#resolveRTL', () => {
7 | beforeEach(() => {
8 | StyleSheetTestUtils.suppressStyleInjection();
9 | });
10 |
11 | afterEach(() => {
12 | StyleSheetTestUtils.clearBufferAndResumeStyleInjection();
13 | });
14 |
15 | it('turns a processed style into a className', () => {
16 | const styles = StyleSheet.create({
17 | foo: {
18 | color: 'red',
19 | },
20 | });
21 |
22 | expect(resolveRTL(css, [styles.foo]))
23 | .to.eql({ className: 'foo_137u7ef' });
24 | });
25 |
26 | it('turns multiple processed styles into a className', () => {
27 | const styles = StyleSheet.create({
28 | foo: {
29 | color: 'red',
30 | },
31 |
32 | bar: {
33 | display: 'inline-block',
34 | },
35 | });
36 |
37 | expect(resolveRTL(css, [styles.foo, styles.bar]))
38 | .to.eql({ className: 'foo_137u7ef-o_O-bar_36rlri' });
39 | });
40 |
41 | it('handles an object with inline styles', () => {
42 | const style = {
43 | color: 'red',
44 | };
45 |
46 | expect(resolveRTL(css, [style]))
47 | .to.eql({
48 | style: {
49 | color: 'red',
50 | },
51 | });
52 | });
53 |
54 | it('flips inline styles', () => {
55 | const style = {
56 | marginLeft: 10,
57 | };
58 |
59 | expect(resolveRTL(css, [style])).to.eql({ style: { marginRight: 10 } });
60 | });
61 |
62 | it('handles multiple objects with inline styles', () => {
63 | const styleA = {
64 | color: 'red',
65 | };
66 |
67 | const styleB = {
68 | display: 'inline-block',
69 | };
70 |
71 | expect(resolveRTL(css, [styleA, styleB]))
72 | .to.eql({
73 | style: {
74 | color: 'red',
75 | display: 'inline-block',
76 | },
77 | });
78 | });
79 |
80 | it('prefers inline styles from later arguments', () => {
81 | const styleA = {
82 | color: 'red',
83 | };
84 |
85 | const styleB = {
86 | color: 'blue',
87 | };
88 |
89 | expect(resolveRTL(css, [styleA, styleB]))
90 | .to.eql({
91 | style: {
92 | color: 'blue',
93 | },
94 | });
95 | });
96 |
97 | it('handles a mix of Aphrodite and inline styles', () => {
98 | const styles = StyleSheet.create({
99 | foo: {
100 | color: 'red',
101 | },
102 | });
103 |
104 | const style = {
105 | display: 'inline-block',
106 | };
107 |
108 | expect(resolveRTL(css, [styles.foo, style]))
109 | .to.eql({
110 | className: 'foo_137u7ef',
111 | style: {
112 | display: 'inline-block',
113 | },
114 | });
115 | });
116 |
117 | it('handles nested arrays', () => {
118 | const styles = StyleSheet.create({
119 | foo: {
120 | color: 'red',
121 | },
122 | });
123 |
124 | const styleA = {
125 | display: 'inline-block',
126 | };
127 |
128 | const styleB = {
129 | padding: 1,
130 | };
131 |
132 | expect(resolveRTL(css, [[styles.foo], [[styleA, styleB]]]))
133 | .to.eql({
134 | className: 'foo_137u7ef',
135 | style: {
136 | display: 'inline-block',
137 | padding: 1,
138 | },
139 | });
140 | });
141 |
142 | it('handles multiple calls to the same style definition', () => {
143 | const styles = StyleSheet.create({
144 | container: {
145 | textAlign: 'left',
146 | },
147 | });
148 |
149 | resolveRTL(css, [styles.container]);
150 | const definition = { ...styles.container._definition };
151 |
152 | resolveRTL(css, [styles.container]);
153 | const newDefinition = styles.container._definition;
154 | expect(definition).to.eql(newDefinition);
155 | });
156 | });
157 |
--------------------------------------------------------------------------------