Skip to content

Commit 35f822b

Browse files
authored
Merge pull request #20 from dev-five-git/real-testr
Real testr
2 parents c7a152e + 4f110aa commit 35f822b

19 files changed

+34019
-72
lines changed

src/code-impl.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Codegen } from './codegen/Codegen'
22
import { ResponsiveCodegen } from './codegen/responsive/ResponsiveCodegen'
3+
import { nodeProxyTracker } from './codegen/utils/node-proxy'
34
import { exportDevup, importDevup } from './commands/devup'
45
import { exportAssets } from './commands/exportAssets'
56
import { exportComponents } from './commands/exportComponents'
@@ -113,9 +114,12 @@ function generatePowerShellCLI(
113114
return commands.join('\n')
114115
}
115116

117+
const debug = true
118+
116119
export function registerCodegen(ctx: typeof figma) {
117120
if (ctx.editorType === 'dev' && ctx.mode === 'codegen') {
118-
ctx.codegen.on('generate', async ({ node, language }) => {
121+
ctx.codegen.on('generate', async ({ node: n, language }) => {
122+
const node = debug ? nodeProxyTracker.wrap(n) : n
119123
switch (language) {
120124
case 'devup-ui': {
121125
const time = Date.now()
@@ -161,6 +165,11 @@ export function registerCodegen(ctx: typeof figma) {
161165
console.error('[responsive] Error generating responsive code:', e)
162166
}
163167
}
168+
if (debug) {
169+
console.log(
170+
await nodeProxyTracker.toTestCaseFormatWithVariables(node.id),
171+
)
172+
}
164173

165174
return [
166175
...(node.type === 'COMPONENT' ||
@@ -202,6 +211,16 @@ export function registerCodegen(ctx: typeof figma) {
202211
.map((code) => code[1])
203212
.join('\n\n'),
204213
},
214+
{
215+
title: `${node.name} - Components Responsive CLI (Bash)`,
216+
language: 'BASH' as const,
217+
code: generateBashCLI(responsiveComponentsCodes),
218+
},
219+
{
220+
title: `${node.name} - Components Responsive CLI (PowerShell)`,
221+
language: 'BASH' as const,
222+
code: generatePowerShellCLI(responsiveComponentsCodes),
223+
},
205224
]
206225
: []),
207226
...responsiveResult,

src/codegen/__tests__/codegen-viewport.test.ts

Lines changed: 343 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,3 +355,346 @@ describe('Codegen viewport variant', () => {
355355
expect(codes.length).toBe(2)
356356
})
357357
})
358+
359+
describe('Codegen effect-only COMPONENT_SET', () => {
360+
test('generates code with pseudo-selectors for effect-only component set', async () => {
361+
// Create effect variants: default, hover, active, disabled
362+
const defaultVariant = createComponentNode(
363+
'effect=default',
364+
{ effect: 'default' },
365+
{
366+
fills: [
367+
{
368+
type: 'SOLID',
369+
visible: true,
370+
color: { r: 0.5, g: 0.3, b: 0.9 },
371+
opacity: 1,
372+
} as unknown as Paint,
373+
],
374+
reactions: [
375+
{
376+
trigger: { type: 'ON_HOVER' },
377+
actions: [
378+
{
379+
type: 'NODE',
380+
transition: {
381+
type: 'SMART_ANIMATE',
382+
duration: 0.3,
383+
easing: { type: 'EASE_OUT' },
384+
},
385+
},
386+
],
387+
},
388+
] as unknown as Reaction[],
389+
},
390+
)
391+
392+
const hoverVariant = createComponentNode(
393+
'effect=hover',
394+
{ effect: 'hover' },
395+
{
396+
fills: [
397+
{
398+
type: 'SOLID',
399+
visible: true,
400+
color: { r: 0.4, g: 0.2, b: 0.8 },
401+
opacity: 1,
402+
} as unknown as Paint,
403+
],
404+
},
405+
)
406+
407+
const activeVariant = createComponentNode(
408+
'effect=active',
409+
{ effect: 'active' },
410+
{
411+
fills: [
412+
{
413+
type: 'SOLID',
414+
visible: true,
415+
color: { r: 0.3, g: 0.1, b: 0.7 },
416+
opacity: 1,
417+
} as unknown as Paint,
418+
],
419+
},
420+
)
421+
422+
const disabledVariant = createComponentNode(
423+
'effect=disabled',
424+
{ effect: 'disabled' },
425+
{
426+
fills: [
427+
{
428+
type: 'SOLID',
429+
visible: true,
430+
color: { r: 0.8, g: 0.8, b: 0.8 },
431+
opacity: 1,
432+
} as unknown as Paint,
433+
],
434+
},
435+
)
436+
437+
const componentSet = createComponentSetNode(
438+
'EffectButton',
439+
{
440+
effect: {
441+
type: 'VARIANT',
442+
defaultValue: 'default',
443+
variantOptions: ['default', 'hover', 'active', 'disabled'],
444+
},
445+
},
446+
[defaultVariant, hoverVariant, activeVariant, disabledVariant],
447+
)
448+
449+
const codes = await ResponsiveCodegen.generateVariantResponsiveComponents(
450+
componentSet,
451+
'EffectButton',
452+
)
453+
454+
expect(codes.length).toBe(1)
455+
const [componentName, generatedCode] = codes[0]
456+
expect(componentName).toBe('EffectButton')
457+
458+
// Should have pseudo-selector props
459+
expect(generatedCode).toContain('_hover')
460+
expect(generatedCode).toContain('_active')
461+
expect(generatedCode).toContain('_disabled')
462+
463+
// Should have transition properties
464+
expect(generatedCode).toContain('transition=')
465+
expect(generatedCode).toContain('transitionProperty=')
466+
467+
// Should NOT have effect as a prop (handled via pseudo-selectors)
468+
expect(generatedCode).not.toContain('effect:')
469+
})
470+
471+
test('generates code with viewport + effect variants', async () => {
472+
// Mobile variants
473+
const mobileDefault = createComponentNode(
474+
'effect=default, viewport=Mobile',
475+
{ effect: 'default', viewport: 'Mobile' },
476+
{
477+
width: 150,
478+
height: 50,
479+
layoutSizingHorizontal: 'FIXED',
480+
layoutSizingVertical: 'FIXED',
481+
fills: [
482+
{
483+
type: 'SOLID',
484+
visible: true,
485+
color: { r: 0.5, g: 0.5, b: 0.5 },
486+
opacity: 1,
487+
} as unknown as Paint,
488+
],
489+
},
490+
)
491+
492+
const mobileHover = createComponentNode(
493+
'effect=hover, viewport=Mobile',
494+
{ effect: 'hover', viewport: 'Mobile' },
495+
{
496+
width: 150,
497+
height: 50,
498+
layoutSizingHorizontal: 'FIXED',
499+
layoutSizingVertical: 'FIXED',
500+
fills: [
501+
{
502+
type: 'SOLID',
503+
visible: true,
504+
color: { r: 0.6, g: 0.6, b: 0.6 },
505+
opacity: 1,
506+
} as unknown as Paint,
507+
],
508+
},
509+
)
510+
511+
// Desktop variants
512+
const desktopDefault = createComponentNode(
513+
'effect=default, viewport=Desktop',
514+
{ effect: 'default', viewport: 'Desktop' },
515+
{
516+
width: 200,
517+
height: 50,
518+
layoutSizingHorizontal: 'FIXED',
519+
layoutSizingVertical: 'FIXED',
520+
fills: [
521+
{
522+
type: 'SOLID',
523+
visible: true,
524+
color: { r: 0.5, g: 0.5, b: 0.5 },
525+
opacity: 1,
526+
} as unknown as Paint,
527+
],
528+
},
529+
)
530+
531+
const desktopHover = createComponentNode(
532+
'effect=hover, viewport=Desktop',
533+
{ effect: 'hover', viewport: 'Desktop' },
534+
{
535+
width: 200,
536+
height: 50,
537+
layoutSizingHorizontal: 'FIXED',
538+
layoutSizingVertical: 'FIXED',
539+
fills: [
540+
{
541+
type: 'SOLID',
542+
visible: true,
543+
color: { r: 0.7, g: 0.7, b: 0.7 },
544+
opacity: 1,
545+
} as unknown as Paint,
546+
],
547+
},
548+
)
549+
550+
const componentSet = createComponentSetNode(
551+
'ResponsiveEffectButton',
552+
{
553+
effect: {
554+
type: 'VARIANT',
555+
defaultValue: 'default',
556+
variantOptions: ['default', 'hover'],
557+
},
558+
viewport: {
559+
type: 'VARIANT',
560+
defaultValue: 'Desktop',
561+
variantOptions: ['Mobile', 'Desktop'],
562+
},
563+
},
564+
[mobileDefault, mobileHover, desktopDefault, desktopHover],
565+
)
566+
567+
const codes = await ResponsiveCodegen.generateVariantResponsiveComponents(
568+
componentSet,
569+
'ResponsiveEffectButton',
570+
)
571+
572+
expect(codes.length).toBe(1)
573+
const [componentName, generatedCode] = codes[0]
574+
expect(componentName).toBe('ResponsiveEffectButton')
575+
576+
// Should have responsive width (different for mobile vs desktop)
577+
expect(generatedCode).toContain('w={')
578+
expect(generatedCode).toContain('"150px"')
579+
expect(generatedCode).toContain('"200px"')
580+
581+
// Should have _hover with responsive bg colors
582+
expect(generatedCode).toContain('_hover')
583+
})
584+
585+
test('generates code with effect + size variants', async () => {
586+
// Size=Md variants
587+
const mdDefault = createComponentNode(
588+
'effect=default, size=Md',
589+
{ effect: 'default', size: 'Md' },
590+
{
591+
width: 100,
592+
height: 50,
593+
layoutSizingHorizontal: 'FIXED',
594+
layoutSizingVertical: 'FIXED',
595+
fills: [
596+
{
597+
type: 'SOLID',
598+
visible: true,
599+
color: { r: 0.2, g: 0.4, b: 0.8 },
600+
opacity: 1,
601+
} as unknown as Paint,
602+
],
603+
},
604+
)
605+
606+
const mdHover = createComponentNode(
607+
'effect=hover, size=Md',
608+
{ effect: 'hover', size: 'Md' },
609+
{
610+
width: 100,
611+
height: 50,
612+
layoutSizingHorizontal: 'FIXED',
613+
layoutSizingVertical: 'FIXED',
614+
fills: [
615+
{
616+
type: 'SOLID',
617+
visible: true,
618+
color: { r: 0.3, g: 0.5, b: 0.9 },
619+
opacity: 1,
620+
} as unknown as Paint,
621+
],
622+
},
623+
)
624+
625+
// Size=Sm variants
626+
const smDefault = createComponentNode(
627+
'effect=default, size=Sm',
628+
{ effect: 'default', size: 'Sm' },
629+
{
630+
width: 80,
631+
height: 40,
632+
layoutSizingHorizontal: 'FIXED',
633+
layoutSizingVertical: 'FIXED',
634+
fills: [
635+
{
636+
type: 'SOLID',
637+
visible: true,
638+
color: { r: 0.2, g: 0.4, b: 0.8 },
639+
opacity: 1,
640+
} as unknown as Paint,
641+
],
642+
},
643+
)
644+
645+
const smHover = createComponentNode(
646+
'effect=hover, size=Sm',
647+
{ effect: 'hover', size: 'Sm' },
648+
{
649+
width: 80,
650+
height: 40,
651+
layoutSizingHorizontal: 'FIXED',
652+
layoutSizingVertical: 'FIXED',
653+
fills: [
654+
{
655+
type: 'SOLID',
656+
visible: true,
657+
color: { r: 0.3, g: 0.5, b: 0.9 },
658+
opacity: 1,
659+
} as unknown as Paint,
660+
],
661+
},
662+
)
663+
664+
const componentSet = createComponentSetNode(
665+
'SizeEffectButton',
666+
{
667+
effect: {
668+
type: 'VARIANT',
669+
defaultValue: 'default',
670+
variantOptions: ['default', 'hover'],
671+
},
672+
size: {
673+
type: 'VARIANT',
674+
defaultValue: 'Md',
675+
variantOptions: ['Md', 'Sm'],
676+
},
677+
},
678+
[mdDefault, mdHover, smDefault, smHover],
679+
)
680+
681+
const codes = await ResponsiveCodegen.generateVariantResponsiveComponents(
682+
componentSet,
683+
'SizeEffectButton',
684+
)
685+
686+
expect(codes.length).toBe(1)
687+
const [componentName, generatedCode] = codes[0]
688+
expect(componentName).toBe('SizeEffectButton')
689+
690+
// Should have size prop in interface
691+
expect(generatedCode).toContain("size: 'Md' | 'Sm'")
692+
693+
// Should have variant-conditional width
694+
expect(generatedCode).toContain('w={')
695+
expect(generatedCode).toContain('[size]')
696+
697+
// Should have _hover props
698+
expect(generatedCode).toContain('_hover')
699+
})
700+
})

0 commit comments

Comments
 (0)