@@ -32,7 +32,8 @@ import { ResponsiveStyleValue, stringifyStyles } from './utils/styles';
3232const styleKeyToClass = new Map < string , string > ( ) ;
3333let nextClassId = 0 ;
3434function allocateClassName ( styleKey : string , contextKey ?: string ) : string {
35- const key = contextKey ? `${ styleKey } ||${ contextKey } ` : styleKey ;
35+ // Use null character as separator for better performance and no collision risk
36+ const key = contextKey ? `${ styleKey } \0${ contextKey } ` : styleKey ;
3637 const existing = styleKeyToClass . get ( key ) ;
3738 if ( existing ) return existing ;
3839 const cls = `t${ nextClassId ++ } ` ;
@@ -88,10 +89,10 @@ type TastyComponentPropsWithDefaults<
8889> = keyof DefaultProps extends never
8990 ? Props
9091 : {
91- [ key in Extract < keyof Props , keyof DefaultProps > ] ?: Props [ key ] ;
92- } & {
93- [ key in keyof Omit < Props , keyof DefaultProps > ] : Props [ key ] ;
94- } ;
92+ [ key in Extract < keyof Props , keyof DefaultProps > ] ?: Props [ key ] ;
93+ } & {
94+ [ key in keyof Omit < Props , keyof DefaultProps > ] : Props [ key ] ;
95+ } ;
9596
9697export function tasty < K extends StyleList , V extends VariantMap > (
9798 options : TastyProps < K , V > ,
@@ -131,13 +132,12 @@ function tastyGlobal(selector: string, styles?: Styles) {
131132 let contextBreakpoints = useContext ( BreakpointsContext ) ;
132133
133134 const breakpointsList = ( breakpoints ?? contextBreakpoints ) || [ 980 ] ;
134- const breakpointsHash = breakpointsList . join ( ',' ) ;
135135 const disposeRef = useRef < ( ( ) => void ) | null > ( null ) ;
136136
137137 const styleResults = useMemo ( ( ) => {
138138 if ( ! styles ) return [ ] ;
139139 return renderStyles ( styles , breakpointsList , selector , true ) ;
140- } , [ selector , breakpointsHash ] ) ;
140+ } , [ selector , styles , breakpointsList ] ) ;
141141
142142 // Inject styles at insertion phase; cleanup on change/unmount
143143 useInsertionEffect ( ( ) => {
@@ -322,23 +322,21 @@ function tastyElement<K extends StyleList, V extends VariantMap>(
322322 className : userClassName ,
323323 ...otherProps
324324 } = allProps as Record < string , unknown > as AllBasePropsWithMods < K > &
325- WithVariant < V > & { className ?: string } ;
325+ WithVariant < V > & { className ?: string } ;
326+
327+ // Optimize propStyles extraction - avoid creating empty objects
328+ let propStyles : Styles | null = null ;
329+ const propsToCheck = styleProps
330+ ? ( styleProps as StyleList ) . concat ( BASE_STYLES )
331+ : BASE_STYLES ;
326332
327- let propStyles : Styles | null = (
328- ( styleProps
329- ? ( styleProps as StyleList ) . concat ( BASE_STYLES )
330- : BASE_STYLES ) as StyleList
331- ) . reduce ( ( map , prop ) => {
333+ for ( const prop of propsToCheck ) {
332334 const key = prop as unknown as string ;
333335 if ( Object . prototype . hasOwnProperty . call ( otherProps as object , key ) ) {
334- ( map as any ) [ key ] = ( otherProps as any ) [ key ] ;
336+ if ( ! propStyles ) propStyles = { } ;
337+ ( propStyles as any ) [ key ] = ( otherProps as any ) [ key ] ;
335338 delete ( otherProps as any ) [ key ] ;
336339 }
337- return map ;
338- } , { } as Styles ) ;
339-
340- if ( Object . keys ( propStyles ) . length === 0 ) {
341- propStyles = null ;
342340 }
343341
344342 if (
@@ -348,38 +346,39 @@ function tastyElement<K extends StyleList, V extends VariantMap>(
348346 styles = undefined as unknown as Styles ;
349347 }
350348
351- const propStylesCacheKey = stringifyStyles ( propStyles ) ;
352- const stylesCacheKey = useMemo ( ( ) => stringifyStyles ( styles ) , [ styles ] ) ;
353-
354- const useDefaultStyles = ! propStyles && ! styles ;
355-
356- const styleCacheKey = useMemo (
357- ( ) => `${ propStylesCacheKey } .${ stylesCacheKey } ` ,
358- [ propStylesCacheKey , stylesCacheKey ] ,
359- ) ;
360-
361- let allStyles : Styles | undefined = useMemo (
362- ( ) =>
363- useDefaultStyles
364- ? defaultStyles
365- : mergeStyles (
366- defaultStyles ,
367- styles as Styles ,
368- propStyles as Styles ,
369- ) ,
370- [ styleCacheKey ] ,
371- ) ;
372-
373349 let contextBreakpoints = useContext ( BreakpointsContext ) ;
374-
375350 breakpoints = ( breakpoints as number [ ] | undefined ) ?? contextBreakpoints ;
376351
377- // Allocate a stable sequential class per style-key
378- const className = useMemo ( ( ) => {
379- const stylesKey = stringifyStyles ( allStyles || { } ) ;
380- const bpKey = ( breakpoints as number [ ] | undefined ) ?. join ( ',' ) || '' ;
381- return allocateClassName ( stylesKey , `bp:${ bpKey } ` ) ;
382- } , [ allStyles , breakpoints ?. join ( ',' ) ] ) ;
352+ // Memoize breakpoints key once
353+ const breakpointsKey = useMemo (
354+ ( ) => ( breakpoints as number [ ] | undefined ) ?. join ( ',' ) || '' ,
355+ [ breakpoints ?. join ( ',' ) ] ,
356+ ) ;
357+
358+ // Optimize style computation and className allocation
359+ const { allStyles, className, useDefaultStyles } = useMemo ( ( ) => {
360+ const hasStyles =
361+ styles && Object . keys ( styles as Record < string , unknown > ) . length > 0 ;
362+ const hasPropStyles = propStyles && Object . keys ( propStyles ) . length > 0 ;
363+ const useDefault = ! hasStyles && ! hasPropStyles ;
364+
365+ const merged = useDefault
366+ ? defaultStyles
367+ : mergeStyles ( defaultStyles , styles as Styles , propStyles as Styles ) ;
368+
369+ // Single stringifyStyles call
370+ const styleKey = stringifyStyles ( merged || { } ) ;
371+ const cls = allocateClassName (
372+ styleKey ,
373+ breakpointsKey ? `bp:${ breakpointsKey } ` : undefined ,
374+ ) ;
375+
376+ return {
377+ allStyles : merged ,
378+ className : cls ,
379+ useDefaultStyles : useDefault ,
380+ } ;
381+ } , [ styles , propStyles , breakpointsKey ] ) ;
383382
384383 // Compute rules synchronously; inject via insertion effect
385384 const directResult : RenderResult = useMemo ( ( ) => {
@@ -390,7 +389,7 @@ function tastyElement<K extends StyleList, V extends VariantMap>(
390389 } else {
391390 return { rules : [ ] , className : '' } ;
392391 }
393- } , [ useDefaultStyles , allStyles , breakpoints ?. join ( ',' ) , className ] ) ;
392+ } , [ useDefaultStyles , allStyles , breakpointsKey , className ] ) ;
394393
395394 const disposeRef = useRef < ( ( ) => void ) | null > ( null ) ;
396395
@@ -456,8 +455,9 @@ function tastyElement<K extends StyleList, V extends VariantMap>(
456455 } ) ;
457456 }
458457
459- _TastyComponent . displayName = `TastyComponent(${ ( defaultProps as any ) . qa || originalAs
460- } )`;
458+ _TastyComponent . displayName = `TastyComponent(${
459+ ( defaultProps as any ) . qa || originalAs
460+ } )`;
461461
462462 return _TastyComponent ;
463463}
0 commit comments