styled-components 2.1.1 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -1
- package/CODE_OF_CONDUCT.md +1 -1
- package/README.md +12 -67
- package/dist/styled-components.es.js +273 -110
- package/dist/styled-components.js +325 -119
- package/dist/styled-components.min.js +2 -2
- package/lib/hoc/withTheme.js +13 -7
- package/lib/models/BrowserStyleSheet.js +11 -0
- package/lib/models/ComponentStyle.js +45 -2
- package/lib/models/InlineStyle.js +1 -1
- package/lib/models/ServerStyleSheet.js +33 -17
- package/lib/models/StyleSheet.js +9 -0
- package/lib/models/StyledComponent.js +82 -38
- package/lib/models/StyledNativeComponent.js +31 -15
- package/lib/models/ThemeProvider.js +44 -12
- package/lib/native/index.js +1 -1
- package/lib/test/utils.js +5 -2
- package/lib/utils/create-broadcast.js +34 -24
- package/lib/utils/domElements.js +1 -1
- package/lib/utils/flatten.js +4 -1
- package/lib/utils/generateAlphabeticName.js +1 -1
- package/lib/utils/nonce.js +10 -0
- package/lib/utils/once.js +17 -0
- package/package.json +10 -10
- package/src/hoc/withTheme.js +14 -7
- package/src/models/BrowserStyleSheet.js +8 -0
- package/src/models/ComponentStyle.js +42 -2
- package/src/models/InlineStyle.js +1 -1
- package/src/models/ServerStyleSheet.js +27 -12
- package/src/models/StyleSheet.js +9 -0
- package/src/models/StyledComponent.js +81 -26
- package/src/models/StyledNativeComponent.js +30 -10
- package/src/models/ThemeProvider.js +38 -9
- package/src/models/test/ThemeProvider.test.js +7 -8
- package/src/native/index.js +1 -1
- package/src/native/test/native.test.js +14 -0
- package/src/test/__snapshots__/ssr.test.js.snap +147 -0
- package/src/test/expanded-api.test.js +24 -0
- package/src/test/props.test.js +14 -3
- package/src/test/ssr.test.js +90 -123
- package/src/test/styles.test.js +52 -0
- package/src/test/utils.js +5 -2
- package/src/utils/create-broadcast.js +31 -17
- package/src/utils/domElements.js +1 -0
- package/src/utils/flatten.js +16 -6
- package/src/utils/generateAlphabeticName.js +1 -1
- package/src/utils/nonce.js +6 -0
- package/src/utils/once.js +12 -0
- package/typings/styled-components.d.ts +15 -21
- package/typings/tests/issue1068.tsx +226 -0
- package/typings/tests/main-test.tsx +1 -1
- package/typings/tests/string-tags-test.tsx +62 -0
- package/typings/tests/themed-tests/issue1068.tsx +226 -0
- package/typings/tests/themed-tests/mytheme-styled-components.tsx +1 -1
- package/typings/tests/themed-tests/with-theme-test.tsx +2 -1
- package/typings/tests/with-theme-test.tsx +17 -0
- package/lib/constructors/test/injectGlobal.test.js +0 -63
- package/lib/constructors/test/keyframes.test.js +0 -48
- package/lib/constructors/test/styled.test.js +0 -19
- package/lib/models/AbstractStyledComponent.js +0 -43
- package/lib/models/test/ThemeProvider.test.js +0 -200
- package/lib/native/test/native.test.js +0 -290
- package/lib/no-parser/test/basic.test.js +0 -46
- package/lib/no-parser/test/flatten.test.js +0 -125
- package/lib/no-parser/test/keyframes.test.js +0 -45
- package/lib/primitives/test/primitives.test.js +0 -289
- package/lib/test/attrs.test.js +0 -158
- package/lib/test/basic.test.js +0 -267
- package/lib/test/css.test.js +0 -43
- package/lib/test/expanded-api.test.js +0 -90
- package/lib/test/extending.test.js +0 -198
- package/lib/test/overriding.test.js +0 -35
- package/lib/test/props.test.js +0 -38
- package/lib/test/rehydration.test.js +0 -306
- package/lib/test/ssr.test.js +0 -187
- package/lib/test/styles.test.js +0 -146
- package/lib/test/theme.test.js +0 -497
- package/lib/test/warnTooManyClasses.test.js +0 -71
- package/lib/utils/test/extractCompsFromCSS.test.js +0 -46
- package/lib/utils/test/flatten.test.js +0 -109
- package/lib/utils/test/generateAlphabeticName.test.js +0 -14
- package/lib/utils/test/interleave.test.js +0 -22
- package/lib/utils/test/validAttr.test.js +0 -560
- package/src/models/AbstractStyledComponent.js +0 -21
- package/typings/tags.d.ts +0 -137
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// @flow
|
|
2
|
-
import { createElement } from 'react'
|
|
2
|
+
import { Component, createElement } from 'react'
|
|
3
|
+
import PropTypes from 'prop-types'
|
|
3
4
|
|
|
4
5
|
import type { Theme } from './ThemeProvider'
|
|
5
6
|
|
|
@@ -8,11 +9,10 @@ import isStyledComponent from '../utils/isStyledComponent'
|
|
|
8
9
|
import getComponentName from '../utils/getComponentName'
|
|
9
10
|
import type { RuleSet, Target } from '../types'
|
|
10
11
|
|
|
11
|
-
import { CHANNEL } from './ThemeProvider'
|
|
12
|
-
import AbstractStyledComponent from './AbstractStyledComponent'
|
|
12
|
+
import { CHANNEL, CHANNEL_NEXT, CONTEXT_CHANNEL_SHAPE } from './ThemeProvider'
|
|
13
13
|
|
|
14
14
|
export default (constructWithOptions: Function, InlineStyle: Function) => {
|
|
15
|
-
class BaseStyledNativeComponent extends
|
|
15
|
+
class BaseStyledNativeComponent extends Component {
|
|
16
16
|
static target: Target
|
|
17
17
|
static styledComponentId: string
|
|
18
18
|
static attrs: Object
|
|
@@ -25,6 +25,15 @@ export default (constructWithOptions: Function, InlineStyle: Function) => {
|
|
|
25
25
|
generatedStyles: undefined,
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
unsubscribeId: number = -1
|
|
29
|
+
|
|
30
|
+
unsubscribeFromContext() {
|
|
31
|
+
if (this.unsubscribeId !== -1) {
|
|
32
|
+
this.context[CHANNEL_NEXT].unsubscribe(this.unsubscribeId)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
28
37
|
buildExecutionContext(theme: any, props: any) {
|
|
29
38
|
const { attrs } = this.constructor
|
|
30
39
|
const context = { ...props, theme }
|
|
@@ -53,20 +62,24 @@ export default (constructWithOptions: Function, InlineStyle: Function) => {
|
|
|
53
62
|
// If there is a theme in the context, subscribe to the event emitter. This
|
|
54
63
|
// is necessary due to pure components blocking context updates, this circumvents
|
|
55
64
|
// that by updating when an event is emitted
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
65
|
+
const styledContext = this.context[CHANNEL_NEXT]
|
|
66
|
+
if (styledContext !== undefined) {
|
|
67
|
+
const { subscribe } = styledContext
|
|
68
|
+
this.unsubscribeId = subscribe(nextTheme => {
|
|
59
69
|
// This will be called once immediately
|
|
60
70
|
|
|
61
71
|
// Props should take precedence over ThemeProvider, which should take precedence over
|
|
62
72
|
// defaultProps, but React automatically puts defaultProps on props.
|
|
63
73
|
const { defaultProps } = this.constructor
|
|
74
|
+
/* eslint-disable react/prop-types */
|
|
64
75
|
const isDefaultTheme = defaultProps && this.props.theme === defaultProps.theme
|
|
65
76
|
const theme = this.props.theme && !isDefaultTheme ? this.props.theme : nextTheme
|
|
77
|
+
/* eslint-enable */
|
|
66
78
|
const generatedStyles = this.generateAndInjectStyles(theme, this.props)
|
|
67
79
|
this.setState({ theme, generatedStyles })
|
|
68
80
|
})
|
|
69
81
|
} else {
|
|
82
|
+
// eslint-disable-next-line react/prop-types
|
|
70
83
|
const theme = this.props.theme || {}
|
|
71
84
|
const generatedStyles = this.generateAndInjectStyles(
|
|
72
85
|
theme,
|
|
@@ -81,8 +94,10 @@ export default (constructWithOptions: Function, InlineStyle: Function) => {
|
|
|
81
94
|
// Props should take precedence over ThemeProvider, which should take precedence over
|
|
82
95
|
// defaultProps, but React automatically puts defaultProps on props.
|
|
83
96
|
const { defaultProps } = this.constructor
|
|
97
|
+
/* eslint-disable react/prop-types */
|
|
84
98
|
const isDefaultTheme = defaultProps && nextProps.theme === defaultProps.theme
|
|
85
99
|
const theme = nextProps.theme && !isDefaultTheme ? nextProps.theme : oldState.theme
|
|
100
|
+
/* eslint-enable */
|
|
86
101
|
const generatedStyles = this.generateAndInjectStyles(theme, nextProps)
|
|
87
102
|
|
|
88
103
|
return { theme, generatedStyles }
|
|
@@ -90,9 +105,7 @@ export default (constructWithOptions: Function, InlineStyle: Function) => {
|
|
|
90
105
|
}
|
|
91
106
|
|
|
92
107
|
componentWillUnmount() {
|
|
93
|
-
|
|
94
|
-
this.unsubscribe()
|
|
95
|
-
}
|
|
108
|
+
this.unsubscribeFromContext()
|
|
96
109
|
}
|
|
97
110
|
|
|
98
111
|
setNativeProps(nativeProps: Object) {
|
|
@@ -112,6 +125,7 @@ export default (constructWithOptions: Function, InlineStyle: Function) => {
|
|
|
112
125
|
}
|
|
113
126
|
|
|
114
127
|
onRef = (node: any) => {
|
|
128
|
+
// eslint-disable-next-line react/prop-types
|
|
115
129
|
const { innerRef } = this.props
|
|
116
130
|
this.root = node
|
|
117
131
|
|
|
@@ -121,6 +135,7 @@ export default (constructWithOptions: Function, InlineStyle: Function) => {
|
|
|
121
135
|
}
|
|
122
136
|
|
|
123
137
|
render() {
|
|
138
|
+
// eslint-disable-next-line react/prop-types
|
|
124
139
|
const { children, style } = this.props
|
|
125
140
|
const { generatedStyles } = this.state
|
|
126
141
|
const { target } = this.constructor
|
|
@@ -171,6 +186,11 @@ export default (constructWithOptions: Function, InlineStyle: Function) => {
|
|
|
171
186
|
static attrs = attrs
|
|
172
187
|
static inlineStyle = inlineStyle
|
|
173
188
|
|
|
189
|
+
static contextTypes = {
|
|
190
|
+
[CHANNEL]: PropTypes.func,
|
|
191
|
+
[CHANNEL_NEXT]: CONTEXT_CHANNEL_SHAPE,
|
|
192
|
+
}
|
|
193
|
+
|
|
174
194
|
// NOTE: This is so that isStyledComponent passes for the innerRef unwrapping
|
|
175
195
|
static styledComponentId = 'StyledNativeComponent'
|
|
176
196
|
|
|
@@ -6,9 +6,17 @@ import isFunction from 'is-function'
|
|
|
6
6
|
import isPlainObject from 'is-plain-object'
|
|
7
7
|
import createBroadcast from '../utils/create-broadcast'
|
|
8
8
|
import type { Broadcast } from '../utils/create-broadcast'
|
|
9
|
+
import once from '../utils/once'
|
|
9
10
|
|
|
10
11
|
// NOTE: DO NOT CHANGE, changing this is a semver major change!
|
|
11
12
|
export const CHANNEL = '__styled-components__'
|
|
13
|
+
export const CHANNEL_NEXT = `${CHANNEL}next__`
|
|
14
|
+
|
|
15
|
+
export const CONTEXT_CHANNEL_SHAPE = PropTypes.shape({
|
|
16
|
+
getTheme: PropTypes.func,
|
|
17
|
+
subscribe: PropTypes.func,
|
|
18
|
+
unsubscribe: PropTypes.func,
|
|
19
|
+
})
|
|
12
20
|
|
|
13
21
|
export type Theme = {[key: string]: mixed}
|
|
14
22
|
type ThemeProviderProps = {|
|
|
@@ -16,6 +24,11 @@ type ThemeProviderProps = {|
|
|
|
16
24
|
theme: Theme | (outerTheme: Theme) => void,
|
|
17
25
|
|}
|
|
18
26
|
|
|
27
|
+
|
|
28
|
+
const warnChannelDeprecated = once(() => {
|
|
29
|
+
// eslint-disable-next-line no-console
|
|
30
|
+
console.error(`Warning: Usage of \`context.${CHANNEL}\` as a function is deprecated. It will be replaced with the object on \`.context.${CHANNEL_NEXT}\` in a future version.`)
|
|
31
|
+
})
|
|
19
32
|
/**
|
|
20
33
|
* Provide a theme to an entire react component tree via context and event listeners (have to do
|
|
21
34
|
* both context and event emitter as pure components block context updates)
|
|
@@ -23,9 +36,10 @@ type ThemeProviderProps = {|
|
|
|
23
36
|
class ThemeProvider extends Component {
|
|
24
37
|
getTheme: (theme?: Theme | (outerTheme: Theme) => void) => Theme
|
|
25
38
|
outerTheme: Theme
|
|
26
|
-
|
|
39
|
+
unsubscribeToOuterId: string
|
|
27
40
|
props: ThemeProviderProps
|
|
28
41
|
broadcast: Broadcast
|
|
42
|
+
unsubscribeToOuterId: number = -1
|
|
29
43
|
|
|
30
44
|
constructor() {
|
|
31
45
|
super()
|
|
@@ -35,9 +49,9 @@ class ThemeProvider extends Component {
|
|
|
35
49
|
componentWillMount() {
|
|
36
50
|
// If there is a ThemeProvider wrapper anywhere around this theme provider, merge this theme
|
|
37
51
|
// with the outer theme
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
this.
|
|
52
|
+
const outerContext = this.context[CHANNEL_NEXT]
|
|
53
|
+
if (outerContext !== undefined) {
|
|
54
|
+
this.unsubscribeToOuterId = outerContext.subscribe(theme => {
|
|
41
55
|
this.outerTheme = theme
|
|
42
56
|
})
|
|
43
57
|
}
|
|
@@ -45,7 +59,21 @@ class ThemeProvider extends Component {
|
|
|
45
59
|
}
|
|
46
60
|
|
|
47
61
|
getChildContext() {
|
|
48
|
-
return {
|
|
62
|
+
return {
|
|
63
|
+
...this.context,
|
|
64
|
+
[CHANNEL_NEXT]: {
|
|
65
|
+
getTheme: this.getTheme,
|
|
66
|
+
subscribe: this.broadcast.subscribe,
|
|
67
|
+
unsubscribe: this.broadcast.unsubscribe,
|
|
68
|
+
},
|
|
69
|
+
[CHANNEL]: (subscriber) => {
|
|
70
|
+
warnChannelDeprecated()
|
|
71
|
+
|
|
72
|
+
// Patch the old `subscribe` provide via `CHANNEL` for older clients.
|
|
73
|
+
const unsubscribeId = this.broadcast.subscribe(subscriber)
|
|
74
|
+
return () => this.broadcast.unsubscribe(unsubscribeId)
|
|
75
|
+
},
|
|
76
|
+
}
|
|
49
77
|
}
|
|
50
78
|
|
|
51
79
|
componentWillReceiveProps(nextProps: ThemeProviderProps) {
|
|
@@ -53,8 +81,8 @@ class ThemeProvider extends Component {
|
|
|
53
81
|
}
|
|
54
82
|
|
|
55
83
|
componentWillUnmount() {
|
|
56
|
-
if (this.
|
|
57
|
-
this.
|
|
84
|
+
if (this.unsubscribeToOuterId !== -1) {
|
|
85
|
+
this.context[CHANNEL_NEXT].unsubscribe(this.unsubscribeToOuterId)
|
|
58
86
|
}
|
|
59
87
|
}
|
|
60
88
|
|
|
@@ -83,10 +111,11 @@ class ThemeProvider extends Component {
|
|
|
83
111
|
}
|
|
84
112
|
|
|
85
113
|
ThemeProvider.childContextTypes = {
|
|
86
|
-
[CHANNEL]: PropTypes.func
|
|
114
|
+
[CHANNEL]: PropTypes.func, // legacy
|
|
115
|
+
[CHANNEL_NEXT]: CONTEXT_CHANNEL_SHAPE,
|
|
87
116
|
}
|
|
88
117
|
ThemeProvider.contextTypes = {
|
|
89
|
-
[
|
|
118
|
+
[CHANNEL_NEXT]: CONTEXT_CHANNEL_SHAPE,
|
|
90
119
|
}
|
|
91
120
|
|
|
92
121
|
export default ThemeProvider
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
// @flow
|
|
2
2
|
/* eslint-disable react/no-multi-comp */
|
|
3
3
|
import React from 'react'
|
|
4
|
-
import PropTypes from 'prop-types'
|
|
5
4
|
import { shallow, render } from 'enzyme'
|
|
6
|
-
import ThemeProvider, {
|
|
5
|
+
import ThemeProvider, { CHANNEL_NEXT, CONTEXT_CHANNEL_SHAPE } from '../ThemeProvider'
|
|
7
6
|
|
|
8
7
|
describe('ThemeProvider', () => {
|
|
9
8
|
it('should not throw an error when no children are passed', () => {
|
|
@@ -31,7 +30,7 @@ describe('ThemeProvider', () => {
|
|
|
31
30
|
// Setup Child
|
|
32
31
|
class Child extends React.Component {
|
|
33
32
|
componentWillMount() {
|
|
34
|
-
this.context[
|
|
33
|
+
this.context[CHANNEL_NEXT].subscribe(theme => {
|
|
35
34
|
expect(theme).toEqual({ ...outerTheme, ...innerTheme })
|
|
36
35
|
done()
|
|
37
36
|
})
|
|
@@ -39,7 +38,7 @@ describe('ThemeProvider', () => {
|
|
|
39
38
|
render() { return null }
|
|
40
39
|
}
|
|
41
40
|
Child.contextTypes = {
|
|
42
|
-
[
|
|
41
|
+
[CHANNEL_NEXT]: CONTEXT_CHANNEL_SHAPE,
|
|
43
42
|
}
|
|
44
43
|
|
|
45
44
|
render(
|
|
@@ -58,7 +57,7 @@ describe('ThemeProvider', () => {
|
|
|
58
57
|
// Setup Child
|
|
59
58
|
class Child extends React.Component {
|
|
60
59
|
componentWillMount() {
|
|
61
|
-
this.context[
|
|
60
|
+
this.context[CHANNEL_NEXT].subscribe(theme => {
|
|
62
61
|
expect(theme).toEqual({ ...outerestTheme, ...outerTheme, ...innerTheme })
|
|
63
62
|
done()
|
|
64
63
|
})
|
|
@@ -66,7 +65,7 @@ describe('ThemeProvider', () => {
|
|
|
66
65
|
render() { return null }
|
|
67
66
|
}
|
|
68
67
|
Child.contextTypes = {
|
|
69
|
-
[
|
|
68
|
+
[CHANNEL_NEXT]: CONTEXT_CHANNEL_SHAPE,
|
|
70
69
|
}
|
|
71
70
|
|
|
72
71
|
render(
|
|
@@ -89,7 +88,7 @@ describe('ThemeProvider', () => {
|
|
|
89
88
|
// Setup Child
|
|
90
89
|
class Child extends React.Component {
|
|
91
90
|
componentWillMount() {
|
|
92
|
-
this.context[
|
|
91
|
+
this.context[CHANNEL_NEXT].subscribe(theme => {
|
|
93
92
|
// eslint-disable-next-line react/prop-types
|
|
94
93
|
expect(theme).toEqual(themes[this.props.shouldHaveTheme])
|
|
95
94
|
childRendered++ // eslint-disable-line no-plusplus
|
|
@@ -101,7 +100,7 @@ describe('ThemeProvider', () => {
|
|
|
101
100
|
render() { return null }
|
|
102
101
|
}
|
|
103
102
|
Child.contextTypes = {
|
|
104
|
-
[
|
|
103
|
+
[CHANNEL_NEXT]: CONTEXT_CHANNEL_SHAPE,
|
|
105
104
|
}
|
|
106
105
|
|
|
107
106
|
render(
|
package/src/native/index.js
CHANGED
|
@@ -21,7 +21,7 @@ const styled = (tag: Target) => constructWithOptions(StyledNativeComponent, tag)
|
|
|
21
21
|
/* React native lazy-requires each of these modules for some reason, so let's
|
|
22
22
|
* assume it's for a good reason and not eagerly load them all */
|
|
23
23
|
const aliases = `ActivityIndicator ActivityIndicatorIOS ART Button DatePickerIOS DrawerLayoutAndroid
|
|
24
|
-
Image ImageEditor ImageStore KeyboardAvoidingView ListView MapView Modal Navigator NavigatorIOS
|
|
24
|
+
Image ImageBackground ImageEditor ImageStore KeyboardAvoidingView ListView MapView Modal Navigator NavigatorIOS
|
|
25
25
|
Picker PickerIOS ProgressBarAndroid ProgressViewIOS ScrollView SegmentedControlIOS Slider
|
|
26
26
|
SliderIOS SnapshotViewIOS Switch RecyclerViewBackedScrollView RefreshControl StatusBar
|
|
27
27
|
SwipeableListView SwitchAndroid SwitchIOS TabBarIOS Text TextInput ToastAndroid ToolbarAndroid
|
|
@@ -32,6 +32,20 @@ describe('native', () => {
|
|
|
32
32
|
expect(view.prop('style')).toEqual([ { paddingTop: 10 }, style ])
|
|
33
33
|
})
|
|
34
34
|
|
|
35
|
+
it('should not console.warn if a comment is seen', () => {
|
|
36
|
+
const oldConsoleWarn = console.warn;
|
|
37
|
+
console.warn = jest.fn();
|
|
38
|
+
try {
|
|
39
|
+
styled.View`
|
|
40
|
+
/* this is a comment */
|
|
41
|
+
`
|
|
42
|
+
|
|
43
|
+
expect(console.warn).not.toHaveBeenCalled();
|
|
44
|
+
} finally {
|
|
45
|
+
console.warn = oldConsoleWarn;
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
|
|
35
49
|
describe('extending', () => {
|
|
36
50
|
it('should combine styles of extending components', () => {
|
|
37
51
|
const Parent = styled.View`opacity: 0.9;`
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`ssr should add a nonce to the stylesheet if webpack nonce is detected in the global scope 1`] = `"<h1 class=\\"sc-a b\\" data-reactroot=\\"\\" data-reactid=\\"1\\" data-react-checksum=\\"197727696\\">Hello SSR!</h1>"`;
|
|
4
|
+
|
|
5
|
+
exports[`ssr should add a nonce to the stylesheet if webpack nonce is detected in the global scope 2`] = `
|
|
6
|
+
"<style type=\\"text/css\\" data-styled-components=\\"\\" data-styled-components-is-local=\\"false\\" nonce=\\"foo\\">/* sc-component-id: sc-global-2303210225 */
|
|
7
|
+
body{background: papayawhip;}
|
|
8
|
+
</style><style type=\\"text/css\\" data-styled-components=\\"b\\" data-styled-components-is-local=\\"true\\" nonce=\\"foo\\">/* sc-component-id: sc-a */
|
|
9
|
+
.sc-a {}
|
|
10
|
+
|
|
11
|
+
.b{color: red;}
|
|
12
|
+
</style>"
|
|
13
|
+
`;
|
|
14
|
+
|
|
15
|
+
exports[`ssr should allow global styles to be injected during rendering 1`] = `"<h1 class=\\"PageOne a\\" data-reactroot=\\"\\" data-reactid=\\"1\\" data-react-checksum=\\"2014320521\\">Camera One!</h1>"`;
|
|
16
|
+
|
|
17
|
+
exports[`ssr should allow global styles to be injected during rendering 2`] = `
|
|
18
|
+
"<style type=\\"text/css\\" data-styled-components=\\"\\" data-styled-components-is-local=\\"false\\">/* sc-component-id: sc-global-737874422 */
|
|
19
|
+
html::before{content: 'Before both renders';}
|
|
20
|
+
</style><style type=\\"text/css\\" data-styled-components=\\"a\\" data-styled-components-is-local=\\"true\\">/* sc-component-id: PageOne */
|
|
21
|
+
.PageOne {}
|
|
22
|
+
|
|
23
|
+
.a{color: red;}
|
|
24
|
+
</style><style type=\\"text/css\\" data-styled-components=\\"\\" data-styled-components-is-local=\\"false\\">/* sc-component-id: sc-global-2914197427 */
|
|
25
|
+
html::before{content: 'During first render';}
|
|
26
|
+
</style>"
|
|
27
|
+
`;
|
|
28
|
+
|
|
29
|
+
exports[`ssr should allow global styles to be injected during rendering 3`] = `"<h2 class=\\"PageTwo b\\" data-reactroot=\\"\\" data-reactid=\\"1\\" data-react-checksum=\\"2124224444\\">Camera Two!</h2>"`;
|
|
30
|
+
|
|
31
|
+
exports[`ssr should allow global styles to be injected during rendering 4`] = `
|
|
32
|
+
"<style type=\\"text/css\\" data-styled-components=\\"\\" data-styled-components-is-local=\\"false\\">/* sc-component-id: sc-global-737874422 */
|
|
33
|
+
html::before{content: 'Before both renders';}
|
|
34
|
+
</style><style type=\\"text/css\\" data-styled-components=\\"b\\" data-styled-components-is-local=\\"true\\">/* sc-component-id: PageTwo */
|
|
35
|
+
.PageTwo {}
|
|
36
|
+
|
|
37
|
+
.b{color: blue;}
|
|
38
|
+
</style><style type=\\"text/css\\" data-styled-components=\\"\\" data-styled-components-is-local=\\"false\\">/* sc-component-id: sc-global-2914197427 */
|
|
39
|
+
html::before{content: 'During first render';}
|
|
40
|
+
/* sc-component-id: sc-global-1207956261 */
|
|
41
|
+
html::before{content: 'Between renders';}
|
|
42
|
+
/* sc-component-id: sc-global-3990873394 */
|
|
43
|
+
html::before{content: 'During second render';}
|
|
44
|
+
</style>"
|
|
45
|
+
`;
|
|
46
|
+
|
|
47
|
+
exports[`ssr should dispatch global styles to each ServerStyleSheet 1`] = `"<h1 class=\\"Header a\\" data-reactroot=\\"\\" data-reactid=\\"1\\" data-react-checksum=\\"1829114759\\"></h1>"`;
|
|
48
|
+
|
|
49
|
+
exports[`ssr should dispatch global styles to each ServerStyleSheet 2`] = `
|
|
50
|
+
"<style type=\\"text/css\\" data-styled-components=\\"\\" data-styled-components-is-local=\\"false\\">/* sc-component-id: sc-global-2303210225 */
|
|
51
|
+
body{background: papayawhip;}
|
|
52
|
+
</style><style type=\\"text/css\\" data-styled-components=\\"a\\" data-styled-components-is-local=\\"true\\">/* sc-component-id: Header */
|
|
53
|
+
.Header {}
|
|
54
|
+
|
|
55
|
+
.a{-webkit-animation:keyframe_0 1s both;animation:keyframe_0 1s both;}
|
|
56
|
+
/* sc-component-id: sc-keyframes-keyframe_0 */
|
|
57
|
+
@-webkit-keyframes keyframe_0{0%{opacity: 0;}}@keyframes keyframe_0{0%{opacity: 0;}}
|
|
58
|
+
</style>"
|
|
59
|
+
`;
|
|
60
|
+
|
|
61
|
+
exports[`ssr should extract both global and local CSS 1`] = `"<h1 class=\\"sc-a b\\" data-reactroot=\\"\\" data-reactid=\\"1\\" data-react-checksum=\\"197727696\\">Hello SSR!</h1>"`;
|
|
62
|
+
|
|
63
|
+
exports[`ssr should extract both global and local CSS 2`] = `
|
|
64
|
+
"<style type=\\"text/css\\" data-styled-components=\\"\\" data-styled-components-is-local=\\"false\\">/* sc-component-id: sc-global-2303210225 */
|
|
65
|
+
body{background: papayawhip;}
|
|
66
|
+
</style><style type=\\"text/css\\" data-styled-components=\\"b\\" data-styled-components-is-local=\\"true\\">/* sc-component-id: sc-a */
|
|
67
|
+
.sc-a {}
|
|
68
|
+
|
|
69
|
+
.b{color: red;}
|
|
70
|
+
</style>"
|
|
71
|
+
`;
|
|
72
|
+
|
|
73
|
+
exports[`ssr should extract the CSS in a simple case 1`] = `"<h1 class=\\"sc-a b\\" data-reactroot=\\"\\" data-reactid=\\"1\\" data-react-checksum=\\"197727696\\">Hello SSR!</h1>"`;
|
|
74
|
+
|
|
75
|
+
exports[`ssr should extract the CSS in a simple case 2`] = `
|
|
76
|
+
"<style type=\\"text/css\\" data-styled-components=\\"b\\" data-styled-components-is-local=\\"true\\">/* sc-component-id: sc-a */
|
|
77
|
+
.sc-a {}
|
|
78
|
+
|
|
79
|
+
.b{color: red;}
|
|
80
|
+
</style>"
|
|
81
|
+
`;
|
|
82
|
+
|
|
83
|
+
exports[`ssr should render CSS in the order the components were defined, not rendered 1`] = `"<div data-reactroot=\\"\\" data-reactid=\\"1\\" data-react-checksum=\\"275982144\\"><h2 class=\\"TWO a\\" data-reactid=\\"2\\"></h2><h1 class=\\"ONE b\\" data-reactid=\\"3\\"></h1></div>"`;
|
|
84
|
+
|
|
85
|
+
exports[`ssr should render CSS in the order the components were defined, not rendered 2`] = `
|
|
86
|
+
"<style type=\\"text/css\\" data-styled-components=\\"a b\\" data-styled-components-is-local=\\"true\\">/* sc-component-id: ONE */
|
|
87
|
+
.ONE {}
|
|
88
|
+
|
|
89
|
+
.b{color: red;}
|
|
90
|
+
/* sc-component-id: TWO */
|
|
91
|
+
.TWO {}
|
|
92
|
+
|
|
93
|
+
.a{color: blue;}
|
|
94
|
+
</style>"
|
|
95
|
+
`;
|
|
96
|
+
|
|
97
|
+
exports[`ssr should return a generated React style element 1`] = `
|
|
98
|
+
Object {
|
|
99
|
+
"dangerouslySetInnerHTML": Object {
|
|
100
|
+
"__html": "/* sc-component-id: sc-global-2303210225 */
|
|
101
|
+
body{background: papayawhip;}
|
|
102
|
+
",
|
|
103
|
+
},
|
|
104
|
+
"data-styled-components": "",
|
|
105
|
+
"data-styled-components-is-local": "false",
|
|
106
|
+
"type": "text/css",
|
|
107
|
+
}
|
|
108
|
+
`;
|
|
109
|
+
|
|
110
|
+
exports[`ssr should return a generated React style element 2`] = `
|
|
111
|
+
Object {
|
|
112
|
+
"dangerouslySetInnerHTML": Object {
|
|
113
|
+
"__html": "/* sc-component-id: sc-a */
|
|
114
|
+
.sc-a {}
|
|
115
|
+
|
|
116
|
+
.b{color: red;}
|
|
117
|
+
",
|
|
118
|
+
},
|
|
119
|
+
"data-styled-components": "b",
|
|
120
|
+
"data-styled-components-is-local": "true",
|
|
121
|
+
"type": "text/css",
|
|
122
|
+
}
|
|
123
|
+
`;
|
|
124
|
+
|
|
125
|
+
exports[`ssr should share global styles but keep renders separate 1`] = `"<h1 class=\\"PageOne a\\" data-reactroot=\\"\\" data-reactid=\\"1\\" data-react-checksum=\\"2014320521\\">Camera One!</h1>"`;
|
|
126
|
+
|
|
127
|
+
exports[`ssr should share global styles but keep renders separate 2`] = `
|
|
128
|
+
"<style type=\\"text/css\\" data-styled-components=\\"\\" data-styled-components-is-local=\\"false\\">/* sc-component-id: sc-global-2303210225 */
|
|
129
|
+
body{background: papayawhip;}
|
|
130
|
+
</style><style type=\\"text/css\\" data-styled-components=\\"a\\" data-styled-components-is-local=\\"true\\">/* sc-component-id: PageOne */
|
|
131
|
+
.PageOne {}
|
|
132
|
+
|
|
133
|
+
.a{color: red;}
|
|
134
|
+
</style>"
|
|
135
|
+
`;
|
|
136
|
+
|
|
137
|
+
exports[`ssr should share global styles but keep renders separate 3`] = `"<h2 class=\\"PageTwo b\\" data-reactroot=\\"\\" data-reactid=\\"1\\" data-react-checksum=\\"2124224444\\">Camera Two!</h2>"`;
|
|
138
|
+
|
|
139
|
+
exports[`ssr should share global styles but keep renders separate 4`] = `
|
|
140
|
+
"<style type=\\"text/css\\" data-styled-components=\\"\\" data-styled-components-is-local=\\"false\\">/* sc-component-id: sc-global-2303210225 */
|
|
141
|
+
body{background: papayawhip;}
|
|
142
|
+
</style><style type=\\"text/css\\" data-styled-components=\\"b\\" data-styled-components-is-local=\\"true\\">/* sc-component-id: PageTwo */
|
|
143
|
+
.PageTwo {}
|
|
144
|
+
|
|
145
|
+
.b{color: blue;}
|
|
146
|
+
</style>"
|
|
147
|
+
`;
|
|
@@ -62,6 +62,30 @@ describe('expanded api', () => {
|
|
|
62
62
|
expect(Comp2.styledComponentId).toBe('Comp2-OMGLOL')
|
|
63
63
|
expect(shallow(<Comp2 />).prop('className')).toMatch(/Comp2-OMGLOL/)
|
|
64
64
|
})
|
|
65
|
+
|
|
66
|
+
it('should work with `.extend`', () => {
|
|
67
|
+
const Comp = styled.div.withConfig({ displayName: 'Comp', componentId: 'LOLOMG' })`
|
|
68
|
+
color: blue;
|
|
69
|
+
`
|
|
70
|
+
const Comp2 = Comp.extend`
|
|
71
|
+
color: ${'red'};
|
|
72
|
+
background: ${props => props.bg};
|
|
73
|
+
`
|
|
74
|
+
expect(Comp.styledComponentId).toBe('Comp-LOLOMG')
|
|
75
|
+
expect(shallow(<Comp />).prop('className')).toMatch(/Comp-LOLOMG/)
|
|
76
|
+
expect(Comp2.styledComponentId).toBe('LOLOMG-Comp-a')
|
|
77
|
+
expect(shallow(<Comp2 bg="red" />).prop('className')).toMatch(/LOLOMG-Comp-a/)
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
it('should work with `.withComponent`', () => {
|
|
81
|
+
const Dummy = () => null
|
|
82
|
+
const Comp = styled.div.withConfig({ displayName: 'Comp', componentId: 'OMGLOL' })``.withComponent('h1')
|
|
83
|
+
const Comp2 = styled.div.withConfig({ displayName: 'Comp2', componentId: 'OMFG' })``.withComponent(Dummy)
|
|
84
|
+
expect(Comp.styledComponentId).toBe('Comp-OMGLOL-h1')
|
|
85
|
+
expect(shallow(<Comp />).prop('className')).toMatch(/Comp-OMGLOL-h1/)
|
|
86
|
+
expect(Comp2.styledComponentId).toBe('Comp2-OMFG-Dummy')
|
|
87
|
+
expect(shallow(<Comp2 />).prop('className')).toMatch(/Comp2-OMFG-Dummy/)
|
|
88
|
+
})
|
|
65
89
|
})
|
|
66
90
|
|
|
67
91
|
describe('chaining', () => {
|
package/src/test/props.test.js
CHANGED
|
@@ -19,10 +19,21 @@ describe('props', () => {
|
|
|
19
19
|
expectCSSMatches('.sc-a {} .b { color: black; }')
|
|
20
20
|
})
|
|
21
21
|
it('should execute interpolations and inject props', () => {
|
|
22
|
+
const Comp = styled.div`color: ${props => props.fg || 'black'};`
|
|
23
|
+
shallow(<Comp fg="red" />)
|
|
24
|
+
expectCSSMatches('.sc-a {} .b { color: red; }')
|
|
25
|
+
})
|
|
26
|
+
it('should ignore non-0 falsy object interpolations', () => {
|
|
22
27
|
const Comp = styled.div`
|
|
23
|
-
|
|
28
|
+
${() => ({
|
|
29
|
+
borderWidth: 0,
|
|
30
|
+
colorA: null,
|
|
31
|
+
colorB: false,
|
|
32
|
+
colorC: undefined,
|
|
33
|
+
colorD: '',
|
|
34
|
+
})};
|
|
24
35
|
`
|
|
25
|
-
shallow(<Comp fg="red"/>)
|
|
26
|
-
expectCSSMatches('.sc-a {} .b {
|
|
36
|
+
shallow(<Comp fg="red" />)
|
|
37
|
+
expectCSSMatches('.sc-a {} .b { border-width: 0; ; ; }')
|
|
27
38
|
})
|
|
28
39
|
})
|