diff --git a/src/components/Badge/Badge.tsx b/src/components/Badge/Badge.tsx index cdbf44f4..23367160 100644 --- a/src/components/Badge/Badge.tsx +++ b/src/components/Badge/Badge.tsx @@ -20,7 +20,7 @@ export const Badge: FC = ({ }) => { const hasLabel = !!label; const styles = useMemo( - () => stylesBuilder(custom, intent, emphasis, hasLabel, appearance), + () => stylesBuilder(intent, emphasis, custom, hasLabel, appearance), [custom, intent, emphasis, hasLabel, appearance], ); diff --git a/src/components/Badge/stylesBuilder/stylesBuilder.ts b/src/components/Badge/stylesBuilder/stylesBuilder.ts index 97179fbe..5733d58d 100644 --- a/src/components/Badge/stylesBuilder/stylesBuilder.ts +++ b/src/components/Badge/stylesBuilder/stylesBuilder.ts @@ -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'; @@ -14,9 +13,9 @@ type BadgeStylesBuilder = { }; export const stylesBuilder = ( - custom: BadgeProps['custom'], intent: BadgeIntent, emphasis: BadgeEmphasis, + custom?: BadgeConfig, hasLabel?: boolean, appearance?: BadgeAppearance, ): BadgeStylesBuilder => { diff --git a/src/components/InlineSearchInput/InlineSearchInput.styles.ts b/src/components/InlineSearchInput/InlineSearchInput.styles.ts index 4ac9b9af..35452804 100644 --- a/src/components/InlineSearchInput/InlineSearchInput.styles.ts +++ b/src/components/InlineSearchInput/InlineSearchInput.styles.ts @@ -13,7 +13,7 @@ export const defaultConfig: SearchInputProps['custom'] = { ringColor: { _: 'unset', }, - innerComponents: { + innerElements: { input: { w: 'unset', h: 'unset', @@ -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', + }, }, }, }, diff --git a/src/components/TextInput/TextInput.props.ts b/src/components/TextInput/TextInput.props.ts index 82281653..2c149e36 100644 --- a/src/components/TextInput/TextInput.props.ts +++ b/src/components/TextInput/TextInput.props.ts @@ -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>; @@ -42,7 +41,7 @@ export type TextInputProps = { | TextInputProps.InnerComponents.Dropdown; state?: BasicInputState; hasClearButton?: boolean; - custom?: DeepPartial; + custom?: TextInputConfig; } & Omit< InputHTMLAttributes, 'checked' | 'disabled' | 'color' | 'type' diff --git a/src/components/TextInput/TextInput.stories.tsx b/src/components/TextInput/TextInput.stories.tsx index aa742788..88c6d7ba 100644 --- a/src/components/TextInput/TextInput.stories.tsx +++ b/src/components/TextInput/TextInput.stories.tsx @@ -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: { diff --git a/src/components/TextInput/TextInput.style.ts b/src/components/TextInput/TextInput.style.ts index 64441460..297cd28b 100644 --- a/src/components/TextInput/TextInput.style.ts +++ b/src/components/TextInput/TextInput.style.ts @@ -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 = { @@ -51,7 +57,7 @@ export const defaultConfig = { pointerEvents: { disabled: 'none', }, - innerComponents: { + innerElements: { input: { w: '100%', h: '100%', @@ -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', + }, }, }, }, diff --git a/src/components/TextInput/TextInput.test.tsx b/src/components/TextInput/TextInput.test.tsx index 65e888f8..c8a1e7a3 100644 --- a/src/components/TextInput/TextInput.test.tsx +++ b/src/components/TextInput/TextInput.test.tsx @@ -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) => { @@ -20,6 +22,10 @@ describe('TextInput', () => { handleEventMock.mockClear(); }); + customPropTester(, { + containerId: 'text-input', + }); + it('should render the text input', () => { const { textInput } = getTextInput(); expect(textInput).toBeInTheDocument(); diff --git a/src/components/TextInput/TextInput.tsx b/src/components/TextInput/TextInput.tsx index 27704902..42d45dd0 100644 --- a/src/components/TextInput/TextInput.tsx +++ b/src/components/TextInput/TextInput.tsx @@ -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'; @@ -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(null); const handleContainerClick: MouseEventHandler = useCallback( @@ -84,25 +77,25 @@ export const TextInput = forwardRef< {!!beforeComponent && ( {beforeComponent.type === 'Icon' && ( - + )} {beforeComponent.type === 'Prefix' && ( - {beforeComponent.props.text} + {beforeComponent.props.text} )} {beforeComponent.type === 'Dropdown' && (