diff --git a/.changeset/fruity-cooks-flow.md b/.changeset/fruity-cooks-flow.md new file mode 100644 index 00000000..23f25d13 --- /dev/null +++ b/.changeset/fruity-cooks-flow.md @@ -0,0 +1,6 @@ +--- +"@blockle/blocks-core": patch +"@blockle/blocks": patch +--- + +fix getComponentStyles when using defaults diff --git a/packages/core/src/theme/getComponentStyles.test.ts b/packages/core/src/theme/getComponentStyles.test.ts index 0fa93618..f6d4439b 100644 --- a/packages/core/src/theme/getComponentStyles.test.ts +++ b/packages/core/src/theme/getComponentStyles.test.ts @@ -47,14 +47,6 @@ describe('getComponentStyles', () => { expect(result).toBe('btn-sm'); }); - it('should apply multiple variant styles', () => { - const result = getComponentStyles(testTheme, 'button', { - variants: { size: 'large' }, - }); - - expect(result).toBe('btn-lg'); - }); - it('should combine root and variant styles', () => { const result = getComponentStyles(testTheme, 'button', { root: true, @@ -332,7 +324,7 @@ describe('getComponentStyles', () => { expect(result).toBe('btn-base btn-elevated'); }); - it('should handle non-existent variant values gracefully', () => { + it('should return empty string for non-existent variant values', () => { const result = getComponentStyles(testTheme, 'button', { variants: { size: 'medium' as unknown as 'small' | 'large' }, }); @@ -371,4 +363,123 @@ describe('getComponentStyles', () => { 'btn-base btn-full-width btn-sm btn-primary btn-small-primary', ); }); + + it('should return empty string when no style props provided', () => { + const result = getComponentStyles(testTheme, 'button', {}); + + expect(result).toBe(''); + }); + + it('should ignore variants when component has no variants defined', () => { + const minimalTheme = { + components: { + button: { + root: 'btn-base', + variants: {}, + }, + }, + } satisfies Partial as unknown as Theme; + + const result = getComponentStyles(minimalTheme, 'button', { + root: true, + variants: { size: 'small' }, + }); + + expect(result).toBe('btn-base'); + }); + + it('should handle compound variants with partial match from defaults', () => { + const themeWithCompound = { + components: { + button: { + root: 'btn-base', + variants: { + size: { small: 'btn-sm', large: 'btn-lg' }, + intent: { primary: 'btn-primary', secondary: 'btn-secondary' }, + }, + defaultVariants: { intent: 'primary' }, + compoundVariants: [ + { + variants: { size: 'small', intent: 'primary' }, + style: 'btn-small-primary', + }, + ], + }, + }, + } satisfies Partial as unknown as Theme; + + const result = getComponentStyles(themeWithCompound, 'button', { + variants: { size: 'small' }, + }); + + expect(result).toBe('btn-sm btn-primary btn-small-primary'); + }); + + it('should handle empty compoundVariants array', () => { + const themeWithEmptyCompound = { + components: { + button: { + root: 'btn-base', + variants: { + size: { small: 'btn-sm', large: 'btn-lg' }, + }, + compoundVariants: [], + }, + }, + } satisfies Partial as unknown as Theme; + + const result = getComponentStyles(themeWithEmptyCompound, 'button', { + variants: { size: 'small' }, + }); + + expect(result).toBe('btn-sm'); + }); + + it('should prioritize provided variants over default variants in compound matching', () => { + const themeWithCompound = { + components: { + button: { + root: 'btn-base', + variants: { + size: { small: 'btn-sm', large: 'btn-lg' }, + intent: { primary: 'btn-primary', secondary: 'btn-secondary' }, + }, + defaultVariants: { size: 'large', intent: 'secondary' }, + compoundVariants: [ + { + variants: { size: 'small', intent: 'primary' }, + style: 'btn-small-primary', + }, + ], + }, + }, + } satisfies Partial as unknown as Theme; + + const result = getComponentStyles(themeWithCompound, 'button', { + variants: { size: 'small', intent: 'primary' }, + }); + + expect(result).toBe('btn-sm btn-primary btn-small-primary'); + }); + + it('should handle mixed string and boolean variants', () => { + const mixedTheme = { + components: { + button: { + root: 'btn-base', + variants: { + size: { small: 'btn-sm', large: 'btn-lg' }, + disabled: 'btn-disabled', + loading: 'btn-loading', + }, + }, + }, + } satisfies Partial as unknown as Theme; + + const result = getComponentStyles(mixedTheme, 'button', { + variants: { size: 'small', disabled: true, loading: false }, + }); + + expect(result).toBe('btn-sm btn-disabled'); + }); }); diff --git a/packages/core/src/theme/getComponentStyles.ts b/packages/core/src/theme/getComponentStyles.ts index c60092b0..90666723 100644 --- a/packages/core/src/theme/getComponentStyles.ts +++ b/packages/core/src/theme/getComponentStyles.ts @@ -31,11 +31,6 @@ export function getComponentStyles( } } - // No variants for component, return early - if (!componentVariants) { - return classNames.join(' '); - } - const defaultVariants = useDefaultVariants ? component.defaultVariants : null; for (const key in componentVariants) {