Skip to content

Commit f879c94

Browse files
authored
feat: update inputs to work with react-hook-form (#31)
* fix: checkbox label alignments * feat: add demo for custom labels in checkbox * fix: input with forward ref * fix: checkbox to work with react-hook-form
1 parent 815a3b2 commit f879c94

File tree

3 files changed

+149
-132
lines changed

3 files changed

+149
-132
lines changed

src/components/Checkbox/Checkbox.stories.tsx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { ComponentProps } from 'react';
22
import { Story } from '@storybook/react';
33

4+
import { Text } from '../Text';
45
import { Checkbox } from './Checkbox';
56

67
export default {
@@ -9,10 +10,22 @@ export default {
910
};
1011

1112
const Template: Story<ComponentProps<typeof Checkbox>> = (props: any) => (
12-
<Checkbox {...props} />
13+
<>
14+
<Checkbox {...props} />
15+
<Checkbox
16+
{...props}
17+
label={
18+
<Text as="span" variant="b1m" margin="0 0 0 xs">
19+
Custom label component
20+
</Text>
21+
}
22+
margin="s 0 0"
23+
/>
24+
</>
1325
);
1426

1527
export const Basic = Template.bind({});
28+
1629
Basic.args = {
1730
name: 'chkbox1',
1831
label: 'Checkbox label',

src/components/Checkbox/Checkbox.tsx

Lines changed: 57 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { FC, Fragment } from 'react';
1+
import { ChangeEventHandler, forwardRef, Fragment } from 'react';
22
import styled from 'styled-components';
33
import { Flex } from '../Flex';
44
import { getMargin, visuallyHidden } from '../../theme/utils';
@@ -10,7 +10,7 @@ export type CheckboxVariant = 'basic';
1010
export type CheckboxProps = {
1111
variant: CheckboxVariant;
1212
margin?: string;
13-
onChange?: (e: boolean) => void;
13+
onChange?: ChangeEventHandler<HTMLInputElement>;
1414
defaultChecked?: boolean;
1515
checked?: boolean;
1616
name?: string;
@@ -111,65 +111,61 @@ const LabelComponent = styled.label<{ variant: string; margin?: string }>(
111111

112112
const Label = styled(Flex)<any>(({ theme }) => ({
113113
...(theme.CHECKBOX['labelMargin'] || {}),
114+
paddingTop: '1px',
114115
}));
115116

116-
export const Checkbox: FC<CheckboxProps> = ({
117-
variant,
118-
margin,
119-
name,
120-
defaultChecked,
121-
checked,
122-
onChange,
123-
label,
124-
indeterminate,
125-
...props
126-
}) => {
127-
const checkedProps =
128-
typeof checked !== 'undefined' ? { checked } : { defaultChecked };
129-
130-
const handleChange = (e: any) => {
131-
if (onChange) {
132-
onChange(e.currentTarget.checked);
133-
}
134-
};
135-
136-
return (
137-
<LabelComponent variant={variant} margin={margin}>
138-
<Flex variant="raw">
139-
<Input
140-
{...props}
141-
{...checkedProps}
142-
type="checkbox"
143-
id={name}
144-
name={name}
145-
onChange={handleChange}
146-
/>
147-
<CheckboxInput
148-
{...(indeterminate ? { className: 'indeterminate' } : {})}
149-
>
150-
<MinusBoxIcon
151-
variant="basic"
152-
size="1.5em"
153-
icon={polyIcons.MinusBox}
154-
className="minusIcon"
117+
export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
118+
function ForwardRefCheckbox(checkboxProps, ref) {
119+
const {
120+
variant,
121+
margin,
122+
defaultChecked,
123+
checked,
124+
label,
125+
indeterminate,
126+
name,
127+
...props
128+
} = checkboxProps;
129+
130+
const checkedProps =
131+
typeof checked !== 'undefined' ? { checked } : { defaultChecked };
132+
133+
return (
134+
<LabelComponent variant={variant} margin={margin}>
135+
<Flex variant="raw" align="center">
136+
<Input
137+
{...props}
138+
{...checkedProps}
139+
ref={ref}
140+
id={name}
141+
name={name}
142+
type="checkbox"
155143
/>
156-
<CheckStateIcon
157-
variant="basic"
158-
size="1.5em"
159-
icon={polyIcons.CheckboxMarked}
160-
className="checkIcon"
161-
/>
162-
</CheckboxInput>
163-
<Fragment key={`${name}Label`}>
164-
{typeof label === 'string' ? (
165-
<Label variant="raw">
166-
<label htmlFor={name}>{label}</label>
167-
</Label>
168-
) : (
169-
label
170-
)}
171-
</Fragment>
172-
</Flex>
173-
</LabelComponent>
174-
);
175-
};
144+
<CheckboxInput
145+
{...(indeterminate ? { className: 'indeterminate' } : {})}
146+
>
147+
<MinusBoxIcon
148+
variant="basic"
149+
size="1.5em"
150+
icon={polyIcons.MinusBox}
151+
className="minusIcon"
152+
/>
153+
<CheckStateIcon
154+
variant="basic"
155+
size="1.5em"
156+
icon={polyIcons.CheckboxMarked}
157+
className="checkIcon"
158+
/>
159+
</CheckboxInput>
160+
<Fragment key={`${name}Label`}>
161+
{typeof label === 'string' ? (
162+
<Label variant="raw">{label}</Label>
163+
) : (
164+
label
165+
)}
166+
</Fragment>
167+
</Flex>
168+
</LabelComponent>
169+
);
170+
},
171+
);

src/components/Input/Input.tsx

Lines changed: 78 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { FC, WheelEvent, ComponentType } from 'react';
1+
import { WheelEvent, ComponentType, forwardRef } from 'react';
22
import styled from 'styled-components';
33
import NumberInput from 'react-number-format';
44

@@ -61,7 +61,7 @@ const InputWrapper = styled(Grid)<InputWrapperProps>(
6161
}),
6262
);
6363

64-
const Component = styled.input(({ theme, readOnly }) => ({
64+
const InputComponent = styled.input(({ theme, readOnly }) => ({
6565
...(theme.INPUT || {}),
6666
margin: 0,
6767
padding: 0,
@@ -81,75 +81,83 @@ const Unit = styled.div(({ theme }) => ({
8181
color: theme.COLOR.gray3,
8282
}));
8383

84-
export const Input: FC<InputProps> = ({
85-
variant,
86-
margin,
87-
type,
88-
label,
89-
tooltip,
90-
icon,
91-
unit,
92-
error,
93-
isDivisible = true,
94-
disabled,
95-
readOnly,
96-
...props
97-
}) => {
98-
const isBasic = variant === 'basic';
99-
const isAmount = variant === 'amount';
84+
export const Input = forwardRef<HTMLInputElement, InputProps>(
85+
function ForwardRefInput(inputProps, ref) {
86+
const {
87+
variant,
88+
margin,
89+
type,
90+
label,
91+
tooltip,
92+
icon,
93+
unit,
94+
error,
95+
isDivisible = true,
96+
disabled,
97+
readOnly,
98+
...props
99+
} = inputProps;
100100

101-
const componentProps = {
102-
...props,
103-
disabled,
104-
readOnly,
105-
...(isBasic ? { type } : {}),
106-
...(isAmount
107-
? {
108-
thousandSeparator: true,
109-
allowNegative: false,
110-
decimalScale: isDivisible ? 6 : 0,
111-
onWheel: (e: WheelEvent<HTMLInputElement>) => {
112-
e.currentTarget.blur();
113-
},
114-
}
115-
: {}),
116-
};
101+
const isBasic = variant === 'basic';
102+
const isAmount = variant === 'amount';
117103

118-
return (
119-
<Text as="label" variant="b2m" display="block" margin={margin}>
120-
{label && tooltip && (
121-
<Flex variant="raw" justify={tooltip ? 'spaced' : 'start'}>
122-
<Text as="span" variant="b2m" color={disabled ? 'gray4' : 'gray1'}>
123-
{label}
124-
</Text>
125-
{tooltip && <Tooltip variant="icon" content={tooltip} />}
126-
</Flex>
127-
)}
128-
<InputWrapper
129-
variant="raw"
130-
align="center"
131-
cols={`${icon ? 'auto ' : ''}1fr${unit ? ' auto' : ''}`}
132-
error={error}
133-
disabled={disabled}
134-
readOnly={readOnly}
135-
>
136-
{icon && (
137-
<Icon
138-
icon={icon}
139-
variant="basic"
140-
size="24px"
141-
color="gray3"
142-
margin="0 s 0 0"
104+
const componentProps = {
105+
...props,
106+
disabled,
107+
readOnly,
108+
...(isBasic ? { type } : {}),
109+
...(isAmount
110+
? {
111+
thousandSeparator: true,
112+
allowNegative: false,
113+
decimalScale: isDivisible ? 6 : 0,
114+
onWheel: (e: WheelEvent<HTMLInputElement>) => {
115+
e.currentTarget.blur();
116+
},
117+
}
118+
: {}),
119+
};
120+
121+
return (
122+
<Text as="label" variant="b2m" display="block" margin={margin}>
123+
{label && tooltip && (
124+
<Flex variant="raw" justify={tooltip ? 'spaced' : 'start'}>
125+
<Text as="span" variant="b2m" color={disabled ? 'gray4' : 'gray1'}>
126+
{label}
127+
</Text>
128+
{tooltip && <Tooltip variant="icon" content={tooltip} />}
129+
</Flex>
130+
)}
131+
<InputWrapper
132+
variant="raw"
133+
align="center"
134+
cols={`${icon ? 'auto ' : ''}1fr${unit ? ' auto' : ''}`}
135+
error={error}
136+
disabled={disabled}
137+
readOnly={readOnly}
138+
>
139+
{icon && (
140+
<Icon
141+
icon={icon}
142+
variant="basic"
143+
size="24px"
144+
color="gray3"
145+
margin="0 s 0 0"
146+
/>
147+
)}
148+
<InputComponent
149+
ref={ref}
150+
as={isAmount ? NumberInput : 'input'}
151+
{...componentProps}
143152
/>
153+
{unit && <Unit>{unit}</Unit>}
154+
</InputWrapper>
155+
{error && (
156+
<Text as="span" variant="b3" color="danger">
157+
{error}
158+
</Text>
144159
)}
145-
<Component as={isAmount ? NumberInput : 'input'} {...componentProps} />
146-
{unit && <Unit>{unit}</Unit>}
147-
</InputWrapper>
148-
{error && (
149-
<Text as="span" variant="b3" color="danger">
150-
{error}
151-
</Text>
152-
)}
153-
</Text>
154-
);
155-
};
160+
</Text>
161+
);
162+
},
163+
);

0 commit comments

Comments
 (0)