diff --git a/.changeset/good-cobras-pay.md b/.changeset/good-cobras-pay.md
new file mode 100644
index 00000000..56f6a6bb
--- /dev/null
+++ b/.changeset/good-cobras-pay.md
@@ -0,0 +1,5 @@
+---
+"eslint-plugin-primer-react": patch
+---
+
+Fixes for `use-styled-react-import` rule for compound components.
diff --git a/src/rules/__tests__/use-styled-react-import.test.js b/src/rules/__tests__/use-styled-react-import.test.js
index 860f473c..dc06459b 100644
--- a/src/rules/__tests__/use-styled-react-import.test.js
+++ b/src/rules/__tests__/use-styled-react-import.test.js
@@ -56,6 +56,53 @@ ruleTester.run('use-styled-react-import', rule, {
],
},
+ // Invalid: ActionList.Item with sx prop and ActionList imported from @primer/react
+ {
+ code: `import { ActionList } from '@primer/react'
+ const Component = () => Content`,
+ output: `import { ActionList } from '@primer/styled-react'
+ const Component = () => Content`,
+ errors: [
+ {
+ messageId: 'useStyledReactImport',
+ data: {componentName: 'ActionList'},
+ },
+ ],
+ },
+
+ // Invalid: FormControl used both with and without sx prop - should use alias
+ {
+ code: `import { FormControl } from '@primer/react'
+ const Component = () => (
+
+
+
+ Label
+
+
+ )`,
+ output: `import { FormControl } from '@primer/react'
+import { FormControl as StyledFormControl } from '@primer/styled-react'
+ const Component = () => (
+
+
+
+ Label
+
+
+ )`,
+ errors: [
+ {
+ messageId: 'useStyledReactImportWithAlias',
+ data: {componentName: 'FormControl', aliasName: 'StyledFormControl'},
+ },
+ {
+ messageId: 'useAliasedComponent',
+ data: {componentName: 'FormControl', aliasName: 'StyledFormControl'},
+ },
+ ],
+ },
+
// Invalid: Button with sx prop imported from @primer/react
{
code: `import { Button } from '@primer/react'
diff --git a/src/rules/use-styled-react-import.js b/src/rules/use-styled-react-import.js
index 136ff644..606473a5 100644
--- a/src/rules/use-styled-react-import.js
+++ b/src/rules/use-styled-react-import.js
@@ -132,9 +132,14 @@ module.exports = {
// Check if this is an aliased component from styled-react
const originalComponentName = aliasMapping.get(componentName) || componentName
+ // For compound components like "ActionList.Item", we need to check the parent component
+ const parentComponentName = originalComponentName.includes('.')
+ ? originalComponentName.split('.')[0]
+ : originalComponentName
+
// Track all used components that are in our styled components list
- if (styledComponents.has(originalComponentName)) {
- allUsedComponents.add(originalComponentName)
+ if (styledComponents.has(parentComponentName)) {
+ allUsedComponents.add(parentComponentName)
// Check if this component has an sx prop
const hasSxProp = openingElement.attributes.some(
@@ -142,17 +147,17 @@ module.exports = {
)
if (hasSxProp) {
- componentsWithSx.add(originalComponentName)
+ componentsWithSx.add(parentComponentName)
jsxElementsWithSx.push({node, componentName: originalComponentName, openingElement})
} else {
- componentsWithoutSx.add(originalComponentName)
+ componentsWithoutSx.add(parentComponentName)
// If this is an aliased component without sx, we need to track it for renaming
if (aliasMapping.has(componentName)) {
jsxElementsWithoutSx.push({
node,
localName: componentName,
- originalName: originalComponentName,
+ originalName: parentComponentName,
openingElement,
})
}
@@ -293,17 +298,14 @@ module.exports = {
messageId: 'useAliasedComponent',
data: {componentName, aliasName},
fix(fixer) {
- const fixes = []
-
- // Replace the component name in the JSX opening tag
- fixes.push(fixer.replaceText(openingElement.name, aliasName))
+ const sourceCode = context.getSourceCode()
+ const jsxText = sourceCode.getText(jsxNode)
- // Replace the component name in the JSX closing tag if it exists
- if (jsxNode.closingElement) {
- fixes.push(fixer.replaceText(jsxNode.closingElement.name, aliasName))
- }
+ // Replace all instances of the component name (both main component and compound components)
+ const componentPattern = new RegExp(`\\b${componentName}(?=\\.|\\s|>)`, 'g')
+ const aliasedText = jsxText.replace(componentPattern, aliasName)
- return fixes
+ return fixer.replaceText(jsxNode, aliasedText)
},
})
}