What's Changed
A minor release with one breaking change: UnistylesRuntime.themeName now always returns the app theme. It also adds support for React Native 0.88's new style props and a Unistyles track in DevTools performance traces. Fixes cover keyboard insets in Android Modals, a duplicate copy of Unistyles in Expo bundles, Next.js server components, Reanimated styles in withUnistyles, and the Babel plugin's dependency tracking.
⚠️ Breaking change
UnistylesRuntime.themeNamenow always returns the app theme, likeUnistylesRuntime.getTheme(). Before, inside aScopedThemeit returned the scoped name only on renders that went through theScopedTheme. When a component re-rendered on its own or read it in a callback, it got the app theme.UnistylesRuntimeis global and can't read React Context, so it can't follow the scope reliably. To read the scoped theme name, useuseUnistyles().rt.themeNameorwithUnistyles(#1346, closes #1295)
// before 3.7.0, inside a ScopedTheme
const themeName = UnistylesRuntime.themeName
// 3.7.0
const { rt } = useUnistyles()
const themeName = rt.themeName✨ New
- React Native 0.88 style props work on native and web: the object form of
fontVariationSettings({ wght: 900 }) and arrays forbackgroundSize,backgroundPositionandbackgroundRepeat. Before, the objects and arrays were dropped because the parser read them as breakpoints, and the string forms were lost after the first theme or breakpoint change (#1338) - Unistyles now has its own "Unistyles" track in React Native DevTools performance traces (React Native 0.86+, development builds only). It shows StyleSheet creation, dependency updates, shadow tree commits and refreshes, so you can read a slow theme switch straight from the Performance panel. Before, Unistyles commits showed up on the Renderer track as
source: Unknown(#1332)
🎨 Themes and styles
rt.themeNamein a StyleSheet inside aScopedThemestays scoped after styles are rebuilt (rotation, breakpoint or theme change). Before, it switched to the app theme whilethemestayed scoped (#1346)- Adaptive themes keep following the OS after a
ScopedThemesuspends (#1346) - After a theme change, a plain view sharing a style with a
withUnistylescomponent (e.g.styles.rooton both a wrappedScrollViewand aView) no longer shows the previous theme (#1335 by @rladnjs705, closes #1317) withUnistyles(Animated.View)no longer breaks styling when its style array contains auseAnimatedStyleresult, on native and web. This had been broken since 3.0.0 (#1345, closes #1309)- Styles created by spreading a unistyle into another
StyleSheet.create(e.g.@rexovolt/react-native-markdown-display) no longer throwValue is undefined, expected an Object. This had been broken since 3.5.0 (#1341, closes #1337)
🧩 Babel plugin
- Styles that return a ternary or a logical expression now track their dependencies on every branch. Before, they kept their first value, e.g.
(compact) => compact ? { fontSize: 14 * rt.fontScale } : { fontSize: 18 * rt.fontScale }ignored font scale changes, even thoughdebug: truesaid the dependency was tracked. Withdebug: true, the plugin now warns when it finds dependencies but can't attach them to the returned style (#1344, closes #1314)
🚇 Metro and bundling
- In a default Expo app, Metro bundled two copies of Unistyles (
lib/moduleandsrc), soScopedThemedidn't reach children that mount later.react-nativenow comes beforeimportin the packageexports, so native resolves to a single copy. Web, Node/SSR and Jest resolve as before (#1307 by @budaestew, closes #1306) - With the experimental Metro integration, libraries that subclass a React Native class component (e.g.
react-native-pdfextendingFlatList) no longer crash on load withObject is not a constructor(#1340, closes #1324)
🤖 Android
rt.insets.imenow follows the keyboard inside a<Modal>on Android 11+ (React Native 0.86+). It resets to0when the Modal closes with the keyboard up.UnistylesRuntime.statusBar.setHiddenandnavigationBar.setHiddennow apply to open Modals too, anduseUnistyles().rt.insets.imeupdates with the keyboard, like on iOS (#1331, closes #810)- Unistyles reads the React Native version at build time. If Gradle prints
🦄 Unistyles: React Native not found, setREACT_NATIVE_NODE_MODULES_DIRin your rootbuild.gradle
- Unistyles reads the React Native version at build time. If Gradle prints
- The
Bridgeless doesn't support CatalystInstancewarning no longer appears on init, and Unistyles works withUNSTABLE_ENABLE_MINIFY_LEGACY_ARCHITECTURE. Android now uses theCallInvokerfrom the bindings installer, like iOS (#1330)
🌐 Web and SSR
- Importing Unistyles from a Next.js App Router server component (the setup from the SSR guide) no longer throws
createContext is not a function. This had been broken since 3.5.2 (#1301 by @bayasdev) - With
CSSVars: false,setThemeno longer skips a real theme change, and StyleSheets outside aScopedThemeno longer pick up a leftover scope (#1346)
🃏 Jest
- Importing
react-native-unistyles/web,/diagnosticsor/components/native/*under the Jest mocks no longer throwsStyleSheet.addChangeListener is not a function(#1342, closes #1339) - The
withUnistylesmock now resolvesuniPropsand merges it like the real implementation. Before, the component gotuniPropsas a raw function prop (#1336 by @mayuriphad, closes #1318)
📚 Docs
react-native-edge-to-edgeis deprecated. The docs now point to React Native's built-inedgeToEdgeEnabled=trueGradle property (#1326)
🧪 Internal
- A Next.js App Router e2e runs in CI against the packed package, in both
next devandnext start(#1302 by @bayasdev) - Example apps updated to React Native 0.88 and Expo SDK 58 (#1325)
❤️ Contributors
Thanks to everyone who sent a PR for this release:
And to those whose PRs and reports shaped the fixes:
- @mvanhorn (#1343), whose PR also addressed the
themeNamescope - @Mohamed-kassim, @slvvn, @rladnjs705, @Rexogamer, @ryanlntn, @facundofernandez, @bladeSk for detailed bug reports
Full Changelog: v3.6.0...v3.7.0