diff --git a/example/storybook/src/api/DescendantsStyles/ContextBasedStyles.tsx b/example/storybook/src/api/DescendantsStyles/ContextBasedStyles.tsx index 55d3d5ec2..ead6a4b04 100644 --- a/example/storybook/src/api/DescendantsStyles/ContextBasedStyles.tsx +++ b/example/storybook/src/api/DescendantsStyles/ContextBasedStyles.tsx @@ -16,9 +16,10 @@ import { import { AsForwarder, createStyled, - styled1, + styled, Theme, useBreakpointValue, + useColorMode, useStyled, useToken, } from '@gluestack-style/react'; @@ -40,6 +41,16 @@ const Pressable = styled( { bg: '$red200', p: '$2', + props: { + variant: 'solid', + }, + variants: { + variant: { + solid: { + bg: '$red400', + }, + }, + }, }, { componentName: 'Pressable', @@ -184,8 +195,17 @@ const Text1 = styled( { ancestorStyle: ['_text'], componentName: 'TEXT' } ); export function ContextBasedStyles() { + const [state, setState] = useState(false); + return ( - + + { + setState(!state); + }} + > + color mode: {state ? 'dark' : 'light'} + {/* */} @@ -229,10 +249,15 @@ export function ContextBasedStylesContent() { setTabName(tabName); }; - const value = useToken('colors', 'red500'); - - console.log(value, 'value here'); - + // const value = useToken('colors', 'red500'); + // const value = useBreakpointValue({ + // base: 'base', + // sm: 'sm', + // md: 'md', + // // md: 'md', + // }); + const colorMode = useColorMode(); + console.log(colorMode, 'color mode'); // const color = tabName ? '$red500' : '$green500'; // return ( // <> @@ -299,6 +324,12 @@ export function ContextBasedStylesContent() { const renderItem = (item: any) => ( { - let styledComponent = ( + let styledComponent = ( Component: React.ComponentType

, - styledObject: ITheme, + styledObject: ITheme, compConfig: IComponentStyleConfig = {}, extendedConfig: any = {} ) => { diff --git a/packages/react/src/hooks/useBreakpointValue.ts b/packages/react/src/hooks/useBreakpointValue.ts index a70590ffb..823a7e276 100644 --- a/packages/react/src/hooks/useBreakpointValue.ts +++ b/packages/react/src/hooks/useBreakpointValue.ts @@ -9,23 +9,46 @@ type BreakPointValue = Partial<{ [key in keyof ICustomConfig['tokens']['breakpoints']]: any; }>; +function getLastValidObject(mediaQueries: any) { + for (let i = mediaQueries.length - 1; i >= 0; i--) { + if (mediaQueries[i].isValid) { + return mediaQueries[i]; + } + } + return null; // No valid object found +} + export function useBreakpointValue(values: BreakPointValue) { let { width } = useWindowDimensions(); const theme = useStyled(); const mediaQueries = theme?.config?.tokens?.mediaQueries; - let validBreakpoints: any = []; + let mediaQueriesBreakpoints: any = []; + Object.keys(mediaQueries).forEach((key: any) => { const currentBreakpoint: any = extractWidthValues(mediaQueries[key]); const isValid = isValidBreakpoint(theme.config, mediaQueries[key], width); - if (isValid) { - validBreakpoints.push({ key: key, value: currentBreakpoint[0] }); - } + mediaQueriesBreakpoints.push({ + key: key, + breakpoint: currentBreakpoint[0], + query: mediaQueries[key], + isValid: isValid, + }); }); - if (validBreakpoints.length === 0) { + mediaQueriesBreakpoints.sort((a: any, b: any) => a.breakpoint - b.breakpoint); + + mediaQueriesBreakpoints.forEach((breakpoint: any, index: any) => { + breakpoint.value = values[breakpoint.key] + ? values[breakpoint.key] + : mediaQueriesBreakpoints[index - 1].value; + }); + + const lastValidObject = getLastValidObject(mediaQueriesBreakpoints); + + if (!lastValidObject) { return values; } - validBreakpoints.sort((a: any, b: any) => a.value - b.value); - return values[validBreakpoints[validBreakpoints.length - 1].key]; + + return lastValidObject.value; } diff --git a/packages/react/src/hooks/useColorMode.ts b/packages/react/src/hooks/useColorMode.ts index ffb745ec0..cf4c27edc 100644 --- a/packages/react/src/hooks/useColorMode.ts +++ b/packages/react/src/hooks/useColorMode.ts @@ -1,9 +1,22 @@ -import { get } from '../core/colorMode'; +import { get, onChange } from '../core/colorMode'; +import { useState, useEffect } from 'react'; /** * * @returns Current color mode value (light or dark) */ export const useColorMode = () => { - return get(); + const [currentColorMode, setCurrentColorMode] = useState(get()); + useEffect(() => { + onChange((colorMode: any) => { + setCurrentColorMode(colorMode); + }); + // remove onchage listener on unmount + () => + onChange((colorMode: any) => { + setCurrentColorMode(colorMode); + }); + }, []); + + return currentColorMode; }; diff --git a/packages/react/src/hooks/useToken.ts b/packages/react/src/hooks/useToken.ts index 44b7940b6..2bbd1b679 100644 --- a/packages/react/src/hooks/useToken.ts +++ b/packages/react/src/hooks/useToken.ts @@ -1,4 +1,5 @@ -import { useStyled, ICustomConfig } from '@gluestack-style/react'; +import { useStyled } from '../StyledProvider'; +import type { ICustomConfig } from '../types'; /** * diff --git a/packages/react/src/styled.tsx b/packages/react/src/styled.tsx index 572bfe8f2..29d2ef056 100644 --- a/packages/react/src/styled.tsx +++ b/packages/react/src/styled.tsx @@ -823,7 +823,7 @@ const getStyleIdsFromMap = ( return componentStyleObject; }; -export function verboseStyled( +export function verboseStyled( Component: React.ComponentType

, theme: Partial>, componentStyleConfig: IComponentStyleConfig = {}, @@ -991,9 +991,7 @@ export function verboseStyled( // sxHash: BUILD_TIME_sxHash = '', ...componentProps }: Omit & - Partial< - ComponentProps - > & + Partial> & Partial> & { as?: any; children?: any; @@ -1862,7 +1860,7 @@ export function verboseStyled( export function styled( Component: React.ComponentType

, - theme: ITheme, + theme: ITheme, componentStyleConfig?: IComponentStyleConfig, ExtendedConfig?: ExtendedConfigType, BUILD_TIME_PARAMS?: { @@ -1894,7 +1892,7 @@ export function styled( theme = styledObj; const sxConvertedObject = convertStyledToStyledVerbosed(theme); - let StyledComponent = verboseStyled( + let StyledComponent = verboseStyled( Component, sxConvertedObject, componentStyleConfig, diff --git a/packages/react/src/types.ts b/packages/react/src/types.ts index b77cf4292..e1af3c537 100644 --- a/packages/react/src/types.ts +++ b/packages/react/src/types.ts @@ -88,7 +88,7 @@ export type GlueStackConfig< components?: { [key: string]: { theme: Partial>; - componentConfig?: IConfigProps; + componentConfig?: IComponentStyleConfig; }; }; }; @@ -121,18 +121,10 @@ export type IMediaQueries = keyof GSConfig['tokens']['mediaQueries']; export type SxStyleProps< GenericComponentStyles, Variants, - GenericComponentProps, - PluginType + GenericComponentProps > = { sx?: Partial< - SxProps< - GenericComponentStyles, - Variants, - GenericComponentProps, - '', - '', - PluginType - > & { + SxProps & { [Key in `@${IMediaQueries}`]?: SxProps< GenericComponentStyles, Variants, @@ -147,13 +139,6 @@ export type SxStyleProps< //@ts-ignore type GlobalVariants = GSConfig['globalStyle']['variants']; -export interface IConfigProps { - descendantStyle: Array; - ancestorStyle: Array; - resolveProps: Array; - componentName: string; -} - export type IComponentStyleConfig = Partial< { descendantStyle: any; @@ -162,7 +147,6 @@ export type IComponentStyleConfig = Partial< componentName: ComCon; } & { [key: string]: any } >; -export type ConfigType = Partial & { [key: string]: any }; export type Config = { alias: { [K: string]: any }; @@ -276,23 +260,21 @@ export type GlobalStyles = GlobalVariantSx< /*********************** USER THEME / SX TYPES ****************************************/ -export type ITheme = Partial< +export type ITheme = Partial< //@ts-ignore - StyledThemeProps + StyledThemeProps >; export type StyledThemeProps< Variants, GenericComponentStyles, - GenericComponentProps, - PluginType + GenericComponentProps > = SxProps< GenericComponentStyles, Variants & GlobalVariants, GenericComponentProps, '', - '', - PluginType + '' > & { [Key in `@${IMediaQueries}`]: SxProps< GenericComponentStyles, @@ -405,8 +387,7 @@ export type SxProps< Variants = unknown, GenericComponentProps = unknown, PLATFORM = '', - MediaQuery = '', - _PluginType = [] + MediaQuery = '' > = Partial< StylePropsType & PassingPropsType< @@ -673,53 +654,48 @@ export interface GSConfig /********************* COMPONENT PROPS TYPE *****************************************/ -export type ComponentProps< - GenericComponentStyles, - Variants, - P, - ComCon, - PluginType -> = SxStyleProps & { - states?: { - [K in IState]?: boolean; - }; -} & (GSConfig['globalStyle'] extends object - ? { - [Key in keyof MergeNestedThree< - GlobalVariants, - Variants, - // @ts-ignore - Components[`${ComCon}`]['theme']['variants'] - >]?: keyof MergeNestedThree< - GlobalVariants, - Variants, - // @ts-ignore - Components[`${ComCon}`]['theme']['variants'] - >[Key] extends 'true' | 'false' - ? boolean - : keyof MergeNestedThree< - GlobalVariants, - Variants, - // @ts-ignore - Components[`${ComCon}`]['theme']['variants'] - >[Key]; - } & Omit - : { - [Key in keyof MergeNested< - Variants, - // @ts-ignore - Components[`${ComCon}`]['theme']['variants'] - >]?: keyof MergeNested< - Variants, // @ts-ignore - Components[`${ComCon}`]['theme']['variants'] - >[Key] extends 'true' | 'false' - ? boolean - : keyof MergeNested< - Variants, - // @ts-ignore - Components[`${ComCon}`]['theme']['variants'] - >[Key]; - }); +export type ComponentProps = + SxStyleProps & { + states?: { + [K in IState]?: boolean; + }; + } & (GSConfig['globalStyle'] extends object + ? { + [Key in keyof MergeNestedThree< + GlobalVariants, + Variants, + // @ts-ignore + Components[`${ComCon}`]['theme']['variants'] + >]?: keyof MergeNestedThree< + GlobalVariants, + Variants, + // @ts-ignore + Components[`${ComCon}`]['theme']['variants'] + >[Key] extends 'true' | 'false' + ? boolean + : keyof MergeNestedThree< + GlobalVariants, + Variants, + // @ts-ignore + Components[`${ComCon}`]['theme']['variants'] + >[Key]; + } & Omit + : { + [Key in keyof MergeNested< + Variants, + // @ts-ignore + Components[`${ComCon}`]['theme']['variants'] + >]?: keyof MergeNested< + Variants, // @ts-ignore + Components[`${ComCon}`]['theme']['variants'] + >[Key] extends 'true' | 'false' + ? boolean + : keyof MergeNested< + Variants, + // @ts-ignore + Components[`${ComCon}`]['theme']['variants'] + >[Key]; + }); export type UtilityProps = TokenizedRNStyleProps< GetRNStyles diff --git a/packages/react/src/utils.ts b/packages/react/src/utils.ts index 0aeb605b4..5d91159ce 100644 --- a/packages/react/src/utils.ts +++ b/packages/react/src/utils.ts @@ -253,7 +253,8 @@ export const shallowMerge = (target: any = {}, source: any) => { }; export function deepMergeObjects(...objects: any) { - const isObject = (obj: any) => obj && typeof obj === 'object'; + const isObject = (obj: any) => + obj && typeof obj === 'object' && !Array.isArray(obj); return objects.reduce((prev: any, obj: any) => { if (isObject(prev) && isObject(obj)) { @@ -262,9 +263,13 @@ export function deepMergeObjects(...objects: any) { if (!prev[key] || !isObject(prev[key])) { prev[key] = {}; } - prev[key] = deepMerge(prev[key], obj[key]); + prev[key] = deepMergeObjects(prev[key], obj[key]); } else { - prev[key] = obj[key]; + if (Array.isArray(obj[key]) && Array.isArray(prev[key])) { + prev[key] = prev[key].concat(obj[key]); // Merge arrays without converting to an object + } else { + prev[key] = obj[key]; + } } }); }