From ae9f893723819856ff2f422a139ea199308c9b38 Mon Sep 17 00:00:00 2001
From: Eric Bailey <git@esb.lol>
Date: Fri, 16 Feb 2024 11:50:24 -0600
Subject: Some button updates (#2889)

* Some button updates

* Better name
---
 src/components/Button.tsx | 100 ++++++++++++++++++++++++++++++----------------
 1 file changed, 66 insertions(+), 34 deletions(-)

(limited to 'src/components/Button.tsx')

diff --git a/src/components/Button.tsx b/src/components/Button.tsx
index 68cee4374..e401bda2a 100644
--- a/src/components/Button.tsx
+++ b/src/components/Button.tsx
@@ -27,7 +27,7 @@ export type ButtonColor =
   | 'gradient_sunset'
   | 'gradient_nordic'
   | 'gradient_bonfire'
-export type ButtonSize = 'small' | 'large'
+export type ButtonSize = 'tiny' | 'small' | 'large'
 export type ButtonShape = 'round' | 'square' | 'default'
 export type VariantProps = {
   /**
@@ -48,25 +48,32 @@ export type VariantProps = {
   shape?: ButtonShape
 }
 
-export type ButtonProps = React.PropsWithChildren<
-  Pick<PressableProps, 'disabled' | 'onPress'> &
-    AccessibilityProps &
-    VariantProps & {
-      testID?: string
-      label: string
-      style?: StyleProp<ViewStyle>
-    }
->
-export type ButtonTextProps = TextProps & VariantProps & {disabled?: boolean}
+export type ButtonState = {
+  hovered: boolean
+  focused: boolean
+  pressed: boolean
+  disabled: boolean
+}
+
+export type ButtonContext = VariantProps & ButtonState
 
-const Context = React.createContext<
+export type ButtonProps = Pick<
+  PressableProps,
+  'disabled' | 'onPress' | 'testID'
+> &
+  AccessibilityProps &
   VariantProps & {
-    hovered: boolean
-    focused: boolean
-    pressed: boolean
-    disabled: boolean
+    testID?: string
+    label: string
+    style?: StyleProp<ViewStyle>
+    children:
+      | React.ReactNode
+      | string
+      | ((context: ButtonContext) => React.ReactNode | string)
   }
->({
+export type ButtonTextProps = TextProps & VariantProps & {disabled?: boolean}
+
+const Context = React.createContext<VariantProps & ButtonState>({
   hovered: false,
   focused: false,
   pressed: false,
@@ -277,6 +284,8 @@ export function Button({
         baseStyles.push({paddingVertical: 15}, a.px_2xl, a.rounded_sm, a.gap_md)
       } else if (size === 'small') {
         baseStyles.push({paddingVertical: 9}, a.px_lg, a.rounded_sm, a.gap_sm)
+      } else if (size === 'tiny') {
+        baseStyles.push({paddingVertical: 4}, a.px_sm, a.rounded_xs, a.gap_xs)
       }
     } else if (shape === 'round' || shape === 'square') {
       if (size === 'large') {
@@ -287,12 +296,18 @@ export function Button({
         }
       } else if (size === 'small') {
         baseStyles.push({height: 40, width: 40})
+      } else if (size === 'tiny') {
+        baseStyles.push({height: 20, width: 20})
       }
 
       if (shape === 'round') {
         baseStyles.push(a.rounded_full)
       } else if (shape === 'square') {
-        baseStyles.push(a.rounded_sm)
+        if (size === 'tiny') {
+          baseStyles.push(a.rounded_xs)
+        } else {
+          baseStyles.push(a.rounded_sm)
+        }
       }
     }
 
@@ -338,7 +353,7 @@ export function Button({
       }
     }, [variant, color])
 
-  const context = React.useMemo(
+  const context = React.useMemo<ButtonContext>(
     () => ({
       ...state,
       variant,
@@ -349,6 +364,8 @@ export function Button({
     [state, variant, color, size, disabled],
   )
 
+  const flattenedBaseStyles = flatten(baseStyles)
+
   return (
     <Pressable
       role="button"
@@ -362,15 +379,14 @@ export function Button({
         disabled: disabled || false,
       }}
       style={[
-        flatten(style),
         a.flex_row,
         a.align_center,
         a.justify_center,
-        a.overflow_hidden,
         a.justify_center,
-        ...baseStyles,
+        flattenedBaseStyles,
         ...(state.hovered || state.pressed ? hoverStyles : []),
         ...(state.focused ? focusStyles : []),
+        flatten(style),
       ]}
       onPressIn={onPressIn}
       onPressOut={onPressOut}
@@ -379,21 +395,31 @@ export function Button({
       onFocus={onFocus}
       onBlur={onBlur}>
       {variant === 'gradient' && (
-        <LinearGradient
-          colors={
-            state.hovered || state.pressed || state.focused
-              ? gradientHoverColors
-              : gradientColors
-          }
-          locations={gradientLocations}
-          start={{x: 0, y: 0}}
-          end={{x: 1, y: 1}}
-          style={[a.absolute, a.inset_0]}
-        />
+        <View
+          style={[
+            a.absolute,
+            a.inset_0,
+            a.overflow_hidden,
+            {borderRadius: flattenedBaseStyles.borderRadius},
+          ]}>
+          <LinearGradient
+            colors={
+              state.hovered || state.pressed || state.focused
+                ? gradientHoverColors
+                : gradientColors
+            }
+            locations={gradientLocations}
+            start={{x: 0, y: 0}}
+            end={{x: 1, y: 1}}
+            style={[a.absolute, a.inset_0]}
+          />
+        </View>
       )}
       <Context.Provider value={context}>
         {typeof children === 'string' ? (
           <ButtonText>{children}</ButtonText>
+        ) : typeof children === 'function' ? (
+          children(context)
         ) : (
           children
         )}
@@ -493,6 +519,8 @@ export function useSharedButtonTextStyles() {
 
     if (size === 'large') {
       baseStyles.push(a.text_md, android({paddingBottom: 1}))
+    } else if (size === 'tiny') {
+      baseStyles.push(a.text_xs, android({paddingBottom: 1}))
     } else {
       baseStyles.push(a.text_sm, android({paddingBottom: 1}))
     }
@@ -514,9 +542,11 @@ export function ButtonText({children, style, ...rest}: ButtonTextProps) {
 export function ButtonIcon({
   icon: Comp,
   position,
+  size: iconSize,
 }: {
   icon: React.ComponentType<SVGIconProps>
   position?: 'left' | 'right'
+  size?: SVGIconProps['size']
 }) {
   const {size, disabled} = useButtonContext()
   const textStyles = useSharedButtonTextStyles()
@@ -532,7 +562,9 @@ export function ButtonIcon({
         },
       ]}>
       <Comp
-        size={size === 'large' ? 'md' : 'sm'}
+        size={
+          iconSize ?? (size === 'large' ? 'md' : size === 'tiny' ? 'xs' : 'sm')
+        }
         style={[{color: textStyles.color, pointerEvents: 'none'}]}
       />
     </View>
-- 
cgit 1.4.1

