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

LinearGradient component #73

Closed
nandorojo opened this issue Feb 11, 2021 · 10 comments
Closed

LinearGradient component #73

nandorojo opened this issue Feb 11, 2021 · 10 comments

Comments

@nandorojo
Copy link
Owner

I recently came across this beautiful landing page from auth0: https://auth0.design/

It included these cool gradients:

Screen Shot 2021-02-11 at 11 06 28 AM

Which reminded me of this webflow theme I used for the doorman.cool website:

Screen Shot 2021-02-11 at 11 09 04 AM

It would be cool to have a LinearGradient component in Dripsy, which re-exports Expo's.

import { LinearGradient } from '@dripsy/gradient'

// theme colors
<LinearGradient colors={['primary', 'accent']} />

Maybe you could even have gradients in your theme.

const theme = {
  linearGradients: {
    strong: ['primary', 'secondary']
  }
}

<LinearGradient variant="strong" />

The variant prop might not be the right one to use here, since we're technically not applying a set of styles, but rather we're using an opinionated mapping of colors -> props.

This might be more appropriate:

const theme = {
  linearGradients: {
    strong: ['primary', 'secondary']
  }
}

<LinearGradient gradient="strong" />
@cmaycumber
Copy link
Contributor

This is super cool. It'd be instantly useful for me, I'm currently using a dripsy + expo-linear-gradient combo myself.

Mind if I take a crack at this? I can also add in a re-exported Pressable component while I'm at it.

@nandorojo
Copy link
Owner Author

Definitely, go for it.

This is what I'm using in my app now:

import React from 'react'
import { LinearGradient } from 'expo-linear-gradient'
import { styled, useDripsyTheme } from 'dripsy'
type Props = React.ComponentProps<typeof LinearGradient>

const Grad = styled(
  React.memo(
    function Gradient(props: Props) {
      const { colors } = useDripsyTheme().theme
      return (
        <LinearGradient
          {...props}
          colors={props.colors?.map(
            (color) => (colors?.[color] as string) ?? color
          )}
        />
      )
    },
    (prev, next) => JSON.stringify(prev) === JSON.stringify(next)
  )
)({})

export default function Gradient(props: React.ComponentProps<typeof Grad>) {
  return <Grad {...props} />
}

The memoizing might not be necessary, but I noticed flickers on web when I didn't do it. Might be better for people to do that in their own apps if they want it and to document it.

Since we're adding a dependency, I think it would be good to make this a @dripsy/gradient package. It might also mean we should move styled etc to a @drispy/core package, the way I did for moti.

@nandorojo
Copy link
Owner Author

nandorojo commented Feb 11, 2021

I've had issues with wrapping Pressable. Its TS types don't lend themselves well to HOCs, so I think we're best off making our own component for it. I think I linked to mine in another issue, but this is it for context:

import React, { ReactNode, ComponentProps } from 'react'
import { styled } from 'dripsy'
import {
  Pressable as NativePressable,
  PressableStateCallbackType,
  ViewStyle,
} from 'react-native'
 
declare module 'react-native' {
  interface PressableStateCallbackType {
    hovered?: boolean
    focused?: boolean
  }
}

type CallbackWithHovered = PressableStateCallbackType
const StyledPressable = styled(NativePressable)({})


// I think we can remove this in favor of  type Props = ComponentProps<typeof StyledPressable>
type Props = {
  style?: ((prop: CallbackWithHovered) => ViewStyle) | ViewStyle
  children?: ReactNode | ((prop: CallbackWithHovered) => ReactNode)
} & Omit<ComponentProps<typeof StyledPressable>, 'children' | 'style'>

const Press = React.forwardRef(function Pressable(
  { sx = {}, disabled, ...props }: Props,
  ref: ComponentProps<typeof NativePressable>['ref']
) {
  return (
    <StyledPressable
      {...props}
      ref={ref as any}
      disabled={disabled}
      sx={{
        cursor:
          props.onPress || props.accessibilityRole === 'link' || !disabled
            ? 'pointer'
            : 'default',
        ...sx,
      }}
    />
  )
})

export default Press

Should probably add a Platform.select for the cursor style, such that we only show it on web.

I think now that I added declaration merging, the custom props can be deleted. We should be able to just forward the exact StyledPressable props.

@cmaycumber
Copy link
Contributor

Since we're adding a dependency, I think it would be good to make this a @dripsy/gradient package. It might also mean we should move styled etc to a @drispy/core package, the way I did for moti.

Got it.

@cmaycumber
Copy link
Contributor

Alright, I'll try to make your code the basis for the pressable component and check out that other issue. We can always tweak as we go.

@nandorojo
Copy link
Owner Author

One last thing, which is unrelated but I'm seeing on the Pressable code. Our current types for the ref prop in createThemedComponent are wrong. I'm forced to pass as any whenever I pass a ref down.

@cmaycumber
Copy link
Contributor

How do you think we should start breaking up the main dripsy package into smaller packages? I think that's the first PR I'm going to handle so that it's a little more flexible.

Do you think we should take the current dripsy package and move all of that into @dripsy/core or break that out further? Into something like @dripsy/css, @dripsy/utils, etc.

@cmaycumber
Copy link
Contributor

Do you think the gradient prop should replace the color prop entirely? I don't know what the best move would be here is, Otherwise, either the gradient or the colors object needs to take precedence, if we choose this way I think the colors prop should probably take precedence.

So it could be used like:

const theme = {
  linearGradients: {
    strong: ['primary', 'secondary']
  }
}

<LinearGradient gradient="strong" />
// or
<LinearGradient gradient={['primary', 'secondary']} />

Let me know what you think.

@nandorojo
Copy link
Owner Author

Similar to what you said, here's what I think makes sense:

const theme = {
  linearGradients: {
    strong: ['primary', 'secondary']
  }
}

// these are equivalent
<LinearGradient gradient="strong" />
<LinearGradient colors={['primary', 'secondary']} />

// colors prop takes precedence
<LinearGradient gradient="strong"  colors={['accent', 'highlight']}  />

@cmaycumber
Copy link
Contributor

Got it. That's how I'm currently handling it.

I have this just about done along with another branch for the pressable component if we can get #74 merged in.

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