Skip to content
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

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
const { getFromPackage, getAllJSXElements } = require("../../helpers");

// https://github.com/patternfly/patternfly-react/pull/9074
// https://github.com/patternfly/patternfly-react/pull/9176
module.exports = {
meta: { fixable: "code" },
create: function (context) {
const { imports } = getFromPackage(context, "@patternfly/react-core");

const inputGroupImport = imports.find(
(specifier) => specifier.imported?.name == "InputGroup"
);
const inputGroupItemImport = imports.find(
(specifier) => specifier.imported?.name == "InputGroupItem"
);
const inputGroupTextImport = imports.find(
(specifier) => specifier.imported?.name == "InputGroupText"
);

return !inputGroupImport
? {}
: {
ImportDeclaration(node) {
const getMatchingSpecifier = (name) =>
node.specifiers.find(
(specifier) => specifier.imported?.name === name
);

const inputGroupElements = getAllJSXElements(context).filter(
(elem) =>
elem.openingElement?.name?.name === inputGroupImport.local?.name
);

const needsInputGroupItemImport = inputGroupElements.some(
(inputGroup) => {
return inputGroup.children?.some(
(inputGroupChild) =>
![
inputGroupTextImport?.local?.name,
"InputGroupText",
].includes(inputGroupChild.openingElement?.name?.name)
);
}
);

if (
getMatchingSpecifier(inputGroupImport.imported?.name) &&
!inputGroupItemImport &&
needsInputGroupItemImport
) {
context.report({
node,
message: `add missing import InputGroupItem from @patternfly/react-core`,
fix(fixer) {
return fixer.insertTextAfter(
node.specifiers[node.specifiers.length - 1],
", InputGroupItem"
);
},
});
}
},
JSXElement(node) {
const parentName = node.openingElement?.name?.name;
if (parentName !== inputGroupImport.local?.name) {
return;
}
const inputGroupTextName = inputGroupTextImport?.local?.name;

node.children?.forEach((child) => {
const childName = child.openingElement?.name?.name;
if (
[
"InputGroupItem",
inputGroupItemImport?.local?.name,
inputGroupTextName,
].includes(childName) ||
["JSXText", "Literal"].includes(child.type)
) {
return;
}

const matchingChildImport = imports.find(
(imp) => imp.local?.name === childName
);
const shouldFill =
["input", "textarea"].includes(childName) ||
["TextArea", "TextInput"].includes(
matchingChildImport?.imported?.name
);

context.report({
node,
message: `Any non-InputGroupText child passed to ${parentName} must now be wrapped within an InputGroupItem. The InputGroupItem may need the "isFill", "isPlain", and/or "isBox" props adjusted.`,
fix(fixer) {
const sourceCode = context.getSourceCode();
const newChild = sourceCode.getText(child);

return fixer.replaceText(
child,
`<InputGroupItem${
shouldFill ? " isFill " : ""
}>${newChild}</InputGroupItem>`
);
},
});
});
},
};
},
};
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
const ruleTester = require("../../ruletester");
const rule = require("../../../lib/rules/v5/inputGroup-add-inputGroupItem");
const rule = require("../../../lib/rules/v5/inputGroup-update-api");

ruleTester.run("inputGroup-add-inputGroupItem", rule, {
ruleTester.run("inputGroup-update-api", rule, {
valid: [
{
code: `import { InputGroup, InputGroupItem } from '@patternfly/react-core'; <InputGroup><InputGroupItem></InputGroupItem></InputGroup>`,
code: `import { InputGroup, InputGroupItem } from '@patternfly/react-core'; <InputGroup><InputGroupItem><input /></InputGroupItem></InputGroup>`,
},
{
code: `import { InputGroup, InputGroupText } from '@patternfly/react-core'; <InputGroup><InputGroupText>Some text</InputGroupText></InputGroup>`,
},
// no @patternfly/react-core import
{
Expand All @@ -22,79 +25,79 @@ ruleTester.run("inputGroup-add-inputGroupItem", rule, {
type: "ImportDeclaration",
},
{
message: `Each child passed to InputGroup must now be wrapped within an InputGroupItem. The InputGroupItem may also need the "isFill", "isPlain", and/or "isBox" props passed in.`,
message: `Any non-InputGroupText child passed to InputGroup must now be wrapped within an InputGroupItem. The InputGroupItem may need the "isFill", "isPlain", and/or "isBox" props adjusted.`,
type: "JSXElement",
},
],
},
// Child that is input-like, e.g. textarea, input, TextInput, or TextArea
{
code: `import { InputGroup } from '@patternfly/react-core'; <InputGroup><input /></InputGroup>`,
output: `import { InputGroup, InputGroupItem } from '@patternfly/react-core'; <InputGroup><InputGroupItem isFill><input /></InputGroupItem></InputGroup>`,
output: `import { InputGroup, InputGroupItem } from '@patternfly/react-core'; <InputGroup><InputGroupItem isFill ><input /></InputGroupItem></InputGroup>`,
errors: [
{
message: `add missing import InputGroupItem from @patternfly/react-core`,
type: "ImportDeclaration",
},
{
message: `Each child passed to InputGroup must now be wrapped within an InputGroupItem. The InputGroupItem may also need the "isFill", "isPlain", and/or "isBox" props passed in.`,
message: `Any non-InputGroupText child passed to InputGroup must now be wrapped within an InputGroupItem. The InputGroupItem may need the "isFill", "isPlain", and/or "isBox" props adjusted.`,
type: "JSXElement",
},
],
},
{
code: `import { InputGroup } from '@patternfly/react-core'; <InputGroup><textarea /></InputGroup>`,
output: `import { InputGroup, InputGroupItem } from '@patternfly/react-core'; <InputGroup><InputGroupItem isFill><textarea /></InputGroupItem></InputGroup>`,
output: `import { InputGroup, InputGroupItem } from '@patternfly/react-core'; <InputGroup><InputGroupItem isFill ><textarea /></InputGroupItem></InputGroup>`,
errors: [
{
message: `add missing import InputGroupItem from @patternfly/react-core`,
type: "ImportDeclaration",
},
{
message: `Each child passed to InputGroup must now be wrapped within an InputGroupItem. The InputGroupItem may also need the "isFill", "isPlain", and/or "isBox" props passed in.`,
message: `Any non-InputGroupText child passed to InputGroup must now be wrapped within an InputGroupItem. The InputGroupItem may need the "isFill", "isPlain", and/or "isBox" props adjusted.`,
type: "JSXElement",
},
],
},
{
code: `import { InputGroup, TextInput } from '@patternfly/react-core'; <InputGroup><TextInput /></InputGroup>`,
output: `import { InputGroup, TextInput, InputGroupItem } from '@patternfly/react-core'; <InputGroup><InputGroupItem isFill><TextInput /></InputGroupItem></InputGroup>`,
output: `import { InputGroup, TextInput, InputGroupItem } from '@patternfly/react-core'; <InputGroup><InputGroupItem isFill ><TextInput /></InputGroupItem></InputGroup>`,
errors: [
{
message: `add missing import InputGroupItem from @patternfly/react-core`,
type: "ImportDeclaration",
},
{
message: `Each child passed to InputGroup must now be wrapped within an InputGroupItem. The InputGroupItem may also need the "isFill", "isPlain", and/or "isBox" props passed in.`,
message: `Any non-InputGroupText child passed to InputGroup must now be wrapped within an InputGroupItem. The InputGroupItem may need the "isFill", "isPlain", and/or "isBox" props adjusted.`,
type: "JSXElement",
},
],
},
{
code: `import { InputGroup, TextArea } from '@patternfly/react-core'; <InputGroup><TextArea /></InputGroup>`,
output: `import { InputGroup, TextArea, InputGroupItem } from '@patternfly/react-core'; <InputGroup><InputGroupItem isFill><TextArea /></InputGroupItem></InputGroup>`,
output: `import { InputGroup, TextArea, InputGroupItem } from '@patternfly/react-core'; <InputGroup><InputGroupItem isFill ><TextArea /></InputGroupItem></InputGroup>`,
errors: [
{
message: `add missing import InputGroupItem from @patternfly/react-core`,
type: "ImportDeclaration",
},
{
message: `Each child passed to InputGroup must now be wrapped within an InputGroupItem. The InputGroupItem may also need the "isFill", "isPlain", and/or "isBox" props passed in.`,
message: `Any non-InputGroupText child passed to InputGroup must now be wrapped within an InputGroupItem. The InputGroupItem may need the "isFill", "isPlain", and/or "isBox" props adjusted.`,
type: "JSXElement",
},
],
},
// Child that is InputGroupText
// InputGroupText child and non-InputGroupText child
{
code: `import { InputGroup, InputGroupText } from '@patternfly/react-core'; <InputGroup><InputGroupText /></InputGroup>`,
output: `import { InputGroup, InputGroupText, InputGroupItem } from '@patternfly/react-core'; <InputGroup><InputGroupItem isBox><InputGroupText /></InputGroupItem></InputGroup>`,
code: `import { InputGroup, InputGroupText } from '@patternfly/react-core'; <InputGroup><InputGroupText>Some text</InputGroupText><button /></InputGroup>`,
output: `import { InputGroup, InputGroupText, InputGroupItem } from '@patternfly/react-core'; <InputGroup><InputGroupText>Some text</InputGroupText><InputGroupItem><button /></InputGroupItem></InputGroup>`,
errors: [
{
message: `add missing import InputGroupItem from @patternfly/react-core`,
type: "ImportDeclaration",
},
{
message: `Each child passed to InputGroup must now be wrapped within an InputGroupItem. The InputGroupItem may also need the "isFill", "isPlain", and/or "isBox" props passed in.`,
message: `Any non-InputGroupText child passed to InputGroup must now be wrapped within an InputGroupItem. The InputGroupItem may need the "isFill", "isPlain", and/or "isBox" props adjusted.`,
type: "JSXElement",
},
],
Expand All @@ -109,7 +112,7 @@ ruleTester.run("inputGroup-add-inputGroupItem", rule, {
type: "ImportDeclaration",
},
{
message: `Each child passed to InputGroup must now be wrapped within an InputGroupItem. The InputGroupItem may also need the "isFill", "isPlain", and/or "isBox" props passed in.`,
message: `Any non-InputGroupText child passed to InputGroup must now be wrapped within an InputGroupItem. The InputGroupItem may need the "isFill", "isPlain", and/or "isBox" props adjusted.`,
type: "JSXElement",
},
],
Expand All @@ -124,7 +127,21 @@ ruleTester.run("inputGroup-add-inputGroupItem", rule, {
type: "ImportDeclaration",
},
{
message: `Each child passed to PFInputGroup must now be wrapped within an InputGroupItem. The InputGroupItem may also need the "isFill", "isPlain", and/or "isBox" props passed in.`,
message: `Any non-InputGroupText child passed to PFInputGroup must now be wrapped within an InputGroupItem. The InputGroupItem may need the "isFill", "isPlain", and/or "isBox" props adjusted.`,
type: "JSXElement",
},
],
},
{
code: `import { InputGroup, TextArea as PFTA } from '@patternfly/react-core'; <InputGroup><PFTA /></InputGroup>`,
output: `import { InputGroup, TextArea as PFTA, InputGroupItem } from '@patternfly/react-core'; <InputGroup><InputGroupItem isFill ><PFTA /></InputGroupItem></InputGroup>`,
errors: [
{
message: `add missing import InputGroupItem from @patternfly/react-core`,
type: "ImportDeclaration",
},
{
message: `Any non-InputGroupText child passed to InputGroup must now be wrapped within an InputGroupItem. The InputGroupItem may need the "isFill", "isPlain", and/or "isBox" props adjusted.`,
type: "JSXElement",
},
],
Expand Down
9 changes: 5 additions & 4 deletions packages/pf-codemods/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1465,9 +1465,10 @@ Out:

We've updated the default value of the `aria-label` attribute for Nav with a `horizontal-subnav` variant to "local" (previously the default value was "Global").

### inputGroup-add-inputGroupItem [(#9074)](https://github.com/patternfly/patternfly-react/pull/9074)
### inputGroup-update-api [(#9074)](https://github.com/patternfly/patternfly-react/pull/9074) and [(#9176)](https://github.com/patternfly/patternfly-react/pull/9176)

We've added the InputGroupItem component, which must wrap all non-InputGroupText children passed to an InputGroup. The InputGroupItem component may need to have the `isFill`, `isBox`, and/or `isPlain` props adjusted to retain styling.

We've added the InputGroupItem component, which must wrap each child passed to an InputGroup. Additionally, the InputGroupItem component may need to have the `isFill`, `isBox`, and/or `isPlain` props passed in.

#### Examples

Expand All @@ -1479,7 +1480,7 @@ In:
<textarea />
<TextArea />
<TextInput />
<InputGroupText />
<InputGroupText>Some text</InputGroupText>
<button />
</InputGroup>
```
Expand All @@ -1492,7 +1493,7 @@ Out:
<InputGroupItem isFill><textarea /></InputGroupItem>
<InputGroupItem isFill><TextArea /></InputGroupItem>
<InputGroupItem isFill><TextInput /></InputGroupItem>
<InputGroupItem isBox><InputGroupText /></InputGroupItem>
<InputGroupText>Some text</InputGroupText>
<InputGroupItem><button /></InputGroupItem>
</InputGroup>
```
Expand Down
3 changes: 2 additions & 1 deletion test/test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import {
FileUploadField,
FormSelect,
InputGroup,
InputGroupItem,
InputGroupText,
KebabToggle,
KEY_CODES,
Expand Down Expand Up @@ -230,7 +231,7 @@ const alertVariantOption = AlertVariant.default;
<textarea />
<TextArea />
<TextInput />
<InputGroupText />
<InputGroupText>Text</InputGroupText>
<button />
</InputGroup>
<InputGroupText variant />
Expand Down