From 9a2742e7efc613f7f580d86b2ee73465e316b773 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Thu, 22 Jul 2021 23:39:46 +0800 Subject: [PATCH] contextual styles --- index.js | 1 + package.json | 2 +- readme.md | 388 ++++++++++++++++--------------- server.js | 1 - src/index.js | 1 + src/server.js | 29 --- src/style.js | 22 +- src/stylesheet-registry.js | 51 +++- test/index.js | 145 +++++++++--- test/snapshots/attribute.js.snap | Bin 1528 -> 1509 bytes test/snapshots/external.js.snap | Bin 1809 -> 1806 bytes test/snapshots/index.js.snap | Bin 3391 -> 3387 bytes test/snapshots/plugins.js.snap | Bin 601 -> 599 bytes test/stylesheet-registry.js | 2 +- 14 files changed, 374 insertions(+), 268 deletions(-) create mode 100644 index.js delete mode 100644 server.js create mode 100644 src/index.js delete mode 100644 src/server.js diff --git a/index.js b/index.js new file mode 100644 index 00000000..2d2f3c0b --- /dev/null +++ b/index.js @@ -0,0 +1 @@ +module.exports = require('./dist') diff --git a/package.json b/package.json index c1ff298d..a3e2692e 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "build": "babel src --out-dir dist", "test": "ava", "lint": "xo", - "prepublishOnly": "yarn build && yarn test && yarn lint --quiet" + "prepublishOnly": "rm -rf dist && yarn build" }, "husky": { "hooks": { diff --git a/readme.md b/readme.md index cd5f80ff..524943e6 100644 --- a/readme.md +++ b/readme.md @@ -11,38 +11,37 @@ Code and docs are for v3 which we highly recommend you to try. Looking for style - [Getting started](#getting-started) - [Configuration options](#configuration-options) - * [`optimizeForSpeed`](#optimizeforspeed) - * [`sourceMaps`](#sourcemaps) - * [`styleModule`](#stylemodule) - * [`vendorPrefixes`](#vendorprefixes) + - [`optimizeForSpeed`](#optimizeforspeed) + - [`sourceMaps`](#sourcemaps) + - [`styleModule`](#stylemodule) + - [`vendorPrefixes`](#vendorprefixes) - [Features](#features) - [How It Works](#how-it-works) - * [Why It Works Like This](#why-it-works-like-this) + - [Why It Works Like This](#why-it-works-like-this) - [Targeting The Root](#targeting-the-root) - [Global styles](#global-styles) - * [One-off global selectors](#one-off-global-selectors) + - [One-off global selectors](#one-off-global-selectors) - [Dynamic styles](#dynamic-styles) - * [Via interpolated dynamic props](#via-interpolated-dynamic-props) - * [Via `className` toggling](#via-classname-toggling) - * [Via inline `style`](#via-inline-style) + - [Via interpolated dynamic props](#via-interpolated-dynamic-props) + - [Via `className` toggling](#via-classname-toggling) + - [Via inline `style`](#via-inline-style) - [Constants](#constants) - [Server-Side Rendering](#server-side-rendering) - * [`styled-jsx/server`](#styled-jsxserver) - [External CSS and styles outside of the component](#external-css-and-styles-outside-of-the-component) - * [External styles](#external-styles) - * [Styles outside of components](#styles-outside-of-components) - * [The `resolve` tag](#the-resolve-tag) - * [Styles in regular CSS files](#styles-in-regular-css-files) + - [External styles](#external-styles) + - [Styles outside of components](#styles-outside-of-components) + - [The `resolve` tag](#the-resolve-tag) + - [Styles in regular CSS files](#styles-in-regular-css-files) - [CSS Preprocessing via Plugins](#css-preprocessing-via-plugins) - * [Plugin options](#plugin-options) - * [Example plugins](#example-plugins) + - [Plugin options](#plugin-options) + - [Example plugins](#example-plugins) - [Rendering in tests](#rendering-in-tests) - [FAQ](#faq) - * [Warning: unknown `jsx` prop on <style> tag](#warning-unknown-jsx-prop-on-style-tag) - * [Can I return an array of components when using React 16?](#can-i-return-an-array-of-components-when-using-react-16) - * [Styling third parties / child components from the parent](#styling-third-parties--child-components-from-the-parent) - * [Some styles are missing in production](https://github.com/zeit/styled-jsx/issues/319#issuecomment-349239326) - * [Build a component library with styled-jsx](#build-a-component-library-with-styled-jsx) + - [Warning: unknown `jsx` prop on <style> tag](#warning-unknown-jsx-prop-on-style-tag) + - [Can I return an array of components when using React 16?](#can-i-return-an-array-of-components-when-using-react-16) + - [Styling third parties / child components from the parent](#styling-third-parties--child-components-from-the-parent) + - [Some styles are missing in production](https://github.com/zeit/styled-jsx/issues/319#issuecomment-349239326) + - [Build a component library with styled-jsx](#build-a-component-library-with-styled-jsx) - [Syntax Highlighting](#syntax-highlighting) ## Getting started @@ -57,9 +56,7 @@ Next, add `styled-jsx/babel` to `plugins` in your babel configuration: ```json { - "plugins": [ - "styled-jsx/babel" - ] + "plugins": ["styled-jsx/babel"] } ``` @@ -70,8 +67,8 @@ export default () => (

only this paragraph will get the style :)

- { /* you can include s here that include - other

s that don't get unexpected styles! */ } + {/* you can include s here that include + other

s that don't get unexpected styles! */}

@@ -198,7 +193,7 @@ the global styles being inserted multiple times. Sometimes it's useful to skip selectors scoping. In order to get a one-off global selector we support `:global()`, inspired by [css-modules](https://github.com/css-modules/css-modules). -This is very useful in order to, for example, generate a *global class* that +This is very useful in order to, for example, generate a _global class_ that you can pass to 3rd-party components. For example, to style `react-select` which supports passing a custom class via `optionClassName`: @@ -212,7 +207,7 @@ export default () => ( /* "div" will be prefixed, but ".react-select" won't */ div :global(.react-select) { - color: red + color: red; } `} @@ -228,18 +223,18 @@ To make a component's visual representation customizable from the outside world Any value that comes from the component's `render` method scope is treated as dynamic. This makes it possible to use `props` and `state` for example. ```jsx -const Button = (props) => ( +const Button = props => ( ) ``` @@ -249,22 +244,22 @@ New styles' injection is optimized to perform well at runtime. That said when your CSS is mostly static we recommend to split it up in static and dynamic styles and use two separate `style` tags so that, when changing, only the dynamic parts are recomputed/rendered. ```jsx -const Button = (props) => ( +const Button = props => ( ) ``` @@ -274,19 +269,19 @@ const Button = (props) => ( The second option is to pass properties that toggle class names. ```jsx -const Button = (props) => ( - ) ``` @@ -302,14 +297,14 @@ Imagine that you wanted to make the padding in the button above completely custo ```jsx const Button = ({ padding, children }) => ( ) ``` @@ -326,14 +321,14 @@ import { invertColor } from '../theme/utils' const Button = ({ children }) => ( ) ``` @@ -342,48 +337,31 @@ Please keep in mind that constants defined outside of the component scope are tr ## Server-Side Rendering -### `styled-jsx/server` - -The main export flushes your styles to an array of `React.Element`: - ```jsx import React from 'react' import ReactDOM from 'react-dom/server' -import flush from 'styled-jsx/server' +import { StyleRegistry, useStyles } from 'styled-jsx' import App from './app' -export default (req, res) => { - const app = ReactDOM.renderToString() - const styles = flush() - const html = ReactDOM.renderToStaticMarkup( - { styles } - -
- - ) - res.end('' + html) +function Head() { + const registry = useStyleRegistry() + const styles = registry.styles() + return {styles} } -``` - -We also expose `flushToHTML` to return generated HTML: - -```jsx -import React from 'react' -import ReactDOM from 'react-dom/server' -import { flushToHTML } from 'styled-jsx/server' -import App from './app' export default (req, res) => { const app = ReactDOM.renderToString() - const styles = flushToHTML() - const html = ` - - ${styles} - -
${app}
- - ` - res.end(html) + const html = ReactDOM.renderToStaticMarkup( + + + + +
+ + + + ) + res.end('' + html) } ``` @@ -396,6 +374,7 @@ duplicate styles are avoided. Strict [CSP](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) is supported. You should generate a nonce **per request**. + ```js import nanoid from 'nanoid' @@ -411,9 +390,9 @@ Your CSP policy must share the same nonce as well (the header nonce needs to mat In styled-jsx styles can be defined outside of the component's render method or in separate JavaScript modules using the `styled-jsx/css` library. `styled-jsx/css` exports three tags that can be used to tag your styles: -* `css`, the default export, to define scoped styles. -* `css.global` to define global styles. -* `css.resolve` to define scoped styles that resolve to the scoped `className` and a `styles` element. +- `css`, the default export, to define scoped styles. +- `css.global` to define global styles. +- `css.resolve` to define scoped styles that resolve to the scoped `className` and a `styles` element. #### External styles @@ -424,7 +403,11 @@ In an external file: import css from 'styled-jsx/css' // Scoped styles -export const button = css`button { color: hotpink; }` +export const button = css` + button { + color: hotpink; + } +` // Global styles export const body = css.global`body { margin: 0; }` @@ -435,7 +418,11 @@ export const link = css.resolve`a { color: green; }` // link.styles -> styles element to render inside of your component // Works also with default exports -export default css`div { color: green; }` +export default css` + div { + color: green; + } +` ``` You can then import and use those styles: @@ -448,7 +435,9 @@ export default () => ( - +
) ``` @@ -478,7 +467,11 @@ export default () => (
) -const button = css`button { color: hotpink; }` +const button = css` + button { + color: hotpink; + } +` ``` Like in externals styles `css` doesn't work with dynamic styles. If you have dynamic parts you might want to place them inline inside of your component using a regular ` + {alt} + ) ``` @@ -900,7 +906,7 @@ export default () => ( /* "div" will be prefixed, but ".nested-element" won't */ div > :global(.nested-element) { - color: red + color: red; } `} @@ -917,7 +923,7 @@ There's an [article](https://medium.com/@tomaszmularczyk89/guide-to-building-a-r When working with template literals a common drawback is missing syntax highlighting. The following editors currently have support for highlighting CSS inside ` + {children} + + {/*language=CSS*/} + ) ``` ### Emmet - If you're using Emmet you can add the following snippet to `~/emmet/snippets-styledjsx.json` This will allow you to expand `style-jsx` to a styled-jsx block. +If you're using Emmet you can add the following snippet to `~/emmet/snippets-styledjsx.json` This will allow you to expand `style-jsx` to a styled-jsx block. - ```json - { +```json +{ "html": { "snippets": { "style-jsx": "" @@ -974,18 +980,23 @@ const Button = ({ children }) => ( ``` ### Syntax Highlighting [Visual Studio Code Extension](https://marketplace.visualstudio.com/items?itemName=Divlo.vscode-styled-jsx-syntax) + Launch VS Code Quick Open (⌘+P), paste the following command, and press enter. + ``` ext install Divlo.vscode-styled-jsx-syntax ``` If you use Stylus instead of plain CSS, install [vscode-styled-jsx-stylus](https://marketplace.visualstudio.com/items?itemName=samuelroy.vscode-styled-jsx-stylus) or paste the command below. + ``` ext install vscode-styled-jsx-stylus ``` ### Autocomplete [Visual Studio Code Extension](https://marketplace.visualstudio.com/items?itemName=Divlo.vscode-styled-jsx-languageserver) + Launch VS Code Quick Open (⌘+P), paste the following command, and press enter. + ``` ext install Divlo.vscode-styled-jsx-languageserver ``` @@ -995,6 +1006,7 @@ ext install Divlo.vscode-styled-jsx-languageserver Install [vim-styled-jsx](https://github.com/alampros/vim-styled-jsx) with your plugin manager of choice. ## ESLint + If you're using `eslint-plugin-import`, the `css` import will generate errors, being that it's a "magic" import (not listed in package.json). To avoid these, simply add the following line to your eslint configuration: ``` diff --git a/server.js b/server.js deleted file mode 100644 index 3b4b9b0e..00000000 --- a/server.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('./dist/server') diff --git a/src/index.js b/src/index.js new file mode 100644 index 00000000..cb4fe737 --- /dev/null +++ b/src/index.js @@ -0,0 +1 @@ +export { StyleRegistry, useStyleRegistry } from './stylesheet-registry' diff --git a/src/server.js b/src/server.js deleted file mode 100644 index 19e833f2..00000000 --- a/src/server.js +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react' -import { flush } from './style' - -export default function flushToReact(options = {}) { - return flush().map(args => { - const id = args[0] - const css = args[1] - return React.createElement('style', { - id: `__${id}`, - // Avoid warnings upon render with a key - key: `__${id}`, - nonce: options.nonce ? options.nonce : undefined, - dangerouslySetInnerHTML: { - __html: css - } - }) - }) -} - -export function flushToHTML(options = {}) { - return flush().reduce((html, args) => { - const id = args[0] - const css = args[1] - html += `` - return html - }, '') -} diff --git a/src/style.js b/src/style.js index 3a08f433..2d0c6bc2 100644 --- a/src/style.js +++ b/src/style.js @@ -1,17 +1,16 @@ -import { useLayoutEffect } from 'react' -import StyleSheetRegistry from './stylesheet-registry' - -const styleSheetRegistry = new StyleSheetRegistry() +import { useLayoutEffect, useContext } from 'react' +import { StyleSheetContext } from './stylesheet-registry' export default function JSXStyle(props) { + const registry = useContext(StyleSheetContext) if (typeof window === 'undefined') { - styleSheetRegistry.add(props) + registry.add(props) return null } useLayoutEffect(() => { - styleSheetRegistry.add(props) + registry.add(props) return () => { - styleSheetRegistry.remove(props) + registry.remove(props) } // props.children can be string[], will be striped since id is identical }, [props.id, String(props.dynamic)]) @@ -19,17 +18,12 @@ export default function JSXStyle(props) { } JSXStyle.dynamic = info => { + const registry = useContext(StyleSheetContext) return info .map(tagInfo => { const baseId = tagInfo[0] const props = tagInfo[1] - return styleSheetRegistry.computeId(baseId, props) + return registry.computeId(baseId, props) }) .join(' ') } - -export function flush() { - const cssRules = styleSheetRegistry.cssRules() - styleSheetRegistry.flush() - return cssRules -} diff --git a/src/stylesheet-registry.js b/src/stylesheet-registry.js index a3e2593f..cbbaff97 100644 --- a/src/stylesheet-registry.js +++ b/src/stylesheet-registry.js @@ -1,8 +1,10 @@ +import React, { useState, useContext, createContext, useMemo } from 'react' import hashString from 'string-hash' import DefaultStyleSheet from './lib/stylesheet' const sanitize = rule => rule.replace(/\/style/gi, '\\/style') -export default class StyleSheetRegistry { + +export class StyleSheetRegistry { constructor({ styleSheet = null, optimizeForSpeed = false, @@ -217,3 +219,50 @@ function invariant(condition, message) { throw new Error(`StyleSheetRegistry: ${message}.`) } } + +export const StyleSheetContext = createContext(new StyleSheetRegistry()) + +export function StyleRegistry({ children }) { + const rootRegistry = useContext(StyleSheetContext) + const registry = useState(() => rootRegistry || new StyleSheetRegistry()) + + return React.createElement( + StyleSheetContext.Provider, + { value: registry }, + children + ) +} + +export function useStyleRegistry() { + const registry = useContext(StyleSheetContext) + + return useMemo( + () => ({ + styles() { + return mapRulesToStyle(registry.cssRules()) + }, + flush() { + registry.flush() + } + }), + [registry] + ) +} + +function mapRulesToStyle(options = {}) { + const registry = useStyleRegistry() + const cssRules = registry.styles() + return cssRules.map(args => { + const id = args[0] + const css = args[1] + return React.createElement('style', { + id: `__${id}`, + // Avoid warnings upon render with a key + key: `__${id}`, + nonce: options.nonce ? options.nonce : undefined, + dangerouslySetInnerHTML: { + __html: css + } + }) + }) +} diff --git a/test/index.js b/test/index.js index d0dfc89c..06969e07 100644 --- a/test/index.js +++ b/test/index.js @@ -5,8 +5,44 @@ import ReactDOM from 'react-dom/server' // Ours import plugin from '../src/babel' +import JSXStyle from '../src/style' +import { + StyleSheetRegistry, + StyleSheetContext +} from '../src/stylesheet-registry' import _transform, { transformSource as _transformSource } from './_transform' +const flushToHTML = (registry, options = {}) => { + const cssRules = registry.cssRules() + registry.flush() + return cssRules.reduce((html, args) => { + const id = args[0] + const css = args[1] + html += `` + return html + }, '') +} + +function flushToReact(registry, options = {}) { + const cssRules = registry.cssRules() + registry.flush() + return cssRules.map(args => { + const id = args[0] + const css = args[1] + return React.createElement('style', { + id: `__${id}`, + // Avoid warnings upon render with a key + key: `__${id}`, + nonce: options.nonce ? options.nonce : undefined, + dangerouslySetInnerHTML: { + __html: css + } + }) + }) +} + const transform = (file, opts = {}) => _transform(file, { plugins: [plugin], @@ -143,18 +179,39 @@ test('works with exported non-jsx style (CommonJS modules)', async t => { t.snapshot(code) }) -function clearModulesCache() { - ;['../src/lib/stylesheet', '../src/style', '../src/server'].forEach( - moduleName => { - delete require.cache[require.resolve(moduleName)] - } +test('sever rendering with hook api', t => { + function App() { + const color = 'green' + return React.createElement( + 'div', + null, + React.createElement(JSXStyle, { id: 2 }, 'div { color: blue }'), + React.createElement(JSXStyle, { id: 3 }, `div { color: ${color} }`) + ) + } + + // Expected CSS + const expected = + '' + + '' + + const registry = new StyleSheetRegistry() + const createApp = () => + React.createElement( + StyleSheetContext.Provider, + { value: registry }, + React.createElement(App) + ) + + // Render using react + ReactDOM.renderToString(createApp()) + const html = ReactDOM.renderToStaticMarkup( + React.createElement('head', null, flushToReact(registry)) ) -} + t.is(html, `${expected}`) +}) test('server rendering', t => { - clearModulesCache() - const JSXStyle = require('../src/style').default - const { default: flush, flushToHTML } = require('../src/server') function App() { const color = 'green' return React.createElement( @@ -190,31 +247,36 @@ test('server rendering', t => { '' + '' + const registry = new StyleSheetRegistry() + const createApp = () => + React.createElement( + StyleSheetContext.Provider, + { value: registry }, + React.createElement(App) + ) + // Render using react - ReactDOM.renderToString(React.createElement(App)) + ReactDOM.renderToString(createApp()) const html = ReactDOM.renderToStaticMarkup( - React.createElement('head', null, flush()) + React.createElement('head', null, flushToReact(registry)) ) t.is(html, `${expected}`) // Assert that memory is empty - t.is(0, flush().length) - t.is('', flushToHTML()) + t.is(0, registry.cssRules().length) + t.is('', flushToHTML(registry)) // Render to html again - ReactDOM.renderToString(React.createElement(App)) - t.is(expected, flushToHTML()) + ReactDOM.renderToString(createApp()) + t.is(expected, flushToHTML(registry)) // Assert that memory is empty - t.is(0, flush().length) - t.is('', flushToHTML()) + t.is(0, flushToReact(registry).length) + t.is('', flushToHTML(registry)) }) test('server rendering with nonce', t => { - clearModulesCache() - const JSXStyle = require('../src/style').default - const { default: flush, flushToHTML } = require('../src/server') function App() { const color = 'green' return React.createElement( @@ -244,6 +306,14 @@ test('server rendering with nonce', t => { ) } + const registry = new StyleSheetRegistry() + const createApp = () => + React.createElement( + StyleSheetContext.Provider, + { value: registry }, + React.createElement(App) + ) + // Expected CSS const expected = '' + @@ -251,30 +321,31 @@ test('server rendering with nonce', t => { '' // Render using react - ReactDOM.renderToString(React.createElement(App)) + ReactDOM.renderToString(createApp()) const html = ReactDOM.renderToStaticMarkup( - React.createElement('head', null, flush({ nonce: 'test-nonce' })) + React.createElement( + 'head', + null, + flushToReact(registry, { nonce: 'test-nonce' }) + ) ) t.is(html, `${expected}`) // Assert that memory is empty - t.is(0, flush({ nonce: 'test-nonce' }).length) - t.is('', flushToHTML({ nonce: 'test-nonce' })) + t.is(0, flushToReact(registry, { nonce: 'test-nonce' }).length) + t.is('', flushToHTML(registry, { nonce: 'test-nonce' })) // Render to html again - ReactDOM.renderToString(React.createElement(App)) - t.is(expected, flushToHTML({ nonce: 'test-nonce' })) + ReactDOM.renderToString(createApp()) + t.is(expected, flushToHTML(registry, { nonce: 'test-nonce' })) // Assert that memory is empty - t.is(0, flush({ nonce: 'test-nonce' }).length) - t.is('', flushToHTML({ nonce: 'test-nonce' })) + t.is(0, flushToReact(registry, { nonce: 'test-nonce' }).length) + t.is('', flushToHTML(registry, { nonce: 'test-nonce' })) }) test('optimized styles do not contain new lines', t => { - clearModulesCache() - const JSXStyle = require('../src/style').default - const { default: flush } = require('../src/server') function App() { return React.createElement( 'div', @@ -289,9 +360,17 @@ test('optimized styles do not contain new lines', t => { ) } - ReactDOM.renderToString(React.createElement(App)) + const registry = new StyleSheetRegistry() + const createApp = () => + React.createElement( + StyleSheetContext.Provider, + { value: registry }, + React.createElement(App) + ) + + ReactDOM.renderToString(createApp()) const html = ReactDOM.renderToStaticMarkup( - React.createElement('head', null, flush()) + React.createElement('head', null, flushToReact(registry)) ) const expected = '' diff --git a/test/snapshots/attribute.js.snap b/test/snapshots/attribute.js.snap index 6130091626d9dc65a2fdf35bea7a13d4cdbf3a43..b6a89e61485ca10b78b21ad3562be49b636f14e2 100644 GIT binary patch literal 1509 zcmVt!{0{yil^=@;00000000B+ zT2F7|L=;aKAy94=2M!zQ8z**b=U)@F2M&O=LRth!Rn@rhgu3h4S=(6}xjyp= z;LbBFLzxUoaqxLG5%7aSv?cW!| zt6!e}{NBy5cJ=DBg9`rqby%r<`R-SL{PX^IPkKN7SfBs!+xG|L>7NfPl{YGH5vzkY zD~At$J=CW&%XY!}r_a8A<}M5fCbl&NjDxSW`jvCtAeT(P8d{QDCop6AVANsz)#}(X zo#n6y2Ec|d=DH2J$Vg;seb8tCcbuN7ne<&`Wj{IR2pwG#yIKWz@CyiN%xFSo}1{+wz z@ZLXZL}nRo;-;Ut>3GsW91PcqQ%wyKt-AU+fju#mJqE8+>~=(1lx0Z)40sF@2}$NI zk9$I>Y5XxONCwfs%=q3icF%@d-)AUk-K9nvsoKI+r-`h#FsmMNCDBxU`t%$j znixV>6apX4!=0WoLRV@_9Z6D}%rQ76=x1kVHTvu=il4ObRE=UN{?d5hg>Z=G(F}!y zqa(4^LyNit4LEi!JJj$f`1boKMea<<<1pWL2r88n6pyroZnN8wg=Ra0|5i(p&_`5C z>05fbEP7I9U(FaR&DBFs)18^2E_%9Y=q9XR7}oeXO_j#Od|mS?q$${>w$ew=?y^Fw zEh>M`8<(0cW+~ZOXC>PoXJ1<}S*sJm`O-bYg;r&S^!^ zrjfGru9puW9`gRSvjh&m)!j?rjI9~e5MStJdXBQ_rE2Tyg#i=D?Ie+l@AV1b$g>)` z1)+~_n$Z5-wq_1;3n-;iNJZ}6{SvB6y_}}FPH|R0v2At12y$+a%w0R~`THIEV z@WB9>bHhj*zPSMme#F##&`6J_P)G@J(FB(-!b{!BAK{u4nSJd^N`z@P=@DwGtJd+* zATY?xg$-Ytl?13oJX!3?7V#Wm&rxB|BhR(x5PSq!BDu(d9$;C&5FkfZfsh^(EF#3V z2vkU?0U^f$F(P}$Us<}zv4E|WfhB82xf7t5K_X>^X$z2gBrVIuR+6%1?UY|zyiWw0 zmSY{gOu-5IDXEnKA!T2}f1(-=OaX}cLWx?vRSb&$v;zt^;~9R9r0l`O7K=U$-aV5# z?&c68Gt7>R+3}@KzZckH?%An*e`5p%ac8mLC3B?v0@Qvt`Uq~m`-&+?;qNn|T}^J! zv5_6?cIn$$} LGCswaC?)^^FmK?$ literal 1528 zcmV;RzVaTxEk00000000B+ zTFq|bR1{7JAy9UsS+HQi#gwt5X`I-Joxdh%7Ayd1gfs|{s;Y70Tk4Ku2iqAMxnA=G zu;&rj^8)h_NQfOmLc9Qi`{OuvVmmkXv>9p0B8lyDzI*QXopY{zlYXUAxmWq}ov;4< z=e_SA_kaGWKL7Fe9}X(`_3wj9rTX?C3+ctLPkwp#W>mX+@!0`6``3q+${Urph}FTH zmHYSpeqc;zw&Q`bPoIAM)LWPkTsZa=a4!C?*RR~`2KmYjs_>dv>hMCFn;sB^8W@g% zUj<-dTdoH_HsKUn9vA{%H=gqYbisk%+_AthItCL{bKNJ}6b^k3!Pez&S5=yARc>;@ z2-)HnG4w@I^q}jJw;<0CJOUiR??Pk`9zF!off)IM_lLlmn`YMKn;XF4Q(P?ojqGR& zg_IH(OK`hIcxkx1N0@LTqbJT}M3`lh9igsyS{+{+QiI%FSo39>2}Ld9$zxBxi02r4 zjthGp`kpg~;3L2j$z>k&0nZ1800lA&g!G7D5g|53U_v^fgd9;~Wd2mVvJFe%0beTv zOXiAlhoYB3B4veXqey*{mgQnAN!hY?%Fiv{C#a_7Sf5*{R~r`8%YcxwFX4ZonJ&x# zi26c_T79V)4E<>f6mG^d$DX;2J($>H(aD$ej=O#dkr`%3&gl57!@d?cVeUDZeShr= z3gXsczfI;y_XVi^uJsYzeD@X84u!wZh_*GkJ;z2?td~pQ)*9cf%3d;Dp`zVy_2oh`SsxXJo)VcY*tpj-m_;R!=W{TPMAlj9&am_m2`7&|Y32!uTj=7*78ZZWdrJl7mX zg^(qd0ez(Fle~cC!DHsClSR%>fibeQm&q2=N?+q9j&1NA|`1;>rZpCTSNkjrRL4QhkL_TO*! z*|+~fOLFK^GhU=uU4Brl(oH~mEQ2BH{NK(E2MUpq%-05>(E#w;gN~({z_!dqwYuC_ zr2bzZ9VFyUHy77C`WVmp(5HCf+1aJ$UIrk3QeK`NhntGWv*G}WNRJz{5HTrE5^EG5 zr)ZGoCa?R+>yDvx3F0(MM?`C$F-c)h&SZ}!ZLcdUvZAzAx*3&5NIG}BxTl1g#UHnV zB*{G!ljCel?ILPqk*Y5&ZJNqz3$sf1x=}Q!keJhR9QB4M1Th>(I62{@Uc1xow%clx zI|3&J{q*#-#-6=J@zW-rsZk6iSQ-!g5Dw8io}qAXbR@QVXi;~e2`8TIgc=^w&tQO3 zH{N9*C^*S$;#8Xn0yaJZ24&JTz%#fQ z`bMxlO;Kx5l~z~nB$kcUJ`e_u{U2#P6Ibr(>xPK^OW(Qz@CkweANU3eNeaSbG>uU$ eUgL8!zHdk9<3>LDM38fnWbS`Mq@O(~CIA4rPwuw> diff --git a/test/snapshots/external.js.snap b/test/snapshots/external.js.snap index 83c58757758b337fd7f38cae2c2914d4d22c966f..4ef41ea0a692f362de77614213575bcc9c7581bc 100644 GIT binary patch literal 1806 zcmV+p2l4npRzVmB`kCN+OPfTBBsI=M!z=PeVPVcyq z`1#1W;eX%x=iMoWO55)N;N#GR1J{}J!uH^unTKeRHr#BZ4UmZRF%)#fU4lz_(y$^sd*8a_=R)jAe`+W7fGcP~# zB15H@+5vdrhxYsX2(BVA-NiL9tvBB?V?SjBX!Q zCQAs8Nn#nYGWnhF-6c=>=}$K9@r+f4oKh48s32MKcEOqlLNED(kdBcDV8XIf%n#OB zE*g!5`$7?}k5!X3HecN1!zOzzaV;m7L}@@m`MAoe3BReI?4gEpC0>?C_%a%RtX-4E z&(*HDN3|uin_;Um!tqGOoI--$!%Hwj!-In`Qxp^=iIpvAceN;?b!d#QmK3j~-Fh3d z?&>m33{@&F4EX$boKHhTQ#L_sp(^g&g^`33QmT>w@f}>Xid=k|43amB`6>>44V4ez zVR=n!fC|(&RO=jUwW^|9OJKZ{6h`t%XfXJ68?-r^i#HL>X#1`~c_ z-HHDYqc>CyViX}S!wk8qdRs||&nbRVNU16)#WLwD_Z^rM1zCYZxDF&qqv!nH4`ni& zw{02DWV-#to7Xhe1GV-n=5hOQ{ai5I7mY;%tlnFNVks{n0Y5Vv(;TBW=D38AfLoI` z8&PX$NXx26jeF1pO~%03EY5l%k0v(rnJw{lJ6XG(jvBeB#99_x;(XpP zZDuWYolhLDjVJG1D4tBYVaK#G@#7lq>#A&lmrt=FBG99>~tb zC~W$FVZntDd||jSb%SK6q2QJfn_zOwFrvi^ttk-)ke!_tXD|E=ytp4|b)6fn(~%i(LSejH9V)wbfe0qmvnyxupM@P0-HzB+e#ug?g z%lbQ^fJ!AdF9WQR#r46l>yyd~8IqVuUwN`~AzWgSn$z44K%+6#Y{O>5m3Ig$`csEN zGdRut)}lhU%-Z|YR|sT1rV5#S9-H}aUu7b0DGv#vQb3YngI+QE3KH^J-Nw#R6~&!U zJS<}51tgGWz#ApZREc_1$&Hh+g7;7fzfEc{-xM?Fm4G&*$x48Lj`ysZAXv91&?KEE zt7`Wgj?>utn}fK{u14bU>gkv}@=i{t+gBT7G>I|B&N#X|Yu~O5 zY<$sLG3Znbx>R)PIn}fby6k0{p2JC#tt^ctXbr8!jDxi-VUG?+$XV4u*3D3Rf#wYg z{(3vq0R`6#3o^G$Xb&pk)(qhFi~V&!Tta1SdSwe8H9C$EiFIOR444%ixEiwf4}VLz zMOoE67IKBGu_!^BI}_yVgqZ-XM@~+p9C)vt``(~c>$#o%<{{YZgyOE7wFO=z6p6(8 zIW9_(w}ETUX6U}}Z`7#O12|3AIbY`0mAc?eIPV26 wsd0Ka&%|zjX_Iqj>wSIQFx_a2-kff9)p$3ze-^e?^ke@202)&YtaKXy08m14mjD0& literal 1809 zcmV+s2k!VmRzV1|N$E00000000Bc zSZ{0-Wf;E$iCT0Dq7gp5o(pTo)~?q-YuB!1$V?z%AOizwn)Yblt;P1P++AU#IgJ{U zVbs6}jfq4cpnlLq4956DW0XG;5Dl6b;}_$<#DJQZ=oeVj_s{+5UDxdf!?9%R`rP~c zp6B^J&;9OwFU2ykOJw?yWf$;b07v7Wnw zVU8(pOW%HyTD*Ok{NeA*-atOs`orA}^Ktm%{%ea?pO4ggue~Yk|C1%wBlj@OL!GBi zZ@-fK>G1i%f8Y7%-3gXhSKrGp$3sgezdYG>@r#dA>t0VzUS)~(YxMi_FRxua<=^-I z(}UaF&SW;8WQld>QieIT_^JKRY$_hQI(*^T120S*WQnzQAHzKG{j&Rel(xUl9zT@0 zc!~R!CDyYKGR)^|{^rulBbSbSwrcH}R~~(dCD!N)hFQqmPMBgBF-sPF%9JWqNmfC2 z{qVM7b-WD0h%8kAr{Mn!-8+@B0Qr|ocswIDF|U>+5vWj6y*^O)0N}-c03d6WK9IC< zN`?M9$H!vPNKZJ*_i$RO&J{|#{Rpz#GS~A`S(5u?SV(A`mJFEwsV)MXFAIt?BvfD@ z;Ow3px~};W9?e$JE|#k)5alD6@+wYxw;+QoNe}dcY)Mq1ELAtdUA2-7*TNB@R#v?- z{pxM5+UGMM2C7vT0R8}4=cjB?XOpxRuF{U3h)EzrwI+)IeFH03;tzi|3zZF0p@tG) zP3(PWS%G@>5rdWhT0?*>R#$YiB;q?oXv9BBN`qg=APvH083q)wC@4kLr$#I8iOtUd zOa?Hzlm7u$AE-J&ECN9RS^TN#Vs0^Wq zMw1L1c550)3)Q0~JaCK@V{mLXXPsDpW1ECgXz$Sa;f+InJgnkqX=L0x&@|7>7rCcL zUr7>IQ0YJ^?S%&Q9sU5JPY_k5!=REZMRazc`_DA)5U@#vd%!SB%xkd|3Tl*>T$I_(Q{JIfN!OVnz8l zACHAXoY^XhSi_f51rGCwBsGVkT=4ODyeAgsd-X|ar=J=PiX0omnu}3fZ{zSf1v41p z<55&>Zv+db8O<`=qbYtep#E}cw5X!c!qlsYyylwZ)j7)z!97@7^|m?gw_7)5B)2r> z!ni0@N_mtx4GH>Fqy&3GtxF1p_z1=gqmm4;{(8DO|BO*_77I@|!Ryu?x)oT4c~z2U zs^5ig3pQ+gn3w!Ih&P>XtfUJ}RX`@=!`hZ0>^anHx~?PMdxAke5{}!tZke4ocGY>k z>9(1%*$pvKx;CA>bG~#k?M59luGKL;r6y)vYGQgCCCto)5~f}0UuLfKFFk8D$#ns4 zIz{0!|BDLFf8z6_h3OjIT0IK>`2cVf84Zo$N zlJg&Z82F39oX2#*ljO0%M|!Gb3Cnpvl++@W4Gi+>hhr)f3ppKQN4W+QPAVRe5c47w zRpf+r{phw!HbSK~jDspV5F`UOtG#^(7>bqEX&IyeT5QjeqK6~VSa8bixyO!SS7+T1 zsdI%KIsLQ}1s{2BZua!{wMsATCMoooxCuE;u(RF?&^sFM1n``qGb=TO8ukR#(qXD9 z{m!FYjI+PFi0|+<3x`*q0P{qitfug5lw_c)f5%t$NRmp=)y5iXG1k}>M-OM6+jWCY zFIqc>oQ@%vj!r+P8?C@+Z_DH?-Za_T(%gd9)LP2eU(ey`Yj>oa(+pFWim+o6EW8=Qe-1|DO8gJ9)SZM6eUHl%@dgNX=O*cBCH)k4M z4c^V2pZOgX{k5}AP=)J#p z^$OltFyrIK8W$O{%W39&c2|!ozU(M{JzA0*D=XXbQ=HwnSFe{ diff --git a/test/snapshots/index.js.snap b/test/snapshots/index.js.snap index ff80a432f76d7d6144cd3013a4768f5b1d3646a5..aa6e036c885091923742fe8b390f13d020c05401 100644 GIT binary patch literal 3387 zcmV-B4aD+6RzVr&X;UiZh$?9bb~gS)Hk?e$vPUg=$XGMx;eCzO{yDrKHN2W(Tf2Lefa|fvH7Fdy&3z{J$L`{j_`S} zKRWWS0EWgk5X39DZ@F{-(!$QyzA}(n_vI(v3Sj7CXA{Ib$M*l@w&7?0cJ57AZhY$K zgHH!A^mFGB#8p2Df9c@o*WLTox9`!f6OZkjcx3Xj5C4+=Zg6J+L#H+o z#Bc99RMoAFs-OH0fK%o&5J6OrSd*_ZH1TNHaN>v1hrc>9=n4WkBiJJ z)foO642Kbm*^0=jyd?UOONIF`r~?_Q6x;Qr4D`jy139Nb1ACk7=_~6%A7(XBpD80P z?P-8EgXS^DyzKL=Bq}OkY(^ZvFwh0i2eB;jI)(9Mat|#^k{Yr&qOrc1PLgYK1HPmS z2&PBJC&%&X&&pB>cvm>rWvJ3v7tn3X;W0mzPS8|>Or>aKTvN#QNGeoRTZd(kb=6jh zZ0m`=z=hfH0vqV@f(Es1&#>E|=dIqLSPM``oMk9-P)7ExW1-D}X>DmTPG%BGIvHfLh%F<*qlSx`0sgxNJ)T7ZT=C1*cQJIL&x<9D@54Ph0dO#59|GN$0 zP$I)Wq81I<)DOgpAha4fdK3hM;l?uPa+o3wOUN`L6jc!O@mHrB^`K4~b&J-4%ew4F z*>=N%IAn6+(W|p>TRe~cr%2oX%|JW0fjb5QriTB+UVlW1J5 z8h&X5O}}JojF{7+NU`SeSxHnQ3cmz<$xOMLGti5YTIR(gIqgz?<(f$%i?DEnS5XSC zsu2#dlFaDUWN$@}QGpj>&VQs;@DI3ZQY*ERX1F(k-Lj7!NJhNcrBw`tmez_3)x@P$ z%1DsO6iKI2$%LIUn(geusRt38sGD?|4A6*w?f+%nsVwWRUx7g#o2I>IE+e47MBeSI z?FyyRbUd9(Wistn$cf}$p=R%-QrUQ#%EXN

{GcWcD_@Q$ zPjoq2+K!4NWsywQ4)4*!iD8<7sJAJKGWnRRcq9; z?6!)r@8~F0JYG_~D7d^w!=+k;l_bGlFI$enyxGb$76gO}g2W!d4UH$%9f)0;zwgpn zv|psj6iwpd$+BUTtBFjBXS=7SP^p=q6A7A3q=Q?*lwrJXY^(6$!w3?j=nR=kClgu9 zgMfHa1`?g2<7jcobP6LGqJb+KN&uve?qMMVn@lE?$QKgkoNcfVhy4@Q`$N07nU;*l zX*v^6lQ?W<%F)e6;Al~|0nBjPT(|vMvr+|u7UrYola|8=N~=lDp6NPG^r<+N%u?AT z?$>6Tw~K~K9SL?4S&>vGnM`N1S<|#W7X7bsbhxhuOtE}!Vk*qO4m zaNTDKaGK9)z6&&i9D4?d&uE>A)^a8=E6IzD%qhSzs%L12tScqd8qJPFnodHzwa3_r+vU9eIa#*`K2d7x z$aZS=XVqcOus4g7DPeB`A``<71w}Q8in`a{&^0rm7E-q?wm-XqbEKB_ivSm(fQlZ{ ztYCDQQ4D=dfcjAc8k;F@u46oHCg*6Y8wj404k}4!)0uQU>o_rzQA_CPv|F5y*i_np zX-EK#DV!%Io^0##MfI4ph_-Z8w(G@pd&9xy3hWSn%L^dM5#Oo%pUqvF02-wfcR0$4?f5^YP_WKcJ2+9LNz@R~30xQY zN2?R7=>n$Dp^i~EIB>1@rvdZreyDbbuLGyc;j8H(VJxjam|V0dBZJ9h4Y(ju(4DTz@@5_Y-Zv@kYUWaPUf;l9RrZa#{HvUDmqH z@u3x@`xPICnS+Dvjh9TLJ~5F^wedm+O4~yZ2VSEyX@HjRp_@)6huTYxI?62S(NYPj zjodDzwvxLrt**)fwmhY2qk?}LFsC21d~C@0)iPMr)fWT4cjC>3x>;;F_dVYtJrj?U zX)2LP`_`JRt1X+ZUA5Js-f|MU>Md)alX}ZtsvDc*%Bs#~-!NFV2tC~mLs^z_yWlTQ zq#iv@ZXQ>^r(Gk)wp@WBvMFOD}p9cov_3#O4)A%&|pAR-oEn zQD-BWTmkicsl--T8>J3SjxI41*-Cz1S{fT3T`JHAY6qzUOZoY7AusM;;3h}s4~>)R z!O5Yeu~K;{FT|C6DOoH`7&w#Ti+o{X`y#tTs2rkq@mKMqLwm0l#JzkKeea$h+kOCj z@8S{f5;IX1&^$a#Wl6TQTNs-li|oj*3M1liYwo>Nw!-Z=P~nF2sfpUC07r%vSaI*% zp&bWG2PY3G-0+~Zb9^wnhaZ$CcO>TW+p0&H$%8%k_weA{o{_;GM8CvsTU=nbCD{T$ zsKYbpH(j8z@jb)Y#XUl`qT?dkC2mAe4vi08%hGc_u*NOsN0hmPR8}d_`BZ*nR5&y| zlpUqxnK62I93mY|+RPZWuguNs`~~zk%FXWW?+06A`odgkE{wh+#;-_;K}Gevf)F~Z zMz){1x>stpqEgB(7qs?o*cizpkMc&<>O$Q8hoT}kV!@nV!0{^22z&JIpgGCZ&6qX( z6NH#+D-5dVcoBy1h-OBxCrRN~f%UEfWitIM*VV4gX?Yt%#;Hs?OC~9N*)r{HVRUI6 z*FE~DK1FT?)Zr*vj&8dh;JIqpQo=p`5m@W5qjBvd3t|XEZv}}K!cb0W{3N1Il1OzA zT(i5i#zzZl&Xb1OnE7A5!z;#FAu}aIk Rfaar?{{V4Ps1KPl003F{nBV{a literal 3391 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 diff --git a/test/stylesheet-registry.js b/test/stylesheet-registry.js index 12c06840..2dca45b7 100644 --- a/test/stylesheet-registry.js +++ b/test/stylesheet-registry.js @@ -2,7 +2,7 @@ import test from 'ava' // Ours -import StyleSheetRegistry from '../src/stylesheet-registry' +import { StyleSheetRegistry } from '../src/stylesheet-registry' import makeSheet, { invalidRules } from './stylesheet' import withMock, { withMockDocument } from './helpers/with-mock'