-
Notifications
You must be signed in to change notification settings - Fork 19
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
feat(Button): Extend icon moving to support Icon and react-icon children #735
Merged
adamviktora
merged 5 commits into
patternfly:main
from
wise-king-sullyman:button-icon-extend-applicability
Aug 26, 2024
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
2f2ad31
feat(Button): Extend icon moving to support Icon and react-icon children
wise-king-sullyman 3b28577
fix(Button): fix bugs found during review
wise-king-sullyman 2dab24b
chore(Button): Update single test files
wise-king-sullyman 2085af4
Merge branch 'main' into button-icon-extend-applicability
wise-king-sullyman 834c357
chore(helpers): Update helper import after merge
wise-king-sullyman File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
31 changes: 31 additions & 0 deletions
31
packages/eslint-plugin-pf-codemods/src/rules/helpers/isReactIcon.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,31 @@ | ||
import { Rule } from "eslint"; | ||
import { JSXElement } from "estree-jsx"; | ||
import { getFromPackage, getDefaultImportsFromPackage } from "./index"; | ||
|
||
/** Returns true if an element is a patternfly/react-icons import, false if it isn't, and undefined | ||
* if no element is passed (for type safety) */ | ||
export function isReactIcon(context: Rule.RuleContext, element?: JSXElement) { | ||
if (!element) { | ||
return; | ||
} | ||
|
||
const openingElementIdentifier = element.openingElement.name; | ||
|
||
// TODO: update this to use the appropriate getNodeName helper once it lands | ||
if (openingElementIdentifier.type !== "JSXIdentifier") { | ||
return; | ||
} | ||
const elementName = openingElementIdentifier.name; | ||
|
||
const pfIconsPackage = "@patternfly/react-icons"; | ||
const { imports: iconImports } = getFromPackage(context, pfIconsPackage); | ||
const iconDefaultImports = getDefaultImportsFromPackage( | ||
context, | ||
pfIconsPackage | ||
); | ||
const allIconImports = [...iconImports, ...iconDefaultImports]; | ||
|
||
return allIconImports.some( | ||
(iconImport) => iconImport.local.name === elementName | ||
); | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,12 +6,15 @@ import { | |
getAttributeValue, | ||
getExpression, | ||
getChildrenAsAttributeValueText, | ||
getChildJSXElementByName, | ||
isReactIcon, | ||
} from "../../helpers"; | ||
|
||
// https://github.com/patternfly/patternfly-react/pull/10663 | ||
module.exports = { | ||
meta: { fixable: "code" }, | ||
create: function (context: Rule.RuleContext) { | ||
const source = context.getSourceCode(); | ||
const { imports } = getFromPackage(context, "@patternfly/react-core"); | ||
|
||
const buttonImport = imports.find( | ||
|
@@ -20,6 +23,9 @@ module.exports = { | |
const buttonVariantEnumImport = imports.find( | ||
(specifier) => specifier.imported.name === "ButtonVariant" | ||
); | ||
const hasIconImport = imports.some( | ||
(specifier) => specifier.imported.name === "Icon" | ||
); | ||
|
||
return !buttonImport | ||
? {} | ||
|
@@ -31,41 +37,61 @@ module.exports = { | |
) { | ||
const variantProp = getAttribute(node.openingElement, "variant"); | ||
const iconProp = getAttribute(node.openingElement, "icon"); | ||
if (!variantProp || iconProp) { | ||
if (iconProp) { | ||
return; | ||
} | ||
const variantValue = getAttributeValue( | ||
context, | ||
variantProp.value | ||
variantProp?.value | ||
); | ||
|
||
const isEnumValuePlain = | ||
buttonVariantEnumImport && | ||
variantValue?.object?.name === | ||
buttonVariantEnumImport.local.name && | ||
variantValue?.property.name === "plain"; | ||
if (variantValue !== "plain" && !isEnumValuePlain) { | ||
return; | ||
} | ||
|
||
const isPlain = variantValue === "plain" || isEnumValuePlain; | ||
|
||
const childrenProp = getAttribute(node, "children"); | ||
let childrenValue; | ||
|
||
let childrenValue: string | undefined; | ||
if (childrenProp) { | ||
const childrenPropExpression = getExpression( | ||
childrenProp?.value | ||
); | ||
childrenValue = childrenPropExpression | ||
? context.getSourceCode().getText(childrenPropExpression) | ||
? `{${source.getText(childrenPropExpression)}}` | ||
: ""; | ||
} else { | ||
} else if (isPlain) { | ||
childrenValue = getChildrenAsAttributeValueText( | ||
context, | ||
node.children | ||
); | ||
} | ||
if (!childrenValue) { | ||
|
||
if (!childrenValue && isPlain) { | ||
return; | ||
} | ||
|
||
const iconComponentChild = | ||
hasIconImport && getChildJSXElementByName(node, "Icon"); | ||
|
||
const jsxElementChildren = node.children.filter( | ||
(child) => child.type === "JSXElement" | ||
) as JSXElement[]; | ||
const reactIconChild = jsxElementChildren.find((child) => | ||
isReactIcon(context, child) | ||
); | ||
|
||
const iconChild = iconComponentChild || reactIconChild; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if we should also handle this icon child in case of children as an attribute. Because currently this is valid:
and the rule won't be applied. I think it is a pretty rare use case and it would complicate the rule, so I wouldn't bother. |
||
|
||
if (!isPlain && !iconChild) { | ||
return; | ||
} | ||
|
||
const iconChildString = `{${source.getText(iconChild)}}`; | ||
|
||
context.report({ | ||
node, | ||
message: `Icons must now be passed to the \`icon\` prop of Button instead of as children. If you are passing anything other than an icon as children, ignore this rule when running fixes.`, | ||
|
@@ -74,18 +100,20 @@ module.exports = { | |
fixes.push( | ||
fixer.insertTextAfter( | ||
node.openingElement.name, | ||
` icon=${childrenValue}` | ||
` icon=${childrenValue || iconChildString}` | ||
) | ||
); | ||
|
||
if (childrenProp) { | ||
fixes.push(fixer.remove(childrenProp)); | ||
} else { | ||
} else if (isPlain) { | ||
node.children.forEach( | ||
(child) => | ||
child.type !== "JSXSpreadChild" && | ||
fixes.push(fixer.replaceText(child, "")) | ||
); | ||
} else if (iconChild) { | ||
fixes.push(fixer.replaceText(iconChild, "")); | ||
} | ||
return fixes; | ||
}, | ||
|
19 changes: 15 additions & 4 deletions
19
...-plugin-pf-codemods/src/rules/v6/buttonMoveIconsIconProp/buttonMoveIconsIconPropInput.tsx
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 |
---|---|---|
@@ -1,7 +1,18 @@ | ||
import { Button } from "@patternfly/react-core"; | ||
import { Button, Icon } from "@patternfly/react-core"; | ||
import { SomeIcon } from "@patternfly/react-icons"; | ||
|
||
export const ButtonMoveIconsIconPropInput = () => ( | ||
<Button variant='plain'> | ||
<span>Icon</span> | ||
</Button> | ||
<> | ||
<Button variant="plain"> | ||
<span>Icon</span> | ||
</Button> | ||
<Button> | ||
<Icon> | ||
<SomeIcon /> | ||
</Icon> | ||
</Button> | ||
<Button> | ||
<SomeIcon /> | ||
</Button> | ||
</> | ||
); |
15 changes: 13 additions & 2 deletions
15
...plugin-pf-codemods/src/rules/v6/buttonMoveIconsIconProp/buttonMoveIconsIconPropOutput.tsx
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 |
---|---|---|
@@ -1,5 +1,16 @@ | ||
import { Button } from "@patternfly/react-core"; | ||
import { Button, Icon } from "@patternfly/react-core"; | ||
import { SomeIcon } from "@patternfly/react-icons"; | ||
|
||
export const ButtonMoveIconsIconPropInput = () => ( | ||
<Button icon={<span>Icon</span>} variant='plain'></Button> | ||
<> | ||
<Button icon={<span>Icon</span>} variant="plain"></Button> | ||
<Button icon={<Icon> | ||
<SomeIcon /> | ||
</Icon>}> | ||
|
||
</Button> | ||
<Button icon={<SomeIcon />}> | ||
|
||
</Button> | ||
</> | ||
); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we also add a test for the children attribute mentioned above?