Skip to content

Releases: jpudysz/react-native-unistyles

Release 2.10.0

02 Oct 07:48
Compare
Choose a tag to compare

2.10.0 (2024-10-02)

Features

  • [Core] add support for React Native 0.76 (764ae9d)
  • [Core] get theme by name (e5026b8)
UnistylesRuntime.getTheme() // <-- get current theme
UnistylesRuntime.getTheme('dark') // <-- get theme by name

Theme returned from UnsityelsRuntime will reflect all changes you made with UnistylesRuntime.updateTheme, so it's better than importing theme from file.

  • [Web] Migrate from webpack to metro, upgrade expo example to 0.75.3 (e99d65a)
  • [Android] Prevent keyboard controller to report new ime insets when listener is disabled (7f0ccc4)

This works well with following setting:

UnistylesRegistry
    .addConfig({
        disableAnimatedInsets: true
    })
  • [Android] Upgrade cmake (422293a)

Bug Fixes

  • [iOS] Set root view background color on ui thread (a3b7b0f)

Release 2.9.2

30 Aug 12:11
Compare
Choose a tag to compare

2.9.2 (2024-08-30)

This is a small release that addresses some issues.

  • Thanks to @LeeMoonki, Unistyles 2.9.2 again supports React Native 0.72!
  • Unistyles will now reject transform with undefined values
<View
  style={{
    transform: [
       { scale: undefined }
    ]
  }}
/>

This used to work in the past but was changed in the React Native core. Developers can easily reproduce this issue when using, for example, media queries or breakpoints.

  • Disabling bottom inset animations

Some users reported poor performance and unnecessary re-renders when Unistyles attempted to animate the values of insets.bottom on Android (eg. when toggling keyboard).

This default behavior can now be disabled using UnistylesRegistry:

UnistylesRegistry
  .addConfig({
    disableAnimatedInsets: true // android only
 })

Features

  • [Android] - add support back for React Native 0.72 - fix JSI issue (21301cf) by @LeeMoonki
  • [Android] add option to disable animated insets (908fdd2)
  • [Core] remove undefined transforms (6d6245b)

Docs

  • Improve warning about issues with TS when registering different theme shapes (d0a76f2) by @404mat

Release 2.9.1

31 Jul 13:03
Compare
Choose a tag to compare

2.9.1 (2024-07-31)

This is a small update with a few improvements from the community!

  • Detecting RTL on the web is now dynamic and doesn't require a page reload
  • Fixed a race condition for iOS core, where reading values from UnistylesRuntime could return default values

Features

Release 2.9.0

20 Jul 11:37
Compare
Choose a tag to compare

2.9.0 (2024-07-20)

‼️ Plugins have been deprecated and will be removed in the Unistyles 3.0.

Use hairlineWidth and rtl in UnistylesRuntime and miniRuntime:

const stylesheet = createStyleSheet((theme, rt) => ({
  container: {
    backgroundColor: theme.colors.background,
    borderBottomWidth: rt.hairlineWidth, // the thinnest visible width on the platform
    justifyContent: rt.rtl ? 'flex-end' : 'flex-start' // detects if user prefers RTL or LTR direction
  }
}))

Features

  • [Core] add support for rtl (ea128f5)
  • [TypeScript] export UniStyle(View|Text|Image) types (c779713) by @yzhe554
  • [Core] implement hairlinewidth (c6913ef)

Deprecation

  • [Core] Deprecate plugins (2bddd97)

Bug Fixes

Docs

  • [Docs] Mention KeyboardAvoidingView with edge to edge layout 4fdccfa

Release 2.8.4

15 Jul 12:07
Compare
Choose a tag to compare

2.8.4 (2024-07-15)

Features

  • [Android] animate bottom insets on keyboard transition (bd9c4a1)
  • [C++] remove dynamicTypeSize event (df65dba)

Bug fixes

  • [Android] update screen height with edge to edge layout (4fdf92d)

Docs

  • [Docs] mention eslint-plugin-react-native-unistyles (612f786)

Release 2.8.3

08 Jul 14:27
Compare
Choose a tag to compare

2.8.3 (2024-07-08)

Features

  • add mini runtime to mocks (f7f003e)

Release 2.8.2

05 Jul 13:55
Compare
Choose a tag to compare

2.8.2 (2024-07-05)

Features

  • [Android] improve bottom insets when keyboard is visible (1b98797)
  • [iOS] improve parsing transparent color (c018b33)

Release 2.8.1

27 Jun 15:55
Compare
Choose a tag to compare

2.8.1 (2024-06-27)

Features

  • [Web] allow disabling debouncing for window resize event (f8d94c3)
UnistylesRegistry
    .addConfig({
         // disables debouncing for window resize event (web only)
         windowResizeDebounceTimeMs: 0
    })

Bug Fixes

  • [iPad] avoid computing incorrect screen sizes when the app is backgrounded (f224852) by @vanstinator
  • [Core] parse fontScale back to float after rounding (268e2cb)

Docs

  • [Docs] mention keyboard controller that can interfere with Android insets (1ad0616)

Release 2.8.0

25 Jun 10:52
Compare
Choose a tag to compare

2.8.0 (2024-06-25)

Introducing Unistyles 2.8.0 - the biggest upgrade since version 2.0! This version introduces many new features with backward compatibility and no breaking changes! (still works with React Native 0.73 and Expo SDK 50).

New core

Sometimes it’s hard to move forward and add new features, especially when the code was designed for Unistyles 2.0, which started with two platforms (iOS, Android) and ended up including all possible React Native targets: iOS, Android, tvOS, Windows, macOS, and even visionOS. Additionally, with new architecture in beta, which will stabilize with React Native 0.75 later this year, it’s possible to finally drop some boilerplate and move to pure C++ Turbo Modules.

If you have followed my work for a long time, you know that Unistyles is built on top of a C++ core, which is the heart of the library. That’s why Unistyles 2.8.0 started to transition to a pure C++ TurboModule, and I plan a full conversion later this year. From your perspective, it won’t change anything, but from a core contributor's perspective, maintaining Unistyles will be easier.

The new core is also more friendly for new contributors. Each platform has its own file with atomic functions to get some platform info like getInsets or getScreenDimensions. Also, as of now, every platform API is optional , with the use of C++ std::optional, it means that adding a new exclusive API for Android has no impact on iOS, as iOS won’t implement this method.

The big rewrite is also a big win for package size. I was able to significantly reduce the number of lines and be smart about sharing library logic that is similar across other platforms.

Android Insets

Android insets are difficult to handle. Google has introduced many APIs across different API levels, and there are numerous ways to manage them. In the past, Unistyles implemented a custom algorithm to handle dynamic insets. It was somewhat similar to react-native-safe-area-context, but I was listening to different events and had to apply ugly debouncing for insets reported by the system. This approach introduced several issues created by developers. That’s why I had to switch to the one and only viable solution, which is the WindowInsetsCompat API!

Here is a great introduction by Alex Vanyo, a Developer Relations Engineer at Google—I strongly encourage you to watch it (it’s 6 minutes long). Alex said during the video:

(…) querying for an internal system resource to get the status bar height or navigation bar height will lead to awkward extra spacing in the best case or make components impossible to interact with in the worst case.

I strongly agree with him, which is why Unistyles shifts the responsibility for insets to Android itself. Of course, it’s not that easy to query a magical API and get everything right. That’s why Unistyles uses many other techniques to get them correct, for example:

  • Handling insets in headless mode (when the app opens from a Push Notification)
  • Handling React Native StatusBar translucent/hidden events, as they do not use window flags
  • Managing other cases when developers want to hide the navigation bar or use old 3-button navigation

Also, insets are now reported correctly on the first render, so you won’t see weird jumps in the UI when the system reports new insets!

EdgeToEdge by default

Using WindowInsetsCompat requires your layout to be edgeToEdge. In other words, it means that your StatusBar is always translucent and the app can draw below the NavigationBar. A translucent status bar is also the default when you build your app with Expo. To leverage WindowInsetsCompat, Unistyles enables it by default.

It’s worth mentioning that from Android 15, the edgeToEdge layout will likely be enabled by default. You can read more about this development here: Android 15 Apps Could Be Forced to Display Edge-to-Edge by Google.

Normal layout vs. EdgeToEdge layout:

e2e-intro

I’m eager to hear your feedback about the new Insets API!

Emitting Events from C++

It’s also worth mentioning that Unistyles is now capable of emitting events directly from C++, without the Kotlin and Objective-C proxies! I was able to remove several hundred lines of repetitive code for each platform and simply emit events directly from the core.

iPads / Android Tablets / Foldables

Unistyles now correctly handles resizing windows in multitasking mode (when two apps are displayed side by side). This update also includes support for foldables, such as the Samsung Galaxy Fold!

xxx

Pixel Density and Font Scale

UnistylesRuntime now exposes the fontScale and pixelRatio values:

UnistylesRuntime.fontScale // e.g., 1.3
UnistylesRuntime.pixelRatio // e.g., 2.0

Additionally, on Android, the pixelRatio is taken into account to correctly return window dimensions. You can change your display settings with accessibility option

New StatusBar and NavigationBar APIs

UnistylesRuntime.statusBar and UnistylesRuntime.navigationBar can now be hidden or shown directly with Unistyles. Using these methods ensures that insets will be calculated correctly down to SDK 23 (Android 6.0). Using the expo-navigation-bar API for older Android versions exposes some discrepancies in insets, as shown below:

Expo API - works correctly for recent SDKs, but has some issues on older Androids:

image 2

With Unistyles:

2

NavigationBar and StatusBar Now Accept Alpha Colors

From Unistyles 2.6.0, you can set the color of the StatusBar and NavigationBar. Unfortunately, the colors accepted by default on Android are quite limited. That's why Unistyles now calculates opacity with a super easy API, allowing you to display transparent colors:

UnistylesRuntime.statusBar.setColor('#000000', 0.5) // 6 digits hex with opacity 0 to 1
UnistylesRuntime.statusBar.setColor('#50000000') // 8-digits hex
UnistylesRuntime.navigationBar.setColor('red') // some Android reserved words

Immersive mode

UnistylesRuntime has gained another new API to enable immersive mode. In immersive mode, you can easily hide both the StatusBar and NavigationBar to display your app content fully. This can be especially useful for movies, photo galleries, or other content that requires an edgeToEdge experience:

UnistylesRuntime.setimmersiveMode(true) // or false to go back to regular UI

Root View background color

You can also change your Root View's background color based on your themes without leaving the library! This API is cross-platform and easy to use:

UnistylesRuntime.setRootViewBackgroundColor('#c2c2c2') // API also accepts opacity

Introducing mini runtime

For convenience, Unistyles was injecting UnistylesRuntime as an optional second parameter in the createStyleSheet function:

const stylesheet = createStylesheet((theme, rt) => ({
    container: {
         flex: 1,
         paddingTop: rt.insets.top,
         paddingBottom: rt.insets.bottom
    }
}))

However, rt was cluttered with a full list of APIs such as setTheme or addPlugin, which don’t make sense to be used directly in your stylesheet. From now on, Unistyles injects a mini runtime containing only the most important values:

mini

I hope this will make it easier for you to select the required values!

Infer variants types

This feature was requested by several developers, and I'm happy to announce that you can now infer your variants type without manually specifying all the props! Sometimes it’s easier to show than to explain, so please check out the example with the before and after results:

Before: (you need to specify all the props yourself):

interface TypographyProps extends React.PropsWithChildren, TextProps {
    style?: TextStyle,
    weight?: 'heavy' | 'regular' | 'light',
    type?: 'heading' | 'subheading' | 'button' | 'title' | 'subtitle' | 'regular' | 'label'
}

export const Typography: React.FunctionComponent<TypographyProps> = props => {
    const { styles, theme } = useStyles(stylesheet, {
        weight: props.weight || 'light',
        type: props.type || 'regular',
        alignCenter: props.isCentered
    })

     // your JSX
}

After: (much, much cleaner):

import { UnistylesVariants } from 'react-native-unistyles'

interface TypographyProps extends React.PropsWithChildren, TextProps, UnistylesVariants<typeof stylesheet> {
    style?: TextStyle
}

export const Typography: React.FunctionComponent<TypographyProps> = props => {
    const { styles, theme } = useStyles(stylesheet, {
        weight: props.weight || 'light',
        type: props.type || 'regular',
        alignCenter: props.isCentered
    })

     // your JSX
}

Summary

Thank you for sticking with Unistyles, which is gaining more and more popularity. I can assure you that I’m spending countless hours making the API stable and thinking...

Read more

Release 2.8.0-rc.6

25 Jun 06:15
Compare
Choose a tag to compare
Release 2.8.0-rc.6 Pre-release
Pre-release

2.8.0-rc.6 (2024-06-25)

Features

  • add support for macos and RN 0.73 (671fede)