Shared:Components:TextInput: rewrite to typescript

This commit is contained in:
Timofey Boyko 2023-12-06 16:32:43 +03:00
parent d36d822fb2
commit 1e9cb7e35a
19 changed files with 486 additions and 430 deletions

View File

@ -36,6 +36,7 @@
"e2e.test:translation": "yarn workspaces foreach -vptiR --from '{@docspace/client,@docspace/login}' run test:translation:model"
},
"devDependencies": {
"@types/react-text-mask": "^5.4.14",
"he": "^1.2.0",
"madge": "^6.1.0",
"shx": "^0.3.4",

View File

@ -1,2 +0,0 @@
// @ts-expect-error TS(2304): Cannot find name 'from'.
export default from "./text-input";

View File

@ -1,48 +0,0 @@
import React from "react";
// @ts-expect-error TS(7016): Could not find a declaration file for module 'reac... Remove this comment to see the full error message
import MaskedInput from "react-text-mask";
/* eslint-disable no-unused-vars, react/prop-types */
const Input = ({
isAutoFocussed,
isDisabled,
isReadOnly,
hasError,
hasWarning,
scale,
withBorder,
keepCharPositions,
guide,
fontWeight,
isBold,
forwardedRef,
className,
theme,
dir = "auto",
...props
}: any) => {
const rest = {};
// @ts-expect-error TS(2339): Property 'autoFocus' does not exist on type '{}'.
if (isAutoFocussed) rest.autoFocus = true;
// @ts-expect-error TS(2339): Property 'ref' does not exist on type '{}'.
if (forwardedRef) rest.ref = forwardedRef;
return props.mask != null ? (
<MaskedInput
className={`${className} not-selectable`}
keepCharPositions={true}
guide={false}
{...props}
/>
) : (
<input
className={`${className} not-selectable`}
dir={dir}
{...props}
{...rest}
/>
);
};
export default Input;

View File

@ -1,138 +0,0 @@
import styled, { css } from "styled-components";
import commonInputStyles from "./common-input-styles";
import Input from "./input";
import Base from "../themes/base";
import NoUserSelect from "../utils/commonStyles";
/* eslint-enable react/prop-types, no-unused-vars */
const StyledTextInput = styled(Input).attrs((props) => ({
id: props.id,
forwardedRef: props.forwardedRef,
name: props.name,
type: props.type,
value: props.value,
placeholder: props.placeholder,
maxLength: props.maxLength,
onChange: props.onChange,
onBlur: props.onBlur,
onFocus: props.onFocus,
readOnly: props.isReadOnly,
autoFocus: props.isAutoFocussed,
autoComplete: props.autoComplete,
tabIndex: props.tabIndex,
disabled: props.isDisabled ? "disabled" : "",
}))`
${commonInputStyles}
-webkit-appearance: ${(props) => props.theme.textInput.appearance};
background-color:
${(props) => props.isDisabled ?
props.theme.input.disableBackgroundColor
: props.theme.input.backgroundColor};
-webkit-text-fill-color: ${(props) => props.isDisabled ? props.theme.input.disableColor :
props?.value?.length > 0
? props.theme.text.color
: props.theme.textInput.placeholderColor} !important;
caret-color: ${(props) => props.isDisabled ? props.theme.input.disableColor : props.theme.text.color};
-webkit-background-clip: text !important;
box-shadow: inset 0 0 20px 20px
${(props) => props.isDisabled ?
props.theme.input.disableBackgroundColor
: props.theme.input.backgroundColor} !important;
display: ${(props) => props.theme.textInput.display};
font-family: ${(props) => props.theme.fontFamily};
line-height: ${(props) =>
(props.size === "base" && props.theme.textInput.lineHeight.base) ||
(props.size === "middle" && props.theme.textInput.lineHeight.middle) ||
(props.size === "big" && props.theme.textInput.lineHeight.big) ||
(props.size === "huge" && props.theme.textInput.lineHeight.huge) ||
(props.size === "large" && props.theme.textInput.lineHeight.large)};
font-size: ${(props) =>
props.theme.getCorrectFontSize(
(props.size === "base" && props.theme.textInput.fontSize.base) ||
(props.size === "middle" && props.theme.textInput.fontSize.middle) ||
(props.size === "big" && props.theme.textInput.fontSize.big) ||
(props.size === "huge" && props.theme.textInput.fontSize.huge) ||
(props.size === "large" && props.theme.textInput.fontSize.large)
)};
font-weight: ${(props) =>
props.fontWeight
? props.fontWeight
: props.isBold
? 600
: props.theme.textInput.fontWeight};
flex: ${(props) => props.theme.textInput.flex};
outline: ${(props) => props.theme.textInput.outline};
overflow: ${(props) => props.theme.textInput.overflow};
opacity: ${(props) => props.theme.textInput.opacity};
width: ${(props) =>
(props.scale && "100%") ||
(props.size === "base" && props.theme.input.width.base) ||
(props.size === "middle" && props.theme.input.width.middle) ||
(props.size === "big" && props.theme.input.width.big) ||
(props.size === "huge" && props.theme.input.width.huge) ||
(props.size === "large" && props.theme.input.width.large)};
padding: ${(props) =>
(props.size === "base" && props.theme.textInput.padding.base) ||
(props.size === "middle" && props.theme.textInput.padding.middle) ||
(props.size === "big" && props.theme.textInput.padding.big) ||
(props.size === "huge" && props.theme.textInput.padding.huge) ||
(props.size === "large" && props.theme.textInput.padding.large)};
transition: ${(props) => props.theme.textInput.transition};
::-webkit-input-placeholder {
color: ${(props) =>
props.isDisabled
? props.theme.textInput.disablePlaceholderColor
: props.theme.textInput.placeholderColor};
font-family: ${(props) => props.theme.fontFamily};
${NoUserSelect}
}
:-moz-placeholder {
color: ${(props) =>
props.isDisabled
? props.theme.textInput.disablePlaceholderColor
: props.theme.textInput.placeholderColor};
font-family: ${(props) => props.theme.fontFamily};
${NoUserSelect}
}
::-moz-placeholder {
color: ${(props) =>
props.isDisabled
? props.theme.textInput.disablePlaceholderColor
: props.theme.textInput.placeholderColor};
font-family: ${(props) => props.theme.fontFamily};
${NoUserSelect}
}
:-ms-input-placeholder {
color: ${(props) =>
props.isDisabled
? props.theme.textInput.disablePlaceholderColor
: props.theme.textInput.placeholderColor};
font-family: ${(props) => props.theme.fontFamily};
${NoUserSelect}
}
::placeholder {
color: ${(props) =>
props.isDisabled
? props.theme.textInput.disablePlaceholderColor
: props.theme.textInput.placeholderColor};
font-family: ${(props) => props.theme.fontFamily};
${NoUserSelect}
}
${(props) => !props.withBorder && `border: none;`}
`;
StyledTextInput.defaultProps = { theme: Base };
export default StyledTextInput;

View File

@ -1,64 +0,0 @@
import React, { useState } from "react";
import TextInput from "./";
export default {
title: "Components/TextInput",
component: TextInput,
parameters: {
docs: {
description: {
component: "Input field for single-line strings",
},
},
design: {
type: "figma",
url: "https://www.figma.com/file/ZiW5KSwb4t7Tj6Nz5TducC/UI-Kit-DocSpace-1.0.0?type=design&node-id=633-3686&mode=dev",
},
},
argTypes: {
onBlur: { action: "onBlur" },
onFocus: { action: "onFocus" },
onChange: { action: "onChange" },
scale: { description: "Indicates that the input field has scaled" },
},
};
const Template = ({
onChange,
value,
...args
}: any) => {
const [val, setValue] = useState(value);
return (
<TextInput
{...args}
value={val}
onChange={(e: any) => {
setValue(e.target.value);
onChange(e.target.value);
}}
/>
);
};
export const Default = Template.bind({});
// @ts-expect-error TS(2339): Property 'args' does not exist on type '({ onChang... Remove this comment to see the full error message
Default.args = {
id: "",
name: "",
placeholder: "This is placeholder",
maxLength: 255,
size: "base",
isAutoFocussed: false,
isDisabled: false,
isReadOnly: false,
hasError: false,
hasWarning: false,
scale: false,
autoComplete: "off",
tabIndex: 1,
withBorder: true,
mask: null,
value: "",
};

View File

@ -1,82 +0,0 @@
import React from "react";
// @ts-expect-error TS(7016): Could not find a declaration file for module 'enzy... Remove this comment to see the full error message
import { mount, shallow } from "enzyme";
import TextInput from ".";
// @ts-expect-error TS(2582): Cannot find name 'describe'. Do you need to instal... Remove this comment to see the full error message
describe("<TextInput />", () => {
// @ts-expect-error TS(2582): Cannot find name 'it'. Do you need to install type... Remove this comment to see the full error message
it("renders without error", () => {
// @ts-expect-error TS(2708): Cannot use namespace 'jest' as a value.
const wrapper = mount(<TextInput value="text" onChange={jest.fn()} />);
// @ts-expect-error TS(2304): Cannot find name 'expect'.
expect(wrapper).toExist();
});
// @ts-expect-error TS(2582): Cannot find name 'it'. Do you need to install type... Remove this comment to see the full error message
it("not re-render test", () => {
// @ts-expect-error TS(2708): Cannot use namespace 'jest' as a value.
const onChange = jest.fn();
const wrapper = shallow(
<TextInput value="text" onChange={onChange} />
).instance();
const shouldUpdate = wrapper.shouldComponentUpdate(wrapper.props);
// @ts-expect-error TS(2304): Cannot find name 'expect'.
expect(shouldUpdate).toBe(false);
});
// @ts-expect-error TS(2582): Cannot find name 'it'. Do you need to install type... Remove this comment to see the full error message
it("re-render test by value", () => {
// @ts-expect-error TS(2708): Cannot use namespace 'jest' as a value.
const onChange = jest.fn();
const wrapper = shallow(
<TextInput value="text" onChange={onChange} />
).instance();
const shouldUpdate = wrapper.shouldComponentUpdate({
...wrapper.props,
value: "another text",
});
// @ts-expect-error TS(2304): Cannot find name 'expect'.
expect(shouldUpdate).toBe(true);
});
// @ts-expect-error TS(2582): Cannot find name 'it'. Do you need to install type... Remove this comment to see the full error message
it("accepts id", () => {
const wrapper = mount(
// @ts-expect-error TS(2708): Cannot use namespace 'jest' as a value.
<TextInput value="text" onChange={jest.fn()} id="testId" />
);
// @ts-expect-error TS(2304): Cannot find name 'expect'.
expect(wrapper.prop("id")).toEqual("testId");
});
// @ts-expect-error TS(2582): Cannot find name 'it'. Do you need to install type... Remove this comment to see the full error message
it("accepts className", () => {
const wrapper = mount(
// @ts-expect-error TS(2708): Cannot use namespace 'jest' as a value.
<TextInput value="text" onChange={jest.fn()} className="test" />
);
// @ts-expect-error TS(2304): Cannot find name 'expect'.
expect(wrapper.prop("className")).toEqual("test");
});
// @ts-expect-error TS(2582): Cannot find name 'it'. Do you need to install type... Remove this comment to see the full error message
it("accepts style", () => {
const wrapper = mount(
// @ts-expect-error TS(2708): Cannot use namespace 'jest' as a value.
<TextInput value="text" onChange={jest.fn()} style={{ color: "red" }} />
);
// @ts-expect-error TS(2304): Cannot find name 'expect'.
expect(wrapper.getDOMNode().style).toHaveProperty("color", "red");
});
});

View File

@ -1,95 +0,0 @@
import React from "react";
import PropTypes from "prop-types";
import equal from "fast-deep-equal/react";
import StyledTextInput from "./styled-text-input";
class TextInput extends React.Component {
shouldComponentUpdate(nextProps: any) {
return !equal(this.props, nextProps);
}
render() {
// console.log(`TextInput render id=${this.props.id}`);
return <StyledTextInput {...this.props} />;
}
}
// @ts-expect-error TS(2339): Property 'propTypes' does not exist on type 'typeo... Remove this comment to see the full error message
TextInput.propTypes = {
/** Used as HTML `id` property */
id: PropTypes.string,
/** Forwarded ref */
forwardedRef: PropTypes.object,
/** Used as HTML `name` property */
name: PropTypes.string,
/** Supported type of the input fields. */
type: PropTypes.oneOf(["text", "password", "email", "tel", "search"]),
/** Value of the input */
value: PropTypes.string.isRequired,
/** Default maxLength value of the input */
maxLength: PropTypes.number,
/** Placeholder text for the input */
placeholder: PropTypes.string,
/** Used as HTML `tabindex` property */
tabIndex: PropTypes.number,
/** input text mask */
mask: PropTypes.oneOfType([PropTypes.array, PropTypes.func]),
/** Allows to add or delete characters without changing the positions of the existing characters.*/
keepCharPositions: PropTypes.bool,
/** When guide is true, Text Mask always shows both placeholder characters and non-placeholder mask characters. */
guide: PropTypes.bool,
/** Supported size of the input fields. */
size: PropTypes.oneOf(["base", "middle", "big", "huge", "large"]),
/** Indicates the input field has scale */
scale: PropTypes.bool,
/** Called with the new value. Required when input is not read only. Parent should pass it back as `value` */
onChange: PropTypes.func,
/** Called when field is blurred */
onBlur: PropTypes.func,
/** Called when field is focused */
onFocus: PropTypes.func,
/** Focus the input field on initial render */
isAutoFocussed: PropTypes.bool,
/** Indicates that the field cannot be used (e.g not authorised, or changes not saved) */
isDisabled: PropTypes.bool,
/** Indicates that the field is displaying read-only content */
isReadOnly: PropTypes.bool,
/** Indicates the input field has an error */
hasError: PropTypes.bool,
/** Indicates the input field has a warning */
hasWarning: PropTypes.bool,
/** Used as HTML `autocomplete` property */
autoComplete: PropTypes.string,
/** Accepts class */
className: PropTypes.string,
/** Accepts css style */
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
/** Sets the font weight */
fontWeight: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
/** Sets font weight value to 600 */
isBold: PropTypes.bool,
/** Indicates that component contain border */
withBorder: PropTypes.bool,
};
// @ts-expect-error TS(2339): Property 'defaultProps' does not exist on type 'ty... Remove this comment to see the full error message
TextInput.defaultProps = {
type: "text",
// Empty placeholder by default needed for RTL mode to make :placeholder-shown work to put cursor on the right side of input
placeholder: " ",
value: "",
maxLength: 255,
size: "base",
scale: false,
tabIndex: -1,
hasError: false,
hasWarning: false,
autoComplete: "off",
withBorder: true,
keepCharPositions: false,
guide: false,
isBold: false,
};
export default TextInput;

View File

@ -29,8 +29,12 @@ import {
import { Checkbox } from "./checkbox";
import { Toast, toastr, ToastType } from "./toast";
import { Textarea } from "./textarea";
import { TextInput, InputSize, InputType } from "./text-input";
export {
TextInput,
InputSize,
InputType,
Textarea,
Toast,
toastr,

View File

@ -5,7 +5,7 @@ Input field for single-line strings
### Usage
```js
import TextInput from "@docspace/components/text-input";
import { TextInput } from "@docspace/shared/components";
```
```js

View File

@ -0,0 +1,15 @@
export const enum InputType {
text = "text",
password = "password",
email = "email",
tel = "tel",
search = "search",
}
export const enum InputSize {
base = "base",
middle = "middle",
big = "big",
huge = "huge",
large = "large",
}

View File

@ -0,0 +1,69 @@
import React, { useState } from "react";
import { Meta, StoryObj } from "@storybook/react";
import { TextInputPure } from "./TextInput";
import { TextInputProps } from "./TextInput.types";
import { InputSize, InputType } from "./TextInput.enums";
const meta = {
title: "Components/TextInput",
component: TextInputPure,
parameters: {
docs: {
description: {
component: "Input field for single-line strings",
},
},
design: {
type: "figma",
url: "https://www.figma.com/file/ZiW5KSwb4t7Tj6Nz5TducC/UI-Kit-DocSpace-1.0.0?type=design&node-id=633-3686&mode=dev",
},
},
argTypes: {
onBlur: { action: "onBlur" },
onFocus: { action: "onFocus" },
onChange: { action: "onChange" },
scale: { description: "Indicates that the input field has scaled" },
},
} satisfies Meta<typeof TextInputPure>;
type Story = StoryObj<typeof TextInputPure>;
export default meta;
const Template = ({ onChange, value, ...args }: TextInputProps) => {
const [val, setValue] = useState(value);
return (
<TextInputPure
{...args}
value={val}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setValue(e.target.value);
onChange?.(e);
}}
/>
);
};
export const Default: Story = {
render: (args) => <Template {...args} />,
args: {
id: "",
name: "",
placeholder: "This is placeholder",
maxLength: 255,
size: InputSize.base,
type: InputType.text,
isAutoFocussed: false,
isDisabled: false,
isReadOnly: false,
hasError: false,
hasWarning: false,
scale: false,
autoComplete: "off",
tabIndex: 1,
withBorder: true,
mask: undefined,
value: "",
},
};

View File

@ -0,0 +1,149 @@
import styled from "styled-components";
import { commonInputStyle, NoUserSelect } from "../../constants";
import { Base } from "../../themes";
import { InputSize } from "./TextInput.enums";
import { Input } from "./sub-components/Input";
const StyledTextInput = styled(Input).attrs((props) => ({
id: props.id,
forwardedRef: props.forwardedRef,
name: props.name,
type: props.type,
value: props.value,
placeholder: props.placeholder,
maxLength: props.maxLength,
onChange: props.onChange,
onBlur: props.onBlur,
onFocus: props.onFocus,
readOnly: props.isReadOnly,
autoFocus: props.isAutoFocussed,
autoComplete: props.autoComplete,
tabIndex: props.tabIndex,
disabled: props.isDisabled ? "disabled" : "",
}))`
${commonInputStyle}
-webkit-appearance: ${(props) => props.theme.textInput.appearance};
background-color: ${(props) =>
props.isDisabled
? props.theme.input.disableBackgroundColor
: props.theme.input.backgroundColor};
-webkit-text-fill-color: ${(props) =>
props.isDisabled
? props.theme.input.disableColor
: props?.value?.length > 0
? props.theme.text.color
: props.theme.textInput.placeholderColor} !important;
caret-color: ${(props) =>
props.isDisabled ? props.theme.input.disableColor : props.theme.text.color};
-webkit-background-clip: text !important;
box-shadow: inset 0 0 20px 20px
${(props) =>
props.isDisabled
? props.theme.input.disableBackgroundColor
: props.theme.input.backgroundColor} !important;
display: ${(props) => props.theme.textInput.display};
font-family: ${(props) => props.theme.fontFamily};
line-height: ${(props) =>
(props.size === InputSize.base && props.theme.textInput.lineHeight.base) ||
(props.size === InputSize.middle &&
props.theme.textInput.lineHeight.middle) ||
(props.size === InputSize.big && props.theme.textInput.lineHeight.big) ||
(props.size === InputSize.huge && props.theme.textInput.lineHeight.huge) ||
(props.size === InputSize.large && props.theme.textInput.lineHeight.large)};
font-size: ${(props) =>
props.theme.getCorrectFontSize(
(props.size === InputSize.base && props.theme.textInput.fontSize.base) ||
(props.size === InputSize.middle &&
props.theme.textInput.fontSize.middle) ||
(props.size === InputSize.big && props.theme.textInput.fontSize.big) ||
(props.size === InputSize.huge &&
props.theme.textInput.fontSize.huge) ||
(props.size === InputSize.large &&
props.theme.textInput.fontSize.large) ||
props.theme.textInput.fontSize.base,
)};
font-weight: ${(props) =>
props.fontWeight
? props.fontWeight
: props.isBold
? 600
: props.theme.textInput.fontWeight};
flex: ${(props) => props.theme.textInput.flex};
outline: ${(props) => props.theme.textInput.outline};
overflow: ${(props) => props.theme.textInput.overflow};
opacity: ${(props) => props.theme.textInput.opacity};
width: ${(props) =>
(props.scale && "100%") ||
(props.size === InputSize.base && props.theme.input.width.base) ||
(props.size === InputSize.middle && props.theme.input.width.middle) ||
(props.size === InputSize.big && props.theme.input.width.big) ||
(props.size === InputSize.huge && props.theme.input.width.huge) ||
(props.size === InputSize.large && props.theme.input.width.large)};
padding: ${(props) =>
(props.size === InputSize.base && props.theme.textInput.padding.base) ||
(props.size === InputSize.middle && props.theme.textInput.padding.middle) ||
(props.size === InputSize.big && props.theme.textInput.padding.big) ||
(props.size === InputSize.huge && props.theme.textInput.padding.huge) ||
(props.size === InputSize.large && props.theme.textInput.padding.large)};
transition: ${(props) => props.theme.textInput.transition};
::-webkit-input-placeholder {
color: ${(props) =>
props.isDisabled
? props.theme.textInput.disablePlaceholderColor
: props.theme.textInput.placeholderColor};
font-family: ${(props) => props.theme.fontFamily};
${NoUserSelect}
}
:-moz-placeholder {
color: ${(props) =>
props.isDisabled
? props.theme.textInput.disablePlaceholderColor
: props.theme.textInput.placeholderColor};
font-family: ${(props) => props.theme.fontFamily};
${NoUserSelect}
}
::-moz-placeholder {
color: ${(props) =>
props.isDisabled
? props.theme.textInput.disablePlaceholderColor
: props.theme.textInput.placeholderColor};
font-family: ${(props) => props.theme.fontFamily};
${NoUserSelect}
}
:-ms-input-placeholder {
color: ${(props) =>
props.isDisabled
? props.theme.textInput.disablePlaceholderColor
: props.theme.textInput.placeholderColor};
font-family: ${(props) => props.theme.fontFamily};
${NoUserSelect}
}
::placeholder {
color: ${(props) =>
props.isDisabled
? props.theme.textInput.disablePlaceholderColor
: props.theme.textInput.placeholderColor};
font-family: ${(props) => props.theme.fontFamily};
${NoUserSelect}
}
${(props) => !props.withBorder && `border: none;`}
`;
StyledTextInput.defaultProps = { theme: Base };
export { StyledTextInput };

View File

@ -0,0 +1,87 @@
import React from "react";
import { screen, render } from "@testing-library/react";
import "@testing-library/jest-dom";
import { TextInput } from "./TextInput";
import { InputSize, InputType } from "./TextInput.enums";
describe("<TextInput />", () => {
it("renders without error", () => {
render(
<TextInput
value="text"
size={InputSize.base}
type={InputType.text}
onChange={jest.fn()}
/>,
);
expect(screen.getByTestId("text-input")).toBeInTheDocument();
});
//
// it("not re-render test", () => {
//
// const onChange = jest.fn();
// const wrapper = shallow(
// <TextInput value="text" onChange={onChange} />
// ).instance();
// const shouldUpdate = wrapper.shouldComponentUpdate(wrapper.props);
// // @ts-expect-error TS(2304): Cannot find name 'expect'.
// expect(shouldUpdate).toBe(false);
// });
//
// it("re-render test by value", () => {
//
// const onChange = jest.fn();
// const wrapper = shallow(
// <TextInput value="text" onChange={onChange} />
// ).instance();
// const shouldUpdate = wrapper.shouldComponentUpdate({
// ...wrapper.props,
// value: "another text",
// });
// // @ts-expect-error TS(2304): Cannot find name 'expect'.
// expect(shouldUpdate).toBe(true);
// });
//
// it("accepts id", () => {
// const wrapper = mount(
//
// <TextInput value="text" onChange={jest.fn()} id="testId" />
// );
// // @ts-expect-error TS(2304): Cannot find name 'expect'.
// expect(wrapper.prop("id")).toEqual("testId");
// });
//
// it("accepts className", () => {
// const wrapper = mount(
//
// <TextInput value="text" onChange={jest.fn()} className="test" />
// );
// // @ts-expect-error TS(2304): Cannot find name 'expect'.
// expect(wrapper.prop("className")).toEqual("test");
// });
//
// it("accepts style", () => {
// const wrapper = mount(
//
// <TextInput value="text" onChange={jest.fn()} style={{ color: "red" }} />
// );
// // @ts-expect-error TS(2304): Cannot find name 'expect'.
// expect(wrapper.getDOMNode().style).toHaveProperty("color", "red");
// });
});

View File

@ -0,0 +1,22 @@
import React from "react";
import equal from "fast-deep-equal/react";
import { StyledTextInput } from "./TextInput.styled";
import { TextInputProps } from "./TextInput.types";
const compare = (
prevProps: Readonly<TextInputProps>,
nextProps: Readonly<TextInputProps>,
) => {
return !equal(prevProps, nextProps);
};
export const TextInputPure = (props: TextInputProps) => {
return <StyledTextInput {...props} data-testid="text-input" />;
};
const TextInput = React.memo(TextInputPure, compare);
TextInput.displayName = "TextInput";
export { TextInput };

View File

@ -0,0 +1,61 @@
import { Mask } from "react-text-mask";
import { InputSize, InputType } from "./TextInput.enums";
export interface TextInputProps {
/** Used as HTML `id` property */
id?: string;
/** Forwarded ref */
forwardedRef?: React.Ref<HTMLInputElement>;
/** Used as HTML `name` property */
name?: string;
/** Supported type of the input fields. */
type: InputType;
/** Value of the input */
value: string;
/** Default maxLength value of the input */
maxLength?: number;
/** Placeholder text for the input */
placeholder?: string;
/** Used as HTML `tabindex` property */
tabIndex?: number;
/** input text mask */
mask?: Mask | ((value: string) => Mask);
/** Allows to add or delete characters without changing the positions of the existing characters. */
keepCharPositions?: boolean;
/** When guide is true, Text Mask always shows both placeholder characters and non-placeholder mask characters. */
guide?: boolean;
/** Supported size of the input fields. */
size: InputSize;
/** Indicates the input field has scale */
scale?: boolean;
/** Called with the new value. Required when input is not read only. Parent should pass it back as `value` */
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
/** Called when field is blurred */
onBlur?: (e: React.FocusEvent<HTMLInputElement>) => void;
/** Called when field is focused */
onFocus?: (e: React.FocusEvent<HTMLInputElement>) => void;
/** Focus the input field on initial render */
isAutoFocussed?: boolean;
/** Indicates that the field cannot be used (e.g not authorised, or changes not saved) */
isDisabled?: boolean;
/** Indicates that the field is displaying read-only content */
isReadOnly?: boolean;
/** Indicates the input field has an error */
hasError?: boolean;
/** Indicates the input field has a warning */
hasWarning?: boolean;
/** Used as HTML `autocomplete` property */
autoComplete?: string;
/** Accepts class */
className?: string;
/** Accepts css style */
style?: React.CSSProperties;
/** Sets the font weight */
fontWeight?: number | string;
/** Sets font weight value to 600 */
isBold?: boolean;
/** Indicates that component contain border */
withBorder?: boolean;
dir?: string;
}

View File

@ -0,0 +1,2 @@
export { TextInput } from "./TextInput";
export { InputSize, InputType } from "./TextInput.enums";

View File

@ -0,0 +1,65 @@
import React from "react";
import MaskedInput from "react-text-mask";
import { TextInputProps } from "../TextInput.types";
const Input = ({
isAutoFocussed,
isDisabled,
isReadOnly,
hasError,
hasWarning,
scale,
withBorder,
keepCharPositions,
guide,
fontWeight,
isBold,
forwardedRef,
className,
dir = "auto",
size,
mask,
...props
}: TextInputProps) => {
const rest = {
autoFocus: isAutoFocussed,
ref: forwardedRef || null,
};
return mask ? (
<MaskedInput
className={`${className} not-selectable`}
keepCharPositions
guide={false}
mask={mask}
{...props}
/>
) : (
<input
className={`${className} not-selectable`}
dir={dir}
{...props}
{...rest}
/>
);
};
Input.defaultProps = {
type: "text",
// Empty placeholder by default needed for RTL mode to make :placeholder-shown work to put cursor on the right side of input
placeholder: " ",
value: "",
maxLength: 255,
size: "base",
scale: false,
tabIndex: -1,
hasError: false,
hasWarning: false,
autoComplete: "off",
withBorder: true,
keepCharPositions: false,
guide: false,
isBold: false,
};
export { Input };

View File

@ -9326,6 +9326,15 @@ __metadata:
languageName: node
linkType: hard
"@types/react-text-mask@npm:^5.4.14":
version: 5.4.14
resolution: "@types/react-text-mask@npm:5.4.14"
dependencies:
"@types/react": "*"
checksum: 52ddb3f68673a833da5c14fb21d3341f60975908849b99d7a3a6fde5f1c83d0a3e3a086f97fd3675788f15049dbd1988971e33263cdaead87ce825513e5b585c
languageName: node
linkType: hard
"@types/react-textarea-autosize@npm:^4.3.3":
version: 4.3.6
resolution: "@types/react-textarea-autosize@npm:4.3.6"
@ -14276,6 +14285,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "docspace@workspace:."
dependencies:
"@types/react-text-mask": ^5.4.14
he: ^1.2.0
madge: ^6.1.0
shx: ^0.3.4