@@ -56,27 +56,7 @@ describe('extractCssLayerNameFromAppearance', () => {
5656 expect ( extractCssLayerNameFromAppearance ( undefined ) ) . toBeUndefined ( ) ;
5757 } ) ;
5858
59- describe ( 'Components.updateProps state merge' , ( ) => {
60- // This replicates the state merge in Components.tsx updateProps handler:
61- // setState(s => ({ ...s, ...restProps, options: { ...s.options, ...restProps.options } }))
62- //
63- // When ClerkProvider re-renders, it calls __internal_updateProps({ appearance: { theme: shadcn } }).
64- // This arrives in updateProps as restProps = { appearance: { theme: shadcn } }.
65- // The bug: cssLayerName buried in theme is not promoted to appearance level,
66- // so StyleCacheProvider never wraps Clerk CSS in @layer .
67-
68- function updatePropsStateMerge ( currentState : Record < string , any > , restProps : Record < string , any > ) {
69- // This is the exact logic from Components.tsx line 400 (without fix)
70- return { ...currentState , ...restProps , options : { ...currentState . options , ...restProps . options } } ;
71- }
72-
73- function updatePropsStateMergeFixed ( currentState : Record < string , any > , restProps : Record < string , any > ) {
74- if ( restProps . appearance ) {
75- restProps = { ...restProps , appearance : extractCssLayerNameFromAppearance ( restProps . appearance ) } ;
76- }
77- return { ...currentState , ...restProps , options : { ...currentState . options , ...restProps . options } } ;
78- }
79-
59+ it ( 'persists cssLayerName when appearance is re-extracted after an updateProps-style state merge' , ( ) => {
8060 const theme = {
8161 name : 'shadcn' ,
8262 cssLayerName : 'components' ,
@@ -85,25 +65,32 @@ describe('extractCssLayerNameFromAppearance', () => {
8565 __type : 'prebuilt_appearance' as const ,
8666 } ;
8767
88- const initialState = {
89- appearance : { theme, cssLayerName : 'components' } , // after mountComponentRenderer extraction
90- options : { } ,
91- } ;
68+ // Initial mount: cssLayerName is extracted to appearance level
69+ const initialAppearance = extractCssLayerNameFromAppearance ( { theme } ) ;
70+ expect ( initialAppearance ?. cssLayerName ) . toBe ( 'components' ) ;
71+
72+ // ClerkProvider re-renders and sends raw appearance (cssLayerName only inside theme)
73+ const rawAppearance = { theme } ;
9274
93- it ( 'BUG: updateProps overwrites extracted cssLayerName with raw appearance from ClerkProvider' , ( ) => {
94- // ClerkProvider sends raw appearance (cssLayerName only inside theme, not at top level)
95- const restProps = { appearance : { theme } } ;
96- const newState = updatePropsStateMerge ( initialState , restProps ) ;
75+ // updateProps must re-extract before merging into state
76+ const reExtracted = extractCssLayerNameFromAppearance ( rawAppearance ) ;
77+ expect ( reExtracted ?. cssLayerName ) . toBe ( 'components' ) ;
78+ } ) ;
9779
98- // cssLayerName is lost — it's only inside theme, not at the appearance level
99- expect ( newState . appearance . cssLayerName ) . toBeUndefined ( ) ;
100- } ) ;
80+ it ( 'respects a new cssLayerName passed via updateProps' , ( ) => {
81+ const theme = {
82+ name : 'shadcn' ,
83+ cssLayerName : 'components' ,
84+ variables : { } ,
85+ elements : { } ,
86+ __type : 'prebuilt_appearance' as const ,
87+ } ;
10188
102- it ( 'FIX: updateProps extracts cssLayerName from theme before merging into state' , ( ) => {
103- const restProps = { appearance : { theme } } ;
104- const newState = updatePropsStateMergeFixed ( initialState , restProps ) ;
89+ // User changes cssLayerName at the appearance level
90+ const updatedAppearance = { theme, cssLayerName : 'utilities' } ;
91+ const result = extractCssLayerNameFromAppearance ( updatedAppearance ) ;
10592
106- expect ( newState . appearance . cssLayerName ) . toBe ( 'components' ) ;
107- } ) ;
93+ // Explicit appearance-level cssLayerName takes precedence over theme
94+ expect ( result ?. cssLayerName ) . toBe ( 'utilities' ) ;
10895 } ) ;
10996} ) ;
0 commit comments