From 10b037fff2f702f0a848dcd1425eff4438b82b4a Mon Sep 17 00:00:00 2001 From: codinsonn Date: Thu, 4 Apr 2024 23:55:01 +0200 Subject: [PATCH 1/5] feat: Add nativewind --- apps/expo/babel.config.js | 3 +- apps/expo/tailwind.config.js | 14 + apps/next/babel.config.js | 3 +- apps/next/global.css | 5 + apps/next/next.config.js | 1 + apps/next/package.json | 5 +- apps/next/postcss.config.js | 6 + apps/next/tailwind.config.js | 15 + features/app-core/components/Typography.tsx | 7 + features/app-core/package.json | 5 +- features/app-core/screens/HomeScreen.tsx | 5 +- features/app-core/tailwind.config.js | 12 + features/app-core/tailwind.theme.js | 24 + package-lock.json | 577 +++++++++++++++++++- 14 files changed, 669 insertions(+), 13 deletions(-) create mode 100644 apps/expo/tailwind.config.js create mode 100644 apps/next/postcss.config.js create mode 100644 apps/next/tailwind.config.js create mode 100644 features/app-core/components/Typography.tsx create mode 100644 features/app-core/tailwind.config.js create mode 100644 features/app-core/tailwind.theme.js diff --git a/apps/expo/babel.config.js b/apps/expo/babel.config.js index 4f30874..6fb6b9c 100644 --- a/apps/expo/babel.config.js +++ b/apps/expo/babel.config.js @@ -2,6 +2,7 @@ module.exports = function (api) { api.cache(true) return { - presets: ["babel-preset-expo"], + presets: ['babel-preset-expo'], + plugins: ['nativewind/babel'], } } diff --git a/apps/expo/tailwind.config.js b/apps/expo/tailwind.config.js new file mode 100644 index 0000000..f3640ac --- /dev/null +++ b/apps/expo/tailwind.config.js @@ -0,0 +1,14 @@ +const { universalTheme } = require('@app/core/tailwind.theme') + +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + './app/**/*.{js,jsx,ts,tsx}', + '../../features/**/*.{js,jsx,ts,tsx}', + '../../packages/**/*.{js,jsx,ts,tsx}', + ], + plugins: [], + theme: { + //...universalTheme, + }, +} diff --git a/apps/next/babel.config.js b/apps/next/babel.config.js index 4f30874..7df53e0 100644 --- a/apps/next/babel.config.js +++ b/apps/next/babel.config.js @@ -2,6 +2,7 @@ module.exports = function (api) { api.cache(true) return { - presets: ["babel-preset-expo"], + presets: ['babel-preset-expo'], + plugins: ['nativewind/babel', { mode: 'transformOnly' }], } } diff --git a/apps/next/global.css b/apps/next/global.css index 658fe65..72e135b 100644 --- a/apps/next/global.css +++ b/apps/next/global.css @@ -1,3 +1,8 @@ + +@tailwind base; +@tailwind components; +@tailwind utilities; + /* -i- Upgrade from the CSS reset that came with Expo's default Next.js setup */ /* Follows the setup for react-native-web: */ /* https://necolas.github.io/react-native-web/docs/setup/#root-element */ diff --git a/apps/next/next.config.js b/apps/next/next.config.js index 13d929d..af744a6 100644 --- a/apps/next/next.config.js +++ b/apps/next/next.config.js @@ -8,6 +8,7 @@ const nextConfig = withExpo({ "react-native", "react-native-web", "expo", + "nativewind", // Add more React Native / Expo packages here... ], typescript: { diff --git a/apps/next/package.json b/apps/next/package.json index 1ea911a..65ce7d4 100644 --- a/apps/next/package.json +++ b/apps/next/package.json @@ -5,7 +5,10 @@ "dependencies": { "next": "~14.0.4" }, - "devDependencies": {}, + "devDependencies": { + "autoprefixer": "^10.4.19", + "postcss": "8.4.23" + }, "scripts": { "dev": "next dev", "build": "next build", diff --git a/apps/next/postcss.config.js b/apps/next/postcss.config.js new file mode 100644 index 0000000..fef1b22 --- /dev/null +++ b/apps/next/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/apps/next/tailwind.config.js b/apps/next/tailwind.config.js new file mode 100644 index 0000000..e77a1bc --- /dev/null +++ b/apps/next/tailwind.config.js @@ -0,0 +1,15 @@ +const { universalTheme } = require('@app/core/tailwind.theme') + +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + './app/**/*.{js,jsx,ts,tsx}', + '../../features/**/*.{js,jsx,ts,tsx}', + '../../packages/**/*.{js,jsx,ts,tsx}', + ], + plugins: [require('nativewind/tailwind/css')], + important: 'html', + theme: { + ...universalTheme, + }, +} diff --git a/features/app-core/components/Typography.tsx b/features/app-core/components/Typography.tsx new file mode 100644 index 0000000..23339fc --- /dev/null +++ b/features/app-core/components/Typography.tsx @@ -0,0 +1,7 @@ +import { styled } from 'nativewind' +import { Text } from 'react-native' + +export const H1 = styled(Text, 'font-bold text-2xl') +export const H2 = styled(Text, 'font-bold text-xl') +export const H3 = styled(Text, 'font-bold text-lg') +export const P = styled(Text, 'text-base') diff --git a/features/app-core/package.json b/features/app-core/package.json index e04b339..9002a7f 100644 --- a/features/app-core/package.json +++ b/features/app-core/package.json @@ -2,8 +2,11 @@ "name": "@app/core", "version": "1.0.0", "private": true, - "dependencies": {}, + "dependencies": { + "nativewind": "^2.0.11" + }, "devDependencies": { + "tailwindcss": "3.3.2", "typescript": "5.3.3" }, "scripts": {} diff --git a/features/app-core/screens/HomeScreen.tsx b/features/app-core/screens/HomeScreen.tsx index 7db3255..23a036e 100644 --- a/features/app-core/screens/HomeScreen.tsx +++ b/features/app-core/screens/HomeScreen.tsx @@ -2,6 +2,7 @@ import React from 'react' import { StyleSheet, Text, View } from 'react-native' import { Link } from '../navigation/Link' import { Image } from '../components/Image' +import { H3, P } from '../components/Typography' /* --- --------------------------------------------------------------------------- */ @@ -9,8 +10,8 @@ const HomeScreen = () => { return ( - Expo + Next.js app routing 🚀 - Open HomeScreen.tsx in features/app-core/screens to start working on your app +

Expo + Next.js app routing 🚀

+

Open HomeScreen.tsx in features/app-core/screens to start working on your app

Test navigation Test images Docs diff --git a/features/app-core/tailwind.config.js b/features/app-core/tailwind.config.js new file mode 100644 index 0000000..44a139c --- /dev/null +++ b/features/app-core/tailwind.config.js @@ -0,0 +1,12 @@ +const { universalTheme } = require('./tailwind.theme') + +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + './**/*.{js,jsx,ts,tsx}', + ], + plugins: [], + theme: { + ...universalTheme, + }, +} diff --git a/features/app-core/tailwind.theme.js b/features/app-core/tailwind.theme.js new file mode 100644 index 0000000..ddcd558 --- /dev/null +++ b/features/app-core/tailwind.theme.js @@ -0,0 +1,24 @@ +/** @type {import('tailwindcss').Config['theme']} */ +const universalTheme = { + // -i- Extend default tailwind theme here + // -i- Reference this theme in the tailwind.config.js files in apps/expo, apps/next, features/app-core and other package or feature folders + extend: { + // colors: { + // primary: { + // 100: '#FFA8E2', + // 200: '#FF8CD4', + // 300: '#FF70C6', + // 400: '#FF54B8', + // 500: '#FF38AA', + // 600: '#FF1C9C', + // 700: '#FF0090', + // 800: '#E60082', + // 900: '#CC0074', + // }, + // } + } +} + +/* --- Exports --------------------------------------------------------------------------------- */ + +module.exports = { universalTheme } diff --git a/package-lock.json b/package-lock.json index 2f76ce4..5c49033 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,15 +47,33 @@ "dependencies": { "next": "~14.0.4" }, - "devDependencies": {} + "devDependencies": { + "autoprefixer": "^10.4.19", + "postcss": "8.4.23" + } }, "features/app-core": { "name": "@app/core", "version": "1.0.0", + "dependencies": { + "nativewind": "^2.0.11" + }, "devDependencies": { + "tailwindcss": "3.3.2", "typescript": "5.3.3" } }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@ampproject/remapping": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", @@ -2913,6 +2931,33 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/@expo/metro-config/node_modules/postcss": { + "version": "8.4.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.39.tgz", + "integrity": "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.1", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, "node_modules/@expo/metro-config/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -7116,6 +7161,43 @@ "node": ">= 4.0.0" } }, + "node_modules/autoprefixer": { + "version": "10.4.19", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", + "integrity": "sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-lite": "^1.0.30001599", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", @@ -7345,6 +7427,17 @@ "node": ">=0.6" } }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", @@ -7644,6 +7737,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/camelize": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz", + "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001643", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001643.tgz", @@ -7684,6 +7793,29 @@ "node": "*" } }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, "node_modules/chownr": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", @@ -8078,6 +8210,14 @@ "node": ">=8" } }, + "node_modules/css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==", + "engines": { + "node": ">=4" + } + }, "node_modules/css-in-js-utils": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/css-in-js-utils/-/css-in-js-utils-3.1.0.tgz", @@ -8086,6 +8226,32 @@ "hyphenate-style-name": "^1.0.3" } }, + "node_modules/css-mediaquery": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/css-mediaquery/-/css-mediaquery-0.1.2.tgz", + "integrity": "sha512-COtn4EROW5dBGlE/4PiKnh6rZpAPxDeFLaEEwt4i10jpDMFt2EhQGS79QmmrO+iKCHv0PU/HrOWEhijFd1x99Q==" + }, + "node_modules/css-to-react-native": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz", + "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==", + "dependencies": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -8354,6 +8520,11 @@ "node": ">=0.10" } }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -8365,6 +8536,11 @@ "node": ">=8" } }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" + }, "node_modules/dotenv": { "version": "16.4.5", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", @@ -9152,6 +9328,11 @@ "resolved": "https://registry.npmjs.org/expo-status-bar/-/expo-status-bar-1.12.1.tgz", "integrity": "sha512-/t3xdbS8KB0prj5KG5w7z+wZPFlPtkgs95BsmrP/E7Q0xHXTcDcQ6Cu2FkFuRM+PKTb17cJDnLkawyS5vDLxMA==" }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -9408,6 +9589,19 @@ "node": ">= 6" } }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, "node_modules/freeport-async": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/freeport-async/-/freeport-async-2.0.0.tgz", @@ -10066,6 +10260,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-boolean-object": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", @@ -11133,6 +11338,14 @@ "resolved": "https://registry.npmjs.org/jimp-compact/-/jimp-compact-0.16.1.tgz", "integrity": "sha512-dZ6Ra7u1G8c4Letq/B5EzAxj4tLFHL+cGtdpR+PVm4yzPDj+lCk+AbivWt1eOM+ikzkowtyV7qSqX6qr3t71Ww==" }, + "node_modules/jiti": { + "version": "1.21.6", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", + "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", + "bin": { + "jiti": "bin/jiti.js" + } + }, "node_modules/joi": { "version": "17.13.3", "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.3.tgz", @@ -11571,6 +11784,14 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "engines": { + "node": ">=10" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -12628,6 +12849,61 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/nativewind": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/nativewind/-/nativewind-2.0.11.tgz", + "integrity": "sha512-qCEXUwKW21RYJ33KRAJl3zXq2bCq82WoI564fI21D/TiqhfmstZOqPN53RF8qK1NDK6PGl56b2xaTxgObEePEg==", + "dependencies": { + "@babel/generator": "^7.18.7", + "@babel/helper-module-imports": "7.18.6", + "@babel/types": "7.19.0", + "css-mediaquery": "^0.1.2", + "css-to-react-native": "^3.0.0", + "micromatch": "^4.0.5", + "postcss": "^8.4.12", + "postcss-calc": "^8.2.4", + "postcss-color-functional-notation": "^4.2.2", + "postcss-css-variables": "^0.18.0", + "postcss-nested": "^5.0.6", + "react-is": "^18.1.0", + "use-sync-external-store": "^1.1.0" + }, + "engines": { + "node": ">=14.18" + }, + "peerDependencies": { + "tailwindcss": "~3" + } + }, + "node_modules/nativewind/node_modules/@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/nativewind/node_modules/@babel/types": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.0.tgz", + "integrity": "sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==", + "dependencies": { + "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-validator-identifier": "^7.18.6", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/nativewind/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" + }, "node_modules/ncp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", @@ -12814,6 +13090,15 @@ "node": ">=0.10.0" } }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/npm-package-arg": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-7.0.0.tgz", @@ -12873,6 +13158,14 @@ "node": ">=0.10.0" } }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "engines": { + "node": ">= 6" + } + }, "node_modules/object-inspect": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", @@ -13310,9 +13603,9 @@ } }, "node_modules/postcss": { - "version": "8.4.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.39.tgz", - "integrity": "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==", + "version": "8.4.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz", + "integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==", "funding": [ { "type": "opencollective", @@ -13328,14 +13621,166 @@ } ], "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.1", - "source-map-js": "^1.2.0" + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" }, "engines": { "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-calc": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", + "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", + "dependencies": { + "postcss-selector-parser": "^6.0.9", + "postcss-value-parser": "^4.2.0" + }, + "peerDependencies": { + "postcss": "^8.2.2" + } + }, + "node_modules/postcss-color-functional-notation": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-4.2.4.tgz", + "integrity": "sha512-2yrTAUZUab9s6CpxkxC4rVgFEVaR6/2Pipvi6qcgvnYiVqZcbDHEoBDhrXzyb7Efh2CCfHQNtcqWcIruDTIUeg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-css-variables": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/postcss-css-variables/-/postcss-css-variables-0.18.0.tgz", + "integrity": "sha512-lYS802gHbzn1GI+lXvy9MYIYDuGnl1WB4FTKoqMQqJ3Mab09A7a/1wZvGTkCEZJTM8mSbIyb1mJYn8f0aPye0Q==", + "dependencies": { + "balanced-match": "^1.0.0", + "escape-string-regexp": "^1.0.3", + "extend": "^3.0.1" + }, + "peerDependencies": { + "postcss": "^8.2.6" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-load-config/node_modules/lilconfig": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/postcss-nested": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-5.0.6.tgz", + "integrity": "sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==", + "dependencies": { + "postcss-selector-parser": "^6.0.6" + }, + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.1.tgz", + "integrity": "sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/postcss-value-parser": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", @@ -13906,6 +14351,22 @@ "react": "^16.0.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/read-cache/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", @@ -13920,6 +14381,28 @@ "util-deprecate": "~1.0.1" } }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/readline": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/readline/-/readline-1.3.0.tgz", @@ -15023,6 +15506,78 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/tailwindcss": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.2.tgz", + "integrity": "sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w==", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.2.12", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.18.2", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "postcss-value-parser": "^4.2.0", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/tailwindcss/node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, "node_modules/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -15768,6 +16323,14 @@ "react": ">=16.8" } }, + "node_modules/use-sync-external-store": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", + "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/util": { "version": "0.12.5", "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", From 45f38ae8232e0bbbdc42ea1e3bd80071733162a2 Mon Sep 17 00:00:00 2001 From: codinsonn Date: Fri, 5 Apr 2024 11:30:56 +0200 Subject: [PATCH 2/5] fix: Add TextLink to provide styles for Next Link --- features/app-core/components/Typography.tsx | 7 ----- features/app-core/components/styled.tsx | 30 +++++++++++++++++++++ features/app-core/navigation/Link.types.ts | 3 +++ 3 files changed, 33 insertions(+), 7 deletions(-) delete mode 100644 features/app-core/components/Typography.tsx create mode 100644 features/app-core/components/styled.tsx diff --git a/features/app-core/components/Typography.tsx b/features/app-core/components/Typography.tsx deleted file mode 100644 index 23339fc..0000000 --- a/features/app-core/components/Typography.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { styled } from 'nativewind' -import { Text } from 'react-native' - -export const H1 = styled(Text, 'font-bold text-2xl') -export const H2 = styled(Text, 'font-bold text-xl') -export const H3 = styled(Text, 'font-bold text-lg') -export const P = styled(Text, 'text-base') diff --git a/features/app-core/components/styled.tsx b/features/app-core/components/styled.tsx new file mode 100644 index 0000000..5c74837 --- /dev/null +++ b/features/app-core/components/styled.tsx @@ -0,0 +1,30 @@ +import { styled } from 'nativewind' +import { Text as RNText, View as RNView } from 'react-native' +import { Link as UniversalLink } from './Link' + +/* --- Primitives ------------------------------------------------------------------------------ */ + +export const View = styled(RNView, '') +export const Text = styled(RNText, '') + +/* --- Typography ------------------------------------------------------------------------------ */ + +export const H1 = styled(RNText, 'font-bold text-2xl') +export const H2 = styled(RNText, 'font-bold text-xl') +export const H3 = styled(RNText, 'font-bold text-lg') + +export const P = styled(RNText, 'text-base') + +/* --- Fix for Next Link ----------------------------------------------------------------------- */ + +export const LinkText = styled(RNText, 'text-blue-500 underline') +export const TextLink = (props: Omit, 'className'> & { className?: string }) => { + const { className, style, children, ...universalLinkProps } = props + return ( + + + {children} + + + ) +} diff --git a/features/app-core/navigation/Link.types.ts b/features/app-core/navigation/Link.types.ts index f0fbd3a..7af0c6e 100644 --- a/features/app-core/navigation/Link.types.ts +++ b/features/app-core/navigation/Link.types.ts @@ -13,6 +13,9 @@ export type UniversalLinkProps = { /** Universal - Style prop: https://reactnative.dev/docs/text#style */ style?: ExpoLinkProps['style']; + /** -!- Nativewind classNames should be applied to either the parent or children of Link. Ideally, create or use a TextLink component instead */ + className?: never; + /** Universal - Should replace the current route without adding to the history - Default: false. */ replace?: boolean; From ddb3c1072df8c8bc8e53a2f785256b26ee308566 Mon Sep 17 00:00:00 2001 From: codinsonn Date: Fri, 5 Apr 2024 11:31:31 +0200 Subject: [PATCH 3/5] chore: Rewrite HomeScreen & SlugScreen to use Nativewind classNames --- apps/expo/app/ExpoRootLayout.tsx | 2 + features/app-core/screens/HomeScreen.tsx | 42 +++------------- features/app-core/screens/SlugScreen.tsx | 63 +++++++----------------- 3 files changed, 27 insertions(+), 80 deletions(-) diff --git a/apps/expo/app/ExpoRootLayout.tsx b/apps/expo/app/ExpoRootLayout.tsx index b8bd9f5..e0f79d6 100644 --- a/apps/expo/app/ExpoRootLayout.tsx +++ b/apps/expo/app/ExpoRootLayout.tsx @@ -7,6 +7,8 @@ import UniversalRootLayout from '@app/core/screens/UniversalRootLayout' // -i- Use this file to apply your Expo specific layout setup: // -i- like rendering our Universal Layout and App Providers +/* --- ------------------------------------------------------------------------ */ + export default function ExpoRootLayout() { return ( diff --git a/features/app-core/screens/HomeScreen.tsx b/features/app-core/screens/HomeScreen.tsx index 23a036e..c07743e 100644 --- a/features/app-core/screens/HomeScreen.tsx +++ b/features/app-core/screens/HomeScreen.tsx @@ -1,51 +1,23 @@ import React from 'react' -import { StyleSheet, Text, View } from 'react-native' -import { Link } from '../navigation/Link' import { Image } from '../components/Image' -import { H3, P } from '../components/Typography' +import { View, H3, P, TextLink } from '../components/styled' /* --- --------------------------------------------------------------------------- */ const HomeScreen = () => { return ( - + -

Expo + Next.js app routing 🚀

-

Open HomeScreen.tsx in features/app-core/screens to start working on your app

- Test navigation - Test images +

Expo + Next.js app routing 👋

+

Open HomeScreen.tsx in features/app-core/screens to start working on your app

+ + Test navigation + Docs
) } -/* --- Styles ---------------------------------------------------------------------------------- */ - -const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: 'center', - alignItems: 'center', - }, - title: { - fontWeight: 'bold', - fontSize: 16, - textAlign: 'center', - }, - subtitle: { - marginTop: 8, - fontSize: 16, - textAlign: 'center', - }, - link: { - marginTop: 16, - fontSize: 16, - color: 'blue', - textAlign: 'center', - textDecorationLine: 'underline', - }, -}) - /* --- Exports --------------------------------------------------------------------------------- */ export default HomeScreen diff --git a/features/app-core/screens/SlugScreen.tsx b/features/app-core/screens/SlugScreen.tsx index c0184ec..e72b264 100644 --- a/features/app-core/screens/SlugScreen.tsx +++ b/features/app-core/screens/SlugScreen.tsx @@ -1,7 +1,6 @@ import React from 'react' -import { StyleSheet, Text, View } from 'react-native' -import { useRouteParams } from '../navigation/useRouteParams' -import { Link } from '../navigation/Link' +import { useRouteParams } from '@app/core/navigation/useRouteParams' +import { View, Text, H3, TextLink } from '../components/styled' import { useRouter } from '../navigation/useRouter' /* --- --------------------------------------------------------------------------- */ @@ -17,71 +16,45 @@ const SlugScreen = (props) => { // -- Render -- return ( - + {showBackButton && ( {`< Back`} )} - +

Page slug: {slug} {!!count && ` | count: ${count}`} +

+ + Need a more robust, Fully-Stacked, Full-Product, Universal App Setup? - Need a more robust, Fully-Stacked, Full-Product, Universal App Setup? - + Check out the GREEN Stack Starter - - push('/subpages/push')}> + + push('/subpages/push')}> {`router.push()`} - navigate('/subpages/navigate')}> + navigate('/subpages/navigate')}> {`router.navigate()`} - replace('/subpages/replace')}> + replace('/subpages/replace')}> {`router.replace()`} - setParams({ count: `${+count + 1}` })}> + setParams({ count: `${+count + 1}` })}> {`router.setParams()`}
) } -/* --- Styles ---------------------------------------------------------------------------------- */ - -const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: 'center', - alignItems: 'center', - }, - backButton: { - position: 'absolute', - top: 16, - left: 16, - }, - title: { - fontWeight: 'bold', - fontSize: 16, - textAlign: 'center', - }, - subtitle: { - marginTop: 8, - fontSize: 16, - textAlign: 'center', - }, - link: { - marginTop: 16, - fontSize: 16, - color: 'blue', - textAlign: 'center', - textDecorationLine: 'underline', - }, -}) - /* --- Exports --------------------------------------------------------------------------------- */ export default SlugScreen From a259e5603df3335fa6d460aec5b113c51a5b8057 Mon Sep 17 00:00:00 2001 From: codinsonn Date: Fri, 5 Apr 2024 17:14:49 +0200 Subject: [PATCH 4/5] chore: Add custom primary color in tailwind.theme.js --- apps/expo/app/ExpoRootLayout.tsx | 7 +++++++ apps/expo/tailwind.config.js | 8 ++++---- apps/next/tailwind.config.js | 6 +++--- features/app-core/components/styled.tsx | 8 ++++---- features/app-core/tailwind.config.js | 4 +++- features/app-core/tailwind.theme.js | 18 +++++------------- 6 files changed, 26 insertions(+), 25 deletions(-) diff --git a/apps/expo/app/ExpoRootLayout.tsx b/apps/expo/app/ExpoRootLayout.tsx index e0f79d6..42a23fc 100644 --- a/apps/expo/app/ExpoRootLayout.tsx +++ b/apps/expo/app/ExpoRootLayout.tsx @@ -1,12 +1,19 @@ import { Stack } from 'expo-router' import UniversalAppProviders from '@app/core/screens/UniversalAppProviders' import UniversalRootLayout from '@app/core/screens/UniversalRootLayout' +import { NativeWindStyleSheet } from 'nativewind' // -i- Expo Router's layout setup is much simpler than Next.js's layout setup // -i- Since Expo doesn't require a custom document setup or server component root layout // -i- Use this file to apply your Expo specific layout setup: // -i- like rendering our Universal Layout and App Providers +/* --- Settings -------------------------------------------------------------------------------- */ + +NativeWindStyleSheet.setOutput({ + default: 'native', +}) + /* --- ------------------------------------------------------------------------ */ export default function ExpoRootLayout() { diff --git a/apps/expo/tailwind.config.js b/apps/expo/tailwind.config.js index f3640ac..b0e0700 100644 --- a/apps/expo/tailwind.config.js +++ b/apps/expo/tailwind.config.js @@ -3,12 +3,12 @@ const { universalTheme } = require('@app/core/tailwind.theme') /** @type {import('tailwindcss').Config} */ module.exports = { content: [ - './app/**/*.{js,jsx,ts,tsx}', - '../../features/**/*.{js,jsx,ts,tsx}', - '../../packages/**/*.{js,jsx,ts,tsx}', + '../../apps/**/*.tsx', + '../../features/**/*.tsx', + '../../packages/**/*.tsx', ], plugins: [], theme: { - //...universalTheme, + ...universalTheme, }, } diff --git a/apps/next/tailwind.config.js b/apps/next/tailwind.config.js index e77a1bc..434c6cd 100644 --- a/apps/next/tailwind.config.js +++ b/apps/next/tailwind.config.js @@ -3,9 +3,9 @@ const { universalTheme } = require('@app/core/tailwind.theme') /** @type {import('tailwindcss').Config} */ module.exports = { content: [ - './app/**/*.{js,jsx,ts,tsx}', - '../../features/**/*.{js,jsx,ts,tsx}', - '../../packages/**/*.{js,jsx,ts,tsx}', + '../../apps/**/*.tsx', + '../../features/**/*.tsx', + '../../packages/**/*.tsx', ], plugins: [require('nativewind/tailwind/css')], important: 'html', diff --git a/features/app-core/components/styled.tsx b/features/app-core/components/styled.tsx index 5c74837..eb9b30e 100644 --- a/features/app-core/components/styled.tsx +++ b/features/app-core/components/styled.tsx @@ -1,6 +1,6 @@ import { styled } from 'nativewind' import { Text as RNText, View as RNView } from 'react-native' -import { Link as UniversalLink } from './Link' +import { Link as UniversalLink } from '../navigation/Link' /* --- Primitives ------------------------------------------------------------------------------ */ @@ -9,9 +9,9 @@ export const Text = styled(RNText, '') /* --- Typography ------------------------------------------------------------------------------ */ -export const H1 = styled(RNText, 'font-bold text-2xl') -export const H2 = styled(RNText, 'font-bold text-xl') -export const H3 = styled(RNText, 'font-bold text-lg') +export const H1 = styled(RNText, 'font-bold text-2xl text-primary-500') +export const H2 = styled(RNText, 'font-bold text-xl text-primary-500') +export const H3 = styled(RNText, 'font-bold text-lg text-primary-500') export const P = styled(RNText, 'text-base') diff --git a/features/app-core/tailwind.config.js b/features/app-core/tailwind.config.js index 44a139c..03a600b 100644 --- a/features/app-core/tailwind.config.js +++ b/features/app-core/tailwind.config.js @@ -3,7 +3,9 @@ const { universalTheme } = require('./tailwind.theme') /** @type {import('tailwindcss').Config} */ module.exports = { content: [ - './**/*.{js,jsx,ts,tsx}', + '../../apps/**/*.tsx', + '../../features/**/*.tsx', + '../../packages/**/*.tsx', ], plugins: [], theme: { diff --git a/features/app-core/tailwind.theme.js b/features/app-core/tailwind.theme.js index ddcd558..fdb93f5 100644 --- a/features/app-core/tailwind.theme.js +++ b/features/app-core/tailwind.theme.js @@ -1,21 +1,13 @@ +const colors = require('tailwindcss/colors') + /** @type {import('tailwindcss').Config['theme']} */ const universalTheme = { // -i- Extend default tailwind theme here // -i- Reference this theme in the tailwind.config.js files in apps/expo, apps/next, features/app-core and other package or feature folders extend: { - // colors: { - // primary: { - // 100: '#FFA8E2', - // 200: '#FF8CD4', - // 300: '#FF70C6', - // 400: '#FF54B8', - // 500: '#FF38AA', - // 600: '#FF1C9C', - // 700: '#FF0090', - // 800: '#E60082', - // 900: '#CC0074', - // }, - // } + colors: { + primary: colors.green, + }, } } From e0c249c38527b3a6762faf0d05efbae6e6c1dc8d Mon Sep 17 00:00:00 2001 From: codinsonn Date: Tue, 9 Apr 2024 00:21:53 +0200 Subject: [PATCH 5/5] feat: Parse NativeWind styles in custom Image & Link --- features/app-core/components/Image.tsx | 8 +++- features/app-core/components/Image.types.tsx | 4 ++ features/app-core/components/Image.web.tsx | 12 +++-- features/app-core/components/styled.tsx | 3 ++ features/app-core/navigation/Link.tsx | 8 +++- features/app-core/navigation/Link.types.ts | 2 +- features/app-core/navigation/Link.web.tsx | 10 +++- features/app-core/screens/HomeScreen.tsx | 18 ++++--- features/app-core/screens/ImagesScreen.tsx | 48 ++++--------------- features/app-core/screens/SlugScreen.tsx | 6 +-- .../app-core/utils/parseNativeWindStyles.ts | 31 ++++++++++++ 11 files changed, 93 insertions(+), 57 deletions(-) create mode 100644 features/app-core/utils/parseNativeWindStyles.ts diff --git a/features/app-core/components/Image.tsx b/features/app-core/components/Image.tsx index 71bf58f..1b1fe6b 100644 --- a/features/app-core/components/Image.tsx +++ b/features/app-core/components/Image.tsx @@ -1,6 +1,7 @@ import { Image as ExpoImage } from 'expo-image' import { Platform } from 'react-native' import { UniversalImageProps, UniversalImageMethods } from './Image.types' +import { parseNativeWindStyles } from '../utils/parseNativeWindStyles' /* --- -------------------------------------------------------------------------------- */ @@ -39,10 +40,13 @@ const Image = (props: UniversalImageProps): JSX.Element => { responsivePolicy, } = props + // -- Nativewind -- + + const { nativeWindStyles, restStyle } = parseNativeWindStyles(style) + const finalStyle = { width, height, ...nativeWindStyles, ...restStyle } + // -- Overrides -- - // @ts-ignore - const finalStyle = { width, height, ...style } if (fill) finalStyle.height = '100%' if (fill) finalStyle.width = '100%' diff --git a/features/app-core/components/Image.types.tsx b/features/app-core/components/Image.types.tsx index ae5fe5f..839416e 100644 --- a/features/app-core/components/Image.types.tsx +++ b/features/app-core/components/Image.types.tsx @@ -38,6 +38,10 @@ export type UniversalImageProps = { * - Remember that the required width and height props can interact with your styling. If you use styling to modify an image's width, you should also style its height to auto to preserve its intrinsic aspect ratio, or your image will be distorted. */ style?: ExpoImageProps['style'] + /** Universal, will affect both Expo & Next.js + * - Remember that the required width and height props can interact with your styling. If you use styling to modify an image's width, you should also style its height to auto to preserve its intrinsic aspect ratio, or your image will be distorted. */ + className?: string + /** Universal, will affect both Expo & Next.js - Called on an image fetching error. */ onError?: ExpoImageProps['onError'] diff --git a/features/app-core/components/Image.web.tsx b/features/app-core/components/Image.web.tsx index f37b907..6bcc6ee 100644 --- a/features/app-core/components/Image.web.tsx +++ b/features/app-core/components/Image.web.tsx @@ -1,5 +1,6 @@ import NextImage from 'next/image' import { UniversalImageProps, UniversalImageMethods } from './Image.types' +import { parseNativeWindStyles } from '../utils/parseNativeWindStyles' /* --- -------------------------------------------------------------------------------- */ @@ -11,6 +12,7 @@ const Image = (props: UniversalImageProps): JSX.Element => { alt, width, height, + className, style = {}, priority = 'normal', onError, @@ -31,10 +33,13 @@ const Image = (props: UniversalImageProps): JSX.Element => { contentFit, } = props + // -- Nativewind -- + + const { nativeWindStyles, nativeWindClassName, restStyle } = parseNativeWindStyles(style) + const finalStyle = { width, height, ...nativeWindStyles, ...restStyle } as React.CSSProperties + // -- Overrides -- - // @ts-ignore - const finalStyle = { width, height, ...style } if (fill) finalStyle.height = '100%' if (fill) finalStyle.width = '100%' if (fill) finalStyle.objectFit = contentFit || 'cover' @@ -47,7 +52,8 @@ const Image = (props: UniversalImageProps): JSX.Element => { src={src as any} alt={alt || accessibilityLabel} width={width} - height={height} // @ts-ignore + height={height} + className={[className, nativeWindClassName].filter(Boolean).join(' ')} style={finalStyle} priority={priority === 'high'} onError={onError as any} diff --git a/features/app-core/components/styled.tsx b/features/app-core/components/styled.tsx index eb9b30e..4a503f1 100644 --- a/features/app-core/components/styled.tsx +++ b/features/app-core/components/styled.tsx @@ -1,11 +1,13 @@ import { styled } from 'nativewind' import { Text as RNText, View as RNView } from 'react-native' import { Link as UniversalLink } from '../navigation/Link' +import { Image as UniversalImage } from './Image' /* --- Primitives ------------------------------------------------------------------------------ */ export const View = styled(RNView, '') export const Text = styled(RNText, '') +export const Image = styled(UniversalImage, '') /* --- Typography ------------------------------------------------------------------------------ */ @@ -17,6 +19,7 @@ export const P = styled(RNText, 'text-base') /* --- Fix for Next Link ----------------------------------------------------------------------- */ +export const Link = styled(UniversalLink, 'text-blue-500 underline') export const LinkText = styled(RNText, 'text-blue-500 underline') export const TextLink = (props: Omit, 'className'> & { className?: string }) => { const { className, style, children, ...universalLinkProps } = props diff --git a/features/app-core/navigation/Link.tsx b/features/app-core/navigation/Link.tsx index 6f36026..6efc365 100644 --- a/features/app-core/navigation/Link.tsx +++ b/features/app-core/navigation/Link.tsx @@ -1,5 +1,6 @@ import { Link as ExpoLink } from 'expo-router' import type { UniversalLinkProps } from './Link.types' +import { parseNativeWindStyles } from '../utils/parseNativeWindStyles' /* --- --------------------------------------------------------------------------------- */ @@ -21,12 +22,17 @@ export const Link = (props: UniversalLinkProps) => { maxFontSizeMultiplier } = props + // -- Nativewind -- + + const { nativeWindStyles, restStyle } = parseNativeWindStyles(style) + const finalStyle = { ...nativeWindStyles, ...restStyle } + // -- Render -- return ( --------------------------------------------------------------------------------- */ @@ -9,6 +10,7 @@ export const Link = (props: UniversalLinkProps) => { const { children, href, + className, style, replace, onPress, @@ -21,12 +23,18 @@ export const Link = (props: UniversalLinkProps) => { as, } = props + // -- Nativewind -- + + const { nativeWindStyles, nativeWindClassName, restStyle } = parseNativeWindStyles(style) + const finalStyle = { ...nativeWindStyles, ...restStyle } as React.CSSProperties + // -- Render -- return ( ['style']} + className={[className, nativeWindClassName].filter(Boolean).join(' ')} + style={finalStyle as unknown as ComponentProps['style']} onClick={onPress} target={target} replace={replace} diff --git a/features/app-core/screens/HomeScreen.tsx b/features/app-core/screens/HomeScreen.tsx index c07743e..fa73032 100644 --- a/features/app-core/screens/HomeScreen.tsx +++ b/features/app-core/screens/HomeScreen.tsx @@ -1,19 +1,23 @@ import React from 'react' -import { Image } from '../components/Image' -import { View, H3, P, TextLink } from '../components/styled' +import { View, Image, H3, P, Link } from '../components/styled' /* --- --------------------------------------------------------------------------- */ const HomeScreen = () => { return ( - -

Expo + Next.js app routing 👋

+ +

Expo + Next.js app routing 🚀

Open HomeScreen.tsx in features/app-core/screens to start working on your app

- + Test navigation - - Docs + + + Test images + + + Docs +
) } diff --git a/features/app-core/screens/ImagesScreen.tsx b/features/app-core/screens/ImagesScreen.tsx index 81bd68e..06a1e6e 100644 --- a/features/app-core/screens/ImagesScreen.tsx +++ b/features/app-core/screens/ImagesScreen.tsx @@ -1,67 +1,37 @@ import React from 'react' -import { StyleSheet, Text, View } from 'react-native' -import { Link } from '../navigation/Link' -import { Image } from '../components/Image' +import { View, Text, Image, Link } from '../components/styled' /* --- --------------------------------------------------------------------------- */ const ImagesScreen = () => { return ( - + {`< Back`} {/* - 1 - */} - src=static-require | width: 60 | height: 60 + src=static-require | width: 60 | height: 60 {/* - 2 - */} - src=external-url | width: 60 | height: 60 + src=external-url | width: 60 | height: 60 {/* - 3 - */} - + - wrapper=50x80, relative | fill=true + wrapper=50x80, relative | fill=true {/* - 4 - */} - + - wrapper=80x60, relative | fill | contentFit=contain + wrapper=80x60, relative | fill | contentFit=contain ) } -/* --- Styles ---------------------------------------------------------------------------------- */ - -const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: 'center', - alignItems: 'center', - }, - backButton: { - position: 'absolute', - top: 16, - left: 16, - }, - subtitle: { - marginTop: 8, - marginBottom: 16, - fontSize: 16, - textAlign: 'center', - }, - link: { - marginTop: 16, - fontSize: 16, - color: 'blue', - textAlign: 'center', - textDecorationLine: 'underline', - }, -}) - /* --- Exports --------------------------------------------------------------------------------- */ export default ImagesScreen diff --git a/features/app-core/screens/SlugScreen.tsx b/features/app-core/screens/SlugScreen.tsx index e72b264..2924afb 100644 --- a/features/app-core/screens/SlugScreen.tsx +++ b/features/app-core/screens/SlugScreen.tsx @@ -1,6 +1,6 @@ import React from 'react' import { useRouteParams } from '@app/core/navigation/useRouteParams' -import { View, Text, H3, TextLink } from '../components/styled' +import { View, Text, H3, Link } from '../components/styled' import { useRouter } from '../navigation/useRouter' /* --- --------------------------------------------------------------------------- */ @@ -32,13 +32,13 @@ const SlugScreen = (props) => { Need a more robust, Fully-Stacked, Full-Product, Universal App Setup? - Check out the GREEN Stack Starter - + push('/subpages/push')}> {`router.push()`} diff --git a/features/app-core/utils/parseNativeWindStyles.ts b/features/app-core/utils/parseNativeWindStyles.ts new file mode 100644 index 0000000..afa1855 --- /dev/null +++ b/features/app-core/utils/parseNativeWindStyles.ts @@ -0,0 +1,31 @@ + +/** --- parseNativeWindStyles() ---------------------------------------------------------------- */ +/** -i- Util to extract Nativewind's style and/or className from a styled() components style prop */ +export const parseNativeWindStyles = (style: any) => { + return Object.entries(style || {}).reduce( + (acc, [key, value]) => { + // If the key is unsupported, ignore it + if (['mask', 'childClassNames'].includes(key)) return acc + // If the key is a number, it's a Nativewind style + if (Number.isInteger(Number(key))) { + const isCSS = !!(value as Record)['$$css'] + if (isCSS) { + // If it's a CSS object, add as a Nativewind className + const { '$$css': _, ...classNameObjects } = value as Record + const className = [acc.nativeWindClassName, ...Object.values(classNameObjects)].filter(Boolean).join(' ') // prettier-ignore + return { ...acc, nativeWindClassName: className } + } else if (Array.isArray(value)) { + // If it's an array, we should merge the arrays + const flattenedStyles = value.reduce((acc, val) => ({ ...acc, ...val }), {}) + return { ...acc, nativeWindStyles: { ...acc.nativeWindStyles, ...flattenedStyles } } // prettier-ignore + } else { + // If it's a React-Native style object, check if we should merge arrays or objects + return { ...acc, nativeWindStyles: { ...acc.nativeWindStyles, ...(value as Record) } } // prettier-ignore + } + } + // If the key is a string, it's a regular style + return { ...acc, restStyle: { ...acc.restStyle, [key]: value } } + }, + { nativeWindStyles: {}, nativeWindClassName: '', restStyle: {} } + ) +}