Skip to content

Commit

Permalink
Merge pull request #215 from storybookjs/link-ts
Browse files Browse the repository at this point in the history
Convert Link to TS
  • Loading branch information
winkerVSbecks authored Oct 26, 2020
2 parents 9674dfb + b460634 commit b131adf
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 70 deletions.
8 changes: 8 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,12 @@ const ignore = 0;
module.exports = {
root: true,
extends: ['@storybook/eslint-config-storybook'],
overrides: [
{
files: ['**/*.tsx'],
rules: {
'react/prop-types': 'off',
},
},
],
};
8 changes: 2 additions & 6 deletions .storybook/main.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
module.exports = {
stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.js'],
addons: [
'@storybook/addon-essentials',
'@storybook/addon-storysource',
'@storybook/addon-a11y',
],
stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.js', '../src/**/*.stories.tsx'],
addons: ['@storybook/addon-essentials', '@storybook/addon-storysource', '@storybook/addon-a11y'],
};
1 change: 0 additions & 1 deletion src/components/Avatar.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable react/prop-types */
import React, { FunctionComponent, ComponentProps } from 'react';
import styled, { css } from 'styled-components';
import { color, typography } from './shared/styles';
Expand Down
1 change: 0 additions & 1 deletion src/components/AvatarList.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable react/prop-types */
import React, { ComponentProps, FunctionComponent } from 'react';
import styled from 'styled-components';

Expand Down
1 change: 0 additions & 1 deletion src/components/Icon.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable react/prop-types */
import React, { FunctionComponent } from 'react';
import styled from 'styled-components';
import { icons } from './shared/icons';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { action } from '@storybook/addon-actions';

import { Icon } from './Icon';
import { Link } from './Link';
// @ts-ignore
import { StoryLinkWrapper } from './StoryLinkWrapper';

const CustomLink = styled(Link)`
Expand All @@ -19,8 +20,11 @@ export default {
component: Link,
};

export const Basic = (args) => <Link {...args} />;
Basic.args = { children: 'link text', inverse: false };
export const Basic: React.FunctionComponent<React.ComponentProps<typeof Link>> = () => (
<Link href="http://chromatic.com/" inverse={false}>
link text
</Link>
);

export const All = () => (
<>
Expand Down
118 changes: 59 additions & 59 deletions src/components/Link.js → src/components/Link.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import React, { forwardRef } from 'react';
import PropTypes from 'prop-types';
import styled, { css } from 'styled-components';
import { darken } from 'polished';

import { Icon } from './Icon';
import { color } from './shared/styles';

const LinkInner = styled.span`
const LinkInner = styled.span<{ withArrow: boolean }>`
${(props) =>
props.withArrow &&
css`
Expand All @@ -21,7 +20,15 @@ const LinkInner = styled.span`
`};
`;

const StyledLink = styled.a`
interface StyledLinkProps {
containsIcon?: boolean;
secondary?: boolean;
tertiary?: boolean;
nochrome?: boolean;
inverse?: boolean;
}

const StyledLink = styled.a<StyledLinkProps>`
display: inline-block;
transition: transform 150ms ease-out, color 150ms ease-out;
text-decoration: none;
Expand Down Expand Up @@ -127,78 +134,71 @@ const LinkButton = styled.button`
outline: inherit;
`;

/**
* Links can contains text and/or icons. Be careful using only icons, you must provide a text alternative via aria-label for accessibility.
*/
export type LinkProps = React.ComponentProps<typeof StyledLink> & {
withArrow?: boolean;
isButton?: boolean;
LinkWrapper?: React.ComponentType<any>;
};

// The main purpose of this component is to strip certain props that get passed
// down to the styled component, so that we don't end up passing them to a
// tag which would throw warnings for non-standard props.
const LinkComponentPicker = forwardRef(
(
{ containsIcon, inverse, isButton, LinkWrapper, nochrome, secondary, tertiary, ...rest },
{
containsIcon,
inverse,
isButton,
LinkWrapper,
nochrome,
secondary,
tertiary,
...rest
}: LinkProps,
ref
) => {
// Use the UnstyledLink here to avoid duplicating styles and creating
// specificity conflicts by first rendering the StyledLink higher up the chain
// and then re-rendering it through the 'as' prop.
const LinkComponent = isButton ? LinkButton : LinkWrapper || UnstyledLink;
return <LinkComponent {...rest} />;
/* eslint no-else-return: ["error", { allowElseIf: true }] */
if (isButton) {
return <LinkButton {...rest} ref={ref} />;
} else if (LinkWrapper) {
return <LinkWrapper {...rest} ref={ref} />;
}

return <UnstyledLink {...rest} ref={ref} />;
}
);

const linkStyleProps = {
containsIcon: PropTypes.bool,
inverse: PropTypes.bool,
isButton: PropTypes.bool,
LinkWrapper: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
nochrome: PropTypes.bool,
secondary: PropTypes.bool,
tertiary: PropTypes.bool,
};
export const Link = forwardRef<HTMLAnchorElement | HTMLButtonElement, LinkProps>(
({ children, withArrow, ...rest }, ref) => {
const content = (
<>
<LinkInner withArrow={withArrow}>
{children}
{withArrow && <Icon icon="arrowright" />}
</LinkInner>
</>
);

return (
<StyledLink as={LinkComponentPicker} ref={ref} {...rest}>
{content}
</StyledLink>
);
}
);

const linkStyleDefaultProps = {
Link.defaultProps = {
withArrow: false,
isButton: false,
containsIcon: false,
LinkWrapper: undefined,
inverse: false,
nochrome: false,
secondary: false,
tertiary: false,
};

LinkComponentPicker.propTypes = {
...linkStyleProps,
};

LinkComponentPicker.defaultProps = {
...linkStyleDefaultProps,
};

/**
* Links can contains text and/or icons. Be careful using only icons, you must provide a text alternative via aria-label for accessibility.
*/
export const Link = forwardRef(({ children, withArrow, ...rest }, ref) => {
const content = (
<>
<LinkInner withArrow={withArrow}>
{children}
{withArrow && <Icon icon="arrowright" />}
</LinkInner>
</>
);

return (
<StyledLink as={LinkComponentPicker} ref={ref} {...rest}>
{content}
</StyledLink>
);
});

Link.propTypes = {
children: PropTypes.node,
withArrow: PropTypes.bool,
...linkStyleProps,
};

Link.defaultProps = {
children: null,
withArrow: false,
...linkStyleDefaultProps,
nochrome: false,
inverse: false,
};

0 comments on commit b131adf

Please sign in to comment.