Skip to content

Commit db8244e

Browse files
authored
Components: extend react types to reduce repetition (codesandbox#3548)
* extend react types * fix tag error * cant belive that worked? * include label props to build them with text
1 parent b54d300 commit db8244e

File tree

10 files changed

+85
-98
lines changed

10 files changed

+85
-98
lines changed

packages/components/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"lint": "eslint --ext .js,.ts,.tsx src",
2222
"start": "yarn tsc --watch",
2323
"start:storybook": "start-storybook",
24-
"typecheck": "tsc --noEmit",
24+
"typecheck": "tsc --noEmit --pretty",
2525
"chromatic": "if-env CIRCLE_BRANCH=master && yarn chromatic:master || yarn chromatic:branch",
2626
"chromatic:master": "CHROMATIC_APP_CODE=nffds42ndde ./node_modules/.bin/chromatic --build-script-name=build:storybook --exit-zero-on-changes --auto-accept-changes",
2727
"chromatic:branch": "CHROMATIC_APP_CODE=nffds42ndde ./node_modules/.bin/chromatic --build-script-name=build:storybook --exit-zero-on-changes",

packages/components/src/components/Button/index.tsx

Lines changed: 45 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -70,54 +70,54 @@ const variantStyles = {
7070
},
7171
};
7272

73-
export const Button = styled(Element).attrs({ as: 'button' })<{
74-
type?: 'submit' | 'button' | 'reset';
73+
interface IButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
7574
variant?: 'primary' | 'secondary' | 'link' | 'danger';
76-
disabled?: boolean;
77-
onClick?: any;
78-
}>(({ variant = 'primary', ...props }) =>
79-
css(
80-
deepmerge(
81-
// @ts-ignore deepmerge allows functions as values
82-
// it overrides instead of merging, which is what we want
83-
// but it's types don't like it. so we're going to ignore that
84-
// TODO: raise a pull request for deepmerge or pick a different
85-
// library to deep merge objects
86-
variantStyles[variant],
87-
// static styles:
88-
{
89-
display: 'inline-flex',
90-
justifyContent: 'center',
91-
alignItems: 'center',
92-
flex: 'none', // as a flex child
93-
cursor: 'pointer',
94-
fontFamily: 'Inter, sans-serif',
95-
paddingY: 0,
96-
paddingX: 2,
97-
height: '26px', // match with inputs
98-
width: '100%',
99-
fontSize: 2,
100-
fontWeight: 'medium',
101-
lineHeight: 1, // trust the height
102-
border: 'none',
103-
borderRadius: 'small',
104-
transition: 'all ease-in',
105-
transitionDuration: theme => theme.speeds[2],
75+
}
10676

107-
':focus': {
108-
outline: 'none',
109-
},
110-
':active': {
111-
transform: 'scale(0.98)',
112-
},
113-
':disabled': {
114-
opacity: '0.4',
115-
cursor: 'not-allowed',
116-
},
117-
...props.css,
118-
}
77+
export const Button = styled(Element).attrs({ as: 'button' })<IButtonProps>(
78+
({ variant = 'primary', ...props }) =>
79+
css(
80+
deepmerge(
81+
// @ts-ignore deepmerge allows functions as values
82+
// it overrides instead of merging, which is what we want
83+
// but it's types don't like it. so we're going to ignore that
84+
// TODO: raise a pull request for deepmerge or pick a different
85+
// library to deep merge objects
86+
variantStyles[variant],
87+
// static styles:
88+
{
89+
display: 'inline-flex',
90+
justifyContent: 'center',
91+
alignItems: 'center',
92+
flex: 'none', // as a flex child
93+
cursor: 'pointer',
94+
fontFamily: 'Inter, sans-serif',
95+
paddingY: 0,
96+
paddingX: 2,
97+
height: '26px', // match with inputs
98+
width: '100%',
99+
fontSize: 2,
100+
fontWeight: 'medium',
101+
lineHeight: 1, // trust the height
102+
border: 'none',
103+
borderRadius: 'small',
104+
transition: 'all ease-in',
105+
transitionDuration: theme => theme.speeds[2],
106+
107+
':focus': {
108+
outline: 'none',
109+
},
110+
':active': {
111+
transform: 'scale(0.98)',
112+
},
113+
':disabled': {
114+
opacity: '0.4',
115+
cursor: 'not-allowed',
116+
},
117+
...props.css,
118+
}
119+
)
119120
)
120-
)
121121
);
122122

123123
Button.defaultProps = {

packages/components/src/components/Input/index.tsx

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,9 @@ const placeholderStyles = {
77
fontSize: 3,
88
};
99

10-
export const Input = styled(Element).attrs({ as: 'input' })<{
11-
type?: string;
12-
onBlur?: any;
13-
onChange?: any;
14-
onKeyUp?: any;
15-
placeholder?: string;
16-
ref?: any;
17-
required?: boolean;
18-
value?: string | number;
19-
defaultValue?: string | number;
20-
autoComplete?: 'on' | 'off';
21-
spellCheck?: 'true' | 'false';
22-
autoFocus?: boolean;
23-
}>(
10+
interface IInputProps extends React.InputHTMLAttributes<HTMLInputElement> {}
11+
12+
export const Input = styled(Element).attrs({ as: 'input' })<IInputProps>(
2413
css({
2514
height: '26px',
2615
width: '100%',
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import styled from 'styled-components';
22
import css from '@styled-system/css';
3-
import { Text } from '../Text';
3+
import { Text, ITextProps } from '../Text';
44

5-
export const Label = styled(Text).attrs({ as: 'label' })<{ htmlFor: string }>(
6-
css({})
7-
);
5+
type LabelProps = React.LabelHTMLAttributes<HTMLLabelElement> & ITextProps & {};
6+
7+
export const Label = styled(Text).attrs({ as: 'label' })<LabelProps>(css({}));

packages/components/src/components/Label/label.stories.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ export default {
66
component: Label,
77
};
88

9-
export const Basic = () => <Label>Plan old boring text</Label>;
9+
export const Basic = () => (
10+
<Label htmlFor="input-element">Plan old boring text</Label>
11+
);
1012

1113
export const Block = () => (
1214
<Label block marginX={2}>

packages/components/src/components/Link/index.tsx

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,12 @@ import styled from 'styled-components';
33
import css from '@styled-system/css';
44
import { Text } from '../Text';
55

6-
interface ILinkProps {
7-
href: string;
8-
target?: string;
9-
rel?: string;
10-
variant?: 'body' | 'muted' | 'danger'; // from Text
11-
}
6+
type LinkProps = React.AnchorHTMLAttributes<HTMLAnchorElement> &
7+
React.AnchorHTMLAttributes<HTMLSpanElement> & {
8+
variant?: 'body' | 'muted' | 'danger'; // same as Text
9+
};
1210

13-
const LinkElement = styled(Text).attrs({ as: 'a' })<ILinkProps>(
11+
const LinkElement = styled(Text).attrs({ as: 'a' })<LinkProps>(
1412
css({
1513
cursor: 'pointer',
1614
textDecoration: 'none',
@@ -22,7 +20,7 @@ const LinkElement = styled(Text).attrs({ as: 'a' })<ILinkProps>(
2220
})
2321
);
2422

25-
export const Link: React.FC<ILinkProps> = props => (
23+
export const Link: React.FC<LinkProps> = props => (
2624
<LinkElement
2725
rel={props.target === '_blank' ? 'noopener noreferrer' : null}
2826
{...props}

packages/components/src/components/Select/index.tsx

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -102,22 +102,18 @@ const SelectWithIcon = styled(Element)<{
102102
})
103103
);
104104

105-
interface ISelectProps {
106-
icon?: any;
107-
placeholder?: string;
108-
children?: any;
109-
disabled?: boolean;
110-
onChange?: any;
111-
value?: string | number;
112-
defaultValue?: string | number;
113-
variant?: string;
114-
}
105+
type SelectProps = React.SelectHTMLAttributes<HTMLSelectElement> &
106+
React.SelectHTMLAttributes<HTMLInputElement> & {
107+
icon?: any;
108+
placeholder?: string;
109+
variant?: 'default' | 'link';
110+
};
115111

116112
export const Select = ({
117113
icon = null,
118114
placeholder = null,
119115
...props
120-
}: ISelectProps) => {
116+
}: SelectProps) => {
121117
const PrefixIcon = icon;
122118

123119
if (icon)

packages/components/src/components/Tags/Tag.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export function Tag({ tag, onRemove }: TagProps) {
3434
<Button
3535
variant="link"
3636
css={{ width: 'auto' }}
37-
onClick={onRemove}
37+
onClick={() => onRemove(tag)}
3838
marginLeft={1}
3939
>
4040
<CrossIcon />

packages/components/src/components/Text/index.tsx

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,24 @@ const overflowStyles = {
1414
whiteSpace: 'nowrap',
1515
};
1616

17-
export const Text = styled(Element).attrs({ as: 'span' })<{
17+
export interface ITextProps extends React.HTMLAttributes<HTMLSpanElement> {
1818
size?: number;
1919
align?: string;
2020
weight?: string;
2121
block?: boolean;
22-
variant?: 'body' | 'muted' | 'danger';
2322
maxWidth?: number | string;
24-
}>(({ size, align, weight, block, variant = 'body', maxWidth, ...props }) =>
25-
css({
26-
fontSize: size || 'inherit', // from theme.fontSizes
27-
textAlign: align || 'left',
28-
fontWeight: weight || null, // from theme.fontWeights
29-
display: block ? 'block' : 'inline',
30-
color: variants[variant],
31-
maxWidth,
32-
...(maxWidth ? overflowStyles : {}),
33-
})
23+
variant?: 'body' | 'muted' | 'danger';
24+
}
25+
26+
export const Text = styled(Element).attrs({ as: 'span' })<ITextProps>(
27+
({ size, align, weight, block, variant = 'body', maxWidth, ...props }) =>
28+
css({
29+
fontSize: size || 'inherit', // from theme.fontSizes
30+
textAlign: align || 'left',
31+
fontWeight: weight || null, // from theme.fontWeights
32+
display: block ? 'block' : 'inline',
33+
color: variants[variant],
34+
maxWidth,
35+
...(maxWidth ? overflowStyles : {}),
36+
})
3437
);

packages/components/src/components/Textarea/index.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ interface ITextareaProps
77
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
88
maxLength?: number;
99
autosize?: boolean;
10-
ref?: any;
1110
value?: string;
1211
}
1312

0 commit comments

Comments
 (0)