Skip to content

Commit

Permalink
feat: update inputs to work with react-hook-form (#31)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
wahidrahim authored Feb 10, 2022
1 parent 815a3b2 commit f879c94
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 132 deletions.
15 changes: 14 additions & 1 deletion src/components/Checkbox/Checkbox.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ComponentProps } from 'react';
import { Story } from '@storybook/react';

import { Text } from '../Text';
import { Checkbox } from './Checkbox';

export default {
Expand All @@ -9,10 +10,22 @@ export default {
};

const Template: Story<ComponentProps<typeof Checkbox>> = (props: any) => (
<Checkbox {...props} />
<>
<Checkbox {...props} />
<Checkbox
{...props}
label={
<Text as="span" variant="b1m" margin="0 0 0 xs">
Custom label component
</Text>
}
margin="s 0 0"
/>
</>
);

export const Basic = Template.bind({});

Basic.args = {
name: 'chkbox1',
label: 'Checkbox label',
Expand Down
118 changes: 57 additions & 61 deletions src/components/Checkbox/Checkbox.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FC, Fragment } from 'react';
import { ChangeEventHandler, forwardRef, Fragment } from 'react';
import styled from 'styled-components';
import { Flex } from '../Flex';
import { getMargin, visuallyHidden } from '../../theme/utils';
Expand All @@ -10,7 +10,7 @@ export type CheckboxVariant = 'basic';
export type CheckboxProps = {
variant: CheckboxVariant;
margin?: string;
onChange?: (e: boolean) => void;
onChange?: ChangeEventHandler<HTMLInputElement>;
defaultChecked?: boolean;
checked?: boolean;
name?: string;
Expand Down Expand Up @@ -111,65 +111,61 @@ const LabelComponent = styled.label<{ variant: string; margin?: string }>(

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

export const Checkbox: FC<CheckboxProps> = ({
variant,
margin,
name,
defaultChecked,
checked,
onChange,
label,
indeterminate,
...props
}) => {
const checkedProps =
typeof checked !== 'undefined' ? { checked } : { defaultChecked };

const handleChange = (e: any) => {
if (onChange) {
onChange(e.currentTarget.checked);
}
};

return (
<LabelComponent variant={variant} margin={margin}>
<Flex variant="raw">
<Input
{...props}
{...checkedProps}
type="checkbox"
id={name}
name={name}
onChange={handleChange}
/>
<CheckboxInput
{...(indeterminate ? { className: 'indeterminate' } : {})}
>
<MinusBoxIcon
variant="basic"
size="1.5em"
icon={polyIcons.MinusBox}
className="minusIcon"
export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
function ForwardRefCheckbox(checkboxProps, ref) {
const {
variant,
margin,
defaultChecked,
checked,
label,
indeterminate,
name,
...props
} = checkboxProps;

const checkedProps =
typeof checked !== 'undefined' ? { checked } : { defaultChecked };

return (
<LabelComponent variant={variant} margin={margin}>
<Flex variant="raw" align="center">
<Input
{...props}
{...checkedProps}
ref={ref}
id={name}
name={name}
type="checkbox"
/>
<CheckStateIcon
variant="basic"
size="1.5em"
icon={polyIcons.CheckboxMarked}
className="checkIcon"
/>
</CheckboxInput>
<Fragment key={`${name}Label`}>
{typeof label === 'string' ? (
<Label variant="raw">
<label htmlFor={name}>{label}</label>
</Label>
) : (
label
)}
</Fragment>
</Flex>
</LabelComponent>
);
};
<CheckboxInput
{...(indeterminate ? { className: 'indeterminate' } : {})}
>
<MinusBoxIcon
variant="basic"
size="1.5em"
icon={polyIcons.MinusBox}
className="minusIcon"
/>
<CheckStateIcon
variant="basic"
size="1.5em"
icon={polyIcons.CheckboxMarked}
className="checkIcon"
/>
</CheckboxInput>
<Fragment key={`${name}Label`}>
{typeof label === 'string' ? (
<Label variant="raw">{label}</Label>
) : (
label
)}
</Fragment>
</Flex>
</LabelComponent>
);
},
);
148 changes: 78 additions & 70 deletions src/components/Input/Input.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FC, WheelEvent, ComponentType } from 'react';
import { WheelEvent, ComponentType, forwardRef } from 'react';
import styled from 'styled-components';
import NumberInput from 'react-number-format';

Expand Down Expand Up @@ -61,7 +61,7 @@ const InputWrapper = styled(Grid)<InputWrapperProps>(
}),
);

const Component = styled.input(({ theme, readOnly }) => ({
const InputComponent = styled.input(({ theme, readOnly }) => ({
...(theme.INPUT || {}),
margin: 0,
padding: 0,
Expand All @@ -81,75 +81,83 @@ const Unit = styled.div(({ theme }) => ({
color: theme.COLOR.gray3,
}));

export const Input: FC<InputProps> = ({
variant,
margin,
type,
label,
tooltip,
icon,
unit,
error,
isDivisible = true,
disabled,
readOnly,
...props
}) => {
const isBasic = variant === 'basic';
const isAmount = variant === 'amount';
export const Input = forwardRef<HTMLInputElement, InputProps>(
function ForwardRefInput(inputProps, ref) {
const {
variant,
margin,
type,
label,
tooltip,
icon,
unit,
error,
isDivisible = true,
disabled,
readOnly,
...props
} = inputProps;

const componentProps = {
...props,
disabled,
readOnly,
...(isBasic ? { type } : {}),
...(isAmount
? {
thousandSeparator: true,
allowNegative: false,
decimalScale: isDivisible ? 6 : 0,
onWheel: (e: WheelEvent<HTMLInputElement>) => {
e.currentTarget.blur();
},
}
: {}),
};
const isBasic = variant === 'basic';
const isAmount = variant === 'amount';

return (
<Text as="label" variant="b2m" display="block" margin={margin}>
{label && tooltip && (
<Flex variant="raw" justify={tooltip ? 'spaced' : 'start'}>
<Text as="span" variant="b2m" color={disabled ? 'gray4' : 'gray1'}>
{label}
</Text>
{tooltip && <Tooltip variant="icon" content={tooltip} />}
</Flex>
)}
<InputWrapper
variant="raw"
align="center"
cols={`${icon ? 'auto ' : ''}1fr${unit ? ' auto' : ''}`}
error={error}
disabled={disabled}
readOnly={readOnly}
>
{icon && (
<Icon
icon={icon}
variant="basic"
size="24px"
color="gray3"
margin="0 s 0 0"
const componentProps = {
...props,
disabled,
readOnly,
...(isBasic ? { type } : {}),
...(isAmount
? {
thousandSeparator: true,
allowNegative: false,
decimalScale: isDivisible ? 6 : 0,
onWheel: (e: WheelEvent<HTMLInputElement>) => {
e.currentTarget.blur();
},
}
: {}),
};

return (
<Text as="label" variant="b2m" display="block" margin={margin}>
{label && tooltip && (
<Flex variant="raw" justify={tooltip ? 'spaced' : 'start'}>
<Text as="span" variant="b2m" color={disabled ? 'gray4' : 'gray1'}>
{label}
</Text>
{tooltip && <Tooltip variant="icon" content={tooltip} />}
</Flex>
)}
<InputWrapper
variant="raw"
align="center"
cols={`${icon ? 'auto ' : ''}1fr${unit ? ' auto' : ''}`}
error={error}
disabled={disabled}
readOnly={readOnly}
>
{icon && (
<Icon
icon={icon}
variant="basic"
size="24px"
color="gray3"
margin="0 s 0 0"
/>
)}
<InputComponent
ref={ref}
as={isAmount ? NumberInput : 'input'}
{...componentProps}
/>
{unit && <Unit>{unit}</Unit>}
</InputWrapper>
{error && (
<Text as="span" variant="b3" color="danger">
{error}
</Text>
)}
<Component as={isAmount ? NumberInput : 'input'} {...componentProps} />
{unit && <Unit>{unit}</Unit>}
</InputWrapper>
{error && (
<Text as="span" variant="b3" color="danger">
{error}
</Text>
)}
</Text>
);
};
</Text>
);
},
);

0 comments on commit f879c94

Please sign in to comment.