Skip to content

Commit

Permalink
feat(Toolbar): replaced spacer props with gap
Browse files Browse the repository at this point in the history
  • Loading branch information
thatblindgeye committed May 23, 2024
1 parent dc98e0c commit 1a74735
Show file tree
Hide file tree
Showing 5 changed files with 232 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
### toolbar-replaced-spacer-spaceItems [(#10418)](https://github.com/patternfly/patternfly-react/pull/10418)

The `spacer` property has been removed from ToolbarGroup, ToolbarItem, and ToolbarToggleGroup. We recommend instead using our new `gap`, `columnGap`, or `rowGap` properties.

Additionally, the `spaceItems` property has been removed from ToolbarGroup and ToolbarToggleGroup.

#### Examples

In:

```jsx
%inputExample%
```

Out:

```jsx
%outputExample%
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
const ruleTester = require("../../ruletester");
import * as rule from "./toolbar-replaced-spacer-spaceItems";
import { RuleTester } from "eslint";

const toolbarComponents = ["ToolbarGroup", "ToolbarToggleGroup", "ToolbarItem"];
const validTests: Array<string | RuleTester.ValidTestCase> = [];
const invalidTests: RuleTester.InvalidTestCase[] = [];
const createValidTest = (code: string) => ({
code,
});
const createInvalidTest = (code: string, output: string, message: string) => ({
code,
output,
errors: [
{
message,
type: "JSXOpeningElement",
},
],
});

toolbarComponents.forEach((component) => {
validTests.push(createValidTest(`<${component} spacer />`));
validTests.push(createValidTest(`<${component} spaceItems />`));
validTests.push(
createValidTest(
`import { ${component} } from '@patternfly/react-core'; <${component} />`
)
);

const spacerErrorMessage = `The spacer property has been removed from ${component}. We recommend instead using our new gap, columnGap, or rowGap properties.`;
const spaceItemsErrorMessage = `spaceItems property has been removed from ${component}.`;
invalidTests.push(
createInvalidTest(
`import { ${component} } from '@patternfly/react-core'; <${component} spacer={{default: "spacerNone"}} />`,
`import { ${component} } from '@patternfly/react-core'; <${component} gap={{default: "gapNone"}} />`,
spacerErrorMessage
)
);
invalidTests.push(
createInvalidTest(
`import { ${component} as CustomComponent } from '@patternfly/react-core'; <CustomComponent spacer={{default: "spacerNone"}} />`,
`import { ${component} as CustomComponent } from '@patternfly/react-core'; <CustomComponent gap={{default: "gapNone"}} />`,
`The spacer property has been removed from CustomComponent. We recommend instead using our new gap, columnGap, or rowGap properties.`
)
);
invalidTests.push(
createInvalidTest(
`import { ${component} } from '@patternfly/react-core'; <${component} spacer={{default: "spacerNone", md: "spacerLg", lg: "spacerSm"}} />`,
`import { ${component} } from '@patternfly/react-core'; <${component} gap={{default: "gapNone", md: "gapLg", lg: "gapSm"}} />`,
spacerErrorMessage
)
);
createInvalidTest(
`import { ${component} } from '@patternfly/react-core'; <${component} spaceItems={{default: "spaceItemsNone"}} />`,
`import { ${component} } from '@patternfly/react-core'; <${component} />`,
`The ${spaceItemsErrorMessage}`
);
createInvalidTest(
`import { ${component} } from '@patternfly/react-core'; <${component} spacer={{default: "spacerNone"}} spaceItems={{default: "spaceItemsNone"}} />`,
`import { ${component} } from '@patternfly/react-core'; <${component} gap={{default: "gapNone"}} />`,
`${spacerErrorMessage} Additionally, the ${spaceItemsErrorMessage}`
);
invalidTests.push(
createInvalidTest(
`import { ${component} } from '@patternfly/react-core/dist/esm/components/Toolbar/index.js'; <${component} spacer={{default: "spacerNone"}} />`,
`import { ${component} } from '@patternfly/react-core/dist/esm/components/Toolbar/index.js'; <${component} gap={{default: "gapNone"}} />`,
spacerErrorMessage
)
);
invalidTests.push(
createInvalidTest(
`import { ${component} } from '@patternfly/react-core/dist/js/components/Toolbar/index.js'; <${component} spacer={{default: "spacerNone"}} />`,
`import { ${component} } from '@patternfly/react-core/dist/js/components/Toolbar/index.js'; <${component} gap={{default: "gapNone"}} />`,
spacerErrorMessage
)
);
invalidTests.push(
createInvalidTest(
`import { ${component} } from '@patternfly/react-core/dist/dynamic/components/Toolbar/index.js'; <${component} spacer={{default: "spacerNone"}} />`,
`import { ${component} } from '@patternfly/react-core/dist/dynamic/components/Toolbar/index.js'; <${component} gap={{default: "gapNone"}} />`,
spacerErrorMessage
)
);
});

ruleTester.run("toolbar-replaced-spacer-spaceItems", rule, {
valid: validTests,
invalid: invalidTests,
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { Rule } from "eslint";
import { JSXOpeningElement, JSXAttribute } from "estree-jsx";
import { Property } from "estree-jsx";
import { getFromPackage, getAttribute, getAttributeValue } from "../../helpers";

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

const toolbarImports = imports.filter((specifier) =>
["ToolbarGroup", "ToolbarToggleGroup", "ToolbarItem"].includes(
specifier.imported.name
)
);

return !toolbarImports.length
? {}
: {
JSXOpeningElement(node: JSXOpeningElement) {
if (
node.name.type === "JSXIdentifier" &&
toolbarImports
.map((imp) => imp.local.name)
.includes(node.name.name)
) {
const spacerProp = getAttribute(node, "spacer");
const spaceItemsProp = getAttribute(node, "spaceItems");
if (!spacerProp && !spaceItemsProp) {
return;
}
const spacerPropMessage = `The spacer property has been removed from ${node.name.name}. We recommend instead using our new gap, columnGap, or rowGap properties.`;
const spaceItemsPropMessage = `${
spacerProp ? " Additionally, the" : "The"
} spaceItems property has been removed from ${node.name.name}.`;
const spacerVal =
spacerProp && getAttributeValue(context, spacerProp.value);

context.report({
node,
message: `${spacerProp ? spacerPropMessage : ""}${
spaceItemsProp ? spaceItemsPropMessage : ""
}`,
fix(fixer) {
const fixes = [];

if (spacerProp) {
spacerVal &&
spacerVal.forEach((val: Property) => {
const newValue =
val.value?.type === "Literal" &&
(val.value.value as string).replace("spacer", "gap");

fixes.push(
fixer.replaceText(val.value, `"${newValue}"`)
);
});

fixes.push(fixer.replaceText(spacerProp.name, "gap"));
}
if (spaceItemsProp) {
fixes.push(fixer.replaceText(spaceItemsProp, ""));
}

return fixes;
},
});
}
},
};
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {
ToolbarGroup,
ToolbarItem,
ToolbarToggleGroup,
} from "@patternfly/react-core";

export const ToolbarReplacedSpacerSpaceItemsInput = () => (
<>
<ToolbarGroup
spacer={{ default: "spacerNone", md: "spacerSm", lg: "spacerMd" }}
spaceItems={{
default: "spaceItemsNone",
md: "spaceItemsSm",
lg: "spaceItemsMd",
}}
/>
<ToolbarItem
spacer={{ default: "spacerNone", md: "spacerSm", lg: "spacerMd" }}
/>
<ToolbarToggleGroup
spacer={{ default: "spacerNone", md: "spacerSm", lg: "spacerMd" }}
spaceItems={{
default: "spaceItemsNone",
md: "spaceItemsSm",
lg: "spaceItemsMd",
}}
/>
</>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import {
ToolbarGroup,
ToolbarItem,
ToolbarToggleGroup,
} from "@patternfly/react-core";

export const ToolbarReplacedSpacerSpaceItemsInput = () => (
<>
<ToolbarGroup
gap={{ default: "gapNone", md: "gapSm", lg: "gapMd" }}

/>
<ToolbarItem
gap={{ default: "gapNone", md: "gapSm", lg: "gapMd" }}
/>
<ToolbarToggleGroup
gap={{ default: "gapNone", md: "gapSm", lg: "gapMd" }}

/>
</>
);

0 comments on commit 1a74735

Please sign in to comment.