Skip to content

Commit

Permalink
Add loading state for tags and split TagItem into Item and Link
Browse files Browse the repository at this point in the history
  • Loading branch information
winkerVSbecks committed Oct 20, 2020
1 parent 17d457c commit 2aa9499
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 83 deletions.
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'],
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React from 'react';
import { TagItem } from './TagItem';
import { StoryLinkWrapper } from '../StoryLinkWrapper';

export default {
component: TagItem,
Expand All @@ -9,4 +8,6 @@ export default {

export const Default = () => <TagItem>⚛️ React</TagItem>;

export const WithLinkWrapper = () => <TagItem LinkWrapper={StoryLinkWrapper}>⚛️ React</TagItem>;
export const WithLinkWrapper = () => <TagItem>⚛️ React</TagItem>;

export const Loading = () => <TagItem isLoading />;
54 changes: 21 additions & 33 deletions src/components/tag/TagItem.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,17 @@
import React from 'react';
import styled from 'styled-components';
import styled, { css } from 'styled-components';
import { rgba } from 'polished';
import { color, typography, background, spacing } from '../shared/styles';
// @ts-ignore
import { Link } from '../Link';
import { inlineGlow } from '../shared/animation';

type TagItemProps = {
containsIcon?: boolean;
inverse?: boolean;
isButton?: boolean;
LinkWrapper?: React.ComponentType | (() => React.ReactNode);
nochrome?: boolean;
secondary?: boolean;
tertiary?: boolean;
withArrow?: boolean;
export type TagItemProps = {
isLoading?: boolean;
};

export const TagItem = styled(Link)<TagItemProps>`
export const TagItem = styled.div.attrs<TagItemProps>(({ isLoading, children }) => ({
children: isLoading ? 'Loading tag' : children,
}))<TagItemProps>`
display: inline-block;
background: ${background.app};
border-radius: ${spacing.borderRadius.small}px;
padding: 5px 10px;
Expand All @@ -29,24 +24,17 @@ export const TagItem = styled(Link)<TagItemProps>`
border-color: transparent;
white-space: nowrap;
&:after {
content: '';
position: absolute;
z-index: -1;
top: 0;
left: 0;
width: 100%;
height: 100%;
box-shadow: rgba(0, 0, 0, 0.08) 0 3px 10px 0;
opacity: 0;
transition: opacity 0.3s ease-in-out;
}
&:hover {
border-color: ${rgba(color.secondary, 0.5)};
&:after {
opacity: 1;
}
}
${(props) =>
props.isLoading &&
css`
cursor: progress !important;
${inlineGlow};
&:hover {
color: transparent;
}
`}
`;

TagItem.defaultProps = {
isLoading: false,
};
19 changes: 19 additions & 0 deletions src/components/tag/TagLink.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';
import { TagLink } from './TagLink';
// @ts-ignore
import { StoryLinkWrapper } from '../StoryLinkWrapper';

export default {
component: TagLink,
title: 'Design System/Tag/TagLink',
};

export const Default = () => <TagLink href="https://chromatic.com">⚛️ React</TagLink>;

export const WithLinkWrapper = () => (
<TagLink to="https://chromatic.com" LinkWrapper={StoryLinkWrapper as React.FC<{ to: string }>}>
⚛️ React
</TagLink>
);

export const Loading = () => <TagLink isLoading />;
75 changes: 75 additions & 0 deletions src/components/tag/TagLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import styled, { css } from 'styled-components';
import { rgba } from 'polished';
import { color, typography, background, spacing } from '../shared/styles';
// @ts-ignore
import { inlineGlow } from '../shared/animation';
// @ts-ignore
import { Link } from '../Link';

export type TagLinkProps = {
isLoading?: boolean;
containsIcon?: boolean;
inverse?: boolean;
isButton?: boolean;
LinkWrapper?: React.ComponentType | (() => React.ReactNode);
nochrome?: boolean;
secondary?: boolean;
tertiary?: boolean;
withArrow?: boolean;
};

export const TagLink = styled(Link).attrs<TagLinkProps>(({ isLoading, children }) => ({
children: isLoading ? 'Loading tag' : children,
}))<TagLinkProps>`
display: inline-block;
background: ${background.app};
border-radius: ${spacing.borderRadius.small}px;
padding: 5px 10px;
font-size: ${typography.size.s2}px;
line-height: ${typography.size.m2}px;
position: relative;
color: ${color.darkest};
border-width: 1px;
border-style: solid;
border-color: transparent;
white-space: nowrap;
&:after {
content: '';
position: absolute;
z-index: -1;
top: 0;
left: 0;
width: 100%;
height: 100%;
box-shadow: rgba(0, 0, 0, 0.08) 0 3px 10px 0;
opacity: 0;
transition: opacity 0.3s ease-in-out;
}
${(props) =>
!props.isLoading &&
css`
&:hover {
border-color: ${rgba(color.secondary, 0.5)};
&:after {
opacity: 1;
}
}
`}
${(props) =>
props.isLoading &&
css`
cursor: progress !important;
${inlineGlow};
&:hover {
color: transparent;
}
`}
`;

TagLink.defaultProps = {
isLoading: false,
};
Original file line number Diff line number Diff line change
@@ -1,44 +1,14 @@
import React from 'react';
import { TagList } from './TagList';
import { TagItem } from './TagItem';
import { TagLink } from './TagLink';

export default {
component: TagList,
excludeStories: /.*Data$/,
title: 'Design System/Tag/TagList',
};

export const Default = () => (
<TagList
tags={mockTagsData.slice(0, 4).map((tag) => (
<TagItem key={tag.link} href={tag.link}>
{tag.name}
</TagItem>
))}
/>
);

export const WithMoreTags = () => (
<TagList
tags={mockTagsData.map((tag) => (
<TagItem key={tag.link} href={tag.link}>
{tag.name}
</TagItem>
))}
/>
);

export const WithCustomLimit = () => (
<TagList
tags={mockTagsData.map((tag) => (
<TagItem key={tag.link} href={tag.link}>
{tag.name}
</TagItem>
))}
limit={6}
/>
);

export const mockTagsData = [
{
link: '/ui',
Expand Down Expand Up @@ -125,3 +95,35 @@ export const mockTagsData = [
name: '📽 Animation',
},
];

const Template = (args: { tags: any[]; limit: number; isLoading }) => (
<TagList
isLoading={args.isLoading}
limit={args.limit}
tags={args.tags.map((tag: any) => (
<TagItem key={tag.link}>{tag.name}</TagItem>
))}
/>
);

export const Default = Template.bind({});
Default.args = { tags: mockTagsData.slice(0, 4) };

export const WithMoreTags = Template.bind({});
WithMoreTags.args = { tags: mockTagsData };

export const WithCustomLimit = Template.bind({});
WithCustomLimit.args = { tags: mockTagsData, limit: 6 };

export const Loading = Template.bind({});
Loading.args = { tags: [], isLoading: true };

export const AsLinks = () => (
<TagList
tags={mockTagsData.map((tag: any) => (
<TagLink key={tag.link} href={tag.link}>
{tag.name}
</TagLink>
))}
/>
);
35 changes: 24 additions & 11 deletions src/components/tag/TagList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,31 +27,44 @@ const MoreTagsButton = styled(Link)`
}
`;

type TagListTypes = {
tags: typeof TagItem[];
limit: number;
export type TagListProps = {
tags: React.ReactNode[];
isLoading?: boolean;
limit?: number;
};

export const TagList = forwardRef<HTMLDivElement, TagListTypes>(
({ tags, limit, ...props }: TagListTypes, ref) => {
export const TagList = forwardRef<HTMLDivElement, TagListProps>(
({ tags = [], limit = 4, isLoading = false, ...props }: TagListProps, ref) => {
const primaryTags = tags.slice(0, limit);
const moreTags = tags.slice(limit);

const [moreTagsVisible, setMoreTagsVisible] = useState(false);

return (
<TagListWrapper {...props} ref={ref}>
const tagContent = (
<>
{primaryTags}
{moreTagsVisible && moreTags}
{moreTags.length > 0 && !moreTagsVisible && (
<MoreTagsButton isButton appearance="primary" onClick={() => setMoreTagsVisible(true)}>
{`+ ${moreTags.length} more`}
</MoreTagsButton>
)}
</>
);

return (
<TagListWrapper {...props} ref={ref}>
{isLoading ? (
<>
<TagItem isLoading />
<TagItem isLoading />
<TagItem isLoading />
<TagItem isLoading />
</>
) : (
tagContent
)}
</TagListWrapper>
);
}
);

TagList.defaultProps = {
limit: 4,
};

0 comments on commit 2aa9499

Please sign in to comment.