1
1
/**
2
- * Copyright (c) 2016-present, Nicolas Gallagher.
2
+ * Copyright (c) Nicolas Gallagher.
3
3
*
4
4
* This source code is licensed under the MIT license found in the
5
5
* LICENSE file in the root directory of this source tree.
13
13
*/
14
14
15
15
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment' ;
16
- import createReactDOMStyle from './createReactDOMStyle' ;
16
+ import createCSSStyleSheet from './createCSSStyleSheet' ;
17
+ import createCompileableStyle from './createCompileableStyle' ;
18
+ import createOrderedCSSStyleSheet from './createOrderedCSSStyleSheet' ;
17
19
import flattenArray from '../../modules/flattenArray' ;
18
20
import flattenStyle from './flattenStyle' ;
19
21
import I18nManager from '../I18nManager' ;
20
22
import i18nStyle from './i18nStyle' ;
21
- import { prefixInlineStyles } from '../../modules/prefixStyles' ;
22
- import StyleSheetManager from './StyleSheetManager' ;
23
+ import { atomic , inline , stringifyValueWithProperty } from './compile' ;
24
+ import initialRules from './initialRules' ;
25
+ import modality from './modality' ;
26
+ import { STYLE_ELEMENT_ID , STYLE_GROUPS } from './constants' ;
23
27
24
28
const emptyObject = { } ;
25
29
26
30
export default class ReactNativeStyleResolver {
27
31
_init ( ) {
28
32
this . cache = { ltr : { } , rtl : { } , rtlNoSwap : { } } ;
29
33
this . injectedCache = { ltr : { } , rtl : { } , rtlNoSwap : { } } ;
30
- this . styleSheetManager = new StyleSheetManager ( ) ;
34
+ this . sheet = createOrderedCSSStyleSheet ( createCSSStyleSheet ( STYLE_ELEMENT_ID ) ) ;
35
+ this . _lookupCache = {
36
+ byClassName : { } ,
37
+ byProp : { }
38
+ } ;
31
39
}
32
40
33
41
constructor ( ) {
34
42
this . _init ( ) ;
43
+ modality ( rule => this . sheet . insert ( rule , STYLE_GROUPS . modality ) ) ;
44
+ initialRules . forEach ( rule => {
45
+ this . sheet . insert ( rule , STYLE_GROUPS . reset ) ;
46
+ } ) ;
47
+ }
48
+
49
+ _addToCache ( className , prop , value ) {
50
+ const cache = this . _lookupCache ;
51
+ if ( ! cache . byProp [ prop ] ) {
52
+ cache . byProp [ prop ] = { } ;
53
+ }
54
+ cache . byProp [ prop ] [ value ] = className ;
55
+ cache . byClassName [ className ] = { prop, value } ;
56
+ }
57
+
58
+ getClassName ( prop , value ) {
59
+ const val = stringifyValueWithProperty ( value , prop ) ;
60
+ const cache = this . _lookupCache . byProp ;
61
+ return cache [ prop ] && cache [ prop ] . hasOwnProperty ( val ) && cache [ prop ] [ val ] ;
62
+ }
63
+
64
+ getDeclaration ( className ) {
65
+ const cache = this . _lookupCache . byClassName ;
66
+ return cache [ className ] || emptyObject ;
35
67
}
36
68
37
69
getStyleSheet ( ) {
38
70
// reset state on the server so critical css is always the result
39
- const sheet = this . styleSheetManager . getStyleSheet ( ) ;
71
+ const textContent = this . sheet . getTextContent ( ) ;
40
72
if ( ! canUseDOM ) {
41
73
this . _init ( ) ;
42
74
}
43
- return sheet ;
75
+ return {
76
+ id : STYLE_ELEMENT_ID ,
77
+ textContent
78
+ } ;
44
79
}
45
80
46
81
_injectRegisteredStyle ( id ) {
47
82
const { doLeftAndRightSwapInRTL, isRTL } = I18nManager ;
48
83
const dir = isRTL ? ( doLeftAndRightSwapInRTL ? 'rtl' : 'rtlNoSwap' ) : 'ltr' ;
49
84
if ( ! this . injectedCache [ dir ] [ id ] ) {
50
- const style = flattenStyle ( id ) ;
51
- const domStyle = createReactDOMStyle ( i18nStyle ( style ) ) ;
52
- Object . keys ( domStyle ) . forEach ( styleProp => {
53
- const value = domStyle [ styleProp ] ;
54
- if ( value != null ) {
55
- this . styleSheetManager . injectDeclaration ( styleProp , value ) ;
56
- }
85
+ const style = createCompileableStyle ( i18nStyle ( flattenStyle ( id ) ) ) ;
86
+ const results = atomic ( style ) ;
87
+ Object . values ( results ) . forEach ( ( { identifier, property, rules, value } ) => {
88
+ this . _addToCache ( identifier , property , value ) ;
89
+ rules . forEach ( rule => {
90
+ const group = STYLE_GROUPS . custom [ property ] || STYLE_GROUPS . atomic ;
91
+ this . sheet . insert ( rule , group ) ;
92
+ } ) ;
57
93
} ) ;
58
94
this . injectedCache [ dir ] [ id ] = true ;
59
95
}
@@ -91,7 +127,7 @@ export default class ReactNativeStyleResolver {
91
127
isArrayOfNumbers = false ;
92
128
} else {
93
129
if ( isArrayOfNumbers ) {
94
- cacheKey += ( id + '-' ) ;
130
+ cacheKey += id + '-' ;
95
131
}
96
132
this . _injectRegisteredStyle ( id ) ;
97
133
}
@@ -113,7 +149,7 @@ export default class ReactNativeStyleResolver {
113
149
// Preserves unrecognized class names.
114
150
const { classList : rnClassList , style : rnStyle } = rdomClassList . reduce (
115
151
( styleProps , className ) => {
116
- const { prop, value } = this . styleSheetManager . getDeclaration ( className ) ;
152
+ const { prop, value } = this . getDeclaration ( className ) ;
117
153
if ( prop ) {
118
154
styleProps . style [ prop ] = value ;
119
155
} else {
@@ -138,7 +174,7 @@ export default class ReactNativeStyleResolver {
138
174
// Next class names take priority over current inline styles
139
175
const style = { ...rdomStyle } ;
140
176
rdomClassListNext . forEach ( className => {
141
- const { prop } = this . styleSheetManager . getDeclaration ( className ) ;
177
+ const { prop } = this . getDeclaration ( className ) ;
142
178
if ( style [ prop ] ) {
143
179
style [ prop ] = '' ;
144
180
}
@@ -154,45 +190,50 @@ export default class ReactNativeStyleResolver {
154
190
*/
155
191
_resolveStyle ( style ) {
156
192
const flatStyle = flattenStyle ( style ) ;
157
- const domStyle = createReactDOMStyle ( i18nStyle ( flatStyle ) ) ;
158
-
159
- const props = Object . keys ( domStyle ) . reduce (
160
- ( props , styleProp ) => {
161
- const value = domStyle [ styleProp ] ;
162
- if ( value != null ) {
163
- const className = this . styleSheetManager . getClassName ( styleProp , value ) ;
164
- if ( className ) {
165
- props . classList . push ( className ) ;
166
- } else {
167
- // Certain properties and values are not transformed by 'createReactDOMStyle' as they
168
- // require more complex transforms into multiple CSS rules. Here we assume that StyleManager
169
- // can bind these styles to a className, and prevent them becoming invalid inline-styles.
170
- if (
171
- styleProp === 'pointerEvents' ||
172
- styleProp === 'placeholderTextColor' ||
173
- styleProp === 'animationName'
174
- ) {
175
- const className = this . styleSheetManager . injectDeclaration ( styleProp , value ) ;
176
- if ( className ) {
177
- props . classList . push ( className ) ;
178
- }
193
+ const localizedStyle = createCompileableStyle ( i18nStyle ( flatStyle ) ) ;
194
+
195
+ const props = Object . keys ( localizedStyle )
196
+ . sort ( )
197
+ . reduce (
198
+ ( props , styleProp ) => {
199
+ const value = localizedStyle [ styleProp ] ;
200
+ if ( value != null ) {
201
+ const className = this . getClassName ( styleProp , value ) ;
202
+ if ( className ) {
203
+ props . classList . push ( className ) ;
179
204
} else {
180
- if ( ! props . style ) {
181
- props . style = { } ;
205
+ // Certain properties and values are not transformed by 'createReactDOMStyle' as they
206
+ // require more complex transforms into multiple CSS rules. Here we assume that StyleManager
207
+ // can bind these styles to a className, and prevent them becoming invalid inline-styles.
208
+ if (
209
+ styleProp === 'pointerEvents' ||
210
+ styleProp === 'placeholderTextColor' ||
211
+ styleProp === 'animationKeyframes'
212
+ ) {
213
+ const a = atomic ( { [ styleProp ] : value } ) ;
214
+ Object . values ( a ) . forEach ( ( { identifier, rules } ) => {
215
+ props . classList . push ( identifier ) ;
216
+ rules . forEach ( rule => {
217
+ this . sheet . insert ( rule , STYLE_GROUPS . atomic ) ;
218
+ } ) ;
219
+ } ) ;
220
+ } else {
221
+ if ( ! props . style ) {
222
+ props . style = { } ;
223
+ }
224
+ // 4x slower render
225
+ props . style [ styleProp ] = value ;
182
226
}
183
- // 4x slower render
184
- props . style [ styleProp ] = value ;
185
227
}
186
228
}
187
- }
188
- return props ;
189
- } ,
190
- { classList : [ ] }
191
- ) ;
229
+ return props ;
230
+ } ,
231
+ { classList : [ ] }
232
+ ) ;
192
233
193
234
props . className = classListToString ( props . classList ) ;
194
235
if ( props . style ) {
195
- props . style = prefixInlineStyles ( props . style ) ;
236
+ props . style = inline ( props . style ) ;
196
237
}
197
238
return props ;
198
239
}
0 commit comments