├── .gitignore ├── .npmignore ├── .storybook ├── addons.js ├── attr.stories.js ├── classnames.stories.js ├── config.js ├── css.stories.js ├── dom.stories.js ├── lifecycles.stories.js ├── on.stories.js └── prefixer.stories.js ├── .travis.yml ├── README.md ├── package.json ├── renovate.json └── src ├── __tests__ ├── index.test.js └── setup.js ├── applyPlugins.js ├── patch.js └── plugins ├── attr.js ├── classnames.js ├── css.js ├── dom.js ├── on.js └── prefixer.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | node_modules/ 3 | .nyc_output/ 4 | coverage/ 5 | package-lock.json 6 | yarn.lock 7 | .DS_Store 8 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | test/ 3 | .idea/ 4 | .nyc_output/ 5 | coverage/ 6 | package-lock.json 7 | yarn.lock 8 | .DS_Store 9 | -------------------------------------------------------------------------------- /.storybook/addons.js: -------------------------------------------------------------------------------- 1 | import '@storybook/addon-actions/register'; 2 | import '@storybook/addon-links/register'; 3 | -------------------------------------------------------------------------------- /.storybook/attr.stories.js: -------------------------------------------------------------------------------- 1 | import '../src/patch'; 2 | import React from 'react'; 3 | import {storiesOf} from '@storybook/react'; 4 | import {action} from '@storybook/addon-actions'; 5 | import {linkTo} from '@storybook/addon-links'; 6 | import {create} from 'nano-css'; 7 | import {addon as addonRule} from 'nano-css/addon/rule'; 8 | 9 | storiesOf('attr', module) 10 | .add('[aria-hidden]', () =>
aria-hidden
) 11 | -------------------------------------------------------------------------------- /.storybook/classnames.stories.js: -------------------------------------------------------------------------------- 1 | import '../src/patch'; 2 | import React from 'react'; 3 | import {storiesOf} from '@storybook/react'; 4 | import {action} from '@storybook/addon-actions'; 5 | import {linkTo} from '@storybook/addon-links'; 6 | import {create} from 'nano-css'; 7 | import {addon as addonRule} from 'nano-css/addon/rule'; 8 | 9 | const nano = create(); 10 | 11 | addonRule(nano); 12 | 13 | const {rule} = nano; 14 | 15 | const classNameRed = rule({ 16 | color: 'red' 17 | }); 18 | 19 | storiesOf('classnames', module) 20 | .add('className', () =>
test
) 21 | .add('class', () =>
test
) 22 | .add('object', () =>
test
) 23 | .add('object, negative', () =>
test
) 24 | .add('long', () =>
long
) 25 | -------------------------------------------------------------------------------- /.storybook/config.js: -------------------------------------------------------------------------------- 1 | import {configure} from '@storybook/react'; 2 | 3 | // automatically import all files ending in *.stories.js 4 | const req = require.context('.', true, /.stories.js$/); 5 | function loadStories() { 6 | req.keys().forEach(filename => req(filename)); 7 | } 8 | 9 | configure(loadStories, module); 10 | -------------------------------------------------------------------------------- /.storybook/css.stories.js: -------------------------------------------------------------------------------- 1 | import '../src/patch'; 2 | import React from 'react'; 3 | import {storiesOf} from '@storybook/react'; 4 | import {action} from '@storybook/addon-actions'; 5 | import {linkTo} from '@storybook/addon-links'; 6 | import {create} from 'nano-css'; 7 | import {addon as addonRule} from 'nano-css/addon/rule'; 8 | 9 | storiesOf('css', module) 10 | .add('basic', () =>
Hover me!
) 11 | -------------------------------------------------------------------------------- /.storybook/dom.stories.js: -------------------------------------------------------------------------------- 1 | import '../src/patch'; 2 | import React from 'react'; 3 | import {storiesOf} from '@storybook/react'; 4 | import {action} from '@storybook/addon-actions'; 5 | import {linkTo} from '@storybook/addon-links'; 6 | import {create} from 'nano-css'; 7 | import {addon as addonRule} from 'nano-css/addon/rule'; 8 | 9 | storiesOf('dom', module) 10 | .add('.innerHTML', () =>
) 11 | -------------------------------------------------------------------------------- /.storybook/lifecycles.stories.js: -------------------------------------------------------------------------------- 1 | import '../src/patch'; 2 | import React from 'react'; 3 | import {storiesOf} from '@storybook/react'; 4 | import {action} from '@storybook/addon-actions'; 5 | import {linkTo} from '@storybook/addon-links'; 6 | import {create} from 'nano-css'; 7 | import {addon as addonRule} from 'nano-css/addon/rule'; 8 | 9 | storiesOf('life-cycles', module) 10 | .add('basic', () =>
console.log('ATTACH')} 12 | $detach={() => console.log('DETACH')} 13 | >Hello
) 14 | -------------------------------------------------------------------------------- /.storybook/on.stories.js: -------------------------------------------------------------------------------- 1 | import '../src/patch'; 2 | import React from 'react'; 3 | import {storiesOf} from '@storybook/react'; 4 | import {action} from '@storybook/addon-actions'; 5 | import {linkTo} from '@storybook/addon-links'; 6 | import {create} from 'nano-css'; 7 | import {addon as addonRule} from 'nano-css/addon/rule'; 8 | 9 | storiesOf('on', module) 10 | .add('click', () =>
console.log('LOLO')}}>Click me!
) 11 | -------------------------------------------------------------------------------- /.storybook/prefixer.stories.js: -------------------------------------------------------------------------------- 1 | import '../src/patch'; 2 | import React from 'react'; 3 | import {storiesOf} from '@storybook/react'; 4 | import {action} from '@storybook/addon-actions'; 5 | import {linkTo} from '@storybook/addon-links'; 6 | import {create} from 'nano-css'; 7 | import {addon as addonRule} from 'nano-css/addon/rule'; 8 | 9 | storiesOf('prefixer', module) 10 | .add('hyphens', () =>
hyphens
) 14 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | os: 3 | - linux 4 | language: node_js 5 | node_js: 6 | - '8' 7 | matrix: 8 | allow_failures: [] 9 | fast_finish: true 10 | cache: 11 | yarn: true 12 | directories: 13 | - "node_modules" 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JSX++ 2 | 3 | Missing features for your React JSX templates. 4 | 5 | - Inline style prefixing 6 | - Better class name syntax 7 | - Dynamic CSS — [*demo!*](https://codesandbox.io/s/ryoy53q4mn) 8 | - Set DOM element props — [*demo!*](https://codesandbox.io/s/535k08vwm4) 9 | - Set DOM element attributes 10 | - Add native DOM event listeners — [*demo!*](https://codesandbox.io/s/2wlvo21yp0) 11 | - Micro life-cycles 12 | 13 | 14 | Usage: 15 | 16 | ```js 17 | require('jsx-plus-plus'); 18 | ``` 19 | 20 | Done! 21 | 22 | 23 | ## Inline Style Prefixing 24 | 25 | Auto-prefixes inline styles, uses only required prefixes by your browser. 26 | 27 | ```jsx 28 |
29 | ``` 30 | 31 | Result: 32 | 33 | ```html 34 |
35 | ``` 36 | 37 | 38 | ## Better Class Names 39 | 40 | Set class names using either `class` or `className` props. Use [`classnames`](https://www.npmjs.com/package/classnames) 41 | syntax. 42 | 43 | ```jsx 44 |
45 |
46 | ``` 47 | 48 | Result: 49 | 50 | ```html 51 |
52 |
53 | ``` 54 | 55 | 56 | ## Dynamic CSS 57 | 58 | JSX++ will dynamically generate scoped CSS for your nodes. 59 | 60 | ```jsx 61 |
Hover me!
67 | ``` 68 | 69 | Result: 70 | 71 | ```css 72 | [data-css-123] { 73 | color: red; 74 | } 75 | [data-css-123]:hover { 76 | color: blue; 77 | } 78 | ``` 79 | 80 | ```html 81 |
Hover me!
82 | ``` 83 | 84 | 85 | ## DOM Element Props 86 | 87 | Sets props on native DOM elements. 88 | 89 | ```jsx 90 |
91 | ``` 92 | 93 | Result: 94 | 95 | ```html 96 |
foobar
97 | ``` 98 | 99 | 100 | ## DOM Element Attributes 101 | 102 | Sets attributes of DOM elements. 103 | 104 | ```jsx 105 |
106 | ``` 107 | 108 | Result: 109 | 110 | ```html 111 |
112 | ``` 113 | 114 | 115 | ## Native DOM Events 116 | 117 | Add listeners to native DOM events. 118 | 119 | ```jsx 120 | 121 | ``` 122 | 123 | 124 | ## Micro Life-cycles 125 | 126 | Add micro life-cycles to React DOM string elements. 127 | 128 | ```jsx 129 |
console.log('element attached: ', el, props)} 131 | $update={(el, props, oldProps) => console.log('element updated: ', el, props, oldProps)} 132 | $detach={(el, oldProps) => console.log('element detached: ', el, oldProps)} 133 | /> 134 | ``` 135 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jsx-plus-plus", 3 | "version": "0.1.0", 4 | "description": "Better JSX for busy developers", 5 | "main": "lib/patch.js", 6 | "scripts": { 7 | "start": "npm run storybook", 8 | "clean": "rimraf lib", 9 | "build": "babel src --out-dir lib", 10 | "test": "jest", 11 | "test:coverage": "jest --coverage", 12 | "storybook": "start-storybook -p 6006", 13 | "build-storybook": "build-storybook", 14 | "prettier": "prettier --write '**/*.js'", 15 | "precommit": "lint-staged" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "https://github.com/streamich/jsx-plus-plus.git" 20 | }, 21 | "dependencies": { 22 | "nano-css": "^2.0.0", 23 | "classnames": "^2.2.5", 24 | "react-micro-lifecycles": "^1.0.0" 25 | }, 26 | "devDependencies": { 27 | "@storybook/addon-actions": "9.0.3", 28 | "@storybook/addon-links": "9.0.3", 29 | "@storybook/addons": "7.6.17", 30 | "@storybook/react": "9.0.3", 31 | "babel-cli": "6.26.0", 32 | "babel-core": "6.26.3", 33 | "babel-polyfill": "6.26.0", 34 | "babel-preset-es2015": "6.24.1", 35 | "babel-preset-es2016": "6.24.1", 36 | "babel-preset-es2017": "6.24.1", 37 | "babel-preset-flow": "6.23.0", 38 | "babel-preset-stage-0": "6.24.1", 39 | "jest": "29.7.0", 40 | "jest-tap-reporter": "1.9.0", 41 | "prettier": "3.5.3", 42 | "react": "19.1.0", 43 | "react-dom": "19.1.0", 44 | "rimraf": "6.0.1", 45 | "lint-staged": "16.1.0", 46 | "mol-conventional-changelog": "2.0.0", 47 | "nano-css": "2.2.0" 48 | }, 49 | "lint-staged": { 50 | "**/*.js": [ 51 | "prettier --write", 52 | "git add" 53 | ] 54 | }, 55 | "prettier": { 56 | "printWidth": 120, 57 | "tabWidth": 4, 58 | "useTabs": false, 59 | "semi": true, 60 | "singleQuote": true, 61 | "trailingComma": "es5", 62 | "bracketSpacing": false, 63 | "jsxBracketSameLine": false 64 | }, 65 | "jest": { 66 | "transformIgnorePatterns": [], 67 | "testRegex": ".*/__tests__/.*\\.(test|spec)\\.(jsx?)$", 68 | "setupFiles": [ 69 | "./src/__tests__/setup.js" 70 | ], 71 | "moduleFileExtensions": [ 72 | "js", 73 | "jsx", 74 | "json" 75 | ], 76 | "reporters": [ 77 | "jest-tap-reporter" 78 | ] 79 | }, 80 | "babel": { 81 | "presets": [ 82 | "es2015", 83 | "es2016", 84 | "es2017", 85 | "stage-0", 86 | "flow" 87 | ], 88 | "comments": false 89 | }, 90 | "config": { 91 | "commitizen": { 92 | "path": "./node_modules/mol-conventional-changelog" 93 | } 94 | }, 95 | "keywords": [ 96 | "jsx", 97 | "jsxpp", 98 | "jsx-plus-plus", 99 | "jsx++", 100 | "better-jsx", 101 | "hyperscript", 102 | "react", 103 | "h", 104 | "attributes", 105 | "dom-props", 106 | "native-events", 107 | "css", 108 | "styles" 109 | ] 110 | } 111 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ], 5 | "automerge": true, 6 | "pinVersions": false, 7 | "major": { 8 | "automerge": false 9 | }, 10 | "devDependencies": { 11 | "automerge": true, 12 | "pinVersions": true 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/__tests__/index.test.js: -------------------------------------------------------------------------------- 1 | describe('works', () => { 2 | it('runs', () => {}); 3 | }); -------------------------------------------------------------------------------- /src/__tests__/setup.js: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = 'production'; 2 | -------------------------------------------------------------------------------- /src/applyPlugins.js: -------------------------------------------------------------------------------- 1 | const applyPlugins = (h, plugins) => { 2 | return (...args) => { 3 | const type = args[0]; 4 | const props = args[1]; 5 | 6 | if (props && (typeof type === 'string')) { 7 | for (let i = 0; i < plugins.length; i++) 8 | args = plugins[i](args); 9 | } 10 | 11 | return h(...args); 12 | }; 13 | }; 14 | 15 | export default applyPlugins; 16 | -------------------------------------------------------------------------------- /src/patch.js: -------------------------------------------------------------------------------- 1 | import createHyperscriptStable from 'react-micro-lifecycles/lib/createHyperscriptStable'; 2 | import React from 'react'; 3 | import applyPlugins from './applyPlugins'; 4 | import classnames from './plugins/classnames'; 5 | import dom from './plugins/dom'; 6 | import attr from './plugins/attr'; 7 | import prefixer from './plugins/prefixer'; 8 | import css from './plugins/css'; 9 | import on from './plugins/on'; 10 | 11 | const plugins = [ 12 | prefixer, 13 | classnames, 14 | dom, 15 | attr, 16 | css, 17 | on, 18 | ]; 19 | 20 | var h = React.createElement; 21 | 22 | h = createHyperscriptStable(h, React.Component); 23 | h = applyPlugins(h, plugins); 24 | 25 | React.createElement = h; 26 | -------------------------------------------------------------------------------- /src/plugins/attr.js: -------------------------------------------------------------------------------- 1 | const plugin = (args) => { 2 | const props = args[1]; 3 | 4 | if (!props) return args; 5 | 6 | const {$attr} = props; 7 | 8 | if (!$attr) return args; 9 | 10 | delete props.$attr; 11 | 12 | if (process.env.NODE_ENV !== 'production') { 13 | if (typeof $attr !== 'object') { 14 | console.error( 15 | `JSX++ $attr plugin expected $attr prop to be an object, received "${typeof $attr}".` 16 | ); 17 | } 18 | } 19 | 20 | const {$attach, $update, $detach} = props; 21 | 22 | props.$attach = (el, props) => { 23 | if ($attach) $attach(el, props); 24 | 25 | for (const prop in $attr) 26 | el.setAttribute(prop, $attr[prop]); 27 | }; 28 | 29 | props.$update = (el, props, oldProps) => { 30 | if ($update) $update(el, props, oldProps); 31 | 32 | for (const prop in $attr) 33 | el.setAttribute(prop, $attr[prop]); 34 | 35 | const oldAtts = oldProps.$attr || {}; 36 | 37 | for (const prop in oldAttrs) { 38 | if (!(prop in $attr)) { 39 | el.removeAttribute(prop); 40 | } 41 | } 42 | }; 43 | 44 | props.$detach = (el, oldProps) => { 45 | if ($detach) $detach(el, oldProps); 46 | 47 | const oldAttrs = oldProps.$attr || {}; 48 | 49 | for (const prop in oldAttrs) { 50 | el.removeAttribute(prop); 51 | } 52 | }; 53 | 54 | return args; 55 | }; 56 | 57 | export default plugin; 58 | -------------------------------------------------------------------------------- /src/plugins/classnames.js: -------------------------------------------------------------------------------- 1 | import cx from 'classnames'; 2 | 3 | const plugin = (args) => { 4 | const props = args[1]; 5 | 6 | if (!props) return args; 7 | 8 | let className = props.className || props.class; 9 | 10 | delete props.class; 11 | 12 | if (className) { 13 | className = cx(className); 14 | props.className = className; 15 | } 16 | 17 | return args; 18 | }; 19 | 20 | export default plugin; 21 | -------------------------------------------------------------------------------- /src/plugins/css.js: -------------------------------------------------------------------------------- 1 | import {create} from 'nano-css'; 2 | import {addon as addonRule} from 'nano-css/addon/rule'; 3 | import {addon as addonPipe} from 'nano-css/addon/pipe'; 4 | 5 | const nano = create({ 6 | pfx: 'jsxpp-' 7 | }); 8 | 9 | addonRule(nano); 10 | addonPipe(nano); 11 | 12 | const pipes = new WeakMap; 13 | 14 | 15 | const plugin = (args) => { 16 | const props = args[1]; 17 | 18 | if (!props) return args; 19 | 20 | const {$css} = props; 21 | 22 | if (!$css) return args; 23 | 24 | delete props.$css; 25 | 26 | if (process.env.NODE_ENV !== 'production') { 27 | if (typeof $css !== 'object') { 28 | console.error( 29 | `JSX++ $css plugin expected $css prop to be an object, received "${typeof $css}".` 30 | ); 31 | } 32 | } 33 | 34 | const {$attach, $update, $detach} = props; 35 | 36 | props.$attach = (el, props) => { 37 | if ($attach) $attach(el, props); 38 | 39 | const pipe = nano.pipe(); 40 | 41 | pipes.set(el, pipe); 42 | 43 | const self = {}; 44 | let added = false; 45 | 46 | for (const prop in $css) { 47 | const value = $css[prop]; 48 | 49 | if (typeof value !== 'object') { 50 | added = true; 51 | self[prop] = value; 52 | } 53 | } 54 | 55 | if (added) { 56 | $css['&'] = Object.assign($css['&'] || {}, self); 57 | } 58 | 59 | pipe.css($css); 60 | el.setAttribute(pipe.attr, ''); 61 | }; 62 | 63 | props.$update = (el, props, oldProps) => { 64 | if ($update) $update(el, props, oldProps); 65 | 66 | let pipe = pipes.get(el); 67 | 68 | if (!pipe) { 69 | pipe = nano.pipe(); 70 | pipes.set(el, pipe); 71 | el.setAttribute(pipe.attr, ''); 72 | } 73 | 74 | const self = {}; 75 | let added = false; 76 | 77 | for (const prop in $css) { 78 | const value = $css[prop]; 79 | 80 | if (typeof value !== 'object') { 81 | added = true; 82 | self[prop] = value; 83 | } 84 | } 85 | 86 | if (added) { 87 | $css['&'] = Object.assign($css['&'] || {}, self); 88 | } 89 | 90 | pipe.css($css); 91 | }; 92 | 93 | props.$detach = (el, oldProps) => { 94 | if ($detach) $detach(el, oldProps); 95 | 96 | const pipe = pipes.get(el); 97 | 98 | pipes.delete(el); 99 | 100 | if (pipe) { 101 | el.removeAttribute(pipe.attr); 102 | pipe.remove(); 103 | } 104 | }; 105 | 106 | return args; 107 | }; 108 | 109 | export default plugin; 110 | -------------------------------------------------------------------------------- /src/plugins/dom.js: -------------------------------------------------------------------------------- 1 | const plugin = (args) => { 2 | const props = args[1]; 3 | 4 | if (!props) return args; 5 | 6 | const {$dom} = props; 7 | 8 | if (!$dom) return args; 9 | 10 | delete props.$dom; 11 | 12 | if (process.env.NODE_ENV !== 'production') { 13 | if (typeof $dom !== 'object') { 14 | console.error( 15 | `JSX++ $dom plugin expected $dom prop to be an object, received "${typeof $dom}".` 16 | ); 17 | } 18 | } 19 | 20 | const {$attach, $update, $detach} = props; 21 | 22 | props.$attach = (el, props) => { 23 | if ($attach) $attach(el, props); 24 | 25 | for (const prop in $dom) 26 | el[prop] = $dom[prop]; 27 | }; 28 | 29 | props.$update = (el, props, oldProps) => { 30 | if ($update) $update(el, props, oldProps); 31 | 32 | for (const prop in $dom) 33 | el[prop] = $dom[prop]; 34 | 35 | const oldDom = (oldProps || {}).$dom || {}; 36 | 37 | for (const prop in oldProps) { 38 | if (!(prop in $dom)) { 39 | delete el[prop]; 40 | } 41 | } 42 | }; 43 | 44 | props.$detach = (el, oldProps) => { 45 | if ($detach) $detach(el, oldProps); 46 | 47 | const oldDom = (oldProps || {}).$dom || {}; 48 | 49 | for (const prop in oldProps) { 50 | delete el[prop]; 51 | } 52 | }; 53 | 54 | return args; 55 | }; 56 | 57 | export default plugin; 58 | -------------------------------------------------------------------------------- /src/plugins/on.js: -------------------------------------------------------------------------------- 1 | const noop = () => {}; 2 | const mapListeners = new WeakMap; 3 | const mapOn = new WeakMap; 4 | 5 | const plugin = (args) => { 6 | const props = args[1]; 7 | 8 | if (!props) return args; 9 | 10 | const {$on} = props; 11 | 12 | if (!$on) return args; 13 | 14 | delete props.$on; 15 | 16 | if (process.env.NODE_ENV !== 'production') { 17 | if (typeof $on !== 'object') { 18 | console.error( 19 | `JSX++ $on plugin expected $on prop to be an object, received "${typeof $on}".` 20 | ); 21 | } 22 | } 23 | 24 | const {$attach, $update, $detach} = props; 25 | 26 | props.$attach = (el, props) => { 27 | if ($attach) $attach(el, props); 28 | 29 | mapOn.set(el, $on); 30 | 31 | let listeners = mapListeners.get(el); 32 | 33 | if (!listeners) { 34 | listeners = {}; 35 | mapListeners.set(el, listeners); 36 | } 37 | 38 | for (const prop in $on) { 39 | const listener = function () { 40 | const on = mapOn.get(el); 41 | 42 | (on[prop] || noop).apply(this, arguments); 43 | }; 44 | 45 | listeners[prop] = listener; 46 | el.addEventListener(prop, listener); 47 | } 48 | }; 49 | 50 | props.$update = (el, props, oldProps) => { 51 | if ($update) $update(el, props, oldProps); 52 | 53 | mapOn.set(el, $on); 54 | 55 | let listeners = mapListeners.get(el); 56 | 57 | if (!listeners) { 58 | listeners = {}; 59 | mapListeners.set(el, listeners); 60 | } 61 | 62 | for (const prop in $on) { 63 | if (!(prop in listeners)) { 64 | const listener = function () { 65 | const on = mapOn.get(el); 66 | 67 | (on[prop] || noop).apply(this, arguments); 68 | }; 69 | 70 | listeners[prop] = listener; 71 | el.addEventListener(prop, listener); 72 | } 73 | } 74 | 75 | for (const prop in listeners) { 76 | if (!(prop in $on)) { 77 | el.removeEventListener(prop, listeners[prop]); 78 | } 79 | } 80 | }; 81 | 82 | props.$detach = (el, oldProps) => { 83 | if ($detach) $detach(el, props); 84 | 85 | const listeners = mapListeners.get(el) || {}; 86 | 87 | mapListeners.delete(el); 88 | 89 | for (const prop in listeners) { 90 | el.removeEventListener(prop, listeners[prop]); 91 | } 92 | }; 93 | 94 | return args; 95 | }; 96 | 97 | export default plugin; 98 | -------------------------------------------------------------------------------- /src/plugins/prefixer.js: -------------------------------------------------------------------------------- 1 | import Prefixer from 'inline-style-prefixer' 2 | 3 | const prefixer = new Prefixer(); 4 | 5 | const plugin = (args) => { 6 | const props = args[1]; 7 | 8 | if (props && props.style) { 9 | props.style = prefixer.prefix(props.style); 10 | } 11 | 12 | return args; 13 | }; 14 | 15 | export default plugin; 16 | --------------------------------------------------------------------------------