@utilitywarehouse/hearth-react-native 0.27.2 → 0.28.0-testid-fix-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.
Files changed (155) hide show
  1. package/.turbo/turbo-build.log +5 -4
  2. package/.turbo/turbo-lint.log +70 -69
  3. package/CHANGELOG.md +149 -0
  4. package/build/components/Button/ButtonRoot.js +8 -0
  5. package/build/components/Combobox/Combobox.context.d.ts +13 -0
  6. package/build/components/Combobox/Combobox.context.js +9 -0
  7. package/build/components/Combobox/Combobox.d.ts +6 -0
  8. package/build/components/Combobox/Combobox.js +246 -0
  9. package/build/components/Combobox/Combobox.props.d.ts +180 -0
  10. package/build/components/Combobox/Combobox.props.js +1 -0
  11. package/build/components/Combobox/ComboboxOption.d.ts +6 -0
  12. package/build/components/Combobox/ComboboxOption.js +56 -0
  13. package/build/components/Combobox/index.d.ts +4 -0
  14. package/build/components/Combobox/index.js +3 -0
  15. package/build/components/DatePicker/TimePicker.d.ts +3 -0
  16. package/build/components/DatePicker/TimePicker.js +84 -0
  17. package/build/components/DatePicker/time-picker/animated-math.d.ts +4 -0
  18. package/build/components/DatePicker/time-picker/animated-math.js +19 -0
  19. package/build/components/DatePicker/time-picker/period-native.d.ts +6 -0
  20. package/build/components/DatePicker/time-picker/period-native.js +17 -0
  21. package/build/components/DatePicker/time-picker/period-picker.d.ts +6 -0
  22. package/build/components/DatePicker/time-picker/period-picker.js +10 -0
  23. package/build/components/DatePicker/time-picker/period-web.d.ts +6 -0
  24. package/build/components/DatePicker/time-picker/period-web.js +21 -0
  25. package/build/components/DatePicker/time-picker/wheel-native.d.ts +8 -0
  26. package/build/components/DatePicker/time-picker/wheel-native.js +19 -0
  27. package/build/components/DatePicker/time-picker/wheel-picker/index.d.ts +2 -0
  28. package/build/components/DatePicker/time-picker/wheel-picker/index.js +2 -0
  29. package/build/components/DatePicker/time-picker/wheel-picker/wheel-picker-item.d.ts +16 -0
  30. package/build/components/DatePicker/time-picker/wheel-picker/wheel-picker-item.js +97 -0
  31. package/build/components/DatePicker/time-picker/wheel-picker/wheel-picker.d.ts +21 -0
  32. package/build/components/DatePicker/time-picker/wheel-picker/wheel-picker.js +88 -0
  33. package/build/components/DatePicker/time-picker/wheel-picker/wheel-picker.style.d.ts +23 -0
  34. package/build/components/DatePicker/time-picker/wheel-picker/wheel-picker.style.js +21 -0
  35. package/build/components/DatePicker/time-picker/wheel-web.d.ts +8 -0
  36. package/build/components/DatePicker/time-picker/wheel-web.js +146 -0
  37. package/build/components/DatePicker/time-picker/wheel.d.ts +8 -0
  38. package/build/components/DatePicker/time-picker/wheel.js +10 -0
  39. package/build/components/List/List.js +2 -2
  40. package/build/components/Modal/Modal.js +31 -42
  41. package/build/components/Modal/Modal.web.js +3 -3
  42. package/build/components/Pagination/Pagination.d.ts +6 -0
  43. package/build/components/Pagination/Pagination.js +125 -0
  44. package/build/components/Pagination/Pagination.props.d.ts +26 -0
  45. package/build/components/Pagination/Pagination.props.js +1 -0
  46. package/build/components/Pagination/Pagination.utils.d.ts +2 -0
  47. package/build/components/Pagination/Pagination.utils.js +20 -0
  48. package/build/components/Pagination/Pagination.utils.test.d.ts +1 -0
  49. package/build/components/Pagination/Pagination.utils.test.js +16 -0
  50. package/build/components/Pagination/index.d.ts +2 -0
  51. package/build/components/Pagination/index.js +1 -0
  52. package/build/components/SafeAreaView/SafeAreaView.d.ts +5 -0
  53. package/build/components/SafeAreaView/SafeAreaView.js +117 -0
  54. package/build/components/SafeAreaView/SafeAreaView.props.d.ts +17 -0
  55. package/build/components/SafeAreaView/SafeAreaView.props.js +1 -0
  56. package/build/components/SafeAreaView/index.d.ts +2 -0
  57. package/build/components/SafeAreaView/index.js +1 -0
  58. package/build/components/Select/Select.d.ts +1 -1
  59. package/build/components/Select/Select.js +6 -5
  60. package/build/components/Select/Select.props.d.ts +4 -0
  61. package/build/components/Select/SelectOption.d.ts +1 -1
  62. package/build/components/Select/SelectOption.js +2 -2
  63. package/build/components/Table/Table.context.d.ts +12 -0
  64. package/build/components/Table/Table.context.js +9 -0
  65. package/build/components/Table/Table.d.ts +6 -0
  66. package/build/components/Table/Table.js +71 -0
  67. package/build/components/Table/Table.props.d.ts +56 -0
  68. package/build/components/Table/Table.props.js +1 -0
  69. package/build/components/Table/Table.utils.d.ts +5 -0
  70. package/build/components/Table/Table.utils.js +48 -0
  71. package/build/components/Table/Table.utils.test.d.ts +1 -0
  72. package/build/components/Table/Table.utils.test.js +71 -0
  73. package/build/components/Table/TableBody.d.ts +6 -0
  74. package/build/components/Table/TableBody.js +16 -0
  75. package/build/components/Table/TableCell.d.ts +10 -0
  76. package/build/components/Table/TableCell.js +44 -0
  77. package/build/components/Table/TableHeader.d.ts +6 -0
  78. package/build/components/Table/TableHeader.js +24 -0
  79. package/build/components/Table/TableHeaderCell.d.ts +10 -0
  80. package/build/components/Table/TableHeaderCell.js +97 -0
  81. package/build/components/Table/TablePagination.d.ts +6 -0
  82. package/build/components/Table/TablePagination.js +7 -0
  83. package/build/components/Table/TableRow.d.ts +8 -0
  84. package/build/components/Table/TableRow.js +25 -0
  85. package/build/components/Table/index.d.ts +8 -0
  86. package/build/components/Table/index.js +7 -0
  87. package/build/components/Timeline/Timeline.d.ts +6 -0
  88. package/build/components/Timeline/Timeline.js +34 -0
  89. package/build/components/Timeline/Timeline.props.d.ts +47 -0
  90. package/build/components/Timeline/Timeline.props.js +1 -0
  91. package/build/components/Timeline/TimelineItem.d.ts +6 -0
  92. package/build/components/Timeline/TimelineItem.js +235 -0
  93. package/build/components/Timeline/index.d.ts +3 -0
  94. package/build/components/Timeline/index.js +2 -0
  95. package/build/components/VerificationInput/VerificationInput.js +3 -3
  96. package/build/components/index.d.ts +5 -0
  97. package/build/components/index.js +5 -0
  98. package/build/tokens/components/dark/timeline.d.ts +2 -2
  99. package/build/tokens/components/dark/timeline.js +2 -2
  100. package/docs/components/AllComponents.web.tsx +106 -23
  101. package/docs/llm-docs/unistyles-llms-full.txt +1132 -534
  102. package/docs/llm-docs/unistyles-llms-small.txt +37 -37
  103. package/package.json +4 -4
  104. package/src/components/Button/Button.stories.tsx +43 -7
  105. package/src/components/Button/ButtonRoot.tsx +8 -0
  106. package/src/components/Combobox/Combobox.context.ts +26 -0
  107. package/src/components/Combobox/Combobox.docs.mdx +277 -0
  108. package/src/components/Combobox/Combobox.figma.tsx +60 -0
  109. package/src/components/Combobox/Combobox.props.ts +187 -0
  110. package/src/components/Combobox/Combobox.stories.tsx +233 -0
  111. package/src/components/Combobox/Combobox.tsx +446 -0
  112. package/src/components/Combobox/ComboboxOption.tsx +100 -0
  113. package/src/components/Combobox/index.ts +9 -0
  114. package/src/components/List/List.tsx +5 -4
  115. package/src/components/Modal/Modal.tsx +67 -74
  116. package/src/components/Modal/Modal.web.tsx +3 -3
  117. package/src/components/Pagination/Pagination.docs.mdx +99 -0
  118. package/src/components/Pagination/Pagination.figma.tsx +20 -0
  119. package/src/components/Pagination/Pagination.props.ts +28 -0
  120. package/src/components/Pagination/Pagination.stories.tsx +88 -0
  121. package/src/components/Pagination/Pagination.tsx +248 -0
  122. package/src/components/Pagination/Pagination.utils.test.ts +20 -0
  123. package/src/components/Pagination/Pagination.utils.ts +37 -0
  124. package/src/components/Pagination/index.ts +2 -0
  125. package/src/components/SafeAreaView/SafeAreaView.props.ts +20 -0
  126. package/src/components/SafeAreaView/SafeAreaView.tsx +173 -0
  127. package/src/components/SafeAreaView/index.ts +2 -0
  128. package/src/components/Select/Select.props.ts +4 -0
  129. package/src/components/Select/Select.tsx +35 -28
  130. package/src/components/Select/SelectOption.tsx +2 -0
  131. package/src/components/Table/Table.context.tsx +23 -0
  132. package/src/components/Table/Table.docs.mdx +239 -0
  133. package/src/components/Table/Table.figma.tsx +65 -0
  134. package/src/components/Table/Table.props.ts +65 -0
  135. package/src/components/Table/Table.stories.tsx +399 -0
  136. package/src/components/Table/Table.tsx +127 -0
  137. package/src/components/Table/Table.utils.test.ts +82 -0
  138. package/src/components/Table/Table.utils.ts +72 -0
  139. package/src/components/Table/TableBody.tsx +25 -0
  140. package/src/components/Table/TableCell.tsx +67 -0
  141. package/src/components/Table/TableHeader.tsx +41 -0
  142. package/src/components/Table/TableHeaderCell.tsx +136 -0
  143. package/src/components/Table/TablePagination.tsx +10 -0
  144. package/src/components/Table/TableRow.tsx +42 -0
  145. package/src/components/Table/index.ts +16 -0
  146. package/src/components/Timeline/Timeline.docs.mdx +177 -0
  147. package/src/components/Timeline/Timeline.figma.tsx +89 -0
  148. package/src/components/Timeline/Timeline.props.ts +51 -0
  149. package/src/components/Timeline/Timeline.stories.tsx +102 -0
  150. package/src/components/Timeline/Timeline.tsx +48 -0
  151. package/src/components/Timeline/TimelineItem.tsx +293 -0
  152. package/src/components/Timeline/index.ts +9 -0
  153. package/src/components/VerificationInput/VerificationInput.tsx +3 -0
  154. package/src/components/index.ts +5 -0
  155. package/src/tokens/components/dark/timeline.ts +2 -2
@@ -16,6 +16,8 @@ Each configuration is optional but enables advanced features, which are explaine
16
16
 
17
17
  ### Themes (Optional)
18
18
 
19
+ [Section titled “Themes (Optional)”](#themes-optional)
20
+
19
21
  `Themes` is a JavaScript object where the keys represent unique theme names, and the values are the corresponding theme definitions. For more details, refer to the [theming](/v3/guides/theming) guide.
20
22
 
21
23
  unistyles.ts
@@ -53,6 +55,8 @@ Unistyles supports any dynamic theme and doesn’t enforce a specific structure.
53
55
 
54
56
  ### Breakpoints (Optional)
55
57
 
58
+ [Section titled “Breakpoints (Optional)”](#breakpoints-optional)
59
+
56
60
  `Breakpoints` is a JavaScript object where the keys are unique breakpoint names and the values are the corresponding breakpoint values (numbers). Be sure to register at least one breakpoint with a value of 0, as it’s required to simulate the cascading behavior of CSS media queries.
57
61
 
58
62
  unistyles.ts
@@ -70,6 +74,8 @@ const breakpoints = {
70
74
 
71
75
  ### Settings (Optional)
72
76
 
77
+ [Section titled “Settings (Optional)”](#settings-optional)
78
+
73
79
  The `Settings` object has been simplified, and in the most recent version, it supports only four properties:
74
80
 
75
81
  * **`adaptiveThemes`** – a boolean that enables or disables adaptive themes [learn more](/v3/guides/theming#adaptive-themes)
@@ -108,6 +114,8 @@ In the Unistyles 3.0 setting both `initialTheme` and `adaptiveThemes` will cause
108
114
 
109
115
  ### TypeScript Types (Optional)
110
116
 
117
+ [Section titled “TypeScript Types (Optional)”](#typescript-types-optional)
118
+
111
119
  If your repository is using TypeScript, it is highly recommended to override the library types for optimal autocomplete and type safety regarding your themes and breakpoints:
112
120
 
113
121
  unistyles.ts
@@ -125,6 +133,8 @@ declare module 'react-native-unistyles' {
125
133
 
126
134
  ### Set configuration
127
135
 
136
+ [Section titled “Set configuration”](#set-configuration)
137
+
128
138
  The final step in the configuration is to set all the options by calling the `StyleSheet.configure` function:
129
139
 
130
140
  unistyles.ts
@@ -150,6 +160,8 @@ For expo router users, please refer to the [Expo Router guide](/v3/guides/expo-r
150
160
 
151
161
  ### Full example
152
162
 
163
+ [Section titled “Full example”](#full-example)
164
+
153
165
  unistyles.ts
154
166
 
155
167
  ```tsx
@@ -216,7 +228,9 @@ We’ve made Unistyles incredibly easy to use. You no longer need the `useStyle`
216
228
 
217
229
  ### Prerequisites
218
230
 
219
- Unistyles 3.0 is tightly integrated with `Fabric` and the latest versions of React Native. Therefore, you must use the **New Architecture** and at least **React Native 0.78.0**. Additionally, Unistyles relies on `react-native-nitro-modules` and `react-native-edge-to-edge`.
231
+ [Section titled “Prerequisites”](#prerequisites)
232
+
233
+ Unistyles 3.0 is tightly integrated with `Fabric` and the latest versions of React Native. Therefore, you must use the **New Architecture** and at least **React Native 0.78.0**. Additionally, Unistyles relies on `react-native-nitro-modules`.
220
234
 
221
235
  Note
222
236
 
@@ -236,16 +250,27 @@ Since Unistyles relies on `Fabric`, it cannot run on the `Old Architecture` or o
236
250
 
237
251
  ### Installation
238
252
 
253
+ [Section titled “Installation”](#installation)
254
+
239
255
  Install Unistyles and its dependencies
240
256
 
241
257
  ```shell
242
- yarn add react-native-unistyles react-native-nitro-modules react-native-edge-to-edge
258
+ yarn add react-native-unistyles react-native-nitro-modules
243
259
  ```
244
260
 
245
261
  Caution
246
262
 
247
263
  To avoid unexpected behaviors always use a fixed version of `react-native-nitro-modules`. Check compatibility table [here](https://github.com/jpudysz/react-native-unistyles?tab=readme-ov-file#installation).
248
264
 
265
+ react-native-edge-to-edge is optional since v3.1.0
266
+
267
+ `react-native-edge-to-edge` is no longer a required dependency. We **strongly recommend** setting `edgeToEdgeEnabled=true` in your `android/gradle.properties` — it enforces translucent system bars on modals, disables legacy StatusBar hacks, and enables additional React Native core fixes.
268
+
269
+ * **Expo SDK 54+**: Already enabled automatically
270
+ * **Expo SDK 53 / Bare React Native**: Add `edgeToEdgeEnabled=true` to `android/gradle.properties`
271
+
272
+ You can still install `react-native-edge-to-edge` alongside this property for ecosystem compatibility (e.g. `react-native-bootsplash`, `react-native-permissions`). Learn more [here](/v3/other/dependencies).
273
+
249
274
  Add babel plugin:
250
275
 
251
276
  babel.config.js
@@ -327,13 +352,15 @@ Finish installation based on your platform:
327
352
 
328
353
  ### As easy as React Native StyleSheet
329
354
 
355
+ [Section titled “As easy as React Native StyleSheet”](#as-easy-as-react-native-stylesheet)
356
+
330
357
  Getting started with Unistyles couldn’t be easier. Simply replace React Native’s `StyleSheet` with the `StyleSheet` exported from Unistyles. From that moment, you’ll be using a `StyleSheet` with superpowers 🦸🏼‍♂️.
331
358
 
332
359
  Example.tsx
333
360
 
334
- ```tsx
335
- import { StyleSheet } from 'react-native'
336
- import { StyleSheet } from 'react-native-unistyles'
361
+ ```diff
362
+ -import { StyleSheet } from 'react-native'
363
+ +import { StyleSheet } from 'react-native-unistyles'
337
364
 
338
365
 
339
366
  const MyComponent = () => {
@@ -372,6 +399,8 @@ To get the most out of Unistyles, it’s important to understand how it works an
372
399
 
373
400
  ### 1. StyleSheets
374
401
 
402
+ [Section titled “1. StyleSheets”](#1-stylesheets)
403
+
375
404
  A typical app consists of many `StyleSheets`. A `StyleSheet` is a JavaScript object that holds one or many styles. Each style is associated with a native view. What’s more important is that each `StyleSheet` is unique, tailored to the needs of the view, or to a shared component.
376
405
 
377
406
  ![](/_astro/how-1.ClhanbTT.png)
@@ -380,6 +409,8 @@ Your app’s StyleSheets
380
409
 
381
410
  ### 2. Babel plugin: dependencies
382
411
 
412
+ [Section titled “2. Babel plugin: dependencies”](#2-babel-plugin-dependencies)
413
+
383
414
  Unistyles needs to understand your `StyleSheet` dependencies in order to update them only when necessary. This process begins when Babel transforms your app’s code. At this stage, the Unistyles Babel plugin scans your `StyleSheets` and determines the dependencies for each style:
384
415
 
385
416
  ```ts
@@ -402,6 +433,8 @@ const styles = StyleSheet.create((theme, rt) => ({
402
433
 
403
434
  ### 3. Babel plugin: component factory
404
435
 
436
+ [Section titled “3. Babel plugin: component factory”](#3-babel-plugin-component-factory)
437
+
405
438
  As you already know, Unistyles has no components. This means your native view hierarchy remains exactly the same as in your original code. The Babel plugin processes your components through our component factory to borrow `refs` and bind the `ShadowNode` with `Unistyle`.
406
439
 
407
440
  You might be wondering, what is `Unistyle`? We refer to it as your `StyleSheet` style that has been parsed by the Unistyles compiler, and with the attached `C++` state.
@@ -416,6 +449,8 @@ Learn more on how the Babel plugin works [here](/v3/other/babel-plugin).
416
449
 
417
450
  ### 4. StyleSheet registry
418
451
 
452
+ [Section titled “4. StyleSheet registry”](#4-stylesheet-registry)
453
+
419
454
  We don’t just extract metadata from your styles. We do the same for your `StyleSheet`. On the C++ side, we know exactly which `StyleSheet` is static, which depends on a `theme`, and which `Unistyles` it contains. At this point, your app’s `StyleSheets` are reconstructed on the C++ side and stored in native C++ `StyleSheets`, which contain the parsed `Unistyles`.
420
455
 
421
456
  ![](/_astro/how-3.C8JEACBb.png)
@@ -430,6 +465,8 @@ Unistyles workflow
430
465
 
431
466
  ### 5. Reacting to events
432
467
 
468
+ [Section titled “5. Reacting to events”](#5-reacting-to-events)
469
+
433
470
  When you access your `StyleSheet` styles in your component, you’ll get a regular JS object as expected. If your component re-renders, we simply return the same `Unistyle` that’s already parsed and stored in the cache.
434
471
 
435
472
  To visualize the true power of `Unistyles`, imagine that some event occurs, such as:
@@ -450,6 +487,8 @@ Affected styles are then re-computed to reflect the new state of your app.
450
487
 
451
488
  ### 6. Shadow Tree updates
452
489
 
490
+ [Section titled “6. Shadow Tree updates”](#6-shadow-tree-updates)
491
+
453
492
  With the list of affected styles, we can now browse the `ShadowRegistry`, where we keep the bindings between `ShadowNode` and `Unistyles`. In other words, we know which `component` relies on which `style`. With all this information, we can translate the update into atomic `ShadowTree` instructions.
454
493
 
455
494
  With Unistyles 2.0 or any other library, we would need to re-render your entire app to reflect the changes:
@@ -482,6 +521,8 @@ Unistyles is a cross-platform library that enables you to share up to 100% of yo
482
521
 
483
522
  ### Why should you use Unistyles?
484
523
 
524
+ [Section titled “Why should you use Unistyles?”](#why-should-you-use-unistyles)
525
+
485
526
  * Guarantees no re-renders across the entire app (no hooks, no context—just pure JSI bindings)
486
527
  * Doesn’t pollute your native view hierarchy, you can use any component you want
487
528
  * Includes a cross-platform parser written in C++, ensuring consistent output across all platforms
@@ -502,58 +543,58 @@ The migration process is quite simple, but it can be tedious since you’ll need
502
543
 
503
544
  `UnistylesRegistry` can be easily replaced with `StyleSheet.configure` as it follows the same syntax. `Themes` and `Breakpoints` work exactly the same. For `Settings` we removed 4 out of 6 options:
504
545
 
505
- ```tsx
506
- import { UnistylesRegistry } from 'react-native-unistyles'
507
- import { StyleSheet } from 'react-native-unistyles'
546
+ ```diff
547
+ -import { UnistylesRegistry } from 'react-native-unistyles'
548
+ +import { StyleSheet } from 'react-native-unistyles'
508
549
 
509
550
 
510
- UnistylesRegistry.addConfig({
511
- adaptiveThemes: false,
512
- initialTheme: 'dark',
513
- plugins: [...],
514
- experimentalCSSMediaQueries: true,
515
- windowResizeDebounceTimeMs: 100,
516
- disableAnimatedInsets: true
517
- })
551
+ - UnistylesRegistry.addConfig({
552
+ - adaptiveThemes: false,
553
+ - initialTheme: 'dark',
554
+ - plugins: [...],
555
+ - experimentalCSSMediaQueries: true,
556
+ - windowResizeDebounceTimeMs: 100,
557
+ - disableAnimatedInsets: true
558
+ - })
518
559
 
519
560
 
520
- StyleSheet.configure({
521
- settings: {
522
- adaptiveThemes: false, // works exactly the same like in 2.0
523
- initialTheme: 'dark', // works exactly the same like in 2.0
561
+ + StyleSheet.configure({
562
+ + settings: {
563
+ + adaptiveThemes: false, // works exactly the same like in 2.0
564
+ + initialTheme: 'dark', // works exactly the same like in 2.0
524
565
  // plugins are removed, instead transform your styles with static functions
525
566
  // experimentalCSSMediaQueries: these options is also removed, and enabled by default with custom parser
526
567
  // windowResizeDebounceTimeMs: removed, there is no debouncing anymore. Styles are updated with CSS media queries
527
568
  // disableAnimatedInsets: removed, insets won't re-render your views
528
- }
529
- })
569
+ + }
570
+ + })
530
571
  ```
531
572
 
532
573
  3. Import `StyleSheet` from `react-native-unistyles`:
533
574
 
534
- ```tsx
535
- import { createStyleSheet, useStyles } from 'react-native-unistyles'
536
- import { StyleSheet } from 'react-native-unistyles'
575
+ ```diff
576
+ -import { createStyleSheet, useStyles } from 'react-native-unistyles'
577
+ +import { StyleSheet } from 'react-native-unistyles'
537
578
  ```
538
579
 
539
580
  4. Replace `createStyleSheet` with `StyleSheet.create`:
540
581
 
541
- ```tsx
542
- const stylesheet = createStyleSheet(theme => ({
543
- const stylesheet = StyleSheet.create(theme => ({
582
+ ```diff
583
+ -const stylesheet = createStyleSheet(theme => ({
584
+ +const stylesheet = StyleSheet.create(theme => ({
544
585
  ```
545
586
 
546
587
  5. Remove all occurrences of `useStyles` hook:
547
588
 
548
- ```tsx
549
- const { styles } = useStyles(stylesheet)
589
+ ```diff
590
+ -const { styles } = useStyles(stylesheet)
550
591
  ```
551
592
 
552
593
  6. Rename your `stylesheet` to `styles`:
553
594
 
554
- ```tsx
555
- const stylesheet = StyleSheet.create(theme => ({
556
- const styles = StyleSheet.create(theme => ({
595
+ ```diff
596
+ -const stylesheet = StyleSheet.create(theme => ({
597
+ +const styles = StyleSheet.create(theme => ({
557
598
  ```
558
599
 
559
600
  7. If you used `useInitialTheme`, remove it and set initial theme in `StyleSheet.configure`:
@@ -577,15 +618,15 @@ The migration process is quite simple, but it can be tedious since you’ll need
577
618
 
578
619
  8. If you need to access your `theme` in component, refactor it to use `withUnistyles`:
579
620
 
580
- ```tsx
621
+ ```diff
581
622
  import { Button } from 'react-native'
582
- import { useStyles } from 'react-native-unistyles'
583
- import { withUnistyles } from 'react-native-unistyles'
623
+ -import { useStyles } from 'react-native-unistyles'
624
+ +import { withUnistyles } from 'react-native-unistyles'
584
625
 
585
626
 
586
- const UniButton = withUnistyles(Button, theme => ({
627
+ +const UniButton = withUnistyles(Button, theme => ({
587
628
  color: theme.colors.primary
588
- }))
629
+ +}))
589
630
 
590
631
 
591
632
  const MyButton = () => {
@@ -594,7 +635,7 @@ The migration process is quite simple, but it can be tedious since you’ll need
594
635
 
595
636
 
596
637
  const MyButton = () => {
597
- const { theme } = useStyles(stylesheet)
638
+ -const { theme } = useStyles(stylesheet)
598
639
 
599
640
 
600
641
  return <Button color={theme.colors.primary} />
@@ -640,22 +681,22 @@ The migration process is quite simple, but it can be tedious since you’ll need
640
681
 
641
682
  11. If you used `UnistylesProvider`, remove it as it’s not available anymore:
642
683
 
643
- ```tsx
644
- import { UnistylesProvider } from 'react-native-unistyles'
684
+ ```diff
685
+ -import { UnistylesProvider } from 'react-native-unistyles'
645
686
 
646
687
 
647
- <UnistylesProvider>
688
+ -<UnistylesProvider>
648
689
  <App />
649
- </UnistylesProvider>
690
+ -</UnistylesProvider>
650
691
  ```
651
692
 
652
693
  12. If you want to move your component based on keyboard position, use `ime` inset:
653
694
 
654
- ```tsx
695
+ ```diff
655
696
  const style = StyleSheet.create({
656
697
  container: {
657
698
  paddingBottom: rt.insets.bottom // bottom is no longer dynamic
658
- paddingBottom: rt.insets.ime
699
+ +paddingBottom: rt.insets.ime
659
700
  }
660
701
  })
661
702
  ```
@@ -664,43 +705,43 @@ The migration process is quite simple, but it can be tedious since you’ll need
664
705
 
665
706
  14. Some `UnistylesRuntime` methods have been removed:
666
707
 
667
- ```tsx
668
- UnistylesRuntime.addPlugin(plugin) // Unistyles has no plugins anymore
669
- UnistylesRuntime.removePlugin(plugin) // Unistyles has no plugins anymore
670
- UnistylesRuntime.statusBar.setColor(color) // removed due to Android 15 deprecation
671
- UnistylesRuntime.navigationBar.setColor(color) // removed due to Android 15 deprecation
708
+ ```diff
709
+ -UnistylesRuntime.addPlugin(plugin) // Unistyles has no plugins anymore
710
+ -UnistylesRuntime.removePlugin(plugin) // Unistyles has no plugins anymore
711
+ -UnistylesRuntime.statusBar.setColor(color) // removed due to Android 15 deprecation
712
+ -UnistylesRuntime.navigationBar.setColor(color) // removed due to Android 15 deprecation
672
713
  ```
673
714
 
674
715
  15. `UnistylesRuntime` methods that accepted `color` and `alpha` have been changed to accept `color` only. Each method supports **any** color that is respected by React Native:
675
716
 
676
- ```tsx
677
- UnistylesRuntime.setRootViewBackgroundColor(color, alpha) // no need for separate alpha
678
- UnistylesRuntime.setRootViewBackgroundColor(color) // accepts any color
717
+ ```diff
718
+ -UnistylesRuntime.setRootViewBackgroundColor(color, alpha) // no need for separate alpha
719
+ +UnistylesRuntime.setRootViewBackgroundColor(color) // accepts any color
679
720
  ```
680
721
 
681
722
  16. `hairlineWidth` has been moved from `UnistylesRuntime` to `StyleSheet`. Use `StyleSheet.hairlineWidth` instead:
682
723
 
683
- ```tsx
684
- UnistylesRuntime.hairlineWidth // no longer available
685
- StyleSheet.hairlineWidth // matches StyleSheet API
724
+ ```diff
725
+ -UnistylesRuntime.hairlineWidth // no longer available
726
+ +StyleSheet.hairlineWidth // matches StyleSheet API
686
727
  ```
687
728
 
688
729
  17. If your app used variants, move config to `styles.useVariants` instead:
689
730
 
690
- ```tsx
691
- import { useStyles } from 'react-native-unistyles'
692
- import { StyleSheet } from 'react-native-unistyles'
731
+ ```diff
732
+ -import { useStyles } from 'react-native-unistyles'
733
+ +import { StyleSheet } from 'react-native-unistyles'
693
734
 
694
735
 
695
736
  const MyComponent = () => {
696
- const { styles } = useStyles(stylesheet, {
737
+ -const { styles } = useStyles(stylesheet, {
697
738
  variant1: 'primary',
698
739
  variant2: 'secondary'
699
- })
700
- styles.useVariants({
740
+ -})
741
+ +styles.useVariants({
701
742
  variant1: 'primary',
702
743
  variant2: 'secondary'
703
- })
744
+ +})
704
745
 
705
746
 
706
747
  return <View style={styles.container} />
@@ -790,6 +831,8 @@ Unistyles provides its own mocks to help you test your components. Follow this g
790
831
 
791
832
  ### Including Mocks
792
833
 
834
+ [Section titled “Including Mocks”](#including-mocks)
835
+
793
836
  You don’t need to mock anything manually, as Unistyles supplies all necessary mocks for its core and for `NitroModules`. To use them, simply include `react-native-unistyles/mocks` in your `jest.setup.ts` file.
794
837
 
795
838
  package.json
@@ -807,6 +850,8 @@ package.json
807
850
 
808
851
  ### Include Unistyles Configuration
809
852
 
853
+ [Section titled “Include Unistyles Configuration”](#include-unistyles-configuration)
854
+
810
855
  Each `StyleSheet` requires a configuration object passed to the `StyleSheet.configure` function. This is also true in the test environment. Extend the configuration from the previous step by including the file where you configure Unistyles.
811
856
 
812
857
  package.json
@@ -829,10 +874,14 @@ You must include configuration file **after** the mocks as they provide all nece
829
874
 
830
875
  ### Babel Plugin
831
876
 
877
+ [Section titled “Babel Plugin”](#babel-plugin)
878
+
832
879
  The Babel plugin is automatically disabled in the `jest` test environment or when `NODE_ENV === 'test'`.
833
880
 
834
881
  ### Understanding the role of mocks
835
882
 
883
+ [Section titled “Understanding the role of mocks”](#understanding-the-role-of-mocks)
884
+
836
885
  Mocks contain basic logic to correctly execute Unistyles code. The Jest environment does not provide a `screen` (width and height), pixel ratio, or any other values from `UnistylesRuntime`.
837
886
 
838
887
  You should never test how Unistyles parses your styles, whether your component has certain styles, or if it is visible. These tests can result in false positives.
@@ -849,6 +898,8 @@ This guide will explain when you should consider using Unistyles and when it’s
849
898
 
850
899
  ### When should you use Unistyles?
851
900
 
901
+ [Section titled “When should you use Unistyles?”](#when-should-you-use-unistyles)
902
+
852
903
  Unistyles is recommended for projects that:
853
904
 
854
905
  * leverage the New Architecture and care about performance and memory usage
@@ -861,18 +912,24 @@ Unistyles is recommended for projects that:
861
912
 
862
913
  ### When is Unistyles not the best option?
863
914
 
915
+ [Section titled “When is Unistyles not the best option?”](#when-is-unistyles-not-the-best-option)
916
+
864
917
  * You’re looking for a component library (Unistyles has no components, instead we encourage you to build your own design system specifically tailored to your project)
865
- * You use Tailwind on the web, as Unistyles has no native bindings to process `classNames` on the native side. Instead, we recommend using [Nativewind](https://www.nativewind.dev/)
918
+ * You use Tailwind on the web, as Unistyles has no native bindings to process `classNames` on the native side. Instead, we recommend using [uniwind](https://uniwind.dev/)
866
919
  * You’re building a super simple app that doesn’t require theme changes or any advanced features. In this case, stick with React Native’s `StyleSheet` and consider updating to Unistyles 3.0 when it will be more efficient
867
920
 
868
921
  ### When you can’t use Unistyles 3.0?
869
922
 
923
+ [Section titled “When you can’t use Unistyles 3.0?”](#when-you-cant-use-unistyles-30)
924
+
870
925
  * In Expo Go apps, as Unistyles is not (yet) selected by the Expo team
871
926
  * In apps that can’t update to the New Architecture. Instead, consider using [Unistyles 2.0](https://v2.unistyl.es/start/introduction/)
872
927
  * In apps that target unsupported platforms (eg. TV, Windows, macOS etc.), again consider using [Unistyles 2.0](https://v2.unistyl.es/start/introduction/)
873
928
 
874
929
  ### Other alternatives
875
930
 
931
+ [Section titled “Other alternatives”](#other-alternatives)
932
+
876
933
  To find other alternatives, please check the latest [State of React Native survey](https://stateofreactnative.com/).
877
934
 
878
935
  # Avoiding keyboard
@@ -885,6 +942,8 @@ Unistyles dynamically recalculates your styles based on their dependencies. To l
885
942
 
886
943
  ### Usage
887
944
 
945
+ [Section titled “Usage”](#usage)
946
+
888
947
  ```tsx
889
948
  import { TextInput, View } from 'react-native'
890
949
  import { StyleSheet } from 'react-native-unistyles'
@@ -933,6 +992,8 @@ For this we recommend following the guidelines provided by [Expo](https://docs.e
933
992
 
934
993
  ## How to create custom web components
935
994
 
995
+ [Section titled “How to create custom web components”](#how-to-create-custom-web-components)
996
+
936
997
  In order to create custom web components, you need to use `getWebProps` function. It takes a `StyleProp` and returns an object with `className` and `ref` properties.
937
998
 
938
999
  src/components/Header.tsx
@@ -1017,14 +1078,16 @@ If you’re creating multiplatform app, remember to create a native fallback for
1017
1078
 
1018
1079
  ### Modify main entry
1019
1080
 
1081
+ [Section titled “Modify main entry”](#modify-main-entry)
1082
+
1020
1083
  Expo Router resolves routes differently than expected. Also, Unistyles 3.0 is parsing your `StyleSheets` as soon as you import file containing it. This combination may cause some issues. To prevent that you need to modify your main entry file:
1021
1084
 
1022
1085
  package.json
1023
1086
 
1024
- ```json
1087
+ ```diff
1025
1088
  {
1026
- "main": "expo-router/entry"
1027
- "main": "index.ts"
1089
+ -"main": "expo-router/entry"
1090
+ +"main": "index.ts"
1028
1091
  }
1029
1092
  ```
1030
1093
 
@@ -1045,6 +1108,8 @@ With this setup, we will ensure that Unistyles is initialized before any other c
1045
1108
 
1046
1109
  ### Expo Router Web - Static rendering
1047
1110
 
1111
+ [Section titled “Expo Router Web - Static rendering”](#expo-router-web---static-rendering)
1112
+
1048
1113
  Caution
1049
1114
 
1050
1115
  This is the default option since Expo SDK 52.
@@ -1070,11 +1135,11 @@ In this file, initialize Unistyles by importing the config file:
1070
1135
 
1071
1136
  +html.tsx
1072
1137
 
1073
- ```tsx
1138
+ ```diff
1074
1139
  import React from 'react'
1075
1140
  import { ScrollViewStyleReset } from 'expo-router/html'
1076
1141
  import { type PropsWithChildren } from 'react'
1077
- import '../unistyles' // <-- file that initializes Unistyles
1142
+ +import '../unistyles' // <-- file that initializes Unistyles
1078
1143
 
1079
1144
 
1080
1145
  export default function Root({ children }: PropsWithChildren) {
@@ -1092,12 +1157,16 @@ While using Unistyles, it’s crucial to understand how styles need to be merged
1092
1157
 
1093
1158
  ### Introduction
1094
1159
 
1160
+ [Section titled “Introduction”](#introduction)
1161
+
1095
1162
  In the early versions of Unistyles 3.0, we tried to solve this issue with a Babel plugin. However, it was too complex to maintain various edge cases (especially with `Pressable`), and developers frequently encountered many `Unistyles: Style is not bound!` errors.
1096
1163
 
1097
1164
  With the new approach, we shift the responsibility of merging styles to the user. In other words, the Babel plugin will no longer convert your style tags from objects to arrays.
1098
1165
 
1099
1166
  ### How to merge multiple styles
1100
1167
 
1168
+ [Section titled “How to merge multiple styles”](#how-to-merge-multiple-styles)
1169
+
1101
1170
  Unistyles doesn’t provide any extra API for merging styles. Instead, we encourage you to use the `[]` syntax supported by React Native components.
1102
1171
 
1103
1172
  ```tsx
@@ -1123,12 +1192,16 @@ It’s critical to ship Unistyles 3.0 apps without this warning, as it can cause
1123
1192
 
1124
1193
  ### Reanimated
1125
1194
 
1195
+ [Section titled “Reanimated”](#reanimated)
1196
+
1126
1197
  In older versions of Reanimated, the `Animated` component was flattening your styles array, causing warnings and only allowing to pass a **single** unistyles to an `Animated` component ([original issue](https://github.com/jpudysz/react-native-unistyles/issues/512)).
1127
1198
 
1128
1199
  However, from `react-native-reanimated@3.17.2` or `react-native-reanimated@4.0.0-beta.3`, styles are no longer flattened.
1129
1200
 
1130
1201
  ### Spreading a single Unistyle
1131
1202
 
1203
+ [Section titled “Spreading a single Unistyle”](#spreading-a-single-unistyle)
1204
+
1132
1205
  Another problematic case is spreading a single Unistyle and merging it, e.g., with inline styles:
1133
1206
 
1134
1207
  ```tsx
@@ -1141,6 +1214,8 @@ Also, keep in mind that restoring the C++ state takes unnecessary extra time, so
1141
1214
 
1142
1215
  ### Summary
1143
1216
 
1217
+ [Section titled “Summary”](#summary)
1218
+
1144
1219
  * Use the `[]` syntax to merge styles
1145
1220
  * Avoid spreading Unistyles
1146
1221
  * Avoid merging your styles with the spread operator
@@ -1156,10 +1231,14 @@ React Compiler is a build-time tool that automatically optimizes your React app.
1156
1231
 
1157
1232
  ## With Expo
1158
1233
 
1234
+ [Section titled “With Expo”](#with-expo)
1235
+
1159
1236
  For Expo projects, simply follow the [official Expo guide](https://docs.expo.dev/guides/react-compiler/). No additional configuration changes are necessary!
1160
1237
 
1161
1238
  ## With Bare React Native
1162
1239
 
1240
+ [Section titled “With Bare React Native”](#with-bare-react-native)
1241
+
1163
1242
  For bare React Native projects, refer to the [official React guide](https://react.dev/learn/react-compiler#usage-with-babel) with one key adjustment:
1164
1243
 
1165
1244
  Ensure that the React Compiler runs *after* the Unistyles Babel plugin. Failure to do so may result in errors because Unistyles needs to process `Variants` before the React Compiler does. You can read more about the Babel plugin [here](/v3/other/babel-plugin).
@@ -1168,12 +1247,12 @@ Here’s a sample configuration for your `babel.config.js`:
1168
1247
 
1169
1248
  babel.config.js
1170
1249
 
1171
- ```js
1250
+ ```diff
1172
1251
  module.exports = function () {
1173
1252
  return {
1174
1253
  plugins: [
1175
1254
  ['react-native-unistyles/plugin'], // Must run before react-compiler
1176
- 'babel-plugin-react-compiler',
1255
+ +'babel-plugin-react-compiler',
1177
1256
  // Add other plugins here
1178
1257
  ]
1179
1258
  }
@@ -1195,6 +1274,8 @@ Reanimated works the best with Unistyles in:
1195
1274
 
1196
1275
  ### Access theme in worklets
1197
1276
 
1277
+ [Section titled “Access theme in worklets”](#access-theme-in-worklets)
1278
+
1198
1279
  Using the theme from `UnistylesRuntime.getTheme()` will not trigger worklet updates. Importing it from `useUnistyles` will cause a re-render.
1199
1280
 
1200
1281
  That’s why to use Unistyles theme in worklets (e.g. in `useAnimatedStyle`), you need to import a special hook from `react-native-unistyles/reanimated`.
@@ -1224,6 +1305,8 @@ Note
1224
1305
 
1225
1306
  ### Animating variant colors
1226
1307
 
1308
+ [Section titled “Animating variant colors”](#animating-variant-colors)
1309
+
1227
1310
  It’s possible to reuse Unistyles variant colors and animate them using the `useAnimatedStyle` hook.
1228
1311
 
1229
1312
  Define your variants with a `color` property:
@@ -1275,6 +1358,8 @@ const animatedStyle = useAnimatedStyle(() => {
1275
1358
 
1276
1359
  ### Merging styles
1277
1360
 
1361
+ [Section titled “Merging styles”](#merging-styles)
1362
+
1278
1363
  When you want to use `Unistyles` styles in `Animated` components, never mix them with `Reanimated` styles:
1279
1364
 
1280
1365
  ```tsx
@@ -1295,7 +1380,7 @@ export const MyAnimatedComponent = () => {
1295
1380
  }
1296
1381
 
1297
1382
 
1298
- const style = StyleSheet.create(theme => ({
1383
+ const styles = StyleSheet.create(theme => ({
1299
1384
  container: {
1300
1385
  flex: 1,
1301
1386
  justifyContent: 'center',
@@ -1326,7 +1411,7 @@ export const MyAnimatedComponent = () => {
1326
1411
  }
1327
1412
 
1328
1413
 
1329
- const style = StyleSheet.create(theme => ({
1414
+ const styles = StyleSheet.create(theme => ({
1330
1415
  container: {
1331
1416
  flex: 1,
1332
1417
  justifyContent: 'center',
@@ -1346,6 +1431,8 @@ Unistyles 3.0 is fully compatible with Next.js Server Side Rendering (SSR). We
1346
1431
 
1347
1432
  ### Usage
1348
1433
 
1434
+ [Section titled “Usage”](#usage)
1435
+
1349
1436
  * App router
1350
1437
 
1351
1438
  To use server-side rendered styles, create the following **client-side** component:
@@ -1388,9 +1475,9 @@ Unistyles 3.0 is fully compatible with Next.js Server Side Rendering (SSR). We
1388
1475
 
1389
1476
  layout.tsx
1390
1477
 
1391
- ```tsx
1392
- import '../unistyles'
1393
- import { Style } from '../Style'
1478
+ ```diff
1479
+ +import '../unistyles'
1480
+ +import { Style } from '../Style'
1394
1481
 
1395
1482
 
1396
1483
  export default function RootLayout({
@@ -1401,9 +1488,9 @@ Unistyles 3.0 is fully compatible with Next.js Server Side Rendering (SSR). We
1401
1488
  return (
1402
1489
  <html lang="en">
1403
1490
  <body>
1404
- <Style>
1491
+ +<Style>
1405
1492
  {children}
1406
- </Style>
1493
+ +</Style>
1407
1494
  </body>
1408
1495
  </html>
1409
1496
  );
@@ -1418,6 +1505,8 @@ Unistyles 3.0 is fully compatible with Next.js Server Side Rendering (SSR). We
1418
1505
 
1419
1506
  ### Config (Optional)
1420
1507
 
1508
+ [Section titled “Config (Optional)”](#config-optional)
1509
+
1421
1510
  `useServerUnistyles` accepts an optional config object:
1422
1511
 
1423
1512
  * **`includeRNWStyles`** – a boolean that enables or disables injecting React Native Web default CSS styles. Defaults to `true`.
@@ -1428,68 +1517,74 @@ Unistyles 3.0 is fully compatible with Next.js Server Side Rendering (SSR). We
1428
1517
 
1429
1518
  \_document.tsx
1430
1519
 
1431
- ```tsx
1432
- import { getServerUnistyles, resetServerUnistyles } from 'react-native-unistyles/server'
1520
+ ```diff
1521
+ +import { getServerUnistyles, resetServerUnistyles } from 'react-native-unistyles/server'
1433
1522
 
1434
1523
 
1435
1524
  export default class Document extends NextDocument {
1436
- static async getInitialProps({ renderPage }: DocumentContext) {
1437
- const page = await renderPage()
1438
- const styles = getServerUnistyles()
1525
+ +static async getInitialProps({ renderPage }: DocumentContext) {
1526
+ +const page = await renderPage()
1527
+ +const styles = getServerUnistyles()
1439
1528
 
1440
1529
 
1441
- resetServerUnistyles()
1530
+ +resetServerUnistyles()
1442
1531
 
1443
1532
 
1444
- return {
1445
- ...page,
1446
- styles
1447
- }
1448
- }
1533
+ +return {
1534
+ +...page,
1535
+ + styles
1536
+ + }
1537
+ + }
1449
1538
  ```
1450
1539
 
1451
1540
  And add the following use effect to your `_app.tsx`
1452
1541
 
1453
1542
  \_app.tsx
1454
1543
 
1455
- ```tsx
1456
- import { hydrateServerUnistyles } from 'react-native-unistyles/server'
1544
+ ```diff
1545
+ +import { hydrateServerUnistyles } from 'react-native-unistyles/server'
1457
1546
 
1458
1547
 
1459
1548
  {/* JSX of your component */}
1460
- useEffect(() => {
1461
- hydrateServerUnistyles()
1462
- }, [])
1549
+ +useEffect(() => {
1550
+ +hydrateServerUnistyles()
1551
+ + }, [])
1463
1552
  ```
1464
1553
 
1465
1554
  ### Config (Optional)
1466
1555
 
1556
+ [Section titled “Config (Optional)”](#config-optional-1)
1557
+
1467
1558
  `getServerUnistyles` accepts an optional config object:
1468
1559
 
1469
1560
  * **`includeRNWStyles`** – a boolean that enables or disables injecting React Native Web default CSS styles. Defaults to `true`.
1470
1561
 
1471
1562
  ## Troubleshooting
1472
1563
 
1564
+ [Section titled “Troubleshooting”](#troubleshooting)
1565
+
1473
1566
  ### Hydration error
1474
1567
 
1568
+ [Section titled “Hydration error”](#hydration-error)
1569
+
1475
1570
  If you’re not using adaptive themes, you might encounter hydration error on your root html element. This is because unistyles is adding a className to it based on the current theme.
1476
1571
 
1477
1572
  To fix this simply add `suppressHydrationWarning` to your root html element.
1478
1573
 
1479
1574
  layout.tsx
1480
1575
 
1481
- ```tsx
1482
- <html lang="en">
1483
- <html lang="en" suppressHydrationWarning>
1576
+ ```diff
1577
+ -<html lang="en">
1578
+ +<html lang="en" suppressHydrationWarning>
1484
1579
  ```
1485
1580
 
1486
1581
  Or you can directly add the className to your root html element.
1487
1582
 
1488
1583
  layout.tsx
1489
1584
 
1490
- ```tsx
1491
- <html lang="en">
1492
- <html lang="en" className="dark">
1585
+ ```diff
1586
+ -<html lang="en">
1587
+ +<html lang="en" className="dark">
1493
1588
  ```
1494
1589
 
1495
1590
  # Theming
@@ -1506,6 +1601,8 @@ Theming is optional. If you don’t register themes with [StyleSheet.configure](
1506
1601
 
1507
1602
  ### Create a theme
1508
1603
 
1604
+ [Section titled “Create a theme”](#create-a-theme)
1605
+
1509
1606
  You can organize your themes however you want:
1510
1607
 
1511
1608
  ```tsx
@@ -1570,6 +1667,8 @@ It’s not recommended to use themes with different shapes. Unistyles allows tha
1570
1667
 
1571
1668
  ### Select theme
1572
1669
 
1670
+ [Section titled “Select theme”](#select-theme)
1671
+
1573
1672
  If you’ve registered more than one theme, Unistyles won’t know which one is the initial one. At this point, you have 3 options:
1574
1673
 
1575
1674
  * If you know the initial theme upfront, select it with `settings` from [StyleSheet.configure](/v3/start/configuration#settings-optional)
@@ -1603,6 +1702,8 @@ It’s not possible to use `async` functions with `initialTheme` option.
1603
1702
 
1604
1703
  ### Get the current theme
1605
1704
 
1705
+ [Section titled “Get the current theme”](#get-the-current-theme)
1706
+
1606
1707
  To get the current theme you can access it in the `StyleSheet.create` function:
1607
1708
 
1608
1709
  ```tsx
@@ -1635,6 +1736,8 @@ Caution
1635
1736
 
1636
1737
  ### Get the current theme name
1637
1738
 
1739
+ [Section titled “Get the current theme name”](#get-the-current-theme-name)
1740
+
1638
1741
  To get the current theme name, import `UnistylesRuntime`:
1639
1742
 
1640
1743
  ```tsx
@@ -1651,6 +1754,8 @@ export const UserTheme = () => (
1651
1754
 
1652
1755
  ### Adaptive themes
1653
1756
 
1757
+ [Section titled “Adaptive themes”](#adaptive-themes)
1758
+
1654
1759
  Adaptive themes allow Unistyles to automatically manage the selection of your themes based on device color scheme settings. To enable this, you need to meet two conditions:
1655
1760
 
1656
1761
  * register two themes with reserved names `light` and `dark`:
@@ -1685,6 +1790,8 @@ Setting initial theme and enabling adaptive themes at the same time will throw a
1685
1790
 
1686
1791
  ### Toggle adaptive themes during runtime
1687
1792
 
1793
+ [Section titled “Toggle adaptive themes during runtime”](#toggle-adaptive-themes-during-runtime)
1794
+
1688
1795
  To toggle adaptive themes support at any point, use `UnistylesRuntime`:
1689
1796
 
1690
1797
  ```tsx
@@ -1704,6 +1811,8 @@ With adaptive themes disabled, you can now manually change the theme.
1704
1811
 
1705
1812
  ### Check if adaptive themes are enabled
1706
1813
 
1814
+ [Section titled “Check if adaptive themes are enabled”](#check-if-adaptive-themes-are-enabled)
1815
+
1707
1816
  To check if adaptive themes are enabled, use `UnistylesRuntime` again:
1708
1817
 
1709
1818
  ```tsx
@@ -1720,6 +1829,8 @@ export const AdaptiveThemes = () => (
1720
1829
 
1721
1830
  ### Get device color scheme
1722
1831
 
1832
+ [Section titled “Get device color scheme”](#get-device-color-scheme)
1833
+
1723
1834
  Check your device color preference with `UnistylesRuntime`:
1724
1835
 
1725
1836
  ```tsx
@@ -1744,6 +1855,8 @@ If your app’s theme is not changing based on device settings, please refer to
1744
1855
 
1745
1856
  ### Change theme
1746
1857
 
1858
+ [Section titled “Change theme”](#change-theme)
1859
+
1747
1860
  To change the theme at any time, simply call `setTheme` function:
1748
1861
 
1749
1862
  ```tsx
@@ -1765,6 +1878,8 @@ Calling this function with enabled adaptive themes will throw an error.
1765
1878
 
1766
1879
  ### Update theme during runtime
1767
1880
 
1881
+ [Section titled “Update theme during runtime”](#update-theme-during-runtime)
1882
+
1768
1883
  Unistyles allows you to update your theme during runtime. This is useful if you want to show the user interface with default colors and later alter theme based on user preferences.
1769
1884
 
1770
1885
  If you update the currently selected theme, it will be automatically applied, and Unistyles will notify all stylesheets about the change. Otherwise, theme will be updated silently.
@@ -1792,6 +1907,8 @@ export const UpdateTheme = ({ selectedColors }) => (
1792
1907
 
1793
1908
  ### Update rootView background color during runtime
1794
1909
 
1910
+ [Section titled “Update rootView background color during runtime”](#update-rootview-background-color-during-runtime)
1911
+
1795
1912
  You can also change dynamically the root view background color with `UnistylesRuntime`:
1796
1913
 
1797
1914
  ```tsx
@@ -1825,12 +1942,16 @@ If you start working with Unistyles 3.0, it might be unclear why some views are
1825
1942
 
1826
1943
  ### Problem 1: Babel
1827
1944
 
1945
+ [Section titled “Problem 1: Babel”](#problem-1-babel)
1946
+
1828
1947
  To leverage ShadowTree updates and avoid unnecessary re-renders, Unistyles must process both `StyleSheets` and your components. By default, the Babel plugin looks for `react-native-unistyles` imports and always ignores the `node_modules` folder.
1829
1948
 
1830
1949
  If you separate `StyleSheets` from your components, it’s your responsibility to configure Babel to detect components that lack a Unistyles import. We’ve added plenty of options, so be sure to [check them out](/v3/other/babel-plugin##extra-configuration).
1831
1950
 
1832
1951
  ### Problem 2: Dependency detection
1833
1952
 
1953
+ [Section titled “Problem 2: Dependency detection”](#problem-2-dependency-detection)
1954
+
1834
1955
  Unistyles will automatically detect all your dependencies for every `StyleSheet`, but there’s a chance you used custom syntax that isn’t covered by the plugin. If Babel fails to detect some style dependencies, they won’t be updated when necessary.
1835
1956
 
1836
1957
  You can easily debug this issue by adding the following Babel plugin configuration:
@@ -1859,10 +1980,14 @@ Then, restart the Metro server cache and check the console, where you’ll find
1859
1980
 
1860
1981
  ### Problem 3: Non React Native components
1861
1982
 
1983
+ [Section titled “Problem 3: Non React Native components”](#problem-3-non-react-native-components)
1984
+
1862
1985
  Unistyles can only update React Native components. If you’re using a third-party component, you’ll need to apply a different strategy. Follow our [decision algorithm](/v3/references/3rd-party-views) to help you choose the best approach.
1863
1986
 
1864
1987
  ### Problem 4: Web styles are not applied
1865
1988
 
1989
+ [Section titled “Problem 4: Web styles are not applied”](#problem-4-web-styles-are-not-applied)
1990
+
1866
1991
  This issue indicates that the Babel plugin didn’t detect some of your components. Initially, it may seem like native styles are working correctly, but that’s not the case.
1867
1992
 
1868
1993
  On mobile, styles are returned the same way as in React Native. You can always `console.log` them to inspect the parsed values:
@@ -1937,6 +2062,8 @@ Breakpoints are user-defined key/value pairs that describe the boundaries of scr
1937
2062
 
1938
2063
  ### Register breakpoints
1939
2064
 
2065
+ [Section titled “Register breakpoints”](#register-breakpoints)
2066
+
1940
2067
  To register your breakpoints, create an object with **any** keys:
1941
2068
 
1942
2069
  unistyles.ts
@@ -1981,9 +2108,11 @@ To learn more, follow the configuration [guide](/v3/start/configuration).
1981
2108
 
1982
2109
  ### How to use breakpoints?
1983
2110
 
2111
+ [Section titled “How to use breakpoints?”](#how-to-use-breakpoints)
2112
+
1984
2113
  Any style can change based on breakpoints. To do this, change a `value` to an `object`:
1985
2114
 
1986
- ```tsx
2115
+ ```diff
1987
2116
  const styles = StyleSheet.create(theme => ({
1988
2117
  container: {
1989
2118
  flex: 1,
@@ -1991,10 +2120,10 @@ const styles = StyleSheet.create(theme => ({
1991
2120
  alignItems: 'center',
1992
2121
  backgroundColor: theme.colors.background,
1993
2122
  backgroundColor: {
1994
- // your breakpoints
2123
+ +// your breakpoints
1995
2124
  xs: theme.colors.background,
1996
2125
  sm: theme.colors.barbie
1997
- }
2126
+ +}
1998
2127
  },
1999
2128
  text: {
2000
2129
  color: theme.colors.typography
@@ -2033,6 +2162,8 @@ Breakpoints are also available with [variants](/v3/references/variants/) and [co
2033
2162
 
2034
2163
  ### Built-in breakpoints `landscape` and `portrait`
2035
2164
 
2165
+ [Section titled “Built-in breakpoints landscape and portrait”](#built-in-breakpoints-landscape-and-portrait)
2166
+
2036
2167
  Even if you don’t use custom breakpoints, you can still utilize Unistyles’ predefined breakpoints available on mobile devices: `portrait` and `landscape`.
2037
2168
 
2038
2169
  * `portrait` will resolve to your device’s width in portrait mode
@@ -2058,12 +2189,16 @@ const styles = StyleSheet.create(theme => ({
2058
2189
 
2059
2190
  ### Pixel/Point mode for native breakpoints
2060
2191
 
2192
+ [Section titled “Pixel/Point mode for native breakpoints”](#pixelpoint-mode-for-native-breakpoints)
2193
+
2061
2194
  By default, Unistyles will use `pixels` for native breakpoints. This means that the breakpoints and [mq](/v3/references/media-queries) will be computed based on mobile screen pixels. You can change this behavior by setting `nativeBreakpointsMode` to `points` in your [configuration](/v3/start/configuration#settings-optional).
2062
2195
 
2063
2196
  If `nativeBreakpointsMode` is set to `points`, all breakpoints and `mq` will be computed based on mobile screen points (screen in pixels divided by pixel ratio).
2064
2197
 
2065
2198
  ### Show/Hide your components based on breakpoints
2066
2199
 
2200
+ [Section titled “Show/Hide your components based on breakpoints”](#showhide-your-components-based-on-breakpoints)
2201
+
2067
2202
  In order to show or hide your components based on the screen size, you can leverage the `mq` utility and one of the two built-in components: `Display` and `Hide`.
2068
2203
 
2069
2204
  ```tsx
@@ -2098,6 +2233,8 @@ export const CurrentBreakpoint = () => (
2098
2233
 
2099
2234
  ### Get registered breakpoints
2100
2235
 
2236
+ [Section titled “Get registered breakpoints”](#get-registered-breakpoints)
2237
+
2101
2238
  Access your registered breakpoints object with `UnistylesRuntime`:
2102
2239
 
2103
2240
  ```tsx
@@ -2122,6 +2259,8 @@ Compound variants are a way of applying additional styles when certain condition
2122
2259
 
2123
2260
  ### Basic usage
2124
2261
 
2262
+ [Section titled “Basic usage”](#basic-usage)
2263
+
2125
2264
  Let’s say you created a base `Typography` component with the following variants:
2126
2265
 
2127
2266
  ```tsx
@@ -2168,6 +2307,8 @@ What if you’ve received a new requirement where the text should be underlined
2168
2307
 
2169
2308
  ### Usage with Compound variants
2170
2309
 
2310
+ [Section titled “Usage with Compound variants”](#usage-with-compound-variants)
2311
+
2171
2312
  With compound variants, it can be achieved in a more concise way:
2172
2313
 
2173
2314
  ```tsx
@@ -2233,6 +2374,8 @@ It’s also possible to use these values to build responsive layouts based on na
2233
2374
 
2234
2375
  ### iOS
2235
2376
 
2377
+ [Section titled “iOS”](#ios)
2378
+
2236
2379
  Unistyles’ implementation is based on [Human Interface Guidelines](https://developer.apple.com/design/human-interface-guidelines/typography#Specifications) and the available values are:
2237
2380
 
2238
2381
  `xSmall`, `Small`, `Medium`, `Large`, `xLarge`, `xxLarge`, `xxxLarge`, `unspecified`
@@ -2243,6 +2386,8 @@ In addition to the above categories, you can also use the [Accessibility sizes](
2243
2386
 
2244
2387
  ### Android
2245
2388
 
2389
+ [Section titled “Android”](#android)
2390
+
2246
2391
  There is no direct equivalent to the iOS content size category on Android. The implementation is based on [Font Scale](https://developer.android.com/reference/android/content/res/Configuration#fontScale), and the available values are:
2247
2392
 
2248
2393
  `Small`, `Default`, `Large`, `ExtraLarge`, `Huge`
@@ -2261,10 +2406,14 @@ Mapping is based on the following table:
2261
2406
 
2262
2407
  ### Web
2263
2408
 
2409
+ [Section titled “Web”](#web)
2410
+
2264
2411
  There is no support for the content size category on the web. Reading the value will always resolve to `unspecified`.
2265
2412
 
2266
2413
  ### Usage
2267
2414
 
2415
+ [Section titled “Usage”](#usage)
2416
+
2268
2417
  To get the current `contentSizeCategory`, you need to use `UnistylesRuntime`:
2269
2418
 
2270
2419
  ```tsx
@@ -2296,6 +2445,8 @@ Unistyles provides rich metadata about your device dimensions. This is useful fo
2296
2445
 
2297
2446
  ### Accessing dimensions
2298
2447
 
2448
+ [Section titled “Accessing dimensions”](#accessing-dimensions)
2449
+
2299
2450
  In order to start using the dimensions metadata, you need to import `UnistylesRuntime`:
2300
2451
 
2301
2452
  ```tsx
@@ -2304,6 +2455,8 @@ import { UnistylesRuntime } from 'react-native-unistyles'
2304
2455
 
2305
2456
  ### Screen dimensions
2306
2457
 
2458
+ [Section titled “Screen dimensions”](#screen-dimensions)
2459
+
2307
2460
  The most basic dimensions are the screen dimensions. These are the dimensions of the screen that your app is running on. You can access them with the `screen` prop:
2308
2461
 
2309
2462
  ```tsx
@@ -2316,6 +2469,8 @@ UnistylesRuntime.screen.height // eg. 760
2316
2469
 
2317
2470
  ### Status bar
2318
2471
 
2472
+ [Section titled “Status bar”](#status-bar)
2473
+
2319
2474
  You can access status bar dimensions with the `statusBar` prop:
2320
2475
 
2321
2476
  ```tsx
@@ -2330,6 +2485,8 @@ This prop may be useful for creating custom headers. In most of the cases status
2330
2485
 
2331
2486
  ### Navigation bar
2332
2487
 
2488
+ [Section titled “Navigation bar”](#navigation-bar)
2489
+
2333
2490
  You can access navigation bar dimensions with `navigationBar` prop:
2334
2491
 
2335
2492
  ```tsx
@@ -2344,6 +2501,8 @@ This prop may be useful for creating custom bottom bars. In most of the cases na
2344
2501
 
2345
2502
  ### Insets
2346
2503
 
2504
+ [Section titled “Insets”](#insets)
2505
+
2347
2506
  Insets are the safe areas of the screen. They are used to avoid overlapping with system UI elements such as the status bar, navigation bar, and home indicator. You can access them with `insets` prop:
2348
2507
 
2349
2508
  ```tsx
@@ -2379,6 +2538,8 @@ Unistyles automatically reacts when you hide or show status and navigation bars.
2379
2538
 
2380
2539
  ### Pixel ratio
2381
2540
 
2541
+ [Section titled “Pixel ratio”](#pixel-ratio)
2542
+
2382
2543
  Device Pixel Ratio (DPR) is the ratio between physical pixels and device-independent pixels (DIPs) on a screen. It determines how many physical pixels are used to represent a single CSS pixel.
2383
2544
 
2384
2545
  Most likely, your phone pixel ratio ranges between 1.0 to 3.0 (retina).
@@ -2389,6 +2550,8 @@ UnistylesRuntime.pixelRatio // eg. 2.0
2389
2550
 
2390
2551
  ### Font scale
2391
2552
 
2553
+ [Section titled “Font scale”](#font-scale)
2554
+
2392
2555
  Font scale is a ratio between the font size of the device and the default font size. It is used to adjust the size of text on the screen in companion with [content size category](/v3/references/content-size-category/).
2393
2556
 
2394
2557
  ```tsx
@@ -2407,6 +2570,8 @@ With Unistyles 3.0, preferred way of listening for breakpoint changes is with `D
2407
2570
 
2408
2571
  ### Display
2409
2572
 
2573
+ [Section titled “Display”](#display)
2574
+
2410
2575
  The Display component helps you show its children based on `breakpoints` or `media queries`.
2411
2576
 
2412
2577
  ```tsx
@@ -2451,6 +2616,8 @@ const Component = () => {
2451
2616
 
2452
2617
  ### Hide
2453
2618
 
2619
+ [Section titled “Hide”](#hide)
2620
+
2454
2621
  On the opposite side, the `Hide` component helps you hide its children based on `breakpoints` or `media queries`. It works exactly the same way as the Display component.
2455
2622
 
2456
2623
  ```tsx
@@ -2488,9 +2655,11 @@ If you need to pass a value from JSX to your `stylesheet` you can do so using a
2488
2655
 
2489
2656
  ### Usage
2490
2657
 
2658
+ [Section titled “Usage”](#usage)
2659
+
2491
2660
  To use a dynamic function, change **any** stylesheet’s value from an `object` to a `function`:
2492
2661
 
2493
- ```tsx
2662
+ ```diff
2494
2663
  const styles = StyleSheet.create(theme => ({
2495
2664
  container: {
2496
2665
  container: () => ({
@@ -2498,7 +2667,7 @@ const styles = StyleSheet.create(theme => ({
2498
2667
  flex: 1,
2499
2668
  justifyContent: 'center',
2500
2669
  alignItems: 'center'
2501
- }
2670
+ -}
2502
2671
  })
2503
2672
  }))
2504
2673
  ```
@@ -2537,12 +2706,16 @@ Keep in mind that a dynamic function can accept only serializable arguments. The
2537
2706
 
2538
2707
  ### iOS
2539
2708
 
2709
+ [Section titled “iOS”](#ios)
2710
+
2540
2711
  Unistyles uses native `SafeAreaInsets` API to handle insets on iOS. This API is stable and works the same across all iOS versions.
2541
2712
 
2542
2713
  Most likely, you’ll never receive incorrect inset values on iOS.
2543
2714
 
2544
2715
  ### Android
2545
2716
 
2717
+ [Section titled “Android”](#android)
2718
+
2546
2719
  Unistyles uses `WindowsInsetsCompat` API to handle insets on Android. This API requires your app to have edge to edge layout enabled. In other words, it means that your `StatusBar` is always `translucent` and the app can draw behind the `NavigationBar`. A translucent status bar is also the default when you build your app with Expo. To leverage `WindowInsetsCompat`, Unistyles enables `edgeToEdge` layout by default.
2547
2720
 
2548
2721
  As a result you need to use paddings to draw your app content above system bars. To learn more about `edgeToEdge` layout please check [Window insets in Compose](https://developer.android.com/develop/ui/compose/layouts/insets).
@@ -2580,9 +2753,11 @@ Apps are edge-to-edge by default on devices running Android 15 if the app is tar
2580
2753
 
2581
2754
  [Learn more](https://developer.android.com/about/versions/15/behavior-changes-15)
2582
2755
 
2583
- Caution
2756
+ Enable edgeToEdgeEnabled in gradle.properties
2584
2757
 
2585
- Unistyles enables `edgeToEdge` by default, but sometimes other libraries might interfere with it. We decided to depend on `react-native-edge-to-edge` package, to help reduce these issues. Learn more [here](/v3/other/dependencies#react-native-edge-to-edge).
2758
+ We **strongly recommend** setting `edgeToEdgeEnabled=true` in your `android/gradle.properties`. Beyond enabling edge-to-edge layout, it enforces translucent system bars on modals, disables legacy StatusBar hacks, and enables additional React Native core fixes. **Expo SDK 54+** enables this automatically.
2759
+
2760
+ Since v3.1.0, `react-native-edge-to-edge` is optional — you can still install it for ecosystem compatibility. Learn more [here](/v3/other/dependencies#react-native-edge-to-edge-optional-since-v310).
2586
2761
 
2587
2762
  # Media Queries
2588
2763
 
@@ -2592,9 +2767,11 @@ Media queries provide more power and allow you to style cross-platform apps with
2592
2767
 
2593
2768
  ### Basic usage
2594
2769
 
2770
+ [Section titled “Basic usage”](#basic-usage)
2771
+
2595
2772
  To use media queries, you need to import the `mq` utility and convert your value to an `object`:
2596
2773
 
2597
- ```tsx
2774
+ ```diff
2598
2775
  import { Stylesheet, mq } from 'react-native-unistyles'
2599
2776
 
2600
2777
 
@@ -2605,9 +2782,9 @@ const styles = Stylesheet.create(theme => ({
2605
2782
  alignItems: 'center'
2606
2783
  backgroundColor: theme.colors.background,
2607
2784
  backgroundColor: {
2608
- [mq.only.width(240, 380)]: theme.colors.background,
2609
- [mq.only.width(380)]: theme.colors.barbie
2610
- }
2785
+ +[mq.only.width(240, 380)]: theme.colors.background,
2786
+ +[mq.only.width(380)]: theme.colors.barbie
2787
+ +}
2611
2788
  }
2612
2789
  }))
2613
2790
  ```
@@ -2616,6 +2793,8 @@ The `mq` utility provides Intellisense for quickly building your media queries.
2616
2793
 
2617
2794
  ### Advanced usage
2618
2795
 
2796
+ [Section titled “Advanced usage”](#advanced-usage)
2797
+
2619
2798
  You can also combine `width` media queries with `height` media queries:
2620
2799
 
2621
2800
  ```tsx
@@ -2678,6 +2857,8 @@ const styles = Stylesheet.create(theme => ({
2678
2857
 
2679
2858
  ### Reference
2680
2859
 
2860
+ [Section titled “Reference”](#reference)
2861
+
2681
2862
  Available combinations
2682
2863
 
2683
2864
  ```shell
@@ -2712,6 +2893,8 @@ If you pass an invalid range to mq utility eg. (‘xl’, ‘sm’) or (500, 200
2712
2893
 
2713
2894
  ### Combining media queries with breakpoints
2714
2895
 
2896
+ [Section titled “Combining media queries with breakpoints”](#combining-media-queries-with-breakpoints)
2897
+
2715
2898
  You can mix media queries with breakpoints, but media queries will always have higher priority:
2716
2899
 
2717
2900
  ```tsx
@@ -2734,6 +2917,8 @@ const styles = Stylesheet.create(theme => ({
2734
2917
 
2735
2918
  ### CSS Media Queries
2736
2919
 
2920
+ [Section titled “CSS Media Queries”](#css-media-queries)
2921
+
2737
2922
  `Breakpoints` and `Media Queries` will be auto converted to Web CSS media queries. Learn more about [Web Media Queries](/v3/references/web-styles#how-it-works).
2738
2923
 
2739
2924
  # Mini Runtime
@@ -2777,6 +2962,8 @@ To address this, Unistyles 3.0 introduces the concept of a `Scoped Theme`, which
2777
2962
 
2778
2963
  ### Usage with named theme
2779
2964
 
2965
+ [Section titled “Usage with named theme”](#usage-with-named-theme)
2966
+
2780
2967
  To use scoped theme, you need to import `ScopedTheme` component from `react-native-unistyles`:
2781
2968
 
2782
2969
  ```ts
@@ -2825,6 +3012,8 @@ You can also nest `ScopedTheme` components:
2825
3012
 
2826
3013
  ### Usage with inverted adaptive theme
2827
3014
 
3015
+ [Section titled “Usage with inverted adaptive theme”](#usage-with-inverted-adaptive-theme)
3016
+
2828
3017
  You can also use `ScopedTheme` with the `invertedAdaptive` prop. This prop cannot be used together with a named `ScopedTheme`, as these options are mutually exclusive. The purpose of `invertedAdaptive` is to apply the opposite adaptive theme to the one that is currently active.
2829
3018
 
2830
3019
  In other words, if your app supports [adaptive themes](/v3/guides/theming#adaptive-themes) and you use `ScopedTheme` with the `invertedAdaptive` prop, it will apply:
@@ -2858,6 +3047,8 @@ You can also nest other `ScopedThemes` inside `ScopedTheme` with `invertedAdapti
2858
3047
 
2859
3048
  ### Reset
2860
3049
 
3050
+ [Section titled “Reset”](#reset)
3051
+
2861
3052
  If you wrap multiple children in `ScopedTheme` you can disable scoped theme for some of them by using `reset` prop:
2862
3053
 
2863
3054
  ```tsx
@@ -2884,6 +3075,8 @@ If you wrap multiple children in `ScopedTheme` you can disable scoped theme for
2884
3075
 
2885
3076
  ### Reading current scoped theme
2886
3077
 
3078
+ [Section titled “Reading current scoped theme”](#reading-current-scoped-theme)
3079
+
2887
3080
  Information about the current `ScopedTheme` is temporary and only available during the component render phase.
2888
3081
 
2889
3082
  For the following example, `themeName` will be different based on the place where we access it:
@@ -2976,6 +3169,91 @@ const ScopedComponent = () => {
2976
3169
  </ScopedTheme>
2977
3170
  ```
2978
3171
 
3172
+ ### Scoped Theme with Suspense
3173
+
3174
+ [Section titled “Scoped Theme with Suspense”](#scoped-theme-with-suspense)
3175
+
3176
+ When using `ScopedTheme` with React’s `Suspense`, there’s an important consideration about component placement due to how React handles suspension and re-rendering.
3177
+
3178
+ React Suspense works by catching promises thrown by child components that are waiting for data. When this happens:
3179
+
3180
+ 1. React pauses rendering and shows the fallback content
3181
+ 2. Components that successfully rendered before the suspension may be reused
3182
+ 3. Parent components might not re-render when the suspended data becomes available
3183
+
3184
+ This means if you place `ScopedTheme` above a component that suspends, the scoped theme might not be applied correctly when the component finally renders:
3185
+
3186
+ ```tsx
3187
+ // ❌ This won't work correctly
3188
+ <Suspense fallback={<Loading />}>
3189
+ <ScopedTheme name="dark">
3190
+ <SuspendedComponent /> {/* ScopedTheme already rendered before suspension */}
3191
+ </ScopedTheme>
3192
+ </Suspense>
3193
+ ```
3194
+
3195
+ Unistyles ScopedTheme is only available during render phase, we decided to not use `React.Context` to keep the API performant and easy to use.
3196
+
3197
+ To fix this issue, you can move the `ScopedTheme` inside the suspended component:
3198
+
3199
+ ```tsx
3200
+ // ✅ Place ScopedTheme inside the component that suspends
3201
+ const SuspendedComponent = () => {
3202
+ const data = useSuspenseQuery(); // This throws a promise
3203
+
3204
+
3205
+ return (
3206
+ <ScopedTheme name="dark">
3207
+ <View style={styles.container}>
3208
+ <Text style={styles.text}>
3209
+ {data.title}
3210
+ </Text>
3211
+ </View>
3212
+ </ScopedTheme>
3213
+ );
3214
+ };
3215
+
3216
+
3217
+ <Suspense fallback={<Loading />}>
3218
+ <SuspendedComponent />
3219
+ </Suspense>
3220
+ ```
3221
+
3222
+ The key is to ensure that `ScopedTheme` is rendered **after** the suspension occurs, so that when React re-renders the suspended component tree, the scoped theme context is properly established.
3223
+
3224
+ This pattern ensures that your themed components will render with the correct theme once the suspended data becomes available.
3225
+
3226
+ ### Scoped Theme and Hot Module Reloading (HMR)
3227
+
3228
+ [Section titled “Scoped Theme and Hot Module Reloading (HMR)”](#scoped-theme-and-hot-module-reloading-hmr)
3229
+
3230
+ When working with `ScopedTheme` in development, you might notice that Hot Module Reloading doesn’t always update the theme when you make changes to child components. This is a limitation of Metro’s Fast Refresh system.
3231
+
3232
+ Unlike Webpack, Metro’s Fast Refresh only re-runs code in the file you’re actively editing and its direct imports. It doesn’t have a global event system that can notify parent components when child modules change.
3233
+
3234
+ Metro provides these HMR functions:
3235
+
3236
+ ```tsx
3237
+ module.hot.accept(fn) // fires if *this* module is updated
3238
+ module.hot.dispose(fn) // fires just before *this* module is replaced
3239
+ ```
3240
+
3241
+ However, **neither of these runs** when other modules change. This means that changes in child components won’t trigger a re-render of their parent `ScopedTheme`:
3242
+
3243
+ ```tsx
3244
+ <ScopedTheme name="light">
3245
+ <ChildComponent /> {/* Changes in this file won't trigger ScopedTheme to update */}
3246
+ </ScopedTheme>
3247
+ ```
3248
+
3249
+ #### Why We Don’t Use React Context
3250
+
3251
+ [Section titled “Why We Don’t Use React Context”](#why-we-dont-use-react-context)
3252
+
3253
+ The “ideal” solution would be to use React Context for theme propagation, which would work seamlessly with HMR. However, we’ve chosen performance over convenience. Using React Context would introduce additional re-renders and overhead that could impact your app’s performance, especially in complex component trees.
3254
+
3255
+ We prioritize keeping the API fast and lightweight, even if it means accepting some development-time limitations with HMR.
3256
+
2979
3257
  # StyleSheet
2980
3258
 
2981
3259
  > Learn about StyleSheet in Unistyles 3.0
@@ -2984,6 +3262,8 @@ const ScopedComponent = () => {
2984
3262
 
2985
3263
  ### create
2986
3264
 
3265
+ [Section titled “create”](#create)
3266
+
2987
3267
  The `create` function supports all styles that React Native’s StyleSheet does, and it also enables some superpowers 🦸🏼‍♂️. It can parse your `variants`, `compoundVariants` or `dynamic functions` (even if you haven’t configured Unistyles yet!).
2988
3268
 
2989
3269
  Once you register your `themes` and `breakpoints`, it unlocks even more features, like injecting the current `theme` or `miniRuntime` into your stylesheet. It also assists you with TypeScript autocompletion for your styles.
@@ -3058,6 +3338,8 @@ Unistyles StyleSheet will automatically react and recalculate your styles if any
3058
3338
 
3059
3339
  #### Static StyleSheet
3060
3340
 
3341
+ [Section titled “Static StyleSheet”](#static-stylesheet)
3342
+
3061
3343
  ```tsx
3062
3344
  import { StyleSheet } from 'react-native-unistyles'
3063
3345
 
@@ -3071,6 +3353,8 @@ const styles = StyleSheet.create({
3071
3353
 
3072
3354
  #### Themable StyleSheet
3073
3355
 
3356
+ [Section titled “Themable StyleSheet”](#themable-stylesheet)
3357
+
3074
3358
  ```tsx
3075
3359
  import { StyleSheet } from 'react-native-unistyles'
3076
3360
 
@@ -3084,6 +3368,8 @@ const styles = StyleSheet.create(theme => ({
3084
3368
 
3085
3369
  #### Themable StyleSheet with `miniRuntime`
3086
3370
 
3371
+ [Section titled “Themable StyleSheet with miniRuntime”](#themable-stylesheet-with-miniruntime)
3372
+
3087
3373
  ```tsx
3088
3374
  import { StyleSheet } from 'react-native-unistyles'
3089
3375
 
@@ -3100,6 +3386,8 @@ Learn more about `miniRuntime` [here](/v3/references/mini-runtime/).
3100
3386
 
3101
3387
  ### configure
3102
3388
 
3389
+ [Section titled “configure”](#configure)
3390
+
3103
3391
  `StyleSheet.configure` is used to configure Unistyles. It accepts an object with the following properties:
3104
3392
 
3105
3393
  * `themes` your apps themes
@@ -3112,8 +3400,48 @@ The `configure` function **must** be called before you import any component that
3112
3400
 
3113
3401
  You can learn more about how to configure Unistyles [here](/v3/start/configuration).
3114
3402
 
3403
+ ### addChangeListener Since v3.1.0
3404
+
3405
+ [Section titled “addChangeListener ”](#addchangelistener)
3406
+
3407
+ `StyleSheet.addChangeListener` is an advanced API for integrations, custom hooks, and animation helpers that need to react to runtime dependency updates.
3408
+
3409
+ For regular styles, you do not need to use it manually. Unistyles already recalculates `StyleSheet.create` output whenever the relevant dependencies change.
3410
+
3411
+ Signature:
3412
+
3413
+ ```ts
3414
+ addChangeListener(
3415
+ onChanged: (dependencies: Array<UnistyleDependency>) => void
3416
+ ): () => void
3417
+ ```
3418
+
3419
+ The callback receives one or more `UnistyleDependency` values describing what changed. The function returns an unsubscribe callback.
3420
+
3421
+ ```tsx
3422
+ import { useEffect } from 'react'
3423
+ import { StyleSheet, UnistyleDependency } from 'react-native-unistyles'
3424
+
3425
+
3426
+ useEffect(() => {
3427
+ const dispose = StyleSheet.addChangeListener((dependencies) => {
3428
+ if (
3429
+ dependencies.includes(UnistyleDependency.Theme) ||
3430
+ dependencies.includes(UnistyleDependency.Breakpoints)
3431
+ ) {
3432
+ // react to theme or breakpoint updates
3433
+ }
3434
+ })
3435
+
3436
+
3437
+ return dispose
3438
+ }, [])
3439
+ ```
3440
+
3115
3441
  ### hairlineWidth
3116
3442
 
3443
+ [Section titled “hairlineWidth”](#hairlinewidth)
3444
+
3117
3445
  `StyleSheet.hairlineWidth` is a static value representing the smallest value that can be drawn on your device. It’s helpful for borders or dividers.
3118
3446
 
3119
3447
  ```tsx
@@ -3130,14 +3458,20 @@ const styles = StyleSheet.create(theme => ({
3130
3458
 
3131
3459
  ### compose
3132
3460
 
3461
+ [Section titled “compose”](#compose)
3462
+
3133
3463
  Maps to React Native’s [compose function](https://reactnative.dev/docs/stylesheet#compose).
3134
3464
 
3135
3465
  ### flatten
3136
3466
 
3467
+ [Section titled “flatten”](#flatten)
3468
+
3137
3469
  Maps to React Native’s [flatten function](https://reactnative.dev/docs/stylesheet#flatten).
3138
3470
 
3139
3471
  ### absoluteFillObject
3140
3472
 
3473
+ [Section titled “absoluteFillObject”](#absolutefillobject)
3474
+
3141
3475
  Returns following object:
3142
3476
 
3143
3477
  ```ts
@@ -3152,6 +3486,8 @@ Returns following object:
3152
3486
 
3153
3487
  ### absoluteFill
3154
3488
 
3489
+ [Section titled “absoluteFill”](#absolutefill)
3490
+
3155
3491
  Returns following object:
3156
3492
 
3157
3493
  ```ts
@@ -3172,6 +3508,8 @@ Unistyles Runtime is a powerful feature that allows you to access platform speci
3172
3508
 
3173
3509
  ### Usage
3174
3510
 
3511
+ [Section titled “Usage”](#usage)
3512
+
3175
3513
  You can import `UnistylesRuntime` from `react-native-unistyles`:
3176
3514
 
3177
3515
  ```tsx
@@ -3182,6 +3520,8 @@ and use it anywhere in your code, even outside a React component.
3182
3520
 
3183
3521
  ### Available getters
3184
3522
 
3523
+ [Section titled “Available getters”](#available-getters)
3524
+
3185
3525
  | Name | Type | Description |
3186
3526
  | ------------------- | ------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
3187
3527
  | colorScheme | string | Get your device’s color scheme. Available options `dark`, `light` or `unspecified` |
@@ -3203,6 +3543,8 @@ and use it anywhere in your code, even outside a React component.
3203
3543
 
3204
3544
  ## Setters
3205
3545
 
3546
+ [Section titled “Setters”](#setters)
3547
+
3206
3548
  | Name | Type | Description |
3207
3549
  | -------------------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
3208
3550
  | setTheme | (themeName: string) => void | Change the current theme |
@@ -3215,12 +3557,16 @@ and use it anywhere in your code, even outside a React component.
3215
3557
 
3216
3558
  ### Why `UnistylesRuntime` doesn’t re-render my component?
3217
3559
 
3560
+ [Section titled “Why UnistylesRuntime doesn’t re-render my component?”](#why-unistylesruntime-doesnt-re-render-my-component)
3561
+
3218
3562
  You should think of `UnistylesRuntime` as a JavaScript object. It’s not a React hook, so it doesn’t re-render your component when eg. screen size or breakpoint changes. Instead it will return up to date value whenever you access it.
3219
3563
 
3220
3564
  If you’re looking for a way to get fresh values and re-render your component, please check [useUnistyles](/v3/references/use-unistyles) hook.
3221
3565
 
3222
3566
  ### How to re-render my stylesheets based on `UnistylesRuntime`?
3223
3567
 
3568
+ [Section titled “How to re-render my stylesheets based on UnistylesRuntime?”](#how-to-re-render-my-stylesheets-based-on-unistylesruntime)
3569
+
3224
3570
  You can do that while accessing [miniRuntime](/v3/references/mini-runtime/) in your `StyleSheet`:
3225
3571
 
3226
3572
  One example could be reading device width and height:
@@ -3259,6 +3605,8 @@ Follow our [decision algorithm](/v3/references/3rd-party-views) to learn when to
3259
3605
 
3260
3606
  ### When to use it?
3261
3607
 
3608
+ [Section titled “When to use it?”](#when-to-use-it)
3609
+
3262
3610
  If you’re using `react-native`, or `react-native-reanimated` components, you should avoid this hook. Unistyles updates these views via the ShadowTree without causing **any re-renders**.
3263
3611
 
3264
3612
  Consider using this hook only if:
@@ -3270,6 +3618,8 @@ Consider using this hook only if:
3270
3618
 
3271
3619
  ### How to use it?
3272
3620
 
3621
+ [Section titled “How to use it?”](#how-to-use-it)
3622
+
3273
3623
  This is a standard hook that exposes `theme` and `rt` ([runtime](/v3/references/mini-runtime)) properties. You can import it from `react-native-unistyles`:
3274
3624
 
3275
3625
  ```tsx
@@ -3311,6 +3661,8 @@ rt.insets // reading this value will automatically subscribe to insets changes
3311
3661
 
3312
3662
  ### Why isn’t it recommended?
3313
3663
 
3664
+ [Section titled “Why isn’t it recommended?”](#why-isnt-it-recommended)
3665
+
3314
3666
  We encourage using `withUnistyles` instead because it ensures only a single component is re-rendered instead of multiple components or the entire app. If you use this hook in a root component, you lose all the benefits of ShadowTree updates and trigger full app re-renders on every change.
3315
3667
 
3316
3668
  Learn more about [How Unistyles works?](/v3/start/how-unistyles-works) to understand why this is not ideal.
@@ -3319,10 +3671,14 @@ Another advantage of `withUnistyles` is that it tracks style dependencies, ensur
3319
3671
 
3320
3672
  ### How to use it correctly?
3321
3673
 
3674
+ [Section titled “How to use it correctly?”](#how-to-use-it-correctly)
3675
+
3322
3676
  If you must use this hook, follow these best practices:
3323
3677
 
3324
3678
  #### 1. Use it only for a single component
3325
3679
 
3680
+ [Section titled “1. Use it only for a single component”](#1-use-it-only-for-a-single-component)
3681
+
3326
3682
  ```tsx
3327
3683
  import { useUnistyles } from 'react-native-unistyles'
3328
3684
  import Icon from 'react-native-cool-icons/MaterialIcons'
@@ -3343,6 +3699,8 @@ Like `withUnistyles`, create a new component and use the hook there. Avoid using
3343
3699
 
3344
3700
  #### 2. Use it with `react-navigation` components like `Stack` or `Tabs`
3345
3701
 
3702
+ [Section titled “2. Use it with react-navigation components like Stack or Tabs”](#2-use-it-with-react-navigation-components-like-stack-or-tabs)
3703
+
3346
3704
  ```tsx
3347
3705
  import { Stack } from 'expo-router'
3348
3706
 
@@ -3369,12 +3727,18 @@ This is allowed because `react-navigation` does not re-render screens on style p
3369
3727
 
3370
3728
  #### 3. Migration from Unistyles 2.0
3371
3729
 
3730
+ [Section titled “3. Migration from Unistyles 2.0”](#3-migration-from-unistyles-20)
3731
+
3372
3732
  If you’re migrating from version 2.0 to 3.0, you can use `useUnistyles` to access the theme and runtime in your components. This works similarly to the `useStyles` hook in 2.0. Once migration is complete, refactor your code to align with Unistyles 3.0 principles.
3373
3733
 
3374
3734
  ### Bad Practices
3375
3735
 
3736
+ [Section titled “Bad Practices”](#bad-practices)
3737
+
3376
3738
  #### 1. Using it with complex components:
3377
3739
 
3740
+ [Section titled “1. Using it with complex components:”](#1-using-it-with-complex-components)
3741
+
3378
3742
  ```tsx
3379
3743
  import { useUnistyles } from 'react-native-unistyles'
3380
3744
  import { Blurhash } from 'react-native-blurhash'
@@ -3404,6 +3768,8 @@ This will re-render multiple components unnecessarily. Instead move `Blurhash` t
3404
3768
 
3405
3769
  #### 2. Using it at the root level:
3406
3770
 
3771
+ [Section titled “2. Using it at the root level:”](#2-using-it-at-the-root-level)
3772
+
3407
3773
  ```tsx
3408
3774
  import { useUnistyles } from 'react-native-unistyles'
3409
3775
 
@@ -3424,6 +3790,8 @@ Using the hook at the root level eliminates all Unistyles benefits, causing your
3424
3790
 
3425
3791
  #### 3. Using it with `react-native` components:
3426
3792
 
3793
+ [Section titled “3. Using it with react-native components:”](#3-using-it-with-react-native-components)
3794
+
3427
3795
  ```tsx
3428
3796
  import { useUnistyles } from 'react-native-unistyles'
3429
3797
  import { Text } from 'react-native'
@@ -3451,6 +3819,8 @@ Variants helps you to create a more flexible and reusable stylesheet eg. for you
3451
3819
 
3452
3820
  ### Basic usage
3453
3821
 
3822
+ [Section titled “Basic usage”](#basic-usage)
3823
+
3454
3824
  Variants are objects that can be nested in any style object:
3455
3825
 
3456
3826
  ```tsx
@@ -3528,6 +3898,8 @@ const styles = StyleSheet.create(theme => ({
3528
3898
 
3529
3899
  ### Selecting variants
3530
3900
 
3901
+ [Section titled “Selecting variants”](#selecting-variants)
3902
+
3531
3903
  With your named groups, you can now select any variant from your stylesheet using the `useVariants`:
3532
3904
 
3533
3905
  ```tsx
@@ -3554,6 +3926,8 @@ TypeScript will provide perfect autocompletion for your variants, ensuring accur
3554
3926
 
3555
3927
  ### Selecting variants with boolean values
3556
3928
 
3929
+ [Section titled “Selecting variants with boolean values”](#selecting-variants-with-boolean-values)
3930
+
3557
3931
  You can also use boolean values to select variants:
3558
3932
 
3559
3933
  ```tsx
@@ -3614,6 +3988,8 @@ Boolean variants respects other rules, eg. `false` is not equal to `default`. To
3614
3988
 
3615
3989
  ### Default variant
3616
3990
 
3991
+ [Section titled “Default variant”](#default-variant)
3992
+
3617
3993
  You can define a `default` variant that will be used when you don’t pass any variant to the `useVariants` hook:
3618
3994
 
3619
3995
  ```tsx
@@ -3639,6 +4015,8 @@ const styles = StyleSheet.create(theme => ({
3639
4015
 
3640
4016
  ### Options to select the variant
3641
4017
 
4018
+ [Section titled “Options to select the variant”](#options-to-select-the-variant)
4019
+
3642
4020
  If you pass `undefined` or `empty object` Unsityles will try to find the `default` variant in your stylesheet:
3643
4021
 
3644
4022
  ```tsx
@@ -3666,6 +4044,8 @@ styles.useVariants({
3666
4044
 
3667
4045
  ### Pass variants as component props
3668
4046
 
4047
+ [Section titled “Pass variants as component props”](#pass-variants-as-component-props)
4048
+
3669
4049
  Variants were designed to be used as component props:
3670
4050
 
3671
4051
  ```tsx
@@ -3694,6 +4074,8 @@ const Component: React.FunctionComponent = ({ color, size }) => {
3694
4074
 
3695
4075
  ### Infer TypeScript type for your variants
3696
4076
 
4077
+ [Section titled “Infer TypeScript type for your variants”](#infer-typescript-type-for-your-variants)
4078
+
3697
4079
  Instead of using `enum` or `strings` with `|` , you can use `UnistylesVariants` to infer the type of your variants:
3698
4080
 
3699
4081
  ```tsx
@@ -3723,6 +4105,8 @@ const styles = ...
3723
4105
 
3724
4106
  ### Defining the same variant across multiple styles
3725
4107
 
4108
+ [Section titled “Defining the same variant across multiple styles”](#defining-the-same-variant-across-multiple-styles)
4109
+
3726
4110
  It’s possible to define the same variant group across multiple styles:
3727
4111
 
3728
4112
  ```tsx
@@ -3862,6 +4246,8 @@ Unistyles comes with some web-only features that are not available with React Na
3862
4246
 
3863
4247
  ### Web only styles
3864
4248
 
4249
+ [Section titled “Web only styles”](#web-only-styles)
4250
+
3865
4251
  In Unistyles, you can use web-specific styles for your web app under the `_web` key.
3866
4252
 
3867
4253
  ```ts
@@ -3899,7 +4285,7 @@ const styles = StyleSheet.create({
3899
4285
 
3900
4286
  The `transform` property on the web should be a string:
3901
4287
 
3902
- ```ts
4288
+ ```diff
3903
4289
  const styles = StyleSheet.create({
3904
4290
  container: {
3905
4291
  flex: 1,
@@ -3914,7 +4300,7 @@ const styles = StyleSheet.create({
3914
4300
 
3915
4301
  If you want to use React Native specific styles on web simply move them to the `style` level:
3916
4302
 
3917
- ```ts
4303
+ ```diff
3918
4304
  const styles = StyleSheet.create({
3919
4305
  container: {
3920
4306
  flex: 1,
@@ -3932,6 +4318,8 @@ You can also use variants, breakpoints, and other Unistyles features under the `
3932
4318
 
3933
4319
  ### Pseudo elements
3934
4320
 
4321
+ [Section titled “Pseudo elements”](#pseudo-elements)
4322
+
3935
4323
  Unistyles also introduces a way to use **any** pseudo-elements and selectors in your web styles.
3936
4324
 
3937
4325
  ```ts
@@ -3954,6 +4342,8 @@ As you can see, `:` and `::` have been replaced with `_` for easier usage.
3954
4342
 
3955
4343
  ### Injecting custom classNames
3956
4344
 
4345
+ [Section titled “Injecting custom classNames”](#injecting-custom-classnames)
4346
+
3957
4347
  If you want to write some part of your app with plain CSS, you can add custom `classNames` to your styles:
3958
4348
 
3959
4349
  ```ts
@@ -3969,7 +4359,7 @@ const styles = StyleSheet.create({
3969
4359
 
3970
4360
  The `_classNames` key under the `_web` key will be injected into the DOM element as a `className`. You can pass a string or an array of strings into it:
3971
4361
 
3972
- ```ts
4362
+ ```diff
3973
4363
  const styles = StyleSheet.create({
3974
4364
  container: {
3975
4365
  flex: 1,
@@ -3996,6 +4386,8 @@ const styles = StyleSheet.create({
3996
4386
 
3997
4387
  ### CSS Variables
3998
4388
 
4389
+ [Section titled “CSS Variables”](#css-variables)
4390
+
3999
4391
  Unistyles 3.0 converts all your themes to CSS variables by default, eliminating heavy JS processing when changing the theme and allowing the CSS engine to take over.
4000
4392
 
4001
4393
  In more detail, it converts all **strings** into CSS variables. For example, if we have the following theme:
@@ -4022,10 +4414,14 @@ After conversion, Unistyles will use CSS variable instead of string to reference
4022
4414
 
4023
4415
  ##### If you’re using `adaptiveThemes`
4024
4416
 
4417
+ [Section titled “If you’re using adaptiveThemes”](#if-youre-using-adaptivethemes)
4418
+
4025
4419
  CSS variables will be placed under the `@media (prefers-color-scheme)` [query](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) ensuring that the app will automatically switch to the new theme.
4026
4420
 
4027
4421
  ##### If you’re not using `adaptiveThemes`
4028
4422
 
4423
+ [Section titled “If you’re not using adaptiveThemes”](#if-youre-not-using-adaptivethemes)
4424
+
4029
4425
  Class of your html root element will be updated to match the new one.
4030
4426
 
4031
4427
  Caution
@@ -4034,8 +4430,12 @@ It’s possible to [disable](/v3/start/configuration#settings-optional) this fea
4034
4430
 
4035
4431
  ### When to disable CSS variables?
4036
4432
 
4433
+ [Section titled “When to disable CSS variables?”](#when-to-disable-css-variables)
4434
+
4037
4435
  ##### When you have different size variables / functions in your themes
4038
4436
 
4437
+ [Section titled “When you have different size variables / functions in your themes”](#when-you-have-different-size-variables--functions-in-your-themes)
4438
+
4039
4439
  ```tsx
4040
4440
  // ❌ Not OK
4041
4441
  const regularTheme = {
@@ -4080,6 +4480,8 @@ const darkTheme = {
4080
4480
 
4081
4481
  ##### When you use conditions to style your components instead of relying on the same theme values
4082
4482
 
4483
+ [Section titled “When you use conditions to style your components instead of relying on the same theme values”](#when-you-use-conditions-to-style-your-components-instead-of-relying-on-the-same-theme-values)
4484
+
4083
4485
  ```tsx
4084
4486
  // ❌ Not OK
4085
4487
  const styles = StyleSheet.create(theme => ({
@@ -4112,6 +4514,8 @@ Unistyles Web is independent from React Native Web, utilizing a custom web parse
4112
4514
 
4113
4515
  ### How It Works
4114
4516
 
4517
+ [Section titled “How It Works”](#how-it-works)
4518
+
4115
4519
  Unistyles web parser generates unique `classNames` for your styles and assigns them to corresponding DOM elements. This ensures that only the necessary styles are applied, avoiding redundancy. Additionally, media queries are automatically created based on your `breakpoints`, eliminating the need for recalculation on every resize.
4116
4520
 
4117
4521
  Example:
@@ -4161,6 +4565,8 @@ Will produce the following CSS output:
4161
4565
 
4162
4566
  ### Updating Styles
4163
4567
 
4568
+ [Section titled “Updating Styles”](#updating-styles)
4569
+
4164
4570
  When you change your app’s theme, Unistyles automatically updates your CSS without triggering any re-renders. This applies to dynamic functions and variants as well.
4165
4571
 
4166
4572
  For instance, if you define your styles dynamically:
@@ -4200,6 +4606,8 @@ The CSS will automatically update to:
4200
4606
 
4201
4607
  ### Limitations
4202
4608
 
4609
+ [Section titled “Limitations”](#limitations)
4610
+
4203
4611
  Due to Unistyles custom parser, styles cannot be accessed directly as they would be with React Native Web. Passing styles to the `RNW` parser would modify them and generate unnecessary new classes.
4204
4612
 
4205
4613
  As a result, when you try to `console.log` the styles, there will be no output:
@@ -4218,6 +4626,8 @@ console.log(styles) // {}
4218
4626
 
4219
4627
  ### Web-Only Features
4220
4628
 
4629
+ [Section titled “Web-Only Features”](#web-only-features)
4630
+
4221
4631
  Unistyles includes some features specific to the web. Learn more about them [here](/v3/references/web-only).
4222
4632
 
4223
4633
  # withUnistyles
@@ -4228,6 +4638,8 @@ Before reading this guide, make sure that you understand [How Unistyles works](/
4228
4638
 
4229
4639
  ### Why do you need it?
4230
4640
 
4641
+ [Section titled “Why do you need it?”](#why-do-you-need-it)
4642
+
4231
4643
  * Unistyles cannot retrieve `ShadowNode` from third-party components because they might not expose a native view via the ref prop
4232
4644
 
4233
4645
  ```ts
@@ -4284,6 +4696,8 @@ Caution
4284
4696
 
4285
4697
  ### Auto mapping for `style` and `contentContainerStyle` props
4286
4698
 
4699
+ [Section titled “Auto mapping for style and contentContainerStyle props”](#auto-mapping-for-style-and-contentcontainerstyle-props)
4700
+
4287
4701
  If your component expects the `style` or `contentContainerStyle` prop, Unistyles will automatically handle the mapping under the hood. You just need to wrap your custom view in `withUnistyles`. We will also respect your style dependencies, so, for example, the `Blurhash` component will only re-render when the theme changes.
4288
4702
 
4289
4703
  ```ts
@@ -4317,6 +4731,8 @@ const styles = StyleSheet.create(theme => ({
4317
4731
 
4318
4732
  ### Mapping custom props to Unistyles styles
4319
4733
 
4734
+ [Section titled “Mapping custom props to Unistyles styles”](#mapping-custom-props-to-unistyles-styles)
4735
+
4320
4736
  If you need to ensure your component updates but it doesn’t use `style` or `contentContainerStyle` props, you can use `mappings`:
4321
4737
 
4322
4738
  ```ts
@@ -4344,6 +4760,8 @@ TypeScript will autocomplete all your props, so there is no need to specify type
4344
4760
 
4345
4761
  ### Custom mappings for external props
4346
4762
 
4763
+ [Section titled “Custom mappings for external props”](#custom-mappings-for-external-props)
4764
+
4347
4765
  Sometimes, you might want to map your props based on a function or value that is only accessible within the component. For example, if you are using `FlashList` and want to modify the `numColumns` prop based on a condition. Using `mappings` in `withUnistyles` is not an option because it doesn’t allow referencing other props.
4348
4766
 
4349
4767
  ```tsx
@@ -4419,6 +4837,8 @@ Components that use `uniProps` are also aware of your dependencies. In the examp
4419
4837
 
4420
4838
  ### Props resolution priority
4421
4839
 
4840
+ [Section titled “Props resolution priority”](#props-resolution-priority)
4841
+
4422
4842
  We will respect your order of prop resolution, applying them with the following priority:
4423
4843
 
4424
4844
  1. Global mappings
@@ -4475,6 +4895,8 @@ Let’s discuss the responsibilities of the Babel plugin:
4475
4895
 
4476
4896
  ### 1. Detecting StyleSheet dependencies
4477
4897
 
4898
+ [Section titled “1. Detecting StyleSheet dependencies”](#1-detecting-stylesheet-dependencies)
4899
+
4478
4900
  Each `StyleSheet` is different. One might rely on a `theme`, another on `miniRuntime`, and so on. The same applies to `styles`. Each style depends on different things. For example, you can wrap your app in a `View` that safeguards your app from rendering behind the notch or navigation bar. Another style might be used in your `Typography` component and provides text color based on the apps’ theme.
4479
4901
 
4480
4902
  Should the `Typography` style re-calculate on an `insets` change? Or should the `View` that relies on insets re-render on a theme change?
@@ -4534,10 +4956,14 @@ We put a lot of effort into making dependency detection as accurate as possible,
4534
4956
 
4535
4957
  ### 2. Attaching unique id to each StyleSheet
4536
4958
 
4959
+ [Section titled “2. Attaching unique id to each StyleSheet”](#2-attaching-unique-id-to-each-stylesheet)
4960
+
4537
4961
  This helps us identify your `StyleSheet` while you’re developing your app and trigger multiple `hot-reloads`. Such identification is required to swap your `StyleSheet` with another one, ensuring that you get up-to-date values during reloads. This feature does not affect your app in production, as the bundle never reloads in that environment.
4538
4962
 
4539
4963
  ### 3. Component factory (borrowing ref)
4540
4964
 
4965
+ [Section titled “3. Component factory (borrowing ref)”](#3-component-factory-borrowing-ref)
4966
+
4541
4967
  This is the most crucial part—without it, Unistyles won’t be able to update your views from C++. In the early versions of Unistyles 3.0, we tried solving this problem by using the `ref` prop, but it wasn’t reliable enough. Many developers use different style syntaxes, making it impossible to support all of them.
4542
4968
 
4543
4969
  Instead, we decided to leave the user’s `ref` as is and transfer the implementation from Babel to our component factory. This way we have more control and we have an unified way of registering your `ShadowNodes`.
@@ -4617,6 +5043,8 @@ import { Image } from 'react-native-unistyles/components/native/Image'
4617
5043
 
4618
5044
  ### 4. Creating scopes for stateless variants
4619
5045
 
5046
+ [Section titled “4. Creating scopes for stateless variants”](#4-creating-scopes-for-stateless-variants)
5047
+
4620
5048
  When you use variants, each time you call `useVariants`, a new scope is created. This scope contains a local copy of stylesheet that won’t affect other components. This feature is similar to time travel, allowing you to explore different states of your styles with different calls to `useVariants`.
4621
5049
 
4622
5050
  From your perspective, using variants is simple: you just need to call the `useVariants` hook:
@@ -4670,6 +5098,8 @@ By leveraging such scopes, we ensure support for any level of nesting!
4670
5098
 
4671
5099
  ### Extra configuration
4672
5100
 
5101
+ [Section titled “Extra configuration”](#extra-configuration)
5102
+
4673
5103
  The Babel plugin comes with a few additional options to extend its usage.
4674
5104
 
4675
5105
  Caution
@@ -4678,6 +5108,8 @@ By default babel plugin will look for any `react-native-unistyles` import to sta
4678
5108
 
4679
5109
  ### `root` (required)
4680
5110
 
5111
+ [Section titled “root (required)”](#root-required)
5112
+
4681
5113
  All files within the specified root folder will be processed by the Babel plugin. If you need to process extra folders, use with `autoProcessPaths` option.
4682
5114
 
4683
5115
  ```js
@@ -4699,6 +5131,8 @@ In that case:
4699
5131
 
4700
5132
  ### `autoProcessImports`
4701
5133
 
5134
+ [Section titled “autoProcessImports”](#autoprocessimports)
5135
+
4702
5136
  This configuration should be used when you want to process files containing specific imports. It can be useful for monorepos that use Unistyles with absolute paths, such as `@codemask/styles`.
4703
5137
 
4704
5138
  ```js
@@ -4709,6 +5143,8 @@ This configuration should be used when you want to process files containing spec
4709
5143
 
4710
5144
  ### `autoRemapImports`
4711
5145
 
5146
+ [Section titled “autoRemapImports”](#autoremapimports)
5147
+
4712
5148
  This is the most powerful option, but most likely, you won’t need to use it. It allows you to remap uncommon imports to Unistyles components.
4713
5149
 
4714
5150
  This may happen if a 3rd library does not import `react-native` components directly, but instead uses its own factory or a relative path. Unistyles uses it internally to support the following imports from `react-native` internals:
@@ -4756,6 +5192,8 @@ If you use raw `react-native` imports within your code, Unistyles will auto map
4756
5192
 
4757
5193
  ### `autoProcessPaths`
4758
5194
 
5195
+ [Section titled “autoProcessPaths”](#autoprocesspaths)
5196
+
4759
5197
  This configuration is unrelated to the `root`, `autoProcessImports`, and `autoRemapImports` options and can be used alongside them. By default, the Babel plugin ignores `node_modules`. However, you can extend these paths to attempt converting 3rd components into Unistyles compatible ones. Within these paths, we will replace `react-native` imports with `react-native-unistyles` factories that borrow component refs. [Read more](/v3/other/babel-plugin#3-component-factory-borrowing-ref).
4760
5198
 
4761
5199
  Defaults to:
@@ -4766,14 +5204,20 @@ Defaults to:
4766
5204
 
4767
5205
  ### `debug`
4768
5206
 
5207
+ [Section titled “debug”](#debug)
5208
+
4769
5209
  In order to list detected dependencies by the Babel plugin you can enable the `debug` flag. It will `console.log` name of the file and component with Unistyles dependencies.
4770
5210
 
4771
5211
  ### Usage with React Compiler
4772
5212
 
5213
+ [Section titled “Usage with React Compiler”](#usage-with-react-compiler)
5214
+
4773
5215
  Check [this guide](/v3/guides/react-compiler) for more details.
4774
5216
 
4775
5217
  #### Usage in `babel.config.js`
4776
5218
 
5219
+ [Section titled “Usage in babel.config.js”](#usage-in-babelconfigjs)
5220
+
4777
5221
  You can apply any of the options above as follows:
4778
5222
 
4779
5223
  babel.config.js
@@ -4810,10 +5254,12 @@ module.exports = function (api) {
4810
5254
 
4811
5255
  > Learn about Unistyles dependencies
4812
5256
 
4813
- Unistyles 3.0 minimizes dependencies to keep your app as lightweight as possible. In the latest version, we’ve opted to include only two essential dependencies that are shaping the future of the React Native ecosystem.
5257
+ Unistyles 3.0 minimizes dependencies to keep your app as lightweight as possible. In the latest version, we’ve opted to include only the essential dependencies that are shaping the future of the React Native ecosystem.
4814
5258
 
4815
5259
  ### Nitro Modules
4816
5260
 
5261
+ [Section titled “Nitro Modules”](#nitro-modules)
5262
+
4817
5263
  Developed by: [Marc Rousavy](https://github.com/mrousavy)
4818
5264
 
4819
5265
  [Nitro modules](https://nitro.margelo.com/) help Unistyles speed up development time by offering remarkable solutions:
@@ -4826,15 +5272,29 @@ Developed by: [Marc Rousavy](https://github.com/mrousavy)
4826
5272
 
4827
5273
  We highly encourage you to give Nitro a star ⭐ or support Marc through sponsorship.
4828
5274
 
4829
- ### React Native Edge to Edge
5275
+ ### React Native Edge to Edge (optional since v3.1.0)
5276
+
5277
+ [Section titled “React Native Edge to Edge (optional since v3.1.0)”](#react-native-edge-to-edge-optional-since-v310)
4830
5278
 
4831
5279
  Developed by: [Mathieu Acthernoene](https://github.com/zoontek)
4832
5280
 
4833
- [React Native Edge to Edge](https://github.com/zoontek/react-native-edge-to-edge) is a library aimed at unifying the handling of edge-to-edge layouts on Android. We fully support this initiative and have made it a dependency for Unistyles.
5281
+ [React Native Edge to Edge](https://github.com/zoontek/react-native-edge-to-edge) is a library aimed at unifying the handling of edge-to-edge layouts on Android.
5282
+
5283
+ Since v3.1.0, `react-native-edge-to-edge` is **optional** as a direct dependency. Unistyles enables edge-to-edge layout automatically on Android if `react-native-edge-to-edge` is not installed.
4834
5284
 
4835
- You likely won’t notice any changes, as Unistyles has enforced edge-to-edge layouts since version 2.8.0. However, other libraries that detect `react-native-edge-to-edge` can now reliably assume that this mode is enabled. Additionally, Mathieu’s initiative is supported by [Expo](https://docs.expo.dev/), which suggests it may become a standard in the future.
5285
+ However, we **strongly recommend** enabling `edgeToEdgeEnabled` in your `gradle.properties`:
4836
5286
 
4837
- If you use any of Mathieu’s libraries, such as `react-native-permissions` or `react-native-bootsplash`, we encourage you to give them a star ⭐ and support him through sponsorship.
5287
+ android/gradle.properties
5288
+
5289
+ ```properties
5290
+ edgeToEdgeEnabled=true
5291
+ ```
5292
+
5293
+ This property does more than just enabling edge-to-edge layout — it enforces `statusBarTranslucent` / `navigationBarTranslucent` on modals, disables `backgroundColor` / `translucent` on `StatusBar`, and enables additional fixes in React Native core. **Expo SDK 54+** enables this automatically.
5294
+
5295
+ You can still install `react-native-edge-to-edge` alongside this property if you use libraries that detect it for ecosystem-wide edge-to-edge detection (e.g. `react-native-bootsplash`, `react-native-permissions`).
5296
+
5297
+ If you use any of Mathieu’s libraries, we encourage you to give them a star ⭐ and support him through sponsorship.
4838
5298
 
4839
5299
  # For library authors
4840
5300
 
@@ -4844,6 +5304,8 @@ Unistyles is highly extensible and can be used to build UI kits and various othe
4844
5304
 
4845
5305
  ## Using Unistyles in your library
4846
5306
 
5307
+ [Section titled “Using Unistyles in your library”](#using-unistyles-in-your-library)
5308
+
4847
5309
  `StyleSheet.configure` **must** be invoked as soon as possible, before any user code references any `StyleSheet` from your library.
4848
5310
 
4849
5311
  You can then call `StyleSheet.configure` multiple times to override configurations. However, keep in mind that `StyleSheet.configure` makes a roundtrip to C++, which can add a few `ms` to your app’s startup time.
@@ -4852,14 +5314,20 @@ To manipulate your config without replacing it, use [UnistylesRuntime](/v3/refer
4852
5314
 
4853
5315
  ## Unistyles never re-renders
4854
5316
 
5317
+ [Section titled “Unistyles never re-renders”](#unistyles-never-re-renders)
5318
+
4855
5319
  Unistyles’ C++ core ensures that your components never re-render. Instead, they are updated directly from C++ and `Shadow Tree`.
4856
5320
 
4857
5321
  ## No React Context - no additional setup
4858
5322
 
5323
+ [Section titled “No React Context - no additional setup”](#no-react-context---no-additional-setup)
5324
+
4859
5325
  Unistyles does not use the React Context API. This means that users do not need to wrap their app with a `Provider`, reducing boilerplate code and making your library more user-friendly.
4860
5326
 
4861
5327
  ## New architecture only
4862
5328
 
5329
+ [Section titled “New architecture only”](#new-architecture-only)
5330
+
4863
5331
  Unistyles won’t re-render your components unless you want to. While it requires enabling the New Architecture, we believe this trade-off is worthwhile, as more apps are expected to transition to the New Architecture in the coming months.
4864
5332
 
4865
5333
  Note
@@ -4868,6 +5336,8 @@ As of June 2nd, 2025, Old Architecture is [frozen](https://github.com/reactwg/re
4868
5336
 
4869
5337
  ## Minimum requirements
4870
5338
 
5339
+ [Section titled “Minimum requirements”](#minimum-requirements)
5340
+
4871
5341
  Unistyles is compatible with:
4872
5342
 
4873
5343
  * React Native version >= 0.78
@@ -4877,16 +5347,22 @@ Unistyles is compatible with:
4877
5347
 
4878
5348
  ## Out of the box support for Web
4879
5349
 
5350
+ [Section titled “Out of the box support for Web”](#out-of-the-box-support-for-web)
5351
+
4880
5352
  Building a UI kit for both React Native and Web couldn’t be easier. Unistyles automatically manages your styles and converts them into CSS classes.
4881
5353
 
4882
5354
  ## Babel config
4883
5355
 
5356
+ [Section titled “Babel config”](#babel-config)
5357
+
4884
5358
  Make sure to instruct your users to add [autoProcessPaths](/v3/other/babel-plugin#extra-configuration) babel option. It will whitelist your `ui-kit` and process your files even though there are in `node_modules` folder.
4885
5359
 
4886
5360
  You can also consider publishing your UI kit with babel transforms in place. Keep in mind that it could break [testing](/v3/start/testing) views with your components.
4887
5361
 
4888
5362
  ## Why to choose Unistyles?
4889
5363
 
5364
+ [Section titled “Why to choose Unistyles?”](#why-to-choose-unistyles)
5365
+
4890
5366
  Unistyles offers a unique architecture unavailable in any other library. Fully compatible with the React Native StyleSheet API, it is easy to use and extend.
4891
5367
 
4892
5368
  By avoiding component abstraction, Unistyles gives you the freedom to create your own. It supports various platforms and is designed to be easily extendable.
@@ -4909,22 +5385,30 @@ We’re so exited about Unistyles 3.0 core and can’t wait for the new possibil
4909
5385
 
4910
5386
  ### Why sponsor Unistyles?
4911
5387
 
5388
+ [Section titled “Why sponsor Unistyles?”](#why-sponsor-unistyles)
5389
+
4912
5390
  * **Advancing Innovation**: Your sponsorship helps in the continuous innovation and improvement of Unistyles. This support is crucial for developing new features and maintaining the library
4913
5391
  * **Benefit for Developers and Companies**: Both individual developers and large companies that profit from using Unistyles stand to gain from its enhancements. Your support ensures that Unistyles remains a cutting-edge tool in your development arsenal
4914
5392
  * **Limited Free Time Challenge**: The development of innovative libraries like Unistyles is often constrained by the limited free time of creators. Sponsorship can provide the necessary resources for dedicated development time
4915
5393
 
4916
5394
  ### How to sponsor?
4917
5395
 
5396
+ [Section titled “How to sponsor?”](#how-to-sponsor)
5397
+
4918
5398
  * **Github Sponsorship**: [link](https://github.com/sponsors/jpudysz)
4919
5399
  * **Ko-Fi**: [link](https://ko-fi.com/jpudysz)
4920
5400
 
4921
5401
  ### Free options
4922
5402
 
5403
+ [Section titled “Free options”](#free-options)
5404
+
4923
5405
  * **Sharing Unistyles**: A free yet impactful way to support us is by sharing information about Unistyles within your network. Spreading the word helps increase our visibility and user base
4924
5406
  * **Shoutout**: Give us a shoutout on X or Reddit. Public endorsements and mentions can significantly boost our project’s presence and reach
4925
5407
 
4926
5408
  ### Other options
4927
5409
 
5410
+ [Section titled “Other options”](#other-options)
5411
+
4928
5412
  Hire Codemask team
4929
5413
 
4930
5414
  If you’re looking to hire a skilled React Native team, Codemask is open for collaboration. We offer expertise and quality in building React Native applications.
@@ -4943,22 +5427,32 @@ As a Codemask CTO I’m open to share my knowledge and expertise in the React Na
4943
5427
 
4944
5428
  ### Can I run Unistyles on Expo Go?
4945
5429
 
5430
+ [Section titled “Can I run Unistyles on Expo Go?”](#can-i-run-unistyles-on-expo-go)
5431
+
4946
5432
  No, Unistyles includes custom native code, which means it does not support Expo Go.
4947
5433
 
4948
5434
  ### What happened to `macOS`, `windows`, `visionOS`, `tvOS` support?
4949
5435
 
5436
+ [Section titled “What happened to macOS, windows, visionOS, tvOS support?”](#what-happened-to-macos-windows-visionos-tvos-support)
5437
+
4950
5438
  For now they’re not available. We’re seeking sponsors to help us add support, as they are rarely used by our customers.
4951
5439
 
4952
5440
  ### Can I run Unistyles on `Old Architecture`?
4953
5441
 
5442
+ [Section titled “Can I run Unistyles on Old Architecture?”](#can-i-run-unistyles-on-old-architecture)
5443
+
4954
5444
  No, Unistyles is tightly integrated with `Fabric`. There are no plans to support `Old Architecture`.
4955
5445
 
4956
5446
  ### We are not ready to upgrade. What will happen with version `2.0`?
4957
5447
 
5448
+ [Section titled “We are not ready to upgrade. What will happen with version 2.0?”](#we-are-not-ready-to-upgrade-what-will-happen-with-version-20)
5449
+
4958
5450
  We understand that some apps require more time to migrate to the `New Architecture`. We plan to support Unistyles 2.0 for a few more months or stable React Native versions.
4959
5451
 
4960
5452
  ### Adaptive mode doesn’t work for me
4961
5453
 
5454
+ [Section titled “Adaptive mode doesn’t work for me”](#adaptive-mode-doesnt-work-for-me)
5455
+
4962
5456
  To enable adaptive mode, you need to register two themes named `light` and `dark` and set the `adaptiveThemes` flag to true within `StyleSheet.configure`.
4963
5457
 
4964
5458
  If your app still doesn’t automatically switch themes, ensure that:
@@ -4971,6 +5465,8 @@ If your app still doesn’t automatically switch themes, ensure that:
4971
5465
 
4972
5466
  ### ld.lld: error: Undefined symbols margelo::nitro::\*
4973
5467
 
5468
+ [Section titled “ld.lld: error: Undefined symbols margelo::nitro::\*”](#ldlld-error-undefined-symbols-margelonitro)
5469
+
4974
5470
  This error occurs due to the strong caching mechanism in Android Studio. The cache can even survive the `expo prebuild --clean` command in Expo projects.
4975
5471
 
4976
5472
  To clean the cache, please follow these steps:
@@ -5010,24 +5506,26 @@ After cleaning up, your components folder should look like this:
5010
5506
 
5011
5507
  ### ThemedText
5012
5508
 
5509
+ [Section titled “ThemedText”](#themedtext)
5510
+
5013
5511
  The default `ThemedText` component is a perfect candidate for a Unistyles refactor. It contains conditional style logic directly in the JSX - a pattern we can significantly improve.
5014
5512
 
5015
5513
  First, let’s swap the `StyleSheet` import and remove unnecessary `useThemeColor` hook.
5016
5514
 
5017
5515
  components/ThemedText.tsx
5018
5516
 
5019
- ```tsx
5020
- import { StyleSheet, Text, type TextProps } from 'react-native';
5021
- import { Text, type TextProps } from 'react-native';
5022
- import { StyleSheet } from 'react-native-unistyles';
5023
- import { useThemeColor } from '@/hooks/useThemeColor';
5517
+ ```diff
5518
+ -import { StyleSheet, Text, type TextProps } from 'react-native';
5519
+ +import { Text, type TextProps } from 'react-native';
5520
+ +import { StyleSheet } from 'react-native-unistyles';
5521
+ -import { useThemeColor } from '@/hooks/useThemeColor';
5024
5522
  ```
5025
5523
 
5026
5524
  The original component used the `useThemeColor` hook to get a color based on the current theme. We’ll replace this imperative logic with a dynamic function in our stylesheet. A dynamic function is a Unistyles feature that allows a style to accept arguments. Let’s create one called `textColor` to handle the `lightColor` and `darkColor` props.
5027
5525
 
5028
5526
  components/ThemedText.tsx
5029
5527
 
5030
- ```tsx
5528
+ ```diff
5031
5529
  export function ThemedText({
5032
5530
  style,
5033
5531
  lightColor,
@@ -5035,14 +5533,14 @@ export function ThemedText({
5035
5533
  type = 'default',
5036
5534
  ...rest
5037
5535
  }: ThemedTextProps) {
5038
- const color = useThemeColor({ light: lightColor, dark: darkColor });
5536
+ -const color = useThemeColor({ light: lightColor, dark: darkColor });
5039
5537
 
5040
5538
 
5041
5539
  return (
5042
5540
  <Text
5043
5541
  style={[
5044
- { color },
5045
- styles.textColor(lightColor, darkColor),
5542
+ - { color },
5543
+ + styles.textColor(lightColor, darkColor),
5046
5544
  type === 'default' ? styles.default : undefined,
5047
5545
  type === 'title' ? styles.title : undefined,
5048
5546
  type === 'defaultSemiBold' ? styles.defaultSemiBold : undefined,
@@ -5061,9 +5559,9 @@ const styles = StyleSheet.create({
5061
5559
  fontSize: 16,
5062
5560
  lineHeight: 24,
5063
5561
  },
5064
- textColor: (lightColor?: string, darkColor?: string) => ({
5065
- // todo
5066
- }),
5562
+ +textColor: (lightColor?: string, darkColor?: string) => ({
5563
+ +// todo
5564
+ +}),
5067
5565
  defaultSemiBold: {
5068
5566
  fontSize: 16,
5069
5567
  lineHeight: 24,
@@ -5104,7 +5602,7 @@ Let’s complete our dynamic function:
5104
5602
 
5105
5603
  components/ThemedText.tsx
5106
5604
 
5107
- ```tsx
5605
+ ```diff
5108
5606
  export function ThemedText({
5109
5607
  style,
5110
5608
  lightColor,
@@ -5129,14 +5627,14 @@ export function ThemedText({
5129
5627
  }
5130
5628
 
5131
5629
 
5132
- const styles = StyleSheet.create({
5630
+ -const styles = StyleSheet.create({
5133
5631
  const styles = StyleSheet.create((theme, rt) => ({
5134
5632
  default: {
5135
5633
  fontSize: 16,
5136
5634
  lineHeight: 24,
5137
5635
  },
5138
5636
  textColor: (lightColor: string, darkColor: string) => ({
5139
- // todo
5637
+ -// todo
5140
5638
  color: rt.colorScheme === 'dark' ? darkColor : lightColor,
5141
5639
  }),
5142
5640
  defaultSemiBold: {
@@ -5158,7 +5656,7 @@ export function ThemedText({
5158
5656
  fontSize: 16,
5159
5657
  color: '#0a7ea4',
5160
5658
  },
5161
- })
5659
+ -})
5162
5660
  }));
5163
5661
  ```
5164
5662
 
@@ -5166,7 +5664,7 @@ Next, let’s tackle the chain of conditional checks for the type prop. This is
5166
5664
 
5167
5665
  components/ThemedText.tsx
5168
5666
 
5169
- ```tsx
5667
+ ```diff
5170
5668
  export function ThemedText({
5171
5669
  style,
5172
5670
  lightColor,
@@ -5178,11 +5676,11 @@ export function ThemedText({
5178
5676
  <Text
5179
5677
  style={[
5180
5678
  styles.textColor(lightColor, darkColor),
5181
- type === 'default' ? styles.default : undefined,
5182
- type === 'title' ? styles.title : undefined,
5183
- type === 'defaultSemiBold' ? styles.defaultSemiBold : undefined,
5184
- type === 'subtitle' ? styles.subtitle : undefined,
5185
- type === 'link' ? styles.link : undefined,
5679
+ - type === 'default' ? styles.default : undefined,
5680
+ - type === 'title' ? styles.title : undefined,
5681
+ - type === 'defaultSemiBold' ? styles.defaultSemiBold : undefined,
5682
+ - type === 'subtitle' ? styles.subtitle : undefined,
5683
+ - type === 'link' ? styles.link : undefined,
5186
5684
  style,
5187
5685
  ]}
5188
5686
  {...rest}
@@ -5195,7 +5693,7 @@ const styles = StyleSheet.create((theme, rt) => ({
5195
5693
  default: {
5196
5694
  fontSize: 16,
5197
5695
  lineHeight: 24,
5198
- },
5696
+ -},
5199
5697
  textColor: (lightColor?: string, darkColor?: string) => ({
5200
5698
  color: rt.colorScheme === 'dark' ? darkColor : lightColor,
5201
5699
  }),
@@ -5203,27 +5701,27 @@ const styles = StyleSheet.create((theme, rt) => ({
5203
5701
  fontSize: 16,
5204
5702
  lineHeight: 24,
5205
5703
  fontWeight: '600',
5206
- },
5704
+ -},
5207
5705
  title: {
5208
5706
  fontSize: 32,
5209
5707
  fontWeight: 'bold',
5210
5708
  lineHeight: 32,
5211
- },
5709
+ -},
5212
5710
  subtitle: {
5213
5711
  fontSize: 20,
5214
5712
  fontWeight: 'bold',
5215
- },
5713
+ -},
5216
5714
  link: {
5217
5715
  lineHeight: 30,
5218
5716
  fontSize: 16,
5219
5717
  color: '#0a7ea4',
5220
- },
5718
+ -},
5221
5719
  }));
5222
5720
  ```
5223
5721
 
5224
5722
  components/ThemedText.tsx
5225
5723
 
5226
- ```tsx
5724
+ ```diff
5227
5725
  export function ThemedText({
5228
5726
  style,
5229
5727
  lightColor,
@@ -5231,14 +5729,14 @@ export function ThemedText({
5231
5729
  type = 'default',
5232
5730
  ...rest
5233
5731
  }: ThemedTextProps) {
5234
- styles.useVariants({ type })
5732
+ + styles.useVariants({ type })
5235
5733
 
5236
5734
 
5237
5735
  return (
5238
5736
  <Text
5239
5737
  style={[
5240
5738
  styles.textColor(lightColor, darkColor),
5241
- styles.textType,
5739
+ + styles.textType,
5242
5740
  style,
5243
5741
  ]}
5244
5742
  {...rest}
@@ -5254,29 +5752,29 @@ const styles = StyleSheet.create((theme, rt) => ({
5254
5752
  default: {
5255
5753
  fontSize: 16,
5256
5754
  lineHeight: 24,
5257
- },
5755
+ +},
5258
5756
  defaultSemiBold: {
5259
5757
  fontSize: 16,
5260
5758
  lineHeight: 24,
5261
5759
  fontWeight: '600',
5262
- },
5760
+ +},
5263
5761
  title: {
5264
5762
  fontSize: 32,
5265
5763
  fontWeight: 'bold',
5266
5764
  lineHeight: 32,
5267
- },
5765
+ +},
5268
5766
  subtitle: {
5269
5767
  fontSize: 20,
5270
5768
  fontWeight: 'bold',
5271
- },
5769
+ +},
5272
5770
  link: {
5273
5771
  lineHeight: 30,
5274
5772
  fontSize: 16,
5275
5773
  color: '#0a7ea4',
5276
- },
5277
- }
5278
- }
5279
- },
5774
+ +},
5775
+ +}
5776
+ +}
5777
+ +},
5280
5778
  textColor: (lightColor?: string, darkColor?: string) => ({
5281
5779
  color: rt.colorScheme === 'dark' ? darkColor : lightColor,
5282
5780
  }),
@@ -5303,16 +5801,16 @@ Instead of specifying `type` prop manually, we can use `UnistylesVariants` gener
5303
5801
 
5304
5802
  components/ThemedText.tsx
5305
5803
 
5306
- ```tsx
5307
- import { StyleSheet } from 'react-native-unistyles';
5308
- import { StyleSheet, type UnistylesVariants } from 'react-native-unistyles';
5804
+ ```diff
5805
+ -import { StyleSheet } from 'react-native-unistyles';
5806
+ +import { StyleSheet, type UnistylesVariants } from 'react-native-unistyles';
5309
5807
 
5310
5808
 
5311
- export type ThemedTextProps = TextProps & {
5312
- export type ThemedTextProps = TextProps & UnistylesVariants<typeof styles> & {
5809
+ -export type ThemedTextProps = TextProps & {
5810
+ +export type ThemedTextProps = TextProps & UnistylesVariants<typeof styles> & {
5313
5811
  lightColor?: string;
5314
5812
  darkColor?: string;
5315
- type?: 'default' | 'title' | 'defaultSemiBold' | 'subtitle' | 'link';
5813
+ - type?: 'default' | 'title' | 'defaultSemiBold' | 'subtitle' | 'link';
5316
5814
  };
5317
5815
 
5318
5816
 
@@ -5320,8 +5818,8 @@ export function ThemedText({
5320
5818
  style,
5321
5819
  lightColor,
5322
5820
  darkColor,
5323
- type = 'default',
5324
- type,
5821
+ -type = 'default',
5822
+ +type,
5325
5823
  ...rest
5326
5824
  }: ThemedTextProps) {
5327
5825
  ```
@@ -5332,29 +5830,29 @@ Let’s remove those props and use the theme object directly.
5332
5830
 
5333
5831
  components/ThemedText.tsx
5334
5832
 
5335
- ```tsx
5833
+ ```diff
5336
5834
  import { Text, type TextProps } from 'react-native';
5337
5835
  import { StyleSheet, type UnistylesVariants } from 'react-native-unistyles';
5338
5836
 
5339
5837
 
5340
- export type ThemedTextProps = TextProps & UnistylesVariants<typeof styles>
5341
- export type ThemedTextProps = TextProps & UnistylesVariants<typeof styles> & {
5342
- lightColor?: string;
5343
- darkColor?: string;
5344
- };
5838
+ +export type ThemedTextProps = TextProps & UnistylesVariants<typeof styles>
5839
+ -export type ThemedTextProps = TextProps & UnistylesVariants<typeof styles> & {
5840
+ - lightColor?: string;
5841
+ - darkColor?: string;
5842
+ - };
5345
5843
 
5346
5844
 
5347
5845
  export function ThemedText({
5348
5846
  style,
5349
- lightColor,
5350
- darkColor,
5847
+ -lightColor,
5848
+ -darkColor,
5351
5849
  ...rest
5352
5850
  }: ThemedTextProps) {
5353
5851
  return (
5354
5852
  <Text
5355
5853
  style={[
5356
- styles.textColor(lightColor, darkColor),
5357
- styles.textColor,
5854
+ - styles.textColor(lightColor, darkColor),
5855
+ + styles.textColor,
5358
5856
  styles.textType,
5359
5857
  style,
5360
5858
  ]}
@@ -5364,14 +5862,14 @@ export function ThemedText({
5364
5862
  }
5365
5863
 
5366
5864
 
5367
- const styles = StyleSheet.create(theme => ({
5865
+ +const styles = StyleSheet.create(theme => ({
5368
5866
  const styles = StyleSheet.create((theme, rt) => ({
5369
- textColor: (lightColor?: string, darkColor?: string) => ({
5867
+ -textColor: (lightColor?: string, darkColor?: string) => ({
5370
5868
  color: rt.colorScheme === 'dark' ? darkColor : lightColor,
5371
- }),
5869
+ -}),
5372
5870
  textColor: {
5373
5871
  color: theme.colors.typography
5374
- },
5872
+ +},
5375
5873
  textType: {
5376
5874
  variants: {
5377
5875
  type: {
@@ -5414,6 +5912,8 @@ Curious to learn more about variants? Check out the [variants guide](/v3/referen
5414
5912
 
5415
5913
  ### ThemedView - your turn!
5416
5914
 
5915
+ [Section titled “ThemedView - your turn!”](#themedview---your-turn)
5916
+
5417
5917
  Now is the time to refactor the `ThemedView` component. This one is much simpler. Based on what you’ve learned, try refactoring it yourself to use the `theme.colors.background` property.
5418
5918
 
5419
5919
  Once you’re done, check your work against the solution below:
@@ -5442,6 +5942,8 @@ const styles = StyleSheet.create(theme => ({
5442
5942
 
5443
5943
  ### Constants and hooks
5444
5944
 
5945
+ [Section titled “Constants and hooks”](#constants-and-hooks)
5946
+
5445
5947
  Lastly, we can remove the `constants` and `hooks` folders, as they are now redundant. Your final project structure should be clean and organized.
5446
5948
 
5447
5949
  * app/
@@ -5497,6 +5999,8 @@ Before we start building our own features, let’s adapt the default Expo Router
5497
5999
 
5498
6000
  ### App folder
5499
6001
 
6002
+ [Section titled “App folder”](#app-folder)
6003
+
5500
6004
  Let’s start with the root layout file for the entire application.
5501
6005
 
5502
6006
  * app/
@@ -5515,20 +6019,20 @@ Let’s remove the old theming logic:
5515
6019
 
5516
6020
  app/\_layout.tsx
5517
6021
 
5518
- ```tsx
5519
- import React from 'react';
5520
- import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native';
6022
+ ```diff
6023
+ +import React from 'react';
6024
+ -import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native';
5521
6025
  import { useFonts } from 'expo-font';
5522
6026
  import { Stack } from 'expo-router';
5523
6027
  import { StatusBar } from 'expo-status-bar';
5524
6028
  import 'react-native-reanimated';
5525
6029
 
5526
6030
 
5527
- import { useColorScheme } from '@/hooks/useColorScheme';
6031
+ -import { useColorScheme } from '@/hooks/useColorScheme';
5528
6032
 
5529
6033
 
5530
6034
  export default function RootLayout() {
5531
- const colorScheme = useColorScheme();
6035
+ -const colorScheme = useColorScheme();
5532
6036
  const [loaded] = useFonts({
5533
6037
  SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'),
5534
6038
  });
@@ -5541,15 +6045,15 @@ export default function RootLayout() {
5541
6045
 
5542
6046
 
5543
6047
  return (
5544
- <React.Fragment>
5545
- <ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
6048
+ +<React.Fragment>
6049
+ -<ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
5546
6050
  <Stack>
5547
6051
  <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
5548
6052
  <Stack.Screen name="+not-found" />
5549
6053
  </Stack>
5550
6054
  <StatusBar style="auto" />
5551
- </ThemeProvider>
5552
- </React.Fragment>
6055
+ -</ThemeProvider>
6056
+ +</React.Fragment>
5553
6057
  );
5554
6058
  }
5555
6059
  ```
@@ -5558,20 +6062,22 @@ Next, for the `+not_found.tsx` file, we only need to swap the `StyleSheet` impor
5558
6062
 
5559
6063
  app/+not\_found.tsx
5560
6064
 
5561
- ```tsx
5562
- import { StyleSheet } from 'react-native-unistyles';
5563
- import { StyleSheet } from 'react-native';
6065
+ ```diff
6066
+ +import { StyleSheet } from 'react-native-unistyles';
6067
+ -import { StyleSheet } from 'react-native';
5564
6068
  ```
5565
6069
 
5566
6070
  ### (tabs) folder
5567
6071
 
6072
+ [Section titled “(tabs) folder”](#tabs-folder)
6073
+
5568
6074
  This folder contains the layout and screens for your `TabsNavigator`. For the `index.tsx` and `explore.tsx` files, the process is the same: we simply need to replace the standard `StyleSheet` import with the one from Unistyles.
5569
6075
 
5570
6076
  app/(tabs)/index.tsx
5571
6077
 
5572
- ```tsx
5573
- import { Platform, StyleSheet } from 'react-native';
5574
- import { StyleSheet } from 'react-native-unistyles';
6078
+ ```diff
6079
+ -import { Platform, StyleSheet } from 'react-native';
6080
+ +import { StyleSheet } from 'react-native-unistyles';
5575
6081
  ```
5576
6082
 
5577
6083
  For the JSX, we won’t need all these boilerplate components, so we can keep it as simple as possible:
@@ -5656,47 +6162,47 @@ Let’s refactor tab layout to use our new theme:
5656
6162
 
5657
6163
  app/(tabs)/\_layout.tsx
5658
6164
 
5659
- ```tsx
6165
+ ```diff
5660
6166
  import { Tabs } from 'expo-router';
5661
6167
  import React from 'react';
5662
- import { Platform } from 'react-native';
6168
+ -import { Platform } from 'react-native';
5663
6169
 
5664
6170
 
5665
- import { HapticTab } from '@/components/HapticTab';
6171
+ -import { HapticTab } from '@/components/HapticTab';
5666
6172
  import { IconSymbol } from '@/components/ui/IconSymbol';
5667
- import TabBarBackground from '@/components/ui/TabBarBackground';
5668
- import { Colors } from '@/constants/Colors';
5669
- import { useColorScheme } from '@/hooks/useColorScheme';
5670
- import { useUnistyles } from 'react-native-unistyles';
6173
+ -import TabBarBackground from '@/components/ui/TabBarBackground';
6174
+ -import { Colors } from '@/constants/Colors';
6175
+ -import { useColorScheme } from '@/hooks/useColorScheme';
6176
+ +import { useUnistyles } from 'react-native-unistyles';
5671
6177
 
5672
6178
 
5673
6179
  export default function TabLayout() {
5674
- const colorScheme = useColorScheme();
5675
- const { theme } = useUnistyles();
6180
+ -const colorScheme = useColorScheme();
6181
+ +const { theme } = useUnistyles();
5676
6182
 
5677
6183
 
5678
6184
  return (
5679
6185
  <Tabs
5680
6186
  screenOptions={{
5681
- tabBarActiveTintColor: Colors[colorScheme ?? 'light'].tint,
5682
- tabBarInactiveTintColor: theme.colors.tint,
5683
- tabBarActiveTintColor: theme.colors.activeTint,
5684
- sceneStyle: {
5685
- backgroundColor: theme.colors.background
5686
- },
5687
- tabBarStyle: {
5688
- backgroundColor: theme.colors.foreground
5689
- },
6187
+ - tabBarActiveTintColor: Colors[colorScheme ?? 'light'].tint,
6188
+ + tabBarInactiveTintColor: theme.colors.tint,
6189
+ + tabBarActiveTintColor: theme.colors.activeTint,
6190
+ + sceneStyle: {
6191
+ + backgroundColor: theme.colors.background
6192
+ + },
6193
+ + tabBarStyle: {
6194
+ + backgroundColor: theme.colors.foreground
6195
+ + },
5690
6196
  headerShown: false,
5691
- tabBarButton: HapticTab,
5692
- tabBarBackground: TabBarBackground,
5693
- tabBarStyle: Platform.select({
5694
- ios: {
5695
- // Use a transparent background on iOS to show the blur effect
5696
- position: 'absolute',
5697
- },
5698
- default: {},
5699
- }),
6197
+ - tabBarButton: HapticTab,
6198
+ - tabBarBackground: TabBarBackground,
6199
+ - tabBarStyle: Platform.select({
6200
+ - ios: {
6201
+ -// Use a transparent background on iOS to show the blur effect
6202
+ - position: 'absolute',
6203
+ - },
6204
+ - default: {},
6205
+ - }),
5700
6206
  }}>
5701
6207
  <Tabs.Screen
5702
6208
  name="index"
@@ -5739,6 +6245,8 @@ In this final part, we’ll connect all the pieces together using a lightweight
5739
6245
 
5740
6246
  ### Adding State Management with StanJS
5741
6247
 
6248
+ [Section titled “Adding State Management with StanJS”](#adding-state-management-with-stanjs)
6249
+
5742
6250
  For managing the user’s accent preference across our app, we need a state management solution that’s both lightweight and efficient. After considering various options, we decided to use our in-house library called StanJS.
5743
6251
 
5744
6252
  Note
@@ -5749,6 +6257,8 @@ StanJS automatically generates setters for your state values and provides excell
5749
6257
 
5750
6258
  ### Installation and Setup
5751
6259
 
6260
+ [Section titled “Installation and Setup”](#installation-and-setup)
6261
+
5752
6262
  Let’s install StanJS along with MMKV for data persistence:
5753
6263
 
5754
6264
  ```bash
@@ -5765,6 +6275,8 @@ StanJS has built-in MMKV support that makes data persistence effortless.
5765
6275
 
5766
6276
  #### Create the Store
5767
6277
 
6278
+ [Section titled “Create the Store”](#create-the-store)
6279
+
5768
6280
  First, let’s set up our store to manage the user’s preferred accent color:
5769
6281
 
5770
6282
  store/store.ts
@@ -5786,11 +6298,11 @@ Before we can use our store, we need to create the `Accents` type. Let’s add i
5786
6298
 
5787
6299
  unistyles.ts
5788
6300
 
5789
- ```tsx
6301
+ ```diff
5790
6302
  // ... existing imports and theme definitions
5791
6303
 
5792
6304
 
5793
- export type Accents = keyof typeof lightTheme['colors']['accents']
6305
+ +export type Accents = keyof typeof lightTheme['colors']['accents']
5794
6306
 
5795
6307
 
5796
6308
  type AppBreakpoints = typeof breakpoints
@@ -5818,16 +6330,18 @@ export * from './store'
5818
6330
 
5819
6331
  ### Connecting the Accent Settings
5820
6332
 
6333
+ [Section titled “Connecting the Accent Settings”](#connecting-the-accent-settings)
6334
+
5821
6335
  Now we need to update our accent settings screen to actually save the user’s choice to our store. Currently, it only updates local state that gets lost when the user navigates away.
5822
6336
 
5823
6337
  Let’s update the settings screen to use our StanJS store:
5824
6338
 
5825
6339
  app/settings/settings-accent.tsx
5826
6340
 
5827
- ```tsx
6341
+ ```diff
5828
6342
  import { Button } from '@/components/Button'
5829
6343
  import { ThemedText } from '@/components/ThemedText'
5830
- import { useStore } from '@/store'
6344
+ +import { useStore } from '@/store'
5831
6345
  import { router } from 'expo-router'
5832
6346
  import React, { useState } from 'react'
5833
6347
  import { Pressable, ScrollView, View } from 'react-native'
@@ -5836,10 +6350,10 @@ import { StyleSheet, useUnistyles } from 'react-native-unistyles'
5836
6350
 
5837
6351
  export default function SettingsAccentScreen() {
5838
6352
  const { theme } = useUnistyles()
5839
- const { setPreferredAccent, preferredAccent } = useStore()
6353
+ +const { setPreferredAccent, preferredAccent } = useStore()
5840
6354
  const allAccents = theme.colors.accents
5841
- const [selectedAccent, setSelectedAccent] = useState(preferredAccent)
5842
- const [selectedAccent, setSelectedAccent] = useState('banana')
6355
+ +const [selectedAccent, setSelectedAccent] = useState(preferredAccent)
6356
+ -const [selectedAccent, setSelectedAccent] = useState('banana')
5843
6357
 
5844
6358
 
5845
6359
  return (
@@ -5869,7 +6383,7 @@ export default function SettingsAccentScreen() {
5869
6383
  label="Save"
5870
6384
  accent={selectedAccent}
5871
6385
  onPress={() => {
5872
- setPreferredAccent(selectedAccent)
6386
+ +setPreferredAccent(selectedAccent)
5873
6387
  router.back()
5874
6388
  }}
5875
6389
  />
@@ -5888,21 +6402,25 @@ The beautiful thing about this approach is that any other component that listens
5888
6402
 
5889
6403
  ### Making Components Dynamic
5890
6404
 
6405
+ [Section titled “Making Components Dynamic”](#making-components-dynamic)
6406
+
5891
6407
  Now let’s update our components to respond to the user’s accent preference instead of using hardcoded values.
5892
6408
 
5893
6409
  #### Update Button Component
5894
6410
 
6411
+ [Section titled “Update Button Component”](#update-button-component)
6412
+
5895
6413
  The Button component needs to use the store value as a fallback while still allowing accent overrides:
5896
6414
 
5897
6415
  components/Button.tsx
5898
6416
 
5899
- ```tsx
6417
+ ```diff
5900
6418
  import { Pressable } from 'react-native'
5901
6419
  import Animated, { useAnimatedStyle, withTiming } from 'react-native-reanimated'
5902
6420
  import { StyleSheet, UnistylesVariants } from 'react-native-unistyles'
5903
6421
  import { useAnimatedVariantColor } from 'react-native-unistyles/reanimated'
5904
6422
  import { ThemedText } from './ThemedText'
5905
- import { useStore } from '@/store'
6423
+ +import { useStore } from '@/store'
5906
6424
 
5907
6425
 
5908
6426
  interface ButtonProps extends UnistylesVariants<typeof style> {
@@ -5916,12 +6434,12 @@ export const Button: React.FunctionComponent<ButtonProps> = ({
5916
6434
  accent,
5917
6435
  onPress
5918
6436
  }) => {
5919
- const { preferredAccent } = useStore()
6437
+ +const { preferredAccent } = useStore()
5920
6438
 
5921
6439
 
5922
6440
  style.useVariants({
5923
6441
  accent: accent ?? preferredAccent
5924
- accent: accent
6442
+ -accent: accent
5925
6443
  })
5926
6444
 
5927
6445
 
@@ -5952,23 +6470,25 @@ This implementation is flexible - it uses the accent prop if provided (like in t
5952
6470
 
5953
6471
  #### Update PlayerControls Component
5954
6472
 
6473
+ [Section titled “Update PlayerControls Component”](#update-playercontrols-component)
6474
+
5955
6475
  The PlayerControls component should always use the user’s preferred accent:
5956
6476
 
5957
6477
  components/PlayerControls.tsx
5958
6478
 
5959
- ```tsx
6479
+ ```diff
5960
6480
  import { IconSymbol } from '@/components/ui/IconSymbol'
5961
- import { useStore } from '@/store'
6481
+ +import { useStore } from '@/store'
5962
6482
  import { Pressable, View } from 'react-native'
5963
6483
  import { StyleSheet } from 'react-native-unistyles'
5964
6484
  import { useUnistyles } from 'react-native-unistyles'
5965
6485
 
5966
6486
 
5967
6487
  export const PlayerControls = () => {
5968
- const { preferredAccent } = useStore()
6488
+ +const { preferredAccent } = useStore()
5969
6489
  const { theme } = useUnistyles()
5970
- const accent = theme.colors.accents[preferredAccent]
5971
- const accent = theme.colors.accents['banana']
6490
+ +const accent = theme.colors.accents[preferredAccent]
6491
+ -const accent = theme.colors.accents['banana']
5972
6492
 
5973
6493
 
5974
6494
  return (
@@ -6002,7 +6522,7 @@ We need to remove one more `banana` from `[songId].tsx` screen when there is no
6002
6522
 
6003
6523
  screens/player/\[songId].tsx
6004
6524
 
6005
- ```tsx
6525
+ ```diff
6006
6526
  import { Button } from '@/components/Button'
6007
6527
  import { PlayerControls } from '@/components/PlayerControls'
6008
6528
  import { ThemedText } from '@/components/ThemedText'
@@ -6031,7 +6551,7 @@ export default function PlayerScreen() {
6031
6551
  </ThemedText>
6032
6552
  <Button
6033
6553
  label="Pick a song"
6034
- accent="banana"
6554
+ -accent="banana"
6035
6555
  onPress={() => router.replace('/')}
6036
6556
  />
6037
6557
  </ThemedView>
@@ -6044,6 +6564,8 @@ export default function PlayerScreen() {
6044
6564
 
6045
6565
  ### Android
6046
6566
 
6567
+ [Section titled “Android”](#android)
6568
+
6047
6569
  Now let’s test our app on Android to see if there are any platform-specific issues that need addressing.
6048
6570
 
6049
6571
  Running the app on Android, you’ll notice it works correctly overall, but there’s one issue - the TabBar icons are missing! This happens because our `IconSymbol` component uses iOS-specific SF Symbols that don’t exist on Android.
@@ -6052,23 +6574,23 @@ Let’s fix the icon mappings in our `IconSymbol` component:
6052
6574
 
6053
6575
  components/ui/IconSymbol.tsx
6054
6576
 
6055
- ```tsx
6577
+ ```diff
6056
6578
  // ... existing imports and code
6057
6579
 
6058
6580
 
6059
6581
  const MAPPING = {
6060
- 'house.fill': 'home',
6061
- 'paperplane.fill': 'send',
6062
- 'chevron.left.forwardslash.chevron.right': 'code',
6063
- 'chevron.right': 'chevron-right',
6064
- 'music.house': 'queue-music',
6065
- 'play.circle': 'play-circle-outline',
6066
- 'gear.circle': 'settings',
6067
- 'backward.end.fill': 'first-page',
6068
- 'backward.fill': 'fast-rewind',
6069
- 'forward.fill': 'fast-forward',
6070
- 'forward.end.fill': 'last-page',
6071
- 'play.circle.fill': 'play-circle-filled'
6582
+ -'house.fill': 'home',
6583
+ -'paperplane.fill': 'send',
6584
+ -'chevron.left.forwardslash.chevron.right': 'code',
6585
+ -'chevron.right': 'chevron-right',
6586
+ +'music.house': 'queue-music',
6587
+ +'play.circle': 'play-circle-outline',
6588
+ +'gear.circle': 'settings',
6589
+ +'backward.end.fill': 'first-page',
6590
+ +'backward.fill': 'fast-rewind',
6591
+ +'forward.fill': 'fast-forward',
6592
+ +'forward.end.fill': 'last-page',
6593
+ +'play.circle.fill': 'play-circle-filled'
6072
6594
  } as IconMapping;
6073
6595
 
6074
6596
 
@@ -6085,6 +6607,8 @@ We could also improve the bottom navigation bar by properly configuring `react-n
6085
6607
 
6086
6608
  ### Web
6087
6609
 
6610
+ [Section titled “Web”](#web)
6611
+
6088
6612
  When you try to run your app on the web, you will encounter a crash:
6089
6613
 
6090
6614
  ![Web app](/_astro/tutorial-12.DmmorFmX.png)
@@ -6141,6 +6665,8 @@ Before we wrap up this section, let’s explore how Unistyles handles responsive
6141
6665
 
6142
6666
  ### Breakpoints and Media Queries
6143
6667
 
6668
+ [Section titled “Breakpoints and Media Queries”](#breakpoints-and-media-queries)
6669
+
6144
6670
  When your app needs to scale from a phone in your pocket to a large desktop monitor, you face new challenges. Unistyles provides powerful, built-in tools to help you create adaptive and responsive layouts with ease.
6145
6671
 
6146
6672
  The most direct way to create responsive styles is by using **breakpoint objects**. You can turn any style value into an object where the keys are your predefined breakpoint names (`xs`, `sm`, `md`, etc.) and the values are the styles for that specific breakpoint. This enables you to easily create responsive layouts, but only for the properties you need.
@@ -6149,7 +6675,7 @@ Let’s apply this to our `SongTile` component to make the album art larger on b
6149
6675
 
6150
6676
  components/SongTile.tsx
6151
6677
 
6152
- ```tsx
6678
+ ```diff
6153
6679
  // ... JSX remains the same
6154
6680
 
6155
6681
 
@@ -6166,12 +6692,12 @@ const style = StyleSheet.create(theme => ({
6166
6692
  xs: 80,
6167
6693
  md: 120,
6168
6694
  lg: 200
6169
- },
6695
+ +},
6170
6696
  height: {
6171
6697
  xs: 80,
6172
6698
  md: 120,
6173
6699
  lg: 200
6174
- },
6700
+ +},
6175
6701
  borderRadius: theme.gap(2)
6176
6702
  },
6177
6703
  textContainer: {
@@ -6194,9 +6720,9 @@ Let’s modify our `PlayerScreen` to adopt a more traditional web layout on larg
6194
6720
 
6195
6721
  app/(tabs)/player/\[songId].tsx
6196
6722
 
6197
- ```tsx
6198
- import { StyleSheet } from 'react-native-unistyles'
6199
- import { mq, StyleSheet } from 'react-native-unistyles'
6723
+ ```diff
6724
+ -import { StyleSheet } from 'react-native-unistyles'
6725
+ +import { mq, StyleSheet } from 'react-native-unistyles'
6200
6726
 
6201
6727
 
6202
6728
  // ... JSX remains the same
@@ -6213,8 +6739,8 @@ const styles = StyleSheet.create((theme, rt) => ({
6213
6739
  gap: theme.gap(2),
6214
6740
  alignItems: 'center',
6215
6741
  justifyContent: {
6216
- [mq.only.width(600)]: 'center'
6217
- },
6742
+ +[mq.only.width(600)]: 'center'
6743
+ +},
6218
6744
  marginTop: rt.insets.top + theme.gap(3),
6219
6745
  },
6220
6746
  image: {
@@ -6233,6 +6759,8 @@ Dive deeper into the `mq` utility and its helpers [here](/v3/references/media-qu
6233
6759
 
6234
6760
  ### Web styling features
6235
6761
 
6762
+ [Section titled “Web styling features”](#web-styling-features)
6763
+
6236
6764
  While Unistyles excels at universal styling, there are times you’ll want to leverage platform-specific features. On the web, this often means using CSS pseudo-selectors like `:hover` and `:active` for a more native web experience and better performance.
6237
6765
 
6238
6766
  Unistyles makes this incredibly simple with the `_web` property.
@@ -6261,7 +6789,7 @@ To do this, we’ll modify our container style and add a `_web` key. Inside this
6261
6789
 
6262
6790
  components/SettingTile.tsx
6263
6791
 
6264
- ```tsx
6792
+ ```diff
6265
6793
  const styles = StyleSheet.create({
6266
6794
  container: {
6267
6795
  flexDirection: 'row',
@@ -6271,11 +6799,11 @@ const styles = StyleSheet.create({
6271
6799
  _web: {
6272
6800
  _hover: {
6273
6801
  opacity: 0.75
6274
- },
6802
+ +},
6275
6803
  _active: {
6276
6804
  opacity: 0.5
6277
- }
6278
- }
6805
+ +}
6806
+ +}
6279
6807
  }
6280
6808
  })
6281
6809
  ```
@@ -6294,6 +6822,8 @@ Learn more about all the web-specific features [here](/v3/references/web-only).
6294
6822
 
6295
6823
  ### What We’ve Built Together
6296
6824
 
6825
+ [Section titled “What We’ve Built Together”](#what-weve-built-together)
6826
+
6297
6827
  Congratulations! You’ve built a complete, cross-platform music application that demonstrates the full power of Unistyles 3.0. Let’s recap what we’ve accomplished:
6298
6828
 
6299
6829
  **Core Features:**
@@ -6327,6 +6857,8 @@ Congratulations! You’ve built a complete, cross-platform music application tha
6327
6857
 
6328
6858
  ### Summary
6329
6859
 
6860
+ [Section titled “Summary”](#summary)
6861
+
6330
6862
  You’ve just completed an incredible journey building a full-featured, cross-platform music application with Unistyles 3.0. From initial configuration to advanced theming and state management.
6331
6863
 
6332
6864
  But most importantly, you’ve learned to think in Unistyles. You understand when to use variants vs dynamic functions, how to leverage the runtime for device-aware styling, and how to build components that are both flexible and maintainable.
@@ -6353,6 +6885,8 @@ During this tutorial, we will cover most of the Unistyles features and best prac
6353
6885
 
6354
6886
  ### Create new project
6355
6887
 
6888
+ [Section titled “Create new project”](#create-new-project)
6889
+
6356
6890
  First, let’s scaffold a new Expo project using the command line:
6357
6891
 
6358
6892
  ```bash
@@ -6363,9 +6897,11 @@ cd unistyles-tutorial
6363
6897
  Next, install Unistyles, its dependencies, and Reanimated:
6364
6898
 
6365
6899
  ```bash
6366
- yarn add react-native-reanimated react-native-unistyles react-native-nitro-modules react-native-edge-to-edge
6900
+ yarn add react-native-reanimated react-native-unistyles react-native-nitro-modules
6367
6901
  ```
6368
6902
 
6903
+ > `react-native-edge-to-edge` is optional since v3.1.0 — Unistyles enables edge-to-edge automatically. See [dependencies](/v3/other/dependencies) for details.
6904
+
6369
6905
  Tip
6370
6906
 
6371
6907
  For best results and to ensure compatibility, we recommend using the `react-native-nitro-modules` version specified in the Unistyles [compatibility table](https://github.com/jpudysz/react-native-unistyles?tab=readme-ov-file#installation).
@@ -6378,6 +6914,8 @@ yarn expo prebuild --clean
6378
6914
 
6379
6915
  ### Configure Babel Plugins
6380
6916
 
6917
+ [Section titled “Configure Babel Plugins”](#configure-babel-plugins)
6918
+
6381
6919
  Both `Unistyles` and `Reanimated` require a Babel plugin to work. Since a `babel.config.js` file isn’t created by default, we can generate it by running:
6382
6920
 
6383
6921
  ```bash
@@ -6386,17 +6924,17 @@ npx expo customize babel.config.js
6386
6924
 
6387
6925
  Now, add the `unistyles` and `reanimated` plugins to your `babel.config.js`:
6388
6926
 
6389
- ```ts
6927
+ ```diff
6390
6928
  module.exports = function (api) {
6391
6929
  api.cache(true);
6392
6930
  return {
6393
6931
  presets: ['babel-preset-expo'],
6394
- plugins: [
6395
- ['react-native-unistyles/plugin', {
6396
- root: 'app'
6397
- }],
6398
- ['react-native-worklets/plugin']
6399
- ]
6932
+ + plugins: [
6933
+ + ['react-native-unistyles/plugin', {
6934
+ + root: 'app'
6935
+ + }],
6936
+ + ['react-native-reanimated/plugin']
6937
+ + ]
6400
6938
  };
6401
6939
  };
6402
6940
  ```
@@ -6407,14 +6945,16 @@ To learn more about the Unistyles Babel plugin and its configuration options, ch
6407
6945
 
6408
6946
  ### Modify app entry point
6409
6947
 
6948
+ [Section titled “Modify app entry point”](#modify-app-entry-point)
6949
+
6410
6950
  To use features like themes and breakpoints, Unistyles must be configured before your application code runs. This ensures that all stylesheets are created with the correct theme and device context.
6411
6951
 
6412
6952
  First, update your `package.json`:
6413
6953
 
6414
- ```json
6954
+ ```diff
6415
6955
  {
6416
- "main": "expo-router/entry"
6417
- "main": "index.ts"
6956
+ -"main": "expo-router/entry"
6957
+ +"main": "index.ts"
6418
6958
  }
6419
6959
  ```
6420
6960
 
@@ -6429,6 +6969,8 @@ We’ll create the `unistyles.ts` file in the next step.
6429
6969
 
6430
6970
  ### Configure Unistyles
6431
6971
 
6972
+ [Section titled “Configure Unistyles”](#configure-unistyles)
6973
+
6432
6974
  This is where the magic happens! Create a `unistyles.ts` file in your project’s root. Here, we’ll define our `themes`, `breakpoints`, and register them with Unistyles.
6433
6975
 
6434
6976
  ```ts
@@ -6540,6 +7082,8 @@ Time to build the modal screens for theme and accent selection. We’ll create i
6540
7082
 
6541
7083
  ### Create SettingOptionRadio Component
6542
7084
 
7085
+ [Section titled “Create SettingOptionRadio Component”](#create-settingoptionradio-component)
7086
+
6543
7087
  Let’s start with a radio button component for selecting theme modes. This component brings together concepts we’ve covered in previous steps.
6544
7088
 
6545
7089
  Create `components/SettingOptionRadio.tsx`:
@@ -6629,14 +7173,16 @@ This component combines everything we’ve learned: `useVariants` for the radio
6629
7173
 
6630
7174
  ### Basic Theme Settings Screen
6631
7175
 
7176
+ [Section titled “Basic Theme Settings Screen”](#basic-theme-settings-screen)
7177
+
6632
7178
  Let’s add this component to the theme settings screen:
6633
7179
 
6634
7180
  app/settings/settings-theme.tsx
6635
7181
 
6636
- ```tsx
6637
- import { ThemedText } from '@/components/ThemedText'
6638
- import { SettingOptionRadio } from '@/components/SettingOptionRadio'
6639
- import React from 'react'
7182
+ ```diff
7183
+ -import { ThemedText } from '@/components/ThemedText'
7184
+ +import { SettingOptionRadio } from '@/components/SettingOptionRadio'
7185
+ +import React from 'react'
6640
7186
  import { ScrollView } from 'react-native'
6641
7187
  import { StyleSheet } from 'react-native-unistyles'
6642
7188
 
@@ -6644,9 +7190,9 @@ import { StyleSheet } from 'react-native-unistyles'
6644
7190
  export default function SettingsThemeScreen() {
6645
7191
  return (
6646
7192
  <ScrollView contentContainerStyle={styles.container}>
6647
- <ThemedText type="title">
6648
- Change theme
6649
- </ThemedText>
7193
+ -<ThemedText type="title">
7194
+ - Change theme
7195
+ -</ThemedText>
6650
7196
  <SettingOptionRadio
6651
7197
  label="System"
6652
7198
  isSelected={false}
@@ -6674,6 +7220,8 @@ const styles = StyleSheet.create(theme => ({
6674
7220
 
6675
7221
  ### Create ThemeColor Component
6676
7222
 
7223
+ [Section titled “Create ThemeColor Component”](#create-themecolor-component)
7224
+
6677
7225
  Now let’s create a component called `ThemeColor` that will preview different themes.
6678
7226
 
6679
7227
  components/ThemeColor.tsx
@@ -6734,16 +7282,18 @@ Before proceeding further, notice that we used `keyof UnistylesTheme` (as label
6734
7282
 
6735
7283
  ### Enhanced Theme Settings Screen
6736
7284
 
7285
+ [Section titled “Enhanced Theme Settings Screen”](#enhanced-theme-settings-screen)
7286
+
6737
7287
  Let’s update the theme settings screen to include theme previews:
6738
7288
 
6739
7289
  app/settings/settings-theme.tsx
6740
7290
 
6741
- ```tsx
7291
+ ```diff
6742
7292
  import { SettingOptionRadio } from '@/components/SettingOptionRadio'
6743
- import { ThemeColor } from '@/components/ThemeColor'
7293
+ +import { ThemeColor } from '@/components/ThemeColor'
6744
7294
  import React from 'react'
6745
- import { ScrollView, View } from 'react-native'
6746
- import { ScrollView } from 'react-native'
7295
+ +import { ScrollView, View } from 'react-native'
7296
+ -import { ScrollView } from 'react-native'
6747
7297
  import { StyleSheet } from 'react-native-unistyles'
6748
7298
 
6749
7299
 
@@ -6760,16 +7310,16 @@ export default function SettingsThemeScreen() {
6760
7310
  isSelected={false}
6761
7311
  onPress={() => {}}
6762
7312
  />
6763
- <View style={styles.row}>
6764
- <ThemeColor
6765
- label="light"
6766
- onPress={() => {}}
6767
- />
6768
- <ThemeColor
6769
- label="dark"
6770
- onPress={() => {}}
6771
- />
6772
- </View>
7313
+ +<View style={styles.row}>
7314
+ +<ThemeColor
7315
+ +label="light"
7316
+ +onPress={() => {}}
7317
+ + />
7318
+ +<ThemeColor
7319
+ +label="dark"
7320
+ +onPress={() => {}}
7321
+ + />
7322
+ +</View>
6773
7323
  </ScrollView>
6774
7324
  )
6775
7325
  }
@@ -6786,7 +7336,7 @@ const styles = StyleSheet.create(theme => ({
6786
7336
  justifyContent: 'center',
6787
7337
  flexDirection: 'row',
6788
7338
  gap: theme.gap(2)
6789
- }
7339
+ +}
6790
7340
  }))
6791
7341
  ```
6792
7342
 
@@ -6800,64 +7350,66 @@ It seems that we need to also update `react-navigation` Header to use Unistyles
6800
7350
 
6801
7351
  ### Complete Theme Settings Implementation
6802
7352
 
7353
+ [Section titled “Complete Theme Settings Implementation”](#complete-theme-settings-implementation)
7354
+
6803
7355
  Now let’s add the full functionality using `UnistylesRuntime` and `useUnistyles`:
6804
7356
 
6805
7357
  app/settings/settings-theme.tsx
6806
7358
 
6807
- ```tsx
7359
+ ```diff
6808
7360
  import { SettingOptionRadio } from '@/components/SettingOptionRadio'
6809
7361
  import { ThemeColor } from '@/components/ThemeColor'
6810
7362
  import React from 'react'
6811
7363
  import { ScrollView, View } from 'react-native'
6812
- import { StyleSheet, UnistylesRuntime, useUnistyles } from 'react-native-unistyles'
6813
- import { StyleSheet } from 'react-native-unistyles'
7364
+ +import { StyleSheet, UnistylesRuntime, useUnistyles } from 'react-native-unistyles'
7365
+ -import { StyleSheet } from 'react-native-unistyles'
6814
7366
 
6815
7367
 
6816
7368
  export default function SettingsThemeScreen() {
6817
- const { rt } = useUnistyles()
7369
+ +const { rt } = useUnistyles()
6818
7370
 
6819
7371
 
6820
7372
  return (
6821
7373
  <ScrollView contentContainerStyle={styles.container}>
6822
7374
  <SettingOptionRadio
6823
7375
  label="System"
6824
- isSelected={rt.hasAdaptiveThemes}
6825
- onPress={() => {
6826
- if (rt.hasAdaptiveThemes) {
6827
- return
6828
- }
7376
+ +isSelected={rt.hasAdaptiveThemes}
7377
+ +onPress={() => {
7378
+ +if (rt.hasAdaptiveThemes) {
7379
+ +return
7380
+ + }
6829
7381
 
6830
7382
 
6831
- UnistylesRuntime.setAdaptiveThemes(true)
6832
- }}
6833
- isSelected={false}
6834
- onPress={() => {}}
7383
+ +UnistylesRuntime.setAdaptiveThemes(true)
7384
+ + }}
7385
+ -isSelected={false}
7386
+ -onPress={() => {}}
6835
7387
  />
6836
7388
  <SettingOptionRadio
6837
7389
  label="User"
6838
- isSelected={!rt.hasAdaptiveThemes}
6839
- onPress={() => {
6840
- if (rt.hasAdaptiveThemes) {
6841
- UnistylesRuntime.setAdaptiveThemes(false)
6842
- }
6843
- }}
6844
- isSelected={false}
6845
- onPress={() => {}}
7390
+ +isSelected={!rt.hasAdaptiveThemes}
7391
+ +onPress={() => {
7392
+ +if (rt.hasAdaptiveThemes) {
7393
+ +UnistylesRuntime.setAdaptiveThemes(false)
7394
+ + }
7395
+ + }}
7396
+ -isSelected={false}
7397
+ -onPress={() => {}}
6846
7398
  />
6847
- {!rt.hasAdaptiveThemes && (
7399
+ +{!rt.hasAdaptiveThemes && (
6848
7400
  <View style={styles.row}>
6849
7401
  <ThemeColor
6850
7402
  label="light"
6851
- onPress={() => UnistylesRuntime.setTheme('light')}
6852
- onPress={() => {}}
7403
+ +onPress={() => UnistylesRuntime.setTheme('light')}
7404
+ -onPress={() => {}}
6853
7405
  />
6854
7406
  <ThemeColor
6855
7407
  label="dark"
6856
- onPress={() => UnistylesRuntime.setTheme('dark')}
6857
- onPress={() => {}}
7408
+ +onPress={() => UnistylesRuntime.setTheme('dark')}
7409
+ -onPress={() => {}}
6858
7410
  />
6859
7411
  </View>
6860
- )}
7412
+ + )}
6861
7413
  </ScrollView>
6862
7414
  )
6863
7415
  }
@@ -6875,11 +7427,13 @@ Try playing with different settings to see how the app adapts to your choices.
6875
7427
 
6876
7428
  ### Update navigation header colors
6877
7429
 
7430
+ [Section titled “Update navigation header colors”](#update-navigation-header-colors)
7431
+
6878
7432
  As you probably noticed, navigation header colors are not updated when theme changes. Let’s fix that by updating `app/(tabs)/settings/_layout.tsx` file:
6879
7433
 
6880
7434
  app/(tabs)/settings/\_layout.tsx
6881
7435
 
6882
- ```tsx
7436
+ ```diff
6883
7437
  import { Stack } from 'expo-router'
6884
7438
  import React from 'react'
6885
7439
  import { useUnistyles } from 'react-native-unistyles'
@@ -6892,12 +7446,12 @@ export default function SettingsLayout() {
6892
7446
  return (
6893
7447
  <Stack
6894
7448
  screenOptions={{
6895
- headerTitleStyle: {
6896
- color: theme.colors.typography
6897
- },
6898
- headerStyle: {
6899
- backgroundColor: theme.colors.background
6900
- },
7449
+ + headerTitleStyle: {
7450
+ + color: theme.colors.typography
7451
+ + },
7452
+ + headerStyle: {
7453
+ + backgroundColor: theme.colors.background
7454
+ + },
6901
7455
  contentStyle: {
6902
7456
  backgroundColor: theme.colors.background
6903
7457
  }
@@ -6935,6 +7489,8 @@ That’s all for theme settings screen!
6935
7489
 
6936
7490
  ### Create Button Component
6937
7491
 
7492
+ [Section titled “Create Button Component”](#create-button-component)
7493
+
6938
7494
  Now let’s learn something new. We will create an animated button component for the accent settings:
6939
7495
 
6940
7496
  components/Button.tsx
@@ -7013,11 +7569,11 @@ You should be familiar with all the patterns used here: variants, `UnistylesVari
7013
7569
 
7014
7570
  components/Button.tsx
7015
7571
 
7016
- ```tsx
7572
+ ```diff
7017
7573
  import { Pressable } from 'react-native'
7018
7574
  import Animated, { useAnimatedStyle, withTiming } from 'react-native-reanimated'
7019
7575
  import { StyleSheet, UnistylesVariants } from 'react-native-unistyles'
7020
- import { useAnimatedVariantColor } from 'react-native-unistyles/reanimated'
7576
+ +import { useAnimatedVariantColor } from 'react-native-unistyles/reanimated'
7021
7577
  import { ThemedText } from './ThemedText'
7022
7578
 
7023
7579
 
@@ -7037,18 +7593,18 @@ export const Button: React.FunctionComponent<ButtonProps> = ({
7037
7593
  })
7038
7594
 
7039
7595
 
7040
- const color = useAnimatedVariantColor(style.buttonColor, 'backgroundColor')
7041
- const animatedStyle = useAnimatedStyle(() => ({
7596
+ +const color = useAnimatedVariantColor(style.buttonColor, 'backgroundColor')
7597
+ +const animatedStyle = useAnimatedStyle(() => ({
7042
7598
  backgroundColor: withTiming(color.value, {
7043
7599
  duration: 500
7044
- })
7045
- }))
7600
+ +})
7601
+ +}))
7046
7602
 
7047
7603
 
7048
7604
  return (
7049
7605
  <Pressable onPress={onPress}>
7050
- <Animated.View style={style.button}>
7051
- <Animated.View style={[animatedStyle, style.button]}>
7606
+ -<Animated.View style={style.button}>
7607
+ +<Animated.View style={[animatedStyle, style.button]}>
7052
7608
  <ThemedText bold>
7053
7609
  {label}
7054
7610
  </ThemedText>
@@ -7075,6 +7631,8 @@ For a comprehensive explanation, please refer to our dedicated guide on [Merging
7075
7631
 
7076
7632
  ### Build the Accent Settings Modal
7077
7633
 
7634
+ [Section titled “Build the Accent Settings Modal”](#build-the-accent-settings-modal)
7635
+
7078
7636
  Let’s create the final modal screen for accent selection and animate the accent selection:
7079
7637
 
7080
7638
  app/settings/settings-accent.tsx
@@ -7203,27 +7761,29 @@ Our application will feature three primary screens, with the Settings screen als
7203
7761
 
7204
7762
  ### PlaylistScreen
7205
7763
 
7764
+ [Section titled “PlaylistScreen”](#playlistscreen)
7765
+
7206
7766
  First, let’s repurpose the existing `app/(tabs)/index.tsx` file to become our `PlaylistScreen`. This involves changing the component name from `HomeScreen` to `PlaylistScreen` and wrapping the content in a `ScrollView`:
7207
7767
 
7208
7768
  app/(tabs)/index.tsx
7209
7769
 
7210
- ```tsx
7211
- import { ScrollView } from 'react-native';
7770
+ ```diff
7771
+ +import { ScrollView } from 'react-native';
7212
7772
  import { ThemedText } from '@/components/ThemedText'
7213
7773
  import { ThemedView } from '@/components/ThemedView'
7214
7774
  import { StyleSheet } from 'react-native-unistyles'
7215
7775
 
7216
7776
 
7217
- export default function PlaylistScreen() {
7218
- export default function HomeScreen() {
7777
+ +export default function PlaylistScreen() {
7778
+ -export default function HomeScreen() {
7219
7779
  return (
7220
- <ScrollView contentContainerStyle={styles.container}>
7221
- <ThemedView style={styles.container}>
7780
+ +<ScrollView contentContainerStyle={styles.container}>
7781
+ -<ThemedView style={styles.container}>
7222
7782
  <ThemedText type="title">
7223
7783
  Home Screen
7224
7784
  </ThemedText>
7225
- </ThemedView>
7226
- </ScrollView>
7785
+ -</ThemedView>
7786
+ +</ScrollView>
7227
7787
  );
7228
7788
  }
7229
7789
 
@@ -7241,7 +7801,7 @@ Next, let’s update the title and adjust the container styles. We’ll remove t
7241
7801
 
7242
7802
  app/(tabs)/index.tsx
7243
7803
 
7244
- ```tsx
7804
+ ```diff
7245
7805
  import { ThemedText } from '@/components/ThemedText'
7246
7806
  import { ScrollView } from 'react-native'
7247
7807
  import { StyleSheet } from 'react-native-unistyles'
@@ -7251,8 +7811,8 @@ export default function PlaylistScreen() {
7251
7811
  return (
7252
7812
  <ScrollView contentContainerStyle={styles.container}>
7253
7813
  <ThemedText type="title">
7254
- Home Screen
7255
- Playlist
7814
+ - Home Screen
7815
+ + Playlist
7256
7816
  </ThemedText>
7257
7817
  </ScrollView>
7258
7818
  );
@@ -7286,8 +7846,8 @@ Let’s use `rt.insets.top` to add a top margin to our container, pushing the co
7286
7846
 
7287
7847
  app/(tabs)/index.tsx
7288
7848
 
7289
- ```tsx
7290
- const styles = StyleSheet.create((theme, rt) => ({
7849
+ ```diff
7850
+ +const styles = StyleSheet.create((theme, rt) => ({
7291
7851
  const styles = StyleSheet.create(theme => ({
7292
7852
  container: {
7293
7853
  flex: 1,
@@ -7300,8 +7860,8 @@ To give our content some breathing room, let’s also add horizontal padding usi
7300
7860
 
7301
7861
  app/(tabs)/index.tsx
7302
7862
 
7303
- ```tsx
7304
- const styles = StyleSheet.create((theme, rt) => ({
7863
+ ```diff
7864
+ +const styles = StyleSheet.create((theme, rt) => ({
7305
7865
  container: {
7306
7866
  flex: 1,
7307
7867
  marginTop: rt.insets.top,
@@ -7312,6 +7872,8 @@ app/(tabs)/index.tsx
7312
7872
 
7313
7873
  ### PlayerScreen
7314
7874
 
7875
+ [Section titled “PlayerScreen”](#playerscreen)
7876
+
7315
7877
  For the `PlayerScreen`, we’ll start by creating a new file structure and then use a modified version of our `PlaylistScreen` code.
7316
7878
 
7317
7879
  Expo Router uses a file-based routing system. To create a dynamic route for our player, create the following folder and file:
@@ -7368,6 +7930,8 @@ Don’t worry about the TabBar icons and routing just yet - we’ll fix that soo
7368
7930
 
7369
7931
  ### SettingsScreen
7370
7932
 
7933
+ [Section titled “SettingsScreen”](#settingsscreen)
7934
+
7371
7935
  The `SettingsScreen` is our final main screen. It will serve as a hub for navigating to the modal screens where users can change the app’s theme and accent color.
7372
7936
 
7373
7937
  First, set up the required files and folders:
@@ -7399,6 +7963,8 @@ This is a standard Expo Router stack layout. Let’s add the code for each of th
7399
7963
 
7400
7964
  #### 1. Configure the Stack Navigator (\_layout.tsx)
7401
7965
 
7966
+ [Section titled “1. Configure the Stack Navigator (\_layout.tsx)”](#1-configure-the-stack-navigator-_layouttsx)
7967
+
7402
7968
  This file configures the stack navigator for the settings section, defining the main screen and the two modal screens.
7403
7969
 
7404
7970
  app/settings/\_layout.tsx
@@ -7451,6 +8017,8 @@ export default function SettingsLayout() {
7451
8017
 
7452
8018
  #### 2. Create the Main Settings Screen (index.tsx)
7453
8019
 
8020
+ [Section titled “2. Create the Main Settings Screen (index.tsx)”](#2-create-the-main-settings-screen-indextsx)
8021
+
7454
8022
  This is the main `SettingsScreen`. The code is almost identical to our other screens for now.
7455
8023
 
7456
8024
  app/settings/index.tsx
@@ -7483,6 +8051,8 @@ const styles = StyleSheet.create((theme, rt) => ({
7483
8051
 
7484
8052
  #### 3. Create the Modal Screens
7485
8053
 
8054
+ [Section titled “3. Create the Modal Screens”](#3-create-the-modal-screens)
8055
+
7486
8056
  The modal screens for changing the theme and accent color are also simple placeholders. Notice the component names and titles are updated for each.
7487
8057
 
7488
8058
  app/settings/settings-theme.tsx
@@ -7545,11 +8115,13 @@ You should now be able to navigate to all three screens, each with a different t
7545
8115
 
7546
8116
  ### TabBar
7547
8117
 
8118
+ [Section titled “TabBar”](#tabbar)
8119
+
7548
8120
  Currently, `TabBar` doesn’t reflect our new screen structure. Let’s update `app/(tabs)/_layout.tsx` to correctly register our routes and assign new icons.
7549
8121
 
7550
8122
  app/(tabs)/\_layout.tsx
7551
8123
 
7552
- ```tsx
8124
+ ```diff
7553
8125
  import { IconSymbol } from '@/components/ui/IconSymbol'
7554
8126
  import { Tabs } from 'expo-router'
7555
8127
  import React from 'react'
@@ -7576,27 +8148,27 @@ export default function TabLayout() {
7576
8148
  <Tabs.Screen
7577
8149
  name="index"
7578
8150
  options={{
7579
- title: 'Home',
7580
- title: 'Playlist',
7581
- tabBarIcon: ({ color }) => <IconSymbol size={28} name="house.fill" color={color} />,
7582
- tabBarIcon: ({ color }) => <IconSymbol size={24} name="music.house" color={color} />,
8151
+ - title: 'Home',
8152
+ + title: 'Playlist',
8153
+ -tabBarIcon: ({ color }) => <IconSymbol size={28} name="house.fill" color={color} />,
8154
+ +tabBarIcon: ({ color }) => <IconSymbol size={24} name="music.house" color={color} />,
7583
8155
  }}
7584
8156
  />
8157
+ +<Tabs.Screen
8158
+ +name="player/[songId]"
8159
+ +options={{
8160
+ + title: 'Player',
8161
+ +tabBarIcon: ({ color }) => <IconSymbol size={24} name="play.circle" color={color} />,
8162
+ + }}
8163
+ + />
7585
8164
  <Tabs.Screen
7586
- name="player/[songId]"
8165
+ -name="explore"
8166
+ +name="settings"
7587
8167
  options={{
7588
- title: 'Player',
7589
- tabBarIcon: ({ color }) => <IconSymbol size={24} name="play.circle" color={color} />,
7590
- }}
7591
- />
7592
- <Tabs.Screen
7593
- name="explore"
7594
- name="settings"
7595
- options={{
7596
- title: 'Explore',
7597
- title: 'Settings',
7598
- tabBarIcon: ({ color }) => <IconSymbol size={28} name="paperplane.fill" color={color} />,
7599
- tabBarIcon: ({ color }) => <IconSymbol size={24} name="gear.circle" color={color} />,
8168
+ - title: 'Explore',
8169
+ + title: 'Settings',
8170
+ -tabBarIcon: ({ color }) => <IconSymbol size={28} name="paperplane.fill" color={color} />,
8171
+ +tabBarIcon: ({ color }) => <IconSymbol size={24} name="gear.circle" color={color} />,
7600
8172
  }}
7601
8173
  />
7602
8174
  </Tabs>
@@ -7626,12 +8198,16 @@ By the end of this part, you’ll have a functional music app that displays a li
7626
8198
 
7627
8199
  ### Setting Up Types and Mock Data
7628
8200
 
8201
+ [Section titled “Setting Up Types and Mock Data”](#setting-up-types-and-mock-data)
8202
+
7629
8203
  Before we can build our screens, we need to establish the data structure for our songs. This step is crucial for maintaining type safety throughout our application and ensuring that our components receive the expected data format.
7630
8204
 
7631
8205
  Let’s start by creating the fundamental types that will power our music app.
7632
8206
 
7633
8207
  #### Create Song Types
7634
8208
 
8209
+ [Section titled “Create Song Types”](#create-song-types)
8210
+
7635
8211
  First, we’ll define what a song looks like in our application. Each song needs essential information like title, genre, cover image, and duration.
7636
8212
 
7637
8213
  Create `types/song.ts`:
@@ -7663,6 +8239,8 @@ export * from './song'
7663
8239
 
7664
8240
  #### Create Mock Playlist Data
7665
8241
 
8242
+ [Section titled “Create Mock Playlist Data”](#create-mock-playlist-data)
8243
+
7666
8244
  For this tutorial, we’ll use a curated list of 20 fictional songs with diverse genres to showcase our app’s capabilities. In a real application, this data would come from an API or music service.
7667
8245
 
7668
8246
  Create `mocks/playlist.ts`:
@@ -7831,6 +8409,8 @@ This gives us clean access to our mock data throughout the application with simp
7831
8409
 
7832
8410
  ### Building the Playlist Screen
7833
8411
 
8412
+ [Section titled “Building the Playlist Screen”](#building-the-playlist-screen)
8413
+
7834
8414
  Now that we have our data structure in place, let’s transform the placeholder home screen into a proper playlist that displays our collection of songs. The playlist will serve as the main entry point where users can browse and select tracks.
7835
8415
 
7836
8416
  Currently, our home screen at `app/(tabs)/index.tsx` just displays a simple title. We need to replace this with a scrollable list of songs that users can interact with.
@@ -7839,63 +8419,63 @@ Let’s update the playlist screen to display our songs:
7839
8419
 
7840
8420
  app/(tabs)/index.tsx
7841
8421
 
7842
- ```tsx
7843
- import { SongTile } from '@/components/SongTile'
8422
+ ```diff
8423
+ +import { SongTile } from '@/components/SongTile'
7844
8424
  import { ThemedText } from '@/components/ThemedText'
7845
- import { playlist } from '@/mocks'
7846
- import { router } from 'expo-router'
7847
- import { ScrollView, View } from 'react-native'
7848
- import { ScrollView } from 'react-native'
8425
+ +import { playlist } from '@/mocks'
8426
+ +import { router } from 'expo-router'
8427
+ +import { ScrollView, View } from 'react-native'
8428
+ -import { ScrollView } from 'react-native'
7849
8429
  import { StyleSheet } from 'react-native-unistyles'
7850
8430
 
7851
8431
 
7852
8432
  export default function PlaylistScreen() {
7853
8433
  return (
7854
- <View style={styles.container}>
7855
- <ScrollView contentContainerStyle={styles.contentContainer}>
7856
- <View style={styles.header}>
7857
- <ThemedText type="title">
7858
- Playlist
7859
- </ThemedText>
7860
- </View>
7861
- {playlist.map(song => (
7862
- <SongTile
7863
- song={song}
7864
- onPress={() => router.push(`/(tabs)/player/${song.id}`)}
7865
- key={song.id}
7866
- />
7867
- ))}
7868
- </ScrollView>
7869
- </View>
7870
- <ScrollView contentContainerStyle={styles.container}>
7871
- <ThemedText type="title">
7872
- Playlist
7873
- </ThemedText>
7874
- </ScrollView>
8434
+ +<View style={styles.container}>
8435
+ +<ScrollView contentContainerStyle={styles.contentContainer}>
8436
+ +<View style={styles.header}>
8437
+ +<ThemedText type="title">
8438
+ + Playlist
8439
+ +</ThemedText>
8440
+ +</View>
8441
+ +{playlist.map(song => (
8442
+ +<SongTile
8443
+ +song={song}
8444
+ +onPress={() => router.push(`/(tabs)/player/${song.id}`)}
8445
+ +key={song.id}
8446
+ + />
8447
+ + ))}
8448
+ +</ScrollView>
8449
+ +</View>
8450
+ -<ScrollView contentContainerStyle={styles.container}>
8451
+ -<ThemedText type="title">
8452
+ - Playlist
8453
+ -</ThemedText>
8454
+ -</ScrollView>
7875
8455
  );
7876
8456
  }
7877
8457
 
7878
8458
 
7879
- const styles = StyleSheet.create((theme, rt) => ({
8459
+ +const styles = StyleSheet.create((theme, rt) => ({
7880
8460
  container: {
7881
8461
  marginTop: rt.insets.top + theme.gap(3),
7882
8462
  backgroundColor: theme.colors.background
7883
- },
8463
+ +},
7884
8464
  contentContainer: {
7885
8465
  gap: theme.gap(3),
7886
8466
  paddingHorizontal: theme.gap(2)
7887
- },
8467
+ +},
7888
8468
  header: {
7889
8469
  paddingBottom: theme.gap(2)
7890
- }
7891
- }));
7892
- const styles = StyleSheet.create((theme, rt) => ({
8470
+ +}
8471
+ +}));
8472
+ -const styles = StyleSheet.create((theme, rt) => ({
7893
8473
  container: {
7894
8474
  flex: 1,
7895
8475
  marginTop: rt.insets.top,
7896
8476
  paddingHorizontal: theme.gap(2)
7897
- },
7898
- }));
8477
+ -},
8478
+ -}));
7899
8479
  ```
7900
8480
 
7901
8481
  Here’s what we’ve changed and why:
@@ -7912,6 +8492,8 @@ The key difference is that we’re now structuring our app to handle a list of d
7912
8492
 
7913
8493
  ### Creating the SongTile Component
7914
8494
 
8495
+ [Section titled “Creating the SongTile Component”](#creating-the-songtile-component)
8496
+
7915
8497
  The `SongTile` component will be responsible for displaying individual song information in an attractive, tappable format. This component needs to show the song’s cover art, title, genre, and duration in a clean layout.
7916
8498
 
7917
8499
  Before our playlist screen can work, we need to create the `SongTile` component that will display each song:
@@ -7979,101 +8561,103 @@ We now have a fully functional playlist screen that displays our 20 mock songs i
7979
8561
 
7980
8562
  ### Building the Player Screen
7981
8563
 
8564
+ [Section titled “Building the Player Screen”](#building-the-player-screen)
8565
+
7982
8566
  The player screen needs to handle dynamic routing, where the song ID comes from the URL parameter. This screen will display detailed information about the selected song and provide playback controls.
7983
8567
 
7984
8568
  Let’s update our player screen at `app/(tabs)/player/[songId].tsx` to handle the dynamic song data:
7985
8569
 
7986
8570
  app/(tabs)/player/\[songId].tsx
7987
8571
 
7988
- ```tsx
7989
- import { Button } from '@/components/Button'
7990
- import { PlayerControls } from '@/components/PlayerControls'
8572
+ ```diff
8573
+ +import { Button } from '@/components/Button'
8574
+ +import { PlayerControls } from '@/components/PlayerControls'
7991
8575
  import { ThemedText } from '@/components/ThemedText'
7992
- import { ThemedView } from '@/components/ThemedView'
7993
- import { playlist } from '@/mocks'
7994
- import { router, useLocalSearchParams } from 'expo-router'
7995
- import { Image, ScrollView } from 'react-native'
7996
- import { ScrollView } from 'react-native'
8576
+ +import { ThemedView } from '@/components/ThemedView'
8577
+ +import { playlist } from '@/mocks'
8578
+ +import { router, useLocalSearchParams } from 'expo-router'
8579
+ +import { Image, ScrollView } from 'react-native'
8580
+ -import { ScrollView } from 'react-native'
7997
8581
  import { StyleSheet } from 'react-native-unistyles'
7998
8582
 
7999
8583
 
8000
8584
  export default function PlayerScreen() {
8001
- const { songId } = useLocalSearchParams()
8002
-
8003
-
8004
- const song = playlist.find(song => song.id === Number(songId))
8005
-
8006
-
8007
- if (!songId || !song) {
8008
- return (
8009
- <ThemedView style={[styles.centerContainer, styles.container]}>
8010
- <ThemedText type="title">
8011
- Looking for inspiration?
8012
- </ThemedText>
8013
- <ThemedText>
8014
- Pick a song from the playlist
8015
- </ThemedText>
8016
- <Button
8017
- label="Pick a song"
8018
- accent="banana"
8019
- onPress={() => router.replace('/')}
8020
- />
8021
- </ThemedView>
8022
- )
8023
- }
8585
+ +const { songId } = useLocalSearchParams()
8586
+
8587
+
8588
+ +const song = playlist.find(song => song.id === Number(songId))
8589
+
8590
+
8591
+ +if (!songId || !song) {
8592
+ +return (
8593
+ +<ThemedView style={[styles.centerContainer, styles.container]}>
8594
+ +<ThemedText type="title">
8595
+ + Looking for inspiration?
8596
+ +</ThemedText>
8597
+ +<ThemedText>
8598
+ + Pick a song from the playlist
8599
+ +</ThemedText>
8600
+ +<Button
8601
+ +label="Pick a song"
8602
+ +accent="banana"
8603
+ +onPress={() => router.replace('/')}
8604
+ + />
8605
+ +</ThemedView>
8606
+ + )
8607
+ + }
8024
8608
 
8025
8609
 
8026
8610
  return (
8027
- <ScrollView contentContainerStyle={styles.container}>
8028
- <Image
8029
- source={{ uri: song.imageUrl }}
8030
- style={styles.image}
8031
- />
8032
- <ThemedText type="title">
8033
- {song.title}
8034
- </ThemedText>
8035
- <ThemedText dimmed type="subtitle">
8036
- {song.genre}
8037
- </ThemedText>
8038
- <ThemedText>
8039
- {song.duration}
8040
- </ThemedText>
8041
- <PlayerControls />
8042
- </ScrollView>
8043
- <ScrollView contentContainerStyle={styles.container}>
8044
- <ThemedText type="title">
8045
- Player
8046
- </ThemedText>
8047
- </ScrollView>
8611
+ +<ScrollView contentContainerStyle={styles.container}>
8612
+ +<Image
8613
+ +source={{ uri: song.imageUrl }}
8614
+ +style={styles.image}
8615
+ + />
8616
+ +<ThemedText type="title">
8617
+ +{song.title}
8618
+ +</ThemedText>
8619
+ +<ThemedText dimmed type="subtitle">
8620
+ +{song.genre}
8621
+ +</ThemedText>
8622
+ +<ThemedText>
8623
+ +{song.duration}
8624
+ +</ThemedText>
8625
+ +<PlayerControls />
8626
+ +</ScrollView>
8627
+ -<ScrollView contentContainerStyle={styles.container}>
8628
+ -<ThemedText type="title">
8629
+ - Player
8630
+ -</ThemedText>
8631
+ -</ScrollView>
8048
8632
  );
8049
8633
  }
8050
8634
 
8051
8635
 
8052
- const styles = StyleSheet.create((theme, rt) => ({
8636
+ +const styles = StyleSheet.create((theme, rt) => ({
8053
8637
  centerContainer: {
8054
8638
  flex: 1,
8055
8639
  justifyContent: 'center',
8056
8640
  alignItems: 'center'
8057
- },
8641
+ +},
8058
8642
  container: {
8059
8643
  flex: 1,
8060
8644
  gap: theme.gap(2),
8061
8645
  alignItems: 'center',
8062
8646
  marginTop: rt.insets.top + theme.gap(3),
8063
- },
8647
+ +},
8064
8648
  image: {
8065
8649
  width: 200,
8066
8650
  height: 200,
8067
8651
  borderRadius: theme.gap(2)
8068
- }
8069
- }));
8070
- const styles = StyleSheet.create((theme, rt) => ({
8652
+ +}
8653
+ +}));
8654
+ -const styles = StyleSheet.create((theme, rt) => ({
8071
8655
  container: {
8072
8656
  flex: 1,
8073
8657
  marginTop: rt.insets.top,
8074
8658
  paddingHorizontal: theme.gap(2)
8075
- },
8076
- }));
8659
+ -},
8660
+ -}));
8077
8661
  ```
8078
8662
 
8079
8663
  We use `useLocalSearchParams()` to extract the `songId` from the URL. This allows users to navigate directly to any song or bookmark specific tracks.
@@ -8084,6 +8668,8 @@ Our screen still needs one more component to be complete - the `PlayerControls`.
8084
8668
 
8085
8669
  ### Creating the PlayerControls Component
8086
8670
 
8671
+ [Section titled “Creating the PlayerControls Component”](#creating-the-playercontrols-component)
8672
+
8087
8673
  The player controls provide the interface for music playback. While they won’t actually play music in this tutorial, they give users the familiar media controls they expect in a music app.
8088
8674
 
8089
8675
  Let’s create the final component for our player interface:
@@ -8160,6 +8746,8 @@ Our settings screen will feature interactive tiles that users can tap to modify
8160
8746
 
8161
8747
  ### Create the SettingTile Component
8162
8748
 
8749
+ [Section titled “Create the SettingTile Component”](#create-the-settingtile-component)
8750
+
8163
8751
  Let’s start by creating a reusable `SettingTile` component. This component will demonstrate one of Unistyles’ coolest features: zero-config integration with `Pressable` and `PressableStateCallbackType`.
8164
8752
 
8165
8753
  Create a new file `components/SettingTile.tsx`:
@@ -8223,13 +8811,15 @@ When you press the tile, the opacity changes from `1` to `0.75`, giving users im
8223
8811
 
8224
8812
  ### Enhance ThemedText with Variants
8225
8813
 
8814
+ [Section titled “Enhance ThemedText with Variants”](#enhance-themedtext-with-variants)
8815
+
8226
8816
  You might have noticed we’re using `bold` and `dimmed` props on `ThemedText` that don’t exist yet. Let’s add them using Unistyles variants.
8227
8817
 
8228
8818
  Update your `ThemedText` component:
8229
8819
 
8230
8820
  components/ThemedText.tsx
8231
8821
 
8232
- ```tsx
8822
+ ```diff
8233
8823
  import { Text, type TextProps } from 'react-native'
8234
8824
  import { StyleSheet, type UnistylesVariants } from 'react-native-unistyles'
8235
8825
 
@@ -8240,14 +8830,14 @@ export type ThemedTextProps = TextProps & UnistylesVariants<typeof styles>
8240
8830
  export function ThemedText({
8241
8831
  style,
8242
8832
  type,
8243
- bold,
8244
- dimmed,
8833
+ +bold,
8834
+ +dimmed,
8245
8835
  ...rest
8246
8836
  }: ThemedTextProps) {
8247
8837
  styles.useVariants({
8248
8838
  type,
8249
- bold,
8250
- dimmed
8839
+ + bold,
8840
+ + dimmed
8251
8841
  })
8252
8842
 
8253
8843
 
@@ -8292,13 +8882,13 @@ const styles = StyleSheet.create(theme => ({
8292
8882
  bold: {
8293
8883
  true: {
8294
8884
  fontWeight: 'bold',
8295
- }
8296
- },
8885
+ +}
8886
+ +},
8297
8887
  dimmed: {
8298
8888
  true: {
8299
8889
  color: theme.colors.tint
8300
- }
8301
- }
8890
+ +}
8891
+ +}
8302
8892
  }
8303
8893
  }
8304
8894
  }));
@@ -8310,73 +8900,77 @@ This pattern makes your components more readable and eliminates the need for mul
8310
8900
 
8311
8901
  ### Build the Settings Interface
8312
8902
 
8903
+ [Section titled “Build the Settings Interface”](#build-the-settings-interface)
8904
+
8313
8905
  Now let’s implement the actual settings screen with our new `SettingTile` component.
8314
8906
 
8315
8907
  Update your `app/settings/index.tsx`:
8316
8908
 
8317
8909
  app/settings/index.tsx
8318
8910
 
8319
- ```tsx
8320
- import { SettingTile } from '@/components/SettingTile'
8911
+ ```diff
8912
+ +import { SettingTile } from '@/components/SettingTile'
8321
8913
  import { ThemedText } from '@/components/ThemedText'
8322
- import { ScrollView, View } from 'react-native'
8323
- import { StyleSheet, UnistylesRuntime } from 'react-native-unistyles'
8324
- import { ScrollView } from 'react-native'
8325
- import { StyleSheet } from 'react-native-unistyles'
8914
+ +import { ScrollView, View } from 'react-native'
8915
+ +import { StyleSheet, UnistylesRuntime } from 'react-native-unistyles'
8916
+ -import { ScrollView } from 'react-native'
8917
+ -import { StyleSheet } from 'react-native-unistyles'
8326
8918
 
8327
8919
 
8328
8920
  export default function SettingsScreen() {
8329
- const systemTheme = UnistylesRuntime.hasAdaptiveThemes
8921
+ +const systemTheme = UnistylesRuntime.hasAdaptiveThemes
8330
8922
 
8331
8923
 
8332
8924
  return (
8333
- <ScrollView contentContainerStyle={styles.container}>
8334
- <ScrollView contentContainerStyle={styles.scrollView}>
8925
+ -<ScrollView contentContainerStyle={styles.container}>
8926
+ +<ScrollView contentContainerStyle={styles.scrollView}>
8335
8927
  <ThemedText type="title">
8336
- Settings
8337
- Appearance
8928
+ - Settings
8929
+ + Appearance
8338
8930
  </ThemedText>
8339
- <View style={styles.settingsContainer}>
8340
- <SettingTile
8341
- settingName="Theme"
8342
- selectedValue="Light"
8343
- description={systemTheme ? 'System' : 'User'}
8344
- onPress={() => {}}
8345
- />
8346
- <SettingTile
8347
- settingName="App accent"
8348
- selectedValue="Default"
8349
- description="Primary app color"
8350
- onPress={() => {}}
8351
- />
8352
- </View>
8931
+ +<View style={styles.settingsContainer}>
8932
+ +<SettingTile
8933
+ +settingName="Theme"
8934
+ +selectedValue="Light"
8935
+ +description={systemTheme ? 'System' : 'User'}
8936
+ +onPress={() => {}}
8937
+ + />
8938
+ +<SettingTile
8939
+ +settingName="App accent"
8940
+ +selectedValue="Default"
8941
+ +description="Primary app color"
8942
+ +onPress={() => {}}
8943
+ + />
8944
+ +</View>
8353
8945
  </ScrollView>
8354
8946
  );
8355
8947
  }
8356
8948
 
8357
8949
 
8358
- const styles = StyleSheet.create((theme, rt) => ({
8359
- scrollView: {
8360
- marginTop: rt.insets.top + theme.gap(3),
8361
- backgroundColor: theme.colors.background,
8362
- paddingHorizontal: theme.gap(2)
8363
- },
8364
- settingsContainer: {
8365
- marginTop: theme.gap(4),
8366
- gap: theme.gap(4)
8367
- },
8368
- }));
8369
- const styles = StyleSheet.create((theme, rt) => ({
8370
- container: {
8371
- flex: 1,
8372
- marginTop: rt.insets.top,
8373
- paddingHorizontal: theme.gap(2)
8374
- },
8375
- }));
8950
+ + const styles = StyleSheet.create((theme, rt) => ({
8951
+ + scrollView: {
8952
+ + marginTop: rt.insets.top + theme.gap(3),
8953
+ + backgroundColor: theme.colors.background,
8954
+ + paddingHorizontal: theme.gap(2)
8955
+ + },
8956
+ + settingsContainer: {
8957
+ + marginTop: theme.gap(4),
8958
+ + gap: theme.gap(4)
8959
+ + },
8960
+ +}));
8961
+ - const styles = StyleSheet.create((theme, rt) => ({
8962
+ - container: {
8963
+ - flex: 1,
8964
+ - marginTop: rt.insets.top,
8965
+ - paddingHorizontal: theme.gap(2)
8966
+ - },
8967
+ -}));
8376
8968
  ```
8377
8969
 
8378
8970
  ### UnistylesRuntime vs rt Object
8379
8971
 
8972
+ [Section titled “UnistylesRuntime vs rt Object”](#unistylesruntime-vs-rt-object)
8973
+
8380
8974
  Here’s where things get interesting. Notice we’re using `UnistylesRuntime.hasAdaptiveThemes` instead of accessing it through `rt`.
8381
8975
 
8382
8976
  **What’s the difference?**
@@ -8404,6 +8998,8 @@ Learn more about `UnistylesRuntime` in the [dedicated guide](/v3/references/unis
8404
8998
 
8405
8999
  ### ScrollView Background Issue
8406
9000
 
9001
+ [Section titled “ScrollView Background Issue”](#scrollview-background-issue)
9002
+
8407
9003
  Try switching between light and dark themes in your app. You’ll notice something odd - the `ScrollView` background color doesn’t update! This is because `contentContainerStyle` is not a regular style prop that Unistyles can automatically track.
8408
9004
 
8409
9005
  For such cases we created `withUnistyles` higher-order component (HOC) that allows you to wrap any component and automatically re-render it, depending on it’s dependencies.
@@ -8416,15 +9012,15 @@ In order to update background color of `ScrollView`, we need to wrap it with `wi
8416
9012
 
8417
9013
  app/settings/index.tsx
8418
9014
 
8419
- ```tsx
9015
+ ```diff
8420
9016
  import { SettingTile } from '@/components/SettingTile'
8421
9017
  import { ThemedText } from '@/components/ThemedText'
8422
9018
  import { ScrollView, View } from 'react-native'
8423
- import { StyleSheet, UnistylesRuntime } from 'react-native-unistyles'
8424
- import { StyleSheet, UnistylesRuntime, withUnistyles } from 'react-native-unistyles'
9019
+ -import { StyleSheet, UnistylesRuntime } from 'react-native-unistyles'
9020
+ +import { StyleSheet, UnistylesRuntime, withUnistyles } from 'react-native-unistyles'
8425
9021
 
8426
9022
 
8427
- const StyledScrollView = withUnistyles(ScrollView)
9023
+ +const StyledScrollView = withUnistyles(ScrollView)
8428
9024
 
8429
9025
 
8430
9026
  export default function SettingsScreen() {
@@ -8432,8 +9028,8 @@ export default function SettingsScreen() {
8432
9028
 
8433
9029
 
8434
9030
  return (
8435
- <ScrollView contentContainerStyle={styles.scrollView}>
8436
- <StyledScrollView contentContainerStyle={styles.scrollView}>
9031
+ -<ScrollView contentContainerStyle={styles.scrollView}>
9032
+ +<StyledScrollView contentContainerStyle={styles.scrollView}>
8437
9033
  <ThemedText type="title">
8438
9034
  Appearance
8439
9035
  </ThemedText>
@@ -8451,8 +9047,8 @@ export default function SettingsScreen() {
8451
9047
  onPress={() => {}}
8452
9048
  />
8453
9049
  </View>
8454
- </ScrollView>
8455
- </StyledScrollView>
9050
+ -</ScrollView>
9051
+ +</StyledScrollView>
8456
9052
  );
8457
9053
  }
8458
9054
 
@@ -8479,16 +9075,18 @@ Remember these key points about `withUnistyles`:
8479
9075
 
8480
9076
  ### Add Modal Navigation
8481
9077
 
9078
+ [Section titled “Add Modal Navigation”](#add-modal-navigation)
9079
+
8482
9080
  Finally, let’s wire up the `onPress` callbacks to navigate to our modal screens:
8483
9081
 
8484
9082
  app/settings/index.tsx
8485
9083
 
8486
- ```tsx
9084
+ ```diff
8487
9085
  import { SettingTile } from '@/components/SettingTile'
8488
9086
  import { ThemedText } from '@/components/ThemedText'
8489
9087
  import { ScrollView, View } from 'react-native'
8490
9088
  import { StyleSheet, UnistylesRuntime } from 'react-native-unistyles'
8491
- import { router } from 'expo-router'
9089
+ +import { router } from 'expo-router'
8492
9090
 
8493
9091
 
8494
9092
  const StyledScrollView = withUnistyles(ScrollView)
@@ -8508,15 +9106,15 @@ export default function SettingsScreen() {
8508
9106
  settingName="Theme"
8509
9107
  selectedValue="Light"
8510
9108
  description={systemTheme ? "System" : 'User'}
8511
- onPress={() => {}}
8512
- onPress={() => router.push('/(tabs)/settings/settings-theme')}
9109
+ -onPress={() => {}}
9110
+ +onPress={() => router.push('/(tabs)/settings/settings-theme')}
8513
9111
  />
8514
9112
  <SettingTile
8515
9113
  settingName="App accent"
8516
9114
  selectedValue="Default"
8517
9115
  description="Primary app color"
8518
- onPress={() => {}}
8519
- onPress={() => router.push('/(tabs)/settings/settings-accent')}
9116
+ -onPress={() => {}}
9117
+ +onPress={() => router.push('/(tabs)/settings/settings-accent')}
8520
9118
  />
8521
9119
  </View>
8522
9120
  </StyledScrollView>