-
Notifications
You must be signed in to change notification settings - Fork 70
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* chore: add example type test * feat: introduce stricter types part 1 * chore: update docs * feat: wire up xcss prop * feat: adds xcss inline object support * feat: add support for simple collection of pass styles * chore: move * feat: expose cx util * chore: add failing test * chore: remove strict types and replace with direct cx usage * chore: fix types * chore: code review * feat: block at rules from xcss prop * chore: add css prop test * fix: update jsx namespace * chore: add tests and jsdoc * chore: code review * chore: update changeset message * chore: update type from code review * chore: fix spelling * chore: resolve code review comments * chore: remove unused * chore: fix types * chore: ensure selectors isnt available * feat: add scope option --------- Co-authored-by: Alex Hinds <[email protected]>
- Loading branch information
Showing
15 changed files
with
808 additions
and
94 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
--- | ||
'@compiled/babel-plugin': patch | ||
'@compiled/react': patch | ||
--- | ||
|
||
The xcss prop is now available. | ||
Declare styles your component takes with all other styles marked as violations | ||
by the TypeScript compiler. There are two primary use cases for xcss prop: | ||
|
||
- safe style overrides | ||
- inverting style declarations | ||
|
||
Interverting style declarations is interesting for platform teams as | ||
it means products only pay for styles they use as they're now the ones who declare | ||
the styles! | ||
|
||
The `XCSSProp` type has generics which must be defined — of which should be what you | ||
explicitly want to maintain as API. Use `XCSSAllProperties` and `XCSSAllPseudos` types | ||
to enable all properties and pseudos. | ||
|
||
```tsx | ||
import { type XCSSProp } from '@compiled/react'; | ||
|
||
interface MyComponentProps { | ||
// Color is accepted, all other properties / pseudos are considered violations. | ||
xcss?: XCSSProp<'color', never>; | ||
|
||
// Only backgrond color and hover pseudo is accepted. | ||
xcss?: XCSSProp<'backgroundColor', '&:hover'>; | ||
|
||
// All properties are accepted, all pseudos are considered violations. | ||
xcss?: XCSSProp<XCSSAllProperties, never>; | ||
|
||
// All properties are accepted, only the hover pseudo is accepted. | ||
xcss?: XCSSProp<XCSSAllProperties, '&:hover'>; | ||
} | ||
|
||
function MyComponent({ xcss }: MyComponentProps) { | ||
return <div css={{ color: 'var(--ds-text-danger)' }} className={xcss} />; | ||
} | ||
``` | ||
|
||
The xcss prop works with static inline objects and the [cssMap](https://compiledcssinjs.com/docs/api-cssmap) API. | ||
|
||
```tsx | ||
// Declared as an inline object | ||
<Component xcss={{ color: 'var(--ds-text)' }} />; | ||
|
||
// Declared with the cssMap API | ||
const styles = cssMap({ text: { color: 'var(--ds-text)' } }); | ||
<Component xcss={styles.text} />; | ||
``` | ||
|
||
To concatenate and conditonally apply styles use the `cssMap` and `cx` functions. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
193 changes: 193 additions & 0 deletions
193
packages/babel-plugin/src/xcss-prop/__tests__/transformation.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
import { transform } from '../../test-utils'; | ||
|
||
describe('xcss prop transformation', () => { | ||
it('should transform static inline object', () => { | ||
const result = transform(` | ||
<Component xcss={{ color: 'red' }} /> | ||
`); | ||
|
||
expect(result).toMatchInlineSnapshot(` | ||
"import * as React from "react"; | ||
import { ax, ix, CC, CS } from "@compiled/react/runtime"; | ||
const _ = "._syaz5scu{color:red}"; | ||
<CC> | ||
<CS>{[_]}</CS> | ||
{<Component xcss={"_syaz5scu"} />} | ||
</CC>; | ||
" | ||
`); | ||
}); | ||
|
||
it('should throw when not static', () => { | ||
expect(() => { | ||
transform( | ||
` | ||
import { bar } from './foo'; | ||
<Component xcss={{ color: bar }} /> | ||
`, | ||
{ highlightCode: false } | ||
); | ||
}).toThrowErrorMatchingInlineSnapshot(` | ||
"unknown file: Object given to the xcss prop must be static (4:23). | ||
2 | import { bar } from './foo'; | ||
3 | | ||
> 4 | <Component xcss={{ color: bar }} /> | ||
| ^^^^^^^^^^^^^^ | ||
5 | " | ||
`); | ||
}); | ||
|
||
it('should transform named xcss prop usage', () => { | ||
const result = transform(` | ||
<Component innerXcss={{ color: 'red' }} /> | ||
`); | ||
|
||
expect(result).toMatchInlineSnapshot(` | ||
"import * as React from "react"; | ||
import { ax, ix, CC, CS } from "@compiled/react/runtime"; | ||
const _ = "._syaz5scu{color:red}"; | ||
<CC> | ||
<CS>{[_]}</CS> | ||
{<Component innerXcss={"_syaz5scu"} />} | ||
</CC>; | ||
" | ||
`); | ||
}); | ||
|
||
it('should work with css map', () => { | ||
const result = transform(` | ||
import { cssMap } from '@compiled/react'; | ||
const styles = cssMap({ | ||
primary: { color: 'red' }, | ||
}); | ||
<Component xcss={styles.primary} /> | ||
`); | ||
|
||
expect(result).toMatchInlineSnapshot(` | ||
"import * as React from "react"; | ||
import { ax, ix, CC, CS } from "@compiled/react/runtime"; | ||
const _ = "._syaz5scu{color:red}"; | ||
const styles = { | ||
primary: "_syaz5scu", | ||
}; | ||
<CC> | ||
<CS>{[_]}</CS> | ||
{<Component xcss={styles.primary} />} | ||
</CC>; | ||
" | ||
`); | ||
}); | ||
|
||
it('should allow ternaries', () => { | ||
const result = transform(` | ||
import { cssMap } from '@compiled/react'; | ||
const styles = cssMap({ | ||
primary: { color: 'red' }, | ||
secondary: { color: 'blue' } | ||
}); | ||
<Component xcss={isPrimary ? styles.primary : styles.secondary} /> | ||
`); | ||
|
||
expect(result).toMatchInlineSnapshot(` | ||
"import * as React from "react"; | ||
import { ax, ix, CC, CS } from "@compiled/react/runtime"; | ||
const _2 = "._syaz13q2{color:blue}"; | ||
const _ = "._syaz5scu{color:red}"; | ||
const styles = { | ||
primary: "_syaz5scu", | ||
secondary: "_syaz13q2", | ||
}; | ||
<CC> | ||
<CS>{[_, _2]}</CS> | ||
{<Component xcss={isPrimary ? styles.primary : styles.secondary} />} | ||
</CC>; | ||
" | ||
`); | ||
}); | ||
|
||
it('should allow concatenating styles', () => { | ||
const result = transform(` | ||
import { cssMap, j } from '@compiled/react'; | ||
const styles = cssMap({ | ||
primary: { color: 'red' }, | ||
secondary: { color: 'blue' } | ||
}); | ||
<Component xcss={j(isPrimary && styles.primary, !isPrimary && styles.secondary)} /> | ||
`); | ||
|
||
expect(result).toMatchInlineSnapshot(` | ||
"import * as React from "react"; | ||
import { ax, ix, CC, CS } from "@compiled/react/runtime"; | ||
import { j } from "@compiled/react"; | ||
const _2 = "._syaz13q2{color:blue}"; | ||
const _ = "._syaz5scu{color:red}"; | ||
const styles = { | ||
primary: "_syaz5scu", | ||
secondary: "_syaz13q2", | ||
}; | ||
<CC> | ||
<CS>{[_, _2]}</CS> | ||
{ | ||
<Component | ||
xcss={j(isPrimary && styles.primary, !isPrimary && styles.secondary)} | ||
/> | ||
} | ||
</CC>; | ||
" | ||
`); | ||
}); | ||
|
||
it('should ignore xcss prop when compiled must be in scope', () => { | ||
const result = transform( | ||
` | ||
<Component xcss={{ color: 'red' }} /> | ||
`, | ||
{ requireCompiledInScopeForXCSSProp: true } | ||
); | ||
|
||
expect(result).toMatchInlineSnapshot(` | ||
"<Component | ||
xcss={{ | ||
color: "red", | ||
}} | ||
/>; | ||
" | ||
`); | ||
}); | ||
|
||
it('should transform xcss prop when compiled is in scope', () => { | ||
const result = transform( | ||
` | ||
import { cssMap } from '@compiled/react'; | ||
const styles = cssMap({ | ||
primary: { color: 'red' }, | ||
}); | ||
<Component xcss={styles.primary} /> | ||
`, | ||
{ requireCompiledInScopeForXCSSProp: true } | ||
); | ||
|
||
expect(result).toMatchInlineSnapshot(` | ||
"import * as React from "react"; | ||
import { ax, ix, CC, CS } from "@compiled/react/runtime"; | ||
const _ = "._syaz5scu{color:red}"; | ||
const styles = { | ||
primary: "_syaz5scu", | ||
}; | ||
<CC> | ||
<CS>{[_]}</CS> | ||
{<Component xcss={styles.primary} />} | ||
</CC>; | ||
" | ||
`); | ||
}); | ||
}); |
Oops, something went wrong.