tamagui / tamagui

Style React fast with 100% parity on React Native, an optional UI kit, and optimizing compiler.
https://tamagui.dev
MIT License
10.85k stars 450 forks source link

Icons not accepting theme colors "$myColor" #1127

Closed IhsenBouallegue closed 1 year ago

IhsenBouallegue commented 1 year ago

Current Behavior

<Icon color="$myColor" />

Where Icon is any icon from lucide-icons. This produces an error. I just want the icon in my theme color (don't want a button). Here is how I'm adding my colors. Although, this problem occurs with any color defined by tamagui.

const newToken= createTokens({
  ...tokens,
  color: {
    myColor: "#550000",
  },
})

export const config = createTamagui({
  ...
  tokens: newTokens,
  ...
})

Expected Behavior

The icon to be displayed with theme color.

Tamagui Version

1.21.2

Reproduction

Just add 

<Icon color="$myColor" />

where myColor can be any color defined in tamagui theme.

System Info

No response

natew commented 1 year ago

Just verified it working in sandbox, please open repro

IhsenBouallegue commented 1 year ago

@natew Sadly, I do not have the time right now to configure a repo. But here are the relevant files. The mentioned problem appears when changing the color inside tabs of react navigation. I found a workaround by importing the config object itself and getting the color from there. Also in the docs, there are no examples for extending the "base" theme. So not sure if I did the config right. Hope this helps!

tamagui.config.ts

/* eslint-disable import/no-extraneous-dependencies */
import { createAnimations } from "@tamagui/animations-react-native"
import { createInterFont } from "@tamagui/font-inter"
import { createMedia } from "@tamagui/react-native-media-driver"
import { shorthands } from "@tamagui/shorthands"
import { themes, tokens } from "@tamagui/themes"
import { createTamagui, createTokens } from "tamagui"

const rodeoTokenColors = createTokens({
  ...tokens,
  color: {
    ...tokens.color,
    darkRed: "#550000",
  },
})

const animations = createAnimations({
  bouncy: {
    type: "spring",
    damping: 10,
    mass: 0.9,
    stiffness: 100,
  },
  lazy: {
    type: "spring",
    damping: 20,
    stiffness: 60,
  },
  quick: {
    type: "spring",
    damping: 20,
    mass: 1.2,
    stiffness: 250,
  },
})

const headingFont = createInterFont()
const bodyFont = createInterFont()

export const config = createTamagui({
  animations,
  defaultTheme: "light",
  shouldAddPrefersColorThemes: false,
  themeClassNameOnRoot: false,
  shorthands,
  fonts: {
    heading: headingFont,
    body: bodyFont,
  },
  themes,
  tokens: rodeoTokenColors,
  media: createMedia({
    xs: { maxWidth: 660 },
    sm: { maxWidth: 800 },
    md: { maxWidth: 1020 },
    lg: { maxWidth: 1280 },
    xl: { maxWidth: 1420 },
    xxl: { maxWidth: 1600 },
    gtXs: { minWidth: 660 + 1 },
    gtSm: { minWidth: 800 + 1 },
    gtMd: { minWidth: 1020 + 1 },
    gtLg: { minWidth: 1280 + 1 },
    short: { maxHeight: 820 },
    tall: { minHeight: 820 },
    hoverNone: { hover: "none" },
    pointerCoarse: { pointer: "coarse" },
  }),
})

export type AppConfig = typeof config

declare module "tamagui" {
  export interface TamaguiCustomConfig extends AppConfig {}
}

export default config

app/_layout.tsx

import { Book, Heart, MessageCircle, Search, User } from "@tamagui/lucide-icons"
import { IconProps } from "@tamagui/lucide-icons/types/IconProps"
import { Tabs } from "expo-router"
import { useSafeAreaInsets } from "react-native-safe-area-context"
import { Paragraph } from "tamagui"
import { config } from "../../tamagui.config"

function TabIcon({
  focused,
  color,
  Icon,
}: {
  focused: boolean
  color: string
  Icon: React.NamedExoticComponent<IconProps>
}) {
  // this doesn't work
  // but when replaces with color which is simply coming from config.tokens.color.darkRed.val it works
  return <Icon size={focused ? "$2" : "$1.5"} color="$darkRed" />
}
function TabLabel({
  focused,
  color,
  children,
}: {
  focused: boolean
  color: string
  children: string
}) {
  return (
    <Paragraph fontSize={focused ? 12 : 10} color={color}>
      {children}
    </Paragraph>
  )
}
export default function TabLayout() {
  const insets = useSafeAreaInsets()
  return (
    <Tabs
      screenOptions={() => ({
        // this is a workaround (I just import the from config object itself and pass it along)
        tabBarActiveTintColor: config.tokens.color.darkRed.val,
        tabBarInactiveTintColor: "gray",
        tabBarStyle: { height: 60 + insets.bottom },
        tabBarLabel: ({ focused, color, children }) =>
          TabLabel({ focused, color, children }),
      })}
    >
      <Tabs.Screen
        name="explore"
        options={{
          headerShown: false,
          title: "Explore",
          tabBarIcon: ({ focused, color }) =>
            TabIcon({ focused, color, Icon: Search }),
        }}
      />
      <Tabs.Screen name="index" options={{ href: null }} />
    </Tabs>
  )
}

app/(tabs)/_layout.tsx

/* eslint-disable global-require */
import { useFonts } from "expo-font"
import { SplashScreen, Stack } from "expo-router"
import { StatusBar } from "expo-status-bar"
import React from "react"
import { SafeAreaView } from "react-native-safe-area-context"
import { TamaguiProvider, Theme } from "tamagui"
import { config } from "../tamagui.config"

export default function App() {
  const [loaded] = useFonts({
    Inter: require("@tamagui/font-inter/otf/Inter-Medium.otf"),
    InterBold: require("@tamagui/font-inter/otf/Inter-Bold.otf"),
  })

  if (!loaded) {
    return <SplashScreen />
  }

  return (
    <TamaguiProvider config={config}>
      <Theme name="light">
        <StatusBar />
        <SafeAreaView style={{ flex: 1 }} edges={["top", "left", "right"]}>
          <Stack>
            <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
          </Stack>
        </SafeAreaView>
      </Theme>
    </TamaguiProvider>
  )
}
peterjskaltsis commented 1 year ago

@IhsenBouallegue I think Icon's may only pick up theme colors, not token colours that are not used in a theme?

IhsenBouallegue commented 1 year ago

@peterjskaltsis thank you so much, that was it!😄 I am still wrapping my head around how things work in tamagui.