Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dripsy v1 release notes #34

Closed
3 tasks done
nandorojo opened this issue Sep 23, 2020 · 3 comments
Closed
3 tasks done

Dripsy v1 release notes #34

nandorojo opened this issue Sep 23, 2020 · 3 comments

Comments

@nandorojo
Copy link
Owner

nandorojo commented Sep 23, 2020

Dripsy v1 has a number of exciting additions, some minor breaking changes, and styling differences. I'm calling it v1 so that it's clear that there are major changes to the expected web behavior – namely that it works with SSR and has an escape hatch.

To use it before it's released, use yarn add dripsy@fresnel-2. Please test it out and report any issues you find which aren't specified in this doc.

Dripsy for iOS and Android is basically untouched by this update. If you use Dripsy on web, this update is very relevant.

I recommend reading #19 and #14 for context.

[feature] SSR Support

This section describes how the new web behavior works on Dripsy, and why it works for server side rendering. At the very least, check out "changes in web behavior" below.

Dripsy now fully supports SSR. Please refer to the readme for the simple installation steps.

  • Next.js tested
  • Normal RNW tested
  • Gatsby tested (coming soon)

Ever since React Native Web deprecated the classname, the path to responsive styles built in React Native has been a challenge. Without the className prop, we can only use JS dimensions to determine which media breakpoint to display. This is the right direction for the ecosystem in general – JS-based styles that are consistent on all platforms.

However, JS-only dimensions don't work with SSR, since the server doesn't know the screen size with certainty.

The solution used in this update is to wrap every responsive element rendered on the web with a div at each breakpoint.

To see how this is achieved, please refer to the docs for Fresnel.

If your app has 4 breakpoints, then your component will be rendered 4 times next to each other, each time with a div wrapping it. We require a div so that we can use CSS.

Each div's children conditionally render depending on the how big the screen size is. The first paint, which can occur on the server, renders every breakpoint. We rely on the CSS className for each div to hide ones from the wrong breakpoint. Once the div has mounted, it unmounts its children if their styles don't fit the current breakpoint. This is achieved thanks to Fresnel, and was tested extensively at #14, #19, #13.

The benefit of this approach is that there is no flash of unstyled content. We use CSS on the first paint, and the match-media API afterwards.

Even though each component renders multiple times, the div containing it unmounts its children when it needs to. This means that useEffect and other asynchronous effects still only run once, as intended. While this does result in many more DOM nodes, it's been stress tested in real-world apps with great performance.

[important] Changes in web behavior

This section is very important, if you're upgrading I recommend reading it.

This section discusses the webContainerSx prop addition. This prop is an escape hatch for the occasional unintended web behavior for flexbox and percentage widths.

TLDR: If you find that your flex or width values aren't working properly on web, try adding the styles to the webContainerSx prop.

Ok, onto the explanation.

It is important to understand what it means that we will be using @artsy/fresnel, as mentioned in the SSR explanation above. When we have responsive styles on web, we are wrapping our React Native element with a div. This means that sometimes, your styles might not show work.

Basically, this only matters for things like percentage widths and flexbox stretching. The times it matters are rare, but they're non-zero, so I'm going to explain in detail.

Take this example. What do you think this should look like?

<View sx={{ flexDirection: 'row', height: 500 }}>
  <View sx={{ bg: 'blue', height: '100%', flex: [1] }} />
  <View sx={{ bg: 'red', height: '100%', flex: [1] }} />
</View>

You might expect that it would look like this, right?

Frame 1 (6)

Well, turns out it doesn't, exactly.

This short video explains why: https://www.loom.com/share/997c9af614ea4b5392831bfc6db54cd0

Basically, any time you use an array style (in this case, width: [50%],) Dripsy wraps your item in a div. While wrapping your item in a div doesn't usually matter, in the case of percentage widths, flex: 1, etc., it does. Since our blue and red boxes are both wrapped with divs, and the divs don't know to stretch the container, they don't. Thus, our View is 50% width and 100% height of a div whose size is unspecified.

In those cases, you can style the container div with the webContainerSx prop, as seen in the video.

This is the solution for the example above:

<View sx={{ flexDirection: 'row', height: 500 }}>
  <View webContainerSx={{ flex: [1] }} sx={{ bg: 'blue', height: '100%', flex: [1] }} />
  <View webContainerSx={{ flex: [1] }} sx={{ bg: 'red', height: '100%', flex: [1] }} />
</View>

Here we styled the container div for web. All set!

If you never use responsive array styles, then this won't affect you. Once a component has a single array style, though, this does start to affect how it is rendered.

Rely on webContainerSx if you ever find a responsive width/responsive height/flexbox value doesn't work properly on web. And that is all!

[feature] Add styled function

This is a nicer API than createThemedComponent in my mind, and with a cooler name. They do the exact same thing though, so no need to change if you're already using createThemedComponent.

import { View } from 'react-native'
import { styled } from 'dripsy' 

const StyledView = styled(View)({
  flex: 1,
  bg: 'primary'
})

Recursively styling Dripsy components doesn't work yet, see #33 for that. For now, you can only pass native components to styled.

[feature] Add themeKey to components

const theme = {
  cards: {
   primary: {...}
  }
}

...

<View 
  themeKey="cards"
  variant="primary"
/>

Before, we had to use the createThemedComponent to give a component a themeKey.

[minor] ThemeProvider renamed to DripsyProvider

Change this in your imports after updating.

[breaking] changes

  • See the web behavior above.
  • There will soon be breaking changes for how Dripsy is initialized at the root. This will be necessary to allow custom breakpoints. Keep an eye out for this at Support custom breakpoints #25

[coming soon]

  • Custom breakpoints (this will require a breaking change)
  • JSX pragma that allows any component to be styled
  • Custom style props for custom components that accept more than just the style prop
  • Recursively create dripsy components

I'm also looking into custom theme key typescript suggestions still.

@cmaycumber
Copy link
Contributor

Does the styled function have the ability to add the themeKey and defaultVariant in a similar fashion as the createThemeComponent API or is it intended specifically for styling purposes?

@nandorojo
Copy link
Owner Author

nandorojo commented Sep 23, 2020

It does, it works functionally the exact same:

styled(Component, { themeKey, defaultVariant })({
  ...
})

The second argument of styled is optional: https://github.com/nandorojo/dripsy/blob/master/src/css/styled.tsx

I also wanted to allow a pure function that accepts props where sx is now, but I didn't manage to get that to work yet.

@nandorojo
Copy link
Owner Author

Tying to #36 to track webContainerSx bug.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants