diff --git a/gluestack-project/package-lock.json b/gluestack-project/package-lock.json index d21994e..4f76848 100755 --- a/gluestack-project/package-lock.json +++ b/gluestack-project/package-lock.json @@ -14,7 +14,7 @@ "@legendapp/motion": "^2.4.0", "@react-native-async-storage/async-storage": "2.2.0", "babel-plugin-module-resolver": "^5.0.2", - "expo": "^54.0.7", + "expo": "^54.0.8", "expo-status-bar": "~3.0.8", "install": "^0.13.0", "lucide-react-native": "^0.543.0", diff --git a/gluestack-project/package.json b/gluestack-project/package.json index 52ed456..ba8d285 100755 --- a/gluestack-project/package.json +++ b/gluestack-project/package.json @@ -15,7 +15,7 @@ "@legendapp/motion": "^2.4.0", "@react-native-async-storage/async-storage": "2.2.0", "babel-plugin-module-resolver": "^5.0.2", - "expo": "^54.0.7", + "expo": "^54.0.8", "expo-status-bar": "~3.0.8", "install": "^0.13.0", "lucide-react-native": "^0.543.0", diff --git a/my-expo-app/.gitignore b/my-expo-app--gluestack/.gitignore old mode 100755 new mode 100644 similarity index 100% rename from my-expo-app/.gitignore rename to my-expo-app--gluestack/.gitignore diff --git a/my-expo-app--gluestack/.npmrc b/my-expo-app--gluestack/.npmrc new file mode 100644 index 0000000..521a9f7 --- /dev/null +++ b/my-expo-app--gluestack/.npmrc @@ -0,0 +1 @@ +legacy-peer-deps=true diff --git a/my-expo-app--gluestack/App.tsx b/my-expo-app--gluestack/App.tsx new file mode 100644 index 0000000..cdb9814 --- /dev/null +++ b/my-expo-app--gluestack/App.tsx @@ -0,0 +1,25 @@ +import { StatusBar } from 'expo-status-bar'; +import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context'; + +import './global.css'; + +import { GluestackUIProvider } from '@/components/ui/gluestack-ui-provider'; +import IndexPage from './screens/IndexPage'; +import { CounterProvider } from './states/CounterProvider'; + +export default function App() { + return ( + + <> + + + + + + + + + + + ); +} diff --git a/my-expo-app/app-env.d.ts b/my-expo-app--gluestack/app-env.d.ts old mode 100755 new mode 100644 similarity index 100% rename from my-expo-app/app-env.d.ts rename to my-expo-app--gluestack/app-env.d.ts diff --git a/my-expo-app/app.json b/my-expo-app--gluestack/app.json old mode 100755 new mode 100644 similarity index 100% rename from my-expo-app/app.json rename to my-expo-app--gluestack/app.json diff --git a/my-expo-app/assets/adaptive-icon.png b/my-expo-app--gluestack/assets/adaptive-icon.png old mode 100755 new mode 100644 similarity index 100% rename from my-expo-app/assets/adaptive-icon.png rename to my-expo-app--gluestack/assets/adaptive-icon.png diff --git a/my-expo-app/assets/favicon.png b/my-expo-app--gluestack/assets/favicon.png old mode 100755 new mode 100644 similarity index 100% rename from my-expo-app/assets/favicon.png rename to my-expo-app--gluestack/assets/favicon.png diff --git a/my-expo-app/assets/icon.png b/my-expo-app--gluestack/assets/icon.png old mode 100755 new mode 100644 similarity index 100% rename from my-expo-app/assets/icon.png rename to my-expo-app--gluestack/assets/icon.png diff --git a/my-expo-app/assets/splash.png b/my-expo-app--gluestack/assets/splash.png old mode 100755 new mode 100644 similarity index 100% rename from my-expo-app/assets/splash.png rename to my-expo-app--gluestack/assets/splash.png diff --git a/my-expo-app--gluestack/babel.config.js b/my-expo-app--gluestack/babel.config.js new file mode 100644 index 0000000..a017931 --- /dev/null +++ b/my-expo-app--gluestack/babel.config.js @@ -0,0 +1,30 @@ +module.exports = function (api) { + api.cache(true); + + return { + presets: [ + [ + 'babel-preset-expo', + { + jsxImportSource: 'nativewind', + }, + ], + 'nativewind/babel', + ], + + plugins: [ + [ + 'module-resolver', + { + root: ['./'], + + alias: { + '@': './', + 'tailwind.config': './tailwind.config.js', + }, + }, + ], + 'react-native-worklets/plugin', + ], + }; +}; diff --git a/my-expo-app/cesconfig.jsonc b/my-expo-app--gluestack/cesconfig.jsonc old mode 100755 new mode 100644 similarity index 100% rename from my-expo-app/cesconfig.jsonc rename to my-expo-app--gluestack/cesconfig.jsonc diff --git a/my-expo-app--gluestack/components/ui/box/index.tsx b/my-expo-app--gluestack/components/ui/box/index.tsx new file mode 100644 index 0000000..f22bb2f --- /dev/null +++ b/my-expo-app--gluestack/components/ui/box/index.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { View, ViewProps } from 'react-native'; + +import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils'; +import { boxStyle } from './styles'; + +type IBoxProps = ViewProps & + VariantProps & { className?: string }; + +const Box = React.forwardRef, IBoxProps>( + function Box({ className, ...props }, ref) { + return ( + + ); + } +); + +Box.displayName = 'Box'; +export { Box }; diff --git a/my-expo-app--gluestack/components/ui/box/index.web.tsx b/my-expo-app--gluestack/components/ui/box/index.web.tsx new file mode 100644 index 0000000..8839eeb --- /dev/null +++ b/my-expo-app--gluestack/components/ui/box/index.web.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { boxStyle } from './styles'; + +import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils'; + +type IBoxProps = React.ComponentPropsWithoutRef<'div'> & + VariantProps & { className?: string }; + +const Box = React.forwardRef(function Box( + { className, ...props }, + ref +) { + return ( +
+ ); +}); + +Box.displayName = 'Box'; +export { Box }; diff --git a/my-expo-app--gluestack/components/ui/box/styles.tsx b/my-expo-app--gluestack/components/ui/box/styles.tsx new file mode 100644 index 0000000..d2ade82 --- /dev/null +++ b/my-expo-app--gluestack/components/ui/box/styles.tsx @@ -0,0 +1,10 @@ +import { tva } from '@gluestack-ui/utils/nativewind-utils'; +import { isWeb } from '@gluestack-ui/utils/nativewind-utils'; + +const baseStyle = isWeb + ? 'flex flex-col relative z-0 box-border border-0 list-none min-w-0 min-h-0 bg-transparent items-stretch m-0 p-0 text-decoration-none' + : ''; + +export const boxStyle = tva({ + base: baseStyle, +}); diff --git a/my-expo-app--gluestack/components/ui/button/index.tsx b/my-expo-app--gluestack/components/ui/button/index.tsx new file mode 100644 index 0000000..b75e6d5 --- /dev/null +++ b/my-expo-app--gluestack/components/ui/button/index.tsx @@ -0,0 +1,439 @@ +'use client'; +import React from 'react'; +import { createButton } from '@gluestack-ui/core/button/creator'; +import { tva } from '@gluestack-ui/utils/nativewind-utils'; +import { + withStyleContext, + useStyleContext, +} from '@gluestack-ui/utils/nativewind-utils'; +import { cssInterop } from 'nativewind'; +import { ActivityIndicator, Pressable, Text, View } from 'react-native'; +import type { VariantProps } from 'tailwind-variants'; +import { PrimitiveIcon, UIIcon } from '@gluestack-ui/core/icon/creator'; + +const SCOPE = 'BUTTON'; + +const Root = withStyleContext(Pressable, SCOPE); + +const UIButton = createButton({ + Root: Root, + Text, + Group: View, + Spinner: ActivityIndicator, + Icon: UIIcon, +}); + +cssInterop(PrimitiveIcon, { + className: { + target: 'style', + nativeStyleToProp: { + height: true, + width: true, + fill: true, + color: 'classNameColor', + stroke: true, + }, + }, +}); + +const buttonStyle = tva({ + base: 'group/button rounded bg-primary-500 flex-row items-center justify-center data-[focus-visible=true]:web:outline-none data-[focus-visible=true]:web:ring-2 data-[disabled=true]:opacity-40 gap-2', + variants: { + action: { + primary: + 'bg-primary-500 data-[hover=true]:bg-primary-600 data-[active=true]:bg-primary-700 border-primary-300 data-[hover=true]:border-primary-400 data-[active=true]:border-primary-500 data-[focus-visible=true]:web:ring-indicator-info', + secondary: + 'bg-secondary-500 border-secondary-300 data-[hover=true]:bg-secondary-600 data-[hover=true]:border-secondary-400 data-[active=true]:bg-secondary-700 data-[active=true]:border-secondary-700 data-[focus-visible=true]:web:ring-indicator-info', + positive: + 'bg-success-500 border-success-300 data-[hover=true]:bg-success-600 data-[hover=true]:border-success-400 data-[active=true]:bg-success-700 data-[active=true]:border-success-500 data-[focus-visible=true]:web:ring-indicator-info', + negative: + 'bg-error-500 border-error-300 data-[hover=true]:bg-error-600 data-[hover=true]:border-error-400 data-[active=true]:bg-error-700 data-[active=true]:border-error-500 data-[focus-visible=true]:web:ring-indicator-info', + default: + 'bg-transparent data-[hover=true]:bg-background-50 data-[active=true]:bg-transparent', + }, + variant: { + link: 'px-0', + outline: + 'bg-transparent border data-[hover=true]:bg-background-50 data-[active=true]:bg-transparent', + solid: '', + }, + + size: { + xs: 'px-3.5 h-8', + sm: 'px-4 h-9', + md: 'px-5 h-10', + lg: 'px-6 h-11', + xl: 'px-7 h-12', + }, + }, + compoundVariants: [ + { + action: 'primary', + variant: 'link', + class: + 'px-0 bg-transparent data-[hover=true]:bg-transparent data-[active=true]:bg-transparent', + }, + { + action: 'secondary', + variant: 'link', + class: + 'px-0 bg-transparent data-[hover=true]:bg-transparent data-[active=true]:bg-transparent', + }, + { + action: 'positive', + variant: 'link', + class: + 'px-0 bg-transparent data-[hover=true]:bg-transparent data-[active=true]:bg-transparent', + }, + { + action: 'negative', + variant: 'link', + class: + 'px-0 bg-transparent data-[hover=true]:bg-transparent data-[active=true]:bg-transparent', + }, + { + action: 'primary', + variant: 'outline', + class: + 'bg-transparent data-[hover=true]:bg-background-50 data-[active=true]:bg-transparent', + }, + { + action: 'secondary', + variant: 'outline', + class: + 'bg-transparent data-[hover=true]:bg-background-50 data-[active=true]:bg-transparent', + }, + { + action: 'positive', + variant: 'outline', + class: + 'bg-transparent data-[hover=true]:bg-background-50 data-[active=true]:bg-transparent', + }, + { + action: 'negative', + variant: 'outline', + class: + 'bg-transparent data-[hover=true]:bg-background-50 data-[active=true]:bg-transparent', + }, + ], +}); + +const buttonTextStyle = tva({ + base: 'text-typography-0 font-semibold web:select-none', + parentVariants: { + action: { + primary: + 'text-primary-600 data-[hover=true]:text-primary-600 data-[active=true]:text-primary-700', + secondary: + 'text-typography-500 data-[hover=true]:text-typography-600 data-[active=true]:text-typography-700', + positive: + 'text-success-600 data-[hover=true]:text-success-600 data-[active=true]:text-success-700', + negative: + 'text-error-600 data-[hover=true]:text-error-600 data-[active=true]:text-error-700', + }, + variant: { + link: 'data-[hover=true]:underline data-[active=true]:underline', + outline: '', + solid: + 'text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0', + }, + size: { + xs: 'text-xs', + sm: 'text-sm', + md: 'text-base', + lg: 'text-lg', + xl: 'text-xl', + }, + }, + parentCompoundVariants: [ + { + variant: 'solid', + action: 'primary', + class: + 'text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0', + }, + { + variant: 'solid', + action: 'secondary', + class: + 'text-typography-800 data-[hover=true]:text-typography-800 data-[active=true]:text-typography-800', + }, + { + variant: 'solid', + action: 'positive', + class: + 'text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0', + }, + { + variant: 'solid', + action: 'negative', + class: + 'text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0', + }, + { + variant: 'outline', + action: 'primary', + class: + 'text-primary-500 data-[hover=true]:text-primary-500 data-[active=true]:text-primary-500', + }, + { + variant: 'outline', + action: 'secondary', + class: + 'text-typography-500 data-[hover=true]:text-primary-600 data-[active=true]:text-typography-700', + }, + { + variant: 'outline', + action: 'positive', + class: + 'text-primary-500 data-[hover=true]:text-primary-500 data-[active=true]:text-primary-500', + }, + { + variant: 'outline', + action: 'negative', + class: + 'text-primary-500 data-[hover=true]:text-primary-500 data-[active=true]:text-primary-500', + }, + ], +}); + +const buttonIconStyle = tva({ + base: 'fill-none', + parentVariants: { + variant: { + link: 'data-[hover=true]:underline data-[active=true]:underline', + outline: '', + solid: + 'text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0', + }, + size: { + xs: 'h-3.5 w-3.5', + sm: 'h-4 w-4', + md: 'h-[18px] w-[18px]', + lg: 'h-[18px] w-[18px]', + xl: 'h-5 w-5', + }, + action: { + primary: + 'text-primary-600 data-[hover=true]:text-primary-600 data-[active=true]:text-primary-700', + secondary: + 'text-typography-500 data-[hover=true]:text-typography-600 data-[active=true]:text-typography-700', + positive: + 'text-success-600 data-[hover=true]:text-success-600 data-[active=true]:text-success-700', + + negative: + 'text-error-600 data-[hover=true]:text-error-600 data-[active=true]:text-error-700', + }, + }, + parentCompoundVariants: [ + { + variant: 'solid', + action: 'primary', + class: + 'text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0', + }, + { + variant: 'solid', + action: 'secondary', + class: + 'text-typography-800 data-[hover=true]:text-typography-800 data-[active=true]:text-typography-800', + }, + { + variant: 'solid', + action: 'positive', + class: + 'text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0', + }, + { + variant: 'solid', + action: 'negative', + class: + 'text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0', + }, + ], +}); + +const buttonGroupStyle = tva({ + base: '', + variants: { + space: { + 'xs': 'gap-1', + 'sm': 'gap-2', + 'md': 'gap-3', + 'lg': 'gap-4', + 'xl': 'gap-5', + '2xl': 'gap-6', + '3xl': 'gap-7', + '4xl': 'gap-8', + }, + isAttached: { + true: 'gap-0', + }, + flexDirection: { + 'row': 'flex-row', + 'column': 'flex-col', + 'row-reverse': 'flex-row-reverse', + 'column-reverse': 'flex-col-reverse', + }, + }, +}); + +type IButtonProps = Omit< + React.ComponentPropsWithoutRef, + 'context' +> & + VariantProps & { className?: string }; + +const Button = React.forwardRef< + React.ElementRef, + IButtonProps +>( + ( + { className, variant = 'solid', size = 'md', action = 'primary', ...props }, + ref + ) => { + return ( + + ); + } +); + +type IButtonTextProps = React.ComponentPropsWithoutRef & + VariantProps & { className?: string }; + +const ButtonText = React.forwardRef< + React.ElementRef, + IButtonTextProps +>(({ className, variant, size, action, ...props }, ref) => { + const { + variant: parentVariant, + size: parentSize, + action: parentAction, + } = useStyleContext(SCOPE); + + return ( + + ); +}); + +const ButtonSpinner = UIButton.Spinner; + +type IButtonIcon = React.ComponentPropsWithoutRef & + VariantProps & { + className?: string | undefined; + as?: React.ElementType; + height?: number; + width?: number; + }; + +const ButtonIcon = React.forwardRef< + React.ElementRef, + IButtonIcon +>(({ className, size, ...props }, ref) => { + const { + variant: parentVariant, + size: parentSize, + action: parentAction, + } = useStyleContext(SCOPE); + + if (typeof size === 'number') { + return ( + + ); + } else if ( + (props.height !== undefined || props.width !== undefined) && + size === undefined + ) { + return ( + + ); + } + return ( + + ); +}); + +type IButtonGroupProps = React.ComponentPropsWithoutRef & + VariantProps; + +const ButtonGroup = React.forwardRef< + React.ElementRef, + IButtonGroupProps +>( + ( + { + className, + space = 'md', + isAttached = false, + flexDirection = 'column', + ...props + }, + ref + ) => { + return ( + + ); + } +); + +Button.displayName = 'Button'; +ButtonText.displayName = 'ButtonText'; +ButtonSpinner.displayName = 'ButtonSpinner'; +ButtonIcon.displayName = 'ButtonIcon'; +ButtonGroup.displayName = 'ButtonGroup'; + +export { Button, ButtonText, ButtonSpinner, ButtonIcon, ButtonGroup }; diff --git a/my-expo-app--gluestack/components/ui/card/index.tsx b/my-expo-app--gluestack/components/ui/card/index.tsx new file mode 100644 index 0000000..03a4364 --- /dev/null +++ b/my-expo-app--gluestack/components/ui/card/index.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils'; +import { View, ViewProps } from 'react-native'; +import { cardStyle } from './styles'; + +type ICardProps = ViewProps & + VariantProps & { className?: string }; + +const Card = React.forwardRef, ICardProps>( + function Card( + { className, size = 'md', variant = 'elevated', ...props }, + ref + ) { + return ( + + ); + } +); + +Card.displayName = 'Card'; + +export { Card }; diff --git a/my-expo-app--gluestack/components/ui/card/index.web.tsx b/my-expo-app--gluestack/components/ui/card/index.web.tsx new file mode 100644 index 0000000..6f0ff15 --- /dev/null +++ b/my-expo-app--gluestack/components/ui/card/index.web.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { cardStyle } from './styles'; +import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils'; + +type ICardProps = React.ComponentPropsWithoutRef<'div'> & + VariantProps; + +const Card = React.forwardRef(function Card( + { className, size = 'md', variant = 'elevated', ...props }, + ref +) { + return ( +
+ ); +}); + +Card.displayName = 'Card'; + +export { Card }; diff --git a/my-expo-app--gluestack/components/ui/card/styles.tsx b/my-expo-app--gluestack/components/ui/card/styles.tsx new file mode 100644 index 0000000..6525be7 --- /dev/null +++ b/my-expo-app--gluestack/components/ui/card/styles.tsx @@ -0,0 +1,20 @@ +import { tva } from '@gluestack-ui/utils/nativewind-utils'; +import { isWeb } from '@gluestack-ui/utils/nativewind-utils'; +const baseStyle = isWeb ? 'flex flex-col relative z-0' : ''; + +export const cardStyle = tva({ + base: baseStyle, + variants: { + size: { + sm: 'p-3 rounded', + md: 'p-4 rounded-md', + lg: 'p-6 rounded-xl', + }, + variant: { + elevated: 'bg-background-0', + outline: 'border border-outline-200 ', + ghost: 'rounded-none', + filled: 'bg-background-50', + }, + }, +}); diff --git a/my-expo-app--gluestack/components/ui/center/index.tsx b/my-expo-app--gluestack/components/ui/center/index.tsx new file mode 100644 index 0000000..79ee74f --- /dev/null +++ b/my-expo-app--gluestack/components/ui/center/index.tsx @@ -0,0 +1,22 @@ +import { View, ViewProps } from 'react-native'; +import React from 'react'; +import { centerStyle } from './styles'; +import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils'; + +type ICenterProps = ViewProps & VariantProps; + +const Center = React.forwardRef, ICenterProps>( + function Center({ className, ...props }, ref) { + return ( + + ); + } +); + +Center.displayName = 'Center'; + +export { Center }; diff --git a/my-expo-app--gluestack/components/ui/center/index.web.tsx b/my-expo-app--gluestack/components/ui/center/index.web.tsx new file mode 100644 index 0000000..023a01d --- /dev/null +++ b/my-expo-app--gluestack/components/ui/center/index.web.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import { centerStyle } from './styles'; + +import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils'; + +type ICenterProps = React.ComponentPropsWithoutRef<'div'> & + VariantProps; + +const Center = React.forwardRef(function Center( + { className, ...props }, + ref +) { + return ( +
+ ); +}); + +Center.displayName = 'Center'; + +export { Center }; diff --git a/my-expo-app--gluestack/components/ui/center/styles.tsx b/my-expo-app--gluestack/components/ui/center/styles.tsx new file mode 100644 index 0000000..576d23a --- /dev/null +++ b/my-expo-app--gluestack/components/ui/center/styles.tsx @@ -0,0 +1,8 @@ +import { tva } from '@gluestack-ui/utils/nativewind-utils'; +import { isWeb } from '@gluestack-ui/utils/nativewind-utils'; + +const baseStyle = isWeb ? 'flex flex-col relative z-0' : ''; + +export const centerStyle = tva({ + base: `justify-center items-center ${baseStyle}`, +}); diff --git a/my-expo-app--gluestack/components/ui/gluestack-ui-provider/config.ts b/my-expo-app--gluestack/components/ui/gluestack-ui-provider/config.ts new file mode 100644 index 0000000..f388cc6 --- /dev/null +++ b/my-expo-app--gluestack/components/ui/gluestack-ui-provider/config.ts @@ -0,0 +1,309 @@ +'use client'; +import { vars } from 'nativewind'; + +export const config = { + light: vars({ + '--color-primary-0': '179 179 179', + '--color-primary-50': '153 153 153', + '--color-primary-100': '128 128 128', + '--color-primary-200': '115 115 115', + '--color-primary-300': '102 102 102', + '--color-primary-400': '82 82 82', + '--color-primary-500': '51 51 51', + '--color-primary-600': '41 41 41', + '--color-primary-700': '31 31 31', + '--color-primary-800': '13 13 13', + '--color-primary-900': '10 10 10', + '--color-primary-950': '8 8 8', + + /* Secondary */ + '--color-secondary-0': '253 253 253', + '--color-secondary-50': '251 251 251', + '--color-secondary-100': '246 246 246', + '--color-secondary-200': '242 242 242', + '--color-secondary-300': '237 237 237', + '--color-secondary-400': '230 230 231', + '--color-secondary-500': '217 217 219', + '--color-secondary-600': '198 199 199', + '--color-secondary-700': '189 189 189', + '--color-secondary-800': '177 177 177', + '--color-secondary-900': '165 164 164', + '--color-secondary-950': '157 157 157', + + /* Tertiary */ + '--color-tertiary-0': '255 250 245', + '--color-tertiary-50': '255 242 229', + '--color-tertiary-100': '255 233 213', + '--color-tertiary-200': '254 209 170', + '--color-tertiary-300': '253 180 116', + '--color-tertiary-400': '251 157 75', + '--color-tertiary-500': '231 129 40', + '--color-tertiary-600': '215 117 31', + '--color-tertiary-700': '180 98 26', + '--color-tertiary-800': '130 73 23', + '--color-tertiary-900': '108 61 19', + '--color-tertiary-950': '84 49 18', + + /* Error */ + '--color-error-0': '254 233 233', + '--color-error-50': '254 226 226', + '--color-error-100': '254 202 202', + '--color-error-200': '252 165 165', + '--color-error-300': '248 113 113', + '--color-error-400': '239 68 68', + '--color-error-500': '230 53 53', + '--color-error-600': '220 38 38', + '--color-error-700': '185 28 28', + '--color-error-800': '153 27 27', + '--color-error-900': '127 29 29', + '--color-error-950': '83 19 19', + + /* Success */ + '--color-success-0': '228 255 244', + '--color-success-50': '202 255 232', + '--color-success-100': '162 241 192', + '--color-success-200': '132 211 162', + '--color-success-300': '102 181 132', + '--color-success-400': '72 151 102', + '--color-success-500': '52 131 82', + '--color-success-600': '42 121 72', + '--color-success-700': '32 111 62', + '--color-success-800': '22 101 52', + '--color-success-900': '20 83 45', + '--color-success-950': '27 50 36', + + /* Warning */ + '--color-warning-0': '255 249 245', + '--color-warning-50': '255 244 236', + '--color-warning-100': '255 231 213', + '--color-warning-200': '254 205 170', + '--color-warning-300': '253 173 116', + '--color-warning-400': '251 149 75', + '--color-warning-500': '231 120 40', + '--color-warning-600': '215 108 31', + '--color-warning-700': '180 90 26', + '--color-warning-800': '130 68 23', + '--color-warning-900': '108 56 19', + '--color-warning-950': '84 45 18', + + /* Info */ + '--color-info-0': '236 248 254', + '--color-info-50': '199 235 252', + '--color-info-100': '162 221 250', + '--color-info-200': '124 207 248', + '--color-info-300': '87 194 246', + '--color-info-400': '50 180 244', + '--color-info-500': '13 166 242', + '--color-info-600': '11 141 205', + '--color-info-700': '9 115 168', + '--color-info-800': '7 90 131', + '--color-info-900': '5 64 93', + '--color-info-950': '3 38 56', + + /* Typography */ + '--color-typography-0': '254 254 255', + '--color-typography-50': '245 245 245', + '--color-typography-100': '229 229 229', + '--color-typography-200': '219 219 220', + '--color-typography-300': '212 212 212', + '--color-typography-400': '163 163 163', + '--color-typography-500': '140 140 140', + '--color-typography-600': '115 115 115', + '--color-typography-700': '82 82 82', + '--color-typography-800': '64 64 64', + '--color-typography-900': '38 38 39', + '--color-typography-950': '23 23 23', + + /* Outline */ + '--color-outline-0': '253 254 254', + '--color-outline-50': '243 243 243', + '--color-outline-100': '230 230 230', + '--color-outline-200': '221 220 219', + '--color-outline-300': '211 211 211', + '--color-outline-400': '165 163 163', + '--color-outline-500': '140 141 141', + '--color-outline-600': '115 116 116', + '--color-outline-700': '83 82 82', + '--color-outline-800': '65 65 65', + '--color-outline-900': '39 38 36', + '--color-outline-950': '26 23 23', + + /* Background */ + '--color-background-0': '255 255 255', + '--color-background-50': '246 246 246', + '--color-background-100': '242 241 241', + '--color-background-200': '220 219 219', + '--color-background-300': '213 212 212', + '--color-background-400': '162 163 163', + '--color-background-500': '142 142 142', + '--color-background-600': '116 116 116', + '--color-background-700': '83 82 82', + '--color-background-800': '65 64 64', + '--color-background-900': '39 38 37', + '--color-background-950': '18 18 18', + + /* Background Special */ + '--color-background-error': '254 241 241', + '--color-background-warning': '255 243 234', + '--color-background-success': '237 252 242', + '--color-background-muted': '247 248 247', + '--color-background-info': '235 248 254', + + /* Focus Ring Indicator */ + '--color-indicator-primary': '55 55 55', + '--color-indicator-info': '83 153 236', + '--color-indicator-error': '185 28 28', + }), + dark: vars({ + '--color-primary-0': '166 166 166', + '--color-primary-50': '175 175 175', + '--color-primary-100': '186 186 186', + '--color-primary-200': '197 197 197', + '--color-primary-300': '212 212 212', + '--color-primary-400': '221 221 221', + '--color-primary-500': '230 230 230', + '--color-primary-600': '240 240 240', + '--color-primary-700': '250 250 250', + '--color-primary-800': '253 253 253', + '--color-primary-900': '254 249 249', + '--color-primary-950': '253 252 252', + + /* Secondary */ + '--color-secondary-0': '20 20 20', + '--color-secondary-50': '23 23 23', + '--color-secondary-100': '31 31 31', + '--color-secondary-200': '39 39 39', + '--color-secondary-300': '44 44 44', + '--color-secondary-400': '56 57 57', + '--color-secondary-500': '63 64 64', + '--color-secondary-600': '86 86 86', + '--color-secondary-700': '110 110 110', + '--color-secondary-800': '135 135 135', + '--color-secondary-900': '150 150 150', + '--color-secondary-950': '164 164 164', + + /* Tertiary */ + '--color-tertiary-0': '84 49 18', + '--color-tertiary-50': '108 61 19', + '--color-tertiary-100': '130 73 23', + '--color-tertiary-200': '180 98 26', + '--color-tertiary-300': '215 117 31', + '--color-tertiary-400': '231 129 40', + '--color-tertiary-500': '251 157 75', + '--color-tertiary-600': '253 180 116', + '--color-tertiary-700': '254 209 170', + '--color-tertiary-800': '255 233 213', + '--color-tertiary-900': '255 242 229', + '--color-tertiary-950': '255 250 245', + + /* Error */ + '--color-error-0': '83 19 19', + '--color-error-50': '127 29 29', + '--color-error-100': '153 27 27', + '--color-error-200': '185 28 28', + '--color-error-300': '220 38 38', + '--color-error-400': '230 53 53', + '--color-error-500': '239 68 68', + '--color-error-600': '249 97 96', + '--color-error-700': '229 91 90', + '--color-error-800': '254 202 202', + '--color-error-900': '254 226 226', + '--color-error-950': '254 233 233', + + /* Success */ + '--color-success-0': '27 50 36', + '--color-success-50': '20 83 45', + '--color-success-100': '22 101 52', + '--color-success-200': '32 111 62', + '--color-success-300': '42 121 72', + '--color-success-400': '52 131 82', + '--color-success-500': '72 151 102', + '--color-success-600': '102 181 132', + '--color-success-700': '132 211 162', + '--color-success-800': '162 241 192', + '--color-success-900': '202 255 232', + '--color-success-950': '228 255 244', + + /* Warning */ + '--color-warning-0': '84 45 18', + '--color-warning-50': '108 56 19', + '--color-warning-100': '130 68 23', + '--color-warning-200': '180 90 26', + '--color-warning-300': '215 108 31', + '--color-warning-400': '231 120 40', + '--color-warning-500': '251 149 75', + '--color-warning-600': '253 173 116', + '--color-warning-700': '254 205 170', + '--color-warning-800': '255 231 213', + '--color-warning-900': '255 244 237', + '--color-warning-950': '255 249 245', + + /* Info */ + '--color-info-0': '3 38 56', + '--color-info-50': '5 64 93', + '--color-info-100': '7 90 131', + '--color-info-200': '9 115 168', + '--color-info-300': '11 141 205', + '--color-info-400': '13 166 242', + '--color-info-500': '50 180 244', + '--color-info-600': '87 194 246', + '--color-info-700': '124 207 248', + '--color-info-800': '162 221 250', + '--color-info-900': '199 235 252', + '--color-info-950': '236 248 254', + + /* Typography */ + '--color-typography-0': '23 23 23', + '--color-typography-50': '38 38 39', + '--color-typography-100': '64 64 64', + '--color-typography-200': '82 82 82', + '--color-typography-300': '115 115 115', + '--color-typography-400': '140 140 140', + '--color-typography-500': '163 163 163', + '--color-typography-600': '212 212 212', + '--color-typography-700': '219 219 220', + '--color-typography-800': '229 229 229', + '--color-typography-900': '245 245 245', + '--color-typography-950': '254 254 255', + + /* Outline */ + '--color-outline-0': '26 23 23', + '--color-outline-50': '39 38 36', + '--color-outline-100': '65 65 65', + '--color-outline-200': '83 82 82', + '--color-outline-300': '115 116 116', + '--color-outline-400': '140 141 141', + '--color-outline-500': '165 163 163', + '--color-outline-600': '211 211 211', + '--color-outline-700': '221 220 219', + '--color-outline-800': '230 230 230', + '--color-outline-900': '243 243 243', + '--color-outline-950': '253 254 254', + + /* Background */ + '--color-background-0': '18 18 18', + '--color-background-50': '39 38 37', + '--color-background-100': '65 64 64', + '--color-background-200': '83 82 82', + '--color-background-300': '116 116 116', + '--color-background-400': '142 142 142', + '--color-background-500': '162 163 163', + '--color-background-600': '213 212 212', + '--color-background-700': '229 228 228', + '--color-background-800': '242 241 241', + '--color-background-900': '246 246 246', + '--color-background-950': '255 255 255', + + /* Background Special */ + '--color-background-error': '66 43 43', + '--color-background-warning': '65 47 35', + '--color-background-success': '28 43 33', + '--color-background-muted': '51 51 51', + '--color-background-info': '26 40 46', + + /* Focus Ring Indicator */ + '--color-indicator-primary': '247 247 247', + '--color-indicator-info': '161 199 245', + '--color-indicator-error': '232 70 69', + }), +}; diff --git a/my-expo-app--gluestack/components/ui/gluestack-ui-provider/index.next15.tsx b/my-expo-app--gluestack/components/ui/gluestack-ui-provider/index.next15.tsx new file mode 100644 index 0000000..4fafc40 --- /dev/null +++ b/my-expo-app--gluestack/components/ui/gluestack-ui-provider/index.next15.tsx @@ -0,0 +1,87 @@ +// This is a Next.js 15 compatible version of the GluestackUIProvider +'use client'; +import React, { useEffect, useLayoutEffect } from 'react'; +import { config } from './config'; +import { OverlayProvider } from '@gluestack-ui/core/overlay/creator'; +import { ToastProvider } from '@gluestack-ui/core/toast/creator'; +import { setFlushStyles } from '@gluestack-ui/utils/nativewind-utils'; +import { script } from './script'; + +const variableStyleTagId = 'nativewind-style'; +const createStyle = (styleTagId: string) => { + const style = document.createElement('style'); + style.id = styleTagId; + style.appendChild(document.createTextNode('')); + return style; +}; + +export const useSafeLayoutEffect = + typeof window !== 'undefined' ? useLayoutEffect : useEffect; + +export function GluestackUIProvider({ + mode = 'light', + ...props +}: { + mode?: 'light' | 'dark' | 'system'; + children?: React.ReactNode; +}) { + let cssVariablesWithMode = ``; + Object.keys(config).forEach((configKey) => { + cssVariablesWithMode += + configKey === 'dark' ? `\n .dark {\n ` : `\n:root {\n`; + const cssVariables = Object.keys( + config[configKey as keyof typeof config] + ).reduce((acc: string, curr: string) => { + acc += `${curr}:${config[configKey as keyof typeof config][curr]}; `; + return acc; + }, ''); + cssVariablesWithMode += `${cssVariables} \n}`; + }); + + setFlushStyles(cssVariablesWithMode); + + const handleMediaQuery = React.useCallback((e: MediaQueryListEvent) => { + script(e.matches ? 'dark' : 'light'); + }, []); + + useSafeLayoutEffect(() => { + if (mode !== 'system') { + const documentElement = document.documentElement; + if (documentElement) { + documentElement.classList.add(mode); + documentElement.classList.remove(mode === 'light' ? 'dark' : 'light'); + documentElement.style.colorScheme = mode; + } + } + }, [mode]); + + useSafeLayoutEffect(() => { + if (mode !== 'system') return; + const media = window.matchMedia('(prefers-color-scheme: dark)'); + + media.addListener(handleMediaQuery); + + return () => media.removeListener(handleMediaQuery); + }, [handleMediaQuery]); + + useSafeLayoutEffect(() => { + if (typeof window !== 'undefined') { + const documentElement = document.documentElement; + if (documentElement) { + const head = documentElement.querySelector('head'); + let style = head?.querySelector(`[id='${variableStyleTagId}']`); + if (!style) { + style = createStyle(variableStyleTagId); + style.innerHTML = cssVariablesWithMode; + if (head) head.appendChild(style); + } + } + } + }, []); + + return ( + + {props.children} + + ); +} diff --git a/my-expo-app--gluestack/components/ui/gluestack-ui-provider/index.tsx b/my-expo-app--gluestack/components/ui/gluestack-ui-provider/index.tsx new file mode 100644 index 0000000..3453713 --- /dev/null +++ b/my-expo-app--gluestack/components/ui/gluestack-ui-provider/index.tsx @@ -0,0 +1,38 @@ +import React, { useEffect } from 'react'; +import { config } from './config'; +import { View, ViewProps } from 'react-native'; +import { OverlayProvider } from '@gluestack-ui/core/overlay/creator'; +import { ToastProvider } from '@gluestack-ui/core/toast/creator'; +import { useColorScheme } from 'nativewind'; + +export type ModeType = 'light' | 'dark' | 'system'; + +export function GluestackUIProvider({ + mode = 'light', + ...props +}: { + mode?: ModeType; + children?: React.ReactNode; + style?: ViewProps['style']; +}) { + const { colorScheme, setColorScheme } = useColorScheme(); + + useEffect(() => { + setColorScheme(mode); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [mode]); + + return ( + + + {props.children} + + + ); +} diff --git a/my-expo-app--gluestack/components/ui/gluestack-ui-provider/index.web.tsx b/my-expo-app--gluestack/components/ui/gluestack-ui-provider/index.web.tsx new file mode 100644 index 0000000..610b6ad --- /dev/null +++ b/my-expo-app--gluestack/components/ui/gluestack-ui-provider/index.web.tsx @@ -0,0 +1,96 @@ +'use client'; +import React, { useEffect, useLayoutEffect } from 'react'; +import { config } from './config'; +import { OverlayProvider } from '@gluestack-ui/core/overlay/creator'; +import { ToastProvider } from '@gluestack-ui/core/toast/creator'; +import { setFlushStyles } from '@gluestack-ui/utils/nativewind-utils'; +import { script } from './script'; + +export type ModeType = 'light' | 'dark' | 'system'; + +const variableStyleTagId = 'nativewind-style'; +const createStyle = (styleTagId: string) => { + const style = document.createElement('style'); + style.id = styleTagId; + style.appendChild(document.createTextNode('')); + return style; +}; + +export const useSafeLayoutEffect = + typeof window !== 'undefined' ? useLayoutEffect : useEffect; + +export function GluestackUIProvider({ + mode = 'light', + ...props +}: { + mode?: ModeType; + children?: React.ReactNode; +}) { + let cssVariablesWithMode = ``; + Object.keys(config).forEach((configKey) => { + cssVariablesWithMode += + configKey === 'dark' ? `\n .dark {\n ` : `\n:root {\n`; + const cssVariables = Object.keys( + config[configKey as keyof typeof config] + ).reduce((acc: string, curr: string) => { + acc += `${curr}:${config[configKey as keyof typeof config][curr]}; `; + return acc; + }, ''); + cssVariablesWithMode += `${cssVariables} \n}`; + }); + + setFlushStyles(cssVariablesWithMode); + + const handleMediaQuery = React.useCallback((e: MediaQueryListEvent) => { + script(e.matches ? 'dark' : 'light'); + }, []); + + useSafeLayoutEffect(() => { + if (mode !== 'system') { + const documentElement = document.documentElement; + if (documentElement) { + documentElement.classList.add(mode); + documentElement.classList.remove(mode === 'light' ? 'dark' : 'light'); + documentElement.style.colorScheme = mode; + } + } + }, [mode]); + + useSafeLayoutEffect(() => { + if (mode !== 'system') return; + const media = window.matchMedia('(prefers-color-scheme: dark)'); + + media.addListener(handleMediaQuery); + + return () => media.removeListener(handleMediaQuery); + }, [handleMediaQuery]); + + useSafeLayoutEffect(() => { + if (typeof window !== 'undefined') { + const documentElement = document.documentElement; + if (documentElement) { + const head = documentElement.querySelector('head'); + let style = head?.querySelector(`[id='${variableStyleTagId}']`); + if (!style) { + style = createStyle(variableStyleTagId); + style.innerHTML = cssVariablesWithMode; + if (head) head.appendChild(style); + } + } + } + }, []); + + return ( + <> +