@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.
Files changed (68) hide show
  1. package/LICENSE +21 -0
  2. package/README.ja.md +608 -0
  3. package/README.md +599 -0
  4. package/lib/commonjs/index.js +65 -0
  5. package/lib/commonjs/index.js.map +1 -0
  6. package/lib/commonjs/tests/index.test.js +224 -0
  7. package/lib/commonjs/tests/index.test.js.map +1 -0
  8. package/lib/commonjs/tests/media.test.js +226 -0
  9. package/lib/commonjs/tests/media.test.js.map +1 -0
  10. package/lib/commonjs/tests/mock.test.js +54 -0
  11. package/lib/commonjs/tests/mock.test.js.map +1 -0
  12. package/lib/commonjs/tests/test-utils.js +60 -0
  13. package/lib/commonjs/tests/test-utils.js.map +1 -0
  14. package/lib/commonjs/utils/base.js +72 -0
  15. package/lib/commonjs/utils/base.js.map +1 -0
  16. package/lib/commonjs/utils/hooks.js +60 -0
  17. package/lib/commonjs/utils/hooks.js.map +1 -0
  18. package/lib/commonjs/utils/media.js +69 -0
  19. package/lib/commonjs/utils/media.js.map +1 -0
  20. package/lib/commonjs/utils/theme.js +25 -0
  21. package/lib/commonjs/utils/theme.js.map +1 -0
  22. package/lib/commonjs/utils/tokens.js +18 -0
  23. package/lib/commonjs/utils/tokens.js.map +1 -0
  24. package/lib/commonjs/utils/types.js +6 -0
  25. package/lib/commonjs/utils/types.js.map +1 -0
  26. package/lib/commonjs/utils/variant.js +75 -0
  27. package/lib/commonjs/utils/variant.js.map +1 -0
  28. package/lib/module/index.js +6 -0
  29. package/lib/module/index.js.map +1 -0
  30. package/lib/module/tests/index.test.js +220 -0
  31. package/lib/module/tests/index.test.js.map +1 -0
  32. package/lib/module/tests/media.test.js +222 -0
  33. package/lib/module/tests/media.test.js.map +1 -0
  34. package/lib/module/tests/mock.test.js +49 -0
  35. package/lib/module/tests/mock.test.js.map +1 -0
  36. package/lib/module/tests/test-utils.js +52 -0
  37. package/lib/module/tests/test-utils.js.map +1 -0
  38. package/lib/module/utils/base.js +63 -0
  39. package/lib/module/utils/base.js.map +1 -0
  40. package/lib/module/utils/hooks.js +52 -0
  41. package/lib/module/utils/hooks.js.map +1 -0
  42. package/lib/module/utils/media.js +59 -0
  43. package/lib/module/utils/media.js.map +1 -0
  44. package/lib/module/utils/theme.js +16 -0
  45. package/lib/module/utils/theme.js.map +1 -0
  46. package/lib/module/utils/tokens.js +11 -0
  47. package/lib/module/utils/tokens.js.map +1 -0
  48. package/lib/module/utils/types.js +2 -0
  49. package/lib/module/utils/types.js.map +1 -0
  50. package/lib/module/utils/variant.js +65 -0
  51. package/lib/module/utils/variant.js.map +1 -0
  52. package/lib/types/index.d.ts +6 -0
  53. package/lib/types/tests/check-descriptor.test.d.ts +0 -0
  54. package/lib/types/tests/index.test.d.ts +1 -0
  55. package/lib/types/tests/media.test.d.ts +1 -0
  56. package/lib/types/tests/mock.test.d.ts +1 -0
  57. package/lib/types/tests/test-utils.d.ts +7 -0
  58. package/lib/types/tests/utils.d.ts +6 -0
  59. package/lib/types/utils/base.d.ts +13 -0
  60. package/lib/types/utils/hooks.d.ts +16 -0
  61. package/lib/types/utils/index.d.ts +9 -0
  62. package/lib/types/utils/media.d.ts +5 -0
  63. package/lib/types/utils/theme.d.ts +14 -0
  64. package/lib/types/utils/tokens.d.ts +3 -0
  65. package/lib/types/utils/types.d.ts +28 -0
  66. package/lib/types/utils/utils.d.ts +4 -0
  67. package/lib/types/utils/variant.d.ts +50 -0
  68. package/package.json +132 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 Teemu Taskula
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.ja.md ADDED
@@ -0,0 +1,608 @@
1
+ # react-native-stylex-sheet
2
+
3
+ React Native 向け 軽量・高速な CSS-in-JS ライブラリです。React Native標準のStyleSheetのcss指定に対しての下位互換性を保持しつつ、React Nativeで標準でサポートされていないthemeやvariantsなどの拡張を含んでいます。WEBの[stylexjs](https://stylexjs.com/docs/learn/recipes/variants/)と可能な限り互換性のあるインターフェースを保ち、これを用いたクロスプラットフォーム化を簡易化することを目的にしています。ReactNativeおよび、Reactのみをpeer dependenciesとしているため、このライブラリを利用して作成されたコンポーネントは、ネイティブアプリのAPIやデバイスに依存するコードを含めない限り、react-native-webでもそのまま動かすことが出来ます。
4
+
5
+ ## インストール
6
+
7
+ ```sh
8
+ npm install @mochi-inc-japan/react-native-stylex-sheet
9
+ ```
10
+
11
+ ## クイックスタート
12
+
13
+ ### シンプルな使い方(テーマ / バリアント / メディアなし)
14
+
15
+ テーマ・バリアント・レスポンシブメディアクエリが不要な場合は、名前空間インポートを使います。
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>押してください</Text>
32
+ </Pressable>
33
+ );
34
+ }
35
+ ```
36
+
37
+ ダイナミックスタイルを利用したい場合は、props関数に直接styleオブジェクトを指定します。
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>押してください</Text>
54
+ </Pressable>
55
+ );
56
+ }
57
+ ```
58
+
59
+ ### 高度な使い方(テーマ / バリアント / メディア)
60
+
61
+ テーマ・バリアント・レスポンシブブレークポイントを使う場合は、アプリを `RNStyleXProvider` でラップし、コンポーネント内で `const stylex = useStylex()` を使います。
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. メディアブレークポイントを定数として定義
75
+ const media = defineConsts({
76
+ md: '(width >= 750px)',
77
+ lg: '(width >= 1080px)',
78
+ });
79
+
80
+ // 2. テーマを定義
81
+ const { themes } = createThemes(['light', 'dark']);
82
+
83
+ // 3. バリアントグループを定義(任意)
84
+ const buttonVariants = createVariants({
85
+ color: {
86
+ backgroundColor: {
87
+ default: '#6200ee',
88
+ danger: '#b00020',
89
+ },
90
+ },
91
+ });
92
+
93
+ // 4. モジュールレベルでスタイルを定義
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. アプリを 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. コンポーネント内で const stylex = useStylex() を使用
116
+ // — RNStyleXProvider のテーマとメディアは 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>押してください</Text>
126
+ </Pressable>
127
+ );
128
+ }
129
+ ```
130
+
131
+ useStylex()及び、RNStyleXProviderを用いた場合、Providerにセットしたテーマとメディアは自動的に適用されるため、`mix()` はvariantsを指定しない場合は省略可能です。省略せずに明示的にwidthやthemeをその場で指定して書き換えることも可能です。また、ライブラリからexportされているmix関数は省略できないため、テーマ・バリアント・メディアを利用する必要があるコンポーネントについては、標準のmix関数ではなくuseStylex由来のmix関数を利用することを推奨します。
132
+
133
+ ```tsx
134
+
135
+ // const stylex = useStylex();
136
+ // または
137
+ // import * as stylex from '@mochi-inc-japan/react-native-stylex-sheet'
138
+ stylex.mix<Variants<typeof buttonVariants>>(
139
+ [
140
+ styles.button,
141
+ {
142
+ media: stylex.windowWidth,
143
+ theme: themes.dark
144
+ }
145
+ ],
146
+ { color: danger ? 'danger' : 'default' }
147
+ );
148
+ ```
149
+
150
+ ---
151
+
152
+ ## 既存のReact Nativeコンポーネントからの移行
153
+
154
+ `stylex.create`は拡張記法を利用しない限り、react-native標準の`StyleSheet.create`に対して下位互換性を保持しているので、`StyleSheet.create`で定義されているReact Nativeのstyleをそのまま再利用することが出来ます。そのため全てのコンポーネントを一括で変更する必要はなく、部分的に置き換えていくことが可能です。
155
+
156
+ ```tsx
157
+ // 移行前
158
+ import { StyleSheet } from 'react-native';
159
+
160
+ const styles = StyleSheet.create({
161
+ button: {
162
+ padding: 16,
163
+ borderRadius: 8,
164
+ backgroundColor: '#6200ee',
165
+ },
166
+ });
167
+
168
+ function Button() {
169
+ return (
170
+ <Pressable >
171
+ <Text>押してください</Text>
172
+ </Pressable>
173
+ );
174
+ }
175
+
176
+ // 移行後
177
+ import * as stylex from '@mochi-inc-japan/react-native-stylex-sheet';
178
+
179
+ const styles = stylex.create({
180
+ button: {
181
+ padding: 16,
182
+ borderRadius: 8,
183
+ backgroundColor: '#6200ee',
184
+ },
185
+ });
186
+
187
+ function Button() {
188
+ return (
189
+ <Pressable {...stylex.props(styles.button)}>
190
+ <Text>押してください</Text>
191
+ </Pressable>
192
+ );
193
+ }
194
+ ```
195
+
196
+ ## セットアップパターン
197
+
198
+ 共有定数(メディアブレークポイントとテーマ)は単一ファイルに定義してエクスポートするパターンを推奨します。
199
+
200
+ ```ts
201
+ // src/styles/stylex.ts
202
+ import {
203
+ createThemes,
204
+ defineConsts,
205
+ } from '@mochi-inc-japan/react-native-stylex-sheet';
206
+
207
+ export const media = defineConsts({
208
+ md: '(width >= 750px)',
209
+ lg: '(width >= 1080px)',
210
+ });
211
+
212
+ export const fontSize = defineConsts({
213
+ default: 16,
214
+ md: 24,
215
+ lg: 32
216
+ });
217
+
218
+ export const { themes } = createThemes(['light', 'dark']);
219
+ ```
220
+
221
+ ---
222
+
223
+ ## API リファレンス
224
+
225
+ ### `defineConsts(consts)`
226
+
227
+ 渡されたオブジェクトのフリーズコピーを返します。メディアクエリ文字列などのモジュールレベル定数に使用します。
228
+
229
+ ```ts
230
+ const media = defineConsts({
231
+ md: '(width >= 750px)',
232
+ lg: '(width >= 1080px)',
233
+ });
234
+ ```
235
+
236
+ ### `defineVars(defaults)`
237
+
238
+ `defineConsts` のエイリアスです。フリーズコピーを返します。スタイルプロパティオブジェクトとして参照されるデフォルト値の定義に便利です。
239
+
240
+ ```ts
241
+ const colors = defineVars({
242
+ default: 'white',
243
+ primary: 'red',
244
+ secondary: 'blue',
245
+ });
246
+
247
+ const styles = create({
248
+ box: { backgroundColor: colors }, // デフォルトは 'white'
249
+ });
250
+ ```
251
+
252
+ ---
253
+
254
+ ### `create(styleDefs)`
255
+
256
+ モジュールレベルでスタイルを定義します。各プロパティ値にはプレーンな React Native 値か、バリアントキーと値のマップオブジェクトを指定できます。コンパイル済みスタイルエントリのマップを返します。
257
+
258
+ ```ts
259
+ const styles = create({
260
+ container: {
261
+ backgroundColor: {
262
+ default: '#fff',
263
+ [media.md]: '#f0f0f0',
264
+ [themes.dark]: '#111',
265
+ },
266
+ padding: 16,
267
+ },
268
+ title: {
269
+ fontSize: 24,
270
+ fontWeight: '700',
271
+ },
272
+ });
273
+ ```
274
+
275
+ ---
276
+
277
+ ### `createVariants(variantDefs)`
278
+
279
+ 名前付きバリアントグループを定義します。各グループは CSS プロパティ名を `default` および名前付きバリアント値のオブジェクトにマッピングします。`create()` にスプレッドできる処理済みバリアントオブジェクトを返します。
280
+
281
+ ```ts
282
+ const buttonVariants = createVariants({
283
+ // バリアントグループ名: 'color'
284
+ color: {
285
+ backgroundColor: {
286
+ default: '#6200ee',
287
+ primary: '#6200ee',
288
+ danger: '#b00020',
289
+ },
290
+ borderColor: {
291
+ default: 'transparent',
292
+ danger: '#b00020',
293
+ },
294
+ },
295
+ size: {
296
+ height: {
297
+ default: 40,
298
+ sm: 32,
299
+ lg: 48,
300
+ },
301
+ },
302
+ });
303
+
304
+ const styles = create({
305
+ button: {
306
+ ...buttonVariants.color, // カラーバリアントプロパティをスプレッド
307
+ ...buttonVariants.size,
308
+ borderRadius: 8,
309
+ },
310
+ });
311
+ ```
312
+
313
+ バリアント指定時に `Variants` 型ヘルパーを使用して、mix関数の引数として受け入れ可能な値を型推論できます。
314
+
315
+ ```ts
316
+ import type { Variants } from '@mochi-inc-japan/react-native-stylex-sheet';
317
+
318
+ type ButtonVariants = Variants<typeof buttonVariants>;
319
+ // { color: 'primary' | 'danger' | 'default'; size: 'sm' | 'lg' | 'default' }
320
+
321
+ stylex.mix<Variants<ButtonVariants>>(styles.button, { color, size })
322
+ ```
323
+
324
+ ---
325
+
326
+ ### `createThemes(themeNames)`
327
+
328
+ `RNStyleXProvider` にキーを渡してテーマをアクティブにします。
329
+
330
+ ```tsx
331
+ <RNStyleXProvider theme={themes.dark}>
332
+ <App />
333
+ </RNStyleXProvider>
334
+ ```
335
+
336
+ 名前付きテーマキーを作成します。`{ themes }` を返し、各名前は `create()` でスタイルプロパティキーとして使用される不透明なキー文字列にマッピングされます。
337
+
338
+ ```tsx
339
+ import * as stylex from '@mochi-inc-japan/react-native-stylex-sheet'
340
+ import { useStylex } from '@mochi-inc-japan/react-native-stylex-sheet'
341
+
342
+ const { themes } = stylex.createThemes(['light', 'dark']);
343
+
344
+ const styles = stylex.create({
345
+ text: {
346
+ color: {
347
+ default: '#000',
348
+ [themes.light]: '#000',
349
+ [themes.dark]: '#fff',
350
+ },
351
+ },
352
+ });
353
+
354
+ function App () {
355
+ const stylex = useStylex()
356
+ return (
357
+ <Text
358
+ {...stylex.props(styles.text)}
359
+ >
360
+ Hello World!
361
+ </Text>
362
+ )
363
+ }
364
+ ```
365
+
366
+ themeによってスタイルを追加したいケースや異なるvariableを設定したいケースなどでは、`stylex.create`および、`style.props`を使って選択中のthemeに対応するstyleによって、デフォルトのスタイルをオーバーライト出来ます。
367
+
368
+ ```tsx
369
+ import { View, Text } from 'react-native'
370
+ import * as stylex from '@mochi-inc-japan/react-native-stylex-sheet'
371
+ import { useStylex } from '@mochi-inc-japan/react-native-stylex-sheet'
372
+
373
+ const { themes } = stylex.createThemes(['light', 'dark', 'other']);
374
+
375
+ // defaultのスタイル定義
376
+ const defaultColors = stylex.defineVars({
377
+ primary: 'black',
378
+ danger: 'red',
379
+ })
380
+
381
+ const variables = stylex.createVariants({
382
+ text: {
383
+ color: defaultColors
384
+ }
385
+ });
386
+
387
+ const styles = stylex.create({
388
+ view: {
389
+ width: '100%',
390
+ height: '100%'
391
+ },
392
+ text: {
393
+ ...variables.text
394
+ },
395
+ });
396
+
397
+ // 新たなThemeのvariantsスタイル定義
398
+ const darkThemeStyleVariants = stylex.createVariants({
399
+ text: { color: { ...defaultColors, 'primary': 'white' }, },
400
+ })
401
+
402
+ const otherThemeStyleVariants = stylex.createVariants({
403
+ text: { color: { ...defaultColors, 'primary': 'blue' }, },
404
+ })
405
+
406
+ const viewTheme = stylex.create({
407
+ // 追加のスタイルはcreateに直接記入する
408
+ [themes.dark]: { backgroundColor: 'black' }
409
+ [themes.other]: { backgroundColor: 'gray'}
410
+ })
411
+
412
+
413
+ const textTheme = stylex.create({
414
+ // 追加のスタイルはcreateに直接記入する
415
+ [themes.dark]: { borderColor: 'white', borderWidth: 1, ...darkThemeStyleVariants.text}
416
+ [themes.other]: {...otherThemeStyleVariants.text}
417
+ })
418
+
419
+
420
+ function App () {
421
+ const stylex = useStylex()
422
+ return (
423
+ <View {...stylex.props(styles.view, viewTheme[stylex.theme])}>
424
+ <Text
425
+ /* */
426
+ {...stylex.props(styles.text, stylex.mix(textTheme[stylex.theme], { text: 'primary' }))}
427
+ >
428
+ Hello World!
429
+ </Text>
430
+ </View>
431
+ )
432
+ }
433
+ ```
434
+
435
+ ---
436
+
437
+ ### `RNStyleXProvider`
438
+
439
+ `useStylex()` 実行時に `theme` とmediaの判定基準となる `windowWidth` を供給するプロバイダーコンポーネントです。widthは指定しなければ、Provider内で暗黙的に`PixelRatio.getPixelSizeForLayoutSize(useWindowDimensions().width)`を利用します。
440
+
441
+ ```tsx
442
+ <RNStyleXProvider theme={themes.dark}>
443
+ <Screen />
444
+ </RNStyleXProvider>
445
+ ```
446
+
447
+ Props:
448
+ - `theme` — `createThemes()` のテーマキー文字列、またはアクティブテーマなしの場合は省略
449
+ - `windowWidth` — デバイス幅の上書き(デフォルト: `PixelRatio.getPixelSizeForLayoutSize(useWindowDimensions().width)`)
450
+
451
+ ---
452
+
453
+ ### `useStylex()`
454
+
455
+ `{ props, mix, windowWidth, theme }` を返すフックです。`RNStyleXProvider` の内部で使用する必要があります。`mix` はコンテキストからアクティブなテーマと画面幅を自動的に適用します。variantsを指定しない場合は省略可能です。明示的にwidthやthemeをその場で指定することも可能です。
456
+
457
+ ```tsx
458
+ import * as stylex from '@mochi-inc-japan/react-native-stylex-sheet'
459
+
460
+ const { themes } = stylex.createThemes(['light', 'dark']);
461
+ const colors = stylex.defineVars({
462
+ default: '#6200ee',
463
+ primary: '#6200ee',
464
+ danger: '#b00020',
465
+ })
466
+ const cardVariants = stylex.createVariants({
467
+ // バリアントグループ名: 'color'
468
+ bgcolor: {
469
+ backgroundColor: colors,
470
+ }
471
+ })
472
+ const styles = stylex.create({
473
+ card: {
474
+ ...cardVariants
475
+ },
476
+ title: {
477
+ color: {
478
+ [themes.light]: 'black'
479
+ [themes.dark]: 'white'
480
+ },
481
+ padding: {
482
+ default: 12,
483
+ [media.md]: 16,
484
+ },
485
+ borderRadius: 8,
486
+ },
487
+ })
488
+
489
+ function Card({ bgcolor }: { bgcolor: keyof typeof colors }) {
490
+ const stylex = useStylex();
491
+ return (
492
+ <View {...stylex.props(
493
+ stylex.mix<Variants<typeof cardVariants>>(styles.card, { bgcolor })
494
+ )}>
495
+ {/* stylex.mixを実行しなくてもstyles.titleのthemeとmediaのstyleが適用される */}
496
+ <Text {...stylex.props(styles.title)}>Hello</Text>
497
+ </View>
498
+ );
499
+ }
500
+
501
+ render(
502
+ <stylex.RNStylexProvider theme={themes.dark}>
503
+ <Card bgcolor='primary'>
504
+ </stylex.RNStylexProvider>
505
+ )
506
+
507
+ ```
508
+
509
+ ---
510
+
511
+ ### `mix(target, variantArgs?)`
512
+
513
+ コンパイル済みスタイルエントリを `RNStyle` オブジェクトの配列に解決します。
514
+
515
+ 1. 常に `default` スタイルを含めます。
516
+ 2. `variantArgs` が指定された場合、一致するバリアントスタイルを追加します。
517
+ 3. `useStylex().mix()` 経由で呼び出した場合、アクティブなテーマとメディアクエリスタイルも自動的に適用します。
518
+
519
+ ```ts
520
+ // モジュールレベル(非リアクティブ)— デフォルトスタイルのみ
521
+ const style = mix(styles.button);
522
+
523
+ // 明示的なバリアント指定
524
+ const style = mix(styles.button, { color: 'danger', size: 'lg' });
525
+
526
+ // コンポーネント内 — RNStyleXProvider のテーマ・メディアは自動的に適用される
527
+ const stylex = useStylex();
528
+ const style = stylex.mix(styles.button, { color: 'danger' });
529
+
530
+ const media = defineConsts({
531
+ md: '(width >= 750px)',
532
+ lg: '(width >= 1080px)',
533
+ });
534
+
535
+ const style = stylex.mix(
536
+ [
537
+ styles.button,
538
+ {
539
+ media: (media.md(強制的なmediaクエリマッチ) or 750(任意のwidthで判定)),
540
+ theme: themes.dark(強制的にtheme keyの指定が可能)
541
+ }
542
+ ],
543
+ { color: 'danger' }
544
+ );
545
+ ```
546
+
547
+ ---
548
+
549
+ ### `props(...args)`
550
+
551
+ スタイル配列を React Native コンポーネントにスプレッドするための `{ style: [...] }` `RNStyle[]` 配列、またはプレーンなスタイルオブジェクトを受け取ります。
552
+
553
+ ```tsx
554
+ // 複数の mix() 結果を結合
555
+ function Component() {
556
+ const stylex = useStylex();
557
+ return <View {...stylex.props(stylex.mix(styles.base), stylex.mix(styles.override))} />;
558
+ }
559
+
560
+ // モジュールレベル(非リアクティブ、デフォルトスタイルのみ)— import * as stylex
561
+ <View {...stylex.props(styles.container)} />
562
+ ```
563
+
564
+ ---
565
+
566
+ ## メディアクエリ
567
+
568
+ メディアクエリ文字列はスタイルプロパティキーとして直接使用します。文字列はサポートされている範囲形式のいずれかに一致する必要があります。
569
+
570
+ | 形式 | 例 |
571
+ |---|---|
572
+ | 下限 | `(width >= 750px)` / `(width > 750px)` |
573
+ | 上限 | `(width <= 1080px)` / `(width < 1080px)` |
574
+ | 範囲 | `(750px <= width < 1080px)` |
575
+
576
+ **キーの順序が重要です。** 後から一致したキーが前のキーを上書きするため、より具体的なクエリは後に記述してください。
577
+
578
+ ```ts
579
+ const media = defineConsts({
580
+ md: '(width >= 750px)',
581
+ lg: '(width >= 1080px)', // より具体的 — 後に記述
582
+ });
583
+
584
+ const styles = create({
585
+ text: {
586
+ fontSize: {
587
+ default: 16,
588
+ [media.md]: 18,
589
+ [media.lg]: 20, // lg も一致する場合は md より優先される
590
+ },
591
+ },
592
+ });
593
+ ```
594
+
595
+
596
+ ---
597
+
598
+ ## 制限事項
599
+
600
+ React Native には CSS カスケード、継承、キーフレーム、疑似要素、グローバルスタイルがありません。これらの機能は設計上サポートされていません。
601
+
602
+ | 非対応 | 代替手段 |
603
+ |---|---|
604
+ | CSS 変数 | 共有値には `defineVars()` / `defineConsts()` を使用 |
605
+ | `shadows` トークンスケール | iOS/Android のシャドウ API は互換性がないため、シャドウスタイルは直接定義する |
606
+ | `transitions` | [Animated API](https://reactnative.dev/docs/animated) または [react-native-reanimated](https://github.com/software-mansion/react-native-reanimated) を使用 |
607
+ | グローバルスタイル | React Native では該当なし |
608
+ | 疑似クラス / 疑似要素 | React Native では該当なし |