Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Make use-styled-react-import rule configurable #407

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
jonrohan merged 2 commits into main from use_styled_react_component_configuration
Sep 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/large-cherries-cheat.md
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"eslint-plugin-primer-react": minor
---

Make `use-styled-react-import` rule configurable
50 changes: 49 additions & 1 deletion docs/rules/use-styled-react-import.md
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,55 @@ const Component2 = () => <StyledButton sx={{color: 'red'}}>Styled me</StyledButt

## Options

This rule has no options.
This rule accepts an optional configuration object with the following properties:

- `styledComponents` (array of strings): Components that should be imported from `@primer/styled-react` when used with `sx` prop. Defaults to the list shown above.
- `styledTypes` (array of strings): Types that should always be imported from `@primer/styled-react`. Defaults to `['BoxProps', 'SxProp', 'BetterSystemStyleObject']`.
- `styledUtilities` (array of strings): Utilities that should always be imported from `@primer/styled-react`. Defaults to `['sx']`.

### Example Configuration

```json
{
"rules": {
"@primer/primer-react/use-styled-react-import": [
"error",
{
"styledComponents": ["Button", "Box", "CustomComponent"],
"styledTypes": ["BoxProps", "CustomProps"],
"styledUtilities": ["sx", "customSx"]
}
]
}
}
```

### Configuration Examples

#### ❌ Incorrect with custom configuration

```jsx
// With styledComponents: ["CustomButton"]
import {CustomButton} from '@primer/react'

const Component = () => <CustomButton sx={{color: 'red'}}>Click me</CustomButton>
```

#### βœ… Correct with custom configuration

```jsx
// With styledComponents: ["CustomButton"]
import {CustomButton} from '@primer/styled-react'

const Component = () => <CustomButton sx={{color: 'red'}}>Click me</CustomButton>
```

```jsx
// Box is not in custom styledComponents list, so it can be used with sx from @primer/react
import {Box} from '@primer/react'

const Component = () => <Box sx={{color: 'red'}}>Content</Box>
```

## When Not To Use It

Expand Down
61 changes: 61 additions & 0 deletions src/rules/__tests__/use-styled-react-import.test.js
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -249,3 +249,64 @@ import { Button as StyledButton, Link } from '@primer/styled-react'
},
],
})

// Test configuration options
ruleTester.run('use-styled-react-import with custom configuration', rule, {
valid: [
// Valid: Custom component not in default list
{
code: `import { CustomButton } from '@primer/react'
const Component = () => <CustomButton sx={{ color: 'red' }}>Click me</CustomButton>`,
options: [{}], // Using default configuration
},

// Valid: Custom component in custom list used without sx prop
{
code: `import { CustomButton } from '@primer/react'
const Component = () => <CustomButton>Click me</CustomButton>`,
options: [{styledComponents: ['CustomButton']}],
},

// Valid: Custom component with sx prop imported from styled-react
{
code: `import { CustomButton } from '@primer/styled-react'
const Component = () => <CustomButton sx={{ color: 'red' }}>Click me</CustomButton>`,
options: [{styledComponents: ['CustomButton']}],
},

// Valid: Box not in custom list, so sx usage is allowed from @primer/react
{
code: `import { Box } from '@primer/react'
const Component = () => <Box sx={{ color: 'red' }}>Content</Box>`,
options: [{styledComponents: ['CustomButton']}], // Box not included
},
],
invalid: [
// Invalid: Custom component with sx prop should be from styled-react
{
code: `import { CustomButton } from '@primer/react'
const Component = () => <CustomButton sx={{ color: 'red' }}>Click me</CustomButton>`,
output: `import { CustomButton } from '@primer/styled-react'
const Component = () => <CustomButton sx={{ color: 'red' }}>Click me</CustomButton>`,
options: [{styledComponents: ['CustomButton']}],
errors: [
{
messageId: 'useStyledReactImport',
data: {componentName: 'CustomButton'},
},
],
},
// Invalid: Custom utility should be from styled-react
{
code: `import { customSx } from '@primer/react'`,
output: `import { customSx } from '@primer/styled-react'`,
options: [{styledUtilities: ['customSx']}],
errors: [
{
messageId: 'moveToStyledReact',
data: {importName: 'customSx'},
},
],
},
],
})
43 changes: 35 additions & 8 deletions src/rules/use-styled-react-import.js
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
const url = require('../url')
const {getJSXOpeningElementName} = require('../utils/get-jsx-opening-element-name')

// Components that should be imported from @primer/styled-react when used with sx prop
const styledComponents = new Set([
// Default components that should be imported from @primer/styled-react when used with sx prop
const defaultStyledComponents = [
'ActionList',
'ActionMenu',
'Box',
Expand All @@ -23,13 +23,13 @@ const styledComponents = new Set([
'Truncate',
'Octicon',
'Dialog',
])
]

// Types that should be imported from @primer/styled-react
const styledTypes = new Set(['BoxProps', 'SxProp', 'BetterSystemStyleObject'])
// Default types that should be imported from @primer/styled-react
const defaultStyledTypes = ['BoxProps', 'SxProp', 'BetterSystemStyleObject']

// Utilities that should be imported from @primer/styled-react
const styledUtilities = new Set(['sx'])
// Default utilities that should be imported from @primer/styled-react
const defaultStyledUtilities = ['sx']

/**
* @type {import('eslint').Rule.RuleModule}
Expand All @@ -43,7 +43,29 @@ module.exports = {
url: url(module),
},
fixable: 'code',
schema: [],
schema: [
{
type: 'object',
properties: {
styledComponents: {
type: 'array',
items: {type: 'string'},
description: 'Components that should be imported from @primer/styled-react when used with sx prop',
},
styledTypes: {
type: 'array',
items: {type: 'string'},
description: 'Types that should be imported from @primer/styled-react',
},
styledUtilities: {
type: 'array',
items: {type: 'string'},
description: 'Utilities that should be imported from @primer/styled-react',
},
},
additionalProperties: false,
},
],
messages: {
useStyledReactImport: 'Import {{ componentName }} from "@primer/styled-react" when using with sx prop',
useStyledReactImportWithAlias:
Expand All @@ -54,6 +76,11 @@ module.exports = {
},
},
create(context) {
// Get configuration options or use defaults
const options = context.options[0] || {}
const styledComponents = new Set(options.styledComponents || defaultStyledComponents)
const styledTypes = new Set(options.styledTypes || defaultStyledTypes)
const styledUtilities = new Set(options.styledUtilities || defaultStyledUtilities)
const componentsWithSx = new Set()
const componentsWithoutSx = new Set() // Track components used without sx
const allUsedComponents = new Set() // Track all used components
Expand Down

AltStyle γ«γ‚ˆγ£γ¦ε€‰ζ›γ•γ‚ŒγŸγƒšγƒΌγ‚Έ (->γ‚ͺγƒͺγ‚ΈγƒŠγƒ«) /