Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/chatty-kids-jog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@alfalab/core-components-with-suffix': minor
'@alfalab/core-components': minor
---

##### withSuffix

- Обобщена типизация `withSuffix` для принятия как `Input`, так и `NumberInput` компонентов
2 changes: 1 addition & 1 deletion packages/amount-input/src/Component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ export const AmountInput = forwardRef<HTMLInputElement, AmountInputProps>(
onKeyDown?.(event);
};

const handleFocus: withSuffixProps['onFocus'] = (e) => {
const handleFocus: withSuffixProps<InputProps>['onFocus'] = (e) => {
setIsFocused(true);

onFocus?.(e);
Expand Down
1 change: 1 addition & 0 deletions packages/with-suffix/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"module": "./esm/index.js",
"dependencies": {
"@alfalab/core-components-input": "^16.0.3",
"@alfalab/core-components-number-input": "^3.0.4",
"@alfalab/core-components-portal": "^4.0.2",
"classnames": "^2.5.1",
"react-merge-refs": "^1.1.0",
Expand Down
21 changes: 21 additions & 0 deletions packages/with-suffix/src/Component.test.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import React from 'react';
import { render } from '@testing-library/react';
import { Input } from '@alfalab/core-components-input';
import { NumberInput } from '@alfalab/core-components-number-input';

import userEvent from '@testing-library/user-event';
import { withSuffix } from './index';

const SuffixInput = withSuffix(Input);
const NumberSuffixInput = withSuffix(NumberInput);

describe('withSuffix', () => {
Object.defineProperty(window, 'matchMedia', {
Expand Down Expand Up @@ -71,4 +73,23 @@ describe('withSuffix', () => {

expect(unmount).not.toThrow();
});

describe('NumberInput', () => {
it('should render suffix with NumberInput', async () => {
const suffix = ' мес';
const { container } = render(<NumberSuffixInput value={12} suffix={suffix} />);

await new Promise((resolve) => requestAnimationFrame(resolve));

expect(container.querySelector('.suffixVisible')).toBeInTheDocument();
});

it('should forward ref to html input with NumberInput', () => {
const inputRef = jest.fn();
const dataTestId = 'number-test-id';
render(<NumberSuffixInput ref={inputRef} dataTestId={dataTestId} />);

expect(inputRef.mock.calls[0][0].tagName).toBe('INPUT');
});
});
});
63 changes: 36 additions & 27 deletions packages/with-suffix/src/Component.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, {
type ChangeEvent,
type FC,
forwardRef,
Fragment,
Expand All @@ -11,12 +12,16 @@ import mergeRefs from 'react-merge-refs';
import cn from 'classnames';

import { type InputProps } from '@alfalab/core-components-input';
import { type NumberInputProps } from '@alfalab/core-components-number-input';
import { Portal } from '@alfalab/core-components-portal';

import styles from './index.module.css';

// eslint-disable-next-line @typescript-eslint/naming-convention
export type withSuffixProps = InputProps & {
type InputRef = RefAttributes<HTMLInputElement>;

type BaseInputProps = InputProps | NumberInputProps;

type SuffixExtraProps = {
/**
* Дополнительный закрепленный текст справа от основного значения.
* Например: value='85' suffix=' мес' -> 85 мес
Expand All @@ -29,8 +34,11 @@ export type withSuffixProps = InputProps & {
suffixContainerClassName?: string;
};

export const withSuffix = (Input: FC<InputProps & RefAttributes<HTMLInputElement>>) =>
forwardRef<HTMLInputElement, withSuffixProps>(
// eslint-disable-next-line @typescript-eslint/naming-convention
export type withSuffixProps<P extends BaseInputProps> = P & SuffixExtraProps;

export const withSuffix = <P extends BaseInputProps>(Input: FC<P & InputRef>) =>
forwardRef<HTMLInputElement, withSuffixProps<P>>(
(
{
value,
Expand All @@ -53,11 +61,12 @@ export const withSuffix = (Input: FC<InputProps & RefAttributes<HTMLInputElement

const [stateValue, setStateValue] = useState(defaultValue || '');

const handleInputChange = useCallback<Required<InputProps>['onChange']>(
(event, payload) => {
if (onChange) {
onChange(event, payload);
}
const handleInputChange = useCallback(
(
event: ChangeEvent<HTMLInputElement>,
payload: { value: string } & { value: number | null },
) => {
onChange?.(event, payload);

if (uncontrolled) {
setStateValue(payload.value);
Expand All @@ -66,15 +75,13 @@ export const withSuffix = (Input: FC<InputProps & RefAttributes<HTMLInputElement
[onChange, uncontrolled],
);

const handleClear = useCallback<Required<InputProps>['onClear']>(
const handleClear = useCallback<Required<BaseInputProps>['onClear']>(
(event) => {
if (uncontrolled) {
setStateValue('');
}

if (onClear) {
onClear(event);
}
onClear?.(event);
},
[onClear, uncontrolled],
);
Expand All @@ -89,22 +96,24 @@ export const withSuffix = (Input: FC<InputProps & RefAttributes<HTMLInputElement

const isInverted = restProps.colors === 'inverted';

const inputProps = {
ref: mergeRefs([ref, setInputNode]),
value: visibleValue,
disabled,
readOnly,
onChange: handleInputChange,
onClear: handleClear,
placeholder,
className: cn(className, {
[styles.suffixVisible]: Boolean(visibleValue),
[styles.hasSuffix]: suffix,
}),
...restProps,
} as unknown as P & InputRef;

return (
<Fragment>
<Input
ref={mergeRefs([ref, setInputNode])}
value={visibleValue}
disabled={disabled}
readOnly={readOnly}
onChange={handleInputChange}
onClear={handleClear}
placeholder={placeholder}
className={cn(className, {
[styles.suffixVisible]: Boolean(visibleValue),
[styles.hasSuffix]: suffix,
})}
{...restProps}
/>
<Input {...inputProps} />
<Portal getPortalContainer={getPortalContainer}>
<div
translate='no'
Expand Down
3 changes: 3 additions & 0 deletions packages/with-suffix/tsconfig.build.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
"paths": {
"@alfalab/core-components-input": ["../input/src"],
"@alfalab/core-components-input/*": ["../input/src/*"],
"@alfalab/core-components-number-input": ["../number-input/src"],
"@alfalab/core-components-number-input/*": ["../number-input/src/*"],
"@alfalab/core-components-portal": ["../portal/src"],
"@alfalab/core-components-portal/*": ["../portal/src/*"],
"@alfalab/core-components-with-suffix": ["./src"],
Expand All @@ -17,6 +19,7 @@
},
"references": [
{ "path": "../input/tsconfig.build.json" },
{ "path": "../number-input/tsconfig.build.json" },
{ "path": "../portal/tsconfig.build.json" }
]
}
3 changes: 3 additions & 0 deletions packages/with-suffix/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
"paths": {
"@alfalab/core-components-input": ["../input/src"],
"@alfalab/core-components-input/*": ["../input/src/*"],
"@alfalab/core-components-number-input": ["../number-input/src"],
"@alfalab/core-components-number-input/*": ["../number-input/src/*"],
"@alfalab/core-components-portal": ["../portal/src"],
"@alfalab/core-components-portal/*": ["../portal/src/*"],
"@alfalab/core-components-screenshot-utils": ["../screenshot-utils/src"],
Expand All @@ -20,6 +22,7 @@
},
"references": [
{ "path": "../input/tsconfig.build.json" },
{ "path": "../number-input/tsconfig.build.json" },
{ "path": "../portal/tsconfig.build.json" },
{ "path": "../screenshot-utils/tsconfig.build.json" },
{ "path": "../test-utils/tsconfig.build.json" }
Expand Down