@cleartrip/ct-design-field 4.0.0 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/README.md +87 -0
  2. package/dist/Field.d.ts +4 -4
  3. package/dist/Field.d.ts.map +1 -1
  4. package/dist/FieldAction/index.d.ts +0 -1
  5. package/dist/FieldAction/index.d.ts.map +1 -1
  6. package/dist/FieldAction/type.d.ts +1 -1
  7. package/dist/FieldAction/type.d.ts.map +1 -1
  8. package/dist/FieldIcon/index.d.ts +0 -1
  9. package/dist/FieldIcon/index.d.ts.map +1 -1
  10. package/dist/FieldIcon/type.d.ts +4 -2
  11. package/dist/FieldIcon/type.d.ts.map +1 -1
  12. package/dist/Input.d.ts +8 -0
  13. package/dist/Input.d.ts.map +1 -0
  14. package/dist/Input.native.d.ts +7 -0
  15. package/dist/Input.native.d.ts.map +1 -0
  16. package/dist/InputField.d.ts +4 -0
  17. package/dist/InputField.d.ts.map +1 -0
  18. package/dist/Label.d.ts +6 -0
  19. package/dist/Label.d.ts.map +1 -0
  20. package/dist/Label.native.d.ts +6 -0
  21. package/dist/Label.native.d.ts.map +1 -0
  22. package/dist/TextArea.d.ts +7 -0
  23. package/dist/TextArea.d.ts.map +1 -0
  24. package/dist/TextAreaInput.d.ts +7 -0
  25. package/dist/TextAreaInput.d.ts.map +1 -0
  26. package/dist/TextAreaInput.native.d.ts +3 -0
  27. package/dist/TextAreaInput.native.d.ts.map +1 -0
  28. package/dist/constants.d.ts +10 -0
  29. package/dist/constants.d.ts.map +1 -0
  30. package/dist/ct-design-field.browser.cjs.js +11 -1
  31. package/dist/ct-design-field.browser.cjs.js.map +1 -1
  32. package/dist/ct-design-field.browser.esm.js +11 -1
  33. package/dist/ct-design-field.browser.esm.js.map +1 -1
  34. package/dist/ct-design-field.cjs.js +1003 -396
  35. package/dist/ct-design-field.cjs.js.map +1 -1
  36. package/dist/ct-design-field.esm.js +997 -387
  37. package/dist/ct-design-field.esm.js.map +1 -1
  38. package/dist/ct-design-field.umd.js +2721 -537
  39. package/dist/ct-design-field.umd.js.map +1 -1
  40. package/dist/index.d.ts +6 -9
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/style.d.ts +146 -38
  43. package/dist/style.d.ts.map +1 -1
  44. package/dist/type.d.ts +114 -25
  45. package/dist/type.d.ts.map +1 -1
  46. package/dist/variants/Card/index.d.ts +13 -0
  47. package/dist/variants/Card/index.d.ts.map +1 -0
  48. package/dist/variants/Card/index.native.d.ts +13 -0
  49. package/dist/variants/Card/index.native.d.ts.map +1 -0
  50. package/dist/variants/Card/type.d.ts +5 -0
  51. package/dist/variants/Card/type.d.ts.map +1 -0
  52. package/dist/variants/OTP/index.d.ts +4 -0
  53. package/dist/variants/OTP/index.d.ts.map +1 -0
  54. package/dist/variants/OTP/type.d.ts +25 -0
  55. package/dist/variants/OTP/type.d.ts.map +1 -0
  56. package/dist/variants/Phone/Prefix/index.d.ts +4 -0
  57. package/dist/variants/Phone/Prefix/index.d.ts.map +1 -0
  58. package/dist/variants/Phone/Prefix/type.d.ts.map +1 -0
  59. package/dist/variants/Phone/index.d.ts +5 -0
  60. package/dist/variants/Phone/index.d.ts.map +1 -0
  61. package/dist/variants/Phone/index.native.d.ts +5 -0
  62. package/dist/variants/Phone/index.native.d.ts.map +1 -0
  63. package/dist/variants/Phone/type.d.ts +7 -0
  64. package/dist/variants/Phone/type.d.ts.map +1 -0
  65. package/package.json +33 -19
  66. package/src/Field.tsx +201 -0
  67. package/src/FieldAction/index.tsx +47 -0
  68. package/src/FieldAction/type.ts +15 -0
  69. package/src/FieldIcon/index.tsx +48 -0
  70. package/src/FieldIcon/type.ts +52 -0
  71. package/src/Input.native.tsx +284 -0
  72. package/src/Input.tsx +242 -0
  73. package/src/InputField.tsx +22 -0
  74. package/src/Label.native.tsx +83 -0
  75. package/src/Label.tsx +91 -0
  76. package/src/TextArea.tsx +14 -0
  77. package/src/TextAreaInput.native.tsx +4 -0
  78. package/src/TextAreaInput.tsx +243 -0
  79. package/src/constants.ts +10 -0
  80. package/src/index.ts +8 -0
  81. package/src/style.ts +353 -0
  82. package/src/type.ts +243 -0
  83. package/src/variants/Card/index.native.tsx +46 -0
  84. package/src/variants/Card/index.tsx +89 -0
  85. package/src/variants/Card/type.ts +5 -0
  86. package/src/variants/OTP/index.tsx +343 -0
  87. package/src/variants/OTP/type.ts +34 -0
  88. package/src/variants/Phone/Prefix/index.tsx +87 -0
  89. package/src/variants/Phone/Prefix/type.ts +24 -0
  90. package/src/variants/Phone/index.native.tsx +84 -0
  91. package/src/variants/Phone/index.tsx +79 -0
  92. package/src/variants/Phone/type.ts +13 -0
  93. package/dist/CardField/CardField.d.ts +0 -6
  94. package/dist/CardField/CardField.d.ts.map +0 -1
  95. package/dist/CardField/index.d.ts +0 -3
  96. package/dist/CardField/index.d.ts.map +0 -1
  97. package/dist/CardField/type.d.ts +0 -16
  98. package/dist/CardField/type.d.ts.map +0 -1
  99. package/dist/OTPField/OTPField.d.ts +0 -6
  100. package/dist/OTPField/OTPField.d.ts.map +0 -1
  101. package/dist/OTPField/SingleOTPInput.d.ts +0 -6
  102. package/dist/OTPField/SingleOTPInput.d.ts.map +0 -1
  103. package/dist/OTPField/index.d.ts +0 -3
  104. package/dist/OTPField/index.d.ts.map +0 -1
  105. package/dist/OTPField/type.d.ts +0 -23
  106. package/dist/OTPField/type.d.ts.map +0 -1
  107. package/dist/PhoneField/PhoneField.d.ts +0 -6
  108. package/dist/PhoneField/PhoneField.d.ts.map +0 -1
  109. package/dist/PhoneField/index.d.ts +0 -3
  110. package/dist/PhoneField/index.d.ts.map +0 -1
  111. package/dist/PhoneField/type.d.ts +0 -11
  112. package/dist/PhoneField/type.d.ts.map +0 -1
  113. package/dist/PhoneFieldPrefix/index.d.ts +0 -5
  114. package/dist/PhoneFieldPrefix/index.d.ts.map +0 -1
  115. package/dist/PhoneFieldPrefix/type.d.ts.map +0 -1
  116. package/dist/StyledField/StyledField.d.ts +0 -7
  117. package/dist/StyledField/StyledField.d.ts.map +0 -1
  118. package/dist/StyledField/index.d.ts +0 -2
  119. package/dist/StyledField/index.d.ts.map +0 -1
  120. package/dist/StyledField/type.d.ts +0 -12
  121. package/dist/StyledField/type.d.ts.map +0 -1
  122. package/dist/StyledFieldContainer/StyledFieldContainer.d.ts +0 -7
  123. package/dist/StyledFieldContainer/StyledFieldContainer.d.ts.map +0 -1
  124. package/dist/StyledFieldContainer/index.d.ts +0 -2
  125. package/dist/StyledFieldContainer/index.d.ts.map +0 -1
  126. package/dist/StyledFieldContainer/type.d.ts +0 -8
  127. package/dist/StyledFieldContainer/type.d.ts.map +0 -1
  128. package/dist/StyledFieldPlaceholder/StyledFieldPlaceholder.d.ts +0 -7
  129. package/dist/StyledFieldPlaceholder/StyledFieldPlaceholder.d.ts.map +0 -1
  130. package/dist/StyledFieldPlaceholder/index.d.ts +0 -2
  131. package/dist/StyledFieldPlaceholder/index.d.ts.map +0 -1
  132. package/dist/StyledFieldPlaceholder/type.d.ts +0 -7
  133. package/dist/StyledFieldPlaceholder/type.d.ts.map +0 -1
  134. /package/dist/{PhoneFieldPrefix → variants/Phone/Prefix}/type.d.ts +0 -0
package/src/Input.tsx ADDED
@@ -0,0 +1,242 @@
1
+ import React, { forwardRef, isValidElement, useCallback, useImperativeHandle, useRef } from 'react';
2
+ import { makeStyles, useStyles } from '@cleartrip/ct-design-style-manager';
3
+ import { css } from '@emotion/css';
4
+ import { useWebMergeStyles } from '@cleartrip/ct-design-style-manager';
5
+ import { IFieldRef, IFieldProps } from './type';
6
+ import { getFieldStyles, getTypographyVariant } from './style';
7
+
8
+ const styles = css`
9
+ outline: none;
10
+ &:focus {
11
+ outline: none;
12
+ }
13
+ `;
14
+ const staticStyles = makeStyles((theme) => {
15
+ return {
16
+ root: {
17
+ width: '100%',
18
+ border: 'none',
19
+ outline: 'none',
20
+ fontSize: theme.typography.size[16],
21
+ fontWeight: theme.typography.weight.medium,
22
+ lineHeight: theme.typography.lineHeight[24],
23
+ },
24
+ };
25
+ });
26
+
27
+ const InputFieldCore = forwardRef<IFieldRef, IFieldProps & { focus: boolean; numberOfLines?: number }>(
28
+ (
29
+ {
30
+ value,
31
+ disabled,
32
+ styleConfig,
33
+ onChange,
34
+ onFocus,
35
+ onBlur,
36
+ onKeyDown,
37
+ onSelect,
38
+ onPressIn,
39
+ placeholder,
40
+ autoFocus,
41
+ readOnly,
42
+ type,
43
+ inputMode,
44
+ autoCapitalize,
45
+ fieldTypographyVariant,
46
+ variant,
47
+ prefix,
48
+ focus,
49
+ placeholderType,
50
+ id,
51
+ maxLength,
52
+ },
53
+ forwardedRef,
54
+ ) => {
55
+ const inputRef = useRef<HTMLInputElement>(null);
56
+ const { field = [] } = styleConfig ?? {};
57
+ const isPrefixComponent = isValidElement(prefix);
58
+ const disabledPlaceHolder = !placeholder?.length;
59
+
60
+ const dynamicStyles = useStyles(
61
+ (theme) => ({
62
+ root: getTypographyVariant(theme, fieldTypographyVariant ?? 'HM2'),
63
+ }),
64
+ [fieldTypographyVariant],
65
+ );
66
+
67
+ const fieldStyles = useStyles(
68
+ (theme) => {
69
+ return {
70
+ root: getFieldStyles({
71
+ isLabeledPlaceholder: placeholderType === 'labeled',
72
+ disabled: disabled ?? false,
73
+ theme,
74
+ variant: variant ?? 'md',
75
+ focus,
76
+ value,
77
+ type: type ?? 'text',
78
+ isPrefixComponent,
79
+ disabledPlaceHolder,
80
+ }),
81
+ };
82
+ },
83
+ [disabled, variant, focus, value, type, isPrefixComponent, disabledPlaceHolder],
84
+ );
85
+
86
+ const mergedStyles = useWebMergeStyles(
87
+ [staticStyles.root, dynamicStyles.root, styles, fieldStyles.root, ...field],
88
+ [fieldStyles.root, dynamicStyles.root, field],
89
+ );
90
+
91
+ useImperativeHandle(
92
+ forwardedRef,
93
+ () => ({
94
+ focus: () => {
95
+ inputRef.current?.focus();
96
+ },
97
+ blur: () => {
98
+ inputRef.current?.blur();
99
+ },
100
+ setSelection: (start: number, end: number) => {
101
+ inputRef.current?.setSelectionRange(start, end);
102
+ },
103
+ }),
104
+ [],
105
+ );
106
+
107
+ const handleOnChange = useCallback(
108
+ (event: React.ChangeEvent<HTMLInputElement>) => {
109
+ const inputValue = event.target.value;
110
+ onChange?.({
111
+ target: { value: inputValue, selectionStart: event.target.selectionStart || 0 },
112
+ currentTarget: {
113
+ focus: () => inputRef.current?.focus(),
114
+ blur: () => inputRef.current?.blur(),
115
+ setSelection: (start: number, end: number) => {
116
+ inputRef.current?.setSelectionRange(start, end);
117
+ },
118
+ },
119
+ });
120
+ },
121
+ [onChange],
122
+ );
123
+
124
+ const handleOnFocus = useCallback(
125
+ (event: React.FocusEvent<HTMLInputElement>) => {
126
+ onFocus?.({
127
+ target: { value: event.target.value },
128
+ currentTarget: {
129
+ focus: () => inputRef.current?.focus(),
130
+ blur: () => inputRef.current?.blur(),
131
+ setSelection: (start: number, end: number) => {
132
+ inputRef.current?.setSelectionRange(start, end);
133
+ },
134
+ },
135
+ preventDefault: () => event.preventDefault(),
136
+ });
137
+ },
138
+ [onFocus],
139
+ );
140
+
141
+ const handleOnBlur = useCallback(
142
+ (event: React.FocusEvent<HTMLInputElement>) => {
143
+ onBlur?.({
144
+ target: { value: event.target.value },
145
+ currentTarget: {
146
+ focus: () => inputRef.current?.focus(),
147
+ blur: () => inputRef.current?.blur(),
148
+ setSelection: (start: number, end: number) => {
149
+ inputRef.current?.setSelectionRange(start, end);
150
+ },
151
+ },
152
+ preventDefault: () => event.preventDefault(),
153
+ });
154
+ },
155
+ [onBlur],
156
+ );
157
+
158
+ const handleOnKeyDown = useCallback(
159
+ (event: React.KeyboardEvent<HTMLInputElement>) => {
160
+ onKeyDown?.({
161
+ target: { value: (event.target as HTMLInputElement).value, key: event.key },
162
+ currentTarget: {
163
+ focus: () => inputRef.current?.focus(),
164
+ blur: () => inputRef.current?.blur(),
165
+ setSelection: (start: number, end: number) => {
166
+ inputRef.current?.setSelectionRange(start, end);
167
+ },
168
+ },
169
+ preventDefault: () => event.preventDefault(),
170
+ });
171
+ },
172
+ [onKeyDown],
173
+ );
174
+
175
+ const handleOnSelect = useCallback(
176
+ (event: React.SyntheticEvent<HTMLInputElement>) => {
177
+ onSelect?.({
178
+ target: {
179
+ value: (event.target as HTMLInputElement).value,
180
+ selectionStart: (event.target as HTMLInputElement).selectionStart || 0,
181
+ },
182
+ currentTarget: {
183
+ focus: () => inputRef.current?.focus(),
184
+ blur: () => inputRef.current?.blur(),
185
+ setSelection: (start: number, end: number) => {
186
+ inputRef.current?.setSelectionRange(start, end);
187
+ },
188
+ },
189
+ preventDefault: () => event.preventDefault(),
190
+ });
191
+ },
192
+ [onSelect],
193
+ );
194
+
195
+ const handleOnPressIn = useCallback(
196
+ (event: React.MouseEvent<HTMLInputElement>) => {
197
+ onPressIn?.({
198
+ target: { value: inputRef.current?.value || '' },
199
+ currentTarget: {
200
+ focus: () => inputRef.current?.focus(),
201
+ blur: () => inputRef.current?.blur(),
202
+ setSelection: (start: number, end: number) => {
203
+ inputRef.current?.setSelectionRange(start, end);
204
+ },
205
+ },
206
+ preventDefault: () => event.preventDefault(),
207
+ });
208
+ },
209
+ [onPressIn],
210
+ );
211
+
212
+ const webProps = {
213
+ onChange: handleOnChange,
214
+ onFocus: handleOnFocus,
215
+ onBlur: handleOnBlur,
216
+ onKeyDown: handleOnKeyDown,
217
+ onSelect: handleOnSelect,
218
+ onMouseDown: handleOnPressIn,
219
+ placeholder,
220
+ autoFocus,
221
+ readOnly,
222
+ type,
223
+ inputMode,
224
+ autoCapitalize,
225
+ };
226
+
227
+ return (
228
+ <input
229
+ maxLength={maxLength}
230
+ id={id}
231
+ ref={inputRef}
232
+ value={value}
233
+ disabled={disabled}
234
+ className={mergedStyles}
235
+ {...webProps}
236
+ />
237
+ );
238
+ },
239
+ );
240
+
241
+ InputFieldCore.displayName = 'InputFieldCore';
242
+ export default InputFieldCore;
@@ -0,0 +1,22 @@
1
+ import { forwardRef } from 'react';
2
+ import { IFieldRef, InputFieldProps } from './type';
3
+ import Field from './Field';
4
+ import PhoneField from './variants/Phone';
5
+ import OtpField from './variants/OTP';
6
+ import CardField from './variants/Card';
7
+
8
+ const InputField = forwardRef<IFieldRef, InputFieldProps>((props, forwardedRef) => {
9
+ if (props.fieldType === 'phone') {
10
+ return <PhoneField {...props} ref={forwardedRef} />;
11
+ }
12
+ if (props.fieldType === 'otp') {
13
+ return <OtpField {...props} />;
14
+ }
15
+ if (props.fieldType === 'card') {
16
+ return <CardField {...props} ref={forwardedRef} />;
17
+ }
18
+ return <Field {...props} ref={forwardedRef} />;
19
+ });
20
+
21
+ InputField.displayName = 'InputField';
22
+ export default InputField;
@@ -0,0 +1,83 @@
1
+ import { makeStyles, useStyles } from '@cleartrip/ct-design-style-manager';
2
+ import { IFieldProps } from './type';
3
+ import { FieldType, FieldVariant } from './constants';
4
+ import { getFieldPlaceholderStyles } from './style';
5
+ import { Container } from '@cleartrip/ct-design-container';
6
+ import { Typography } from '@cleartrip/ct-design-typography';
7
+ import { isValidElement } from 'react';
8
+
9
+ const staticStyles = makeStyles((theme) => {
10
+ return {
11
+ root: {
12
+ position: 'absolute',
13
+ paddingLeft: theme.spacing[4],
14
+ width: '100%',
15
+ height: '100%',
16
+ display: 'flex',
17
+ transform: [{ translateY: 0 }],
18
+ top: 16,
19
+ },
20
+ };
21
+ });
22
+
23
+ const FieldLabelWrapper: React.FC<IFieldProps & { focus: boolean }> = ({
24
+ variant,
25
+ type,
26
+ value,
27
+ focus = false,
28
+ placeholder,
29
+ placeholderType,
30
+ disabled = false,
31
+ styleConfig,
32
+ prefix,
33
+ }) => {
34
+ const { placeholder: placeholderStyleConfig } = styleConfig ?? {};
35
+ const { placeholderLabel = [], placeholderTypography = {} } = placeholderStyleConfig ?? {};
36
+
37
+ const shiftPlaceholder = placeholderType === 'floating';
38
+ const isPrefixComponent = isValidElement(prefix);
39
+
40
+ const baseStyles = useStyles(
41
+ (theme) => ({
42
+ root: getFieldPlaceholderStyles({
43
+ theme,
44
+ isFocused: focus,
45
+ disabled,
46
+ variant: variant ?? 'md',
47
+ fieldType: type ?? 'text',
48
+ isPrefixComponent,
49
+ shiftPlaceholder,
50
+ }),
51
+ }),
52
+ [focus, disabled, variant, type, isPrefixComponent, shiftPlaceholder],
53
+ );
54
+
55
+ if (placeholderType === 'default' || !focus) {
56
+ return null;
57
+ }
58
+ if (variant === FieldVariant.SM) {
59
+ if (value.length) return null;
60
+
61
+ return (
62
+ <Container styleConfig={{ root: [staticStyles.root, baseStyles.root, ...placeholderLabel] }}>
63
+ <Typography variant='B2' color='tertiary' styleConfig={placeholderTypography}>
64
+ {placeholder}
65
+ </Typography>
66
+ </Container>
67
+ );
68
+ }
69
+
70
+ if (type === FieldType.PHONE && value.length) return null;
71
+
72
+ const typographyVariant = type === FieldType.PHONE ? 'B1' : focus ? 'B3' : 'B1';
73
+
74
+ return (
75
+ <Container styleConfig={{ root: [staticStyles.root, baseStyles.root, ...placeholderLabel] }}>
76
+ <Typography variant={typographyVariant} color='tertiary' styleConfig={placeholderTypography}>
77
+ {placeholder}
78
+ </Typography>
79
+ </Container>
80
+ );
81
+ };
82
+
83
+ export default FieldLabelWrapper;
package/src/Label.tsx ADDED
@@ -0,0 +1,91 @@
1
+ import { makeStyles, useStyles, useWebMergeStyles } from '@cleartrip/ct-design-style-manager';
2
+ import { IFieldProps } from './type';
3
+ import { FieldType, FieldVariant } from './constants';
4
+ import { getFieldPlaceholderStyles } from './style';
5
+ import { Container } from '@cleartrip/ct-design-container';
6
+ import { Typography } from '@cleartrip/ct-design-typography';
7
+ import { isValidElement } from 'react';
8
+
9
+ const staticStyles = makeStyles((theme) => {
10
+ return {
11
+ root: {
12
+ position: 'absolute',
13
+ paddingLeft: theme.spacing[4],
14
+ width: '100%',
15
+ height: '100%',
16
+ display: 'flex',
17
+ transform: [{ translateY: 0 }],
18
+ top: 16,
19
+ },
20
+ };
21
+ });
22
+
23
+ const FieldLabelWrapper: React.FC<
24
+ Omit<IFieldProps, 'onChange' | 'onSelect' | 'onPressIn' | 'onKeyDown' | 'onFocus' | 'onBlur'> & { focus: boolean }
25
+ > = ({
26
+ variant,
27
+ type,
28
+ value,
29
+ focus = false,
30
+ placeholder,
31
+ placeholderType,
32
+ disabled = false,
33
+ styleConfig,
34
+ prefix,
35
+ id,
36
+ }) => {
37
+ const { placeholder: placeholderStyleConfig } = styleConfig ?? {};
38
+ const { placeholderLabel = [], placeholderTypography = {} } = placeholderStyleConfig ?? {};
39
+
40
+ const shiftPlaceholder = placeholderType === 'floating';
41
+ const isPrefixComponent = isValidElement(prefix);
42
+
43
+ const baseStyles = useStyles(
44
+ (theme) => ({
45
+ root: getFieldPlaceholderStyles({
46
+ theme,
47
+ isFocused: focus,
48
+ disabled,
49
+ variant: variant ?? 'md',
50
+ fieldType: type ?? 'text',
51
+ isPrefixComponent,
52
+ shiftPlaceholder,
53
+ }),
54
+ }),
55
+ [focus, disabled, variant, type, isPrefixComponent, shiftPlaceholder],
56
+ );
57
+
58
+ const labelStyles = useWebMergeStyles(
59
+ [baseStyles.root, staticStyles.root, ...placeholderLabel],
60
+ [baseStyles.root, placeholderLabel],
61
+ );
62
+
63
+ if (placeholderType === 'default' || !focus) {
64
+ return null;
65
+ }
66
+ if (variant === FieldVariant.SM) {
67
+ if (value.length) return null;
68
+
69
+ return (
70
+ <Container styleConfig={{ root: [baseStyles.root, staticStyles.root, ...placeholderLabel] }}>
71
+ <Typography variant='B2' color='tertiary' styleConfig={placeholderTypography}>
72
+ {placeholder}
73
+ </Typography>
74
+ </Container>
75
+ );
76
+ }
77
+
78
+ if (type === FieldType.PHONE && value.length) return null;
79
+
80
+ const typographyVariant = type === FieldType.PHONE ? 'B1' : focus ? 'B3' : 'B1';
81
+
82
+ return (
83
+ <label className={labelStyles} htmlFor={id}>
84
+ <Typography variant={typographyVariant} color='tertiary' styleConfig={placeholderTypography}>
85
+ {placeholder}
86
+ </Typography>
87
+ </label>
88
+ );
89
+ };
90
+
91
+ export default FieldLabelWrapper;
@@ -0,0 +1,14 @@
1
+ import { forwardRef } from 'react';
2
+ import { IFieldProps, IFieldRef } from './type';
3
+ import Field from './Field';
4
+
5
+ export interface ITextAreaProps extends IFieldProps {
6
+ numberOfLines?: number;
7
+ }
8
+
9
+ const TextArea = forwardRef<IFieldRef, ITextAreaProps>((props, forwardedRef) => {
10
+ return <Field {...props} ref={forwardedRef} />;
11
+ });
12
+
13
+ TextArea.displayName = 'TextArea';
14
+ export default TextArea;
@@ -0,0 +1,4 @@
1
+ import InputFieldCore from './Input';
2
+ InputFieldCore.displayName = 'TextArea';
3
+
4
+ export default InputFieldCore;
@@ -0,0 +1,243 @@
1
+ import React, { forwardRef, isValidElement, useCallback, useImperativeHandle, useRef } from 'react';
2
+ import { makeStyles, useStyles } from '@cleartrip/ct-design-style-manager';
3
+ import { css } from '@emotion/css';
4
+ import { useWebMergeStyles } from '@cleartrip/ct-design-style-manager';
5
+ import { IFieldRef, IFieldProps } from './type';
6
+ import { getFieldStyles, getTypographyVariant } from './style';
7
+
8
+ const styles = css`
9
+ outline: none;
10
+ &:focus {
11
+ outline: none;
12
+ }
13
+ `;
14
+
15
+ const staticStyles = makeStyles((theme) => {
16
+ return {
17
+ root: {
18
+ width: '100%',
19
+ border: 'none',
20
+ outline: 'none',
21
+ fontSize: theme.typography.size[16],
22
+ fontWeight: theme.typography.weight.medium,
23
+ lineHeight: theme.typography.lineHeight[24],
24
+ },
25
+ };
26
+ });
27
+
28
+ const InputFieldCore = forwardRef<IFieldRef, IFieldProps & { focus: boolean }>(
29
+ (
30
+ {
31
+ value,
32
+ disabled,
33
+ styleConfig,
34
+ onChange,
35
+ onFocus,
36
+ onBlur,
37
+ onKeyDown,
38
+ onSelect,
39
+ onPressIn,
40
+ placeholder,
41
+ autoFocus,
42
+ readOnly,
43
+ type,
44
+ inputMode,
45
+ autoCapitalize,
46
+ fieldTypographyVariant,
47
+ variant,
48
+ prefix,
49
+ focus,
50
+ placeholderType,
51
+ id,
52
+ maxLength,
53
+ },
54
+ forwardedRef,
55
+ ) => {
56
+ const inputRef = useRef<HTMLTextAreaElement>(null);
57
+ const { field = [] } = styleConfig ?? {};
58
+ const isPrefixComponent = isValidElement(prefix);
59
+ const disabledPlaceHolder = !placeholder?.length;
60
+
61
+ const dynamicStyles = useStyles(
62
+ (theme) => ({
63
+ root: getTypographyVariant(theme, fieldTypographyVariant ?? 'HM2'),
64
+ }),
65
+ [fieldTypographyVariant],
66
+ );
67
+
68
+ const fieldStyles = useStyles(
69
+ (theme) => {
70
+ return {
71
+ root: getFieldStyles({
72
+ isLabeledPlaceholder: placeholderType === 'labeled',
73
+ disabled: disabled ?? false,
74
+ theme,
75
+ variant: variant ?? 'md',
76
+ focus,
77
+ value,
78
+ type: type ?? 'text',
79
+ isPrefixComponent,
80
+ disabledPlaceHolder,
81
+ }),
82
+ };
83
+ },
84
+ [disabled, variant, focus, value, type, isPrefixComponent, disabledPlaceHolder],
85
+ );
86
+
87
+ const mergedStyles = useWebMergeStyles(
88
+ [staticStyles.root, dynamicStyles.root, styles, fieldStyles.root, ...field],
89
+ [fieldStyles.root, dynamicStyles.root, field],
90
+ );
91
+
92
+ useImperativeHandle(
93
+ forwardedRef,
94
+ () => ({
95
+ focus: () => {
96
+ inputRef.current?.focus();
97
+ },
98
+ blur: () => {
99
+ inputRef.current?.blur();
100
+ },
101
+ setSelection: (start: number, end: number) => {
102
+ inputRef.current?.setSelectionRange(start, end);
103
+ },
104
+ }),
105
+ [],
106
+ );
107
+
108
+ const handleOnChange = useCallback(
109
+ (event: React.ChangeEvent<HTMLTextAreaElement>) => {
110
+ const inputValue = event.target.value;
111
+ onChange?.({
112
+ target: { value: inputValue, selectionStart: event.target.selectionStart || 0 },
113
+ currentTarget: {
114
+ focus: () => inputRef.current?.focus(),
115
+ blur: () => inputRef.current?.blur(),
116
+ setSelection: (start: number, end: number) => {
117
+ inputRef.current?.setSelectionRange(start, end);
118
+ },
119
+ },
120
+ });
121
+ },
122
+ [onChange],
123
+ );
124
+
125
+ const handleOnFocus = useCallback(
126
+ (event: React.FocusEvent<HTMLTextAreaElement>) => {
127
+ onFocus?.({
128
+ target: { value: event.target.value },
129
+ currentTarget: {
130
+ focus: () => inputRef.current?.focus(),
131
+ blur: () => inputRef.current?.blur(),
132
+ setSelection: (start: number, end: number) => {
133
+ inputRef.current?.setSelectionRange(start, end);
134
+ },
135
+ },
136
+ preventDefault: () => event.preventDefault(),
137
+ });
138
+ },
139
+ [onFocus],
140
+ );
141
+
142
+ const handleOnBlur = useCallback(
143
+ (event: React.FocusEvent<HTMLTextAreaElement>) => {
144
+ onBlur?.({
145
+ target: { value: event.target.value },
146
+ currentTarget: {
147
+ focus: () => inputRef.current?.focus(),
148
+ blur: () => inputRef.current?.blur(),
149
+ setSelection: (start: number, end: number) => {
150
+ inputRef.current?.setSelectionRange(start, end);
151
+ },
152
+ },
153
+ preventDefault: () => event.preventDefault(),
154
+ });
155
+ },
156
+ [onBlur],
157
+ );
158
+
159
+ const handleOnKeyDown = useCallback(
160
+ (event: React.KeyboardEvent<HTMLTextAreaElement>) => {
161
+ onKeyDown?.({
162
+ target: { value: (event.target as HTMLTextAreaElement).value, key: event.key },
163
+ currentTarget: {
164
+ focus: () => inputRef.current?.focus(),
165
+ blur: () => inputRef.current?.blur(),
166
+ setSelection: (start: number, end: number) => {
167
+ inputRef.current?.setSelectionRange(start, end);
168
+ },
169
+ },
170
+ preventDefault: () => event.preventDefault(),
171
+ });
172
+ },
173
+ [onKeyDown],
174
+ );
175
+
176
+ const handleOnSelect = useCallback(
177
+ (event: React.SyntheticEvent<HTMLTextAreaElement>) => {
178
+ onSelect?.({
179
+ target: {
180
+ value: (event.target as HTMLTextAreaElement).value,
181
+ selectionStart: (event.target as HTMLTextAreaElement).selectionStart || 0,
182
+ },
183
+ currentTarget: {
184
+ focus: () => inputRef.current?.focus(),
185
+ blur: () => inputRef.current?.blur(),
186
+ setSelection: (start: number, end: number) => {
187
+ inputRef.current?.setSelectionRange(start, end);
188
+ },
189
+ },
190
+ preventDefault: () => event.preventDefault(),
191
+ });
192
+ },
193
+ [onSelect],
194
+ );
195
+
196
+ const handleOnPressIn = useCallback(
197
+ (event: React.MouseEvent<HTMLTextAreaElement>) => {
198
+ onPressIn?.({
199
+ target: { value: inputRef.current?.value || '' },
200
+ currentTarget: {
201
+ focus: () => inputRef.current?.focus(),
202
+ blur: () => inputRef.current?.blur(),
203
+ setSelection: (start: number, end: number) => {
204
+ inputRef.current?.setSelectionRange(start, end);
205
+ },
206
+ },
207
+ preventDefault: () => event.preventDefault(),
208
+ });
209
+ },
210
+ [onPressIn],
211
+ );
212
+
213
+ const webProps = {
214
+ onChange: handleOnChange,
215
+ onFocus: handleOnFocus,
216
+ onBlur: handleOnBlur,
217
+ onKeyDown: handleOnKeyDown,
218
+ onSelect: handleOnSelect,
219
+ onMouseDown: handleOnPressIn,
220
+ placeholder,
221
+ autoFocus,
222
+ readOnly,
223
+ type,
224
+ inputMode,
225
+ autoCapitalize,
226
+ };
227
+
228
+ return (
229
+ <textarea
230
+ maxLength={maxLength}
231
+ id={id}
232
+ ref={inputRef}
233
+ value={value}
234
+ disabled={disabled}
235
+ className={mergedStyles}
236
+ {...webProps}
237
+ />
238
+ );
239
+ },
240
+ );
241
+
242
+ InputFieldCore.displayName = 'TextArea';
243
+ export default InputFieldCore;