Skip to content

Commit 767e170

Browse files
committed
feat: Add rule to enforce importing components with sx prop from @primer/styled-react
1 parent 52f3be6 commit 767e170

File tree

4 files changed

+416
-0
lines changed

4 files changed

+416
-0
lines changed

docs/rules/use-styled-react-import.md

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# use-styled-react-import
2+
3+
💼 This rule is _disabled_ in the ✅ `recommended` config.
4+
5+
🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
6+
7+
<!-- end auto-generated rule header -->
8+
9+
Enforce importing components that use `sx` prop from `@primer/styled-react` instead of `@primer/react`.
10+
11+
## Rule Details
12+
13+
This rule detects when certain Primer React components are used with the `sx` prop and ensures they are imported from the temporary `@primer/styled-react` package instead of `@primer/react`. It also moves certain types and utilities to the styled-react package.
14+
15+
### Components that should be imported from `@primer/styled-react` when used with `sx`:
16+
17+
- ActionList
18+
- ActionMenu
19+
- Box
20+
- Breadcrumbs
21+
- Button
22+
- Flash
23+
- FormControl
24+
- Heading
25+
- IconButton
26+
- Label
27+
- Link
28+
- LinkButton
29+
- PageLayout
30+
- Text
31+
- TextInput
32+
- Truncate
33+
- Octicon
34+
- Dialog
35+
36+
### Types and utilities that should always be imported from `@primer/styled-react`:
37+
38+
- `BoxProps` (type)
39+
- `SxProp` (type)
40+
- `BetterSystemStyleObject` (type)
41+
- `sx` (utility)
42+
43+
## Examples
44+
45+
### ❌ Incorrect
46+
47+
```jsx
48+
import {Button, Link} from '@primer/react'
49+
50+
const Component = () => <Button sx={{color: 'red'}}>Click me</Button>
51+
```
52+
53+
```jsx
54+
import {Box} from '@primer/react'
55+
56+
const Component = () => <Box sx={{padding: 2}}>Content</Box>
57+
```
58+
59+
```jsx
60+
import {sx} from '@primer/react'
61+
```
62+
63+
### ✅ Correct
64+
65+
```jsx
66+
import {Link} from '@primer/react'
67+
import {Button} from '@primer/styled-react'
68+
69+
const Component = () => <Button sx={{color: 'red'}}>Click me</Button>
70+
```
71+
72+
```jsx
73+
import {Box} from '@primer/styled-react'
74+
75+
const Component = () => <Box sx={{padding: 2}}>Content</Box>
76+
```
77+
78+
```jsx
79+
import {sx} from '@primer/styled-react'
80+
```
81+
82+
```jsx
83+
// Components without sx prop can stay in @primer/react
84+
import {Button} from '@primer/react'
85+
86+
const Component = () => <Button>Click me</Button>
87+
```
88+
89+
## Options
90+
91+
This rule has no options.
92+
93+
## When Not To Use It
94+
95+
This rule is specifically for migrating components that use the `sx` prop to the temporary `@primer/styled-react` package. If you're not using the `sx` prop or not participating in this migration, you can disable this rule.

src/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ module.exports = {
1919
'prefer-action-list-item-onselect': require('./rules/prefer-action-list-item-onselect'),
2020
'enforce-css-module-identifier-casing': require('./rules/enforce-css-module-identifier-casing'),
2121
'enforce-css-module-default-import': require('./rules/enforce-css-module-default-import'),
22+
'use-styled-react-import': require('./rules/use-styled-react-import'),
2223
},
2324
configs: {
2425
recommended: require('./configs/recommended'),
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
const rule = require('../use-styled-react-import')
2+
const {RuleTester} = require('eslint')
3+
4+
const ruleTester = new RuleTester({
5+
parserOptions: {
6+
ecmaVersion: 'latest',
7+
sourceType: 'module',
8+
ecmaFeatures: {
9+
jsx: true,
10+
},
11+
},
12+
})
13+
14+
ruleTester.run('use-styled-react-import', rule, {
15+
valid: [
16+
// Valid: Component used without sx prop
17+
`import { Button } from '@primer/react'
18+
const Component = () => <Button>Click me</Button>`,
19+
20+
// Valid: Component with sx prop imported from styled-react
21+
`import { Button } from '@primer/styled-react'
22+
const Component = () => <Button sx={{ color: 'red' }}>Click me</Button>`,
23+
24+
// Valid: Utilities imported from styled-react
25+
`import { sx } from '@primer/styled-react'`,
26+
27+
// Valid: Component not in the styled list
28+
`import { Avatar } from '@primer/react'
29+
const Component = () => <Avatar sx={{ color: 'red' }} />`,
30+
31+
// Valid: Mixed imports - component without sx prop
32+
`import { Button, Text } from '@primer/react'
33+
const Component = () => <Button>Click me</Button>`,
34+
],
35+
invalid: [
36+
// Invalid: Box with sx prop imported from @primer/react
37+
{
38+
code: `import { Box } from '@primer/react'
39+
const Component = () => <Box sx={{ color: 'red' }}>Content</Box>`,
40+
output: `import { Box } from '@primer/styled-react'
41+
const Component = () => <Box sx={{ color: 'red' }}>Content</Box>`,
42+
errors: [
43+
{
44+
messageId: 'useStyledReactImport',
45+
data: {componentName: 'Box'},
46+
},
47+
],
48+
},
49+
50+
// Invalid: Button with sx prop imported from @primer/react
51+
{
52+
code: `import { Button } from '@primer/react'
53+
const Component = () => <Button sx={{ margin: 2 }}>Click me</Button>`,
54+
output: `import { Button } from '@primer/styled-react'
55+
const Component = () => <Button sx={{ margin: 2 }}>Click me</Button>`,
56+
errors: [
57+
{
58+
messageId: 'useStyledReactImport',
59+
data: {componentName: 'Button'},
60+
},
61+
],
62+
},
63+
64+
// Invalid: Multiple components, one with sx prop
65+
{
66+
code: `import { Button, Box, Avatar } from '@primer/react'
67+
const Component = () => (
68+
<div>
69+
<Button>Regular button</Button>
70+
<Box sx={{ padding: 2 }}>Styled box</Box>
71+
<Avatar />
72+
</div>
73+
)`,
74+
output: `import { Button, Avatar } from '@primer/react'
75+
import { Box } from '@primer/styled-react'
76+
const Component = () => (
77+
<div>
78+
<Button>Regular button</Button>
79+
<Box sx={{ padding: 2 }}>Styled box</Box>
80+
<Avatar />
81+
</div>
82+
)`,
83+
errors: [
84+
{
85+
messageId: 'useStyledReactImport',
86+
data: {componentName: 'Box'},
87+
},
88+
],
89+
},
90+
91+
// Invalid: Utility import from @primer/react that should be from styled-react
92+
{
93+
code: `import { sx } from '@primer/react'`,
94+
output: `import { sx } from '@primer/styled-react'`,
95+
errors: [
96+
{
97+
messageId: 'moveToStyledReact',
98+
data: {importName: 'sx'},
99+
},
100+
],
101+
},
102+
103+
// Invalid: Button and Link, only Button uses sx
104+
{
105+
code: `import { Button, Link } from '@primer/react'
106+
const Component = () => <Button sx={{ color: 'red' }}>Click me</Button>`,
107+
output: `import { Link } from '@primer/react'
108+
import { Button } from '@primer/styled-react'
109+
const Component = () => <Button sx={{ color: 'red' }}>Click me</Button>`,
110+
errors: [
111+
{
112+
messageId: 'useStyledReactImport',
113+
data: {componentName: 'Button'},
114+
},
115+
],
116+
},
117+
],
118+
})

0 commit comments

Comments
 (0)