tamagui / tamagui

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

SizableText or Paragraph styled component don't apply `color`, `fontSize` nor `tag` #2621

Closed guillempuche closed 1 week ago

guillempuche commented 2 weeks ago

Current Behavior

My text component based on Material Design typography https://m3.material.io/styles/typography/ has default font size, color and tag, but Tamagui doesn't use them.

// Example NOT WORKING

<Text display-l>
   This is display-l
</Text>

// Example WORKING (it doesn't apply the default settings, but manually)

<Text display-l fontSize={54} color="$primary">
   This is display-l
</Text>

HTML element should be <h1>, but keep being <span>

imatge

// text.tsx

/**
 * Inspired in https://tamagui.dev/ui/headings and https://github.com/status-im/status-web/blob/main/packages/components/src/text/text.tsx
 */

import type { Ref } from "react";
import type { Text as RNText } from "react-native";
import { type ColorTokens, Paragraph, SizableText, styled } from "tamagui";

type Props = {
    children: React.ReactNode;
    "body-l"?: boolean;
    "body-m"?: boolean;
    bold?: boolean;
    color?: ColorTokens | string;
    "display-l"?: boolean;
    "display-m"?: boolean;
    "headline-l"?: boolean;
    "headline-m"?: boolean;
    label?: boolean;
    lowercase?: boolean;
    select?: false;
    title?: boolean;
    truncate?: boolean;
    uppercase?: boolean;
    wrap?: false;
};

/**
 * Text based on Material Design https://m3.material.io/styles/typography/
 */
const Text = (
    { color = "$onBackground", ...rest }: Props,
    ref: Ref<RNText>,
) => {
    // const { color = "$onBackground", ...rest } = props;
    return <Base {...rest} ref={ref} color={color} />;
};

const Base = styled(SizableText, {
    name: "Text",

    color: "$primary",
    userSelect: "auto",
    // size: "$true",
    whiteSpace: "normal",

    variants: {
        "display-l": {
            true: {
                accessibilityRole: "header",
                fontSize: 57,
                fontWeight: "400",
                letterSpacing: -0.25,
                lineHeight: 64,
                role: "heading",
                tag: "h1",
            },
        },
        "display-m": {
            true: {
                accessibilityRole: "header",
                fontSize: 45,
                fontWeight: "400",
                letterSpacing: 0,
                lineHeight: 52,
                role: "heading",
                tag: "h2",
            },
        },
        // "display-sm": {
        //  true: {
        //      fontSize: 36,
        //      fontWeight: "400",
        //      letterSpacing: 0,
        //      lineHeight: 44,
        //  },
        // },
        "headline-l": {
            true: {
                accessibilityRole: "header",
                fontSize: 32,
                fontWeight: "400",
                letterSpacing: 0,
                lineHeight: 40,
                role: "heading",
                tag: "h3",
            },
        },
        "headline-m": {
            true: {
                accessibilityRole: "header",
                fontSize: 28,
                fontWeight: "400",
                letterSpacing: 0,
                lineHeight: 36,
                role: "heading",
                tag: "h4",
            },
        },
        // "headline-sm": {
        //  true: {
        //      fontSize: 24,
        //      fontWeight: "400",
        //      letterSpacing: 0,
        //      lineHeight: 32,
        //  },
        // },
        title: {
            true: {
                accessibilityRole: "header",
                fontSize: 22,
                fontWeight: "400",
                letterSpacing: 0,
                lineHeight: 28,
                role: "heading",
                tag: "h5",
            },
        },
        // "title-m": {
        //  true: {
        //      fontSize: 16,
        //      fontWeight: "500",
        //      letterSpacing: 0.15,
        //      lineHeight: 24,
        //  },
        // },
        "body-l": {
            true: {
                fontSize: 16,
                fontWeight: "400",
                letterSpacing: 0.5,
                lineHeight: 24,
                tag: "span",
            },
        },
        "body-m": {
            true: {
                fontSize: 14,
                fontWeight: "400",
                letterSpacing: 0.25,
                lineHeight: 20,
                tag: "span",
            },
        },
        label: {
            true: {
                fontSize: 14,
                fontWeight: "500",
                letterSpacing: 0.1,
                lineHeight: 20,
                tag: "span",
            },
        },
        // "label-m": {
        //  true: {
        //      fontSize: 12,
        //      fontWeight: "500",
        //      letterSpacing: 0.5,
        //      lineHeight: 16,
        //  },
        // },

        bold: {
            true: {
                fontWeight: "700",
            },
        },

        lowercase: {
            true: {
                textTransform: "lowercase",
            },
        },
        uppercase: {
            true: {
                textTransform: "uppercase",
            },
        },

        wrap: {
            false: {
                whiteSpace: "nowrap",
            },
        },

        truncate: {
            true: {
                overflow: "hidden",
                textOverflow: "ellipsis",
                whiteSpace: "nowrap",
                wordWrap: "normal",
                maxWidth: "100%",
                minWidth: 0,
            },
        },

        // select: {
        //  false: {
        //      userSelect: "none",
        //  },
        // },
    } as const,

    defaultVariants: {
        "body-l": true,
    },
});

Some Tamagui config files below.

// fonts.ts

import { createInterFont } from "@tamagui/font-inter";

const sans = createInterFont({
    // family: 'System',
    // size: {},
    // transform: {},
    // weight: {},
    // color: {},
    // letterSpacing: {},
    face: {
        400: { normal: "Inter" },
        500: { normal: "Inter" },
        700: { normal: "InterBold" },
    },
});

const mono = createInterFont(
    {
        // size: {},
        // transform: {},
        // weight: {},
        // color: {},
        // letterSpacing: {},
        family:
            'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;',
        face: {
            400: { normal: "Inter" },
            500: { normal: "Inter" },
            700: { normal: "InterBold" },
        },
    },
    // {
    // sizeSize: (size) => Math.round(size * 1.1),
    // sizeLineHeight: (size) => Math.round(size * 1.1 + (size > 20 ? 10 : 10)),
    // },
);

// Tamagui requires body and heading. More here https://tamagui.dev/docs/core/configuration
export const fonts = {
    body: sans,
    heading: sans,
    mono,
};

Color tokens based on Material Design 3 https://github.com/material-foundation/material-tokens: // colors.ts

...
export const lightThemeColors = {
    primary: palette.primary40,
    onPrimary: palette.primary100,
    primaryContainer: palette.primary90,
    onPrimaryContainer: palette.primary10,
    secondary: palette.secondary40,
    onSecondary: palette.secondary100,
    secondaryContainer: palette.secondary90,
    onSecondaryContainer: palette.secondary10,
    tertiary: palette.tertiary40,
...

Expected Behavior

Styled text component shows the default behavior (fontSize=54 and color=$onBackground)

Tamagui Version

1.95.3

Platform (Web, iOS, Android)

Web

Reproduction

Copy `text.tsx` (change color token for your own) and `fonts.tsx`. Then use <Text>

System Info

System:
    OS: macOS 14.4.1
    CPU: (8) arm64 Apple M1
    Memory: 98.16 MB / 16.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.9.0 - ~/.nvm/versions/node/v20.9.0/bin/node
    Yarn: 4.2.1 - ~/.nvm/versions/node/v20.9.0/bin/yarn
    npm: 10.1.0 - ~/.nvm/versions/node/v20.9.0/bin/npm
    Watchman: 2024.04.01.00 - /opt/homebrew/bin/watchman
  Browsers:
    Brave Browser: 124.1.65.123
    Chrome: 124.0.6367.119
    Edge: 124.0.2478.80
    Firefox: 125.0.3
    Safari: 17.4.1
  npmPackages:
    @babel/runtime: ^7.18.9 => 7.21.0 
    @manypkg/cli: ^0.19.1 => 0.19.2 
    check-dependency-version-consistency: ^3.0.3 => 3.0.3 
    eslint: ^8.21.0 => 8.39.0 
    node-gyp: ^9.3.1 => 9.3.1 
    prettier: ^2.7.1 => 2.8.8 
    turbo: ^1.10.3 => 1.10.3 
    typescript: ^5.4.5 => 5.4.5
guillempuche commented 1 week ago

No problem team, it was my fault.