Skip to content

Commit

Permalink
refactor: TET-224 text input (#60)
Browse files Browse the repository at this point in the history
* refactor: TET-224 text input

* refactor: TET-224 text input

* refactor: TET-224 text input
  • Loading branch information
kudyniuk authored Sep 12, 2023
1 parent 5b97834 commit b0c6af6
Show file tree
Hide file tree
Showing 10 changed files with 142 additions and 79 deletions.
2 changes: 1 addition & 1 deletion src/components/Badge/Badge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const Badge: FC<BadgeProps & MarginProps> = ({
}) => {
const hasLabel = !!label;
const styles = useMemo(
() => stylesBuilder(custom, intent, emphasis, hasLabel, appearance),
() => stylesBuilder(intent, emphasis, custom, hasLabel, appearance),
[custom, intent, emphasis, hasLabel, appearance],
);

Expand Down
5 changes: 2 additions & 3 deletions src/components/Badge/stylesBuilder/stylesBuilder.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { BadgeProps } from '../Badge.props';
import { defaultConfig } from '../Badge.styles';
import { BadgeConfig, defaultConfig } from '../Badge.styles';
import { BadgeAppearance } from '../BadgeAppearance.type';
import { BadgeEmphasis } from '../BadgeEmphasis.type';
import { BadgeIntent } from '../BadgeIntent.type';
Expand All @@ -14,9 +13,9 @@ type BadgeStylesBuilder = {
};

export const stylesBuilder = (
custom: BadgeProps['custom'],
intent: BadgeIntent,
emphasis: BadgeEmphasis,
custom?: BadgeConfig,
hasLabel?: boolean,
appearance?: BadgeAppearance,
): BadgeStylesBuilder => {
Expand Down
10 changes: 5 additions & 5 deletions src/components/InlineSearchInput/InlineSearchInput.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const defaultConfig: SearchInputProps['custom'] = {
ringColor: {
_: 'unset',
},
innerComponents: {
innerElements: {
input: {
w: 'unset',
h: 'unset',
Expand All @@ -22,11 +22,11 @@ export const defaultConfig: SearchInputProps['custom'] = {
padding: 'unset',
display: 'inline-block',
},
},
spacing: {
beforeComponent: {
Icon: {
marginLeft: 'component-padding-small',
spacing: {
Icon: {
marginLeft: 'component-padding-small',
},
},
},
},
Expand Down
3 changes: 1 addition & 2 deletions src/components/TextInput/TextInput.props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { IconButtonProps } from '../IconButton/IconButton.props';

import type { BasicInputState } from '@/types';
import { InnerComponent } from '@/types/InnerComponent';
import { DeepPartial } from '@/utility-types/DeepPartial';

export namespace TextInputProps.InnerComponents {
export type Icon = InnerComponent<'Icon', IconProps>;
Expand Down Expand Up @@ -42,7 +41,7 @@ export type TextInputProps = {
| TextInputProps.InnerComponents.Dropdown;
state?: BasicInputState;
hasClearButton?: boolean;
custom?: DeepPartial<TextInputConfig>;
custom?: TextInputConfig;
} & Omit<
InputHTMLAttributes<HTMLInputElement>,
'checked' | 'disabled' | 'color' | 'type'
Expand Down
2 changes: 1 addition & 1 deletion src/components/TextInput/TextInput.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { Meta, StoryObj } from '@storybook/react';
import { TextInput } from './TextInput';

const meta = {
title: 'Components/Text Input',
title: 'Components/TextInput',
component: TextInput,
tags: ['autodocs'],
args: {
Expand Down
92 changes: 50 additions & 42 deletions src/components/TextInput/TextInput.style.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
import { BaseProps } from '@/types/BaseProps';

export type TextInputConfig = {
innerComponents: Record<'input' | 'icon' | 'text' | 'clearButton', BaseProps>;
spacing:
| Record<
'beforeComponent',
innerElements?: {
input?: BaseProps;
icon?: BaseProps;
text?: BaseProps;
clearButton?: BaseProps;
beforeComponent?: {
spacing?: Partial<
Record<'Icon' | 'Avatar' | 'Prefix' | 'Dropdown', BaseProps>
>
| Record<
'afterComponent',
>;
} & BaseProps;
afterComponent?: {
spacing?: Partial<
Record<
'Icon' | 'Sufix' | 'Button' | 'IconButton' | 'Dropdown',
BaseProps
>
>;
} & BaseProps;
};
} & BaseProps;

export const defaultConfig = {
Expand Down Expand Up @@ -51,7 +57,7 @@ export const defaultConfig = {
pointerEvents: {
disabled: 'none',
},
innerComponents: {
innerElements: {
input: {
w: '100%',
h: '100%',
Expand All @@ -72,44 +78,46 @@ export const defaultConfig = {
clearButton: {
marginLeft: 'component-gap-small',
},
},
spacing: {
beforeComponent: {
Icon: {
marginLeft: 'component-padding-medium',
marginRight: 'component-padding-small',
},
Avatar: {
margin: '0 component-padding-small',
},
Prefix: {
margin: '0 component-padding-large',
},
Dropdown: {
marginLeft: 'component-padding-xSmall',
marginRight: 'component-padding-small',
spacing: {
Icon: {
marginLeft: 'component-padding-medium',
marginRight: 'component-padding-small',
},
Avatar: {
margin: '0 component-padding-small',
},
Prefix: {
margin: '0 component-padding-large',
},
Dropdown: {
marginLeft: 'component-padding-xSmall',
marginRight: 'component-padding-small',
},
},
},
afterComponent: {
Icon: {
marginLeft: 'component-padding-small',
marginRight: 'component-padding-large',
},
Sufix: {
marginLeft: 'component-padding-small',
marginRight: 'component-padding-large',
},
Button: {
marginLeft: 'component-padding-small',
marginRight: 'component-padding-xSmall',
},
IconButton: {
marginLeft: 'component-padding-small',
marginRight: 'component-padding-xSmall',
},
Dropdown: {
marginLeft: 'component-padding-small',
marginRight: 'component-padding-xSmall',
spacing: {
Icon: {
marginLeft: 'component-padding-small',
marginRight: 'component-padding-large',
},
Sufix: {
marginLeft: 'component-padding-small',
marginRight: 'component-padding-large',
},
Button: {
marginLeft: 'component-padding-small',
marginRight: 'component-padding-xSmall',
},
IconButton: {
marginLeft: 'component-padding-small',
marginRight: 'component-padding-xSmall',
},
Dropdown: {
marginLeft: 'component-padding-small',
marginRight: 'component-padding-xSmall',
},
},
},
},
Expand Down
6 changes: 6 additions & 0 deletions src/components/TextInput/TextInput.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { vi } from 'vitest';
import { TextInput } from './TextInput';
import { fireEvent, render } from '../../tests/render';

import { customPropTester } from '@/tests/customPropTester';

const handleEventMock = vi.fn();

const getTextInput = (jsx: JSX.Element) => {
Expand All @@ -20,6 +22,10 @@ describe('TextInput', () => {
handleEventMock.mockClear();
});

customPropTester(<TextInput />, {
containerId: 'text-input',
});

it('should render the text input', () => {
const { textInput } = getTextInput(<TextInput />);
expect(textInput).toBeInTheDocument();
Expand Down
43 changes: 18 additions & 25 deletions src/components/TextInput/TextInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import {
ChangeEventHandler,
MouseEventHandler,
ChangeEvent,
useMemo,
} from 'react';

import { stylesBuilder } from './stylesBuilder';
import { TextInputProps } from './TextInput.props';
import { defaultConfig } from './TextInput.style';
import { Button } from '../Button';
import { IconButton } from '../IconButton';

import { mergeConfigWithCustom } from '@/services';
import { extractMarginProps } from '@/services/extractMarginProps';
import { tet } from '@/tetrisly';
import { MarginProps } from '@/types/MarginProps';
Expand All @@ -38,21 +38,14 @@ export const TextInput = forwardRef<
inputRef,
) => {
const [innerValue, setInnerValue] = useState('');
const styles = useMemo(
() => stylesBuilder(custom, beforeComponent?.type, afterComponent?.type),
[afterComponent?.type, beforeComponent?.type, custom],
);
const [marginProps, inputProps] = extractMarginProps<
TextInputProps & MarginProps
>(rest);

const {
innerComponents: {
input: inputStyles,
icon: iconStyles,
text: textStyles,
clearButton: clearButtonStyles,
},
spacing,
...defaultStyles
} = mergeConfigWithCustom({ defaultConfig, custom });

const containerRef = useRef<HTMLInputElement | null>(null);

const handleContainerClick: MouseEventHandler = useCallback(
Expand Down Expand Up @@ -84,25 +77,25 @@ export const TextInput = forwardRef<
<tet.div
ref={containerRef}
onClick={handleContainerClick}
{...defaultStyles}
{...styles.container}
pl={!!beforeComponent && '0'}
pr={!!afterComponent && '0'}
{...marginProps}
data-state={state}
data-testid="text-input"
data-state={state}
{...marginProps}
>
{!!beforeComponent && (
<tet.span
{...spacing.beforeComponent[beforeComponent.type]}
{...styles.beforeComponent}
data-testid="text-input-before-component"
>
{beforeComponent.type === 'Icon' && (
<tet.span {...iconStyles}>
<tet.span {...styles.icon}>
<Icon {...beforeComponent.props} />
</tet.span>
)}
{beforeComponent.type === 'Prefix' && (
<tet.span {...textStyles}>{beforeComponent.props.text}</tet.span>
<tet.span {...styles.text}>{beforeComponent.props.text}</tet.span>
)}
{beforeComponent.type === 'Dropdown' && (
<Button
Expand All @@ -115,31 +108,31 @@ export const TextInput = forwardRef<
</tet.span>
)}
<tet.input
{...inputStyles}
{...styles.input}
value={value || innerValue}
onChange={handleOnChange}
data-testid="text-input-input"
{...inputProps}
type={type}
disabled={state === 'disabled'}
ref={inputRef}
data-testid="text-input-input"
/>
{!!hasClearButton && (value || innerValue) && (
<IconButton
variant="bare"
icon="20-close"
onClick={handleOnClear}
{...clearButtonStyles}
{...styles.clearButton}
data-testid="text-input-clear-button"
/>
)}
{!!afterComponent && (
<tet.span
{...spacing.afterComponent[afterComponent.type]}
{...styles.afterComponent}
data-testid="text-input-after-component"
>
{afterComponent.type === 'Icon' && (
<tet.span {...iconStyles}>
<tet.span {...styles.icon}>
<Icon {...afterComponent.props} />
</tet.span>
)}
Expand All @@ -151,7 +144,7 @@ export const TextInput = forwardRef<
/>
)}
{afterComponent.type === 'Sufix' && (
<tet.span {...textStyles}>{afterComponent.props.text}</tet.span>
<tet.span {...styles.text}>{afterComponent.props.text}</tet.span>
)}
{afterComponent.type === 'Button' && (
<Button size="small" variant="ghost" label="Label" />
Expand Down
1 change: 1 addition & 0 deletions src/components/TextInput/stylesBuilder/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { stylesBuilder } from './stylesBuilder';
Loading

0 comments on commit b0c6af6

Please sign in to comment.