Skip to content

Commit 25a4bed

Browse files
authoredJul 21, 2024··
Fix the cx() function's class collection at runtime as it generated class instances rather than strings. (#1697)
* Fix the `cx()` function's class collection at runtime as it generated class instances rather than strings Migrate from `ac()` which generates `AtomicGroups` classes to `ax()` which strictly collects strings. This is because passing `<Component xcss={cx({ … })}>` around resulted in errors, `'cls.split is not a function'` trying to iterate over non-strings. * Add a test for pass-through props to properly utilize the cx function
1 parent 18024be commit 25a4bed

File tree

4 files changed

+104
-4
lines changed

4 files changed

+104
-4
lines changed
 

‎.changeset/friendly-eels-cover.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@compiled/react': patch
3+
---
4+
5+
Fix the `cx()` function's class collection at runtime as it generated class instances rather than strings

‎packages/react/src/create-strict-api/__tests__/__fixtures__/strict-api.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ interface CSSPropertiesSchema {
55
color: 'var(--ds-text-hover)';
66
background: 'var(--ds-surface-hover)' | 'var(--ds-surface-sunken-hover)';
77
};
8-
color: 'var(--ds-text)' | 'var(--ds-text-bold)';
9-
background: 'var(--ds-surface)' | 'var(--ds-surface-sunken)';
8+
color: 'var(--ds-text)' | 'var(--ds-text-bold)' | 'var(--ds-text-error)';
9+
background: 'var(--ds-surface)' | 'var(--ds-surface-sunken)' | 'var(--ds-surface-overlay)';
1010
bkgrnd: 'red' | 'green';
1111
}
1212

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/** @jsxImportSource @compiled/react */
2+
import { render } from '@testing-library/react';
3+
4+
import { cssMap, type XCSSProp, cx } from './__fixtures__/strict-api';
5+
6+
const styles = cssMap({
7+
rootNative: {
8+
color: 'var(--ds-text)',
9+
background: 'var(--ds-surface)',
10+
},
11+
rootComponent: {
12+
color: 'var(--ds-text-error)',
13+
background: 'var(--ds-surface-overlay)',
14+
},
15+
bold: {
16+
color: 'var(--ds-text-bold)',
17+
},
18+
sunken: {
19+
background: 'var(--ds-surface-sunken)',
20+
},
21+
});
22+
23+
function ComponentPassThrough({
24+
xcss,
25+
}: {
26+
xcss?: ReturnType<typeof XCSSProp<'background' | 'color', '&:hover'>>;
27+
}) {
28+
return <NativePassThrough xcss={cx(styles.rootComponent, xcss)} />;
29+
}
30+
31+
function NativePassThrough({
32+
xcss,
33+
}: {
34+
xcss?: ReturnType<typeof XCSSProp<'background' | 'color', '&:hover'>>;
35+
}) {
36+
return <button data-testid="button" className={xcss} css={styles.rootNative} />;
37+
}
38+
39+
describe('pass-through props.xcss directly to DOM', () => {
40+
it('works with no props.xcss', () => {
41+
const { getByTestId } = render(<NativePassThrough />);
42+
43+
expect(getByTestId('button')).toHaveCompiledCss({
44+
color: 'var(--ds-text)',
45+
background: 'var(--ds-surface)',
46+
});
47+
});
48+
49+
it('works with pass-through props.xcss', () => {
50+
const { getByTestId } = render(<NativePassThrough xcss={styles.bold} />);
51+
52+
expect(getByTestId('button')).toHaveCompiledCss({
53+
color: 'var(--ds-text-bold)',
54+
background: 'var(--ds-surface)', // rootNative styles
55+
});
56+
});
57+
58+
it('works with pass-through multiple props.xcss via cx', () => {
59+
const { getByTestId } = render(<NativePassThrough xcss={cx(styles.bold, styles.sunken)} />);
60+
61+
expect(getByTestId('button')).toHaveCompiledCss({
62+
color: 'var(--ds-text-bold)',
63+
background: 'var(--ds-surface-sunken)',
64+
});
65+
});
66+
});
67+
68+
describe('pass-through props.xcss via another component', () => {
69+
it('works with no props.xcss', () => {
70+
const { getByTestId } = render(<ComponentPassThrough />);
71+
72+
expect(getByTestId('button')).toHaveCompiledCss({
73+
color: 'var(--ds-text-error)',
74+
background: 'var(--ds-surface-overlay)',
75+
});
76+
});
77+
78+
it('works with pass-through props.xcss', () => {
79+
const { getByTestId } = render(<ComponentPassThrough xcss={styles.bold} />);
80+
81+
expect(getByTestId('button')).toHaveCompiledCss({
82+
color: 'var(--ds-text-bold)',
83+
background: 'var(--ds-surface-overlay)', // rootComponent styles
84+
});
85+
});
86+
87+
it('works with pass-through multiple props.xcss via cx', () => {
88+
const { getByTestId } = render(<ComponentPassThrough xcss={cx(styles.bold, styles.sunken)} />);
89+
90+
expect(getByTestId('button')).toHaveCompiledCss({
91+
color: 'var(--ds-text-bold)',
92+
background: 'var(--ds-surface-sunken)',
93+
});
94+
});
95+
});

‎packages/react/src/xcss-prop/index.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type * as CSS from 'csstype';
22

33
import type { ApplySchemaValue } from '../create-strict-api/types';
4-
import { ac } from '../runtime';
4+
import { ax } from '../runtime';
55
import type { CSSPseudos, CSSPseudoClasses, CSSProperties, StrictCSSProperties } from '../types';
66

77
type MarkAsRequired<T, K extends keyof T> = T & { [P in K]-?: T[P] };
@@ -208,5 +208,5 @@ export const cx = <TStyles extends [...XCSSProp<any, any>[]]>(
208208

209209
// The output should be a union type of passed in styles. This ensures the call
210210
// site of xcss prop can raise violations when disallowed styles have been passed.
211-
return ac(actualStyles) as TStyles[number];
211+
return ax(actualStyles) as TStyles[number];
212212
};

0 commit comments

Comments
 (0)
Please sign in to comment.