├── examples
├── CsstaNativeDemo
│ ├── .watchmanconfig
│ ├── android
│ │ ├── settings.gradle
│ │ ├── app
│ │ │ ├── src
│ │ │ │ └── main
│ │ │ │ │ ├── res
│ │ │ │ │ ├── values
│ │ │ │ │ │ ├── strings.xml
│ │ │ │ │ │ └── styles.xml
│ │ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ │ └── ic_launcher.png
│ │ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ │ └── ic_launcher.png
│ │ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ │ └── ic_launcher.png
│ │ │ │ │ └── mipmap-xxhdpi
│ │ │ │ │ │ └── ic_launcher.png
│ │ │ │ │ ├── java
│ │ │ │ │ └── com
│ │ │ │ │ │ └── csstanativedemo
│ │ │ │ │ │ ├── MainActivity.java
│ │ │ │ │ │ └── MainApplication.java
│ │ │ │ │ └── AndroidManifest.xml
│ │ │ ├── BUCK
│ │ │ └── proguard-rules.pro
│ │ ├── gradle
│ │ │ └── wrapper
│ │ │ │ ├── gradle-wrapper.jar
│ │ │ │ └── gradle-wrapper.properties
│ │ ├── keystores
│ │ │ ├── debug.keystore.properties
│ │ │ └── BUCK
│ │ ├── build.gradle
│ │ ├── gradle.properties
│ │ └── gradlew.bat
│ ├── .buckconfig
│ ├── index.android.js
│ ├── index.ios.js
│ ├── .babelrc
│ ├── .eslintrc.js
│ ├── __tests__
│ │ ├── index.ios.js
│ │ └── index.android.js
│ ├── ios
│ │ ├── CsstaNativeDemo
│ │ │ ├── AppDelegate.h
│ │ │ ├── main.m
│ │ │ ├── Images.xcassets
│ │ │ │ └── AppIcon.appiconset
│ │ │ │ │ └── Contents.json
│ │ │ ├── AppDelegate.m
│ │ │ └── Info.plist
│ │ └── CsstaNativeDemoTests
│ │ │ ├── Info.plist
│ │ │ └── CsstaNativeDemoTests.m
│ ├── README.md
│ ├── .gitignore
│ ├── demos
│ │ ├── Basic.js
│ │ ├── ColorFunction.js
│ │ ├── Transitions.js
│ │ ├── CustomAnimations.js
│ │ ├── VariablesProvider.js
│ │ ├── StyleOverrides.js
│ │ ├── CSSVariables.js
│ │ ├── CustomButton.js
│ │ └── Animations.js
│ ├── package.json
│ ├── .flowconfig
│ └── App.js
└── cssta-demo
│ ├── src
│ ├── favicon.ico
│ ├── index.js
│ └── App.js
│ ├── upgrade
│ ├── src
│ │ ├── index.css
│ │ ├── index.js
│ │ ├── App.test.js
│ │ ├── App.css
│ │ ├── App.js
│ │ └── logo.svg
│ ├── public
│ │ ├── favicon.ico
│ │ └── index.html
│ ├── .gitignore
│ └── package.json
│ ├── .gitignore
│ ├── .eslintrc.js
│ ├── config-overrides.js
│ ├── public
│ └── index.html
│ ├── package.json
│ └── README.md
├── packages
├── benchmark
│ ├── .gitignore
│ ├── .babelrc
│ ├── mocks
│ │ └── react-native.js
│ ├── .eslintrc.js
│ ├── webpack.config.js
│ ├── package.json
│ └── index.js
├── cssta
│ ├── .babelrc
│ ├── native.js
│ ├── .flowconfig
│ ├── src
│ │ ├── index.js
│ │ ├── native
│ │ │ ├── withEnhancers.js
│ │ │ ├── util.js
│ │ │ ├── createComponent.js
│ │ │ ├── cssUtil.js
│ │ │ ├── __mocks__
│ │ │ │ └── react-native.js
│ │ │ ├── __tests__
│ │ │ │ ├── index.js
│ │ │ │ └── selectorTransform.js
│ │ │ ├── enhancers
│ │ │ │ ├── README.md
│ │ │ │ └── animationUtil.js
│ │ │ ├── index.js
│ │ │ ├── types.js
│ │ │ └── selectorTransform.js
│ │ ├── web
│ │ │ ├── types.js
│ │ │ ├── createComponent.js
│ │ │ ├── extractRules.js
│ │ │ ├── __tests__
│ │ │ │ └── createComponent.js
│ │ │ └── index.js
│ │ ├── css-transforms
│ │ │ ├── colors.js
│ │ │ └── variables.js
│ │ ├── factories
│ │ │ ├── types.js
│ │ │ ├── enhancerFactory.js
│ │ │ ├── componentFactory.js
│ │ │ └── __tests__
│ │ │ │ └── componentFactory.js
│ │ └── util
│ │ │ ├── index.js
│ │ │ ├── resolveVariableDependencies.js
│ │ │ └── __tests__
│ │ │ └── resolveVariableDependencies.js
│ ├── index.js
│ ├── flow-typed
│ │ ├── css-color-function.js
│ │ └── dependency-graph.js
│ ├── .npmignore
│ ├── webpack.config.js
│ ├── .eslintrc.js
│ └── package.json
└── babel-plugin-cssta
│ ├── fixtures
│ ├── no-imports
│ │ ├── expected.js
│ │ └── actual.js
│ ├── empty-rules
│ │ ├── actual.js
│ │ ├── expected.js
│ │ └── expected.css
│ ├── native-empty-rules
│ │ ├── expected.js
│ │ └── actual.js
│ ├── default
│ │ ├── actual.js
│ │ ├── expected.js
│ │ └── expected.css
│ ├── without-template
│ │ ├── actual.js
│ │ ├── expected.js
│ │ └── expected.css
│ ├── native-simple-interpolation
│ │ ├── options.json
│ │ ├── actual.js
│ │ └── expected.js
│ ├── native-complex-interpolation
│ │ ├── options.json
│ │ ├── actual.js
│ │ └── expected.js
│ ├── native-shorthand-interpolation
│ │ ├── options.json
│ │ ├── actual.js
│ │ └── expected.js
│ ├── without-quasi
│ │ ├── actual.js
│ │ ├── expected.js
│ │ └── expected.css
│ ├── native-simple-interpolation-suffix
│ │ ├── options.json
│ │ ├── actual.js
│ │ └── expected.js
│ ├── import-under-different-name
│ │ ├── actual.js
│ │ ├── expected.js
│ │ └── expected.css
│ ├── computed
│ │ ├── actual.js
│ │ ├── expected.js
│ │ └── expected.css
│ ├── compose-without-template
│ │ ├── actual.js
│ │ ├── expected.js
│ │ └── expected.css
│ ├── boolean-attribute
│ │ ├── actual.js
│ │ ├── expected.css
│ │ └── expected.js
│ ├── compose-component
│ │ ├── actual.js
│ │ ├── expected.js
│ │ └── expected.css
│ ├── native
│ │ ├── actual.js
│ │ └── expected.js
│ ├── compose-without-quasi
│ │ ├── actual.js
│ │ ├── expected.js
│ │ └── expected.css
│ ├── css-variables-single-source-web
│ │ ├── options.json
│ │ ├── actual.js
│ │ ├── expected.js
│ │ └── expected.css
│ ├── css-variables-single-source-native
│ │ ├── options.json
│ │ ├── actual.js
│ │ └── expected.js
│ ├── css-variables-import-native
│ │ ├── actual.js
│ │ └── expected.js
│ ├── native-color-function
│ │ ├── actual.js
│ │ └── expected.js
│ ├── native-shorthand
│ │ ├── actual.js
│ │ └── expected.js
│ ├── css-variables-native
│ │ ├── actual.js
│ │ └── expected.js
│ ├── native-variables-provider
│ │ ├── actual.js
│ │ └── expected.js
│ ├── native-within-closure
│ │ ├── actual.js
│ │ └── expected.js
│ ├── css-variables-single-source-native-interpolated-defaults
│ │ ├── options.json
│ │ ├── actual.js
│ │ └── expected.js
│ ├── multiple-calls-in-file
│ │ ├── actual.js
│ │ ├── expected.css
│ │ └── expected.js
│ ├── css-variables-export-native
│ │ ├── actual.js
│ │ └── expected.js
│ ├── string-attribute
│ │ ├── actual.js
│ │ ├── expected.js
│ │ └── expected.css
│ ├── native-transitions
│ │ ├── actual.js
│ │ └── expected.js
│ ├── native-transitions-variables
│ │ ├── actual.js
│ │ └── expected.js
│ ├── multiple-attributes
│ │ ├── actual.js
│ │ ├── expected.js
│ │ └── expected.css
│ ├── native-keyframes-variables
│ │ ├── actual.js
│ │ └── expected.js
│ ├── native-keyframes
│ │ ├── actual.js
│ │ └── expected.js
│ ├── native-keyframes-without-variables
│ │ ├── actual.js
│ │ └── expected.js
│ ├── native-multiple-attributes
│ │ ├── actual.js
│ │ └── expected.js
│ ├── native-interpolation-no-optimisation
│ │ ├── expected.js
│ │ └── actual.js
│ └── native-transitions-shorthand
│ │ ├── actual.js
│ │ └── expected.js
│ ├── .npmignore
│ ├── src
│ ├── webUtil.js
│ ├── platforms
│ │ ├── native
│ │ │ ├── createArgsStatic.js
│ │ │ ├── createUtil.js
│ │ │ ├── createArgsVariables.js
│ │ │ ├── createKeyframes.js
│ │ │ ├── util.js
│ │ │ ├── index.js
│ │ │ └── simpleInterpolationMap.js
│ │ └── web.js
│ ├── visitors
│ │ ├── program
│ │ │ ├── removeUnusedCsstaImports.js
│ │ │ ├── singleSourceOfVariables.js
│ │ │ └── web.js
│ │ ├── importSpecifier
│ │ │ └── redirectImports.js
│ │ └── csstaCall.js
│ ├── index.js
│ ├── index.test.js
│ ├── transformUtil
│ │ └── extractCsstaCallParts.js
│ └── optimizations
│ │ └── singleSourceOfVariables.js
│ ├── .eslintrc.js
│ └── package.json
├── docs
├── .gitignore
├── _includes
│ └── sidebar-link.html
├── Gemfile
├── external-modules.md
├── _config.yml
├── theming.md
├── web.md
├── _layouts
│ └── page.html
└── editor-integration.md
├── .vscode
└── settings.json
├── lerna.json
├── package.json
└── .gitignore
/examples/CsstaNativeDemo/.watchmanconfig:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/packages/benchmark/.gitignore:
--------------------------------------------------------------------------------
1 | tests-compiled.js
2 |
--------------------------------------------------------------------------------
/packages/cssta/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015"]
3 | }
4 |
--------------------------------------------------------------------------------
/packages/cssta/native.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./lib/native');
2 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/no-imports/expected.js:
--------------------------------------------------------------------------------
1 | console.log('...');
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | _site
2 | .sass-cache
3 | .asset-cache
4 | .jekyll-metadata
5 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/no-imports/actual.js:
--------------------------------------------------------------------------------
1 | console.log('...');
2 |
--------------------------------------------------------------------------------
/packages/cssta/.flowconfig:
--------------------------------------------------------------------------------
1 | [ignore]
2 | .*/lib/.*
3 |
4 | [libs]
5 | flow-typed
6 |
--------------------------------------------------------------------------------
/packages/cssta/src/index.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | module.exports = require('./web/index');
3 |
--------------------------------------------------------------------------------
/packages/cssta/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | module.exports = require('./lib/web');
3 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | // Place your settings in this file to overwrite default and user settings.
2 | {}
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/android/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'CsstaNativeDemo'
2 |
3 | include ':app'
4 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/empty-rules/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta';
2 |
3 | cssta.div``;
4 |
--------------------------------------------------------------------------------
/examples/cssta-demo/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/functions/cssta/master/examples/cssta-demo/src/favicon.ico
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-empty-rules/expected.js:
--------------------------------------------------------------------------------
1 |
2 | import { View } from 'react-native';
3 |
4 | View;
--------------------------------------------------------------------------------
/examples/cssta-demo/upgrade/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "lerna": "2.0.0-beta.37",
3 | "packages": [
4 | "packages/*"
5 | ],
6 | "version": "0.7.0"
7 | }
8 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/default/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta';
2 |
3 | cssta.button`
4 | color: red;
5 | `;
6 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/without-template/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta';
2 |
3 | cssta.button('color: red;');
4 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-simple-interpolation/options.json:
--------------------------------------------------------------------------------
1 | {
2 | "optimizations": ["interpolateValuesOnly"]
3 | }
4 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-complex-interpolation/options.json:
--------------------------------------------------------------------------------
1 | {
2 | "optimizations": ["interpolateValuesOnly"]
3 | }
4 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-shorthand-interpolation/options.json:
--------------------------------------------------------------------------------
1 | {
2 | "optimizations": ["interpolateValuesOnly"]
3 | }
4 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/without-quasi/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta';
2 |
3 | cssta.button(`
4 | color: red;
5 | `);
6 |
--------------------------------------------------------------------------------
/packages/benchmark/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [["latest", { "modules": false }], "react"],
3 | "plugins": ["babel-plugin-cssta"]
4 | }
5 |
--------------------------------------------------------------------------------
/examples/cssta-demo/upgrade/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/functions/cssta/master/examples/cssta-demo/upgrade/public/favicon.ico
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-simple-interpolation-suffix/options.json:
--------------------------------------------------------------------------------
1 | {
2 | "optimizations": ["interpolateValuesOnly"]
3 | }
4 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | CsstaNativeDemo
3 |
4 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/import-under-different-name/actual.js:
--------------------------------------------------------------------------------
1 | import otherName from 'cssta';
2 |
3 | otherName.button`
4 | color: red;
5 | `;
6 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/computed/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta';
2 |
3 | const button = 'button';
4 | cssta[button]`
5 | color: red;
6 | `;
7 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-empty-rules/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta/native';
2 | import { View } from 'react-native';
3 |
4 | cssta(View)``;
5 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/.buckconfig:
--------------------------------------------------------------------------------
1 |
2 | [android]
3 | target = Google Inc.:Google APIs:23
4 |
5 | [maven_repositories]
6 | central = https://repo1.maven.org/maven2
7 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/compose-without-template/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta';
2 | import Link from 'react-router';
3 |
4 | cssta(Link)('color: red;');
5 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/boolean-attribute/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta';
2 |
3 | cssta.button`
4 | &[@booleanAttribute] {
5 | color: red;
6 | }
7 | `;
8 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/compose-component/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta';
2 | import Link from 'react-router';
3 |
4 | cssta(Link)`
5 | color: red;
6 | `;
7 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta/native';
2 | import { View } from 'react-native';
3 |
4 | cssta(View)`
5 | color: red;
6 | `;
7 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/functions/cssta/master/examples/CsstaNativeDemo/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/compose-without-quasi/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta';
2 | import Link from 'react-router';
3 |
4 | cssta(Link)(`
5 | color: red;
6 | `);
7 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/android/keystores/debug.keystore.properties:
--------------------------------------------------------------------------------
1 | key.store=debug.keystore
2 | key.alias=androiddebugkey
3 | key.store.password=android
4 | key.alias.password=android
5 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/index.android.js:
--------------------------------------------------------------------------------
1 | import { AppRegistry } from 'react-native';
2 | import App from './App';
3 |
4 |
5 | AppRegistry.registerComponent('CsstaNativeDemo', () => App);
6 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/index.ios.js:
--------------------------------------------------------------------------------
1 | import { AppRegistry } from 'react-native';
2 | import App from './App';
3 |
4 |
5 | AppRegistry.registerComponent('CsstaNativeDemo', () => App);
6 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/css-variables-single-source-web/options.json:
--------------------------------------------------------------------------------
1 | {
2 | "optimizations": [
3 | ["singleSourceOfVariables", { "sourceFilename": "actual.js" }]
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/css-variables-single-source-native/options.json:
--------------------------------------------------------------------------------
1 | {
2 | "optimizations": [
3 | ["singleSourceOfVariables", { "sourceFilename": "actual.js" }]
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/functions/cssta/master/examples/CsstaNativeDemo/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/functions/cssta/master/examples/CsstaNativeDemo/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/packages/cssta/flow-typed/css-color-function.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | /*::
3 | declare module 'css-color-function' {
4 | declare module.exports: {
5 | convert: (input: string) => string
6 | }
7 | }
8 | */
9 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/functions/cssta/master/examples/CsstaNativeDemo/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/functions/cssta/master/examples/CsstaNativeDemo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/css-variables-import-native/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta/native';
2 | import { View } from 'react-native';
3 |
4 | cssta(View)`
5 | color: var(--color);
6 | `;
7 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-color-function/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta/native';
2 | import { View } from 'react-native';
3 |
4 | cssta(View)`
5 | color: color(red l(+ 25%));
6 | `;
7 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/android/keystores/BUCK:
--------------------------------------------------------------------------------
1 | keystore(
2 | name = 'debug',
3 | store = 'debug.keystore',
4 | properties = 'debug.keystore.properties',
5 | visibility = [
6 | 'PUBLIC',
7 | ],
8 | )
9 |
--------------------------------------------------------------------------------
/examples/cssta-demo/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | ReactDOM.render(
6 | ,
7 | document.getElementById('root')
8 | );
9 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-shorthand/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta/native';
2 | import { View } from 'react-native';
3 |
4 | cssta(View)`
5 | font: bold italic 12px/18px "Helvetica";
6 | `;
7 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/css-variables-native/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta/native';
2 | import { View } from 'react-native';
3 |
4 | cssta(View)`
5 | --color: red;
6 | color: var(--color);
7 | `;
8 |
--------------------------------------------------------------------------------
/docs/_includes/sidebar-link.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/default/expected.js:
--------------------------------------------------------------------------------
1 | import _createComponent from 'cssta/lib/web/createComponent';
2 |
3 |
4 | _createComponent('button', null, {
5 | 'defaultClassName': 'A',
6 | 'classNameMap': {}
7 | });
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/empty-rules/expected.js:
--------------------------------------------------------------------------------
1 | import _createComponent from 'cssta/lib/web/createComponent';
2 |
3 |
4 | _createComponent('div', null, {
5 | 'defaultClassName': null,
6 | 'classNameMap': {}
7 | });
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/empty-rules/expected.css:
--------------------------------------------------------------------------------
1 | /* File generated by babel-plugin-cssta */
2 |
3 | /* Start /fixtures/empty-rules/actual.js */
4 |
5 |
6 | /* End /fixtures/empty-rules/actual.js */
7 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/without-quasi/expected.js:
--------------------------------------------------------------------------------
1 | import _createComponent from 'cssta/lib/web/createComponent';
2 |
3 |
4 | _createComponent('button', null, {
5 | 'defaultClassName': 'A',
6 | 'classNameMap': {}
7 | });
--------------------------------------------------------------------------------
/packages/benchmark/mocks/react-native.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | import { createElement } from 'react';
3 |
4 | export const StyleSheet = {
5 | create: () => ({}),
6 | };
7 |
8 | export const View = props => createElement('view', props);
9 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/without-template/expected.js:
--------------------------------------------------------------------------------
1 | import _createComponent from 'cssta/lib/web/createComponent';
2 |
3 |
4 | _createComponent('button', null, {
5 | 'defaultClassName': 'A',
6 | 'classNameMap': {}
7 | });
--------------------------------------------------------------------------------
/packages/cssta/src/native/withEnhancers.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | const enhancerFactory = require('../factories/enhancerFactory');
3 | const createComponent = require('./createComponent');
4 |
5 | module.exports = enhancerFactory(createComponent);
6 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-variables-provider/actual.js:
--------------------------------------------------------------------------------
1 | import cssta, { VariablesProvider } from 'cssta/native';
2 | import { View } from 'react-native';
3 |
4 | cssta(View)`
5 | color: red;
6 | `;
7 |
8 | VariablesProvider
9 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-within-closure/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta/native';
2 | import { View } from 'react-native';
3 |
4 | function test() {
5 | const Component = cssta(View)`
6 | color: red;
7 | `;
8 | }
9 |
--------------------------------------------------------------------------------
/packages/cssta/src/web/types.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | /*::
3 | export type ClassNameMap = { [key:string]: { [key:string]: string } }
4 |
5 | export type Args = {
6 | defaultClassName: ?string,
7 | classNameMap: ClassNameMap,
8 | }
9 | */
10 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/import-under-different-name/expected.js:
--------------------------------------------------------------------------------
1 | import _createComponent from 'cssta/lib/web/createComponent';
2 |
3 |
4 | _createComponent('button', null, {
5 | 'defaultClassName': 'A',
6 | 'classNameMap': {}
7 | });
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/computed/expected.js:
--------------------------------------------------------------------------------
1 | import _createComponent from 'cssta/lib/web/createComponent';
2 |
3 |
4 | const button = 'button';
5 | _createComponent(button, null, {
6 | 'defaultClassName': 'A',
7 | 'classNameMap': {}
8 | });
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/css-variables-single-source-native-interpolated-defaults/options.json:
--------------------------------------------------------------------------------
1 | {
2 | "optimizations": [
3 | ["singleSourceOfVariables", { "sourceFilename": "actual.js" }],
4 | "interpolateValuesOnly"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/multiple-calls-in-file/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta';
2 |
3 | cssta.button`
4 | color: red;
5 | `;
6 |
7 | cssta.span`
8 | color: green;
9 | `;
10 |
11 | cssta.div`
12 | color: blue;
13 | `;
14 |
--------------------------------------------------------------------------------
/examples/cssta-demo/upgrade/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 | import './index.css';
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | );
10 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-simple-interpolation-suffix/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta/native';
2 | import { View, StyleSheet } from 'react-native';
3 |
4 | cssta(View)`
5 | border-bottom-width: ${StyleSheet.hairlineWidth}px;
6 | `;
7 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["react-native"],
3 | "env": {
4 | "production": {
5 | "plugins": [
6 | ["babel-plugin-cssta", { "optimizations": ["interpolateValuesOnly"] }]
7 | ]
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/css-variables-export-native/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta/native';
2 | import { View } from 'react-native';
3 |
4 | cssta(View)`
5 | --color: red;
6 |
7 | &[@blue] {
8 | --color: blue;
9 | }
10 | `;
11 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/default/expected.css:
--------------------------------------------------------------------------------
1 | /* File generated by babel-plugin-cssta */
2 |
3 | /* Start /fixtures/default/actual.js */
4 |
5 | .A {
6 | color: red
7 | }
8 |
9 | /* End /fixtures/default/actual.js */
10 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/string-attribute/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta';
2 |
3 | cssta.button`
4 | &[@stringAttribute = "1"] {
5 | color: red;
6 | }
7 |
8 | &[@stringAttribute = "2"] {
9 | color: red;
10 | }
11 | `;
12 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/compose-component/expected.js:
--------------------------------------------------------------------------------
1 | import _createComponent from 'cssta/lib/web/createComponent';
2 |
3 | import Link from 'react-router';
4 |
5 | _createComponent(Link, null, {
6 | 'defaultClassName': 'A',
7 | 'classNameMap': {}
8 | });
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/computed/expected.css:
--------------------------------------------------------------------------------
1 | /* File generated by babel-plugin-cssta */
2 |
3 | /* Start /fixtures/computed/actual.js */
4 |
5 | .A {
6 | color: red
7 | }
8 |
9 | /* End /fixtures/computed/actual.js */
10 |
--------------------------------------------------------------------------------
/packages/cssta/src/css-transforms/colors.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | const color = require('css-color-function');
3 |
4 | const colorFnRe = /color\((?:[^()]+|\([^)]+\))+\)/g;
5 |
6 | module.exports = (value /*: string */) /*: string */ => value.replace(colorFnRe, color.convert);
7 |
--------------------------------------------------------------------------------
/examples/cssta-demo/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # testing
7 | coverage
8 |
9 | # production
10 | build
11 |
12 | # misc
13 | .DS_Store
14 | npm-debug.log
15 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/compose-without-quasi/expected.js:
--------------------------------------------------------------------------------
1 | import _createComponent from 'cssta/lib/web/createComponent';
2 |
3 | import Link from 'react-router';
4 |
5 | _createComponent(Link, null, {
6 | 'defaultClassName': 'A',
7 | 'classNameMap': {}
8 | });
--------------------------------------------------------------------------------
/packages/benchmark/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "extends": "airbnb",
3 | "plugins": [
4 | "react",
5 | "jsx-a11y",
6 | "import"
7 | ],
8 | "rules": {
9 | "react/jsx-filename-extension": [0],
10 | }
11 | };
12 |
--------------------------------------------------------------------------------
/examples/cssta-demo/upgrade/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | it('renders without crashing', () => {
6 | const div = document.createElement('div');
7 | ReactDOM.render(, div);
8 | });
9 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/compose-without-template/expected.js:
--------------------------------------------------------------------------------
1 | import _createComponent from 'cssta/lib/web/createComponent';
2 |
3 | import Link from 'react-router';
4 |
5 | _createComponent(Link, null, {
6 | 'defaultClassName': 'A',
7 | 'classNameMap': {}
8 | });
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/without-template/expected.css:
--------------------------------------------------------------------------------
1 | /* File generated by babel-plugin-cssta */
2 |
3 | /* Start /fixtures/without-template/actual.js */
4 |
5 | .A {
6 | color: red
7 | }
8 | /* End /fixtures/without-template/actual.js */
9 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/.npmignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # testing
7 | coverage
8 |
9 | # production
10 | build
11 |
12 | # misc
13 | .DS_Store
14 | npm-debug.log
15 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/without-quasi/expected.css:
--------------------------------------------------------------------------------
1 | /* File generated by babel-plugin-cssta */
2 |
3 | /* Start /fixtures/without-quasi/actual.js */
4 |
5 | .A {
6 | color: red
7 | }
8 |
9 | /* End /fixtures/without-quasi/actual.js */
10 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip
6 |
--------------------------------------------------------------------------------
/examples/cssta-demo/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | parser: 'babel-eslint',
3 | extends: 'airbnb',
4 | rules: {
5 | 'no-shadow': [0],
6 | 'react/prop-types': [0],
7 | 'react/jsx-filename-extension': [0],
8 | 'jsx-a11y/label-has-for': [0],
9 | },
10 | };
11 |
--------------------------------------------------------------------------------
/examples/cssta-demo/upgrade/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # testing
7 | coverage
8 |
9 | # production
10 | build
11 |
12 | # misc
13 | .DS_Store
14 | .env
15 | npm-debug.log
16 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/compose-component/expected.css:
--------------------------------------------------------------------------------
1 | /* File generated by babel-plugin-cssta */
2 |
3 | /* Start /fixtures/compose-component/actual.js */
4 |
5 | .A {
6 | color: red
7 | }
8 |
9 | /* End /fixtures/compose-component/actual.js */
10 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/compose-without-template/expected.css:
--------------------------------------------------------------------------------
1 | /* File generated by babel-plugin-cssta */
2 |
3 | /* Start /fixtures/compose-without-template/actual.js */
4 |
5 | .A {
6 | color: red
7 | }
8 | /* End /fixtures/compose-without-template/actual.js */
9 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-transitions/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta/native';
2 | import { Animated } from 'react-native';
3 |
4 | cssta(Animated.View)`
5 | color: red;
6 | transition: color 1s linear;
7 |
8 | &[@boolAttr] {
9 | color: blue;
10 | }
11 | `;
12 |
--------------------------------------------------------------------------------
/packages/cssta/.npmignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # testing
7 | coverage
8 |
9 | # production
10 | build
11 |
12 | # misc
13 | .DS_Store
14 | npm-debug.log
15 |
16 | # babel
17 | .babelrc
18 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/boolean-attribute/expected.css:
--------------------------------------------------------------------------------
1 | /* File generated by babel-plugin-cssta */
2 |
3 | /* Start /fixtures/boolean-attribute/actual.js */
4 |
5 |
6 | .A.B {
7 | color: red;
8 | }
9 |
10 | /* End /fixtures/boolean-attribute/actual.js */
11 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/compose-without-quasi/expected.css:
--------------------------------------------------------------------------------
1 | /* File generated by babel-plugin-cssta */
2 |
3 | /* Start /fixtures/compose-without-quasi/actual.js */
4 |
5 | .A {
6 | color: red
7 | }
8 |
9 | /* End /fixtures/compose-without-quasi/actual.js */
10 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/css-variables-single-source-web/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta';
2 |
3 | cssta.div`
4 | --large: 100;
5 | --small: 50;
6 | --margin: var(--large) var(--small);
7 |
8 | width: var(--large);
9 | `;
10 |
11 | cssta.div`
12 | width: var(--small);
13 | `;
14 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "extends": "airbnb",
3 | "plugins": [
4 | "react",
5 | "jsx-a11y",
6 | "import"
7 | ],
8 | "rules": {
9 | "react/jsx-filename-extension": [0],
10 | "react/prop-types": [0]
11 | }
12 | };
13 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/boolean-attribute/expected.js:
--------------------------------------------------------------------------------
1 | import _createComponent from 'cssta/lib/web/createComponent';
2 |
3 |
4 | _createComponent('button', null, {
5 | 'defaultClassName': 'A',
6 | 'classNameMap': {
7 | 'booleanAttribute': {
8 | 'true': 'B'
9 | }
10 | }
11 | });
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/import-under-different-name/expected.css:
--------------------------------------------------------------------------------
1 | /* File generated by babel-plugin-cssta */
2 |
3 | /* Start /fixtures/import-under-different-name/actual.js */
4 |
5 | .A {
6 | color: red
7 | }
8 |
9 | /* End /fixtures/import-under-different-name/actual.js */
10 |
--------------------------------------------------------------------------------
/packages/cssta/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = [{
4 | entry: 'postcss',
5 | output: {
6 | path: path.join(__dirname, 'vendor'),
7 | filename: 'postcss.js',
8 | libraryTarget: 'commonjs2',
9 | },
10 | node: {
11 | fs: 'empty',
12 | },
13 | }];
14 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/string-attribute/expected.js:
--------------------------------------------------------------------------------
1 | import _createComponent from 'cssta/lib/web/createComponent';
2 |
3 |
4 | _createComponent('button', null, {
5 | 'defaultClassName': 'A',
6 | 'classNameMap': {
7 | 'stringAttribute': {
8 | '1': 'B',
9 | '2': 'C'
10 | }
11 | }
12 | });
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/css-variables-single-source-native-interpolated-defaults/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta/native';
2 | import { View } from 'react-native';
3 |
4 | const color = 'blue';
5 |
6 | cssta(View)`
7 | --color: red;
8 | `;
9 |
10 | cssta(View)`
11 | color: var(--color, ${color});
12 | `;
13 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-transitions-variables/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta/native';
2 | import { Animated } from 'react-native';
3 |
4 | cssta(Animated.View)`
5 | color: var(--primary);
6 | transition: color 1s linear;
7 |
8 | &[@boolAttr] {
9 | color: var(--secondary);
10 | }
11 | `;
12 |
--------------------------------------------------------------------------------
/packages/cssta/src/native/util.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | /*:: import type { VariableWithValidator } from './types' */
3 |
4 | module.exports.getAppliedRules = /*:: */ (
5 | rules /*: T[] */,
6 | ownProps /*: Object */
7 | ) /*: T[] */ =>
8 | rules.filter(rule => (rule.validate ? rule.validate(ownProps) : true));
9 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/string-attribute/expected.css:
--------------------------------------------------------------------------------
1 | /* File generated by babel-plugin-cssta */
2 |
3 | /* Start /fixtures/string-attribute/actual.js */
4 |
5 |
6 | .A.B {
7 | color: red;
8 | }
9 |
10 | .A.C {
11 | color: red;
12 | }
13 |
14 | /* End /fixtures/string-attribute/actual.js */
15 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/css-variables-single-source-web/expected.js:
--------------------------------------------------------------------------------
1 | import _createComponent from 'cssta/lib/web/createComponent';
2 |
3 |
4 | _createComponent('div', null, {
5 | 'defaultClassName': 'A',
6 | 'classNameMap': {}
7 | });
8 |
9 | _createComponent('div', null, {
10 | 'defaultClassName': 'B',
11 | 'classNameMap': {}
12 | });
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/multiple-attributes/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta';
2 |
3 | cssta.button`
4 | color: red;
5 |
6 | &[@booleanAttribute] {
7 | color: green;
8 | }
9 |
10 | &[@stringAttribute = "1"] {
11 | color: blue;
12 | }
13 |
14 | &[@stringAttribute = "2"] {
15 | color: yellow;
16 | }
17 | `;
18 |
--------------------------------------------------------------------------------
/examples/cssta-demo/config-overrides.js:
--------------------------------------------------------------------------------
1 | module.exports = (config) => {
2 | const babelLoader = config.module.loaders.find(loader => loader.loader === 'babel');
3 | babelLoader.query.plugins = [
4 | ...(babelLoader.query.plugins || []),
5 | ['babel-plugin-cssta', {
6 | output: 'build/styles.css',
7 | }],
8 | ];
9 | return config;
10 | };
11 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/css-variables-single-source-native/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta/native';
2 | import { View } from 'react-native';
3 |
4 | cssta(View)`
5 | --large: 100;
6 | --small: 50;
7 | --margin: var(--large) var(--small);
8 |
9 | width: var(--large);
10 | `;
11 |
12 | cssta(View)`
13 | width: var(--small);
14 | `;
15 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-keyframes-variables/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta/native';
2 | import { Animated } from 'react-native';
3 |
4 | cssta(Animated.View)`
5 | color: red;
6 | animation: test 1s linear;
7 |
8 | @keyframes test {
9 | start { color: rgba(0, 0, 0, 0); }
10 | end { color: var(--primary); }
11 | }
12 | `;
13 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-keyframes/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta/native';
2 | import { Animated } from 'react-native';
3 |
4 | cssta(Animated.View)`
5 | color: red;
6 | animation: test 1s linear;
7 |
8 | @keyframes test {
9 | start { opacity: 0; }
10 | 50% { opacity: 0.2; }
11 | end { opacity: 1; }
12 | }
13 | `;
14 |
--------------------------------------------------------------------------------
/packages/cssta/src/css-transforms/variables.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | const { varRegExp } = require('../util');
3 |
4 | module.exports = (
5 | value /*: string */,
6 | appliedVariables /*: { [key:string]: string } */
7 | ) /*: string */ => (
8 | value.replace(varRegExp, (m, variableName, fallback) => (
9 | appliedVariables[variableName] || fallback
10 | ))
11 | );
12 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/__tests__/index.ios.js:
--------------------------------------------------------------------------------
1 | import 'react-native';
2 | import React from 'react';
3 | import Index from '../index.ios.js';
4 |
5 | // Note: test renderer must be required after react-native.
6 | import renderer from 'react-test-renderer';
7 |
8 | it('renders correctly', () => {
9 | const tree = renderer.create(
10 |
11 | );
12 | });
13 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/__tests__/index.android.js:
--------------------------------------------------------------------------------
1 | import 'react-native';
2 | import React from 'react';
3 | import Index from '../index.android.js';
4 |
5 | // Note: test renderer must be required after react-native.
6 | import renderer from 'react-test-renderer';
7 |
8 | it('renders correctly', () => {
9 | const tree = renderer.create(
10 |
11 | );
12 | });
13 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-keyframes-without-variables/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta/native';
2 | import { Animated } from 'react-native';
3 |
4 | cssta(Animated.View)`
5 | color: var(--primary);
6 | animation: test 1s linear;
7 |
8 | @keyframes test {
9 | start { color: rgba(0, 0, 0, 0); }
10 | end { rgba: rgba(0, 0, 0, 1); }
11 | }
12 | `;
13 |
--------------------------------------------------------------------------------
/packages/cssta/flow-typed/dependency-graph.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | /*::
3 | declare class DepGraph {
4 | addNode: (node: string) => void,
5 | addDependency: (tom: string, jerry: string) => void,
6 | overallOrder: (chuckNorris: boolean) => string[]
7 | }
8 |
9 | declare module 'dependency-graph' {
10 | declare module.exports: {
11 | DepGraph: Class
12 | }
13 | }
14 | */
15 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/multiple-attributes/expected.js:
--------------------------------------------------------------------------------
1 | import _createComponent from 'cssta/lib/web/createComponent';
2 |
3 |
4 | _createComponent('button', null, {
5 | 'defaultClassName': 'A',
6 | 'classNameMap': {
7 | 'booleanAttribute': {
8 | 'true': 'B'
9 | },
10 | 'stringAttribute': {
11 | '1': 'C',
12 | '2': 'D'
13 | }
14 | }
15 | });
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/multiple-calls-in-file/expected.css:
--------------------------------------------------------------------------------
1 | /* File generated by babel-plugin-cssta */
2 |
3 | /* Start /fixtures/multiple-calls-in-file/actual.js */
4 |
5 | .A {
6 | color: red
7 | }
8 |
9 |
10 | .B {
11 | color: green
12 | }
13 |
14 |
15 | .C {
16 | color: blue
17 | }
18 |
19 | /* End /fixtures/multiple-calls-in-file/actual.js */
20 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-multiple-attributes/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta/native';
2 | import { View } from 'react-native';
3 |
4 | cssta(View)`
5 | color: red;
6 |
7 | &[@booleanAttribute] {
8 | color: green;
9 | }
10 |
11 | &[@stringAttribute = "1"] {
12 | color: blue;
13 | }
14 |
15 | &[@stringAttribute = "2"] {
16 | color: yellow;
17 | }
18 | `;
19 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/css-variables-single-source-web/expected.css:
--------------------------------------------------------------------------------
1 | /* File generated by babel-plugin-cssta */
2 |
3 | /* Start /fixtures/css-variables-single-source-web/actual.js */
4 |
5 | .A {
6 | --large: 100;
7 | --small: 50;
8 | --margin: 100 50;
9 | width: 100
10 | }
11 |
12 |
13 | .B {
14 | width: 50
15 | }
16 |
17 | /* End /fixtures/css-variables-single-source-web/actual.js */
18 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/multiple-attributes/expected.css:
--------------------------------------------------------------------------------
1 | /* File generated by babel-plugin-cssta */
2 |
3 | /* Start /fixtures/multiple-attributes/actual.js */
4 |
5 | .A {
6 | color: red;
7 | }
8 |
9 | .A.B {
10 | color: green;
11 | }
12 |
13 | .A.C {
14 | color: blue;
15 | }
16 |
17 | .A.D {
18 | color: yellow;
19 | }
20 |
21 | /* End /fixtures/multiple-attributes/actual.js */
22 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/multiple-calls-in-file/expected.js:
--------------------------------------------------------------------------------
1 | import _createComponent from 'cssta/lib/web/createComponent';
2 |
3 |
4 | _createComponent('button', null, {
5 | 'defaultClassName': 'A',
6 | 'classNameMap': {}
7 | });
8 |
9 | _createComponent('span', null, {
10 | 'defaultClassName': 'B',
11 | 'classNameMap': {}
12 | });
13 |
14 | _createComponent('div', null, {
15 | 'defaultClassName': 'C',
16 | 'classNameMap': {}
17 | });
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "scripts": {
3 | "readme": "cp ./docs/index.md ./README.md; sed -i -e 's%\\./%https://jacobp100.github.io/cssta/%g' ./README.md; sed -i -e 's/\\.md//g' ./README.md; sed -i -e 's/{% raw %}//g' ./README.md; sed -i -e 's/{% endraw %}//g' ./README.md; sed -i -e '1,5d' ./README.md; rm ./README.md-e"
4 | },
5 | "devDependencies": {
6 | "eslint-config-prettier": "^1.5.0",
7 | "lerna": "2.0.0-beta.37",
8 | "prettier": "^0.22.0"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/examples/cssta-demo/upgrade/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "upgrade",
3 | "version": "0.0.1",
4 | "private": true,
5 | "devDependencies": {
6 | "react-scripts": "0.7.0"
7 | },
8 | "dependencies": {
9 | "react": "^15.4.1",
10 | "react-dom": "^15.4.1"
11 | },
12 | "scripts": {
13 | "start": "react-scripts start",
14 | "build": "react-scripts build",
15 | "test": "react-scripts test --env=jsdom",
16 | "eject": "react-scripts eject"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/examples/cssta-demo/upgrade/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | }
16 |
17 | .App-intro {
18 | font-size: large;
19 | }
20 |
21 | @keyframes App-logo-spin {
22 | from { transform: rotate(0deg); }
23 | to { transform: rotate(360deg); }
24 | }
25 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-simple-interpolation/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta/native';
2 | import { View } from 'react-native';
3 |
4 | const color = 'red';
5 |
6 | cssta(View)`
7 | &[@attr1] {
8 | margin-top: 10px;
9 | color: ${color};
10 | }
11 |
12 | &[@attr2] {
13 | color: ${color};
14 | margin-top: 10px;
15 | }
16 |
17 | &[@attr3] {
18 | margin-top: 10px;
19 | color: ${color};
20 | margin-bottom: 10px;
21 | }
22 | `;
23 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-interpolation-no-optimisation/expected.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta/native';
2 | import { View } from 'react-native';
3 |
4 | const color = 'red';
5 |
6 | cssta(View)`
7 | &[@attr1] {
8 | margin-top: 10px;
9 | color: ${color};
10 | }
11 |
12 | &[@attr2] {
13 | color: ${color};
14 | margin-top: 10px;
15 | }
16 |
17 | &[@attr3] {
18 | margin-top: 10px;
19 | color: ${color};
20 | margin-bottom: 10px;
21 | }
22 | `;
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-interpolation-no-optimisation/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta/native';
2 | import { View } from 'react-native';
3 |
4 | const color = 'red';
5 |
6 | cssta(View)`
7 | &[@attr1] {
8 | margin-top: 10px;
9 | color: ${color};
10 | }
11 |
12 | &[@attr2] {
13 | color: ${color};
14 | margin-top: 10px;
15 | }
16 |
17 | &[@attr3] {
18 | margin-top: 10px;
19 | color: ${color};
20 | margin-bottom: 10px;
21 | }
22 | `;
23 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-shorthand-interpolation/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta/native';
2 | import { View } from 'react-native';
3 |
4 | const font = '10px "Helvetica"';
5 |
6 | cssta(View)`
7 | &[@attr1] {
8 | margin-top: 10px;
9 | font: ${font};
10 | }
11 |
12 | &[@attr2] {
13 | font: ${font};
14 | margin-top: 10px;
15 | }
16 |
17 | &[@attr3] {
18 | margin-top: 10px;
19 | font: ${font};
20 | margin-bottom: 10px;
21 | }
22 | `;
23 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-transitions-shorthand/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta/native';
2 | import { Animated } from 'react-native';
3 |
4 | cssta(Animated.View)`
5 | background-color: #e74c3c;
6 | height: 20px;
7 | margin-bottom: 20px;
8 | transform: scaleX(1) rotate(0deg);
9 | transition: background-color 0.5s linear, transform 0.75s linear;
10 |
11 | &[@active] {
12 | background-color: #1abc9c;
13 | transform: scaleX(0.5) rotate(6deg);
14 | }
15 | `;
16 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/android/app/src/main/java/com/csstanativedemo/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.csstanativedemo;
2 |
3 | import com.facebook.react.ReactActivity;
4 |
5 | public class MainActivity extends ReactActivity {
6 |
7 | /**
8 | * Returns the name of the main component registered from JavaScript.
9 | * This is used to schedule rendering of the component.
10 | */
11 | @Override
12 | protected String getMainComponentName() {
13 | return "CsstaNativeDemo";
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/src/webUtil.js:
--------------------------------------------------------------------------------
1 | const startEndMarkers = (commentMarkerBody) => {
2 | const commentStartMarker = `/* Start ${commentMarkerBody} */\n`;
3 | const commentEndMarker = `/* End ${commentMarkerBody} */\n`;
4 |
5 | return { commentStartMarker, commentEndMarker };
6 | };
7 | module.exports.startEndMarkers = startEndMarkers;
8 |
9 | module.exports.fileStartEndCommentMarkers = (state) => {
10 | const filename = state.file.opts.filename;
11 | return startEndMarkers(filename.replace(/\*/g, ''));
12 | };
13 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "extends": "airbnb-base",
3 | "installedESLint": true,
4 | "plugins": [
5 | "import"
6 | ],
7 | "rules": {
8 | "react/jsx-filename-extension": [0],
9 | "comma-dangle": ["error", {
10 | arrays: "always-multiline",
11 | objects: "always-multiline",
12 | imports: "always-multiline",
13 | exports: "always-multiline",
14 | functions: "never",
15 | }],
16 | }
17 | };
18 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/ios/CsstaNativeDemo/AppDelegate.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 |
12 | @interface AppDelegate : UIResponder
13 |
14 | @property (nonatomic, strong) UIWindow *window;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/README.md:
--------------------------------------------------------------------------------
1 | # CsstaNativeDemo
2 |
3 | Simple React-Native project using cssta. Setup:
4 |
5 | ```bash
6 | npm install --save cssta
7 | npm install --save-dev babel-plugin-cssta
8 | ```
9 |
10 | Add following to `.babelrc`:
11 |
12 | ```json
13 | {
14 | "presets": ["react-native"],
15 | "env": {
16 | "production": {
17 | "plugins": ["babel-plugin-cssta"]
18 | }
19 | }
20 | }
21 | ```
22 |
23 | That's all! You probably want to enable some [optimisations](https://jacobp100.gitbooks.io/cssta/content/production_builds.html) if you use template interpolation.
24 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-complex-interpolation/actual.js:
--------------------------------------------------------------------------------
1 | import cssta from 'cssta/native';
2 | import { View } from 'react-native';
3 |
4 | const marginSmall = 10;
5 | const marginLarge = 10;
6 |
7 | cssta(View)`
8 | &[@attr1] {
9 | padding-top: 10px;
10 | margin: ${marginLarge}px ${marginSmall}px;
11 | }
12 |
13 | &[@attr2] {
14 | margin: ${marginLarge}px ${marginSmall}px;
15 | padding-top: 10px;
16 | }
17 |
18 | &[@attr3] {
19 | padding-top: 10px;
20 | margin: ${marginLarge}px ${marginSmall}px;
21 | padding-bottom: 10px;
22 | }
23 | `;
24 |
--------------------------------------------------------------------------------
/packages/cssta/src/native/createComponent.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | /* eslint-disable no-param-reassign */
3 | const componentFactory = require('../factories/componentFactory');
4 | const { getAppliedRules } = require('./util');
5 | /*:: import type { Args } from './types' */
6 |
7 | module.exports = componentFactory((ownProps, passedProps, args /*: Args */) => {
8 | let style = getAppliedRules(args.rules, ownProps).map(rule => rule.style);
9 |
10 | if ('style' in passedProps) style = style.concat(passedProps.style);
11 | if (style.length > 0) passedProps.style = style;
12 |
13 | return passedProps;
14 | });
15 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native/expected.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet as _StyleSheet } from 'react-native';
2 | import _createComponent from 'cssta/lib/native/createComponent';
3 |
4 | import { View } from 'react-native';
5 |
6 | var _csstaStyle = _StyleSheet.create({
7 | 0: {
8 | 'color': 'red'
9 | }
10 | });
11 |
12 | _createComponent(View, [], {
13 | 'transitionedProperties': [],
14 | 'keyframes': {},
15 | 'rules': [{
16 | 'validate': function (p) {
17 | return true;
18 | },
19 | 'transitions': {},
20 | 'animation': null,
21 | 'style': _csstaStyle[0]
22 | }]
23 | });
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # Xcode
6 | #
7 | build/
8 | *.pbxuser
9 | !default.pbxuser
10 | *.mode1v3
11 | !default.mode1v3
12 | *.mode2v3
13 | !default.mode2v3
14 | *.perspectivev3
15 | !default.perspectivev3
16 | xcuserdata
17 | *.xccheckout
18 | *.moved-aside
19 | DerivedData
20 | *.hmap
21 | *.ipa
22 | *.xcuserstate
23 | project.xcworkspace
24 |
25 | # Android/IJ
26 | #
27 | *.iml
28 | .idea
29 | .gradle
30 | local.properties
31 |
32 | # node.js
33 | #
34 | node_modules/
35 | npm-debug.log
36 |
37 | # BUCK
38 | buck-out/
39 | \.buckd/
40 | android/app/libs
41 | *.keystore
42 |
--------------------------------------------------------------------------------
/examples/cssta-demo/upgrade/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import logo from './logo.svg';
3 | import './App.css';
4 |
5 | class App extends Component {
6 | render() {
7 | return (
8 |
9 |
10 |

11 |
Welcome to React
12 |
13 |
14 | To get started, edit src/App.js and save to reload.
15 |
16 |
17 | );
18 | }
19 | }
20 |
21 | export default App;
22 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/ios/CsstaNativeDemo/main.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 |
12 | #import "AppDelegate.h"
13 |
14 | int main(int argc, char * argv[]) {
15 | @autoreleasepool {
16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-color-function/expected.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet as _StyleSheet } from 'react-native';
2 | import _createComponent from 'cssta/lib/native/createComponent';
3 |
4 | import { View } from 'react-native';
5 |
6 | var _csstaStyle = _StyleSheet.create({
7 | 0: {
8 | 'color': 'rgb(255, 128, 128)'
9 | }
10 | });
11 |
12 | _createComponent(View, [], {
13 | 'transitionedProperties': [],
14 | 'keyframes': {},
15 | 'rules': [{
16 | 'validate': function (p) {
17 | return true;
18 | },
19 | 'transitions': {},
20 | 'animation': null,
21 | 'style': _csstaStyle[0]
22 | }]
23 | });
--------------------------------------------------------------------------------
/packages/cssta/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "extends": "airbnb-base",
3 | "installedESLint": true,
4 | "plugins": [
5 | "import",
6 | "flowtype"
7 | ],
8 | "rules": {
9 | "react/jsx-filename-extension": [0],
10 | "flowtype/require-valid-file-annotation": [2, "always"],
11 | "comma-dangle": ["error", {
12 | arrays: "always-multiline",
13 | objects: "always-multiline",
14 | imports: "always-multiline",
15 | exports: "always-multiline",
16 | functions: "never",
17 | }],
18 | "spaced-comment": [0],
19 | "arrow-parens": [0]
20 | }
21 | };
22 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/demos/Basic.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View, Text } from 'react-native';
3 | import cssta from 'cssta/native';
4 |
5 | const HeadingContainer = cssta(View)`
6 | margin: 10px 50px;
7 | padding: 10px 15px;
8 | border-radius: 5px;
9 | border: 1px solid #e67e22;
10 | `;
11 |
12 | const HeadingText = cssta(Text)`
13 | color: #e67e22;
14 | `;
15 |
16 | export default () => (
17 |
18 | Hello World!
19 |
20 | );
21 |
22 | export const code =
23 | ` margin: 10px 50px;
24 | padding: 10px 15px;
25 | border-radius: 5px;
26 | border: 1px solid #e67e22;`;
27 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/src/platforms/native/createArgsStatic.js:
--------------------------------------------------------------------------------
1 | const t = require('babel-types');
2 | const createKeyframes = require('./createKeyframes');
3 | const createStyleSheet = require('./createStyleSheet');
4 | const { commonArgs } = require('./createUtil');
5 |
6 | module.exports = (path, substitutionMap, args) =>
7 | t.objectExpression([
8 | ...commonArgs(args),
9 | t.objectProperty(
10 | t.stringLiteral('keyframes'),
11 | createKeyframes(path, substitutionMap, args.keyframesStyleTuples)
12 | ),
13 | t.objectProperty(
14 | t.stringLiteral('rules'),
15 | createStyleSheet(path, substitutionMap, args.ruleTuples)
16 | ),
17 | ]);
18 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/demos/ColorFunction.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View, Text } from 'react-native';
3 | import cssta from 'cssta/native';
4 |
5 | const HeadingContainer = cssta(View)`
6 | --color: red;
7 | `;
8 |
9 | const HeadingText = cssta(Text)`
10 | color: color(var(--color) tint(50%));
11 | `;
12 |
13 | const Code = cssta(Text)`
14 | font-family: "courier";
15 | background-color: #eee;
16 | color: black;
17 | `;
18 |
19 | export default () => (
20 |
21 | Text styled using CSS’s color(...) function
22 |
23 | );
24 |
25 | export const code = 'color: color(red tint(50%));';
26 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/css-variables-import-native/expected.js:
--------------------------------------------------------------------------------
1 | import _withEnhancers from 'cssta/lib/native/withEnhancers';
2 | import _VariablesStyleSheetManager from 'cssta/lib/native/enhancers/VariablesStyleSheetManager';
3 |
4 | import { View } from 'react-native';
5 |
6 | _withEnhancers([_VariablesStyleSheetManager])(View, [], {
7 | 'transitionedProperties': [],
8 | 'importedVariables': ['color'],
9 | 'keyframesStyleTuples': {},
10 | 'ruleTuples': [{
11 | 'validate': function (p) {
12 | return true;
13 | },
14 | 'exportedVariables': {},
15 | 'transitionParts': {},
16 | 'animationParts': null,
17 | 'styleTuples': [['color', 'var(--color)']]
18 | }]
19 | });
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-within-closure/expected.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet as _StyleSheet } from 'react-native';
2 | import _createComponent from 'cssta/lib/native/createComponent';
3 |
4 | import { View } from 'react-native';
5 |
6 | function test() {
7 | var _csstaStyle = _StyleSheet.create({
8 | 0: {
9 | 'color': 'red'
10 | }
11 | });
12 |
13 | const Component = _createComponent(View, [], {
14 | 'transitionedProperties': [],
15 | 'keyframes': {},
16 | 'rules': [{
17 | 'validate': function (p) {
18 | return true;
19 | },
20 | 'transitions': {},
21 | 'animation': null,
22 | 'style': _csstaStyle[0]
23 | }]
24 | });
25 | }
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/css-variables-single-source-native-interpolated-defaults/expected.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet as _StyleSheet } from 'react-native';
2 | import _createComponent from 'cssta/lib/native/createComponent';
3 |
4 | import { View } from 'react-native';
5 |
6 | const color = 'blue';
7 |
8 | View;
9 |
10 | var _csstaStyle = _StyleSheet.create({
11 | 0: {
12 | 'color': 'red'
13 | }
14 | });
15 |
16 | _createComponent(View, [], {
17 | 'transitionedProperties': [],
18 | 'keyframes': {},
19 | 'rules': [{
20 | 'validate': function (p) {
21 | return true;
22 | },
23 | 'transitions': {},
24 | 'animation': null,
25 | 'style': _csstaStyle[0]
26 | }]
27 | });
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/src/visitors/program/removeUnusedCsstaImports.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-param-reassign */
2 | const t = require('babel-types');
3 | const _ = require('lodash/fp');
4 | const { csstaModules, getImportReferences } = require('../../util');
5 |
6 |
7 | module.exports = (path) => {
8 | const unreferencedCsstaImportReferences = _.flow(
9 | _.flatMap(moduleName => getImportReferences(path, moduleName, 'default')),
10 | _.filter({ references: 0 })
11 | )(_.keys(csstaModules));
12 |
13 | _.forEach((reference) => {
14 | const importDeclaration = reference.path.findParent(t.isImportDeclaration);
15 | importDeclaration.remove();
16 | }, unreferencedCsstaImportReferences);
17 | };
18 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-simple-interpolation-suffix/expected.js:
--------------------------------------------------------------------------------
1 | import { transformRawValue as _transformRawValue } from 'cssta/lib/native/cssUtil';
2 | import _createComponent from 'cssta/lib/native/createComponent';
3 |
4 | import { View, StyleSheet } from 'react-native';
5 |
6 | var _csstaStyle = StyleSheet.create({
7 | 0: {
8 | 'borderBottomWidth': _transformRawValue(`${StyleSheet.hairlineWidth}px`)
9 | }
10 | });
11 |
12 | _createComponent(View, [], {
13 | 'transitionedProperties': [],
14 | 'keyframes': {},
15 | 'rules': [{
16 | 'validate': function (p) {
17 | return true;
18 | },
19 | 'transitions': {},
20 | 'animation': null,
21 | 'style': _csstaStyle[0]
22 | }]
23 | });
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-variables-provider/expected.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet as _StyleSheet } from 'react-native';
2 | import _createComponent from 'cssta/lib/native/createComponent';
3 | import VariablesProvider from 'cssta/lib/native/VariablesProvider';
4 |
5 | import { View } from 'react-native';
6 |
7 | var _csstaStyle = _StyleSheet.create({
8 | 0: {
9 | 'color': 'red'
10 | }
11 | });
12 |
13 | _createComponent(View, [], {
14 | 'transitionedProperties': [],
15 | 'keyframes': {},
16 | 'rules': [{
17 | 'validate': function (p) {
18 | return true;
19 | },
20 | 'transitions': {},
21 | 'animation': null,
22 | 'style': _csstaStyle[0]
23 | }]
24 | });
25 |
26 | VariablesProvider;
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/css-variables-native/expected.js:
--------------------------------------------------------------------------------
1 | import _withEnhancers from 'cssta/lib/native/withEnhancers';
2 | import _VariablesStyleSheetManager from 'cssta/lib/native/enhancers/VariablesStyleSheetManager';
3 |
4 | import { View } from 'react-native';
5 |
6 | _withEnhancers([_VariablesStyleSheetManager])(View, [], {
7 | 'transitionedProperties': [],
8 | 'importedVariables': ['color'],
9 | 'keyframesStyleTuples': {},
10 | 'ruleTuples': [{
11 | 'validate': function (p) {
12 | return true;
13 | },
14 | 'exportedVariables': {
15 | 'color': 'red'
16 | },
17 | 'transitionParts': {},
18 | 'animationParts': null,
19 | 'styleTuples': [['color', 'var(--color)']]
20 | }]
21 | });
--------------------------------------------------------------------------------
/packages/benchmark/webpack.config.js:
--------------------------------------------------------------------------------
1 | const { join } = require('path');
2 | const webpack = require('webpack');
3 |
4 | module.exports = {
5 | entry: './tests',
6 | output: {
7 | filename: 'tests-compiled.js',
8 | libraryTarget: 'commonjs',
9 | },
10 | resolve: {
11 | alias: {
12 | 'react-native': join(__dirname, '/mocks/react-native'),
13 | },
14 | },
15 | module: {
16 | rules: [
17 | { test: /\.js$/, exclude: /node_modules/, use: ['babel-loader'] },
18 | ],
19 | },
20 | plugins: [
21 | new webpack.DefinePlugin({
22 | 'process.env': {
23 | NODE_ENV: JSON.stringify('production'),
24 | },
25 | }),
26 | new webpack.optimize.UglifyJsPlugin(),
27 | ],
28 | };
29 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-shorthand/expected.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet as _StyleSheet } from 'react-native';
2 | import _createComponent from 'cssta/lib/native/createComponent';
3 |
4 | import { View } from 'react-native';
5 |
6 | var _csstaStyle = _StyleSheet.create({
7 | 0: {
8 | 'fontStyle': 'italic',
9 | 'fontWeight': 'bold',
10 | 'fontVariant': [],
11 | 'fontSize': 12,
12 | 'fontFamily': 'Helvetica',
13 | 'lineHeight': 18
14 | }
15 | });
16 |
17 | _createComponent(View, [], {
18 | 'transitionedProperties': [],
19 | 'keyframes': {},
20 | 'rules': [{
21 | 'validate': function (p) {
22 | return true;
23 | },
24 | 'transitions': {},
25 | 'animation': null,
26 | 'style': _csstaStyle[0]
27 | }]
28 | });
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/src/platforms/native/createUtil.js:
--------------------------------------------------------------------------------
1 | const t = require('babel-types');
2 | const { parse } = require('babylon');
3 | const _ = require('lodash/fp');
4 | const { getValidatorSourceForSelector } = require('cssta/src/native/selectorTransform');
5 | const { jsonObjectProperties } = require('./util');
6 |
7 |
8 | const createValidatorNodeForSelector = selector =>
9 | parse(getValidatorSourceForSelector(selector)).program.body[0].expression;
10 |
11 | module.exports.baseRuleElements = rule => [
12 | t.objectProperty(
13 | t.stringLiteral('validate'),
14 | createValidatorNodeForSelector(rule.selector)
15 | ),
16 | ];
17 |
18 | module.exports.commonArgs = _.flow(
19 | _.pick(['transitionedProperties']),
20 | jsonObjectProperties
21 | );
22 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/android/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:1.3.1'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | mavenLocal()
18 | jcenter()
19 | maven {
20 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
21 | url "$rootDir/../node_modules/react-native/android"
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/ios/CsstaNativeDemo/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
--------------------------------------------------------------------------------
/examples/cssta-demo/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | React App
8 |
9 |
10 |
11 |
12 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/src/platforms/native/createArgsVariables.js:
--------------------------------------------------------------------------------
1 | const t = require('babel-types');
2 | const { jsonToNode } = require('../../util');
3 | const createKeyframes = require('./createKeyframes');
4 | const createStyleSheet = require('./createStyleSheet');
5 | const { commonArgs } = require('./createUtil');
6 |
7 | module.exports = (path, substitutionMap, args) =>
8 | t.objectExpression([
9 | ...commonArgs(args),
10 | t.objectProperty(
11 | t.stringLiteral('importedVariables'),
12 | jsonToNode(args.importedVariables)
13 | ),
14 | t.objectProperty(
15 | t.stringLiteral('keyframesStyleTuples'),
16 | createKeyframes(path, substitutionMap, args.keyframesStyleTuples)
17 | ),
18 | t.objectProperty(
19 | t.stringLiteral('ruleTuples'),
20 | createStyleSheet(path, substitutionMap, args.ruleTuples)
21 | ),
22 | ]);
23 |
--------------------------------------------------------------------------------
/examples/cssta-demo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cssta-demo",
3 | "version": "0.0.1",
4 | "private": true,
5 | "devDependencies": {
6 | "babel-eslint": "^6.1.2",
7 | "babel-plugin-cssta": "^0.4.0",
8 | "eslint": "^3.5.0",
9 | "eslint-config-airbnb": "^11.1.0",
10 | "eslint-plugin-import": "^1.15.0",
11 | "eslint-plugin-jsx-a11y": "^2.2.2",
12 | "eslint-plugin-react": "^6.5.0",
13 | "react-app-rewired": "^0.1.0",
14 | "react-scripts": "^0.7.0"
15 | },
16 | "dependencies": {
17 | "cssnano-cli": "^1.0.5",
18 | "cssta": "^0.4.0",
19 | "react": "^15.3.2",
20 | "react-dom": "^15.3.2"
21 | },
22 | "scripts": {
23 | "start": "react-scripts start",
24 | "build": "react-app-rewired build; cssnano build/styles.css build/styles.css",
25 | "test": "react-scripts test --env=jsdom",
26 | "eject": "react-scripts eject"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/ios/CsstaNativeDemoTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/packages/cssta/src/factories/types.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | /*:: import React from 'react' */
3 |
4 | /*::
5 | export type ComponentPropTypes = { [key:string]: any } | string[]
6 |
7 | export type ComponentFactory = (
8 | component: any,
9 | propTypes: ComponentPropTypes,
10 | // Let each enhancer/createComponent typecheck themselves
11 | // since an enhancer may change the type of args
12 | args: any,
13 | enhancer: ?EnhancerConstructor
14 | ) => (props: Object) => any // a React element
15 |
16 | export type Props = {
17 | Element: any,
18 | ownProps: Object,
19 | passedProps: Object,
20 | args: T,
21 | }
22 |
23 | export type DynamicProps = Props & {
24 | children: any,// (props: Props) => any,
25 | }
26 |
27 | export type EnhancerConstructor = (endNode: any) => (props: Object) => any // a react Element
28 |
29 | export type Enhancer = Class, *>>
30 | */
31 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "CsstaNativeDemo",
3 | "version": "0.0.1",
4 | "private": true,
5 | "scripts": {
6 | "start": "node node_modules/react-native/local-cli/cli.js start",
7 | "devtools": "react-devtools",
8 | "test": "jest"
9 | },
10 | "dependencies": {
11 | "cssta": "^0.4.0",
12 | "react": "15.4.1",
13 | "react-native": "0.38.0"
14 | },
15 | "jest": {
16 | "preset": "react-native"
17 | },
18 | "devDependencies": {
19 | "babel-jest": "17.0.2",
20 | "babel-plugin-cssta": "^0.4.0",
21 | "babel-preset-react-native": "1.9.0",
22 | "eslint": "^3.16.1",
23 | "eslint-config-airbnb": "^14.1.0",
24 | "eslint-plugin-import": "^2.2.0",
25 | "eslint-plugin-jsx-a11y": "^4.0.0",
26 | "eslint-plugin-react": "^6.10.0",
27 | "jest": "17.0.3",
28 | "react-devtools": "^2.0.12",
29 | "react-test-renderer": "15.4.1"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/packages/cssta/src/native/cssUtil.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | const { default: cssToReactNative, transformRawValue } = require('css-to-react-native');
3 | const transformVariables = require('../css-transforms/variables');
4 | const transformColors = require('../css-transforms/colors');
5 | /*:: import type { StyleTuple, VariablesStore } from './types' */
6 |
7 | module.exports.transformRawValue = transformRawValue;
8 |
9 | module.exports.transformStyleTuples = (
10 | styleTuples /*: StyleTuple[] */,
11 | appliedVariables /*: VariablesStore */
12 | ) /*: Object */ => {
13 | const transformedStyleTuples = styleTuples.map(([property, value]) => {
14 | let transformedValue = value;
15 | if (appliedVariables) transformedValue = transformVariables(transformedValue, appliedVariables);
16 | transformedValue = transformColors(transformedValue);
17 | return [property, transformedValue];
18 | });
19 | return cssToReactNative(transformedStyleTuples);
20 | };
21 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/css-variables-export-native/expected.js:
--------------------------------------------------------------------------------
1 | import _withEnhancers from 'cssta/lib/native/withEnhancers';
2 | import _VariablesStyleSheetManager from 'cssta/lib/native/enhancers/VariablesStyleSheetManager';
3 |
4 | import { View } from 'react-native';
5 |
6 | _withEnhancers([_VariablesStyleSheetManager])(View, ['blue'], {
7 | 'transitionedProperties': [],
8 | 'importedVariables': [],
9 | 'keyframesStyleTuples': {},
10 | 'ruleTuples': [{
11 | 'validate': function (p) {
12 | return true;
13 | },
14 | 'exportedVariables': {
15 | 'color': 'red'
16 | },
17 | 'transitionParts': {},
18 | 'animationParts': null,
19 | 'styleTuples': []
20 | }, {
21 | 'validate': function (p) {
22 | return !!p["blue"];
23 | },
24 | 'exportedVariables': {
25 | 'color': 'blue'
26 | },
27 | 'transitionParts': {},
28 | 'animationParts': null,
29 | 'styleTuples': []
30 | }]
31 | });
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/src/visitors/importSpecifier/redirectImports.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-param-reassign */
2 | const t = require('babel-types');
3 | const _ = require('lodash/fp');
4 |
5 | const redirectImports = {
6 | 'cssta/native': {
7 | VariablesProvider: 'cssta/lib/native/VariablesProvider',
8 | },
9 | };
10 |
11 | module.exports = (path) => {
12 | const importName = path.node.imported.name;
13 | const importDeclaration = path.findParent(t.isImportDeclaration);
14 | const moduleName = importDeclaration.node.source.value;
15 | const redirect = _.get([moduleName, importName], redirectImports);
16 | if (!redirect) return;
17 | const redirectImport = t.importDeclaration([
18 | t.importDefaultSpecifier(path.node.local),
19 | ], t.stringLiteral(redirect));
20 | importDeclaration.insertBefore(redirectImport);
21 |
22 | if (importDeclaration.node.specifiers.length === 1) {
23 | importDeclaration.remove();
24 | } else {
25 | path.remove();
26 | }
27 | };
28 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 |
20 | android.useDeprecatedNdk=true
21 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-transitions/expected.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet as _StyleSheet } from 'react-native';
2 | import _withEnhancers from 'cssta/lib/native/withEnhancers';
3 | import _Transition from 'cssta/lib/native/enhancers/Transition';
4 |
5 | import { Animated } from 'react-native';
6 |
7 | var _csstaStyle = _StyleSheet.create({
8 | 0: {
9 | 'color': 'red'
10 | },
11 | 1: {
12 | 'color': 'blue'
13 | }
14 | });
15 |
16 | _withEnhancers([_Transition])(Animated.View, ['boolAttr'], {
17 | 'transitionedProperties': ['color'],
18 | 'keyframes': {},
19 | 'rules': [{
20 | 'validate': function (p) {
21 | return true;
22 | },
23 | 'transitions': {
24 | 'color': ['1s', 'linear']
25 | },
26 | 'animation': null,
27 | 'style': _csstaStyle[0]
28 | }, {
29 | 'validate': function (p) {
30 | return !!p["boolAttr"];
31 | },
32 | 'transitions': {},
33 | 'animation': null,
34 | 'style': _csstaStyle[1]
35 | }]
36 | });
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/css-variables-single-source-native/expected.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet as _StyleSheet } from 'react-native';
2 | import _createComponent from 'cssta/lib/native/createComponent';
3 |
4 | import { View } from 'react-native';
5 |
6 | var _csstaStyle = _StyleSheet.create({
7 | 0: {
8 | 'width': 100
9 | }
10 | });
11 |
12 | _createComponent(View, [], {
13 | 'transitionedProperties': [],
14 | 'keyframes': {},
15 | 'rules': [{
16 | 'validate': function (p) {
17 | return true;
18 | },
19 | 'transitions': {},
20 | 'animation': null,
21 | 'style': _csstaStyle[0]
22 | }]
23 | });
24 |
25 | var _csstaStyle2 = _StyleSheet.create({
26 | 0: {
27 | 'width': 50
28 | }
29 | });
30 |
31 | _createComponent(View, [], {
32 | 'transitionedProperties': [],
33 | 'keyframes': {},
34 | 'rules': [{
35 | 'validate': function (p) {
36 | return true;
37 | },
38 | 'transitions': {},
39 | 'animation': null,
40 | 'style': _csstaStyle2[0]
41 | }]
42 | });
--------------------------------------------------------------------------------
/packages/cssta/src/web/createComponent.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | /* eslint-disable no-param-reassign */
3 | const componentFactory = require('../factories/componentFactory');
4 | /*:: import type { Args } from './types' */
5 |
6 | const factory = componentFactory((ownProps, passedProps, args /*: Args */) => {
7 | const { defaultClassName, classNameMap } = args;
8 | const classNames = Object.keys(ownProps)
9 | .map(propName => classNameMap[propName][ownProps[propName]])
10 | .filter(Boolean); // remove undefined values
11 |
12 | if (defaultClassName) classNames.push(defaultClassName);
13 | if (passedProps.className) classNames.push(passedProps.className);
14 |
15 | const className = classNames.join(' ');
16 | if (className) passedProps.className = className;
17 |
18 | return passedProps;
19 | });
20 |
21 | // Optimisation allows not passing propTypes on prod
22 | module.exports = (component /*: any */, propTypes /*: ?Object */, args /*: Args */) =>
23 | factory(component, propTypes || Object.keys(args.classNameMap), args);
24 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-keyframes/expected.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet as _StyleSheet } from 'react-native';
2 | import _withEnhancers from 'cssta/lib/native/withEnhancers';
3 | import _Animation from 'cssta/lib/native/enhancers/Animation';
4 |
5 | import { Animated } from 'react-native';
6 |
7 | var _csstaStyle = _StyleSheet.create({
8 | 0: {
9 | 'color': 'red'
10 | }
11 | });
12 |
13 | _withEnhancers([_Animation])(Animated.View, [], {
14 | 'transitionedProperties': [],
15 | 'keyframes': {
16 | 'test': [{
17 | 'time': 0,
18 | 'styles': {
19 | 'opacity': 0
20 | }
21 | }, {
22 | 'time': 0.5,
23 | 'styles': {
24 | 'opacity': 0.2
25 | }
26 | }, {
27 | 'time': 1,
28 | 'styles': {
29 | 'opacity': 1
30 | }
31 | }]
32 | },
33 | 'rules': [{
34 | 'validate': function (p) {
35 | return true;
36 | },
37 | 'transitions': {},
38 | 'animation': ['test', '1s', 'linear'],
39 | 'style': _csstaStyle[0]
40 | }]
41 | });
--------------------------------------------------------------------------------
/docs/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 | ruby RUBY_VERSION
3 |
4 | # Hello! This is where you manage which Jekyll version is used to run.
5 | # When you want to use a different version, change it below, save the
6 | # file and run `bundle install`. Run Jekyll with `bundle exec`, like so:
7 | #
8 | # bundle exec jekyll serve
9 | #
10 | # This will help ensure the proper Jekyll version is running.
11 | # Happy Jekylling!
12 | gem "jekyll", "3.4.1"
13 |
14 | # This is the default theme for new Jekyll sites. You may change this to anything you like.
15 | gem "minima", "~> 2.0"
16 |
17 | # If you want to use GitHub Pages, remove the "gem "jekyll"" above and
18 | # uncomment the line below. To upgrade, run `bundle update github-pages`.
19 | # gem "github-pages", group: :jekyll_plugins
20 |
21 | # If you have any plugins, put them here!
22 | gem 'github-pages', group: :jekyll_plugins
23 |
24 | # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
25 | gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
26 |
27 |
--------------------------------------------------------------------------------
/packages/cssta/src/native/__mocks__/react-native.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable flowtype/require-valid-file-annotation */
2 | /* global jest */
3 | /* eslint-disable no-param-reassign */
4 |
5 | module.exports.StyleSheet = {
6 | create: body => body,
7 | flatten: styles => Object.assign({}, ...[].concat(styles)),
8 | };
9 |
10 | class Value {
11 | constructor() { this.isAnimatedValue = true; }
12 |
13 | interpolate(value) { // eslint-disable-line
14 | const nextValue = new Value();
15 | nextValue.interpolation = value;
16 | return nextValue;
17 | }
18 |
19 | setValue() { return this; }
20 | }
21 |
22 | module.exports.Animated = {
23 | timing: jest.fn().mockImplementation(() => module.exports.Animated),
24 | parallel: jest.fn().mockImplementation(() => module.exports.Animated),
25 | start: jest.fn().mockImplementation(() => module.exports.Animated),
26 | Value,
27 | };
28 |
29 | module.exports.Easing = {
30 | linear: () => {},
31 | ease: () => {},
32 | in: () => {},
33 | out: () => {},
34 | inOut: () => {},
35 | };
36 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-keyframes-without-variables/expected.js:
--------------------------------------------------------------------------------
1 | import _withEnhancers from 'cssta/lib/native/withEnhancers';
2 | import _Animation from 'cssta/lib/native/enhancers/Animation';
3 | import _VariablesStyleSheetManager from 'cssta/lib/native/enhancers/VariablesStyleSheetManager';
4 |
5 | import { Animated } from 'react-native';
6 |
7 | _withEnhancers([_VariablesStyleSheetManager, _Animation])(Animated.View, [], {
8 | 'transitionedProperties': [],
9 | 'importedVariables': ['primary'],
10 | 'keyframesStyleTuples': {
11 | 'test': [{
12 | 'time': 0,
13 | 'styles': {
14 | 'color': 'rgba(0, 0, 0, 0)'
15 | }
16 | }, {
17 | 'time': 1,
18 | 'styles': {
19 | 'rgba': 'rgba(0, 0, 0, 1)'
20 | }
21 | }]
22 | },
23 | 'ruleTuples': [{
24 | 'validate': function (p) {
25 | return true;
26 | },
27 | 'exportedVariables': {},
28 | 'transitionParts': {},
29 | 'animationParts': ['test', '1s', 'linear'],
30 | 'styleTuples': [['color', 'var(--primary)']]
31 | }]
32 | });
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/src/visitors/program/singleSourceOfVariables.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-param-reassign */
2 | const p = require('path');
3 | const singleSourceOfVariables = require('../../optimizations/singleSourceOfVariables');
4 | const { getOptimisationOpts } = require('../../util');
5 |
6 | module.exports = (path, state) => {
7 | const singleSourceVariableOpts = !state.singleSourceOfVariables
8 | ? getOptimisationOpts(state, 'singleSourceOfVariables')
9 | : null;
10 |
11 | if (singleSourceVariableOpts && !singleSourceVariableOpts.sourceFilename) {
12 | throw new Error(
13 | 'You must provide `sourceFilename` in the options for singleSourceOfVariables'
14 | );
15 | }
16 |
17 | if (singleSourceVariableOpts) {
18 | const fileContainingVariables = p.join(
19 | state.opts.cwd || process.cwd(),
20 | singleSourceVariableOpts.sourceFilename
21 | );
22 | const exportedVariables =
23 | singleSourceOfVariables(fileContainingVariables, state.file.opts);
24 | state.singleSourceOfVariables = exportedVariables;
25 | }
26 | };
27 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-keyframes-variables/expected.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet as _StyleSheet } from 'react-native';
2 | import _withEnhancers from 'cssta/lib/native/withEnhancers';
3 | import _Animation from 'cssta/lib/native/enhancers/Animation';
4 | import _VariablesStyleSheetManager from 'cssta/lib/native/enhancers/VariablesStyleSheetManager';
5 |
6 | import { Animated } from 'react-native';
7 |
8 | var _csstaStyle = _StyleSheet.create({
9 | 0: {
10 | 'color': 'red'
11 | }
12 | });
13 |
14 | _withEnhancers([_VariablesStyleSheetManager, _Animation])(Animated.View, [], {
15 | 'transitionedProperties': [],
16 | 'importedVariables': ['primary'],
17 | 'keyframesStyleTuples': {
18 | 'test': [{
19 | 'time': 0,
20 | 'styleTuples': [['color', 'rgba(0, 0, 0, 0)']]
21 | }, {
22 | 'time': 1,
23 | 'styleTuples': [['color', 'var(--primary)']]
24 | }]
25 | },
26 | 'ruleTuples': [{
27 | 'validate': function (p) {
28 | return true;
29 | },
30 | 'transitions': {},
31 | 'animation': ['test', '1s', 'linear'],
32 | 'style': _csstaStyle[0]
33 | }]
34 | });
--------------------------------------------------------------------------------
/packages/cssta/src/native/__tests__/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable flowtype/require-valid-file-annotation */
2 | /* global jest it, expect */
3 | const React = require('react');
4 | const renderer = require('react-test-renderer'); // eslint-disable-line
5 | const cssta = require('..');
6 |
7 | const runTest = (csstaFactory) => {
8 | const Element = csstaFactory();
9 |
10 | const component = renderer.create(React.createElement(Element, {})).toJSON();
11 |
12 | expect(component.props.style).toEqual([{ color: 'red' }]);
13 | expect(component.children).toEqual(null);
14 | };
15 |
16 | it('creates a component', () => runTest(() => (
17 | cssta('dummy')`
18 | color: red;
19 | `
20 | )));
21 |
22 | it('allows value interpolation', () => runTest(() => {
23 | const color = 'red';
24 | return cssta('dummy')`
25 | color: ${color};
26 | `;
27 | }));
28 |
29 | it('allows rule interpolation', () => runTest(() => {
30 | const rule = 'color: red;';
31 | return cssta('dummy')`
32 | ${rule}
33 | `;
34 | }));
35 |
36 | it('allows non-template-literals', () => runTest(() => (
37 | cssta('dummy')('color: red;')
38 | )));
39 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ##########
2 | # GITHUB #
3 | ##########
4 |
5 | # See http://help.github.com/ignore-files/ for more about ignoring files.
6 |
7 | # dependencies
8 | node_modules
9 |
10 | # testing
11 | coverage
12 |
13 | # production
14 | build
15 |
16 | # misc
17 | .DS_Store
18 | npm-debug.log
19 |
20 | ################
21 | # REACT NATIVE #
22 | ################
23 |
24 | # OSX
25 | #
26 | .DS_Store
27 |
28 | # Xcode
29 | #
30 | build/
31 | *.pbxuser
32 | !default.pbxuser
33 | *.mode1v3
34 | !default.mode1v3
35 | *.mode2v3
36 | !default.mode2v3
37 | *.perspectivev3
38 | !default.perspectivev3
39 | xcuserdata
40 | *.xccheckout
41 | *.moved-aside
42 | DerivedData
43 | *.hmap
44 | *.ipa
45 | *.xcuserstate
46 | project.xcworkspace
47 |
48 | # Android/IJ
49 | #
50 | *.iml
51 | .idea
52 | .gradle
53 | local.properties
54 |
55 | # node.js
56 | #
57 | node_modules/
58 | npm-debug.log
59 |
60 | # BUCK
61 | buck-out/
62 | \.buckd/
63 | android/app/libs
64 | *.keystore
65 |
66 | ##########
67 | # CUSTOM #
68 | ##########
69 |
70 | packages/cssta/lib
71 | packages/cssta/vendor
72 | packages/cssta/README.md
73 | packages/babel-plugin-cssta/README.md
74 | examples/cssta-demo/dist
75 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/demos/Transitions.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Animated, View, Button } from 'react-native';
3 | import cssta from 'cssta/native';
4 |
5 | const Palette = cssta(Animated.View)`
6 | background-color: #e74c3c;
7 | height: 20px;
8 | margin-bottom: 20px;
9 | transform: scaleX(1) rotate(0deg);
10 | transition: background-color 0.5s linear, transform 0.75s linear;
11 |
12 | &[@active] {
13 | background-color: #1abc9c;
14 | transform: scaleX(0.5) rotate(6deg);
15 | }
16 | `;
17 |
18 | export default class VariablesProviderDemo extends Component {
19 | constructor() {
20 | super();
21 |
22 | this.state = { active: false };
23 | this.toggleActive = () => this.setState(({ active }) => ({ active: !active }));
24 | }
25 |
26 | render() {
27 | const { active } = this.state;
28 |
29 | return (
30 |
31 |
32 |
33 |
34 | );
35 | }
36 | }
37 |
38 | export const code =
39 | `transition:
40 | background-color 0.5s linear,
41 | transform 0.75s linear;`;
42 |
--------------------------------------------------------------------------------
/packages/benchmark/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cssta-benchmark",
3 | "version": "0.7.0",
4 | "description": "",
5 | "main": "index.js",
6 | "private": true,
7 | "dependencies": {
8 | "babel-core": "^6.22.1",
9 | "babel-loader": "^6.2.10",
10 | "babel-preset-latest": "^6.22.0",
11 | "babel-preset-react": "^6.22.0",
12 | "benchmark": "^2.1.3",
13 | "console.table": "^0.8.0",
14 | "cssta": "^0.7.0",
15 | "eslint": "^3.15.0",
16 | "react": "^15.4.2",
17 | "react-test-renderer": "^15.4.2",
18 | "styled-components": "^1.4.3",
19 | "webpack": "^2.2.1"
20 | },
21 | "devDependencies": {
22 | "babel-core": "^6.22.1",
23 | "babel-loader": "^6.2.10",
24 | "babel-plugin-cssta": "^0.7.0",
25 | "babel-preset-latest": "^6.22.0",
26 | "eslint": "^3.15.0",
27 | "eslint-config-airbnb": "^14.1.0",
28 | "eslint-plugin-import": "^2.2.0",
29 | "eslint-plugin-jsx-a11y": "^4.0.0",
30 | "eslint-plugin-react": "^6.9.0",
31 | "webpack": "^2.2.1"
32 | },
33 | "scripts": {
34 | "test": "echo \"Error: no test specified\" && exit 1"
35 | },
36 | "keywords": [],
37 | "author": "",
38 | "license": "ISC"
39 | }
40 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/src/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-param-reassign */
2 | const programWeb = require('./visitors/program/web');
3 | const singleSourceOfVariables = require('./visitors/program/singleSourceOfVariables');
4 | const removeUnusedCsstaImports = require('./visitors/program/removeUnusedCsstaImports');
5 | const redirectImports = require('./visitors/importSpecifier/redirectImports');
6 | const csstaCall = require('./visitors/csstaCall');
7 |
8 |
9 | module.exports = () => ({
10 | visitor: {
11 | Program: {
12 | enter(path, state) {
13 | singleSourceOfVariables(path, state);
14 | programWeb.enter(path, state);
15 | },
16 | exit(path, state) {
17 | programWeb.exit(path, state);
18 | removeUnusedCsstaImports(path, state);
19 | },
20 | },
21 | ImportSpecifier(path, state) {
22 | redirectImports(path, state);
23 | },
24 | CallExpression(path, state) {
25 | csstaCall.CallExpression(path, state);
26 | },
27 | TaggedTemplateExpression(path, state) {
28 | csstaCall.TaggedTemplateExpression(path, state);
29 | },
30 | },
31 | });
32 |
33 | module.exports.resetGenerators = csstaCall.resetGenerators;
34 |
--------------------------------------------------------------------------------
/packages/cssta/src/native/enhancers/README.md:
--------------------------------------------------------------------------------
1 | Enhancers are similar to the enhancers in Redux middlewares: each enhances the behaviour of the final component. Each element in the enhancer chain takes props and a child, transforms the props, and clones the child using the transformed props. The final node returns a styled component, defined in createComponent.js.
2 |
3 | Most enhancers just add extra rules. For example, `Transition` and `Animation` add rules with `Animated.Values` to get CSS animations to work.
4 |
5 | We also have `VariablesStyleSheetManager`. In development, this is required, as it transforms the output of `extractRules` into something the other enhancers and `createComponent` can handle. Mainly, it takes style tuples and converts them into style objects (and then puts those through `StyleSheet.create()`). It will also transform keyframes in this manner. It's worth noting that it also handles the `color` function polyfill.
6 |
7 | On production, if variables aren't used, we can actually perform all the actions `VariablesStyleSheetManager` does in the precompilation, and then skip this enhancer on the client. The precompilation step will create a stylesheet using `StyleSheet.create()`. See `types.js` for details.
8 |
--------------------------------------------------------------------------------
/packages/cssta/src/util/index.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | /* eslint-disable no-param-reassign */
3 |
4 | const keyframesRegExp = /keyframes$/i;
5 |
6 | module.exports.shallowEqual = (tom /*: Object */, jerry /*: Object */) /*: boolean */ => {
7 | if (tom === jerry) return true;
8 |
9 | /* eslint-disable */
10 | for (const key in jerry) {
11 | if (!(key in tom)) return false;
12 | }
13 |
14 | for (const key in tom) {
15 | if (!(key in jerry) || tom[key] !== jerry[key]) return false;
16 | }
17 | /* eslint-enable */
18 |
19 | return true;
20 | };
21 |
22 | module.exports.keyframesRegExp = keyframesRegExp;
23 | module.exports.isDirectChildOfKeyframes = (node /*: Object */) /*: boolean */ =>
24 | node.parent && node.parent.type === 'atrule' && keyframesRegExp.test(node.parent.name);
25 | module.exports.varRegExp = /var\s*\(\s*--([_a-z0-9-]+)\s*(?:,\s*([^)]+))?\)/ig;
26 | module.exports.varRegExpNonGlobal = /var\s*\(\s*--([_a-z0-9-]+)\s*(?:,\s*([^)]+))?\)/i;
27 |
28 | module.exports.mapValues = (
29 | iteratee /*: (value: any) => any */,
30 | object /*: Object */
31 | ) /*: Object */ => Object.keys(object).reduce((accum, key) => {
32 | accum[key] = iteratee(object[key]);
33 | return accum;
34 | }, {});
35 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-transitions-variables/expected.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet as _StyleSheet } from 'react-native';
2 | import _withEnhancers from 'cssta/lib/native/withEnhancers';
3 | import _Transition from 'cssta/lib/native/enhancers/Transition';
4 | import _VariablesStyleSheetManager from 'cssta/lib/native/enhancers/VariablesStyleSheetManager';
5 |
6 | import { Animated } from 'react-native';
7 |
8 | var _csstaStyle = _StyleSheet.create({
9 | 0: {
10 | 'color': 'var(--secondary)'
11 | }
12 | });
13 |
14 | _withEnhancers([_VariablesStyleSheetManager, _Transition])(Animated.View, ['boolAttr'], {
15 | 'transitionedProperties': ['color'],
16 | 'importedVariables': ['primary', 'secondary'],
17 | 'keyframesStyleTuples': {},
18 | 'ruleTuples': [{
19 | 'validate': function (p) {
20 | return true;
21 | },
22 | 'exportedVariables': {},
23 | 'transitionParts': {
24 | 'color': ['1s', 'linear']
25 | },
26 | 'animationParts': null,
27 | 'styleTuples': [['color', 'var(--primary)']]
28 | }, {
29 | 'validate': function (p) {
30 | return !!p["boolAttr"];
31 | },
32 | 'transitions': {},
33 | 'animation': null,
34 | 'style': _csstaStyle[0]
35 | }]
36 | });
--------------------------------------------------------------------------------
/examples/cssta-demo/README.md:
--------------------------------------------------------------------------------
1 | # cssta-demo
2 |
3 | Uses [create-react-app](https://github.com/facebookincubator/create-react-app) with cssta. Also uses [react-app-rewired](https://github.com/timarney/react-app-rewired) to override config.
4 |
5 | Set up by first,
6 |
7 | ```bash
8 | npm install --save-dev react-app-rewired
9 | ```
10 |
11 | Then adding the following `/config-overrides.js`:
12 |
13 | ```js
14 | module.exports = (config) => {
15 | const babelLoader = config.module.loaders.find(loader => loader.loader === 'babel');
16 | babelLoader.query.plugins = [
17 | ...(babelLoader.query.plugins || []),
18 | ['babel-plugin-cssta', {
19 | output: 'build/styles.css',
20 | }],
21 | ];
22 | return config;
23 | };
24 | ```
25 |
26 | Then change your `build` script in `package.json` to use `react-app-rewired`. Leave the `start` script as-is.
27 |
28 | ```json
29 | {
30 | "scripts": {
31 | ...
32 | "build": "react-app-rewired build",
33 | ...
34 | }
35 | }
36 | ```
37 |
38 | Then add the following to `index.html`:
39 |
40 | ```html
41 |
42 | ```
43 |
44 | You should probably link up a minifier afterwards. See `package.json` for an example.
45 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
12 |
13 |
19 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-simple-interpolation/expected.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet as _StyleSheet } from 'react-native';
2 | import _createComponent from 'cssta/lib/native/createComponent';
3 |
4 | import { View } from 'react-native';
5 |
6 | const color = 'red';
7 |
8 | var _csstaStyle = _StyleSheet.create({
9 | 0: {
10 | 'marginTop': 10,
11 | 'color': String(color).trim()
12 | },
13 | 1: {
14 | 'color': String(color).trim(),
15 | 'marginTop': 10
16 | },
17 | 2: {
18 | 'marginTop': 10,
19 | 'color': String(color).trim(),
20 | 'marginBottom': 10
21 | }
22 | });
23 |
24 | _createComponent(View, ['attr1', 'attr2', 'attr3'], {
25 | 'transitionedProperties': [],
26 | 'keyframes': {},
27 | 'rules': [{
28 | 'validate': function (p) {
29 | return !!p["attr1"];
30 | },
31 | 'transitions': {},
32 | 'animation': null,
33 | 'style': _csstaStyle[0]
34 | }, {
35 | 'validate': function (p) {
36 | return !!p["attr2"];
37 | },
38 | 'transitions': {},
39 | 'animation': null,
40 | 'style': _csstaStyle[1]
41 | }, {
42 | 'validate': function (p) {
43 | return !!p["attr3"];
44 | },
45 | 'transitions': {},
46 | 'animation': null,
47 | 'style': _csstaStyle[2]
48 | }]
49 | });
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/demos/CustomAnimations.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { View, Animated, Button } from 'react-native';
3 | import cssta from 'cssta/native';
4 |
5 | const Container = cssta(View)`
6 | align-items: center;
7 | `;
8 |
9 | const Box = cssta(Animated.View)`
10 | width: 50px;
11 | height: 50px;
12 | margin: 10px 0px;
13 | background-color: #f39c12;
14 | `;
15 |
16 | export default class VariablesProviderDemo extends Component {
17 | constructor() {
18 | super();
19 |
20 | this.state = {
21 | rotation: new Animated.Value(0),
22 | };
23 |
24 | this.triggerAnimation = () => {
25 | Animated.spring(this.state.rotation, {
26 | toValue: 0,
27 | velocity: 20,
28 | tension: -3,
29 | friction: 2,
30 | }).start();
31 | };
32 | }
33 |
34 | render() {
35 | const { rotation } = this.state;
36 |
37 | const rotate = rotation.interpolate({
38 | inputRange: [-1, 1],
39 | outputRange: ['-30deg', '30deg'],
40 | });
41 |
42 | return (
43 |
44 |
45 |
46 |
47 | );
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/examples/cssta-demo/upgrade/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
16 | React App
17 |
18 |
19 |
20 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/android/app/src/main/java/com/csstanativedemo/MainApplication.java:
--------------------------------------------------------------------------------
1 | package com.csstanativedemo;
2 |
3 | import android.app.Application;
4 | import android.util.Log;
5 |
6 | import com.facebook.react.ReactApplication;
7 | import com.facebook.react.ReactInstanceManager;
8 | import com.facebook.react.ReactNativeHost;
9 | import com.facebook.react.ReactPackage;
10 | import com.facebook.react.shell.MainReactPackage;
11 | import com.facebook.soloader.SoLoader;
12 |
13 | import java.util.Arrays;
14 | import java.util.List;
15 |
16 | public class MainApplication extends Application implements ReactApplication {
17 |
18 | private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
19 | @Override
20 | protected boolean getUseDeveloperSupport() {
21 | return BuildConfig.DEBUG;
22 | }
23 |
24 | @Override
25 | protected List getPackages() {
26 | return Arrays.asList(
27 | new MainReactPackage()
28 | );
29 | }
30 | };
31 |
32 | @Override
33 | public ReactNativeHost getReactNativeHost() {
34 | return mReactNativeHost;
35 | }
36 |
37 | @Override
38 | public void onCreate() {
39 | super.onCreate();
40 | SoLoader.init(this, /* native exopackage */ false);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "babel-plugin-cssta",
3 | "version": "0.7.0",
4 | "description": "",
5 | "main": "src/index.js",
6 | "scripts": {
7 | "test": "jest",
8 | "test:watch": "jest --watch",
9 | "approve": "node ./src/index.test.js --approve",
10 | "prepublish": "cp ../../docs/index.md README.md"
11 | },
12 | "keywords": [
13 | "postcss",
14 | "modules",
15 | "css-modules",
16 | "css",
17 | "minify",
18 | "min",
19 | "class",
20 | "className",
21 | "react",
22 | "css-in-js"
23 | ],
24 | "repository": {
25 | "type": "git",
26 | "url": "https://github.com/jacobp100/cssta"
27 | },
28 | "author": "",
29 | "license": "ISC",
30 | "devDependencies": {
31 | "babel-core": "^6.18.2",
32 | "eslint": "^3.11.1",
33 | "eslint-config-airbnb-base": "^10.0.1",
34 | "eslint-plugin-import": "^1.16.0",
35 | "glob": "^7.1.1",
36 | "jest": "^17.0.3",
37 | "tempfile": "^1.1.1"
38 | },
39 | "dependencies": {
40 | "babel-traverse": "^6.19.0",
41 | "babel-types": "^6.19.0",
42 | "babylon": "^6.14.1",
43 | "css-class-generator": "^1.0.1",
44 | "css-to-react-native": "^2.0.0",
45 | "cssta": "^0.7.0",
46 | "eslint-plugin-import": "^2.2.0",
47 | "lodash": "^4.17.2",
48 | "mkdirp": "^0.5.1"
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-transitions-shorthand/expected.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet as _StyleSheet } from 'react-native';
2 | import _withEnhancers from 'cssta/lib/native/withEnhancers';
3 | import _Transition from 'cssta/lib/native/enhancers/Transition';
4 |
5 | import { Animated } from 'react-native';
6 |
7 | var _csstaStyle = _StyleSheet.create({
8 | 0: {
9 | 'backgroundColor': '#e74c3c',
10 | 'height': 20,
11 | 'marginBottom': 20,
12 | 'transform': [{
13 | 'rotate': '0deg'
14 | }, {
15 | 'scaleX': 1
16 | }]
17 | },
18 | 1: {
19 | 'backgroundColor': '#1abc9c',
20 | 'transform': [{
21 | 'rotate': '6deg'
22 | }, {
23 | 'scaleX': 0.5
24 | }]
25 | }
26 | });
27 |
28 | _withEnhancers([_Transition])(Animated.View, ['active'], {
29 | 'transitionedProperties': ['backgroundColor', 'transform'],
30 | 'keyframes': {},
31 | 'rules': [{
32 | 'validate': function (p) {
33 | return true;
34 | },
35 | 'transitions': {
36 | 'backgroundColor': ['0.5s', 'linear'],
37 | 'transform': ['0.75s', 'linear']
38 | },
39 | 'animation': null,
40 | 'style': _csstaStyle[0]
41 | }, {
42 | 'validate': function (p) {
43 | return !!p["active"];
44 | },
45 | 'transitions': {},
46 | 'animation': null,
47 | 'style': _csstaStyle[1]
48 | }]
49 | });
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-multiple-attributes/expected.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet as _StyleSheet } from 'react-native';
2 | import _createComponent from 'cssta/lib/native/createComponent';
3 |
4 | import { View } from 'react-native';
5 |
6 | var _csstaStyle = _StyleSheet.create({
7 | 0: {
8 | 'color': 'red'
9 | },
10 | 1: {
11 | 'color': 'green'
12 | },
13 | 2: {
14 | 'color': 'blue'
15 | },
16 | 3: {
17 | 'color': 'yellow'
18 | }
19 | });
20 |
21 | _createComponent(View, ['booleanAttribute', 'stringAttribute'], {
22 | 'transitionedProperties': [],
23 | 'keyframes': {},
24 | 'rules': [{
25 | 'validate': function (p) {
26 | return true;
27 | },
28 | 'transitions': {},
29 | 'animation': null,
30 | 'style': _csstaStyle[0]
31 | }, {
32 | 'validate': function (p) {
33 | return !!p["booleanAttribute"];
34 | },
35 | 'transitions': {},
36 | 'animation': null,
37 | 'style': _csstaStyle[1]
38 | }, {
39 | 'validate': function (p) {
40 | return p["stringAttribute"] === "1";
41 | },
42 | 'transitions': {},
43 | 'animation': null,
44 | 'style': _csstaStyle[2]
45 | }, {
46 | 'validate': function (p) {
47 | return p["stringAttribute"] === "2";
48 | },
49 | 'transitions': {},
50 | 'animation': null,
51 | 'style': _csstaStyle[3]
52 | }]
53 | });
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/demos/VariablesProvider.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { View, Button } from 'react-native';
3 | import cssta, { VariablesProvider } from 'cssta/native';
4 |
5 | const Palette = cssta(View)`
6 | background: var(--active-color);
7 | height: 20px;
8 | margin-bottom: 20px;
9 | `;
10 |
11 | const getRandomColor = () => {
12 | const r = Math.round(Math.random() * 255);
13 | const g = Math.round(Math.random() * 255);
14 | const b = Math.round(Math.random() * 255);
15 | return `rgb(${r}, ${g}, ${b})`;
16 | };
17 |
18 | export default class VariablesProviderDemo extends Component {
19 | constructor() {
20 | super();
21 |
22 | this.state = { activeColor: getRandomColor() };
23 | this.setColor = () => this.setState({ activeColor: getRandomColor() });
24 | }
25 |
26 | render() {
27 | const { activeColor } = this.state;
28 |
29 | return (
30 |
31 |
32 |
33 |
34 |
35 |
36 | );
37 | }
38 | }
39 |
40 | export const code =
41 | `/* React */
42 |
44 |
45 | /* CSS */
46 | background-color: var(--color);`;
47 |
--------------------------------------------------------------------------------
/packages/benchmark/index.js:
--------------------------------------------------------------------------------
1 | const Benchmark = require('benchmark');
2 | require('console.table'); // eslint-disable-line
3 | const testFunctions = require('./tests-compiled').default;
4 |
5 | // Benchmark.options.onError = e => console.error(e);
6 |
7 | const suite = new Benchmark.Suite();
8 |
9 | const tests = Object.keys(testFunctions);
10 | const contestantsSet = new Set();
11 |
12 | const getRunName = (testName, contestant) => `${testName}: ${contestant}`;
13 |
14 | tests.forEach((testName) => {
15 | Object.keys(testFunctions[testName]).forEach((contestant) => {
16 | contestantsSet.add(contestant);
17 | suite.add(getRunName(testName, contestant), testFunctions[testName][contestant]);
18 | });
19 | });
20 |
21 | const contestants = Array.from(contestantsSet);
22 |
23 | suite.on('complete', () => {
24 | const suiteResults = Array.from(suite);
25 |
26 | const header = [''].concat(contestants);
27 | const rows = tests.map(testName => (
28 | [testName].concat(contestants.map((contestant) => {
29 | const runName = getRunName(testName, contestant);
30 | const run = suiteResults.find(run => run.name === runName); // eslint-disable-line
31 | return run
32 | ? `${(run.stats.mean * 1000).toFixed(3)}±${(run.stats.deviation * 1000).toFixed(3)}ms`
33 | : '-';
34 | }))
35 | ));
36 |
37 | console.table(header, rows);
38 | });
39 |
40 | suite.run();
41 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/demos/StyleOverrides.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { View, Slider } from 'react-native';
3 | import cssta from 'cssta/native';
4 |
5 | const Palette = cssta(View)`
6 | height: 20px;
7 | margin-bottom: 20px;
8 | `;
9 |
10 | export default class VariablesProviderDemo extends Component {
11 | constructor() {
12 | super();
13 |
14 | this.state = { r: 243, g: 156, b: 18 };
15 | this.setColor = color => value => this.setState({ [color]: value });
16 | }
17 |
18 | render() {
19 | const { r, g, b } = this.state;
20 | const activeColor = `rgb(${r}, ${g}, ${b})`;
21 |
22 | return (
23 |
24 |
25 |
31 |
37 |
43 |
44 | );
45 | }
46 | }
47 |
48 | export const code = "";
49 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/src/platforms/native/createKeyframes.js:
--------------------------------------------------------------------------------
1 | const _ = require('lodash/fp');
2 | const t = require('babel-types');
3 | const { jsonToNode } = require('../../util');
4 | const createStyleBody = require('./createStyleBody');
5 | const { styleTupleHasVariable } = require('./util');
6 |
7 | const keyframeStyleTupleHasVariables = _.flow(
8 | _.get('styleTuples'),
9 | _.some(styleTupleHasVariable)
10 | );
11 |
12 | const createKeyframeStatic = _.curry((path, substitutionMap, keyframe) => (
13 | t.objectExpression([
14 | t.objectProperty(
15 | t.stringLiteral('time'),
16 | t.numericLiteral(keyframe.time)
17 | ),
18 | t.objectProperty(
19 | t.stringLiteral('styles'),
20 | createStyleBody(path, substitutionMap, keyframe.styleTuples)
21 | ),
22 | ])
23 | ));
24 |
25 | const convertKeyframeStyleTuple = _.curry((path, substitutionMap, keyframes) => (
26 | _.some(keyframeStyleTupleHasVariables, keyframes)
27 | ? jsonToNode(keyframes)
28 | : t.arrayExpression(_.map(createKeyframeStatic(path, substitutionMap), keyframes))
29 | ));
30 |
31 | module.exports = (path, substitutionMap, keyframesStyleTuples) =>
32 | t.objectExpression(
33 | _.map(([keyframeName, keyframes]) => t.objectProperty(
34 | t.stringLiteral(keyframeName),
35 | convertKeyframeStyleTuple(path, substitutionMap, keyframes)
36 | ), _.toPairs(keyframesStyleTuples))
37 | );
38 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-shorthand-interpolation/expected.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet as _StyleSheet } from 'react-native';
2 | import { transformStyleTuples as _transformStyleTuples } from 'cssta/lib/native/cssUtil';
3 | import _createComponent from 'cssta/lib/native/createComponent';
4 |
5 | import { View } from 'react-native';
6 |
7 | const font = '10px "Helvetica"';
8 |
9 | var _csstaStyle = _StyleSheet.create({
10 | 0: Object.assign({
11 | 'marginTop': 10
12 | }, _transformStyleTuples([['font', `${font}`]])),
13 | 1: Object.assign(_transformStyleTuples([['font', `${font}`]]), {
14 | 'marginTop': 10
15 | }),
16 | 2: Object.assign({
17 | 'marginTop': 10
18 | }, _transformStyleTuples([['font', `${font}`]]), {
19 | 'marginBottom': 10
20 | })
21 | });
22 |
23 | _createComponent(View, ['attr1', 'attr2', 'attr3'], {
24 | 'transitionedProperties': [],
25 | 'keyframes': {},
26 | 'rules': [{
27 | 'validate': function (p) {
28 | return !!p["attr1"];
29 | },
30 | 'transitions': {},
31 | 'animation': null,
32 | 'style': _csstaStyle[0]
33 | }, {
34 | 'validate': function (p) {
35 | return !!p["attr2"];
36 | },
37 | 'transitions': {},
38 | 'animation': null,
39 | 'style': _csstaStyle[1]
40 | }, {
41 | 'validate': function (p) {
42 | return !!p["attr3"];
43 | },
44 | 'transitions': {},
45 | 'animation': null,
46 | 'style': _csstaStyle[2]
47 | }]
48 | });
--------------------------------------------------------------------------------
/examples/cssta-demo/src/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import cssta from 'cssta';
3 |
4 | cssta.injectGlobal(`
5 | body {
6 | margin: 10em;
7 | }
8 | `);
9 |
10 | const Button = cssta.button`
11 | background: white;
12 | color: black;
13 | padding: 1rem 2rem;
14 | border-radius: 1000px;
15 |
16 | @media (max-width: 768px) {
17 | font-size: 1.5rem;
18 | }
19 |
20 | @supports (background: linear-gradient(to bottom, red, green)) {
21 | &[@christmas] {
22 | background: linear-gradient(to bottom, red, green);
23 | }
24 | }
25 |
26 | :hover {
27 | background: lightgray;
28 | }
29 |
30 | &[@color="red"] {
31 | background: red;
32 | color: white;
33 | }
34 |
35 | &[@color="red"]:hover {
36 | background: maroon;
37 | }
38 |
39 | &[@color="blue"] {
40 | background: blue;
41 | color: white;
42 | }
43 |
44 | &[@color="blue"]:hover {
45 | background: darkblue;
46 | }
47 |
48 | &[@throb] {
49 | animation: 1s throb infinite;
50 | }
51 |
52 | @keyframes throb {
53 | 0% { transform: scale(1); }
54 | 50% { transform: scale(1.1); }
55 | 100% { transform: scale(1); }
56 | }
57 | `;
58 |
59 | const App = () => (
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | );
68 |
69 | export default App;
70 |
--------------------------------------------------------------------------------
/docs/external-modules.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: page
3 | title: External Modules
4 | permalink: /external-modules
5 | ---
6 |
7 | # Ⓜ️ External Modules
8 |
9 | As a user of external Cssta modules, all you have to do is ensure these modules are run through babel using `babel-plugin-cssta`. On the web, this will add the module’s CSS in the outputted CSS file, and on native, this will mostly perform optimizations.
10 |
11 | ## Webpack
12 |
13 | To get Cssta modules working, you have to make sure that you are running all files in `node_modules` through babel. Most guides recommend you exclude `node_modules`, so make sure you haven’t copied this over.
14 |
15 | ```jsx
16 | {
17 | module: {
18 | loaders: [{
19 | test: /\.jsx?$/,
20 | loader: 'babel-loader',
21 | options: {
22 | // Your normal config, just make sure you include babel-plugin-cssta
23 | presets: ['env'],
24 | plugins: [
25 | ['babel-plugin-cssta', { output: 'dist/styles.css' }],
26 | ],
27 | },
28 | }],
29 | },
30 | }
31 | ```
32 |
33 | However, if this is causing serious performance issues, you can do two runs through babel ([example](https://gist.github.com/jacobp100/4f0b08bf485bfcdcb17741cbabf85c75)).
34 |
35 | ## 🅿️ Publishers
36 |
37 | All Cssta modules have to use the ES `import … from 'cssta'` syntax for the babel plugin to work. For users, this means ensuring your build process can handle this. For publishers, just make sure your users get this syntax!
38 |
--------------------------------------------------------------------------------
/docs/_config.yml:
--------------------------------------------------------------------------------
1 | # Welcome to Jekyll!
2 | #
3 | # This config file is meant for settings that affect your whole blog, values
4 | # which you are expected to set up once and rarely edit after that. If you find
5 | # yourself editing this file very often, consider using Jekyll's data files
6 | # feature for the data you need to update frequently.
7 | #
8 | # For technical reasons, this file is *NOT* reloaded automatically when you use
9 | # 'bundle exec jekyll serve'. If you change this file, please restart the server process.
10 |
11 | # Site settings
12 | # These are used to personalize your new site. If you look in the HTML files,
13 | # you will see them accessed via {{ site.title }}, {{ site.email }}, and so on.
14 | # You can create any custom variable you would like, and they will be accessible
15 | # in the templates via {{ site.myvariable }}.
16 | title: Cssta
17 | email: your-email@domain.com
18 | description: > # this means to ignore newlines until "baseurl:"
19 | Write an awesome description for your new site here. You can edit this
20 | line in _config.yml. It will appear in your document head meta (for
21 | Google search results) and in your feed.xml site description.
22 | baseurl: "" # the subpath of your site, e.g. /blog
23 | url: "" # the base hostname & protocol for your site, e.g. http://example.com
24 | twitter_username: jekyllrb
25 | github_username: jekyll
26 |
27 | # Build settings
28 | markdown: kramdown
29 | theme: minima
30 | exclude:
31 | - Gemfile
32 | - Gemfile.lock
33 | highlighter: rouge
34 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/fixtures/native-complex-interpolation/expected.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet as _StyleSheet } from 'react-native';
2 | import { transformStyleTuples as _transformStyleTuples } from 'cssta/lib/native/cssUtil';
3 | import _createComponent from 'cssta/lib/native/createComponent';
4 |
5 | import { View } from 'react-native';
6 |
7 | const marginSmall = 10;
8 | const marginLarge = 10;
9 |
10 | var _csstaStyle = _StyleSheet.create({
11 | 0: Object.assign({
12 | 'paddingTop': 10
13 | }, _transformStyleTuples([['margin', `${marginLarge}px ${marginSmall}px`]])),
14 | 1: Object.assign(_transformStyleTuples([['margin', `${marginLarge}px ${marginSmall}px`]]), {
15 | 'paddingTop': 10
16 | }),
17 | 2: Object.assign({
18 | 'paddingTop': 10
19 | }, _transformStyleTuples([['margin', `${marginLarge}px ${marginSmall}px`]]), {
20 | 'paddingBottom': 10
21 | })
22 | });
23 |
24 | _createComponent(View, ['attr1', 'attr2', 'attr3'], {
25 | 'transitionedProperties': [],
26 | 'keyframes': {},
27 | 'rules': [{
28 | 'validate': function (p) {
29 | return !!p["attr1"];
30 | },
31 | 'transitions': {},
32 | 'animation': null,
33 | 'style': _csstaStyle[0]
34 | }, {
35 | 'validate': function (p) {
36 | return !!p["attr2"];
37 | },
38 | 'transitions': {},
39 | 'animation': null,
40 | 'style': _csstaStyle[1]
41 | }, {
42 | 'validate': function (p) {
43 | return !!p["attr3"];
44 | },
45 | 'transitions': {},
46 | 'animation': null,
47 | 'style': _csstaStyle[2]
48 | }]
49 | });
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/ios/CsstaNativeDemo/AppDelegate.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "AppDelegate.h"
11 |
12 | #import "RCTBundleURLProvider.h"
13 | #import "RCTRootView.h"
14 |
15 | @implementation AppDelegate
16 |
17 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
18 | {
19 | NSURL *jsCodeLocation;
20 |
21 | jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];
22 |
23 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
24 | moduleName:@"CsstaNativeDemo"
25 | initialProperties:nil
26 | launchOptions:launchOptions];
27 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
28 |
29 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
30 | UIViewController *rootViewController = [UIViewController new];
31 | rootViewController.view = rootView;
32 | self.window.rootViewController = rootViewController;
33 | [self.window makeKeyAndVisible];
34 | return YES;
35 | }
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/packages/cssta/src/factories/enhancerFactory.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | const React = require('react');
3 | /*:: import type { ComponentFactory, ComponentPropTypes, Props, Enhancer } from './types' */
4 |
5 | const mergeTransformers = (enhancers, EndNode) =>
6 | enhancers.reduceRight((NextElement, CurrentElement) => (
7 | props => React.createElement(CurrentElement, props, NextElement)
8 | ), EndNode);
9 |
10 | const nextCacheNode = (node, transform) => {
11 | let value = node.get(transform);
12 |
13 | if (!value) {
14 | value = new Map();
15 | node.set(transform, value);
16 | }
17 |
18 | return value;
19 | };
20 |
21 | const LEAF = 'leaf';
22 | const mergeTransformersCached = (getTransformer, enhancers, cache) /*: any */ => {
23 | const cacheEntry = enhancers.reduce(nextCacheNode, cache);
24 |
25 | let value = cacheEntry.get(LEAF);
26 |
27 | if (!value) {
28 | value = new Map();
29 | cacheEntry.set(LEAF, value);
30 | }
31 |
32 | return value;
33 | };
34 |
35 | module.exports = (constructor /*: ComponentFactory */) => {
36 | const cache = new Map();
37 |
38 | return (enhancers /*: Enhancer[] */) => (
39 | component /*: any */,
40 | propTypes /*: ComponentPropTypes */,
41 | args /*: any */
42 | ) => constructor(component, propTypes, args, (EndNode) => {
43 | const RootNode = mergeTransformersCached(
44 | passedEnhancers => mergeTransformers(passedEnhancers, EndNode),
45 | enhancers,
46 | cache
47 | );
48 | const render = props => React.createElement(RootNode, props);
49 | return render;
50 | });
51 | };
52 |
--------------------------------------------------------------------------------
/packages/cssta/src/util/resolveVariableDependencies.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | /* eslint-disable no-param-reassign */
3 | const DepGraph = require('dependency-graph').DepGraph;
4 | const { varRegExp, varRegExpNonGlobal } = require('./index');
5 |
6 | module.exports = (
7 | definedVariables /*: { [key:string]: string } */,
8 | variablesFromScope /*: { [key:string]: string } */
9 | ) /*: { [key:string]: string } */ => {
10 | const graph = new DepGraph();
11 |
12 | const variableNames = Object.keys(definedVariables);
13 |
14 | variableNames.forEach((variableName) => {
15 | graph.addNode(variableName);
16 | });
17 |
18 | variableNames.forEach((variableName) => {
19 | const referencedVariableMatches = definedVariables[variableName].match(varRegExp);
20 | if (!referencedVariableMatches) return;
21 |
22 | const referencedVariables = referencedVariableMatches
23 | .map(match => {
24 | const matchedVariable = match.match(varRegExpNonGlobal);
25 | return matchedVariable ? matchedVariable[1] : null;
26 | })
27 | .filter(Boolean);
28 |
29 | referencedVariables.forEach((referencedVariableName) => {
30 | if (referencedVariableName in definedVariables) {
31 | graph.addDependency(variableName, referencedVariableName);
32 | }
33 | });
34 | });
35 |
36 | const appliedVariables = graph.overallOrder(false).reduce((accum, variableName) => {
37 | const value = definedVariables[variableName].replace(varRegExp, (m, reference, fallback) => (
38 | accum[reference] || variablesFromScope[reference] || fallback
39 | ));
40 | accum[variableName] = value;
41 | return accum;
42 | }, {});
43 |
44 | return appliedVariables;
45 | };
46 |
--------------------------------------------------------------------------------
/docs/theming.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: page
3 | title: Theming
4 | permalink: /theming
5 | ---
6 |
7 | # 🏳️🌈 Theming
8 |
9 | As said in the introduction, theming sholud be done by CSS custom properties. Cssta for React Native has custom property polyfills built in. On the web, you can either rely on native browser support or [a postCSS plugin](https://github.com/MadLittleMods/postcss-css-variables#differences-from-postcss-custom-properties).
10 |
11 | To define global variables, you can do the following on the web.
12 |
13 | ```jsx
14 | // Web
15 | cssta.injectGlobal`
16 | :root {
17 | --primary: red;
18 | }
19 | `
20 | ```
21 |
22 | But in React Native, you’ll have to create a wrapper View.
23 |
24 | ```jsx
25 | // Native
26 | const Root = cssta(View)`
27 | --primary: red;
28 | `
29 | ```
30 |
31 | You can then use the variables as normal.
32 |
33 | ```jsx
34 | const Button = cssta.button`
35 | color: var(--primary);
36 | border: 1px solid var(--primary);
37 | padding: 0.5rem 1rem;
38 | `
39 | ```
40 |
41 | To add dynamic styling based upon context, just redefine variables.
42 |
43 | ```jsx
44 | const LightBox = cssta.div`
45 | background-color: black;
46 | --primary: white;
47 | `
48 |
49 | const Example = (
50 |
51 |
52 |
53 | )
54 | ```
55 |
56 | And to make dynamic styling even more dynamic.
57 |
58 | ```jsx
59 | const LightBox = cssta.div`
60 | background-color: black;
61 | --primary: white;
62 |
63 | &[@inverted] {
64 | background-color: white;
65 | --primary: black;
66 | }
67 | `
68 |
69 | const Example = (
70 |
71 |
72 |
73 | )
74 | ```
75 |
--------------------------------------------------------------------------------
/docs/web.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: page
3 | title: Web
4 | permalink: /web
5 | ---
6 |
7 | # 🌍 Web
8 |
9 | Except for the limitations of selectors, CSS otherwise works as normal. This includes all `@-rules`.
10 |
11 | ```jsx
12 | const Button = cssta.button`
13 | font-size: 12pt;
14 |
15 | &:hover {
16 | font-weight: bold;
17 | }
18 |
19 | @media (max-width: 768px) {
20 | font-size: 12pt;
21 | }
22 |
23 | @supports (background: linear-gradient(to bottom, red, green)) {
24 | &[@christmas] {
25 | background: linear-gradient(to bottom, red, green);
26 | }
27 | }
28 | `
29 | ```
30 |
31 | Animations work too, and CSSTA will scope the keyframe names to avoid conflicts.
32 |
33 | ```jsx
34 | const Button = cssta.button`
35 | animation: 1s scoped-animation;
36 |
37 | @keyframes scoped-animation {
38 | 0% { opacity: 0; }
39 | }
40 | `
41 | ```
42 |
43 | ## 🌐 Globals
44 |
45 | It is common to define some base styles to tag names, such as `h1`s and `p`s. This can be done with `injectGlobal`, and supports all CSS.
46 |
47 | ```jsx
48 | cssta.injectGlobal`
49 | :root {
50 | --margin: 25pt;
51 | }
52 |
53 | body {
54 | margin: var(--margin);
55 | }
56 | `
57 | ```
58 |
59 | This can also create global animations.
60 |
61 | ```jsx
62 | cssta.injectGlobal`
63 | @keyframes fade-in {
64 | 0% { opacity: 0; }
65 | }
66 | `
67 |
68 | const Button = cssta.button`
69 | animation: 1s fade-in;
70 | `
71 | ```
72 |
73 | ## 🎚 Polyfills
74 |
75 | We don’t auto-prefix your CSS, so you’ll likely want to use [autoprefixer](https://github.com/postcss/autoprefixer). If you’re using CSS custom properties, you’ll also want to use [postcss-css-variables](https://github.com/MadLittleMods/postcss-css-variables)
76 |
--------------------------------------------------------------------------------
/docs/_layouts/page.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{ page.title }}
6 |
7 |
8 |
23 | {{ content }}
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/android/app/BUCK:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | # To learn about Buck see [Docs](https://buckbuild.com/).
4 | # To run your application with Buck:
5 | # - install Buck
6 | # - `npm start` - to start the packager
7 | # - `cd android`
8 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
9 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
10 | # - `buck install -r android/app` - compile, install and run application
11 | #
12 |
13 | lib_deps = []
14 | for jarfile in glob(['libs/*.jar']):
15 | name = 'jars__' + re.sub(r'^.*/([^/]+)\.jar$', r'\1', jarfile)
16 | lib_deps.append(':' + name)
17 | prebuilt_jar(
18 | name = name,
19 | binary_jar = jarfile,
20 | )
21 |
22 | for aarfile in glob(['libs/*.aar']):
23 | name = 'aars__' + re.sub(r'^.*/([^/]+)\.aar$', r'\1', aarfile)
24 | lib_deps.append(':' + name)
25 | android_prebuilt_aar(
26 | name = name,
27 | aar = aarfile,
28 | )
29 |
30 | android_library(
31 | name = 'all-libs',
32 | exported_deps = lib_deps
33 | )
34 |
35 | android_library(
36 | name = 'app-code',
37 | srcs = glob([
38 | 'src/main/java/**/*.java',
39 | ]),
40 | deps = [
41 | ':all-libs',
42 | ':build_config',
43 | ':res',
44 | ],
45 | )
46 |
47 | android_build_config(
48 | name = 'build_config',
49 | package = 'com.csstanativedemo',
50 | )
51 |
52 | android_resource(
53 | name = 'res',
54 | res = 'src/main/res',
55 | package = 'com.csstanativedemo',
56 | )
57 |
58 | android_binary(
59 | name = 'app',
60 | package_type = 'debug',
61 | manifest = 'src/main/AndroidManifest.xml',
62 | keystore = '//android/keystores:debug',
63 | deps = [
64 | ':app-code',
65 | ],
66 | )
67 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/demos/CSSVariables.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { View, Button, Animated } from 'react-native';
3 | import cssta from 'cssta/native';
4 |
5 | const PickerRow = cssta(View)`
6 | flex-direction: row;
7 | justify-content: space-between;
8 | margin-top: 20px;
9 | `;
10 |
11 | const DynamicContainer = cssta(View)`
12 | --color: black;
13 |
14 | &[@color="red"] { --color: #e74c3c; }
15 | &[@color="green"] { --color: #2ecc71; }
16 | &[@color="blue"] { --color: #3498db; }
17 | `;
18 |
19 | class DynamicPicker extends Component {
20 | constructor() {
21 | super();
22 | this.state = { color: 'red' };
23 | this.setColor = color => this.setState({ color });
24 | }
25 |
26 | render() {
27 | const { color } = this.state;
28 | const { children } = this.props;
29 |
30 | return (
31 |
32 | {children}
33 |
34 |
39 |
40 | );
41 | }
42 | }
43 |
44 | const DynamicText = cssta(Animated.Text)`
45 | color: var(--color);
46 | font-size: 20px;
47 |
48 | /* You can animate CSS variables */
49 | transition: color 0.1s;
50 | `;
51 |
52 | export default () => (
53 |
54 | Text dynamically styled with CSS variables!
55 |
56 | );
57 |
58 | export const code =
59 | `--primary-color: red;
60 | color: var(--primary-color);`;
61 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/src/platforms/native/util.js:
--------------------------------------------------------------------------------
1 | const t = require('babel-types');
2 | const _ = require('lodash/fp');
3 | const { jsonToNode, getSubstitutionRegExp } = require('../../util');
4 | const { varRegExp } = require('cssta/lib/util');
5 |
6 | const getTemplateValues = cooked => ({
7 | cooked,
8 | raw: JSON.stringify(cooked).slice(1, -1),
9 | });
10 | const jsonObjectProperties = _.flow(
11 | _.toPairs,
12 | _.map(([key, value]) => t.objectProperty(t.stringLiteral(key), jsonToNode(value)))
13 | );
14 |
15 | const getStringWithSubstitutedValues = (substitutionMap, value) => {
16 | /* Don't attempt to optimise `${value}`: it converts to a string and we need that */
17 | const allValues = !_.isEmpty(substitutionMap)
18 | ? _.chunk(2, value.split(getSubstitutionRegExp(substitutionMap)))
19 | : [[value]];
20 | const quasiValues = _.map(0, allValues);
21 | const expressionValues = _.dropLast(1, _.map(1, allValues));
22 |
23 | if (_.isEmpty(expressionValues)) return t.stringLiteral(quasiValues[0]);
24 |
25 | const quasis = [].concat(
26 | _.map(cooked => t.templateElement(getTemplateValues(cooked)), _.initial(quasiValues)),
27 | t.templateElement(getTemplateValues(_.last(quasiValues)), true)
28 | );
29 | const expressions = _.map(_.propertyOf(substitutionMap), expressionValues);
30 |
31 | return t.templateLiteral(quasis, expressions);
32 | };
33 |
34 | const styleHasVariable = style => style && varRegExp.test(style);
35 | const styleTupleHasVariable = styleTuple => styleHasVariable(styleTuple[1]);
36 |
37 | module.exports.getTemplateValues = getTemplateValues;
38 | module.exports.jsonObjectProperties = jsonObjectProperties;
39 | module.exports.getStringWithSubstitutedValues = getStringWithSubstitutedValues;
40 | module.exports.styleHasVariable = styleHasVariable;
41 | module.exports.styleTupleHasVariable = styleTupleHasVariable;
42 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/ios/CsstaNativeDemo/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UIViewControllerBasedStatusBarAppearance
38 |
39 | NSLocationWhenInUseUsageDescription
40 |
41 | NSAppTransportSecurity
42 |
43 |
44 | NSExceptionDomains
45 |
46 | localhost
47 |
48 | NSExceptionAllowsInsecureHTTPLoads
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/packages/cssta/src/util/__tests__/resolveVariableDependencies.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable flowtype/require-valid-file-annotation */
2 | /* global jest it, expect */
3 | const resolveVariableDependencies = require('../resolveVariableDependencies');
4 |
5 | it('should resolve a single variable', () => {
6 | const actualVariables = resolveVariableDependencies({
7 | color: 'red',
8 | }, {});
9 |
10 | expect(actualVariables).toEqual({ color: 'red' });
11 | });
12 |
13 | it('should resolve a variable refercing a higher scope', () => {
14 | const actualVariables = resolveVariableDependencies({
15 | color: 'var(--primary)',
16 | }, {
17 | primary: 'red',
18 | });
19 |
20 | expect(actualVariables).toEqual({ color: 'red' });
21 | });
22 |
23 | it('should resolve a variable refercing the current scope', () => {
24 | const actualVariables = resolveVariableDependencies({
25 | color: 'var(--primary)',
26 | primary: 'red',
27 | }, {});
28 |
29 | expect(actualVariables).toEqual({
30 | color: 'red',
31 | primary: 'red',
32 | });
33 | });
34 |
35 | it('have the current scope override higher scopes', () => {
36 | const actualVariables = resolveVariableDependencies({
37 | color: 'var(--primary)',
38 | primary: 'red',
39 | }, {
40 | primary: 'blue',
41 | });
42 |
43 | expect(actualVariables).toEqual({
44 | color: 'red',
45 | primary: 'red',
46 | });
47 | });
48 |
49 | it('should allow defaults', () => {
50 | const actualVariables = resolveVariableDependencies({
51 | color: 'var(--primary, blue)',
52 | }, {});
53 |
54 | expect(actualVariables).toEqual({
55 | color: 'blue',
56 | });
57 | });
58 |
59 | it('should not allow circular dependencies', () => {
60 | expect(() => {
61 | resolveVariableDependencies({
62 | color: 'var(--primary)',
63 | primary: 'var(--color)',
64 | }, {});
65 | }).toThrow();
66 | });
67 |
--------------------------------------------------------------------------------
/packages/cssta/src/native/index.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | const extractRules = require('./extractRules');
3 | const { createValidatorForSelector } = require('./selectorTransform');
4 | const withEnhancers = require('./withEnhancers');
5 | const VariablesProvider = require('./VariablesProvider');
6 | const VariablesStyleSheetManager = require('./enhancers/VariablesStyleSheetManager');
7 | const Transition = require('./enhancers/Transition');
8 | const Animation = require('./enhancers/Animation');
9 | /*:: import type { RawVariableArgs, VariableArgs } from './types' */
10 |
11 | const dynamicComponent = withEnhancers([VariablesStyleSheetManager, Transition, Animation]);
12 |
13 | const createValidatorsForRules = (args /*: RawVariableArgs */) /*: VariableArgs */ => {
14 | const { transitionedProperties, importedVariables, keyframesStyleTuples } = args;
15 | const ruleTuples = args.ruleTuples.map(rule => ({
16 | validate: createValidatorForSelector(rule.selector),
17 | styleTuples: rule.styleTuples,
18 | transitionParts: rule.transitionParts,
19 | animationParts: rule.animationParts,
20 | exportedVariables: rule.exportedVariables,
21 | }));
22 | return { transitionedProperties, importedVariables, keyframesStyleTuples, ruleTuples };
23 | };
24 |
25 | /* eslint-disable no-param-reassign */
26 | module.exports = (
27 | element /*: any */
28 | ) => (
29 | cssTextFragments /*: string */,
30 | ...substitutions /*: string[] */
31 | ) => {
32 | const cssText = typeof cssTextFragments === 'string'
33 | ? cssTextFragments
34 | : cssTextFragments[0] +
35 | substitutions.map((value, index) => String(value) + cssTextFragments[index + 1]).join('');
36 |
37 | const { propTypes, args: rawArgs } = extractRules(cssText);
38 | const args = createValidatorsForRules(rawArgs);
39 | return dynamicComponent(element, propTypes, args);
40 | };
41 |
42 | module.exports.VariablesProvider = VariablesProvider;
43 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/demos/CustomButton.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { TouchableWithoutFeedback, Animated } from 'react-native';
3 | import cssta from 'cssta/native';
4 |
5 |
6 | const ButtonContainer = cssta(Animated.View)`
7 | --primary: #e67e22;
8 | --foreground: var(--primary);
9 | --background: white;
10 |
11 | margin: 10px 50px;
12 | padding: 10px 15px;
13 | border-radius: 1000px;
14 | border: 1px solid var(--primary);
15 | background-color: var(--background);
16 | transition: background-color 0.2s;
17 |
18 | &[@active] {
19 | --foreground: white;
20 | --background: var(--primary);
21 | }
22 | `;
23 |
24 | const ButtonText = cssta(Animated.Text)`
25 | color: var(--foreground);
26 | text-align: center;
27 | transition: color 0.3s;
28 | `;
29 |
30 | class TouchableCustom extends Component {
31 | /*
32 | Like TouchableOpacity. Pass in a child function that returns a component. Function is invoked
33 | with a bool that determines whether the Touchable is active or not.
34 | */
35 | constructor() {
36 | super();
37 | this.state = { active: false };
38 | this.onPressIn = () => this.setState({ active: true });
39 | this.onPressOut = () => this.setState({ active: false });
40 | }
41 |
42 | render() {
43 | const { active } = this.state;
44 | const { children } = this.props;
45 |
46 | return (
47 |
51 | {children(active)}
52 |
53 | );
54 | }
55 | }
56 |
57 | const Button = ({ children }) => (
58 |
59 | {active => (
60 |
61 | {children}
62 |
63 | )}
64 |
65 | );
66 |
67 | export default () => Hello world!;
68 |
--------------------------------------------------------------------------------
/packages/cssta/src/native/types.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | /*
3 | Arrays of each word in value
4 | i.e. `transition: color 1s linear` => ['color', '1s', 'linear']
5 | transitionParts keyed by property name
6 | These might have variables
7 | */
8 |
9 | /*::
10 | export type VariablesStore = { [key:string]: string }
11 | export type StyleTuple = [string, string]
12 | export type Style = { [key:string]: any } | string
13 |
14 | export type VariableWithValidator = {
15 | validate?: (props: Object) => boolean,
16 | }
17 |
18 | export type BaseVariableArgs = {|
19 | transitionedProperties: string[],
20 | importedVariables: string[],
21 | keyframesStyleTuples: { [key:string]: (VariableKeyframeTuple | Keyframe)[] },
22 | |}
23 |
24 | export type RawVariableArgs = {|
25 | ...BaseVariableArgs,
26 | ruleTuples: RawVariableRuleTuple[],
27 | |}
28 |
29 | export type VariableArgs = {|
30 | ...BaseVariableArgs,
31 | ruleTuples: (VariableRuleTuple | Rule)[],
32 | |}
33 |
34 | export type BaseVariableRuleTuple = {|
35 | exportedVariables: VariablesStore,
36 | transitionParts: ?{ [key:string]: string[] },
37 | animationParts: ?string[],
38 | styleTuples: StyleTuple[],
39 | |}
40 |
41 | export type RawVariableRuleTuple = {|
42 | ...BaseVariableRuleTuple ,
43 | selector: string,
44 | |}
45 |
46 | export type VariableRuleTuple = {|
47 | ...BaseVariableRuleTuple,
48 | ...$Exact,
49 | |}
50 |
51 | export type VariableKeyframeTuple = {|
52 | time: number,
53 | styleTuples: StyleTuple[],
54 | |}
55 |
56 | export type Args = {|
57 | transitionedProperties: string[],
58 | keyframes: { [key:string]: Keyframe[] },
59 | rules: Rule[],
60 | |}
61 |
62 | export type Rule = {|
63 | ...$Exact,
64 | style: Style,
65 | transitions?: ?{ [key:string]: string[] },
66 | animation?: ?string[],
67 | |}
68 |
69 | export type Keyframe = {|
70 | time: number,
71 | styles: any,
72 | |}
73 | */
74 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/.flowconfig:
--------------------------------------------------------------------------------
1 | [ignore]
2 |
3 | # We fork some components by platform.
4 | .*/*[.]android.js
5 |
6 | # Ignore templates with `@flow` in header
7 | .*/local-cli/generator.*
8 |
9 | # Ignore malformed json
10 | .*/node_modules/y18n/test/.*\.json
11 |
12 | # Ignore the website subdir
13 | /website/.*
14 |
15 | # Ignore BUCK generated dirs
16 | /\.buckd/
17 |
18 | # Ignore unexpected extra @providesModule
19 | .*/node_modules/commoner/test/source/widget/share.js
20 | .*/node_modules/.*/node_modules/fbjs/.*
21 |
22 | # Ignore duplicate module providers
23 | # For RN Apps installed via npm, "Libraries" folder is inside node_modules/react-native but in the source repo it is in the root
24 | .*/Libraries/react-native/React.js
25 | .*/Libraries/react-native/ReactNative.js
26 | .*/node_modules/jest-runtime/build/__tests__/.*
27 |
28 | [include]
29 |
30 | [libs]
31 | node_modules/react-native/Libraries/react-native/react-native-interface.js
32 | node_modules/react-native/flow
33 | flow/
34 |
35 | [options]
36 | module.system=haste
37 |
38 | esproposal.class_static_fields=enable
39 | esproposal.class_instance_fields=enable
40 |
41 | experimental.strict_type_args=true
42 |
43 | munge_underscores=true
44 |
45 | module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub'
46 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
47 |
48 | suppress_type=$FlowIssue
49 | suppress_type=$FlowFixMe
50 | suppress_type=$FixMe
51 |
52 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(3[0-3]\\|[1-2][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
53 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(3[0-3]\\|1[0-9]\\|[1-2][0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
54 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
55 |
56 | unsafe.enable_getters_and_setters=true
57 |
58 | [version]
59 | ^0.33.0
60 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/src/visitors/program/web.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-param-reassign */
2 | const fs = require('fs');
3 | const p = require('path');
4 | const mkdirp = require('mkdirp');
5 | const _ = require('lodash/fp');
6 | const { fileStartEndCommentMarkers } = require('../../webUtil');
7 |
8 | const getCssFilename = state => p.resolve(
9 | state.opts.cwd || process.cwd(),
10 | _.getOr('styles.css', ['opts', 'output'], state)
11 | );
12 |
13 | const writeCssToFile = (state) => {
14 | const { currentWebCss } = state;
15 | const cssFilename = getCssFilename(state);
16 |
17 | mkdirp.sync(p.dirname(cssFilename));
18 | fs.writeFileSync(cssFilename, currentWebCss, {
19 | encoding: 'utf-8',
20 | flag: 'w+',
21 | });
22 | };
23 |
24 | const removeRange = (startIndex, endIndex, text) =>
25 | text.slice(0, startIndex) + text.slice(endIndex + 1);
26 |
27 | const removeBetween = (startToken, endToken, text) => {
28 | const startIndex = text.indexOf(startToken);
29 | const endIndex = text.lastIndexOf(endToken);
30 | return (startIndex !== -1 && endIndex !== -1)
31 | ? removeRange(startIndex, endIndex, text)
32 | : text;
33 | };
34 |
35 | let previousCss;
36 | module.exports = {
37 | enter: (path, state) => {
38 | const cssFilename = getCssFilename(state);
39 |
40 | if (!state.didRemoveCssFile) {
41 | _.attempt(() => fs.unlinkSync(cssFilename));
42 | state.didRemoveCssFile = true;
43 | }
44 |
45 | let { currentWebCss } = state;
46 |
47 | if (!currentWebCss && !state.didRemoveCssFile) {
48 | _.attempt(() => fs.readFileSync(cssFilename, 'utf-8'));
49 | }
50 |
51 | if (!currentWebCss || _.isError(currentWebCss)) {
52 | currentWebCss = '/* File generated by babel-plugin-cssta */\n';
53 | }
54 |
55 | const { commentStartMarker, commentEndMarker } = fileStartEndCommentMarkers(state);
56 | currentWebCss = removeBetween(commentStartMarker, commentEndMarker, currentWebCss);
57 |
58 | state.currentWebCss = currentWebCss;
59 | previousCss = currentWebCss;
60 | },
61 | exit: (path, state) => {
62 | if (state.currentWebCss !== previousCss) writeCssToFile(state);
63 | },
64 | };
65 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/demos/Animations.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Animated, View, Button } from 'react-native';
3 | import cssta from 'cssta/native';
4 |
5 | const Center = cssta(View)`
6 | align-items: center;
7 | `;
8 |
9 | const Row = cssta(View)`
10 | flex-direction: row;
11 | `;
12 |
13 | const Palette = cssta(Animated.View)`
14 | background-color: #e74c3c;
15 | height: 50px;
16 | width: 50px;
17 | margin-bottom: 20px;
18 |
19 | &[@animation = "fade-in"] {
20 | animation: 0.5s fade-in;
21 | }
22 |
23 | &[@animation = "slide-in"] {
24 | animation: 0.5s slide-in;
25 | }
26 |
27 | &[@animation = "zoom-in"] {
28 | animation: 0.5s zoom-in;
29 | }
30 |
31 | @keyframes fade-in {
32 | start { opacity: 0; }
33 | end { opacity: 1; }
34 | }
35 |
36 | @keyframes slide-in {
37 | 0% {
38 | opacity: 0;
39 | transform: translateX(-50px);
40 | }
41 |
42 | 80% {
43 | transform: translateX(5px);
44 | }
45 |
46 | 100% {
47 | opacity: 1;
48 | transform: translateX(0);
49 | }
50 | }
51 |
52 | @keyframes zoom-in {
53 | 0% {
54 | opacity: 0;
55 | transform: scale(0);
56 | }
57 |
58 | 80% {
59 | transform: scale(1.25);
60 | }
61 |
62 | 100% {
63 | opacity: 1;
64 | transform: scale(1);
65 | }
66 | }
67 | `;
68 |
69 | export default class VariablesProviderDemo extends Component {
70 | constructor() {
71 | super();
72 | this.state = { animation: 'fade-in' };
73 | this.setAnimation = animation => () => this.setState({ animation });
74 | }
75 |
76 | render() {
77 | const { animation } = this.state;
78 |
79 | return (
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 | );
89 | }
90 | }
91 |
92 | export const code = '@keyframes { ... }';
93 |
--------------------------------------------------------------------------------
/packages/cssta/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cssta",
3 | "version": "0.7.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "jest",
8 | "test:watch": "jest --watch",
9 | "test:coverage": "jest --coverage",
10 | "flow": "flow; test $? -eq 0 -o $? -eq 2",
11 | "lint": "eslint ./src/**/*.js",
12 | "clean": "npm run clean:lib; npm run clean:vendor",
13 | "clean:lib": "rm -rf ./lib || :;",
14 | "clean:vendor": "rm -rf ./vendor || :;",
15 | "build": "npm run clean; npm run build:lib; npm run build:vendor",
16 | "build:lib": "babel ./src --out-dir ./lib --ignore __tests__,__mocks__",
17 | "build:vendor": "webpack --config ./webpack.config.js",
18 | "prepublish": "npm run build; cp ../../docs/index.md README.md"
19 | },
20 | "keywords": [
21 | "postcss",
22 | "modules",
23 | "css-modules",
24 | "css",
25 | "minify",
26 | "min",
27 | "class",
28 | "className",
29 | "react",
30 | "css-in-js"
31 | ],
32 | "repository": {
33 | "type": "git",
34 | "url": "https://github.com/jacobp100/cssta"
35 | },
36 | "author": "",
37 | "license": "ISC",
38 | "dependencies": {
39 | "css-color-function": "^1.3.0",
40 | "css-to-react-native": "^2.0.0",
41 | "dependency-graph": "^0.5.0",
42 | "events": "^1.1.1",
43 | "fbjs": "^0.8.6",
44 | "postcss": "^5.2.6",
45 | "postcss-selector-parser": "^2.2.2",
46 | "postcss-transform-animations": "^1.0.1",
47 | "prop-types": "^15.5.10"
48 | },
49 | "devDependencies": {
50 | "babel-cli": "^6.18.0",
51 | "babel-preset-es2015": "^6.18.0",
52 | "eslint": "^3.11.1",
53 | "eslint-config-airbnb-base": "^10.0.1",
54 | "eslint-plugin-flowtype": "^2.30.3",
55 | "eslint-plugin-import": "^2.2.0",
56 | "flow-bin": "^0.42.0",
57 | "jest": "^17.0.3",
58 | "react": "^15.4.1",
59 | "react-test-renderer": "^15.4.1",
60 | "webpack": "^1.14.0"
61 | },
62 | "peerDependencies": {
63 | "react": "^15.0.0"
64 | },
65 | "jest": {
66 | "testEnvironment": "node",
67 | "collectCoverageFrom": [
68 | "src/**/*.js",
69 | "!src/index.js",
70 | "!src/web/index.js",
71 | "!src/packages/**/*.js"
72 | ]
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/src/visitors/csstaCall.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-param-reassign */
2 | const { varRegExp } = require('cssta/lib/util');
3 | const transformWeb = require('../platforms/web');
4 | const transformNative = require('../platforms/native');
5 | const {
6 | getCsstaReferences, interpolationTypes, extractCsstaCallParts,
7 | } = require('../transformUtil/extractCsstaCallParts');
8 | const { getOptimisationOpts } = require('../util');
9 |
10 | const canInterpolate = {
11 | web: false,
12 | native: true,
13 | };
14 |
15 | const transformCsstaTypes = {
16 | web: transformWeb,
17 | native: transformNative,
18 | };
19 |
20 | const transformCsstaCall = (path, state, target, stringArg) => {
21 | const csstaReferenceParts = getCsstaReferences(path, target);
22 | if (!csstaReferenceParts) return;
23 |
24 | const { callee, component, csstaType } = csstaReferenceParts;
25 |
26 | let interpolationType;
27 | const interpolateValuesOnly = Boolean(getOptimisationOpts(state, 'interpolateValuesOnly'));
28 |
29 | if (!canInterpolate[csstaType]) {
30 | interpolationType = interpolationTypes.DISALLOW;
31 | } else if (!interpolateValuesOnly) {
32 | interpolationType = interpolationTypes.IGNORE;
33 | } else {
34 | interpolationType = interpolationTypes.ALLOW;
35 | }
36 |
37 | const callParts = extractCsstaCallParts(stringArg, interpolationType);
38 | if (!callParts) return;
39 |
40 | let { cssText, substitutionMap } = callParts; // eslint-disable-line
41 |
42 | if (state.singleSourceOfVariables) {
43 | cssText = cssText.replace(varRegExp, (m, variableName, fallback) => (
44 | state.singleSourceOfVariables[variableName] || fallback
45 | ));
46 | }
47 |
48 | transformCsstaTypes[csstaType](path, state, component, cssText, substitutionMap);
49 | const binding = path.scope.getBinding(callee.name);
50 | binding.dereference();
51 | };
52 |
53 | module.exports = {
54 | CallExpression(path, state) {
55 | const { node } = path;
56 | const { callee } = node;
57 | const [arg] = node.arguments;
58 | transformCsstaCall(path, state, callee, arg);
59 | },
60 | TaggedTemplateExpression(path, state) {
61 | const { quasi, tag } = path.node;
62 | transformCsstaCall(path, state, tag, quasi);
63 | },
64 | };
65 | module.exports.resetGenerators = transformWeb.resetGenerators;
66 |
--------------------------------------------------------------------------------
/docs/editor-integration.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: page
3 | title: Editor Integration
4 | permalink: /editor-integration
5 | ---
6 |
7 | # 🖇 Editor Integration
8 |
9 | Plenty of work has been done for styled-components integration into text editors, including syntax highlighting and linting.
10 |
11 | All styled-components tools should work with Cssta: you just have call your Cssta import `styled`.
12 |
13 | ```jsx
14 | import styled from 'cssta'
15 |
16 | styled.h1`
17 | color: red;
18 | `
19 | ```
20 |
21 | ## 🖍 Syntax Highlighting
22 |
23 | The most up-to-date list of plugins can be viewed on the [styled-components page](https://github.com/styled-components/styled-components#syntax-highlighting). Below is a copy (verbatim from styled-components).
24 |
25 | 
26 |
27 | ### Atom
28 |
29 | [@gandm](https://github.com/gandm), the creator of language-babel, has added support for styled-components in Atom!
30 |
31 | To get proper syntax highlighting, all you have to do is install and use the language-babel package for your JavaScript files!
32 |
33 | ### Sublime Text
34 |
35 | There is an [open PR](https://github.com/babel/babel-sublime/pull/289) by [@garetmckinley](https://github.com/garetmckinley) to add support for styled-components to babel-sublime! (if you want the PR to land, feel free to 👍 the initial comment to let the maintainers know there's a need for this!)
36 |
37 | As soon as that PR is merged and a new version released, all you'll have to do is install and use babel-sublime to highlight your JavaScript files!
38 |
39 | ### Visual Studio Code
40 |
41 | The [vscode-styled-components](https://github.com/styled-components/vscode-styled-components) extension provides syntax highlighting inside your Javascript files. You can install it as usual from the [Marketplace](https://marketplace.visualstudio.com/items?itemName=jpoissonnier.vscode-styled-components).
42 |
43 | ### VIM
44 |
45 | The [vim-styled-components](https://github.com/fleischie/vim-styled-components) plugin gives you syntax highlighting inside your Javascript files. Install it with your usual plugin manager like [Plug](https://github.com/junegunn/vim-plug), [Vundle](https://github.com/VundleVim/Vundle.vim), [Pathogen](https://github.com/tpope/vim-pathogen), etc.
46 |
47 | Also if you're looking for an awesome javascript syntax package you can never go wrong with [YAJS.vim](https://github.com/othree/yajs.vim).
48 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/ios/CsstaNativeDemoTests/CsstaNativeDemoTests.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 | #import
12 |
13 | #import "RCTLog.h"
14 | #import "RCTRootView.h"
15 |
16 | #define TIMEOUT_SECONDS 600
17 | #define TEXT_TO_LOOK_FOR @"Welcome to React Native!"
18 |
19 | @interface CsstaNativeDemoTests : XCTestCase
20 |
21 | @end
22 |
23 | @implementation CsstaNativeDemoTests
24 |
25 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test
26 | {
27 | if (test(view)) {
28 | return YES;
29 | }
30 | for (UIView *subview in [view subviews]) {
31 | if ([self findSubviewInView:subview matching:test]) {
32 | return YES;
33 | }
34 | }
35 | return NO;
36 | }
37 |
38 | - (void)testRendersWelcomeScreen
39 | {
40 | UIViewController *vc = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
41 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
42 | BOOL foundElement = NO;
43 |
44 | __block NSString *redboxError = nil;
45 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
46 | if (level >= RCTLogLevelError) {
47 | redboxError = message;
48 | }
49 | });
50 |
51 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
52 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
53 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
54 |
55 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) {
56 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {
57 | return YES;
58 | }
59 | return NO;
60 | }];
61 | }
62 |
63 | RCTSetLogFunction(RCTDefaultLogFunction);
64 |
65 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
66 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
67 | }
68 |
69 |
70 | @end
71 |
--------------------------------------------------------------------------------
/packages/cssta/src/factories/componentFactory.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | /* eslint-disable no-param-reassign */
3 | const React = require('react');
4 | const PropTypes = require('prop-types');
5 | /*:: import type { ComponentFactory, Props, EnhancerConstructor } from './types' */
6 |
7 | const getOwnPropKeys = propTypes =>
8 | (Array.isArray(propTypes) ? propTypes : Object.keys(propTypes));
9 |
10 | const getComponentProps = (ownPropKeys, component, props) => (
11 | Object.keys(props).reduce((accum, key) => {
12 | const prop = props[key];
13 |
14 | if (key === 'component') {
15 | accum.Element = prop;
16 | } else if (ownPropKeys.indexOf(key) !== -1) {
17 | accum.ownProps[key] = prop;
18 | } else {
19 | accum.passedProps[key] = prop;
20 | }
21 |
22 | return accum;
23 | }, {
24 | Element: component,
25 | ownProps: {},
26 | passedProps: {},
27 | })
28 | );
29 |
30 | let getPropTypes;
31 | if (process.env.NODE_ENV !== 'production') {
32 | getPropTypes = (ownPropKeys, propTypes) => ownPropKeys.reduce((out, key) => {
33 | const styleMap = propTypes[key];
34 | const propType = styleMap.type;
35 |
36 | if (propType === 'oneOf') {
37 | out[key] = PropTypes.oneOf(styleMap.values);
38 | } else if (propType === 'bool') {
39 | out[key] = PropTypes.bool;
40 | }
41 |
42 | return out;
43 | }, {
44 | component: PropTypes.oneOfType([
45 | PropTypes.string,
46 | PropTypes.func,
47 | ]),
48 | });
49 | }
50 |
51 | module.exports = (
52 | transformProps /*: (ownProps: Object, passedProps: Object, args: any) => Object */
53 | ) /*: ComponentFactory */ => {
54 | const baseRender = ({ Element, ownProps, passedProps, args }) =>
55 | React.createElement(Element, transformProps(ownProps, passedProps, args));
56 |
57 | return (component, propTypes, args, enhancer) => {
58 | const render = enhancer ? enhancer(baseRender) : baseRender;
59 | const ownPropKeys = getOwnPropKeys(propTypes);
60 |
61 | const StaticComponent = (props /*: Object */) => {
62 | const { Element, ownProps, passedProps } = getComponentProps(ownPropKeys, component, props);
63 | return render({ Element, ownProps, passedProps, args });
64 | };
65 |
66 | if (process.env.NODE_ENV !== 'production' && !Array.isArray(propTypes)) {
67 | StaticComponent.propTypes = getPropTypes(ownPropKeys, propTypes);
68 | }
69 |
70 | return StaticComponent;
71 | };
72 | };
73 |
--------------------------------------------------------------------------------
/examples/cssta-demo/upgrade/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/packages/cssta/src/factories/__tests__/componentFactory.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable flowtype/require-valid-file-annotation */
2 | /* global jest it, expect */
3 | const React = require('react');
4 | const renderer = require('react-test-renderer'); // eslint-disable-line
5 | const componentFactory = require('../componentFactory');
6 |
7 |
8 | const createComponent = componentFactory((ownProps, passedProps) => passedProps);
9 |
10 | const runTest = ({
11 | type = 'button',
12 | propTypes = [],
13 | inputProps = {},
14 | inputChildren = [],
15 | validProps = [],
16 | invalidProps = [],
17 | expectedType = type,
18 | expectedProps = {},
19 | expectedChildren = null,
20 | } = {}) => {
21 | const Element = createComponent(type, propTypes);
22 |
23 | const validator = Element.propTypes;
24 | Object.keys(inputProps).forEach((prop) => {
25 | validProps.forEach((value) => {
26 | validator(inputProps, prop, value);
27 | });
28 |
29 | invalidProps.forEach((value) => {
30 | expect(() => validator(inputProps, prop, value)).toThrow();
31 | });
32 | });
33 |
34 | const component =
35 | renderer.create(React.createElement(Element, inputProps, ...inputChildren)).toJSON();
36 |
37 | expect(component.type).toEqual(expectedType);
38 | expect(component.props).toEqual(expectedProps);
39 | expect(component.children).toEqual(expectedChildren);
40 | };
41 |
42 | it('allows constructing with another component', () => runTest({
43 | type: 'span',
44 | }));
45 |
46 | it('allows overriding the component', () => runTest({
47 | inputProps: { component: 'span' },
48 | expectedType: 'span',
49 | expectedProps: {},
50 | }));
51 |
52 | it('adds boolean propTypes', () => runTest({
53 | propTypes: {
54 | booleanAttribute: { type: 'bool' },
55 | },
56 | validProps: [
57 | { booleanAttribute: true },
58 | { booleanAttribute: false },
59 | ],
60 | invalidProps: [
61 | { booleanAttribute: 5 },
62 | { booleanAttribute: 'string' },
63 | { booleanAttribute: () => {} },
64 | ],
65 | }));
66 |
67 | it('adds string propTypes', () => runTest({
68 | propTypes: {
69 | booleanAttribute: {
70 | type: 'oneOf',
71 | values: ['value1', 'value2'],
72 | },
73 | },
74 | validProps: [
75 | { stringAttribute: 'value1' },
76 | { stringAttribute: 'value2' },
77 | ],
78 | invalidProps: [
79 | { stringAttribute: true },
80 | { stringAttribute: false },
81 | { stringAttribute: 5 },
82 | { stringAttribute: 'other string' },
83 | { stringAttribute: () => {} },
84 | ],
85 | }));
86 |
87 | it('allows children', () => runTest({
88 | inputChildren: ['text'],
89 | expectedChildren: ['text'],
90 | }));
91 |
--------------------------------------------------------------------------------
/packages/cssta/src/native/enhancers/animationUtil.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | /* eslint-disable */
3 | // $FlowFixMe
4 | const { StyleSheet, Easing } = require('react-native');
5 | /* eslint-enable */
6 | const { getAppliedRules } = require('../util');
7 | /*:: import type { Args } from '../types' */
8 |
9 | module.exports.mergeStyles = (props /*: { ownProps: Object, args: Args } */) =>
10 | StyleSheet.flatten(getAppliedRules(props.args.rules, props.ownProps).map(rule => rule.style));
11 |
12 | /*::
13 | export type Interpolation = number | string | [{ [key:string]: Interpolation }]
14 | export type OutputRange = Interpolation[]
15 | export type InterpolatedValue = Object | Object[]
16 | */
17 |
18 | module.exports.interpolateValue = (
19 | inputRange /*: number[] */,
20 | outputRange /*: OutputRange */,
21 | animation /*: any */,
22 | interpolateNumbers /*: boolean */ = false
23 | ) /*: InterpolatedValue */ => {
24 | const firstValue = outputRange[0];
25 | if (interpolateNumbers && typeof firstValue === 'number') {
26 | return animation;
27 | } else if (!Array.isArray(firstValue)) {
28 | return animation.interpolate({ inputRange, outputRange });
29 | }
30 |
31 | // transforms
32 | if (process.env.NODE_ENV !== 'production') {
33 | const currentProperties = String(firstValue.map(Object.keys));
34 | // Not the *best* practise here...
35 | const transformsAreConsistent = outputRange.every((range) => {
36 | // $FlowFixMe
37 | const rangeProperties = String(range.map(Object.keys));
38 | return currentProperties === rangeProperties;
39 | });
40 |
41 | if (!transformsAreConsistent) {
42 | throw new Error('Expected transforms to have same shape between transitions');
43 | }
44 | }
45 |
46 | return firstValue.map((transform, index) => {
47 | const property = Object.keys(transform)[0];
48 | // $FlowFixMe
49 | const innerOutputRange = outputRange.map(range => range[index][property]);
50 |
51 | // We *have* to interpolate even numeric values, as we will always animate between 0--1
52 | const interpolation = animation.interpolate({ inputRange, outputRange: innerOutputRange });
53 |
54 | return { [property]: interpolation };
55 | });
56 | };
57 |
58 | module.exports.getDurationInMs = (duration /*: string */) /*: number */ => {
59 | const time = parseFloat(duration);
60 | const factor = /ms$/i.test(duration) ? 1 : 1000;
61 | return time * factor;
62 | };
63 |
64 | module.exports.easingFunctions = {
65 | linear: Easing.linear,
66 | ease: Easing.ease,
67 | 'ease-in': Easing.in,
68 | 'ease-out': Easing.out,
69 | 'ease-in-out': Easing.inOut,
70 | };
71 |
72 | module.exports.durationRegExp = /^\d/;
73 |
74 | module.exports.easingRegExp = /(linear|ease(?:-in)?(?:-out)+)/i;
75 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Disabling obfuscation is useful if you collect stack traces from production crashes
20 | # (unless you are using a system that supports de-obfuscate the stack traces).
21 | -dontobfuscate
22 |
23 | # React Native
24 |
25 | # Keep our interfaces so they can be used by other ProGuard rules.
26 | # See http://sourceforge.net/p/proguard/bugs/466/
27 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip
28 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters
29 | -keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip
30 |
31 | # Do not strip any method/class that is annotated with @DoNotStrip
32 | -keep @com.facebook.proguard.annotations.DoNotStrip class *
33 | -keep @com.facebook.common.internal.DoNotStrip class *
34 | -keepclassmembers class * {
35 | @com.facebook.proguard.annotations.DoNotStrip *;
36 | @com.facebook.common.internal.DoNotStrip *;
37 | }
38 |
39 | -keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * {
40 | void set*(***);
41 | *** get*();
42 | }
43 |
44 | -keep class * extends com.facebook.react.bridge.JavaScriptModule { *; }
45 | -keep class * extends com.facebook.react.bridge.NativeModule { *; }
46 | -keepclassmembers,includedescriptorclasses class * { native ; }
47 | -keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; }
48 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp ; }
49 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup ; }
50 |
51 | -dontwarn com.facebook.react.**
52 |
53 | # okhttp
54 |
55 | -keepattributes Signature
56 | -keepattributes *Annotation*
57 | -keep class okhttp3.** { *; }
58 | -keep interface okhttp3.** { *; }
59 | -dontwarn okhttp3.**
60 |
61 | # okio
62 |
63 | -keep class sun.misc.Unsafe { *; }
64 | -dontwarn java.nio.file.*
65 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
66 | -dontwarn okio.**
67 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/packages/cssta/src/web/extractRules.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | /* eslint-disable no-param-reassign */
3 | const selectorParser = require('postcss-selector-parser');
4 | const { transformAnimationNames } = require('postcss-transform-animations');
5 | const getRoot = require('../util/getRoot');
6 | const { isDirectChildOfKeyframes } = require('../util');
7 | /*:: import type { Args } from './types' */
8 |
9 | /*::
10 | type Generators = {
11 | generateClassName: () => string,
12 | generateAnimationName: () => string,
13 | }
14 | */
15 |
16 | module.exports = (
17 | inputCss /*: string */,
18 | { generateClassName, generateAnimationName } /*: Generators */
19 | ) /*: { css: string, propTypes: Object, args: Args } */ => {
20 | const classNameMap = {}; // { propName: { propValue: className } }
21 | const animationNameMap = {};
22 |
23 | let defaultClassName = null;
24 | const getDefaultClassName = () => {
25 | if (defaultClassName === null) defaultClassName = generateClassName();
26 | return defaultClassName;
27 | };
28 |
29 | const getClassNameFor = (attribute, value) => {
30 | if (!classNameMap[attribute]) {
31 | classNameMap[attribute] = {};
32 | }
33 |
34 | if (!classNameMap[attribute][value]) {
35 | classNameMap[attribute][value] = generateClassName();
36 | }
37 |
38 | return classNameMap[attribute][value];
39 | };
40 |
41 | const transformSelectors = selectorParser((container) => {
42 | container.each((selector) => {
43 | container.walkNesting((node) => {
44 | const className = getDefaultClassName();
45 | const replacementNode = selectorParser.className({ value: className });
46 | node.replaceWith(replacementNode);
47 | });
48 |
49 | selector.walkAttributes((node) => {
50 | const attribute = node.attribute.trim();
51 | if (attribute[0] !== '*') return;
52 | const prop = attribute.slice(1);
53 | const value = node.value ? node.raws.unquoted : 'true';
54 | const className = getClassNameFor(prop, value);
55 | const replacementNode = selectorParser.className({ value: className });
56 | node.replaceWith(replacementNode);
57 | });
58 | });
59 | });
60 |
61 | const { root, propTypes } = getRoot(inputCss, true);
62 |
63 | root.walkRules((node) => {
64 | if (!isDirectChildOfKeyframes(node)) {
65 | node.selector = transformSelectors.process(node.selector).result;
66 | }
67 | });
68 |
69 | transformAnimationNames({
70 | transform: (value) => {
71 | if (value in animationNameMap) return animationNameMap[value];
72 |
73 | const transformValue = generateAnimationName();
74 | animationNameMap[value] = transformValue;
75 | return transformValue;
76 | },
77 | }, root);
78 |
79 | const css = root.toString();
80 | const args = { defaultClassName, classNameMap };
81 |
82 | return { css, propTypes, args };
83 | };
84 |
--------------------------------------------------------------------------------
/examples/CsstaNativeDemo/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View, Text, ScrollView, StyleSheet } from 'react-native';
3 | import cssta from 'cssta/native';
4 | import Basic, { code as basicCode } from './demos/Basic';
5 | import Animations, { code as animationsCode } from './demos/Animations';
6 | import Transitions, { code as transitionsCode } from './demos/Transitions';
7 | import CSSVariables, { code as cssVariablesCode } from './demos/CSSVariables';
8 | import VariablesProvider, { code as variablesProviderCode } from './demos/VariablesProvider';
9 | import StyleOverrides, { code as styleOverridesCode } from './demos/StyleOverrides';
10 | import CustomAnimations from './demos/CustomAnimations';
11 | import ColorFunction, { code as colorFunctionCode } from './demos/ColorFunction';
12 | import CustomButton from './demos/CustomButton';
13 |
14 | const App = cssta(ScrollView)`
15 | padding: 20px 0px;
16 | background: #ecf0f1;
17 | `;
18 |
19 | const DemoContainer = cssta(View)`
20 | margin: 10px 0px;
21 | `;
22 |
23 | const DemoTitle = cssta(Text)`
24 | padding: 5px 20px;
25 | color: #7f8c8d;
26 | `;
27 |
28 | const DemoBody = cssta(View)`
29 | padding: 20px;
30 | background-color: white;
31 | border-color: #bdc3c7;
32 | border-top-width: ${StyleSheet.hairlineWidth}px;
33 |
34 | &[@noCode] {
35 | border-bottom-width: ${StyleSheet.hairlineWidth}px;
36 | }
37 | `;
38 |
39 | const CodeContainer = cssta(View)`
40 | background-color: #7f8c8d;
41 | padding: 5px 20px;
42 | `;
43 |
44 | const CodeBody = cssta(Text)`
45 | font: 8px "courier";
46 | color: #ecf0f1;
47 | `;
48 |
49 | const Demo = ({ title, children, code }) => (
50 |
51 |
52 | {title}
53 |
54 |
55 | {children}
56 |
57 | {code &&
58 | {code}
59 | }
60 |
61 | );
62 |
63 | export default () => (
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 | );
94 |
--------------------------------------------------------------------------------
/packages/cssta/src/web/__tests__/createComponent.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable flowtype/require-valid-file-annotation */
2 | /* global jest it, expect */
3 | const React = require('react');
4 | const renderer = require('react-test-renderer'); // eslint-disable-line
5 | const createComponent = require('../createComponent');
6 |
7 |
8 | const runTest = ({
9 | type = 'button',
10 | defaultClassName = null,
11 | classNameMap = [],
12 | propTypes = Object.keys(classNameMap),
13 | inputProps = {},
14 | expectedType = type,
15 | expectedProps = {},
16 | expectedChildren = null,
17 | } = {}) => {
18 | const Element = createComponent(type, propTypes, { defaultClassName, classNameMap });
19 |
20 | const component = renderer.create(React.createElement(Element, inputProps)).toJSON();
21 |
22 | expect(component.type).toEqual(expectedType);
23 | expect(component.props).toEqual(expectedProps);
24 | expect(component.children).toEqual(expectedChildren);
25 | };
26 |
27 | it('renders an element', () => runTest());
28 |
29 | it('adds a default class', () => runTest({
30 | defaultClassName: 'default',
31 | expectedProps: { className: 'default' },
32 | }));
33 |
34 | it('adds adds a boolean property', () => runTest({
35 | classNameMap: { booleanAttribute: { true: 'class' } },
36 | inputProps: { booleanAttribute: true },
37 | expectedProps: { className: 'class' },
38 | }));
39 |
40 | it('does not add boolean properties if they are not passed', () => runTest({
41 | classNameMap: { booleanAttribute: { true: 'class' } },
42 | inputProps: {},
43 | }));
44 |
45 | it('adds adds a string property', () => runTest({
46 | classNameMap: { stringAttribute: { value: 'class' } },
47 | inputProps: { stringAttribute: 'value' },
48 | expectedProps: { className: 'class' },
49 | }));
50 |
51 | it('does not add string properties if they are not passed', () => runTest({
52 | classNameMap: { stringAttribute: { value: 'class' } },
53 | inputProps: {},
54 | }));
55 |
56 | it('passes extraneous props down', () => runTest({
57 | classNameMap: { booleanAttribute: { true: 'class' } },
58 | inputProps: { type: 'button', booleanAttribute: true },
59 | expectedProps: { type: 'button', className: 'class' },
60 | }));
61 |
62 | it('allows setting className', () => runTest({
63 | inputProps: { className: 'test' },
64 | expectedProps: { className: 'test' },
65 | }));
66 |
67 | it('allows extending className with default class name', () => runTest({
68 | defaultClassName: 'default',
69 | inputProps: { className: 'test' },
70 | expectedProps: { className: 'default test' },
71 | }));
72 |
73 | it('allows extending className with props', () => runTest({
74 | classNameMap: { booleanAttribute: { true: 'class' } },
75 | inputProps: { className: 'test', booleanAttribute: true },
76 | expectedProps: { className: 'class test' },
77 | }));
78 |
79 | it('allows setting style', () => runTest({
80 | inputProps: { style: { top: 5 } },
81 | expectedProps: { style: { top: 5 } },
82 | }));
83 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/src/platforms/web.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-param-reassign */
2 | const t = require('babel-types');
3 | const _ = require('lodash/fp');
4 | const extractRules = require('cssta/src/web/extractRules');
5 | const cssNameGenerator = require('css-class-generator');
6 | const { jsonToNode, getOrCreateImportReference } = require('../util');
7 | const { startEndMarkers, fileStartEndCommentMarkers } = require('../webUtil');
8 |
9 |
10 | // Make sure we don't somehow generate an animation name that's a keyword
11 | // This is almost impossible anyway, but whatever
12 | const animationKeywords = `
13 | alternate alternate-reverse backwards both ease ease-in ease-in-out ease-out forwards infinite
14 | linear none normal paused reverse running step-end step-start initial inherit unset
15 | `.split(/[^\s]+/g);
16 |
17 | let classGenerator = null;
18 | let animationGenerator = null;
19 |
20 | const resetGenerators = () => {
21 | classGenerator = cssNameGenerator();
22 | animationGenerator = (function* gen() {
23 | for (const value of cssNameGenerator()) { // eslint-disable-line
24 | if (!_.includes(value, animationKeywords)) yield value;
25 | }
26 | }());
27 | };
28 |
29 | resetGenerators();
30 |
31 | module.exports = (path, state, component, cssText, substititionMap) => {
32 | if (!_.isEmpty(substititionMap)) {
33 | throw new Error('You cannot use interpolation in template strings (i.e. `color: ${primary}`)'); // eslint-disable-line
34 | }
35 |
36 | const isInjectGlobal = t.isStringLiteral(component) && component.value === 'injectGlobal';
37 |
38 | const { commentStartMarker, commentEndMarker } = isInjectGlobal
39 | ? startEndMarkers('Injected Globals')
40 | : fileStartEndCommentMarkers(state);
41 |
42 | let { currentWebCss } = state;
43 | let newElement = null;
44 |
45 | if (!isInjectGlobal) {
46 | const { css: output, args } = extractRules(cssText, {
47 | generateClassName: () => classGenerator.next().value,
48 | generateAnimationName: () => animationGenerator.next().value,
49 | });
50 |
51 | const cssBefore = _.endsWith(commentEndMarker, currentWebCss)
52 | ? currentWebCss.slice(0, -commentEndMarker.length)
53 | : `${currentWebCss}\n${commentStartMarker}`;
54 | currentWebCss = `${cssBefore}\n${output}\n${commentEndMarker}`;
55 |
56 | const createComponent = getOrCreateImportReference(
57 | path,
58 | 'cssta/lib/web/createComponent',
59 | 'default'
60 | );
61 |
62 | newElement = t.callExpression(createComponent, [
63 | component,
64 | t.nullLiteral(), // Gets replaced with Object.keys(classNameMap)
65 | jsonToNode(args),
66 | ]);
67 | } else {
68 | currentWebCss = `${commentStartMarker}${cssText}\n${commentEndMarker}${currentWebCss}`;
69 | }
70 |
71 | state.currentWebCss = currentWebCss;
72 |
73 | if (newElement) {
74 | path.replaceWith(newElement);
75 | } else {
76 | path.remove();
77 | }
78 | };
79 |
80 | module.exports.resetGenerators = resetGenerators;
81 |
--------------------------------------------------------------------------------
/packages/cssta/src/web/index.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | /* global document */
3 | const extractRules = require('./extractRules');
4 | const createComponent = require('./createComponent');
5 |
6 | let devId = 0;
7 | const getDevId = name => () => {
8 | devId += 1;
9 | return `${name}-${devId}`;
10 | };
11 |
12 | const assertNoTemplateParams = (cssTextFragments) => {
13 | if (!Array.isArray(cssTextFragments)) {
14 | return cssTextFragments;
15 | } else if (cssTextFragments.length === 1) {
16 | return cssTextFragments[0];
17 | }
18 | throw new Error('You cannot use string interpolation with cssta for web');
19 | };
20 |
21 | let styleElement = null;
22 | const updateCss = (cssText) => {
23 | if (!styleElement) {
24 | styleElement = document.createElement('style');
25 | const styleBody = document.createTextNode(cssText);
26 | styleElement.appendChild(styleBody);
27 | document.getElementsByTagName('head')[0].appendChild(styleElement);
28 | } else {
29 | const existingStyleBody = styleElement.firstChild;
30 | if (!existingStyleBody) throw new Error('Unexpected error creating styles');
31 | const newStyleBody = document.createTextNode(cssText);
32 | styleElement.replaceChild(newStyleBody, existingStyleBody);
33 | }
34 | };
35 |
36 | const opts = {
37 | generateClassName: getDevId('rule'),
38 | generateAnimationName: getDevId('animation'),
39 | };
40 |
41 | let styleContents = '';
42 | const style = (element /*: any */) => (cssTextFragments /*: string[] | string */) => {
43 | const cssText = assertNoTemplateParams(cssTextFragments);
44 |
45 | const { css, propTypes, args } = extractRules(cssText, opts);
46 |
47 | styleContents += css;
48 | updateCss(styleContents);
49 |
50 | return createComponent(element, propTypes, args);
51 | };
52 |
53 | let didInjectGlobal = false;
54 | style.injectGlobal = (cssTextFragments) => {
55 | const cssText = assertNoTemplateParams(cssTextFragments);
56 |
57 | if (didInjectGlobal) {
58 | throw new Error('To help with consistency, you can only call injectGlobal once');
59 | }
60 |
61 | didInjectGlobal = true;
62 | styleContents = cssText + styleContents;
63 | updateCss(styleContents);
64 | };
65 |
66 | `a abbr address area article aside audio b base bdi bdo big blockquote body br button canvas
67 | caption cite code col colgroup data datalist dd del details dfn dialog div dl dt em embed fieldset
68 | figcaption figure footer form h1 h2 h3 h4 h5 h6 head header hgroup hr html i iframe img input ins
69 | kbd keygen label legend li link main map mark menu menuitem meta meter nav noscript object ol
70 | optgroup option output p param picture pre progress q rp rt ruby s samp script section select small
71 | source span strong style sub summary sup table tbody td textarea tfoot th thead time title tr track
72 | u ul var video wbr circle clipPath defs ellipse g image line linearGradient mask path pattern
73 | polygon polyline radialGradient rect stop svg text tspan`.split(/\s+/m).forEach((tagName) => {
74 | style[tagName] = style(tagName);
75 | });
76 |
77 | module.exports = style;
78 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/src/index.test.js:
--------------------------------------------------------------------------------
1 | /* global it expect */
2 | const path = require('path');
3 | const fs = require('fs');
4 | const glob = require('glob');
5 | const { transformFileSync } = require('babel-core');
6 | const tempfile = require('tempfile');
7 | const plugin = require('.');
8 |
9 | const approve = process.argv.includes('--approve');
10 | const printJs = process.argv.includes('--print-js');
11 | const printCss = process.argv.includes('--print-css');
12 | const filterIndex = process.argv.indexOf('--filter');
13 | const filter = filterIndex === -1 ? '' : process.argv[filterIndex + 1];
14 | const baseDir = path.join(__dirname, '..');
15 |
16 | const normaliseCss = (str) => {
17 | let output = str;
18 | do {
19 | output = output.replace(baseDir, '');
20 | } while (output.indexOf(baseDir) !== -1);
21 | return output;
22 | };
23 |
24 | const getMockCssPath = () => tempfile('.css');
25 |
26 | const getActual = (testPath, actualJsPath, optionsPath) => {
27 | plugin.resetGenerators();
28 |
29 | const dummyCssPath = getMockCssPath();
30 | const options = { output: dummyCssPath, cwd: testPath };
31 |
32 | if (fs.existsSync(optionsPath)) {
33 | const userOptions = JSON.parse(fs.readFileSync(optionsPath, 'utf8'));
34 | Object.assign(options, userOptions);
35 | }
36 |
37 | const actualJs = transformFileSync(actualJsPath, {
38 | plugins: [[plugin, options]],
39 | }).code;
40 |
41 | let actualCss = fs.existsSync(dummyCssPath)
42 | ? fs.readFileSync(dummyCssPath, 'utf8')
43 | : '';
44 | actualCss = normaliseCss(actualCss);
45 |
46 | return { actualJs, actualCss };
47 | };
48 |
49 | glob.sync(path.join(baseDir, 'fixtures/*/')).filter(name => (
50 | !filter || name.indexOf(filter) !== -1
51 | )).forEach((testPath) => {
52 | const testName = path.relative(path.join(baseDir, 'fixtures'), testPath);
53 |
54 | const expectedJsPath = path.join(testPath, 'expected.js');
55 | const expectedCssPath = path.join(testPath, 'expected.css');
56 | const actualJsPath = path.join(testPath, 'actual.js');
57 | const optionsPath = path.join(testPath, 'options.json');
58 |
59 | if (global.it) {
60 | it(`should work with ${testName}`, () => {
61 | const { actualJs, actualCss } = getActual(testPath, actualJsPath, optionsPath);
62 | const expectedJs = fs.readFileSync(expectedJsPath, 'utf8');
63 | const expectedCss = actualCss && fs.readFileSync(expectedCssPath, 'utf8');
64 |
65 | expect(actualJs.trim()).toEqual(expectedJs.trim());
66 | if (actualCss) expect(actualCss.trim()).toEqual(expectedCss.trim());
67 | });
68 | } else {
69 | const { actualJs, actualCss } = getActual(testPath, actualJsPath, optionsPath);
70 |
71 | if (approve) {
72 | const options = { flag: 'w+', encoding: 'utf8' };
73 | fs.writeFileSync(expectedJsPath, actualJs, options);
74 | if (actualCss) fs.writeFileSync(expectedCssPath, actualCss, options);
75 | }
76 |
77 | if (printJs) console.log(actualJs); // eslint-disable-line
78 | if (printCss) console.log(actualCss); // eslint-disable-line
79 | }
80 | });
81 |
--------------------------------------------------------------------------------
/packages/cssta/src/native/__tests__/selectorTransform.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable flowtype/require-valid-file-annotation */
2 | /* global jest it, expect */
3 | const {
4 | getValidatorSourceForSelector, createValidatorForSelector,
5 | } = require('../selectorTransform');
6 |
7 | const runTest = (selector, { valid = [], invalid = [] }) => {
8 | const validator = createValidatorForSelector(selector);
9 |
10 | valid.forEach((props) => {
11 | expect(validator(props)).toBe(true);
12 | });
13 |
14 | invalid.forEach((props) => {
15 | expect(validator(props)).toBe(false);
16 | });
17 | };
18 |
19 | // Note that getRoot replaces @ with * (so it parses). We have to use * here.
20 |
21 | it('creates a function that validates boolean attributes', () => runTest('[*bool]', {
22 | valid: [{ bool: true }, { bool: true, otherAttribute: true }],
23 | invalid: [{}, { bool: false }, { otherAttribute: true }],
24 | }));
25 |
26 | it('creates a function that validates string attributes', () => runTest('[*string = "test"]', {
27 | valid: [{ string: 'test' }, { string: 'test', otherAttribute: true }],
28 | invalid: [{}, { string: 'other' }, { otherAttribute: true }],
29 | }));
30 |
31 | it('combines multiple validators', () => runTest('[*bool][*string = "test"]', {
32 | valid: [
33 | { bool: true, string: 'test' },
34 | { bool: true, string: 'test', otherAttribute: true },
35 | ],
36 | invalid: [
37 | {},
38 | { string: 'test' },
39 | { bool: true },
40 | { string: 'other', bool: true },
41 | { string: 'test', bool: false },
42 | { otherAttribute: true },
43 | ],
44 | }));
45 |
46 | it('validates everything for & selector', () => runTest('&', {
47 | valid: [{}, { otherAttribute: true }],
48 | }));
49 |
50 | it('works with :matches for same prop', () => runTest(':matches([*string = "a"], [*string = "b"])', {
51 | valid: [{ string: 'a' }, { string: 'b' }, { string: 'a', otherAttribute: true }],
52 | invalid: [{}, { string: 'other' }, { otherAttribute: true }],
53 | }));
54 |
55 | it('works with :matches for different props', () => runTest(':matches([*string = "a"], [*bool])', {
56 | valid: [{ string: 'a' }, { bool: true }, { string: 'a', otherAttribute: true }],
57 | invalid: [{}, { string: 'other' }, { bool: false }, { otherAttribute: true }],
58 | }));
59 |
60 | it('works with :not for same prop', () => runTest(':not([*string = "a"], [*string = "b"])', {
61 | valid: [{}, { string: 'other' }, { otherAttribute: true }],
62 | invalid: [{ string: 'a' }, { string: 'b' }, { string: 'a', otherAttribute: true }],
63 | }));
64 |
65 | it('works with :not for different props', () => runTest(':not([*string = "a"], [*bool])', {
66 | valid: [{}, { string: 'other' }, { bool: false }, { otherAttribute: true }],
67 | invalid: [{ string: 'a' }, { bool: true }, { string: 'a', otherAttribute: true }],
68 | }));
69 |
70 | it('does not allow other pseudo selectors', () => {
71 | expect(() => createValidatorForSelector(':first-child')).toThrow();
72 | });
73 |
74 | it('creates function source for node', () => {
75 | const node = getValidatorSourceForSelector('&');
76 | expect(node).toEqual('(function(p) {return true;})');
77 | });
78 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/src/transformUtil/extractCsstaCallParts.js:
--------------------------------------------------------------------------------
1 | const t = require('babel-types');
2 | const _ = require('lodash/fp');
3 | const { csstaModules } = require('../util');
4 |
5 |
6 | const interpolationTypes = {
7 | ALLOW: 0,
8 | IGNORE: 1,
9 | DISALLOW: 2,
10 | };
11 |
12 | const csstaConstructorExpressionTypes = {
13 | CallExpression: node => [node.callee, node.arguments[0]],
14 | MemberExpression: node => [
15 | node.object,
16 | node.computed ? node.property : t.stringLiteral(node.property.name),
17 | ],
18 | };
19 |
20 | const getCsstaTypeForCallee = (path, callee) => {
21 | if (!t.isIdentifier(callee)) return null;
22 |
23 | const importScopePath = path.findParent(_.has(['scope', 'bindings', callee.name]));
24 | if (!importScopePath) return null;
25 |
26 | const importSpecifier = _.get(['scope', 'bindings', callee.name, 'path'], importScopePath);
27 | if (!importSpecifier || !t.isImportDefaultSpecifier(importSpecifier)) return null;
28 |
29 | const importDeclaration = importSpecifier.findParent(t.isImportDeclaration);
30 | if (!importDeclaration) return null;
31 |
32 | const source = importDeclaration.node.source.value;
33 | const csstaType = csstaModules[source];
34 | if (!csstaType) return null;
35 |
36 | return { csstaType, importDeclaration };
37 | };
38 |
39 | module.exports.getCsstaReferences = (path, node) => {
40 | if (!(node.type in csstaConstructorExpressionTypes)) return null;
41 |
42 | const [callee, component] = csstaConstructorExpressionTypes[node.type](node);
43 |
44 | const csstaTypeParts = getCsstaTypeForCallee(path, callee);
45 | if (!csstaTypeParts) return null;
46 |
47 | const { csstaType, importBinding } = csstaTypeParts;
48 |
49 | return { callee, importBinding, component, csstaType };
50 | };
51 |
52 | module.exports.interpolationTypes = interpolationTypes;
53 | module.exports.extractCsstaCallParts = (stringArg, interpolationType) => {
54 | if (!t.isTemplateLiteral(stringArg) && !t.isStringLiteral(stringArg)) return null;
55 |
56 | const hasInterpolation = t.isTemplateLiteral(stringArg) && !_.isEmpty(stringArg.expressions);
57 |
58 | if (hasInterpolation && interpolationType === interpolationTypes.DISALLOW) {
59 | const ex = '`color: ${primary}`'; // eslint-disable-line
60 | throw new Error(`You cannot interpolation in template strings (i.e. ${ex})`);
61 | }
62 |
63 | const allowInterpolation = interpolationType === interpolationTypes.ALLOW;
64 |
65 | let cssText = null;
66 | let substitutionMap = {};
67 |
68 | if (t.isTemplateLiteral(stringArg) && (allowInterpolation || !hasInterpolation)) {
69 | const { quasis, expressions } = stringArg;
70 | const substitutionNames = expressions.map((value, index) => `__substitution-${index}__`);
71 | cssText =
72 | quasis[0].value.cooked +
73 | substitutionNames.map((name, index) => name + quasis[index + 1].value.cooked).join('');
74 | substitutionMap = _.fromPairs(_.zip(substitutionNames, expressions));
75 | } else if (t.isStringLiteral(stringArg)) {
76 | cssText = stringArg.value;
77 | }
78 |
79 | if (cssText === null) return null;
80 |
81 | return { cssText, substitutionMap };
82 | };
83 |
--------------------------------------------------------------------------------
/packages/cssta/src/native/selectorTransform.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | // We generate babel nodes that represent a validation function
3 | // In prod, we use the babel nodes to make a function
4 | // In dev, we eval to generate a function
5 |
6 | const selectorParser = require('postcss-selector-parser');
7 |
8 | const propArg = 'p';
9 |
10 | const createLogicalValidator = (nodes, operator) => {
11 | if (nodes.length === 0) throw new Error('Cannot construct logical validaton');
12 | const nodeValidators = nodes
13 | .map(createValidator) // eslint-disable-line
14 | .filter(validator => validator !== null);
15 | if (nodeValidators.length === 0) return null;
16 | return nodeValidators.slice(1).reduce((accum, validator) => (
17 | `(${accum} ${operator} ${validator})`
18 | ), nodeValidators[0]);
19 | };
20 |
21 | const createNestingValidator = () => null;
22 |
23 | const createAttributeValidator = (node) => {
24 | const { raws, value } = node;
25 | const attribute = node.attribute.trim();
26 | if (attribute[0] !== '*') {
27 | throw new Error(`You can only use prop selectors (did you forget a * before ${attribute})`);
28 | }
29 |
30 | const prop = attribute.slice(1);
31 | const memberExpression = `${propArg}[${JSON.stringify(prop)}]`;
32 |
33 | if (!value) return `!!${memberExpression}`;
34 |
35 | const unquoted = raws.unquoted.trim();
36 | return `(${memberExpression} === ${JSON.stringify(unquoted)})`;
37 | };
38 |
39 | const createPseudoValidator = (node) => {
40 | const { value, nodes } = node;
41 |
42 | if (value === ':matches') {
43 | return createLogicalValidator(nodes, '||');
44 | } else if (value === ':not') {
45 | const baseValidator = createLogicalValidator(nodes, '||');
46 | return baseValidator ? `!${baseValidator}` : null;
47 | }
48 | throw new Error(`Invalid selector part: ${node}`);
49 | };
50 |
51 | const createSelectorValidator = node => createLogicalValidator(node.nodes, '&&');
52 |
53 | const validators = {
54 | nesting: createNestingValidator,
55 | attribute: createAttributeValidator,
56 | pseudo: createPseudoValidator,
57 | selector: createSelectorValidator,
58 | root: createSelectorValidator,
59 | };
60 |
61 | const createValidator = (node) => {
62 | if (!(node.type in validators)) throw new Error(`Invalid selector part: ${node}`);
63 | return validators[node.type](node);
64 | };
65 |
66 | const getBaseValidatorSourceForSelector = (selector) => {
67 | let selectorNode;
68 | selectorParser((node) => { selectorNode = node; }).process(selector);
69 | if (!selectorNode) throw new Error('Expected to parse selector');
70 | const validatorNode = createValidator(selectorNode) || 'true';
71 | const returnNode = `return ${validatorNode};`;
72 | return returnNode;
73 | };
74 |
75 | module.exports.getValidatorSourceForSelector = (selector /*: string */) =>
76 | `(function(${propArg}) {${getBaseValidatorSourceForSelector(selector)}})`;
77 |
78 | module.exports.createValidatorForSelector = (
79 | selector /*: string */
80 | ) /*: (props: Object) => boolean */ => {
81 | const source = getBaseValidatorSourceForSelector(selector);
82 | // $FlowFixMe
83 | const validator /*: (props: Object) => boolean */ = new Function(propArg, source); // eslint-disable-line
84 | return validator;
85 | };
86 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/src/optimizations/singleSourceOfVariables.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const { parse } = require('babylon');
3 | const { default: traverse } = require('babel-traverse');
4 | const _ = require('lodash/fp');
5 | const extractRules = require('cssta/src/native/extractRules'); // Is this really native-only?
6 | const resolveVariableDependencies = require('cssta/src/util/resolveVariableDependencies');
7 | const {
8 | getCsstaReferences, interpolationTypes, extractCsstaCallParts,
9 | } = require('../transformUtil/extractCsstaCallParts');
10 | const { containsSubstitution } = require('../util');
11 |
12 |
13 | const extractVariables = (path, target, stringArg) => {
14 | const csstaReferenceParts = getCsstaReferences(path, target);
15 | if (!csstaReferenceParts) return null;
16 |
17 | const callParts = extractCsstaCallParts(stringArg, interpolationTypes.ALLOW);
18 | if (!callParts) return null;
19 |
20 | const { cssText, substitutionMap } = callParts;
21 |
22 | const { args: { ruleTuples } } = extractRules(cssText);
23 | const rulesWithExportedVariables = _.reject(
24 | _.conforms({ exportedVariables: _.isEmpty }),
25 | ruleTuples
26 | );
27 |
28 | if (_.isEmpty(rulesWithExportedVariables)) return null;
29 |
30 | if (!_.every({ selector: '&' }, rulesWithExportedVariables)) {
31 | throw new Error('When using singleSourceOfVariables, all variables must be top-level');
32 | }
33 |
34 | const exportedVariables = _.flow(
35 | _.map('exportedVariables'),
36 | _.reduce(_.assign, {})
37 | )(rulesWithExportedVariables);
38 |
39 | const exportedVariablesContainingSubstitution = _.flow(
40 | _.values,
41 | _.filter(containsSubstitution(substitutionMap))
42 | )(exportedVariables);
43 |
44 | if (!_.isEmpty(exportedVariablesContainingSubstitution)) {
45 | throw new Error(
46 | 'When using singleSourceOfVariables, you cannot use interpolation within variables'
47 | );
48 | }
49 |
50 | return exportedVariables;
51 | };
52 |
53 | module.exports = (filename, fileOpts) => {
54 | const source = fs.readFileSync(filename, 'utf-8');
55 | const ast = parse(source, fileOpts);
56 |
57 | let exportedVariables = null;
58 | const doExtractVariables = (path, node, stringArg) => {
59 | const newExportedVariables = extractVariables(path, node, stringArg);
60 | if (exportedVariables && newExportedVariables) {
61 | throw new Error('When using singleSourceOfVariables, only one component can define variables');
62 | } else if (newExportedVariables) {
63 | exportedVariables = newExportedVariables;
64 | }
65 | };
66 |
67 | traverse(ast, {
68 | CallExpression(path) {
69 | const { node } = path;
70 | const [arg] = node.arguments;
71 | doExtractVariables(path, node, arg);
72 | },
73 | TaggedTemplateExpression(path) {
74 | const { quasi, tag } = path.node;
75 | doExtractVariables(path, tag, quasi);
76 | },
77 | }, null, {
78 | file: { opts: { filename: 'intermediate-file' } },
79 | });
80 |
81 | if (!exportedVariables) {
82 | throw new Error('Expected given file to contain CSS variables for singleSourceOfVariables');
83 | }
84 |
85 | const resolvedVariables = resolveVariableDependencies(exportedVariables, {});
86 | return resolvedVariables;
87 | };
88 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/src/platforms/native/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-param-reassign */
2 | const t = require('babel-types');
3 | const _ = require('lodash/fp');
4 | const resolveVariableDependencies = require('cssta/src/util/resolveVariableDependencies');
5 | const extractRules = require('cssta/src/native/extractRules');
6 | const { getOrCreateImportReference, jsonToNode } = require('../../util');
7 | const createArgsStatic = require('./createArgsStatic');
8 | const createArgsVariables = require('./createArgsVariables');
9 |
10 |
11 | const everyIsEmpty = _.every(_.isEmpty);
12 | const argsIsEmpty = _.flow(
13 | _.update('ruleTuples', _.map(_.omit(['selector']))),
14 | _.update('ruleTuples', _.reject(everyIsEmpty)),
15 | everyIsEmpty
16 | );
17 |
18 | module.exports = (path, state, component, cssText, substitutionMap) => {
19 | const { singleSourceOfVariables } = state;
20 | // eslint-disable-next-line
21 | let { propTypes, args } = extractRules(cssText);
22 |
23 | if (singleSourceOfVariables) {
24 | args = _.flow(
25 | _.set('importedVariables', []),
26 | _.update('ruleTuples', _.map(_.set('exportedVariables', {})))
27 | )(args);
28 | }
29 |
30 | const exportedVariables = _.reduce(_.assign, {}, _.map('exportedVariables', args.ruleTuples));
31 | const exportsVariables = !_.isEmpty(exportedVariables);
32 |
33 | const resolvedVariables = (singleSourceOfVariables && exportsVariables)
34 | ? resolveVariableDependencies(exportedVariables, {})
35 | : null;
36 |
37 | if (resolvedVariables && !_.isEqual(resolvedVariables, singleSourceOfVariables)) {
38 | throw new Error('When using singleSourceOfVariables, only one component can define variables');
39 | }
40 |
41 | // If we end up with nothing after removing configs, and we don't filter props,
42 | // we can just return the component
43 | if (argsIsEmpty(args) && _.isEmpty(propTypes)) {
44 | path.replaceWith(component);
45 | return;
46 | }
47 |
48 | const hasVariables =
49 | exportsVariables || !_.isEmpty(args.importedVariables) || !_.isEmpty(exportedVariables);
50 |
51 | if (hasVariables && singleSourceOfVariables) {
52 | throw new Error('Internal error: expected no variables with singleSourceOfVariables');
53 | }
54 |
55 | const componentRoot = 'cssta/lib/native';
56 | const enhancersRoot = `${componentRoot}/enhancers`;
57 | const enhancers = [];
58 |
59 | const addEnhancer = enhancer =>
60 | enhancers.push(getOrCreateImportReference(path, `${enhancersRoot}/${enhancer}`, 'default'));
61 |
62 | if (hasVariables) addEnhancer('VariablesStyleSheetManager');
63 | if (!_.isEmpty(args.transitionedProperties)) addEnhancer('Transition');
64 | if (!_.isEmpty(args.keyframesStyleTuples)) addEnhancer('Animation');
65 |
66 | let componentConstructor;
67 | if (_.isEmpty(enhancers)) {
68 | const createComponent =
69 | getOrCreateImportReference(path, `${componentRoot}/createComponent`, 'default');
70 | componentConstructor = createComponent;
71 | } else {
72 | const withEnhancers =
73 | getOrCreateImportReference(path, `${componentRoot}/withEnhancers`, 'default');
74 | componentConstructor = t.callExpression(withEnhancers, [
75 | t.arrayExpression(enhancers),
76 | ]);
77 | }
78 |
79 | const argsNode = hasVariables
80 | ? createArgsVariables(path, substitutionMap, args)
81 | : createArgsStatic(path, substitutionMap, args);
82 |
83 | const newElement = t.callExpression(componentConstructor, [
84 | component,
85 | jsonToNode(Object.keys(propTypes)),
86 | argsNode,
87 | ]);
88 |
89 | path.replaceWith(newElement);
90 | };
91 |
--------------------------------------------------------------------------------
/packages/babel-plugin-cssta/src/platforms/native/simpleInterpolationMap.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-param-reassign */
2 | const t = require('babel-types');
3 | const { getOrCreateImportReference } = require('../../util');
4 |
5 | const convertValue = transform => (path, value) =>
6 | t.callExpression(t.identifier(transform), [value]);
7 |
8 | const stringInterpolation = (path, value) =>
9 | t.callExpression(t.memberExpression(convertValue('String')(path, value), t.identifier('trim')), []);
10 |
11 | const lengthInterpolation = (path, value) => {
12 | const transformRawValue = getOrCreateImportReference(
13 | path,
14 | 'cssta/lib/native/cssUtil',
15 | 'transformRawValue'
16 | );
17 |
18 | return t.callExpression(transformRawValue, [value]);
19 | };
20 |
21 | const numberInterpolation = convertValue('Number');
22 |
23 | /*
24 | All the values we can work out easily.
25 |
26 | E.g.
27 | fontSize: ${value} can only be a number -> { fontSize: Number(value) }
28 | position: ${value} can only be a string -> { position: String(value).trim() }
29 |
30 | Some values, like 'margin', have shorthands, so cannot be included.
31 | */
32 | module.exports = {
33 | /* View */
34 | backfaceVisibility: stringInterpolation,
35 | background: stringInterpolation,
36 | backgroundColor: stringInterpolation,
37 | borderBottomColor: stringInterpolation,
38 | borderBottomLeftRadius: lengthInterpolation,
39 | borderBottomRightRadius: lengthInterpolation,
40 | borderBottomWidth: lengthInterpolation,
41 | borderLeftColor: stringInterpolation,
42 | borderLeftWidth: lengthInterpolation,
43 | borderRightColor: stringInterpolation,
44 | borderRightWidth: lengthInterpolation,
45 | borderTopColor: stringInterpolation,
46 | borderTopLeftRadius: lengthInterpolation,
47 | borderTopRightRadius: lengthInterpolation,
48 | borderTopWidth: lengthInterpolation,
49 | opacity: numberInterpolation,
50 | elevation: numberInterpolation,
51 | /* Layout */
52 | alignItems: stringInterpolation,
53 | alignSelf: stringInterpolation,
54 | bottom: lengthInterpolation,
55 | flexBasis: lengthInterpolation,
56 | flexDirection: stringInterpolation,
57 | flexGrow: numberInterpolation,
58 | flexShrink: numberInterpolation,
59 | flexWrap: stringInterpolation,
60 | height: lengthInterpolation,
61 | justifyContent: stringInterpolation,
62 | left: lengthInterpolation,
63 | marginBottomWidth: lengthInterpolation,
64 | marginLeftWidth: lengthInterpolation,
65 | marginRightWidth: lengthInterpolation,
66 | marginTopWidth: lengthInterpolation,
67 | maxHeight: lengthInterpolation,
68 | maxWidth: lengthInterpolation,
69 | minHeight: lengthInterpolation,
70 | minWidth: lengthInterpolation,
71 | overflow: stringInterpolation,
72 | paddingBottomWidth: lengthInterpolation,
73 | paddingLeftWidth: lengthInterpolation,
74 | paddingRightWidth: lengthInterpolation,
75 | paddingTopWidth: lengthInterpolation,
76 | position: stringInterpolation,
77 | right: lengthInterpolation,
78 | top: lengthInterpolation,
79 | width: lengthInterpolation,
80 | zIndex: numberInterpolation,
81 | /* Text */
82 | color: stringInterpolation,
83 | fontSize: lengthInterpolation,
84 | fontStyle: stringInterpolation,
85 | fontWeight: stringInterpolation,
86 | lineHeight: lengthInterpolation,
87 | textAlign: stringInterpolation,
88 | textDecorationLine: stringInterpolation,
89 | textShadowColor: stringInterpolation,
90 | textShadowRadius: lengthInterpolation,
91 | textAlignVertical: stringInterpolation,
92 | letterSpacing: lengthInterpolation,
93 | textDecorationColor: stringInterpolation,
94 | textDecorationStyle: stringInterpolation,
95 | writingDirection: stringInterpolation,
96 | };
97 |
--------------------------------------------------------------------------------