@@ -148,6 +148,53 @@ describe('registerCodegen', () => {
148148 ) ,
149149 ) . toMatchSnapshot ( )
150150 } )
151+
152+ it ( 'should generate responsive code when root node is SECTION' , async ( ) => {
153+ const figmaMock = {
154+ editorType : 'dev' ,
155+ mode : 'codegen' ,
156+ command : 'noop' ,
157+ codegen : { on : mock ( ( ) => { } ) } ,
158+ closePlugin : mock ( ( ) => { } ) ,
159+ } as unknown as typeof figma
160+
161+ codeModule . registerCodegen ( figmaMock )
162+
163+ const sectionNode = {
164+ type : 'SECTION' ,
165+ name : 'ResponsiveSection' ,
166+ visible : true ,
167+ children : [
168+ {
169+ type : 'FRAME' ,
170+ name : 'MobileFrame' ,
171+ visible : true ,
172+ width : 375 ,
173+ height : 200 ,
174+ children : [ ] ,
175+ layoutMode : 'VERTICAL' ,
176+ } ,
177+ {
178+ type : 'FRAME' ,
179+ name : 'DesktopFrame' ,
180+ visible : true ,
181+ width : 1440 ,
182+ height : 200 ,
183+ children : [ ] ,
184+ layoutMode : 'HORIZONTAL' ,
185+ } ,
186+ ] ,
187+ }
188+
189+ const result = await (
190+ figmaMock . codegen . on as ReturnType < typeof mock >
191+ ) . mock . calls [ 0 ] [ 1 ] ( {
192+ node : sectionNode ,
193+ language : 'devup-ui' ,
194+ } )
195+
196+ expect ( result ) . toMatchSnapshot ( )
197+ } )
151198} )
152199
153200it ( 'should not register codegen if figma is not defined' , async ( ) => {
@@ -633,4 +680,131 @@ describe('registerCodegen with viewport variant', () => {
633680 )
634681 }
635682 } )
683+
684+ it ( 'should generate componentsResponsiveCodes when FRAME contains INSTANCE of COMPONENT_SET with viewport' , async ( ) => {
685+ let capturedHandler : CodegenHandler | null = null
686+
687+ const figmaMock = {
688+ editorType : 'dev' ,
689+ mode : 'codegen' ,
690+ command : 'noop' ,
691+ codegen : {
692+ on : ( _event : string , handler : CodegenHandler ) => {
693+ capturedHandler = handler
694+ } ,
695+ } ,
696+ closePlugin : mock ( ( ) => { } ) ,
697+ } as unknown as typeof figma
698+
699+ codeModule . registerCodegen ( figmaMock )
700+
701+ expect ( capturedHandler ) . not . toBeNull ( )
702+ if ( capturedHandler === null ) throw new Error ( 'Handler not captured' )
703+
704+ // Create a COMPONENT_SET with viewport variants
705+ const componentSetNode = {
706+ type : 'COMPONENT_SET' ,
707+ name : 'ResponsiveButton' ,
708+ visible : true ,
709+ componentPropertyDefinitions : {
710+ viewport : {
711+ type : 'VARIANT' ,
712+ defaultValue : 'desktop' ,
713+ variantOptions : [ 'mobile' , 'desktop' ] ,
714+ } ,
715+ } ,
716+ children : [ ] as unknown [ ] ,
717+ defaultVariant : null as unknown ,
718+ }
719+
720+ // Create COMPONENT children for the COMPONENT_SET
721+ const mobileComponent = {
722+ type : 'COMPONENT' ,
723+ name : 'viewport=mobile' ,
724+ visible : true ,
725+ variantProperties : { viewport : 'mobile' } ,
726+ children : [ ] ,
727+ layoutMode : 'VERTICAL' ,
728+ width : 320 ,
729+ height : 100 ,
730+ parent : componentSetNode ,
731+ componentPropertyDefinitions : { } ,
732+ reactions : [ ] ,
733+ }
734+
735+ const desktopComponent = {
736+ type : 'COMPONENT' ,
737+ name : 'viewport=desktop' ,
738+ visible : true ,
739+ variantProperties : { viewport : 'desktop' } ,
740+ children : [ ] ,
741+ layoutMode : 'HORIZONTAL' ,
742+ width : 1200 ,
743+ height : 100 ,
744+ parent : componentSetNode ,
745+ componentPropertyDefinitions : { } ,
746+ reactions : [ ] ,
747+ }
748+
749+ componentSetNode . children = [ mobileComponent , desktopComponent ]
750+ componentSetNode . defaultVariant = desktopComponent
751+
752+ // Create an INSTANCE that references the desktop component
753+ const instanceNode = {
754+ type : 'INSTANCE' ,
755+ name : 'ResponsiveButton' ,
756+ visible : true ,
757+ width : 1200 ,
758+ height : 100 ,
759+ getMainComponentAsync : async ( ) => desktopComponent ,
760+ }
761+
762+ // Create a FRAME that contains the INSTANCE
763+ const frameNode = {
764+ type : 'FRAME' ,
765+ name : 'MyFrame' ,
766+ visible : true ,
767+ children : [ instanceNode ] ,
768+ width : 1400 ,
769+ height : 200 ,
770+ layoutMode : 'VERTICAL' ,
771+ } as unknown as SceneNode
772+
773+ const handler = capturedHandler as CodegenHandler
774+ const result = await handler ( {
775+ node : frameNode ,
776+ language : 'devup-ui' ,
777+ } )
778+
779+ // Should include Components Responsive results
780+ const responsiveResult = result . find (
781+ ( r : unknown ) =>
782+ typeof r === 'object' &&
783+ r !== null &&
784+ 'title' in r &&
785+ ( r as { title : string } ) . title === 'MyFrame - Components Responsive' ,
786+ )
787+ expect ( responsiveResult ) . toBeDefined ( )
788+
789+ // Should also include CLI results for Components Responsive
790+ const bashCLI = result . find (
791+ ( r : unknown ) =>
792+ typeof r === 'object' &&
793+ r !== null &&
794+ 'title' in r &&
795+ ( r as { title : string } ) . title ===
796+ 'MyFrame - Components Responsive CLI (Bash)' ,
797+ )
798+ expect ( bashCLI ) . toBeDefined ( )
799+
800+ const powershellCLI = result . find (
801+ ( r : unknown ) =>
802+ typeof r === 'object' &&
803+ r !== null &&
804+ 'title' in r &&
805+ ( r as { title : string } ) . title ===
806+ 'MyFrame - Components Responsive CLI (PowerShell)' ,
807+ )
808+ expect ( powershellCLI ) . toBeDefined ( )
809+ } )
636810} )
0 commit comments