styled-jsx
Advanced tools
Comparing version 0.0.7 to 0.1.0
@@ -7,4 +7,8 @@ 'use strict'; | ||
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); | ||
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); // Packages | ||
// Ours | ||
exports.default = function (_ref) { | ||
@@ -33,11 +37,8 @@ var t = _ref.types; | ||
if (state.ignoreClosing == null) { | ||
// this flag has a two-fold purpose: | ||
// - ignore the opening tag of the parent element | ||
// of the style tag, since we don't want to add | ||
// the attribute to that one | ||
// - keep a counter of elements inside so that we | ||
// can keep track of when we exit the parent | ||
// to reset state | ||
state.ignoreClosing = 1; | ||
return; | ||
// we keep a counter of elements inside so that we | ||
// can keep track of when we exit the parent to reset state | ||
// note: if we wished to add an option to turn off | ||
// selectors to reach parent elements, it would suffice to | ||
// set this to `1` and do an early return instead | ||
state.ignoreClosing = 0; | ||
} | ||
@@ -93,2 +94,3 @@ | ||
state.styles = []; | ||
var _iteratorNormalCompletion2 = true; | ||
@@ -102,7 +104,14 @@ var _didIteratorError2 = false; | ||
if (style.children.length !== 1) { | ||
throw path.buildCodeFrameError('Expected a child under ' + ('JSX Style tag, but got ' + style.children.length + ' ') + '(eg: <style jsx>{`hi`}</style>)'); | ||
// compute children excluding whitespace | ||
var children = style.children.filter(function (c) { | ||
return t.isJSXExpressionContainer(c) || | ||
// ignore whitespace around the expression container | ||
t.isJSXText(c) && c.value.trim() !== ''; | ||
}); | ||
if (children.length !== 1) { | ||
throw path.buildCodeFrameError('Expected one child under ' + ('JSX Style tag, but got ' + style.children.length + ' ') + '(eg: <style jsx>{`hi`}</style>)'); | ||
} | ||
var child = style.children[0]; | ||
var child = children[0]; | ||
@@ -121,2 +130,3 @@ if (!t.isJSXExpressionContainer(child)) { | ||
var styleId = String((0, _murmurhash2.default)(styleText)); | ||
state.styles.push([styleId, styleText]); | ||
@@ -158,3 +168,7 @@ } | ||
path.replaceWith(t.JSXExpressionContainer(t.callExpression(t.identifier(INJECT_METHOD), [t.stringLiteral(id), t.stringLiteral((0, _styleTransform2.default)(id, css))]))); | ||
var skipTransform = el.attributes.some(function (attr) { | ||
return attr.name.name === GLOBAL_ATTRIBUTE; | ||
}); | ||
path.replaceWith(t.JSXElement(t.JSXOpeningElement(t.JSXIdentifier(STYLE_COMPONENT), [t.JSXAttribute(t.JSXIdentifier(STYLE_COMPONENT_CSS), t.JSXExpressionContainer(t.stringLiteral(skipTransform ? css : (0, _styleTransform2.default)(id, css))))], true), null, [])); | ||
} | ||
@@ -166,2 +180,3 @@ } | ||
state.hasJSXStyle = null; | ||
state.skipTransform = false; | ||
} | ||
@@ -178,7 +193,7 @@ } | ||
if (!(state.file.hasJSXStyle && !scope.hasBinding(INJECT_METHOD))) { | ||
if (!(state.file.hasJSXStyle && !scope.hasBinding(STYLE_COMPONENT))) { | ||
return; | ||
} | ||
var importDeclaration = t.importDeclaration([t.importDefaultSpecifier(t.identifier(INJECT_METHOD))], t.stringLiteral('styled-jsx/inject')); | ||
var importDeclaration = t.importDeclaration([t.importDefaultSpecifier(t.identifier(STYLE_COMPONENT))], t.stringLiteral('styled-jsx/style')); | ||
@@ -207,3 +222,5 @@ node.body.unshift(importDeclaration); | ||
var STYLE_ATTRIBUTE = 'jsx'; | ||
var GLOBAL_ATTRIBUTE = 'global'; | ||
var MARKUP_ATTRIBUTE = 'data-jsx'; | ||
var INJECT_METHOD = '_jsxStyleInject'; | ||
var STYLE_COMPONENT = '_JSXStyle'; | ||
var STYLE_COMPONENT_CSS = 'css'; |
@@ -27,2 +27,2 @@ 'use strict'; | ||
return ret; | ||
} | ||
} // Ours |
@@ -14,3 +14,4 @@ 'use strict'; | ||
var isBrowser = typeof window !== 'undefined'; | ||
var isBrowser = typeof window !== 'undefined'; // Ours | ||
var tags = {}; | ||
@@ -23,2 +24,3 @@ | ||
var el = makeStyleTag(css); | ||
tags[id] = el; | ||
@@ -35,7 +37,10 @@ _memory2.default[id] = el; | ||
var tag = document.createElement('style'); | ||
tag.type = 'text/css'; | ||
tag.appendChild(document.createTextNode(str)); | ||
var head = document.head || document.getElementsByTagName('head')[0]; | ||
head.appendChild(tag); | ||
return tag; | ||
} |
@@ -181,12 +181,91 @@ // based on Stylis (MIT) | ||
for (var j = 0, length = split.length; j < length; j++) { | ||
var selector = split[j]; | ||
var _last = selector[selector.length - 1] | ||
var affix = ''; | ||
var selector = split[j].trim(); | ||
var isLast = selector[selector.length - 1] === '{'; | ||
if (isLast) { | ||
// trim { | ||
selector = selector.substr(0, selector.length - 1); | ||
} | ||
if (_last === '{') { | ||
_line += selector | ||
.substring(0, selector.length - 1) | ||
.trim() + suffix + _last; | ||
var piece = '' | ||
var inGlobal = false | ||
var inSubSelector = false | ||
var inQuotes = false | ||
var quoteChar = null | ||
for (var k = 0; k < selector.length; k++) { | ||
var chr = selector[k] | ||
if (inQuotes) { | ||
if (chr === quoteChar) { | ||
inQuotes = false | ||
quoteChar = null | ||
} | ||
piece += chr | ||
continue | ||
} else { | ||
var prev = selector[k-1] | ||
if ((chr === '"' || chr === "'") && prev !== '\\') { | ||
inQuotes = true | ||
quoteChar = chr | ||
piece += chr | ||
continue | ||
} else { | ||
if (inGlobal) { | ||
if (inSubSelector) { | ||
if (')' === chr) { | ||
inSubSelector = false | ||
} | ||
piece += chr | ||
continue | ||
} else { | ||
if (' ' === chr) { | ||
inGlobal = false | ||
// we omit the suffix | ||
_line += piece + ' ' | ||
piece = '' | ||
continue | ||
} else if (')' === chr) { | ||
// ignore this char | ||
continue | ||
} else if ('(' === chr) { | ||
inSubSelector = true | ||
} | ||
piece += chr | ||
continue | ||
} | ||
} else { | ||
// potential beginning of :global() | ||
if (chr === ':' | ||
&& piece === '' | ||
&& selector.substr(k, 8) === ':global(' ) { | ||
inGlobal = true | ||
k += 7 | ||
continue | ||
} | ||
if (chr === ' ') { | ||
if (piece === '') { | ||
// ignore | ||
continue | ||
} else { | ||
_line += piece + suffix + ' ' | ||
piece = '' | ||
} | ||
} else { | ||
piece += chr | ||
} | ||
} | ||
} | ||
} | ||
} | ||
// flush remainder | ||
if (piece.length) { | ||
_line += piece + suffix | ||
} | ||
if (isLast) { | ||
_line += '{' | ||
} else { | ||
_line += selector.trim() + suffix + ','; | ||
_line += ',' | ||
} | ||
@@ -193,0 +272,0 @@ } |
{ | ||
"name": "styled-jsx", | ||
"version": "0.0.7", | ||
"version": "0.1.0", | ||
"license": "MIT", | ||
"repository": "zeit/styled-jsx", | ||
"description": "Full CSS support for JSX without compromises", | ||
"main": "./dist/flush.js", | ||
@@ -12,7 +13,8 @@ "files": [ | ||
"flush.js", | ||
"inject.js", | ||
"memory.js" | ||
"memory.js", | ||
"style.js" | ||
], | ||
"dependencies": { | ||
"babel-plugin-syntax-jsx": "^6.18.0" | ||
"babel-plugin-syntax-jsx": "^6.18.0", | ||
"object.entries": "^1.0.4" | ||
}, | ||
@@ -29,7 +31,11 @@ "devDependencies": { | ||
"babel-register": "^6.18.0", | ||
"fs-promise": "^1.0.0", | ||
"gulp": "^3.9.1", | ||
"gulp-babel": "^6.1.2", | ||
"mz": "^2.6.0", | ||
"react": "^15.4.1", | ||
"xo": "^0.17.1" | ||
}, | ||
"peerDependencies": { | ||
"react": "^15.0" | ||
}, | ||
"babel": { | ||
@@ -45,3 +51,3 @@ "presets": [ | ||
"prepublish": "gulp transpile", | ||
"test": "xo && ava test/styles.js" | ||
"test": "xo && ava" | ||
}, | ||
@@ -48,0 +54,0 @@ "ava": { |
@@ -6,4 +6,5 @@ # styled-jsx | ||
[![Slack Channel](https://zeit-slackin.now.sh/badge.svg)](https://zeit.chat) | ||
[![npm](https://img.shields.io/npm/v/styled-jsx.svg)](https://www.npmjs.com/package/styled-jsx) | ||
Full, scoped and component-friendly CSS support for JSX (SSR + browser). | ||
Full, scoped and component-friendly CSS support for JSX (rendered on the server or the client). | ||
@@ -22,11 +23,9 @@ ## Usage | ||
{ | ||
"babel": { | ||
"plugins": [ | ||
"styled-jsx/babel" | ||
] | ||
} | ||
"plugins": [ | ||
"styled-jsx/babel" | ||
] | ||
} | ||
``` | ||
As the last step, simply include `<style jsx>` in your code: | ||
Now add `<style jsx>` to your code and fill it with CSS: | ||
@@ -61,11 +60,11 @@ ```js | ||
The example above compiles to the following: | ||
The example above transpiles to the following: | ||
```js | ||
import _jsxStyleInject from 'styled-jsx/inject' | ||
import _JSXStyle from 'styled-jsx/style' | ||
export default () => ( | ||
<div> | ||
<div data-jsx='cn2o3j'> | ||
<p data-jsx='cn2o3j'>only this paragraph will get the style :O</p> | ||
{ _jsxStyleInject('cn2o3j', `p[data-jsx=cn2o3j] {color: red;}`) } | ||
<_JSXStyle data-jsx='cn2o3j' css={`p[data-jsx=cn2o3j] {color: red;}`} /> | ||
</div> | ||
@@ -77,11 +76,79 @@ ) | ||
Data attributes give us style encapsulation and `_jsxStyleInject` is heavily optimized for: | ||
Data attributes give us style encapsulation and `_JSXStyle` is heavily optimized for: | ||
- Injecting styles upon render | ||
- Only injecting a certain component's style once (even if the component is included multiple times) | ||
- Removing unused styles | ||
- Keeping track of styles for server-side rendering (discussed in the next section) | ||
### Targetting The Root | ||
Notice that the parent `<div>` above also gets a `data-jsx` atribute. We do this so that | ||
you can target the "root" element, in the same manner that | ||
[`:host`](https://www.html5rocks.com/en/tutorials/webcomponents/shadowdom-201/#toc-style-host) works with Shadow DOM. | ||
If you want to target _only_ the host, we suggest you use a class: | ||
```js | ||
export default () => ( | ||
<div className="root"> | ||
<style jsx>{` | ||
.root { | ||
color: green; | ||
} | ||
`}</style> | ||
</div> | ||
) | ||
``` | ||
### Global styles | ||
To skip scoping entirely, you can make the global-ness of your styles | ||
explicit by adding _global_. | ||
```js | ||
export default () => ( | ||
<div> | ||
<style jsx global>{` | ||
body { | ||
background: red | ||
} | ||
`}</style> | ||
</div> | ||
) | ||
``` | ||
The advantage of using this over `<style>` is twofold: no need | ||
to use `dangerouslySetInnerHTML` to avoid escaping issues with CSS | ||
and take advantage of `styled-jsx`'s de-duping system to avoid | ||
the global styles being inserted multiple times. | ||
### Global selectors | ||
Sometimes it's useful to skip prefixing. We support `:global()`, | ||
inspired by [css-modules](https://github.com/css-modules/css-modules). | ||
This is very useful in order to, for example, generate an *unprefixed class* that | ||
you can pass to 3rd-party components. For example, to style | ||
`react-select` which supports passing a custom class via `optionClassName`: | ||
```js | ||
import Select from 'react-select' | ||
export default () => ( | ||
<div> | ||
<Select optionClassName="react-select" /> | ||
<style jsx>{` | ||
/* "div" will be prefixed, but ".react-select" won't */ | ||
div :global(.react-select) { | ||
color: red | ||
} | ||
`}</style> | ||
</div> | ||
) | ||
``` | ||
## Server-Side Rendering | ||
In the server rendering pipeline, you can obtain the entire CSS text of all the combined components by invoking `flush`: | ||
In the server rendering pipeline, you can obtain the entire CSS of all components by invoking `flush`: | ||
@@ -88,0 +155,0 @@ ```js |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
40121
15
756
183
3
14
1
+ Addedobject.entries@^1.0.4
+ Addedasap@2.0.6(transitive)
+ Addedcall-bind@1.0.7(transitive)
+ Addedcore-js@1.2.7(transitive)
+ Addedcreate-react-class@15.7.0(transitive)
+ Addeddefine-data-property@1.1.4(transitive)
+ Addeddefine-properties@1.2.1(transitive)
+ Addedencoding@0.1.13(transitive)
+ Addedes-define-property@1.0.0(transitive)
+ Addedes-errors@1.3.0(transitive)
+ Addedes-object-atoms@1.0.0(transitive)
+ Addedfbjs@0.8.18(transitive)
+ Addedfunction-bind@1.1.2(transitive)
+ Addedget-intrinsic@1.2.4(transitive)
+ Addedgopd@1.0.1(transitive)
+ Addedhas-property-descriptors@1.0.2(transitive)
+ Addedhas-proto@1.0.3(transitive)
+ Addedhas-symbols@1.0.3(transitive)
+ Addedhasown@2.0.2(transitive)
+ Addediconv-lite@0.6.3(transitive)
+ Addedis-stream@1.1.0(transitive)
+ Addedisomorphic-fetch@2.2.1(transitive)
+ Addedjs-tokens@4.0.0(transitive)
+ Addedloose-envify@1.4.0(transitive)
+ Addednode-fetch@1.7.3(transitive)
+ Addedobject-assign@4.1.1(transitive)
+ Addedobject-keys@1.1.1(transitive)
+ Addedobject.entries@1.1.8(transitive)
+ Addedpromise@7.3.1(transitive)
+ Addedprop-types@15.8.1(transitive)
+ Addedreact@15.7.0(transitive)
+ Addedreact-is@16.13.1(transitive)
+ Addedsafer-buffer@2.1.2(transitive)
+ Addedset-function-length@1.2.2(transitive)
+ Addedsetimmediate@1.0.5(transitive)
+ Addedua-parser-js@0.7.39(transitive)
+ Addedwhatwg-fetch@3.6.20(transitive)