Skip to content

Commit d5887d4

Browse files
WesSouzaarturbien
authored andcommitted
feat(colorinput): convert to TypeScript and export types
1 parent 2616fe5 commit d5887d4

File tree

4 files changed

+82
-82
lines changed

4 files changed

+82
-82
lines changed

src/ColorInput/ColorInput.spec.js renamed to src/ColorInput/ColorInput.spec.tsx

+6-7
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,29 @@
1-
import React from 'react';
21
import { fireEvent } from '@testing-library/react';
32
import { renderWithTheme } from '../../test/utils';
4-
import ColorInput from './ColorInput';
3+
import { ColorInput } from './ColorInput';
54

6-
function rgb2hex(str) {
5+
function rgb2hex(str: string) {
76
const rgb = str.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
8-
function hex(x) {
7+
function hex(x: string) {
98
return `0${parseInt(x, 10).toString(16)}`.slice(-2);
109
}
11-
return `#${hex(rgb[1])}${hex(rgb[2])}${hex(rgb[3])}`;
10+
return rgb ? `#${hex(rgb[1])}${hex(rgb[2])}${hex(rgb[3])}` : '';
1211
}
1312

1413
describe('<ColorInput />', () => {
1514
it('should call handlers', () => {
1615
const color = '#f0f0dd';
1716
const onChange = jest.fn();
1817
const { container } = renderWithTheme(<ColorInput onChange={onChange} />);
19-
const input = container.querySelector(`[type="color"]`);
18+
const input = container.querySelector(`[type="color"]`) as HTMLInputElement;
2019
fireEvent.change(input, { target: { value: color } });
2120
expect(onChange).toBeCalledTimes(1);
2221
});
2322

2423
it('should properly pass value to input element', () => {
2524
const color = '#f0f0dd';
2625
const { container } = renderWithTheme(<ColorInput value={color} />);
27-
const input = container.querySelector(`[type="color"]`);
26+
const input = container.querySelector(`[type="color"]`) as HTMLInputElement;
2827

2928
expect(input.value).toBe(color);
3029
});

src/ColorInput/ColorInput.stories.js renamed to src/ColorInput/ColorInput.stories.tsx

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
import React from 'react';
2-
1+
import { ComponentMeta } from '@storybook/react';
32
import styled from 'styled-components';
43

5-
import { ColorInput, Cutout } from '..';
4+
import { ColorInput, Cutout } from 'react95';
65

76
const Wrapper = styled.div`
87
background: ${({ theme }) => theme.material};
@@ -31,7 +30,7 @@ export default {
3130
title: 'ColorInput',
3231
component: ColorInput,
3332
decorators: [story => <Wrapper>{story()}</Wrapper>]
34-
};
33+
} as ComponentMeta<typeof ColorInput>;
3534

3635
export function Default() {
3736
return (
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
1-
import React from 'react';
2-
import propTypes from 'prop-types';
3-
1+
import React, { forwardRef } from 'react';
42
import styled, { css } from 'styled-components';
5-
import useControlledOrUncontrolled from '../common/hooks/useControlledOrUncontrolled';
6-
import { focusOutline } from '../common';
73
import { StyledButton } from '../Button/Button';
4+
import { focusOutline } from '../common';
5+
import useControlledOrUncontrolled from '../common/hooks/useControlledOrUncontrolled';
6+
import { noOp } from '../common/utils';
87
import { Divider } from '../Divider/Divider';
8+
import { CommonStyledProps } from '../types';
9+
10+
type ColorInputProps = {
11+
value?: string;
12+
defaultValue?: string;
13+
onChange?: React.ChangeEventHandler<HTMLInputElement>;
14+
disabled?: boolean;
15+
variant?: 'default' | 'flat';
16+
} & React.InputHTMLAttributes<HTMLInputElement> &
17+
CommonStyledProps;
918

1019
const Trigger = styled(StyledButton)`
1120
padding-left: 8px;
@@ -33,7 +42,10 @@ export const StyledColorInput = styled.input`
3342
`;
3443

3544
// TODO replace with SVG icon
36-
const ColorPreview = styled.div`
45+
const ColorPreview = styled.div<{
46+
color: string;
47+
$disabled: boolean;
48+
}>`
3749
box-sizing: border-box;
3850
height: 19px;
3951
display: inline-block;
@@ -42,8 +54,8 @@ const ColorPreview = styled.div`
4254
4355
background: ${({ color }) => color};
4456
45-
${({ isDisabled }) =>
46-
isDisabled
57+
${({ $disabled }) =>
58+
$disabled
4759
? css`
4860
border: 2px solid ${({ theme }) => theme.materialTextDisabled};
4961
filter: drop-shadow(
@@ -65,16 +77,20 @@ const ColorPreview = styled.div`
6577
}
6678
`;
6779

68-
const ChevronIcon = styled.span`
80+
const ChevronIcon = styled.span<
81+
Required<Pick<ColorInputProps, 'variant'>> & {
82+
$disabled: boolean;
83+
}
84+
>`
6985
width: 0px;
7086
height: 0px;
7187
border-left: 6px solid transparent;
7288
border-right: 6px solid transparent;
7389
display: inline-block;
7490
margin-left: 6px;
7591
76-
${({ isDisabled }) =>
77-
isDisabled
92+
${({ $disabled }) =>
93+
$disabled
7894
? css`
7995
border-top: 6px solid ${({ theme }) => theme.materialTextDisabled};
8096
filter: drop-shadow(
@@ -96,66 +112,52 @@ const ChevronIcon = styled.span`
96112
`;
97113

98114
// TODO make sure all aria and role attributes are in place
99-
const ColorInput = React.forwardRef(function ColorInput(props, ref) {
100-
const { value, defaultValue, onChange, disabled, variant, ...otherProps } =
101-
props;
102-
103-
const [valueDerived, setValueState] = useControlledOrUncontrolled({
104-
value,
105-
defaultValue
106-
});
115+
const ColorInput = forwardRef<HTMLInputElement, ColorInputProps>(
116+
function ColorInput(
117+
{
118+
value,
119+
defaultValue,
120+
onChange = noOp,
121+
disabled = false,
122+
variant = 'default',
123+
...otherProps
124+
},
125+
ref
126+
) {
127+
const [valueDerived, setValueState] = useControlledOrUncontrolled({
128+
value,
129+
defaultValue
130+
});
107131

108-
const handleChange = e => {
109-
const color = e.target.value;
110-
setValueState(color);
111-
if (onChange) {
132+
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
133+
const color = e.target.value;
134+
setValueState(color);
112135
onChange(e);
113-
}
114-
};
136+
};
115137

116-
return (
117-
// we only need button styles, so we display
118-
// it as a div and reset type attribute
119-
<Trigger
120-
isDisabled={disabled}
121-
as='div'
122-
type={null}
123-
variant={variant}
124-
size='md'
125-
>
126-
<StyledColorInput
127-
onChange={handleChange}
128-
readOnly={disabled}
129-
disabled={disabled}
130-
value={valueDerived || '#008080'}
131-
type='color'
132-
ref={ref}
133-
{...otherProps}
134-
/>
135-
<ColorPreview
136-
color={valueDerived}
137-
isDisabled={disabled}
138-
role='presentation'
139-
/>
140-
{variant === 'default' && <StyledDivider orientation='vertical' />}
141-
<ChevronIcon isDisabled={disabled} variant={variant} />
142-
</Trigger>
143-
);
144-
});
145-
146-
ColorInput.defaultProps = {
147-
value: undefined,
148-
defaultValue: undefined,
149-
disabled: false,
150-
variant: 'default',
151-
onChange: () => {}
152-
};
138+
return (
139+
// we only need button styles, so we display
140+
// it as a div and reset type attribute
141+
<Trigger disabled={disabled} as='div' variant={variant} size='md'>
142+
<StyledColorInput
143+
onChange={handleChange}
144+
readOnly={disabled}
145+
disabled={disabled}
146+
value={valueDerived || '#008080'}
147+
type='color'
148+
ref={ref}
149+
{...otherProps}
150+
/>
151+
<ColorPreview
152+
$disabled={disabled}
153+
color={valueDerived}
154+
role='presentation'
155+
/>
156+
{variant === 'default' && <StyledDivider orientation='vertical' />}
157+
<ChevronIcon $disabled={disabled} variant={variant} />
158+
</Trigger>
159+
);
160+
}
161+
);
153162

154-
ColorInput.propTypes = {
155-
value: propTypes.string,
156-
defaultValue: propTypes.string,
157-
onChange: propTypes.func,
158-
disabled: propTypes.bool,
159-
variant: propTypes.oneOf(['default', 'flat'])
160-
};
161-
export default ColorInput;
163+
export { ColorInput, ColorInputProps };

src/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export * from './Avatar/Avatar';
99
export * from './Bar/Bar';
1010
export * from './Button/Button';
1111
export * from './Checkbox/Checkbox';
12-
export { default as ColorInput } from './ColorInput/ColorInput';
12+
export * from './ColorInput/ColorInput';
1313
export * from './Counter/Counter';
1414
export * from './Cutout/Cutout';
1515
export * from './Desktop/Desktop';

0 commit comments

Comments
 (0)