@cleartrip/ct-design-field 4.0.0 → 5.0.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/Field.tsx ADDED
@@ -0,0 +1,201 @@
1
+ import { cloneElement, forwardRef, isValidElement, useState } from 'react';
2
+ import { IFieldProps, IFieldRef } from './type';
3
+ import { Box } from '@cleartrip/ct-design-box';
4
+ import { makeStyles, useStyles } from '@cleartrip/ct-design-style-manager';
5
+ import { Container } from '@cleartrip/ct-design-container';
6
+ import { Typography } from '@cleartrip/ct-design-typography';
7
+ import InputFieldCore from './Input';
8
+ import FieldLabelWrapper from './Label';
9
+ import { getFieldContainerStyles } from './style';
10
+ import TextArea from './TextAreaInput';
11
+
12
+ const staticStyles = makeStyles((theme) => {
13
+ return {
14
+ fieldWrapper: {
15
+ flex: 1,
16
+ flexShrink: 1,
17
+ display: 'flex',
18
+ alignItems: 'center',
19
+ justifyContent: 'center',
20
+ position: 'relative',
21
+ height: '100%',
22
+ },
23
+ promptBox: {
24
+ paddingLeft: theme.spacing[4],
25
+ paddingRight: theme.spacing[4],
26
+ display: 'flex',
27
+ alignItems: 'center',
28
+ },
29
+ promptIcon: {
30
+ height: theme.size[4],
31
+ width: theme.size[4],
32
+ paddingRight: theme.spacing[1],
33
+ display: 'flex',
34
+ justifyContent: 'center',
35
+ alignItems: 'center',
36
+ },
37
+ flexNoShrink: {
38
+ flexShrink: 0,
39
+ },
40
+ fieldContainer: {
41
+ position: 'relative',
42
+ display: 'flex',
43
+ alignItems: 'center',
44
+ justifyContent: 'center',
45
+ flexDirection: 'row',
46
+ borderStyle: theme?.border.style.solid,
47
+ borderRadius: theme?.border.radius[8],
48
+ boxSizing: 'border-box',
49
+ },
50
+ };
51
+ });
52
+
53
+ const Field = forwardRef<IFieldRef, IFieldProps & { numberOfLines?: number }>(
54
+ (
55
+ {
56
+ prefix,
57
+ onBlur,
58
+ onFocus,
59
+ onChange,
60
+ onKeyDown,
61
+ onPressIn,
62
+ onSelect,
63
+ value,
64
+ autoCapitalize,
65
+ autoFocus = false,
66
+ disabled,
67
+ inputMode,
68
+ placeholder,
69
+ prefixGap: _prefixGap,
70
+ prompt,
71
+ readOnly,
72
+ placeholderType = 'default',
73
+ suffix,
74
+ suffixGap: _suffixGap,
75
+ type,
76
+ variant,
77
+ styleConfig = {},
78
+ fieldTypographyVariant,
79
+ id,
80
+ maxLength,
81
+ numberOfLines,
82
+ showSoftInputOnFocus,
83
+ customSpacingTop,
84
+ },
85
+ ref,
86
+ ) => {
87
+ const [focus, setFocus] = useState<boolean>(autoFocus);
88
+ const _isFocused = focus || value.length > 0;
89
+
90
+ const { promptStyles } = styleConfig || {};
91
+ const { Icon: promptIcon, message: promptMessage, hasError = false } = prompt || {};
92
+ const fieldContainerStyles = useStyles(
93
+ (theme) => ({
94
+ root: getFieldContainerStyles({
95
+ variant: variant ?? 'md',
96
+ theme,
97
+ hasError,
98
+ focus,
99
+ value,
100
+ disabled,
101
+ }),
102
+ }),
103
+ [variant, hasError, focus, value, disabled, styleConfig],
104
+ );
105
+
106
+ const InputField = numberOfLines && numberOfLines > 1 ? TextArea : InputFieldCore;
107
+
108
+ return (
109
+ <Box boxSize='micro' styleConfig={styleConfig}>
110
+ <Container
111
+ styleConfig={{
112
+ root: [fieldContainerStyles.root, staticStyles.fieldContainer, ...(styleConfig.fieldContainer || [])],
113
+ }}
114
+ >
115
+ {isValidElement(prefix) && (
116
+ <Container styleConfig={{ root: [staticStyles.flexNoShrink] }}>{cloneElement(prefix, { focus })}</Container>
117
+ )}
118
+ <Container styleConfig={{ root: [staticStyles.fieldWrapper, ...(styleConfig.field || [])] }}>
119
+ <FieldLabelWrapper
120
+ id={id}
121
+ variant={variant}
122
+ type={type}
123
+ value={value}
124
+ focus={_isFocused}
125
+ placeholder={placeholder}
126
+ placeholderType={placeholderType}
127
+ disabled={disabled}
128
+ styleConfig={styleConfig}
129
+ prefix={prefix}
130
+ />
131
+ <InputField
132
+ id={id}
133
+ ref={ref}
134
+ value={value}
135
+ disabled={disabled}
136
+ placeholder={placeholder}
137
+ placeholderType={placeholderType}
138
+ autoFocus={autoFocus}
139
+ readOnly={readOnly}
140
+ type={type}
141
+ inputMode={inputMode}
142
+ autoCapitalize={autoCapitalize}
143
+ fieldTypographyVariant={fieldTypographyVariant}
144
+ styleConfig={styleConfig}
145
+ focus={_isFocused}
146
+ onChange={onChange}
147
+ onSelect={onSelect}
148
+ onPressIn={onPressIn}
149
+ onFocus={(e) => {
150
+ setFocus(true);
151
+ onFocus?.(e);
152
+ }}
153
+ onBlur={(e) => {
154
+ setFocus(false);
155
+ onBlur?.(e);
156
+ }}
157
+ onKeyDown={onKeyDown}
158
+ maxLength={maxLength}
159
+ numberOfLines={numberOfLines}
160
+ showSoftInputOnFocus={showSoftInputOnFocus}
161
+ customSpacingTop={customSpacingTop}
162
+ />
163
+ </Container>
164
+ {isValidElement(suffix) && (
165
+ <Container styleConfig={{ root: [staticStyles.flexNoShrink] }}>{cloneElement(suffix, { focus })}</Container>
166
+ )}
167
+ </Container>
168
+ {(promptIcon || promptMessage) && (
169
+ <Box
170
+ boxSize='pico'
171
+ horizontal={true}
172
+ styleConfig={{
173
+ root: [staticStyles.promptBox, ...(promptStyles?.promptBox || [])],
174
+ }}
175
+ >
176
+ {promptIcon && (
177
+ <Container
178
+ styleConfig={{ root: [staticStyles.promptIcon, ...(promptStyles?.promptIconContainer || [])] }}
179
+ >
180
+ {promptIcon}
181
+ </Container>
182
+ )}
183
+ {promptMessage && (
184
+ <Typography
185
+ variant='B3'
186
+ color={hasError ? 'warning' : 'success'}
187
+ styleConfig={promptStyles?.promptMessageTypography}
188
+ >
189
+ {promptMessage}
190
+ </Typography>
191
+ )}
192
+ </Box>
193
+ )}
194
+ </Box>
195
+ );
196
+ },
197
+ );
198
+
199
+ Field.displayName = 'Field';
200
+
201
+ export default Field;
@@ -0,0 +1,47 @@
1
+ import { Box } from '@cleartrip/ct-design-box';
2
+ import { DottedLoader } from '@cleartrip/ct-design-dotted-loader';
3
+ import { Typography, TypographyColor } from '@cleartrip/ct-design-typography';
4
+
5
+ import { IFieldAction } from './type';
6
+ import { makeStyles } from '@cleartrip/ct-design-style-manager';
7
+
8
+ const staticStyles = makeStyles((theme) => ({
9
+ root: {
10
+ paddingRight: theme.spacing[4],
11
+ },
12
+ }));
13
+
14
+ const FieldAction: React.FC<IFieldAction> = ({ actionsList = [] }) => {
15
+ return (
16
+ <Box boxSize='tiny' horizontal={true} styleConfig={{ root: [staticStyles.root] }}>
17
+ {actionsList.map((actionItem) => {
18
+ const { label, color, onClick, isDisabled, isLoading } = actionItem || {};
19
+
20
+ if (isLoading) {
21
+ return <DottedLoader key='fieldAction' />;
22
+ }
23
+
24
+ return (
25
+ <Typography
26
+ key='fieldAction'
27
+ variant='HM4'
28
+ color={isDisabled ? TypographyColor.DISABLED : color}
29
+ onClick={
30
+ !isDisabled
31
+ ? onClick
32
+ : () => {
33
+ // no-op
34
+ }
35
+ }
36
+ isClickable={true}
37
+ isDisabled={isDisabled}
38
+ >
39
+ {label}
40
+ </Typography>
41
+ );
42
+ })}
43
+ </Box>
44
+ );
45
+ };
46
+
47
+ export default FieldAction;
@@ -0,0 +1,15 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ import { TypographyColorType } from '@cleartrip/ct-design-typography';
4
+
5
+ export interface IActionItem {
6
+ label: ReactNode;
7
+ onClick?: () => void;
8
+ isLoading?: boolean;
9
+ isDisabled?: boolean;
10
+ color?: TypographyColorType;
11
+ }
12
+
13
+ export interface IFieldAction {
14
+ actionsList: IActionItem[];
15
+ }
@@ -0,0 +1,48 @@
1
+ import { isValidElement } from 'react';
2
+
3
+ import { Container } from '@cleartrip/ct-design-container';
4
+ import { makeStyles } from '@cleartrip/ct-design-style-manager';
5
+
6
+ import { IFieldIcon } from './type';
7
+
8
+ /**
9
+ * This component is used to Show the Icon in Input box.
10
+ * If there is no onclick prop then we assume that it is only for show icon and so we will add styling related to
11
+ * pointer events none so input events can be triggered over the icon as well in the components.
12
+ */
13
+
14
+ const staticStyles = makeStyles((theme) => {
15
+ return {
16
+ root: {
17
+ display: 'flex',
18
+ alignItems: 'center',
19
+ justifyContent: 'center',
20
+ marginLeft: theme.spacing[4],
21
+ width: theme.size[6],
22
+ height: theme.size[6],
23
+ },
24
+ };
25
+ });
26
+ const FieldIcon: React.FC<IFieldIcon> = ({ icon, onClick, focus, focusedIcon, styleConfig }) => {
27
+ const { root: customRootStyles = [] } = styleConfig || {};
28
+
29
+ if (!isValidElement(icon)) return <></>;
30
+
31
+ let IconPrefix = icon;
32
+
33
+ if (focus && isValidElement(focusedIcon)) {
34
+ IconPrefix = focusedIcon;
35
+ }
36
+
37
+ const handleClick = () => {
38
+ onClick?.();
39
+ };
40
+
41
+ return (
42
+ <Container styleConfig={{ root: [staticStyles.root, ...customRootStyles] }} onClick={handleClick}>
43
+ {IconPrefix}
44
+ </Container>
45
+ );
46
+ };
47
+
48
+ export default FieldIcon;
@@ -0,0 +1,52 @@
1
+ import { Styles } from '@cleartrip/ct-design-types';
2
+ import { ReactNode } from 'react';
3
+
4
+ /**
5
+ * Represents the types for a field icon component.
6
+ */
7
+ export interface IFieldIcon {
8
+ /**
9
+ * The primary icon to be displayed.
10
+ */
11
+ /**
12
+ * The primary icon to be displayed.
13
+ */
14
+ icon: ReactNode;
15
+
16
+ /**
17
+ * Optional click handler for the icon.
18
+ */
19
+
20
+ /**
21
+ * Optional click handler for the icon.
22
+ */
23
+ onClick?: () => void;
24
+
25
+ /**
26
+ * Indicates whether the field is in a focused state.
27
+ */
28
+
29
+ /**
30
+ * Indicates whether the field is in a focused state.
31
+ */
32
+ focus?: boolean;
33
+
34
+ /**
35
+ * The icon to display when the field is focused.
36
+ * If not provided, the `icon` will be used as the default.
37
+ */
38
+
39
+ /**
40
+ * The icon to display when the field is focused.
41
+ * If not provided, the `icon` will be used as the default.
42
+ */
43
+ focusedIcon?: ReactNode;
44
+
45
+ /**
46
+ * Optional styles configuration for the component.
47
+ * - `root`: An array of style objects to apply to the root element.
48
+ */
49
+ styleConfig?: {
50
+ root?: Styles[];
51
+ };
52
+ }
@@ -0,0 +1,284 @@
1
+ import { forwardRef, isValidElement, useCallback, useImperativeHandle, useRef } from 'react';
2
+ import { makeStyles, useStyles } from '@cleartrip/ct-design-style-manager';
3
+ import { useNativeMergeStyles } from '@cleartrip/ct-design-style-manager';
4
+ import {
5
+ NativeSyntheticEvent,
6
+ TextInputChangeEventData,
7
+ TextInputFocusEventData,
8
+ TextInputKeyPressEventData,
9
+ TextInput,
10
+ TextInputSelectionChangeEventData,
11
+ NativeTouchEvent,
12
+ } from 'react-native';
13
+ import { getFieldStyles } from './style';
14
+ import { IFieldProps, IFieldRef } from './type';
15
+ import { useTheme } from '@cleartrip/ct-design-theme';
16
+
17
+ const staticStyles = makeStyles((theme) => {
18
+ return {
19
+ root: {
20
+ width: '100%',
21
+ borderWidth: 0,
22
+ fontSize: theme.typography.size[16],
23
+ fontWeight: theme.typography.weight.medium,
24
+ },
25
+ };
26
+ });
27
+
28
+ const InputFieldCore = forwardRef<IFieldRef, IFieldProps & { focus: boolean; numberOfLines?: number }>(
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
+ autoCapitalize,
45
+ placeholderType,
46
+ variant,
47
+ prefix,
48
+ focus,
49
+ cursorColor,
50
+ maxLength,
51
+ numberOfLines,
52
+ showSoftInputOnFocus,
53
+ inputMode,
54
+ ...restProps
55
+ },
56
+ forwardedRef,
57
+ ) => {
58
+ const theme = useTheme();
59
+ const inputRef = useRef<TextInput>(null);
60
+ const selectionStartRef = useRef(0);
61
+ const { root = [] } = styleConfig ?? {};
62
+ const isPrefixComponent = isValidElement(prefix);
63
+ const disabledPlaceHolder = !placeholder?.length;
64
+
65
+ const fieldStyles = useStyles(
66
+ (theme) => {
67
+ return {
68
+ root: getFieldStyles({
69
+ isLabeledPlaceholder: placeholderType === 'labeled',
70
+ disabled: disabled ?? false,
71
+ theme,
72
+ variant: variant ?? 'md',
73
+ focus,
74
+ value,
75
+ type: type ?? 'text',
76
+ isPrefixComponent,
77
+ disabledPlaceHolder,
78
+ }),
79
+ };
80
+ },
81
+ [disabled, variant, focus, value, type, isPrefixComponent, disabledPlaceHolder],
82
+ );
83
+
84
+ const mergedStyles = useNativeMergeStyles([staticStyles.root, fieldStyles.root, ...(root ?? [])], [root]);
85
+
86
+ useImperativeHandle(
87
+ forwardedRef,
88
+ () => ({
89
+ focus: () => {
90
+ inputRef.current?.focus();
91
+ },
92
+ blur: () => {
93
+ inputRef.current?.blur();
94
+ },
95
+ setSelection: (start: number, end: number) => {
96
+ inputRef.current?.setNativeProps({ selection: { start, end } });
97
+ },
98
+ }),
99
+ [],
100
+ );
101
+
102
+ const handleOnChange = useCallback(
103
+ (event: NativeSyntheticEvent<TextInputChangeEventData>) => {
104
+ const inputValue = event.nativeEvent.text;
105
+ onChange?.({
106
+ target: { value: inputValue, selectionStart: selectionStartRef.current },
107
+ currentTarget: {
108
+ focus: () => {
109
+ inputRef.current?.focus();
110
+ },
111
+ blur: () => {
112
+ inputRef.current?.blur();
113
+ },
114
+ setSelection: (start: number, end: number) => {
115
+ inputRef.current?.setNativeProps({ selection: { start, end } });
116
+ },
117
+ },
118
+ preventDefault: () => event.preventDefault(),
119
+ });
120
+ },
121
+ [onChange],
122
+ );
123
+
124
+ const handleOnFocus = useCallback(
125
+ (event: NativeSyntheticEvent<TextInputFocusEventData>) => {
126
+ const inputValue = event.nativeEvent.text;
127
+ onFocus?.({
128
+ target: { value: inputValue },
129
+ currentTarget: {
130
+ focus: () => {
131
+ inputRef.current?.focus();
132
+ },
133
+ blur: () => {
134
+ inputRef.current?.blur();
135
+ },
136
+ setSelection: (start: number, end: number) => {
137
+ inputRef.current?.setNativeProps({ selection: { start, end } });
138
+ },
139
+ },
140
+ preventDefault: () => event.preventDefault(),
141
+ });
142
+ },
143
+ [onFocus],
144
+ );
145
+
146
+ const handleOnBlur = useCallback(
147
+ (event: NativeSyntheticEvent<TextInputFocusEventData>) => {
148
+ const inputValue = event.nativeEvent.text;
149
+ onBlur?.({
150
+ target: { value: inputValue },
151
+ currentTarget: {
152
+ focus: () => {
153
+ inputRef.current?.focus();
154
+ },
155
+ blur: () => {
156
+ inputRef.current?.blur();
157
+ },
158
+ setSelection: (start: number, end: number) => {
159
+ inputRef.current?.setNativeProps({ selection: { start, end } });
160
+ },
161
+ },
162
+ preventDefault: () => event.preventDefault(),
163
+ });
164
+ },
165
+ [onBlur],
166
+ );
167
+
168
+ const handleOnKeyPress = useCallback(
169
+ (event: NativeSyntheticEvent<TextInputKeyPressEventData>) => {
170
+ onKeyDown?.({
171
+ target: { value, key: event.nativeEvent.key },
172
+ currentTarget: {
173
+ focus: () => {
174
+ inputRef.current?.focus();
175
+ },
176
+ blur: () => {
177
+ inputRef.current?.blur();
178
+ },
179
+ setSelection: (start: number, end: number) => {
180
+ inputRef.current?.setNativeProps({ selection: { start, end } });
181
+ },
182
+ },
183
+ preventDefault: () => event.preventDefault(),
184
+ });
185
+ },
186
+ [onKeyDown, value],
187
+ );
188
+
189
+ const handleOnSelectionChange = useCallback(
190
+ (_event: NativeSyntheticEvent<TextInputSelectionChangeEventData>) => {
191
+ selectionStartRef.current = _event.nativeEvent.selection.start;
192
+ onSelect?.({
193
+ target: { value, selectionStart: selectionStartRef.current },
194
+ currentTarget: {
195
+ focus: () => {
196
+ inputRef.current?.focus();
197
+ },
198
+ blur: () => {
199
+ inputRef.current?.blur();
200
+ },
201
+ setSelection: (start: number, end: number) => {
202
+ inputRef.current?.setNativeProps({ selection: { start, end } });
203
+ },
204
+ },
205
+ });
206
+ },
207
+ [onSelect, value],
208
+ );
209
+
210
+ const handleOnPressIn = useCallback(
211
+ (event: NativeSyntheticEvent<NativeTouchEvent>) => {
212
+ onPressIn?.({
213
+ target: { value },
214
+ currentTarget: {
215
+ focus: () => {
216
+ inputRef.current?.focus();
217
+ },
218
+ blur: () => {
219
+ inputRef.current?.blur();
220
+ },
221
+ setSelection: (start: number, end: number) => {
222
+ inputRef.current?.setNativeProps({ selection: { start, end } });
223
+ },
224
+ },
225
+ preventDefault: () => event.preventDefault(),
226
+ });
227
+ },
228
+ [onPressIn, value],
229
+ );
230
+
231
+ // Map web input types to React Native keyboard types
232
+ const getKeyboardType = () => {
233
+ switch (type) {
234
+ case 'number':
235
+ return 'numeric';
236
+ case 'phone':
237
+ return 'phone-pad';
238
+ default:
239
+ return 'default';
240
+ }
241
+ };
242
+
243
+ // Map web input types to React Native text content types
244
+ const getTextContentType = () => {
245
+ switch (type) {
246
+ case 'phone':
247
+ return 'telephoneNumber';
248
+ default:
249
+ return 'none';
250
+ }
251
+ };
252
+
253
+ return (
254
+ <TextInput
255
+ ref={inputRef}
256
+ value={value}
257
+ placeholder={placeholderType === 'labeled' && focus ? '' : placeholder}
258
+ autoFocus={autoFocus}
259
+ editable={!disabled && !readOnly}
260
+ keyboardType={getKeyboardType()}
261
+ textContentType={getTextContentType()}
262
+ autoCapitalize={autoCapitalize}
263
+ autoCorrect={false}
264
+ allowFontScaling={false}
265
+ onChange={handleOnChange}
266
+ onFocus={handleOnFocus}
267
+ onBlur={handleOnBlur}
268
+ onKeyPress={handleOnKeyPress}
269
+ onSelectionChange={handleOnSelectionChange}
270
+ onPressIn={handleOnPressIn}
271
+ style={mergedStyles}
272
+ cursorColor={cursorColor || theme.color.text.primary}
273
+ maxLength={maxLength}
274
+ numberOfLines={numberOfLines}
275
+ showSoftInputOnFocus={showSoftInputOnFocus}
276
+ inputMode={inputMode}
277
+ {...restProps}
278
+ />
279
+ );
280
+ },
281
+ );
282
+
283
+ InputFieldCore.displayName = 'InputFieldCore';
284
+ export default InputFieldCore;