Skip to content

Commit

Permalink
feat: add forwardRef to icon component (#152)
Browse files Browse the repository at this point in the history
  • Loading branch information
okry authored Jan 11, 2021
1 parent 750dae3 commit f921c3e
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 36 deletions.
9 changes: 9 additions & 0 deletions packages/react/__tests__/src/components/Icon/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,12 @@ test('sets aria-label to the value of the label prop', () => {
const icon = mount(<Icon type="foo" label="Fred" />);
expect(icon.getDOMNode().getAttribute('aria-label')).toBe('Fred');
});

test('supports ref prop', done => {
const ref = icon => {
expect(icon).toBeTruthy();
done();
};

mount(<Icon type="foo" ref={ref} />);
});
78 changes: 42 additions & 36 deletions packages/react/src/components/Icon/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, forwardRef } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

Expand All @@ -8,44 +8,50 @@ export interface IconProps extends React.HTMLAttributes<HTMLDivElement> {
type: string;
}

function Icon({ label, className, type, ...other }: IconProps) {
const [, name, direction] = type.match(/(.*)-(right|left|up|down)$/) || [
'',
type
];
const [IconSVG, setIcon] = useState<React.ComponentType<any> | null>(null);

useEffect(() => {
// NOTE: we don't want to pollute test output with
// console.errors as a result of the dynamic imports
if (process.env.NODE_ENV === 'test') {
return;
}
const Icon = forwardRef<HTMLDivElement, IconProps>(
({ label, className, type, ...other }: IconProps, ref) => {
const [, name, direction] = type.match(/(.*)-(right|left|up|down)$/) || [
'',
type
];
const [IconSVG, setIcon] = useState<React.ComponentType<any> | null>(null);

useEffect(() => {
// NOTE: we don't want to pollute test output with
// console.errors as a result of the dynamic imports
if (process.env.NODE_ENV === 'test') {
return;
}

import(`./icons/${name}.svg`)
.then(icon => {
setIcon(() => icon.default);
import(`./icons/${name}.svg`)
.then(icon => {
setIcon(() => icon.default);
})
.catch(ex => {
console.error(`Could not find icon type "${type}".`);
setIcon(null);
});
}, [type]);

const data = {
...other,
'aria-hidden': !label,
className: classNames('Icon', `Icon--${type}`, className, {
[`Icon__${direction}`]: !!direction
})
.catch(ex => {
console.error(`Could not find icon type "${type}".`);
setIcon(null);
});
}, [type]);

const data = {
...other,
'aria-hidden': !label,
className: classNames('Icon', `Icon--${type}`, className, {
[`Icon__${direction}`]: !!direction
})
};

if (label) {
data['aria-label'] = label;
}
};

return <div {...data}>{IconSVG && <IconSVG />}</div>;
}
if (label) {
data['aria-label'] = label;
}

return (
<div ref={ref} {...data}>
{IconSVG && <IconSVG />}
</div>
);
}
);

Icon.propTypes = {
label: PropTypes.string,
Expand Down

0 comments on commit f921c3e

Please sign in to comment.