L-Blondy / tw-colors

Tailwind plugin to easily add multiple color themes to your projects.
MIT License
456 stars 14 forks source link

NativeWind support #26

Closed freitagdavid closed 1 year ago

freitagdavid commented 1 year ago

I've been trying and trying but no matter what I do I can't seem to get this working with NativeWind. I'm not sure if I'm doing something wrong or if this plugin just fundamentally wouldn't work. But it does precisely what I'm needing out of tailwind in my project.

Just thought I would ask, has this been tested in NativeWind?

L-Blondy commented 1 year ago

Hi @freitagdavid, do you mind sharing your tailwind config and package.json?

freitagdavid commented 1 year ago

I've got my redux provider wrapped in a nativewind styled with a dark class on it. I've also tried putting the class directly on the component I'm styling but it's always coming back as undefined in the style object in react devtools.

Here is my config, I was trying to do the minimum required to get it working. I'm currently working on getting tw into our project, gotta have simple theming to do that though. Tailwinds is definitely working got a screen themed but couldn't get tw-colors working.

Edit: Forgot to mention I've got this setup using babel so I don't need to wrap everything.

const {createThemes} = require('tw-colors');

/** @type {import('tailwindcss').Config} */
console.log('ahhhhhhhhhhhhhhhhhhhhhhhhhhhhhh');
module.exports = {
    content: [
        './App.tsx',
        './src/screens/**/*.tsx',
        './src/components/**/*.tsx',
    ],
    theme: {
        extends: {
            // colors: {
            //     grey: {
            //         1400: '#1A1A1A',
            //     },
            //     blue: {
            //         200: '#48B6FF',
            //         500: '#1D609E',
            //         300: '#0192ed',
            //         1000: '#1F3F66',
            //     },
            // },
        },
    },
    plugins: [
        createThemes({
            dark: {
                background: 'black',
            }, 
            red: {
                background: 'red',
            },
        }),
    ],
};

Sadly I can't post my full package.json this is a project for work but here is a sanitized one I'm not sure exactly what is proprietary so I removed anything relating to my company but I think this covers what you would need.

{
    "name": "mobile",
    "version": "8.0.1",
    "private": true,
    "engines": {
        "npm": ">=8.11.0",
        "node": ">=16.16.0"
    },
    "scripts": {

    },
    "dependencies": {
        "@notifee/react-native": "^7.7.1",
        "@react-native-async-storage/async-storage": "^1.17.11",
        "@react-native-community/hooks": "^3.0.0",
        "@react-native-community/masked-view": "^0.1.11",
        "@react-native-firebase/analytics": "^18.3.0",
        "@react-native-firebase/app": "^18.3.0",
        "@react-native-firebase/crashlytics": "^18.3.0",
        "@react-native-firebase/messaging": "^18.3.0",
        "@react-native-firebase/remote-config": "^18.3.0",
        "@react-native-firebase/storage": "^18.3.0",
        "@react-native-picker/picker": "^2.4.8",
        "@react-navigation/bottom-tabs": "5.11.7",
        "@react-navigation/elements": "1.3.12",
        "@react-navigation/material-top-tabs": "5.2.17",
        "@react-navigation/native": "5.9.3",
        "@react-navigation/stack": "5.9.1",
        "@skele/components": "^1.0.0-alpha.40",
        "@taboola/react-native-taboola": "2.3.8",
        "@types/uuid": "^9.0.2",
        "axios": "^1.2.0",
        "css-tree": "^2.3.0",
        "date-fns": "^2.29.3",
        "deprecated-react-native-prop-types": "^2.3.0",
        "lodash": "^4.17.21",
        "md5": "^2.3.0",
        "nativewind": "^2.0.11",
        "node-html-parser": "^6.1.4",
        "path": "^0.12.7",
        "react": "18.1.0",
        "react-content-loader": "^6.2.0",
        "react-dom": "18.1.0",
        "react-native": "0.70.1",
        "react-native-android-open-settings": "^1.3.0",
        "react-native-auth0": "^3.0.1",
        "react-native-blob-util": "^0.19.0",
        "react-native-build-config": "^0.3.2",
        "react-native-email-link": "^1.14.7",
        "react-native-fs": "^2.20.0",
        "react-native-gesture-handler": "^2.8.0",
        "react-native-get-random-values": "^1.9.0",
        "react-native-google-analytics-bridge": "^7.1.0",
        "react-native-idle-timer": "2.1.7",
        "react-native-json-tree": "^1.3.0",
        "react-native-linear-gradient": "^2.6.2",
        "react-native-maps": "^1.7.1",
        "react-native-orientation-locker": "^1.5.0",
        "react-native-pager-view": "6.1.2",
        "react-native-pdf": "^6.7.1",
        "react-native-reanimated": "^2.13.0",
        "react-native-render-html": "5.1.1",
        "react-native-safe-area-context": "^4.4.1",
        "react-native-screens": "^3.18.2",
        "react-native-share": "^8.2.2",
        "react-native-svg": "^13.6.0",
        "react-native-svg-transformer": "^1.0.0",
        "react-native-tab-view": "^3.3.2",
        "react-native-url-polyfill": "^1.3.0",
        "react-native-vector-icons": "^9.2.0",
        "react-native-webview": "^11.25.0",
        "react-redux": "^7.2.5",
        "redux": "^4.2.0",
        "typesafe-actions": "^5.1.0",
        "uuid": "^9.0.0"
    },
    "devDependencies": {
        "@babel/core": "^7.12.9",
        "@babel/node": "^7.20.5",
        "@babel/preset-env": "^7.20.2",
        "@babel/runtime": "^7.12.5",
        "@native-html/css-processor": "^1.11.0",
        "@react-native-community/eslint-config": "^2.0.0",
        "@testing-library/react-native": "^11.5.0",
        "@types/gulp": "^4.0.10",
        "@types/jest": "^26.0.24",
        "@types/lodash": "^4.14.150",
        "@types/md5": "^2.3.0",
        "@types/plist": "^3.0.2",
        "@types/qs": "^6.9.7",
        "@types/react-native": "0.70.1",
        "@types/react-native-auth0": "^2.17.5",
        "@types/react-native-share": "^3.3.3",
        "@types/react-native-vector-icons": "^6.4.12",
        "@types/react-redux": "^7.1.18",
        "@types/react-test-renderer": "^18.0.0",
        "@types/redux-mock-store": "^1.0.3",
        "@types/trim": "^0.1.1",
        "@types/yargs": "^17.0.17",
        "@typescript-eslint/eslint-plugin": "^5.51.0",
        "@typescript-eslint/parser": "^5.51.0",
        "@wdio/cli": "^7.19.3",
        "@wdio/local-runner": "^7.19.3",
        "@wdio/mocha-framework": "^7.19.3",
        "babel-jest": "^26.6.3",
        "babel-plugin-module-resolver": "^4.0.0",
        "detox": "^18.20.4",
        "eslint": "^7.32.0",
        "eslint-plugin-wdio": "^7.19.0",
        "gulp": "^4.0.2",
        "husky": "^8.0.0",
        "jest": "^26.6.3",
        "jest-circus": "^29.3.1",
        "jetifier": "1.6.8",
        "metro-react-native-babel-preset": "^0.72.1",
        "mocha": "^9.2.2",
        "patch-package": "^6.5.0",
        "plist": "^3.0.6",
        "prettier": "^2.0.5",
        "qs": "^6.11.0",
        "react-test-renderer": "18.1.0",
        "redux-mock-store": "^1.5.4",
        "redux-thunk": "^2.4.2",
        "tailwindcss": "^3.3.2",
        "tailwindcss-themer": "^3.1.2",
        "tw-colors": "^3.0.3",
        "typescript": "~4.8.4",
        "yargs": "^17.6.2"
    },
    "jest": {
        "preset": "react-native"
    },
    "bundleDependencies": [
        "@react-native-async-storage/async-storage",
        "@react-native-community/masked-view",
        "@react-native-firebase/analytics",
        "@react-native-firebase/app",
        "@react-native-firebase/crashlytics",
        "@react-native-firebase/messaging",
        "@react-native-firebase/remote-config",
        "@react-native-firebase/storage",
        "@react-native-picker/picker",
        "@react-navigation/bottom-tabs",
        "@react-navigation/material-top-tabs",
        "@react-navigation/native",
        "@react-navigation/stack",
        "@skele/components",
        "@taboola/react-native-taboola",
        "axios",
        "css-tree",
        "date-fns",
        "lodash",
        "md5",
        "node-html-parser",
        "path",
        "react",
        "react-content-loader",
        "react-dom",
        "react-native",
        "react-native-android-open-settings",
        "react-native-build-config",
        "react-native-fs",
        "react-native-gesture-handler",
        "react-native-google-analytics-bridge",
        "react-native-idle-timer",
        "react-native-linear-gradient",
        "react-native-maps",
        "react-native-orientation-locker",
        "react-native-reanimated",
        "react-native-render-html",
        "react-native-safe-area-context",
        "react-native-screens",
        "react-native-share",
        "react-native-svg",
        "react-native-svg-transformer",
        "react-native-tab-view",
        "react-native-url-polyfill",
        "react-native-vector-icons",
        "react-native-webview",
        "react-redux",
        "redux",
        "trim",
        "typesafe-actions"
    ]
}
freitagdavid commented 1 year ago

I've done some further tinkering and it seems like at least vs code intellisense sees that bg-background is a twc variable so that definitely suggests to me that this might just be an issue with using this on a native platform, or with NativeWind itself. It could potentially be that my className isn't being applied properly but I'm unsure. Have you been able to think of any potentials?

image

L-Blondy commented 1 year ago

Didn't have time to work on it yet. I need to check if the following color definitions work in NativeWind without using tw-colors

primary: 'hsl(var(--color-primary) / <alpha-value>)'

And

primary: () => #00ff00

If just the first one works, I might get tw-colors to work with NativeWind without supporting colors with a default opacity other than 1

If the second one also works, NativeWind might not have full support for all tailwind plugins features.

I'll try to investigate it next week

freitagdavid commented 1 year ago

Thanks so much for the quick responses. If this can work with NativeWind it's gonna make my life so much easier. Goodbye 5000 line theme file haha.

L-Blondy commented 1 year ago

Fixed in version 3.1.0

@freitagdavid you can say goodbye to your 5000 lines file 😏

mikewheaton commented 1 year ago

This looks very promising, but I haven't quite been able to get it to work. Here's what I've tried:

// Tailwind config
plugins: [
  createThemes({
    light: {
      test: '#ffcc00',
    },
    dark: {
      test: '#ff0000',
    },
  }),
],
// Component
<Text className="text-test">Testing</Text>

When I inspect the resulting styles, the color being applied is hsl(undefined / 1). Any ideas what I might be missing here?

L-Blondy commented 1 year ago

Did you declare your theme in the markup? Something like this

<html data-theme='light'>

You can also define a default theme in the options.

Also make sire to use version 3.1.2

mikewheaton commented 1 year ago

Just confirmed I'm on version 3.1.2. This is a React Native project, so I wasn't quite sure where to put data-theme="light". For a quick test I tried it on a parent View like so:

<View data-theme="light">
  <Text className="text-test">Testing</Text>
</View>

If I can get this working manually, I'm hoping to then get the value via the useColorScheme() hook as documented in NativeWind's dark mode page.

L-Blondy commented 1 year ago

Try with className instead of data-theme, the View component most likely does not support data attributes

<View className="light">
  <Text className="text-test">Testing</Text>
</View> 
mikewheaton commented 1 year ago

Unfortunately it's the same result, with the inspector showing a color of hsl(undefined / 1) being set.

L-Blondy commented 1 year ago

Can you share your package.json?

mikewheaton commented 1 year ago
{
  "name": "app",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "lint": "eslint .",
    "start": "react-native start --reset-cache",
    "test": "jest",
    "type-check": "tsc",
    "test:report": "jest --collectCoverage --coverageDirectory=\"./coverage\" --ci --reporters=default --reporters=jest-junit --coverage",
    "bitrise-pod-install": "cd ios && NO_FLIPPER=1 pod install && cd ..",
    "pod-install": "cd ios && bundle exec pod install && cd ..",
    "storybook-generate": "sb-rn-get-stories",
    "storybook-watch": "sb-rn-watcher",
    "storybook": "yarn storybook-generate && STORYBOOK_ENABLED='true' yarn start",
    "postinstall": "patch-package"
  },
  "dependencies": {
    "@atomicfi/transact-react-native": "^3.0.4",
    "@gorhom/bottom-sheet": "^4",
    "@react-native-community/geolocation": "^3.1.0",
    "@react-native-masked-view/masked-view": "^0.2.9",
    "@react-native-segmented-control/segmented-control": "^2.4.2",
    "@react-navigation/bottom-tabs": "^6.5.8",
    "@react-navigation/native": "^6.1.7",
    "@react-navigation/native-stack": "^6.9.13",
    "@react-navigation/stack": "^6.3.17",
    "@reduxjs/toolkit": "^1.9.5",
    "@shopify/flash-list": "^1.6.1",
    "@types/underscore": "^1.11.6",
    "classnames": "^2.3.2",
    "clsx": "^2.0.0",
    "expo": "^49.0.0",
    "expo-linear-gradient": "~12.3.0",
    "lodash": "^4.17.21",
    "lottie-react-native": "^6.1.2",
    "moment": "^2.29.4",
    "nativewind": "^2.0.11",
    "numeral": "^2.0.6",
    "patch-package": "^8.0.0",
    "postinstall-postinstall": "^2.1.0",
    "react": "18.2.0",
    "react-freeze": "^1.0.3",
    "react-native": "0.72.1",
    "react-native-animatable": "^1.3.3",
    "react-native-config": "^1.5.1",
    "react-native-confirmation-code-field": "^7.3.1",
    "react-native-contacts": "^7.0.6",
    "react-native-currency-input": "^1.1.0",
    "react-native-draggable-flatlist": "^4.0.1",
    "react-native-flipper": "^0.212.0",
    "react-native-gesture-handler": "2.12.0",
    "react-native-haptic-feedback": "^2.0.3",
    "react-native-loading-spinner-overlay": "^3.0.1",
    "react-native-magic-modal": "^0.2.20",
    "react-native-maps": "^1.8.0",
    "react-native-mmkv": "^2.10.0",
    "react-native-modal": "^13.0.1",
    "react-native-permissions": "3.10.0",
    "react-native-persona": "^2.6.1",
    "react-native-plaid-link-sdk": "^10.5.0",
    "react-native-reanimated": "^3.3.0",
    "react-native-safe-area-context": "^4.7.2",
    "react-native-screens": "^3.22.0",
    "react-native-segmented-control-tab": "^4.0.0",
    "react-native-svg": "^13.10.0",
    "react-native-svg-transformer": "^1.1.0",
    "react-native-text-input-mask": "^3.2.0",
    "react-native-uuid": "^2.0.1",
    "react-native-vector-icons": "^10.0.0",
    "react-native-webview": "^13.6.0",
    "react-redux": "^8.1.1",
    "redux-flipper": "^2.0.2",
    "redux-persist": "^6.0.0",
    "rn-emoji-keyboard": "^1.5.1",
    "underscore": "^1.13.6"
  },
  "devDependencies": {
    "@babel/core": "^7.20.0",
    "@babel/preset-env": "^7.20.0",
    "@babel/runtime": "^7.20.0",
    "@react-native-async-storage/async-storage": "^1.19.3",
    "@react-native-community/datetimepicker": "^7.5.0",
    "@react-native-community/slider": "^4.4.3",
    "@react-native/eslint-config": "^0.72.2",
    "@react-native/metro-config": "^0.72.7",
    "@react-navigation/devtools": "^6.0.19",
    "@storybook/addon-actions": "^6.5.16",
    "@storybook/addon-controls": "^6.5.16",
    "@storybook/addon-ondevice-actions": "^6.5.6",
    "@storybook/addon-ondevice-controls": "^6.5.6",
    "@storybook/react-native": "^6.5.6",
    "@testing-library/jest-native": "^5.4.2",
    "@testing-library/react-native": "^12.1.2",
    "@tsconfig/react-native": "^3.0.0",
    "@types/jest": "^29.4.0",
    "@types/metro-config": "^0.76.3",
    "@types/node": "^18.14.1",
    "@types/numeral": "^2.0.3",
    "@types/react": "^18.0.24",
    "@types/react-native": "^0.72.3",
    "@types/react-test-renderer": "^18.0.0",
    "babel-eslint": "^10.1.0",
    "babel-jest": "^29.2.1",
    "babel-loader": "^8.3.0",
    "babel-plugin-inline-dotenv": "^1.7.0",
    "babel-plugin-module-resolver": "^5.0.0",
    "babel-plugin-root-import": "^6.6.0",
    "dotenv": "^16.3.1",
    "eslint": "^8.19.0",
    "eslint-plugin-import": "^2.28.1",
    "expo-secure-store": "~12.3.1",
    "jest": "^29.2.1",
    "metro-react-native-babel-preset": "0.76.5",
    "prettier": "^2.4.1",
    "prettier-eslint": "^15.0.1",
    "react-dom": "18.2.0",
    "react-test-renderer": "18.2.0",
    "tailwindcss": "3.3.2",
    "tw-colors": "^3.1.2",
    "typescript": "4.8.4"
  },
  "engines": {
    "node": ">=18"
  }
}
L-Blondy commented 1 year ago

I made some tests with an expo setup this time (the previous attempt was with a Next.js setup).

I'm sorry to tell you that NativeWind 2 cannot be supported. For it to work it should at least support css variables containing multiple values (e.g. --twc-primary: 50 50% 50%)

NativeWind version 3 will not add support for it (see the :root CSS Variables / limitiations section).

mikewheaton commented 1 year ago

@L-Blondy Thank you for looking into this. It looks like setting CSS variables via the theme might be the way to achieve this in NativeWind v3:

// Source: https://github.com/marklawlor/nativewind/issues/308
// tailwind.config.js
module.exports = {
  theme: {
    variables: {
      "--colors-custom-500": "black"
    },
    darkVariables: {
      "--colors-custom-500": "white"
    },
  }
}

// Compiles to
:root { --custom-500: 'black'; }
.dark { --custom-500: 'white'; }
L-Blondy commented 1 year ago

Indeed, in this case tw-colors should not be used.

I might add a nativewind specific export with light and dark themes only in some future version. Need to wait for NativeWind v3 anyways...

useEffects commented 7 months ago

any update on this...