Skip to content

Commit c0ac197

Browse files
authored
feat/841: add optional codemod and flag for enabling animations (#843)
Signed-off-by: gitdallas <[email protected]>
1 parent bb9f1eb commit c0ac197

File tree

6 files changed

+307
-0
lines changed

6 files changed

+307
-0
lines changed

packages/eslint-plugin-pf-codemods/src/ruleCustomization.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55
export const betaRuleNames: string[] = [
66
"data-codemods-cleanup",
7+
"enable-animations",
78
"kebabToggle-replace-with-menuToggle",
89
];
910

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
### enable-animations
2+
3+
This rule adds the `hasAnimations` prop to PatternFly components that support animations. This is an optional enhancement that enables smoother transitions and animations in your UI components.
4+
5+
The following components will have `hasAnimations` added:
6+
- AlertGroup
7+
- DualListSelector
8+
- FormFieldGroupExpandable
9+
- SearchInput
10+
- TreeView
11+
- Table (from @patternfly/react-table)
12+
13+
This rule can only run using the `--only enable-animations` option.
14+
15+
#### Examples
16+
17+
In:
18+
19+
```jsx
20+
import { AlertGroup, TreeView } from '@patternfly/react-core';
21+
import { Table } from '@patternfly/react-table';
22+
23+
export const Example = () => (
24+
<>
25+
<AlertGroup isLiveRegion>
26+
{/* alerts */}
27+
</AlertGroup>
28+
<TreeView />
29+
<Table />
30+
</>
31+
);
32+
```
33+
34+
Out:
35+
36+
```jsx
37+
import { AlertGroup, TreeView } from '@patternfly/react-core';
38+
import { Table } from '@patternfly/react-table';
39+
40+
export const Example = () => (
41+
<>
42+
<AlertGroup hasAnimations isLiveRegion>
43+
{/* alerts */}
44+
</AlertGroup>
45+
<TreeView hasAnimations />
46+
<Table hasAnimations />
47+
</>
48+
);
49+
```
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
const ruleTester = require("../../ruletester");
2+
import * as rule from "./enable-animations";
3+
4+
ruleTester.run("enable-animations", rule, {
5+
valid: [
6+
// No imports, should not trigger
7+
{
8+
code: `<AlertGroup />`,
9+
},
10+
// Already has hasAnimations prop
11+
{
12+
code: `import { AlertGroup } from '@patternfly/react-core'; <AlertGroup hasAnimations />`,
13+
},
14+
// Already has hasAnimations with value
15+
{
16+
code: `import { AlertGroup } from '@patternfly/react-core'; <AlertGroup hasAnimations={true} />`,
17+
},
18+
// Table already has hasAnimations
19+
{
20+
code: `import { Table } from '@patternfly/react-table'; <Table hasAnimations />`,
21+
},
22+
// Non-target component should not be affected
23+
{
24+
code: `import { Button } from '@patternfly/react-core'; <Button />`,
25+
},
26+
],
27+
invalid: [
28+
// AlertGroup without hasAnimations
29+
{
30+
code: `import { AlertGroup } from '@patternfly/react-core'; <AlertGroup />`,
31+
output: `import { AlertGroup } from '@patternfly/react-core'; <AlertGroup hasAnimations />`,
32+
errors: [
33+
{
34+
message: "Consider adding hasAnimations prop to enable component animations.",
35+
type: "JSXOpeningElement",
36+
},
37+
],
38+
},
39+
// DualListSelector without hasAnimations
40+
{
41+
code: `import { DualListSelector } from '@patternfly/react-core'; <DualListSelector />`,
42+
output: `import { DualListSelector } from '@patternfly/react-core'; <DualListSelector hasAnimations />`,
43+
errors: [
44+
{
45+
message: "Consider adding hasAnimations prop to enable component animations.",
46+
type: "JSXOpeningElement",
47+
},
48+
],
49+
},
50+
// TreeView without hasAnimations
51+
{
52+
code: `import { TreeView } from '@patternfly/react-core'; <TreeView />`,
53+
output: `import { TreeView } from '@patternfly/react-core'; <TreeView hasAnimations />`,
54+
errors: [
55+
{
56+
message: "Consider adding hasAnimations prop to enable component animations.",
57+
type: "JSXOpeningElement",
58+
},
59+
],
60+
},
61+
// SearchInput without hasAnimations
62+
{
63+
code: `import { SearchInput } from '@patternfly/react-core'; <SearchInput />`,
64+
output: `import { SearchInput } from '@patternfly/react-core'; <SearchInput hasAnimations />`,
65+
errors: [
66+
{
67+
message: "Consider adding hasAnimations prop to enable component animations.",
68+
type: "JSXOpeningElement",
69+
},
70+
],
71+
},
72+
// FormFieldGroupExpandable without hasAnimations
73+
{
74+
code: `import { FormFieldGroupExpandable } from '@patternfly/react-core'; <FormFieldGroupExpandable />`,
75+
output: `import { FormFieldGroupExpandable } from '@patternfly/react-core'; <FormFieldGroupExpandable hasAnimations />`,
76+
errors: [
77+
{
78+
message: "Consider adding hasAnimations prop to enable component animations.",
79+
type: "JSXOpeningElement",
80+
},
81+
],
82+
},
83+
// Table from react-table without hasAnimations
84+
{
85+
code: `import { Table } from '@patternfly/react-table'; <Table />`,
86+
output: `import { Table } from '@patternfly/react-table'; <Table hasAnimations />`,
87+
errors: [
88+
{
89+
message: "Consider adding hasAnimations prop to enable component animations.",
90+
type: "JSXOpeningElement",
91+
},
92+
],
93+
},
94+
// Multiple components in one file
95+
{
96+
code: `import { AlertGroup, TreeView } from '@patternfly/react-core';
97+
<>
98+
<AlertGroup />
99+
<TreeView />
100+
</>`,
101+
output: `import { AlertGroup, TreeView } from '@patternfly/react-core';
102+
<>
103+
<AlertGroup hasAnimations />
104+
<TreeView hasAnimations />
105+
</>`,
106+
errors: [
107+
{
108+
message: "Consider adding hasAnimations prop to enable component animations.",
109+
type: "JSXOpeningElement",
110+
},
111+
{
112+
message: "Consider adding hasAnimations prop to enable component animations.",
113+
type: "JSXOpeningElement",
114+
},
115+
],
116+
},
117+
// Component with existing props
118+
{
119+
code: `import { AlertGroup } from '@patternfly/react-core'; <AlertGroup isLiveRegion />`,
120+
output: `import { AlertGroup } from '@patternfly/react-core'; <AlertGroup hasAnimations isLiveRegion />`,
121+
errors: [
122+
{
123+
message: "Consider adding hasAnimations prop to enable component animations.",
124+
type: "JSXOpeningElement",
125+
},
126+
],
127+
},
128+
// Self-closing and regular tags
129+
{
130+
code: `import { DualListSelector } from '@patternfly/react-core';
131+
<>
132+
<DualListSelector />
133+
<DualListSelector></DualListSelector>
134+
</>`,
135+
output: `import { DualListSelector } from '@patternfly/react-core';
136+
<>
137+
<DualListSelector hasAnimations />
138+
<DualListSelector hasAnimations></DualListSelector>
139+
</>`,
140+
errors: [
141+
{
142+
message: "Consider adding hasAnimations prop to enable component animations.",
143+
type: "JSXOpeningElement",
144+
},
145+
{
146+
message: "Consider adding hasAnimations prop to enable component animations.",
147+
type: "JSXOpeningElement",
148+
},
149+
],
150+
},
151+
],
152+
});
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { Rule } from "eslint";
2+
import { JSXOpeningElement } from "estree-jsx";
3+
import { getFromPackage, checkMatchingJSXOpeningElement } from "../../helpers";
4+
5+
// Rule to add hasAnimations prop to components that support animations
6+
module.exports = {
7+
meta: { fixable: "code" },
8+
create: function (context: Rule.RuleContext) {
9+
// Get imports from both react-core and react-table packages
10+
const { imports: coreImports } = getFromPackage(
11+
context,
12+
"@patternfly/react-core"
13+
);
14+
const { imports: tableImports } = getFromPackage(
15+
context,
16+
"@patternfly/react-table"
17+
);
18+
19+
// Components that support hasAnimations prop
20+
const targetComponents = [
21+
"FormFieldGroupExpandable",
22+
"DualListSelector",
23+
"TreeView",
24+
"AlertGroup",
25+
"SearchInput"
26+
];
27+
28+
// Table comes from react-table package
29+
const tableComponents = ["Table"];
30+
31+
// Filter imports to only include target components
32+
const targetCoreImports = coreImports.filter((specifier) =>
33+
targetComponents.includes(specifier.imported.name)
34+
);
35+
36+
const targetTableImports = tableImports.filter((specifier) =>
37+
tableComponents.includes(specifier.imported.name)
38+
);
39+
40+
const allTargetImports = [...targetCoreImports, ...targetTableImports];
41+
42+
const message =
43+
"Consider adding hasAnimations prop to enable component animations.";
44+
45+
return allTargetImports.length === 0
46+
? {}
47+
: {
48+
JSXOpeningElement(node: JSXOpeningElement) {
49+
if (checkMatchingJSXOpeningElement(node, allTargetImports)) {
50+
// Check if hasAnimations prop already exists
51+
const hasAnimationsAttribute = node.attributes.find(
52+
(attr) =>
53+
attr.type === "JSXAttribute" &&
54+
attr.name.type === "JSXIdentifier" &&
55+
attr.name.name === "hasAnimations"
56+
);
57+
58+
// Only add prop if it doesn't already exist
59+
if (!hasAnimationsAttribute) {
60+
context.report({
61+
node,
62+
message,
63+
fix(fixer) {
64+
return fixer.insertTextAfter(
65+
node.name,
66+
" hasAnimations"
67+
);
68+
},
69+
});
70+
}
71+
}
72+
},
73+
};
74+
},
75+
};
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { AlertGroup, TreeView, DualListSelector, SearchInput, FormFieldGroupExpandable } from "@patternfly/react-core";
2+
import { Table } from "@patternfly/react-table";
3+
4+
export const EnableAnimationsInput = () => (
5+
<>
6+
<AlertGroup isLiveRegion>
7+
{/* alerts */}
8+
</AlertGroup>
9+
<TreeView />
10+
<DualListSelector />
11+
<SearchInput />
12+
<FormFieldGroupExpandable />
13+
<Table />
14+
</>
15+
);
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { AlertGroup, TreeView, DualListSelector, SearchInput, FormFieldGroupExpandable } from "@patternfly/react-core";
2+
import { Table } from "@patternfly/react-table";
3+
4+
export const EnableAnimationsOutput = () => (
5+
<>
6+
<AlertGroup hasAnimations isLiveRegion>
7+
{/* alerts */}
8+
</AlertGroup>
9+
<TreeView hasAnimations />
10+
<DualListSelector hasAnimations />
11+
<SearchInput hasAnimations />
12+
<FormFieldGroupExpandable hasAnimations />
13+
<Table hasAnimations />
14+
</>
15+
);

0 commit comments

Comments
 (0)