Skip to content
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(Chip): added badge prop #537

Merged
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
1 change: 1 addition & 0 deletions packages/eslint-plugin-pf-codemods/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const warningRules = [
"card-deprecate-props",
"card-warn-component",
"charts-warn-tooltip",
"chip-update-badgeAPI",
"conditional-aria",
"datePicker-warn-appendTo-default-value-changed",
"datepicker-warn-helperText",
Expand Down
10 changes: 7 additions & 3 deletions packages/eslint-plugin-pf-codemods/lib/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -692,7 +692,10 @@ function addCallbackParam(
} else if (propProperties.type === "MemberExpression") {
const memberExpression = attribute.value?.expression;
if (memberExpression.object.type === "ThisExpression") {
const parentClass = findParentClass(memberExpression);
const parentClass = findAncestor(
memberExpression,
(current) => current.type === "ClassDeclaration"
);
const methods = parentClass?.body?.body;
const methodDefinition = methods?.find(
(method) =>
Expand Down Expand Up @@ -925,11 +928,11 @@ function findVariableDeclaration(name, scope) {
return undefined;
}

function findParentClass(node) {
function findAncestor(node, conditionCallback = (_current) => false) {
let current = node?.parent;

while (current) {
if (current.type === "ClassDeclaration") {
if (conditionCallback(current)) {
return current;
}

Expand All @@ -952,4 +955,5 @@ module.exports = {
addCallbackParam,
getAllJSXElements,
findVariableDeclaration,
findAncestor,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
const { getFromPackage, findAncestor } = require("../../helpers");

// https://github.com/patternfly/patternfly-react/pull/9493
module.exports = {
meta: { fixable: "code" },
create: function (context) {
const { imports } = getFromPackage(context, "@patternfly/react-core");
const chipImport = imports.find(
(specifier) => specifier.imported.name === "Chip"
);
const badgeImport = imports.find(
(specifier) => specifier.imported.name === "Badge"
);

return !chipImport || !badgeImport
? {}
: {
JSXElement(node) {
if (badgeImport.local.name !== node.openingElement.name.name) {
return;
}

const chipAncestor = findAncestor(
node,
(current) =>
current?.openingElement?.name?.name === chipImport.local.name
);
const existingBadgeProp =
chipAncestor?.openingElement?.attributes?.find(
(attr) => attr?.name?.name === "badge"
);

if (chipAncestor && !existingBadgeProp) {
context.report({
node,
message: `Badge components should now be passed to the "badge" prop on Chip instead of passed as children.`,
fix(fixer) {
return [
fixer.insertTextAfter(
chipAncestor.openingElement.name,
` badge={${context.getSourceCode().getText(node)}}`
),
fixer.remove(node),
];
},
});
}
},
};
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
const ruleTester = require("../../ruletester");
const rule = require("../../../lib/rules/v5/chip-update-badgeAPI");

ruleTester.run("chip-update-badgeAPI", rule, {
valid: [
{
code: `import { Chip, Badge } from '@patternfly/react-core'; <Chip badge={<Badge>5</Badge>}>Content</Chip>`,
},
{
code: `import { Chip } from '@patternfly/react-core'; <Chip>Content</Chip>`,
},
{
// No @patternfly/react-core import
code: `<Chip>Content<Badge>5</Badge></Chip>`,
},
{
// No @patternfly/react-core Badge import
code: `import { Chip } from '@patternfly/react-core'; <Chip>Content<Badge>5</Badge></Chip>`,
},
{
// No @patternfly/react-core Chip import
code: `import { Badge } from '@patternfly/react-core'; <Chip>Content<Badge>5</Badge></Chip>`,
},
],
invalid: [
{
code: `import { Chip, Badge } from '@patternfly/react-core'; <Chip>Content<Badge>5</Badge></Chip>`,
output: `import { Chip, Badge } from '@patternfly/react-core'; <Chip badge={<Badge>5</Badge>}>Content</Chip>`,
errors: [
{
message: `Badge components should now be passed to the "badge" prop on Chip instead of passed as children.`,
type: "JSXElement",
},
],
},
// Badge rendered within another element
{
code: `import { Chip, Badge } from '@patternfly/react-core'; <Chip>Content<div>Other Content<Badge>5</Badge></div></Chip>`,
output: `import { Chip, Badge } from '@patternfly/react-core'; <Chip badge={<Badge>5</Badge>}>Content<div>Other Content</div></Chip>`,
errors: [
{
message: `Badge components should now be passed to the "badge" prop on Chip instead of passed as children.`,
type: "JSXElement",
},
],
},
// Import from dist
{
code: `import { Chip } from '@patternfly/react-core/dist/esm/components/Chip/index.js'; import { Badge } from '@patternfly/react-core/dist/esm/components/Badge/index.js'; <Chip>Content<Badge>5</Badge></Chip>`,
output: `import { Chip } from '@patternfly/react-core/dist/esm/components/Chip/index.js'; import { Badge } from '@patternfly/react-core/dist/esm/components/Badge/index.js'; <Chip badge={<Badge>5</Badge>}>Content</Chip>`,
errors: [
{
message: `Badge components should now be passed to the "badge" prop on Chip instead of passed as children.`,
type: "JSXElement",
},
],
},
// Aliased imports
{
code: `import { Chip as PFChip, Badge as PFBadge } from '@patternfly/react-core'; <PFChip>Content<PFBadge>5</PFBadge></PFChip>`,
output: `import { Chip as PFChip, Badge as PFBadge } from '@patternfly/react-core'; <PFChip badge={<PFBadge>5</PFBadge>}>Content</PFChip>`,
errors: [
{
message: `Badge components should now be passed to the "badge" prop on Chip instead of passed as children.`,
type: "JSXElement",
},
],
},
],
});
38 changes: 38 additions & 0 deletions packages/pf-codemods/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,44 @@ function handler2(_event, id) {};
<Checkbox onChange={(_event, id) => this.onChange(id)}>
```

### chip-update-badgeAPI [(#9493)](https://github.com/patternfly/patternfly-react/pull/9493)

We've added a `badge` prop to the Chip component, which should now be used instead of passing a Badge as children to Chip. This rule will raise a warning, but a fix can be applied.

#### Examples

In:

```jsx
<Chip>
Some content
<Badge>5</Badge>
</Chip>

<Chip>
Some content
<div>
Some other content
<Badge>5</Badge>
</div>
</Chip>
```

Out:

```jsx
<Chip badge={<Badge>5</Badge>}>
Some content
</Chip>

<Chip badge={<Badge>5</Badge>}>
Some content
<div>
Some other content
</div>
</Chip>
```

### clipboardCopy-onChange-event-added [(#8747)](https://github.com/patternfly/patternfly-react/pull/8747)

The `onChange` prop for ClipboardCopy has been updated to include the `event` as its first parameter. `onChange` handlers may require an update.
Expand Down
Loading