-
Notifications
You must be signed in to change notification settings - Fork 24.4k
/
Copy pathStyleSheet.js
372 lines (346 loc) · 11.7 KB
/
StyleSheet.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
'use strict';
const PixelRatio = require('../Utilities/PixelRatio');
const ReactNativeStyleAttributes = require('../Components/View/ReactNativeStyleAttributes');
const flatten = require('./flattenStyle');
import type {
____ColorValue_Internal,
____Styles_Internal,
____DangerouslyImpreciseStyle_Internal,
____DangerouslyImpreciseStyleProp_Internal,
____ViewStyle_Internal,
____ViewStyleProp_Internal,
____TextStyle_Internal,
____TextStyleProp_Internal,
____ImageStyle_Internal,
____ImageStyleProp_Internal,
} from './StyleSheetTypes';
/**
* This type should be used as the type for anything that is a color. It is
* most useful when using DynamicColorIOS which can be a string or a dynamic
* color object.
*
* type props = {backgroundColor: ColorValue};
*/
export type ColorValue = ____ColorValue_Internal;
/**
* This type should be used as the type for a prop that is passed through
* to a <View>'s `style` prop. This ensures call sites of the component
* can't pass styles that View doesn't support such as `fontSize`.`
*
* type Props = {style: ViewStyleProp}
* const MyComponent = (props: Props) => <View style={props.style} />
*/
export type ViewStyleProp = ____ViewStyleProp_Internal;
/**
* This type should be used as the type for a prop that is passed through
* to a <Text>'s `style` prop. This ensures call sites of the component
* can't pass styles that Text doesn't support such as `resizeMode`.`
*
* type Props = {style: TextStyleProp}
* const MyComponent = (props: Props) => <Text style={props.style} />
*/
export type TextStyleProp = ____TextStyleProp_Internal;
/**
* This type should be used as the type for a prop that is passed through
* to an <Image>'s `style` prop. This ensures call sites of the component
* can't pass styles that Image doesn't support such as `fontSize`.`
*
* type Props = {style: ImageStyleProp}
* const MyComponent = (props: Props) => <Image style={props.style} />
*/
export type ImageStyleProp = ____ImageStyleProp_Internal;
/**
* WARNING: You probably shouldn't be using this type. This type
* is similar to the ones above except it allows styles that are accepted
* by all of View, Text, or Image. It is therefore very unsafe to pass this
* through to an underlying component. Using this is almost always a mistake
* and using one of the other more restrictive types is likely the right choice.
*/
export type DangerouslyImpreciseStyleProp = ____DangerouslyImpreciseStyleProp_Internal;
/**
* Utility type for getting the values for specific style keys.
*
* The following is bad because position is more restrictive than 'string':
* ```
* type Props = {position: string};
* ```
*
* You should use the following instead:
*
* ```
* type Props = {position: TypeForStyleKey<'position'>};
* ```
*
* This will correctly give you the type 'absolute' | 'relative'
*/
export type TypeForStyleKey<
+key: $Keys<____DangerouslyImpreciseStyle_Internal>,
> = $ElementType<____DangerouslyImpreciseStyle_Internal, key>;
/**
* This type is an object of the different possible style
* properties that can be specified for View.
*
* Note that this isn't a safe way to type a style prop for a component as
* results from StyleSheet.create return an internal identifier, not
* an object of styles.
*
* If you want to type the style prop of a function,
* consider using ViewStyleProp.
*
* A reasonable usage of this type is for helper functions that return an
* object of styles to pass to a View that can't be precomputed with
* StyleSheet.create.
*/
export type ViewStyle = ____ViewStyle_Internal;
/**
* This type is an object of the different possible style
* properties that can be specified for Text.
*
* Note that this isn't a safe way to type a style prop for a component as
* results from StyleSheet.create return an internal identifier, not
* an object of styles.
*
* If you want to type the style prop of a function,
* consider using TextStyleProp.
*
* A reasonable usage of this type is for helper functions that return an
* object of styles to pass to a Text that can't be precomputed with
* StyleSheet.create.
*/
export type TextStyle = ____TextStyle_Internal;
/**
* This type is an object of the different possible style
* properties that can be specified for Image.
*
* Note that this isn't a safe way to type a style prop for a component as
* results from StyleSheet.create return an internal identifier, not
* an object of styles.
*
* If you want to type the style prop of a function,
* consider using ImageStyleProp.
*
* A reasonable usage of this type is for helper functions that return an
* object of styles to pass to an Image that can't be precomputed with
* StyleSheet.create.
*/
export type ImageStyle = ____ImageStyle_Internal;
/**
* WARNING: You probably shouldn't be using this type. This type is an object
* with all possible style keys and their values. Note that this isn't
* a safe way to type a style prop for a component as results from
* StyleSheet.create return an internal identifier, not an object of styles.
*
* If you want to type the style prop of a function, consider using
* ViewStyleProp, TextStyleProp, or ImageStyleProp.
*
* This should only be used by very core utilities that operate on an object
* containing any possible style value.
*/
export type DangerouslyImpreciseStyle = ____DangerouslyImpreciseStyle_Internal;
let hairlineWidth: number = PixelRatio.roundToNearestPixel(0.4);
if (hairlineWidth === 0) {
hairlineWidth = 1 / PixelRatio.get();
}
const absoluteFill = {
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
};
if (__DEV__) {
Object.freeze(absoluteFill);
}
/**
* A StyleSheet is an abstraction similar to CSS StyleSheets
*
* Create a new StyleSheet:
*
* ```
* const styles = StyleSheet.create({
* container: {
* borderRadius: 4,
* borderWidth: 0.5,
* borderColor: '#d6d7da',
* },
* title: {
* fontSize: 19,
* fontWeight: 'bold',
* },
* activeTitle: {
* color: 'red',
* },
* });
* ```
*
* Use a StyleSheet:
*
* ```
* <View style={styles.container}>
* <Text style={[styles.title, this.props.isActive && styles.activeTitle]} />
* </View>
* ```
*
* Code quality:
*
* - By moving styles away from the render function, you're making the code
* easier to understand.
* - Naming the styles is a good way to add meaning to the low level components
* in the render function.
*
* Performance:
*
* - Making a stylesheet from a style object makes it possible to refer to it
* by ID instead of creating a new style object every time.
* - It also allows to send the style only once through the bridge. All
* subsequent uses are going to refer an id (not implemented yet).
*/
module.exports = {
/**
* This is defined as the width of a thin line on the platform. It can be
* used as the thickness of a border or division between two elements.
* Example:
* ```
* {
* borderBottomColor: '#bbb',
* borderBottomWidth: StyleSheet.hairlineWidth
* }
* ```
*
* This constant will always be a round number of pixels (so a line defined
* by it look crisp) and will try to match the standard width of a thin line
* on the underlying platform. However, you should not rely on it being a
* constant size, because on different platforms and screen densities its
* value may be calculated differently.
*
* A line with hairline width may not be visible if your simulator is downscaled.
*/
hairlineWidth,
/**
* A very common pattern is to create overlays with position absolute and zero positioning,
* so `absoluteFill` can be used for convenience and to reduce duplication of these repeated
* styles.
*/
absoluteFill: (absoluteFill: any), // TODO: This should be updated after we fix downstream Flow sites.
/**
* Sometimes you may want `absoluteFill` but with a couple tweaks - `absoluteFillObject` can be
* used to create a customized entry in a `StyleSheet`, e.g.:
*
* const styles = StyleSheet.create({
* wrapper: {
* ...StyleSheet.absoluteFillObject,
* top: 10,
* backgroundColor: 'transparent',
* },
* });
*/
absoluteFillObject: absoluteFill,
/**
* Combines two styles such that `style2` will override any styles in `style1`.
* If either style is falsy, the other one is returned without allocating an
* array, saving allocations and maintaining reference equality for
* PureComponent checks.
*/
compose<T: DangerouslyImpreciseStyleProp>(
style1: ?T,
style2: ?T,
): ?T | $ReadOnlyArray<T> {
if (style1 != null && style2 != null) {
return ([style1, style2]: $ReadOnlyArray<T>);
} else {
return style1 != null ? style1 : style2;
}
},
/**
* Flattens an array of style objects, into one aggregated style object.
* Alternatively, this method can be used to lookup IDs, returned by
* StyleSheet.register.
*
* > **NOTE**: Exercise caution as abusing this can tax you in terms of
* > optimizations.
* >
* > IDs enable optimizations through the bridge and memory in general. Referring
* > to style objects directly will deprive you of these optimizations.
*
* Example:
* ```
* const styles = StyleSheet.create({
* listItem: {
* flex: 1,
* fontSize: 16,
* color: 'white'
* },
* selectedListItem: {
* color: 'green'
* }
* });
*
* StyleSheet.flatten([styles.listItem, styles.selectedListItem])
* // returns { flex: 1, fontSize: 16, color: 'green' }
* ```
* Alternative use:
* ```
* StyleSheet.flatten(styles.listItem);
* // return { flex: 1, fontSize: 16, color: 'white' }
* // Simply styles.listItem would return its ID (number)
* ```
* This method internally uses `StyleSheetRegistry.getStyleByID(style)`
* to resolve style objects represented by IDs. Thus, an array of style
* objects (instances of StyleSheet.create), are individually resolved to,
* their respective objects, merged as one and then returned. This also explains
* the alternative use.
*/
flatten,
/**
* WARNING: EXPERIMENTAL. Breaking changes will probably happen a lot and will
* not be reliably announced. The whole thing might be deleted, who knows? Use
* at your own risk.
*
* Sets a function to use to pre-process a style property value. This is used
* internally to process color and transform values. You should not use this
* unless you really know what you are doing and have exhausted other options.
*/
setStyleAttributePreprocessor(
property: string,
process: (nextProp: mixed) => mixed,
) {
let value;
if (ReactNativeStyleAttributes[property] === true) {
value = {process};
} else if (typeof ReactNativeStyleAttributes[property] === 'object') {
value = {...ReactNativeStyleAttributes[property], process};
} else {
console.error(`${property} is not a valid style attribute`);
return;
}
if (__DEV__ && typeof value.process === 'function') {
console.warn(`Overwriting ${property} style attribute preprocessor`);
}
ReactNativeStyleAttributes[property] = value;
},
/**
* Creates a StyleSheet style reference from the given object.
*/
create<+S: ____Styles_Internal>(obj: S): $ReadOnly<S> {
// TODO: This should return S as the return type. But first,
// we need to codemod all the callsites that are typing this
// return value as a number (even though it was opaque).
if (__DEV__) {
for (const key in obj) {
if (obj[key]) {
Object.freeze(obj[key]);
}
}
}
return obj;
},
};