Skip to content

Commit

Permalink
[SvgIcon] Allow viewBox to inherit from Component through inheritView…
Browse files Browse the repository at this point in the history
…Box prop (#29954)

Co-authored-by: Gonçalo Vieira Figueiredo <me@goncalovf.com>
  • Loading branch information
alex-dikusar and goncalovf committed Dec 30, 2021
1 parent d3c609b commit 2663458
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 2 deletions.
1 change: 1 addition & 0 deletions docs/pages/api-docs/svg-icon.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"default": "'medium'"
},
"htmlColor": { "type": { "name": "string" } },
"inheritViewBox": { "type": { "name": "bool" } },
"shapeRendering": { "type": { "name": "string" } },
"sx": {
"type": {
Expand Down
2 changes: 1 addition & 1 deletion docs/src/pages/components/icons/icons.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ If you need a custom SVG icon (not available in the [Material Icons](/components
This component extends the native `<svg>` element:

- It comes with built-in accessibility.
- SVG elements should be scaled for a 24x24px viewport so that the resulting icon can be used as is, or included as a child for other MUI components that use icons. (This can be customized with the `viewBox` attribute).
- SVG elements should be scaled for a 24x24px viewport so that the resulting icon can be used as is, or included as a child for other MUI components that use icons. (This can be customized with the `viewBox` attribute, to inherit `viewBox` value from original image `inheritViewBox` attribute can be used).
- By default, the component inherits the current color. Optionally, you can apply one of the theme colors using the `color` prop.

```jsx
Expand Down
1 change: 1 addition & 0 deletions docs/translations/api-docs/svg-icon/svg-icon.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"component": "The component used for the root node. Either a string to use a HTML element or a component.",
"fontSize": "The fontSize applied to the icon. Defaults to 24px, but can be configure to inherit font size.",
"htmlColor": "Applies a color attribute to the SVG element.",
"inheritViewBox": "Useful when you want to reference a custom <code>component</code> and have <code>SvgIcon</code> pass that <code>component</code>&#39;s viewBox to the root node. If <code>true</code>, the root node will inherit the custom <code>component</code>&#39;s viewBox and the <code>viewBox</code> prop will be ignored.",
"shapeRendering": "The shape-rendering attribute. The behavior of the different options is described on the <a href=\"https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/shape-rendering\">MDN Web Docs</a>. If you are having issues with blurry icons you should investigate this prop.",
"sx": "The system prop that allows defining system overrides as well as additional CSS styles. See the <a href=\"/system/the-sx-prop/\">`sx` page</a> for more details.",
"titleAccess": "Provides a human-readable title for the element that contains it. <a href=\"https://www.w3.org/TR/SVG-access/#Equivalent\">https://www.w3.org/TR/SVG-access/#Equivalent</a>",
Expand Down
8 changes: 8 additions & 0 deletions packages/mui-material/src/SvgIcon/SvgIcon.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ export interface SvgIconTypeMap<P = {}, D extends React.ElementType = 'svg'> {
* Applies a color attribute to the SVG element.
*/
htmlColor?: string;
/**
* Useful when you want to reference a custom `component` and have `SvgIcon` pass that
* `component`'s viewBox to the root node.
* If `true`, the root node will inherit the custom `component`'s viewBox and the `viewBox`
* prop will be ignored.
* @default false
*/
inheritViewBox?: boolean;
/**
* The shape-rendering attribute. The behavior of the different options is described on the
* [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/shape-rendering).
Expand Down
18 changes: 17 additions & 1 deletion packages/mui-material/src/SvgIcon/SvgIcon.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ const SvgIcon = React.forwardRef(function SvgIcon(inProps, ref) {
fontSize = 'medium',
htmlColor,
titleAccess,
inheritViewBox = false,
viewBox = '0 0 24 24',
...other
} = props;
Expand All @@ -78,9 +79,16 @@ const SvgIcon = React.forwardRef(function SvgIcon(inProps, ref) {
color,
component,
fontSize,
inheritViewBox,
viewBox,
};

const more = {};

if (!inheritViewBox) {
more.viewBox = viewBox;
}

const classes = useUtilityClasses(ownerState);

return (
Expand All @@ -89,11 +97,11 @@ const SvgIcon = React.forwardRef(function SvgIcon(inProps, ref) {
className={clsx(classes.root, className)}
ownerState={ownerState}
focusable="false"
viewBox={viewBox}
color={htmlColor}
aria-hidden={titleAccess ? undefined : true}
role={titleAccess ? 'img' : undefined}
ref={ref}
{...more}
{...other}
>
{children}
Expand Down Expand Up @@ -155,6 +163,14 @@ SvgIcon.propTypes /* remove-proptypes */ = {
* Applies a color attribute to the SVG element.
*/
htmlColor: PropTypes.string,
/**
* Useful when you want to reference a custom `component` and have `SvgIcon` pass that
* `component`'s viewBox to the root node.
* If `true`, the root node will inherit the custom `component`'s viewBox and the `viewBox`
* prop will be ignored.
* @default false
*/
inheritViewBox: PropTypes.bool,
/**
* The shape-rendering attribute. The behavior of the different options is described on the
* [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/shape-rendering).
Expand Down
20 changes: 20 additions & 0 deletions packages/mui-material/src/SvgIcon/SvgIcon.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,24 @@ describe('<SvgIcon />', () => {
expect(container.firstChild).to.have.class(classes.fontSizeInherit);
});
});

describe('prop: inheritViewBox', () => {
const customSvg = (props) => (
<svg viewBox="-4 -4 24 24" {...props}>
{path}
</svg>
);
it('should render with the default viewBox if neither inheritViewBox nor viewBox are provided', () => {
const { container } = render(<SvgIcon component={customSvg} />);
expect(container.firstChild).to.have.attribute('viewBox', '0 0 24 24');
});
it('should render with given viewBox if inheritViewBox is not provided', () => {
const { container } = render(<SvgIcon component={customSvg} viewBox="0 0 30 30" />);
expect(container.firstChild).to.have.attribute('viewBox', '0 0 30 30');
});
it("should use the custom component's viewBox if true", () => {
const { container } = render(<SvgIcon component={customSvg} inheritViewBox />);
expect(container.firstChild).to.have.attribute('viewBox', '-4 -4 24 24');
});
});
});

0 comments on commit 2663458

Please sign in to comment.