@mochi-inc-japan/react-native-stylex-sheet 1.0.0
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/LICENSE +21 -0
- package/README.ja.md +608 -0
- package/README.md +599 -0
- package/lib/commonjs/index.js +65 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/tests/index.test.js +224 -0
- package/lib/commonjs/tests/index.test.js.map +1 -0
- package/lib/commonjs/tests/media.test.js +226 -0
- package/lib/commonjs/tests/media.test.js.map +1 -0
- package/lib/commonjs/tests/mock.test.js +54 -0
- package/lib/commonjs/tests/mock.test.js.map +1 -0
- package/lib/commonjs/tests/test-utils.js +60 -0
- package/lib/commonjs/tests/test-utils.js.map +1 -0
- package/lib/commonjs/utils/base.js +72 -0
- package/lib/commonjs/utils/base.js.map +1 -0
- package/lib/commonjs/utils/hooks.js +60 -0
- package/lib/commonjs/utils/hooks.js.map +1 -0
- package/lib/commonjs/utils/media.js +69 -0
- package/lib/commonjs/utils/media.js.map +1 -0
- package/lib/commonjs/utils/theme.js +25 -0
- package/lib/commonjs/utils/theme.js.map +1 -0
- package/lib/commonjs/utils/tokens.js +18 -0
- package/lib/commonjs/utils/tokens.js.map +1 -0
- package/lib/commonjs/utils/types.js +6 -0
- package/lib/commonjs/utils/types.js.map +1 -0
- package/lib/commonjs/utils/variant.js +75 -0
- package/lib/commonjs/utils/variant.js.map +1 -0
- package/lib/module/index.js +6 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/tests/index.test.js +220 -0
- package/lib/module/tests/index.test.js.map +1 -0
- package/lib/module/tests/media.test.js +222 -0
- package/lib/module/tests/media.test.js.map +1 -0
- package/lib/module/tests/mock.test.js +49 -0
- package/lib/module/tests/mock.test.js.map +1 -0
- package/lib/module/tests/test-utils.js +52 -0
- package/lib/module/tests/test-utils.js.map +1 -0
- package/lib/module/utils/base.js +63 -0
- package/lib/module/utils/base.js.map +1 -0
- package/lib/module/utils/hooks.js +52 -0
- package/lib/module/utils/hooks.js.map +1 -0
- package/lib/module/utils/media.js +59 -0
- package/lib/module/utils/media.js.map +1 -0
- package/lib/module/utils/theme.js +16 -0
- package/lib/module/utils/theme.js.map +1 -0
- package/lib/module/utils/tokens.js +11 -0
- package/lib/module/utils/tokens.js.map +1 -0
- package/lib/module/utils/types.js +2 -0
- package/lib/module/utils/types.js.map +1 -0
- package/lib/module/utils/variant.js +65 -0
- package/lib/module/utils/variant.js.map +1 -0
- package/lib/types/index.d.ts +6 -0
- package/lib/types/tests/check-descriptor.test.d.ts +0 -0
- package/lib/types/tests/index.test.d.ts +1 -0
- package/lib/types/tests/media.test.d.ts +1 -0
- package/lib/types/tests/mock.test.d.ts +1 -0
- package/lib/types/tests/test-utils.d.ts +7 -0
- package/lib/types/tests/utils.d.ts +6 -0
- package/lib/types/utils/base.d.ts +13 -0
- package/lib/types/utils/hooks.d.ts +16 -0
- package/lib/types/utils/index.d.ts +9 -0
- package/lib/types/utils/media.d.ts +5 -0
- package/lib/types/utils/theme.d.ts +14 -0
- package/lib/types/utils/tokens.d.ts +3 -0
- package/lib/types/utils/types.d.ts +28 -0
- package/lib/types/utils/utils.d.ts +4 -0
- package/lib/types/utils/variant.d.ts +50 -0
- package/package.json +132 -0
package/README.md
ADDED
|
@@ -0,0 +1,599 @@
|
|
|
1
|
+
# react-native-stylex-sheet
|
|
2
|
+
|
|
3
|
+
A lightweight, fast CSS-in-JS library for React Native. It maintains backward compatibility with React Native's standard `StyleSheet` CSS syntax while adding extensions such as themes and variants that are not natively supported. The goal is to provide an interface as compatible as possible with [stylexjs](https://stylexjs.com/docs/learn/recipes/variants/) on the web, simplifying cross-platform development. Because only React Native and React are peer dependencies, components built with this library can run as-is on react-native-web, as long as they don't include code that depends on native APIs or device-specific behavior.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install @mochi-inc-japan/react-native-stylex-sheet
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick start
|
|
12
|
+
|
|
13
|
+
### Simple usage (no theme / variants / media)
|
|
14
|
+
|
|
15
|
+
When you don't need theming, variants, or responsive media queries, use the namespace import:
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import * as stylex from '@mochi-inc-japan/react-native-stylex-sheet';
|
|
19
|
+
|
|
20
|
+
const styles = stylex.create({
|
|
21
|
+
button: {
|
|
22
|
+
padding: 16,
|
|
23
|
+
borderRadius: 8,
|
|
24
|
+
backgroundColor: '#6200ee',
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
function Button() {
|
|
29
|
+
return (
|
|
30
|
+
<Pressable {...stylex.props(styles.button)}>
|
|
31
|
+
<Text>Press me</Text>
|
|
32
|
+
</Pressable>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
For dynamic styles, pass a style object directly to `props()`:
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
import * as stylex from '@mochi-inc-japan/react-native-stylex-sheet';
|
|
41
|
+
|
|
42
|
+
const styles = stylex.create({
|
|
43
|
+
button: {
|
|
44
|
+
padding: 16,
|
|
45
|
+
borderRadius: 8,
|
|
46
|
+
backgroundColor: '#6200ee',
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
function Button({ width }) {
|
|
51
|
+
return (
|
|
52
|
+
<Pressable {...stylex.props(styles.button, { width })}>
|
|
53
|
+
<Text>Press me</Text>
|
|
54
|
+
</Pressable>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Advanced usage (theme / variants / media)
|
|
60
|
+
|
|
61
|
+
When using theming, variants, or responsive breakpoints, wrap the app in `RNStyleXProvider` and use `const stylex = useStylex()` inside components.
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
import {
|
|
65
|
+
create,
|
|
66
|
+
createVariants,
|
|
67
|
+
createThemes,
|
|
68
|
+
defineConsts,
|
|
69
|
+
useStylex,
|
|
70
|
+
RNStyleXProvider,
|
|
71
|
+
} from '@mochi-inc-japan/react-native-stylex-sheet';
|
|
72
|
+
import type { Variants } from '@mochi-inc-japan/react-native-stylex-sheet';
|
|
73
|
+
|
|
74
|
+
// 1. Define media breakpoints as constants
|
|
75
|
+
const media = defineConsts({
|
|
76
|
+
md: '(width >= 750px)',
|
|
77
|
+
lg: '(width >= 1080px)',
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// 2. Define themes
|
|
81
|
+
const { themes } = createThemes(['light', 'dark']);
|
|
82
|
+
|
|
83
|
+
// 3. Define variant groups (optional)
|
|
84
|
+
const buttonVariants = createVariants({
|
|
85
|
+
color: {
|
|
86
|
+
backgroundColor: {
|
|
87
|
+
default: '#6200ee',
|
|
88
|
+
danger: '#b00020',
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// 4. Define styles at module level
|
|
94
|
+
const styles = create({
|
|
95
|
+
button: {
|
|
96
|
+
...buttonVariants.color,
|
|
97
|
+
padding: {
|
|
98
|
+
default: 12,
|
|
99
|
+
[media.md]: 16,
|
|
100
|
+
},
|
|
101
|
+
borderRadius: 8,
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// 5. Wrap your app in RNStyleXProvider
|
|
106
|
+
function App() {
|
|
107
|
+
const [dark, setDark] = useState(false);
|
|
108
|
+
return (
|
|
109
|
+
<RNStyleXProvider theme={dark ? themes.dark : undefined}>
|
|
110
|
+
<Screen />
|
|
111
|
+
</RNStyleXProvider>
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// 6. Use const stylex = useStylex() inside components
|
|
116
|
+
// — theme and media from RNStyleXProvider are applied automatically in mix()
|
|
117
|
+
function Button({ danger }: { danger?: boolean }) {
|
|
118
|
+
const stylex = useStylex();
|
|
119
|
+
return (
|
|
120
|
+
<Pressable
|
|
121
|
+
{...stylex.props(
|
|
122
|
+
stylex.mix<Variants<typeof buttonVariants>>(styles.button, { color: danger ? 'danger' : 'default' })
|
|
123
|
+
)}
|
|
124
|
+
>
|
|
125
|
+
<Text>Press me</Text>
|
|
126
|
+
</Pressable>
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
When using `useStylex()` with `RNStyleXProvider`, the provider's theme and media are applied automatically, so `mix()` can be omitted when no variants are needed. You can also explicitly override `width` or `theme` at the call site. Because the standalone `mix` function exported from the library cannot omit these, it is recommended to use the `mix` from `useStylex()` for any component that needs theme, variants, or media.
|
|
132
|
+
|
|
133
|
+
```tsx
|
|
134
|
+
// const stylex = useStylex();
|
|
135
|
+
// or
|
|
136
|
+
// import * as stylex from '@mochi-inc-japan/react-native-stylex-sheet'
|
|
137
|
+
stylex.mix<Variants<typeof buttonVariants>>(
|
|
138
|
+
[
|
|
139
|
+
styles.button,
|
|
140
|
+
{
|
|
141
|
+
media: stylex.windowWidth,
|
|
142
|
+
theme: themes.dark
|
|
143
|
+
}
|
|
144
|
+
],
|
|
145
|
+
{ color: danger ? 'danger' : 'default' }
|
|
146
|
+
);
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Migrating from existing React Native components
|
|
152
|
+
|
|
153
|
+
`stylex.create` maintains backward compatibility with React Native's standard `StyleSheet.create` as long as the extended syntax is not used, so existing React Native styles can be reused as-is. This means you don't need to migrate all components at once — you can replace them incrementally.
|
|
154
|
+
|
|
155
|
+
```tsx
|
|
156
|
+
// Before
|
|
157
|
+
import { StyleSheet } from 'react-native';
|
|
158
|
+
|
|
159
|
+
const styles = StyleSheet.create({
|
|
160
|
+
button: {
|
|
161
|
+
padding: 16,
|
|
162
|
+
borderRadius: 8,
|
|
163
|
+
backgroundColor: '#6200ee',
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
function Button() {
|
|
168
|
+
return (
|
|
169
|
+
<Pressable>
|
|
170
|
+
<Text>Press me</Text>
|
|
171
|
+
</Pressable>
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// After
|
|
176
|
+
import * as stylex from '@mochi-inc-japan/react-native-stylex-sheet';
|
|
177
|
+
|
|
178
|
+
const styles = stylex.create({
|
|
179
|
+
button: {
|
|
180
|
+
padding: 16,
|
|
181
|
+
borderRadius: 8,
|
|
182
|
+
backgroundColor: '#6200ee',
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
function Button() {
|
|
187
|
+
return (
|
|
188
|
+
<Pressable {...stylex.props(styles.button)}>
|
|
189
|
+
<Text>Press me</Text>
|
|
190
|
+
</Pressable>
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Setup pattern
|
|
196
|
+
|
|
197
|
+
It is recommended to define shared constants (media breakpoints and themes) in a single file and export them:
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
// src/styles/stylex.ts
|
|
201
|
+
import {
|
|
202
|
+
createThemes,
|
|
203
|
+
defineConsts,
|
|
204
|
+
} from '@mochi-inc-japan/react-native-stylex-sheet';
|
|
205
|
+
|
|
206
|
+
export const media = defineConsts({
|
|
207
|
+
md: '(width >= 750px)',
|
|
208
|
+
lg: '(width >= 1080px)',
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
export const fontSize = defineConsts({
|
|
212
|
+
default: 16,
|
|
213
|
+
md: 24,
|
|
214
|
+
lg: 32,
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
export const { themes } = createThemes(['light', 'dark']);
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## API reference
|
|
223
|
+
|
|
224
|
+
### `defineConsts(consts)`
|
|
225
|
+
|
|
226
|
+
Returns a frozen copy of the given object. Use for module-level constants such as media query strings or other shared values.
|
|
227
|
+
|
|
228
|
+
```ts
|
|
229
|
+
const media = defineConsts({
|
|
230
|
+
md: '(width >= 750px)',
|
|
231
|
+
lg: '(width >= 1080px)',
|
|
232
|
+
});
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### `defineVars(defaults)`
|
|
236
|
+
|
|
237
|
+
Alias for `defineConsts`. Returns a frozen copy. Useful for defining default values that are referenced as style property objects.
|
|
238
|
+
|
|
239
|
+
```ts
|
|
240
|
+
const colors = defineVars({
|
|
241
|
+
default: 'white',
|
|
242
|
+
primary: 'red',
|
|
243
|
+
secondary: 'blue',
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
const styles = create({
|
|
247
|
+
box: { backgroundColor: colors }, // 'white' by default
|
|
248
|
+
});
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
### `create(styleDefs)`
|
|
254
|
+
|
|
255
|
+
Defines styles at module level. Each property value can be a plain React Native value or an object mapping variant keys to values. Returns a map of compiled style entries.
|
|
256
|
+
|
|
257
|
+
```ts
|
|
258
|
+
const styles = create({
|
|
259
|
+
container: {
|
|
260
|
+
backgroundColor: {
|
|
261
|
+
default: '#fff',
|
|
262
|
+
[media.md]: '#f0f0f0',
|
|
263
|
+
[themes.dark]: '#111',
|
|
264
|
+
},
|
|
265
|
+
padding: 16,
|
|
266
|
+
},
|
|
267
|
+
title: {
|
|
268
|
+
fontSize: 24,
|
|
269
|
+
fontWeight: '700',
|
|
270
|
+
},
|
|
271
|
+
});
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
### `createVariants(variantDefs)`
|
|
277
|
+
|
|
278
|
+
Defines named variant groups. Each group maps CSS property names to objects with `default` and named variant values. Returns processed variant objects that can be spread into `create()`.
|
|
279
|
+
|
|
280
|
+
```ts
|
|
281
|
+
const buttonVariants = createVariants({
|
|
282
|
+
// variant group name: 'color'
|
|
283
|
+
color: {
|
|
284
|
+
backgroundColor: {
|
|
285
|
+
default: '#6200ee',
|
|
286
|
+
primary: '#6200ee',
|
|
287
|
+
danger: '#b00020',
|
|
288
|
+
},
|
|
289
|
+
borderColor: {
|
|
290
|
+
default: 'transparent',
|
|
291
|
+
danger: '#b00020',
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
size: {
|
|
295
|
+
height: {
|
|
296
|
+
default: 40,
|
|
297
|
+
sm: 32,
|
|
298
|
+
lg: 48,
|
|
299
|
+
},
|
|
300
|
+
},
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
const styles = create({
|
|
304
|
+
button: {
|
|
305
|
+
...buttonVariants.color, // spread all color-variant properties
|
|
306
|
+
...buttonVariants.size,
|
|
307
|
+
borderRadius: 8,
|
|
308
|
+
},
|
|
309
|
+
});
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
Use the `Variants` type helper to infer the values accepted by `mix()` for a given variant:
|
|
313
|
+
|
|
314
|
+
```ts
|
|
315
|
+
import type { Variants } from '@mochi-inc-japan/react-native-stylex-sheet';
|
|
316
|
+
|
|
317
|
+
type ButtonVariants = Variants<typeof buttonVariants>;
|
|
318
|
+
// { color: 'primary' | 'danger' | 'default'; size: 'sm' | 'lg' | 'default' }
|
|
319
|
+
|
|
320
|
+
stylex.mix<Variants<ButtonVariants>>(styles.button, { color, size })
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
### `createThemes(themeNames)`
|
|
326
|
+
|
|
327
|
+
Activate a theme by passing its key to `RNStyleXProvider`:
|
|
328
|
+
|
|
329
|
+
```tsx
|
|
330
|
+
<RNStyleXProvider theme={themes.dark}>
|
|
331
|
+
<App />
|
|
332
|
+
</RNStyleXProvider>
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
Creates named theme keys. Returns `{ themes }` where each name maps to an opaque key string used as a style property key in `create()`.
|
|
336
|
+
|
|
337
|
+
```tsx
|
|
338
|
+
import * as stylex from '@mochi-inc-japan/react-native-stylex-sheet'
|
|
339
|
+
import { useStylex } from '@mochi-inc-japan/react-native-stylex-sheet'
|
|
340
|
+
|
|
341
|
+
const { themes } = stylex.createThemes(['light', 'dark']);
|
|
342
|
+
|
|
343
|
+
const styles = stylex.create({
|
|
344
|
+
text: {
|
|
345
|
+
color: {
|
|
346
|
+
default: '#000',
|
|
347
|
+
[themes.light]: '#000',
|
|
348
|
+
[themes.dark]: '#fff',
|
|
349
|
+
},
|
|
350
|
+
},
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
function App() {
|
|
354
|
+
const stylex = useStylex()
|
|
355
|
+
return (
|
|
356
|
+
<Text {...stylex.props(styles.text)}>
|
|
357
|
+
Hello World!
|
|
358
|
+
</Text>
|
|
359
|
+
)
|
|
360
|
+
}
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
When you need to add styles or set different variables per theme, use `stylex.create` and `stylex.props` to override the default style with the style corresponding to the active theme:
|
|
364
|
+
|
|
365
|
+
```tsx
|
|
366
|
+
import { View, Text } from 'react-native'
|
|
367
|
+
import * as stylex from '@mochi-inc-japan/react-native-stylex-sheet'
|
|
368
|
+
import { useStylex } from '@mochi-inc-japan/react-native-stylex-sheet'
|
|
369
|
+
|
|
370
|
+
const { themes } = stylex.createThemes(['light', 'dark', 'other']);
|
|
371
|
+
|
|
372
|
+
// Default style definitions
|
|
373
|
+
const defaultColors = stylex.defineVars({
|
|
374
|
+
primary: 'black',
|
|
375
|
+
danger: 'red',
|
|
376
|
+
})
|
|
377
|
+
|
|
378
|
+
const variables = stylex.createVariants({
|
|
379
|
+
text: {
|
|
380
|
+
color: defaultColors
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
const styles = stylex.create({
|
|
385
|
+
view: {
|
|
386
|
+
width: '100%',
|
|
387
|
+
height: '100%'
|
|
388
|
+
},
|
|
389
|
+
text: {
|
|
390
|
+
...variables.text
|
|
391
|
+
},
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
// Variant style definitions for additional themes
|
|
395
|
+
const darkThemeStyleVariants = stylex.createVariants({
|
|
396
|
+
text: { color: { ...defaultColors, 'primary': 'white' }, },
|
|
397
|
+
})
|
|
398
|
+
|
|
399
|
+
const otherThemeStyleVariants = stylex.createVariants({
|
|
400
|
+
text: { color: { ...defaultColors, 'primary': 'blue' }, },
|
|
401
|
+
})
|
|
402
|
+
|
|
403
|
+
const viewTheme = stylex.create({
|
|
404
|
+
// Additional styles written directly into create
|
|
405
|
+
[themes.dark]: { backgroundColor: 'black' },
|
|
406
|
+
[themes.other]: { backgroundColor: 'gray' },
|
|
407
|
+
})
|
|
408
|
+
|
|
409
|
+
const textTheme = stylex.create({
|
|
410
|
+
[themes.dark]: { borderColor: 'white', borderWidth: 1, ...darkThemeStyleVariants.text },
|
|
411
|
+
[themes.other]: { ...otherThemeStyleVariants.text },
|
|
412
|
+
})
|
|
413
|
+
|
|
414
|
+
function App() {
|
|
415
|
+
const stylex = useStylex()
|
|
416
|
+
return (
|
|
417
|
+
<View {...stylex.props(styles.view, viewTheme[stylex.theme])}>
|
|
418
|
+
<Text
|
|
419
|
+
{...stylex.props(styles.text, stylex.mix(textTheme[stylex.theme], { text: 'primary' }))}
|
|
420
|
+
>
|
|
421
|
+
Hello World!
|
|
422
|
+
</Text>
|
|
423
|
+
</View>
|
|
424
|
+
)
|
|
425
|
+
}
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
---
|
|
429
|
+
|
|
430
|
+
### `RNStyleXProvider`
|
|
431
|
+
|
|
432
|
+
Provider component that supplies `theme` and `windowWidth` (the basis for media query evaluation) to all `useStylex()` calls below it. If `windowWidth` is not specified, the provider implicitly uses `PixelRatio.getPixelSizeForLayoutSize(useWindowDimensions().width)`.
|
|
433
|
+
|
|
434
|
+
```tsx
|
|
435
|
+
<RNStyleXProvider theme={themes.dark}>
|
|
436
|
+
<Screen />
|
|
437
|
+
</RNStyleXProvider>
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
Props:
|
|
441
|
+
- `theme` — a theme key string from `createThemes()`, or omit for no active theme
|
|
442
|
+
- `windowWidth` — override device width (defaults to `PixelRatio.getPixelSizeForLayoutSize(useWindowDimensions().width)`)
|
|
443
|
+
|
|
444
|
+
---
|
|
445
|
+
|
|
446
|
+
### `useStylex()`
|
|
447
|
+
|
|
448
|
+
Hook returning `{ props, mix, windowWidth, theme }`. Must be used inside `RNStyleXProvider`. `mix` automatically applies the active theme and screen width from context. It can be omitted when no variants are specified, and explicit `width` or `theme` overrides are also supported at the call site.
|
|
449
|
+
|
|
450
|
+
```tsx
|
|
451
|
+
import * as stylex from '@mochi-inc-japan/react-native-stylex-sheet'
|
|
452
|
+
|
|
453
|
+
const { themes } = stylex.createThemes(['light', 'dark']);
|
|
454
|
+
const colors = stylex.defineVars({
|
|
455
|
+
default: '#6200ee',
|
|
456
|
+
primary: '#6200ee',
|
|
457
|
+
danger: '#b00020',
|
|
458
|
+
})
|
|
459
|
+
const cardVariants = stylex.createVariants({
|
|
460
|
+
// variant group name: 'bgcolor'
|
|
461
|
+
bgcolor: {
|
|
462
|
+
backgroundColor: colors,
|
|
463
|
+
}
|
|
464
|
+
})
|
|
465
|
+
const styles = stylex.create({
|
|
466
|
+
card: {
|
|
467
|
+
...cardVariants
|
|
468
|
+
},
|
|
469
|
+
title: {
|
|
470
|
+
color: {
|
|
471
|
+
[themes.light]: 'black',
|
|
472
|
+
[themes.dark]: 'white',
|
|
473
|
+
},
|
|
474
|
+
padding: {
|
|
475
|
+
default: 12,
|
|
476
|
+
[media.md]: 16,
|
|
477
|
+
},
|
|
478
|
+
borderRadius: 8,
|
|
479
|
+
},
|
|
480
|
+
})
|
|
481
|
+
|
|
482
|
+
function Card({ bgcolor }: { bgcolor: keyof typeof colors }) {
|
|
483
|
+
const stylex = useStylex();
|
|
484
|
+
return (
|
|
485
|
+
<View {...stylex.props(
|
|
486
|
+
stylex.mix<Variants<typeof cardVariants>>(styles.card, { bgcolor })
|
|
487
|
+
)}>
|
|
488
|
+
{/* theme and media styles for styles.title are applied even without calling stylex.mix */}
|
|
489
|
+
<Text {...stylex.props(styles.title)}>Hello</Text>
|
|
490
|
+
</View>
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
render(
|
|
495
|
+
<stylex.RNStylexProvider theme={themes.dark}>
|
|
496
|
+
<Card bgcolor='primary' />
|
|
497
|
+
</stylex.RNStylexProvider>
|
|
498
|
+
)
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
---
|
|
502
|
+
|
|
503
|
+
### `mix(target, variantArgs?)`
|
|
504
|
+
|
|
505
|
+
Resolves a compiled style entry into an array of `RNStyle` objects:
|
|
506
|
+
|
|
507
|
+
1. Always includes the `default` style.
|
|
508
|
+
2. If `variantArgs` is provided, appends the matching variant styles.
|
|
509
|
+
3. When called via `useStylex().mix()`, also applies the active theme and media query styles automatically.
|
|
510
|
+
|
|
511
|
+
```ts
|
|
512
|
+
// Module-level (non-reactive) — only default styles
|
|
513
|
+
const style = mix(styles.button);
|
|
514
|
+
|
|
515
|
+
// With explicit variants
|
|
516
|
+
const style = mix(styles.button, { color: 'danger', size: 'lg' });
|
|
517
|
+
|
|
518
|
+
// Inside component — theme + media from RNStyleXProvider are applied automatically
|
|
519
|
+
const stylex = useStylex();
|
|
520
|
+
const style = stylex.mix(styles.button, { color: 'danger' });
|
|
521
|
+
|
|
522
|
+
const media = defineConsts({
|
|
523
|
+
md: '(width >= 750px)',
|
|
524
|
+
lg: '(width >= 1080px)',
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
const style = stylex.mix(
|
|
528
|
+
[
|
|
529
|
+
styles.button,
|
|
530
|
+
{
|
|
531
|
+
media: media.md, // force a specific media match (or pass a numeric width)
|
|
532
|
+
theme: themes.dark, // force a specific theme key
|
|
533
|
+
}
|
|
534
|
+
],
|
|
535
|
+
{ color: 'danger' }
|
|
536
|
+
);
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
---
|
|
540
|
+
|
|
541
|
+
### `props(...args)`
|
|
542
|
+
|
|
543
|
+
Collects style arrays into `{ style: [...] }` to spread on a React Native component. Accepts `RNStyle[]` arrays or plain style objects.
|
|
544
|
+
|
|
545
|
+
```tsx
|
|
546
|
+
// Combine multiple mix() results
|
|
547
|
+
function Component() {
|
|
548
|
+
const stylex = useStylex();
|
|
549
|
+
return <View {...stylex.props(stylex.mix(styles.base), stylex.mix(styles.override))} />;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// Module-level (non-reactive, default styles only) — import * as stylex
|
|
553
|
+
<View {...stylex.props(styles.container)} />
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
---
|
|
557
|
+
|
|
558
|
+
## Media queries
|
|
559
|
+
|
|
560
|
+
Media query strings are used directly as style property keys. The string must match one of the supported range formats:
|
|
561
|
+
|
|
562
|
+
| Format | Example |
|
|
563
|
+
|---|---|
|
|
564
|
+
| Lower bound | `(width >= 750px)` / `(width > 750px)` |
|
|
565
|
+
| Upper bound | `(width <= 1080px)` / `(width < 1080px)` |
|
|
566
|
+
| Range | `(750px <= width < 1080px)` |
|
|
567
|
+
|
|
568
|
+
**Key ordering matters:** later matching keys overwrite earlier ones, so put more specific queries last.
|
|
569
|
+
|
|
570
|
+
```ts
|
|
571
|
+
const media = defineConsts({
|
|
572
|
+
md: '(width >= 750px)',
|
|
573
|
+
lg: '(width >= 1080px)', // more specific — put last
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
const styles = create({
|
|
577
|
+
text: {
|
|
578
|
+
fontSize: {
|
|
579
|
+
default: 16,
|
|
580
|
+
[media.md]: 18,
|
|
581
|
+
[media.lg]: 20, // wins over md when lg also matches
|
|
582
|
+
},
|
|
583
|
+
},
|
|
584
|
+
});
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
---
|
|
588
|
+
|
|
589
|
+
## Limitations
|
|
590
|
+
|
|
591
|
+
React Native has no CSS cascade, inheritance, keyframes, pseudo-elements, or global styles — these features are absent by design.
|
|
592
|
+
|
|
593
|
+
| Not supported | Alternative |
|
|
594
|
+
|---|---|
|
|
595
|
+
| CSS variables | Use `defineVars()` / `defineConsts()` for shared values |
|
|
596
|
+
| `shadows` token scale | iOS/Android have incompatible shadow APIs — define shadow styles directly |
|
|
597
|
+
| `transitions` | Use [Animated API](https://reactnative.dev/docs/animated) or [react-native-reanimated](https://github.com/software-mansion/react-native-reanimated) |
|
|
598
|
+
| Global styles | Not applicable to React Native |
|
|
599
|
+
| Pseudo-classes / elements | Not applicable to React Native |
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
Object.defineProperty(exports, "RNStyleXProvider", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function () {
|
|
9
|
+
return _hooks.RNStyleXProvider;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
Object.defineProperty(exports, "create", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: function () {
|
|
15
|
+
return _base.create;
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
Object.defineProperty(exports, "createThemes", {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
get: function () {
|
|
21
|
+
return _theme.createThemes;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
Object.defineProperty(exports, "createVariants", {
|
|
25
|
+
enumerable: true,
|
|
26
|
+
get: function () {
|
|
27
|
+
return _variant.createVariants;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
Object.defineProperty(exports, "defineConsts", {
|
|
31
|
+
enumerable: true,
|
|
32
|
+
get: function () {
|
|
33
|
+
return _tokens.defineConsts;
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
Object.defineProperty(exports, "defineVars", {
|
|
37
|
+
enumerable: true,
|
|
38
|
+
get: function () {
|
|
39
|
+
return _tokens.defineVars;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
Object.defineProperty(exports, "mix", {
|
|
43
|
+
enumerable: true,
|
|
44
|
+
get: function () {
|
|
45
|
+
return _base.mix;
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
Object.defineProperty(exports, "props", {
|
|
49
|
+
enumerable: true,
|
|
50
|
+
get: function () {
|
|
51
|
+
return _base.props;
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
Object.defineProperty(exports, "useStylex", {
|
|
55
|
+
enumerable: true,
|
|
56
|
+
get: function () {
|
|
57
|
+
return _hooks.useStylex;
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
var _base = require("./utils/base");
|
|
61
|
+
var _variant = require("./utils/variant");
|
|
62
|
+
var _tokens = require("./utils/tokens");
|
|
63
|
+
var _hooks = require("./utils/hooks");
|
|
64
|
+
var _theme = require("./utils/theme");
|
|
65
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_base","require","_variant","_tokens","_hooks","_theme"],"sources":["index.ts"],"sourcesContent":["export { create, props, mix } from './utils/base';\nexport { createVariants } from './utils/variant';\nexport { defineConsts, defineVars } from './utils/tokens';\nexport { useStylex, RNStyleXProvider } from './utils/hooks';\nexport { createThemes } from './utils/theme';\nexport type {\n Variants,\n XRNStyle,\n RNStyle,\n XRNStyleSheets,\n} from './utils/types';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAAA,KAAA,GAAAC,OAAA;AACA,IAAAC,QAAA,GAAAD,OAAA;AACA,IAAAE,OAAA,GAAAF,OAAA;AACA,IAAAG,MAAA,GAAAH,OAAA;AACA,IAAAI,MAAA,GAAAJ,OAAA","ignoreList":[]}
|