From 38b121f27a30faf4a8825fb94ecd958f0ea74596 Mon Sep 17 00:00:00 2001 From: winkerVSbecks Date: Tue, 17 Nov 2020 16:39:01 -0500 Subject: [PATCH 1/3] Port over Cardinal component from Chromatic --- package.json | 2 + src/components/Cardinal.stories.tsx | 165 +++++++++++++++++++++ src/components/Cardinal.tsx | 215 ++++++++++++++++++++++++++++ src/components/index.js | 1 + yarn.lock | 5 + 5 files changed, 388 insertions(+) create mode 100644 src/components/Cardinal.stories.tsx create mode 100644 src/components/Cardinal.tsx diff --git a/package.json b/package.json index bda3bc43..8867fc45 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,9 @@ ] }, "dependencies": { + "@types/pluralize": "^0.0.29", "copy-to-clipboard": "^3.3.1", + "pluralize": "^8.0.0", "polished": "^3.6.4", "prismjs": "1.20.0", "prop-types": "^15.5.4", diff --git a/src/components/Cardinal.stories.tsx b/src/components/Cardinal.stories.tsx new file mode 100644 index 00000000..30fadbb2 --- /dev/null +++ b/src/components/Cardinal.stories.tsx @@ -0,0 +1,165 @@ +import { action } from '@storybook/addon-actions'; +import React from 'react'; + +import { Cardinal } from './Cardinal'; + +const onHover = action('hover'); +const onClick = action('click'); + +export default { + title: 'Design System/Cardinal', +}; + +export const AllCardinals = () => ( +
+ + + + + + +
+ + + +
+ + + + + +
+); + +AllCardinals.story = { + name: 'all cardinals', +}; + +export const SmallLoading = () => ; + +SmallLoading.story = { + name: 'small loading', +}; + +export const SmallDefault = () => ; + +SmallDefault.story = { + name: 'small default', +}; + +export const SmallPositive = () => ( + +); + +SmallPositive.story = { + name: 'small positive', +}; + +export const SmallNegative = () => ( + +); + +SmallNegative.story = { + name: 'small negative', +}; + +export const SmallWarning = () => ( + +); + +SmallWarning.story = { + name: 'small warning', +}; + +export const SmallNeutral = () => ( + +); + +SmallNeutral.story = { + name: 'small neutral', +}; + +export const SmallSelectable = () => ( +
+ + +
+); + +SmallSelectable.story = { + name: 'small selectable', +}; + +export const LargeLoading = () => ; + +LargeLoading.story = { + name: 'large loading', +}; + +export const LargeDefault = () => ; + +LargeDefault.story = { + name: 'large default', +}; + +export const LargeLink = () => ( + +); + +LargeLink.story = { + name: 'large link', +}; + +export const LargeSingular = () => ; + +LargeSingular.story = { + name: 'large singular', +}; + +export const LargePlural = () => ; + +LargePlural.story = { + name: 'large plural', +}; diff --git a/src/components/Cardinal.tsx b/src/components/Cardinal.tsx new file mode 100644 index 00000000..563d72ee --- /dev/null +++ b/src/components/Cardinal.tsx @@ -0,0 +1,215 @@ +import pluralize from 'pluralize'; +import { darken } from 'polished'; +import React from 'react'; +import styled, { css } from 'styled-components'; +import { Link } from './Link'; +import { background, color, typography, spacing } from './shared/styles'; +import { inlineGlow } from './shared/animation'; + +type Status = 'default' | 'positive' | 'negative' | 'warning' | 'neutral' | 'link'; +type Size = 'small' | 'large'; + +interface CountProps { + status: Status; +} + +const Count = styled.div` + color: ${color.dark}; + display: block; + + ${(props) => + props.status === 'positive' && + css` + color: ${color.positive}; + `}; + ${(props) => + props.status === 'negative' && + css` + color: ${color.negative}; + `}; + ${(props) => + props.status === 'warning' && + css` + color: ${color.warning}; + `}; + ${(props) => + props.status === 'neutral' && + css` + color: ${color.mediumdark}; + `}; + ${(props) => + props.status === 'link' && + css` + color: ${color.secondary}; + text-decoration: none; + &:hover { + color: ${darken(0.07, color.secondary)}; + } + &:active { + color: ${darken(0.1, color.secondary)}; + } + `}; + + span { + display: inline-block; + } +`; + +const Text = styled.div` + span { + display: inline-block; + } +`; + +interface CardinalInnerProps { + isLoading: boolean; + selectable: boolean; + active: boolean; + size: Size; +} + +const CardinalInner = styled.div` + display: inline-block; + vertical-align: top; + padding: 8px 12px; + border-radius: ${spacing.borderRadius.small}px; + + svg { + height: 12px; + margin: 1px 0; + vertical-align: top; + color: inherit; + } + + ${(props) => + props.isLoading && + css` + ${Count}, ${Text} { + overflow: hidden; + + > span, + a { + ${inlineGlow}; + } + + img { + opacity: 0; + } + } + `}; + + ${(props) => + props.selectable && + css` + cursor: pointer; + + &:hover { + background: ${background.app}; + } + `}; + + ${(props) => + props.active && + css` + background: ${background.app}; + `}; + + ${Count} { + font-weight: ${(props) => + props.size === 'small' ? typography.weight.bold : typography.weight.regular}; + font-size: ${(props) => (props.size === 'small' ? typography.size.s2 : typography.size.m3)}px; + line-height: ${(props) => (props.size === 'small' ? typography.size.s3 : typography.size.m3)}px; + margin-bottom: ${(props) => (props.size === 'small' ? 2 : 4)}px; + } + + ${Text} { + color: ${(props) => (props.size === 'small' ? color.mediumdark : color.dark)}; + font-size: ${(props) => (props.size === 'small' ? typography.size.s1 : typography.size.s2)}px; + line-height: ${(props) => (props.size === 'small' ? typography.size.s2 : typography.size.m1)}px; + clear: both; + } +`; + +interface CardinalProps { + isLoading: boolean; + selectable: boolean; + active: boolean; + size: Size; + onHover: (e: boolean) => void; + onClick: React.FormEventHandler; + count: React.ReactNode; + countLink: string; + text: string; + status: Status; + noPlural: boolean; + CountWrapper: React.ElementType; + TextWrapper: React.ElementType; +} + +export function Cardinal({ + isLoading, + selectable, + onHover, + onClick, + active, + size, + count, + countLink, + text, + noPlural, + status, + CountWrapper, + TextWrapper, + ...props +}: CardinalProps) { + let countValue = count; + if (countLink) { + countValue = {count}; + } + let events = {}; + if (selectable) { + events = { + onMouseEnter: () => onHover(true), + onMouseLeave: () => onHover(false), + onClick, + }; + } + + return ( + + + {countValue} + + + + {!noPlural && typeof count === 'number' ? pluralize(text, count) : text} + + + + ); +} + +const DefaultWrapper: React.FunctionComponent = ({ children }) => {children}; + +Cardinal.defaultProps = { + isLoading: false, + selectable: false, + onHover: () => 0, + onClick: () => 0, + active: false, + size: 'large', + status: 'default', + count: '000', + countLink: null, + noPlural: false, + text: 'loading', + CountWrapper: DefaultWrapper, + TextWrapper: DefaultWrapper, +}; diff --git a/src/components/index.js b/src/components/index.js index cfdff00c..c3fcc37d 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -15,6 +15,7 @@ export * from './Link'; export * from './Subheading'; export * from './ProgressDots'; export * from './Spinner'; +export * from './Cardinal'; export * from './Input'; export * from './Textarea'; diff --git a/yarn.lock b/yarn.lock index cd6617fe..3f777680 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4590,6 +4590,11 @@ resolved "https://registry.npmjs.org/@types/parse5/-/parse5-5.0.3.tgz#e7b5aebbac150f8b5fdd4a46e7f0bd8e65e19109" integrity sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw== +"@types/pluralize@^0.0.29": + version "0.0.29" + resolved "https://registry.npmjs.org/@types/pluralize/-/pluralize-0.0.29.tgz#6ffa33ed1fc8813c469b859681d09707eb40d03c" + integrity sha512-BYOID+l2Aco2nBik+iYS4SZX0Lf20KPILP5RGmM1IgzdwNdTs0eebiFriOPcej1sX9mLnSoiNte5zcFxssgpGA== + "@types/prettier@^1.19.0": version "1.19.1" resolved "https://registry.npmjs.org/@types/prettier/-/prettier-1.19.1.tgz#33509849f8e679e4add158959fdb086440e9553f" From 8f2c45de4ef7d20cd1fc57372e03229dd1d6f091 Mon Sep 17 00:00:00 2001 From: winkerVSbecks Date: Wed, 18 Nov 2020 14:41:17 -0500 Subject: [PATCH 2/3] Add alignment control for Cardinal --- src/components/Cardinal.stories.tsx | 16 ++++++++++++++++ src/components/Cardinal.tsx | 7 +++++++ 2 files changed, 23 insertions(+) diff --git a/src/components/Cardinal.stories.tsx b/src/components/Cardinal.stories.tsx index 30fadbb2..03c40a49 100644 --- a/src/components/Cardinal.stories.tsx +++ b/src/components/Cardinal.stories.tsx @@ -60,6 +60,22 @@ AllCardinals.story = { name: 'all cardinals', }; +export const Alignment = () => ( +
+ + + +
+ + + +
+); + +Alignment.story = { + name: 'control alignment', +}; + export const SmallLoading = () => ; SmallLoading.story = { diff --git a/src/components/Cardinal.tsx b/src/components/Cardinal.tsx index 563d72ee..ca5b36c2 100644 --- a/src/components/Cardinal.tsx +++ b/src/components/Cardinal.tsx @@ -8,6 +8,7 @@ import { inlineGlow } from './shared/animation'; type Status = 'default' | 'positive' | 'negative' | 'warning' | 'neutral' | 'link'; type Size = 'small' | 'large'; +type Alignment = 'left' | 'center' | 'right'; interface CountProps { status: Status; @@ -66,6 +67,7 @@ interface CardinalInnerProps { selectable: boolean; active: boolean; size: Size; + alignment: Alignment; } const CardinalInner = styled.div` @@ -73,6 +75,7 @@ const CardinalInner = styled.div` vertical-align: top; padding: 8px 12px; border-radius: ${spacing.borderRadius.small}px; + text-align: ${(props) => props.alignment}; svg { height: 12px; @@ -144,6 +147,7 @@ interface CardinalProps { noPlural: boolean; CountWrapper: React.ElementType; TextWrapper: React.ElementType; + alignment?: Alignment; } export function Cardinal({ @@ -160,6 +164,7 @@ export function Cardinal({ status, CountWrapper, TextWrapper, + alignment, ...props }: CardinalProps) { let countValue = count; @@ -181,6 +186,7 @@ export function Cardinal({ selectable={selectable} active={active} size={size} + alignment={alignment} {...events} {...props} > @@ -212,4 +218,5 @@ Cardinal.defaultProps = { text: 'loading', CountWrapper: DefaultWrapper, TextWrapper: DefaultWrapper, + alignment: 'left', }; From 0368c3ce0cc7b56c4d10312e8ecb30756e420b52 Mon Sep 17 00:00:00 2001 From: winkerVSbecks Date: Fri, 20 Nov 2020 19:51:06 -0500 Subject: [PATCH 3/3] update story name to use the new structure --- src/components/Cardinal.stories.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Cardinal.stories.tsx b/src/components/Cardinal.stories.tsx index 03c40a49..f15e790c 100644 --- a/src/components/Cardinal.stories.tsx +++ b/src/components/Cardinal.stories.tsx @@ -7,7 +7,7 @@ const onHover = action('hover'); const onClick = action('click'); export default { - title: 'Design System/Cardinal', + title: 'Cardinal', }; export const AllCardinals = () => (