@hero-design/rn-work-uikit 1.1.0 → 1.2.0-alpha.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 (40) hide show
  1. package/.cursorrules +57 -0
  2. package/CHANGELOG.md +6 -0
  3. package/DEVELOPMENT.md +118 -0
  4. package/eslint.config.js +20 -0
  5. package/lib/index.js +871 -5
  6. package/package.json +4 -1
  7. package/src/__tests__/__snapshots__/index.spec.tsx.snap +90 -115
  8. package/src/__tests__/theme-export-override.spec.ts +6 -0
  9. package/src/components/TextInput/ErrorOrHelpText.tsx +58 -0
  10. package/src/components/TextInput/FloatingLabel.tsx +120 -0
  11. package/src/components/TextInput/InputComponent.tsx +61 -0
  12. package/src/components/TextInput/InputRow.tsx +103 -0
  13. package/src/components/TextInput/MaxLengthMessage.tsx +66 -0
  14. package/src/components/TextInput/PrefixComponent.tsx +77 -0
  15. package/src/components/TextInput/StyledTextInput.tsx +134 -0
  16. package/src/components/TextInput/SuffixComponent.tsx +73 -0
  17. package/src/components/TextInput/__tests__/ErrorOrHelpText.spec.tsx +20 -0
  18. package/src/components/TextInput/__tests__/FloatingLabel.spec.tsx +203 -0
  19. package/src/components/TextInput/__tests__/InputComponent.spec.tsx +39 -0
  20. package/src/components/TextInput/__tests__/InputRow.spec.tsx +275 -0
  21. package/src/components/TextInput/__tests__/MaxLengthMessage.spec.tsx +17 -0
  22. package/src/components/TextInput/__tests__/PrefixComponent.spec.tsx +14 -0
  23. package/src/components/TextInput/__tests__/StyledTextInput.spec.tsx +114 -0
  24. package/src/components/TextInput/__tests__/SuffixComponent.spec.tsx +20 -0
  25. package/src/components/TextInput/__tests__/__snapshots__/StyledTextInput.spec.tsx.snap +571 -0
  26. package/src/components/TextInput/__tests__/__snapshots__/index.spec.tsx.snap +5671 -0
  27. package/src/components/TextInput/__tests__/getState.spec.tsx +89 -0
  28. package/src/components/TextInput/__tests__/index.spec.tsx +699 -0
  29. package/src/components/TextInput/constants.ts +1 -0
  30. package/src/components/TextInput/index.tsx +327 -0
  31. package/src/components/TextInput/types.ts +95 -0
  32. package/src/emotion.d.ts +15 -0
  33. package/src/index.ts +3 -0
  34. package/src/jest.d.ts +24 -0
  35. package/src/theme/__tests__/__snapshots__/index.spec.ts.snap +15 -8
  36. package/src/theme/components/textInput.ts +33 -0
  37. package/src/utils/__tests__/helpers.spec.ts +92 -0
  38. package/src/utils/helpers.ts +113 -0
  39. package/testUtils/renderWithTheme.tsx +6 -3
  40. package/stats/1.1.0/rn-work-uikit-stats.html +0 -4842
@@ -0,0 +1,327 @@
1
+ import React, { forwardRef, useCallback } from 'react';
2
+ import { StyleSheet, TextInput as RNTextInput } from 'react-native';
3
+ import type {
4
+ TextInputProps as NativeTextInputProps,
5
+ StyleProp,
6
+ ViewStyle,
7
+ NativeSyntheticEvent,
8
+ TextInputFocusEventData,
9
+ } from 'react-native';
10
+ import {
11
+ StyledInputWrapper,
12
+ StyledContainer,
13
+ StyledBorder,
14
+ StyledBottomContainer,
15
+ StyledSuffixContainer,
16
+ } from './StyledTextInput';
17
+ import { useTheme } from '../../theme';
18
+ import type { State } from './StyledTextInput';
19
+ import ErrorOrHelpText from './ErrorOrHelpText';
20
+ import SuffixComponent from './SuffixComponent';
21
+ import MaxLengthMessage from './MaxLengthMessage';
22
+ import FloatingLabel from './FloatingLabel';
23
+ import InputRow from './InputRow';
24
+ import type { TextInputHandles, TextInputProps } from './types';
25
+
26
+ export type {
27
+ TextInputHandles,
28
+ TextInputVariant,
29
+ TextInputProps,
30
+ } from './types';
31
+
32
+ export const getState = ({
33
+ disabled,
34
+ error,
35
+ editable,
36
+ loading,
37
+ isEmptyValue,
38
+ }: {
39
+ disabled?: boolean;
40
+ error?: string;
41
+ editable?: boolean;
42
+ loading: boolean;
43
+ isEmptyValue?: boolean;
44
+ }): State => {
45
+ if (disabled) {
46
+ return 'disabled';
47
+ }
48
+ if (error) {
49
+ return 'error';
50
+ }
51
+ if (!editable || loading) {
52
+ return 'readonly';
53
+ }
54
+ if (!isEmptyValue) {
55
+ return 'filled';
56
+ }
57
+
58
+ return 'default';
59
+ };
60
+
61
+ // Fix issue: Placeholder is not shown on iOS when multiline is true
62
+ // https://github.com/callstack/react-native-paper/pull/3331
63
+ const EMPTY_PLACEHOLDER_VALUE = ' ';
64
+
65
+ // Simplified style extraction functions
66
+ const extractBackgroundColor = (style: StyleProp<ViewStyle>) => {
67
+ const flattened = StyleSheet.flatten(style);
68
+ return flattened?.backgroundColor;
69
+ };
70
+
71
+ const extractBorderStyles = (style: StyleProp<ViewStyle>) => {
72
+ const flattened = StyleSheet.flatten(style);
73
+ if (!flattened) return {};
74
+
75
+ const borderKeys = Object.keys(flattened).filter((key) =>
76
+ key.startsWith('border')
77
+ );
78
+ const borderStyles: Record<string, unknown> = {};
79
+
80
+ borderKeys.forEach((key) => {
81
+ borderStyles[key] = flattened[key as keyof typeof flattened];
82
+ });
83
+
84
+ return borderStyles;
85
+ };
86
+
87
+ /**
88
+ * TextInput Layout Structure:
89
+ *
90
+ * ┌─────────────────────────────────────────────────────────────────────────┐
91
+ * │ StyledContainer (with StyledBorder overlay) │
92
+ * │ ┌─────────────────────────────────────────────────────────┐ │
93
+ * │ │ StyledInputWrapper │ │
94
+ * │ │ ┌─────────────────────────────────────────────────┐ │ │
95
+ * │ │ │ FloatingLabel (Optional) │ │ │
96
+ * │ │ │ "Label" or animated position │ │ ┌──────┐ │
97
+ * │ │ └─────────────────────────────────────────────────┘ │ │Suffix│ │
98
+ * │ │ │ │ Icon │ │
99
+ * │ │ ┌─────────────────────────────────────────────────┐ │ │ or │ │
100
+ * │ │ │ InputRow Component │ │ │Custom│ │
101
+ * │ │ │ ┌──────────┐ ┌─────────────────────────────┐ │ │ │(V- │ │
102
+ * │ │ │ │ Prefix │ │ Input Field │ │ │ │Center│ │
103
+ * │ │ │ │(Animated)│ │ (Animated TextInput) │ │ │ │ ed) │ │
104
+ * │ │ │ └──────────┘ └─────────────────────────────┘ │ │ └──────┘ │
105
+ * │ │ └─────────────────────────────────────────────────┘ │ │
106
+ * │ │ │ │
107
+ * │ │ ┌─────────────────────────────────────────────────┐ │ │
108
+ * │ │ │ StyledBottomContainer │ │ │
109
+ * │ │ │ ┌─────────────────┐ ┌─────────────────────┐ │ │ │
110
+ * │ │ │ │ Error/Help Text │ │ Character Count │ │ │ │
111
+ * │ │ │ │ (flex: 4) │ │ (flex: 1) │ │ │ │
112
+ * │ │ │ └─────────────────┘ └─────────────────────┘ │ │ │
113
+ * │ │ └─────────────────────────────────────────────────┘ │ │
114
+ * │ └─────────────────────────────────────────────────────────┘ │
115
+ * └─────────────────────────────────────────────────────────────────────────┘
116
+ *
117
+ * Note: StyledBorder uses StyleSheet.absoluteFillObject to overlay the entire
118
+ * StyledContainer, providing the border and background styling.
119
+ */
120
+ const TextInput = forwardRef<TextInputHandles, TextInputProps>(
121
+ (
122
+ {
123
+ label,
124
+ prefix,
125
+ suffix,
126
+ style,
127
+ textStyle,
128
+ testID,
129
+ accessibilityLabelledBy,
130
+ error,
131
+ required,
132
+ editable = true,
133
+ disabled = false,
134
+ loading = false,
135
+ maxLength,
136
+ hideCharacterCount = false,
137
+ helpText,
138
+ value,
139
+ defaultValue,
140
+ renderInputValue,
141
+ allowFontScaling = false,
142
+ variant = 'text',
143
+ ...nativeProps
144
+ }: TextInputProps,
145
+ ref?: React.Ref<TextInputHandles>
146
+ ) => {
147
+ // Inline the simple getDisplayText function
148
+ const displayText = (value !== undefined ? value : defaultValue) ?? '';
149
+ const isEmptyValue = displayText.length === 0;
150
+
151
+ const [isFocused, setIsFocused] = React.useState(false);
152
+
153
+ const state = getState({
154
+ disabled,
155
+ error,
156
+ editable,
157
+ loading,
158
+ isEmptyValue,
159
+ });
160
+
161
+ const theme = useTheme();
162
+
163
+ const innerTextInput = React.useRef<RNTextInput | null>(null);
164
+ React.useImperativeHandle(
165
+ ref,
166
+ () => ({
167
+ // we don't expose this method, it's for testing https://medium.com/developer-rants/how-to-test-useref-without-mocking-useref-699165f4994e
168
+ getNativeTextInputRef: () => innerTextInput.current,
169
+ focus: () => {
170
+ innerTextInput.current?.focus();
171
+ },
172
+ clear: () => innerTextInput.current?.clear(),
173
+ setNativeProps: (args: NativeTextInputProps) =>
174
+ innerTextInput.current?.setNativeProps(args),
175
+ isFocused: () => innerTextInput.current?.isFocused() || false,
176
+ blur: () => innerTextInput.current?.blur(),
177
+ }),
178
+ [innerTextInput]
179
+ );
180
+
181
+ // Simplified style extraction
182
+ const borderStyles = extractBorderStyles(textStyle);
183
+ const customBackgroundColor = extractBackgroundColor(style);
184
+ const backgroundColor =
185
+ customBackgroundColor ??
186
+ theme.__hd__.textInput.colors.containerBackground;
187
+
188
+ // Simplified callback functions (removed unnecessary memoization for simple cases)
189
+ const handleFocus = useCallback(
190
+ (event: NativeSyntheticEvent<TextInputFocusEventData>) => {
191
+ setIsFocused(true);
192
+ nativeProps.onFocus?.(event);
193
+ },
194
+ [nativeProps]
195
+ );
196
+
197
+ const handleBlur = useCallback(
198
+ (event: NativeSyntheticEvent<TextInputFocusEventData>) => {
199
+ setIsFocused(false);
200
+ nativeProps.onBlur?.(event);
201
+ },
202
+ [nativeProps]
203
+ );
204
+
205
+ const handleChangeText = useCallback(
206
+ (text: string) => {
207
+ nativeProps.onChangeText?.(text);
208
+ },
209
+ [nativeProps]
210
+ );
211
+
212
+ // Simplified callbacks - these don't need memoization as they're stable
213
+ const handleContainerPress = () => {
214
+ innerTextInput.current?.focus();
215
+ };
216
+
217
+ // Create text input style without border properties
218
+ const textInputStyle = textStyle
219
+ ? { ...StyleSheet.flatten(textStyle) }
220
+ : {};
221
+ Object.keys(borderStyles).forEach((key) => {
222
+ delete textInputStyle[key as keyof typeof textInputStyle];
223
+ });
224
+
225
+ const nativeInputProps: NativeTextInputProps = {
226
+ style: StyleSheet.flatten([
227
+ {
228
+ backgroundColor,
229
+ color: theme.__hd__.textInput.colors.text,
230
+ },
231
+ textInputStyle,
232
+ ]),
233
+ testID: 'text-input',
234
+ accessibilityState: {
235
+ disabled: state === 'disabled' || state === 'readonly',
236
+ },
237
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
238
+ // @ts-ignore
239
+ accessibilityLabelledBy,
240
+ allowFontScaling,
241
+ ...nativeProps,
242
+ onFocus: handleFocus,
243
+ onBlur: handleBlur,
244
+ onChangeText: handleChangeText,
245
+ editable,
246
+ maxLength,
247
+ value,
248
+ defaultValue,
249
+ placeholder:
250
+ isFocused || label === undefined
251
+ ? nativeProps.placeholder
252
+ : EMPTY_PLACEHOLDER_VALUE,
253
+ };
254
+
255
+ // Create container style without background color
256
+ const containerStyle = style ? { ...StyleSheet.flatten(style) } : {};
257
+ if (customBackgroundColor) {
258
+ delete containerStyle.backgroundColor;
259
+ }
260
+
261
+ const isDisabledOrReadonly = state === 'disabled' || state === 'readonly';
262
+
263
+ return (
264
+ <StyledContainer
265
+ style={containerStyle}
266
+ onPress={handleContainerPress}
267
+ disabled={isDisabledOrReadonly}
268
+ accessibilityState={{
269
+ disabled: isDisabledOrReadonly,
270
+ }}
271
+ testID={testID}
272
+ >
273
+ {/*
274
+ StyledBorder: Absolute positioned overlay covering entire container
275
+ - Uses StyleSheet.absoluteFillObject to cover full StyledContainer
276
+ - Provides border styling and background color
277
+ - pointerEvents="none" to allow interaction with underlying components
278
+ */}
279
+ <StyledBorder
280
+ themeFocused={isFocused}
281
+ themeState={state}
282
+ testID="text-input-border"
283
+ pointerEvents="none"
284
+ style={[{ backgroundColor }, borderStyles]}
285
+ />
286
+ <StyledInputWrapper>
287
+ {!!label && (
288
+ <FloatingLabel
289
+ label={label}
290
+ variant={variant}
291
+ state={state}
292
+ isFocused={isFocused}
293
+ required={required}
294
+ accessibilityLabelledBy={accessibilityLabelledBy}
295
+ isEmptyValue={isEmptyValue}
296
+ />
297
+ )}
298
+ <InputRow
299
+ state={state}
300
+ isFocused={isFocused}
301
+ prefix={prefix}
302
+ variant={variant}
303
+ nativeInputProps={nativeInputProps}
304
+ renderInputValue={renderInputValue}
305
+ ref={innerTextInput}
306
+ isEmptyValue={isEmptyValue}
307
+ />
308
+
309
+ <StyledBottomContainer>
310
+ <ErrorOrHelpText error={error} helpText={helpText} />
311
+ <MaxLengthMessage
312
+ state={state}
313
+ currentLength={displayText.length}
314
+ maxLength={maxLength}
315
+ hideCharacterCount={hideCharacterCount}
316
+ />
317
+ </StyledBottomContainer>
318
+ </StyledInputWrapper>
319
+ <StyledSuffixContainer>
320
+ <SuffixComponent state={state} loading={loading} suffix={suffix} />
321
+ </StyledSuffixContainer>
322
+ </StyledContainer>
323
+ );
324
+ }
325
+ );
326
+
327
+ export default TextInput;
@@ -0,0 +1,95 @@
1
+ import type {
2
+ TextInputProps as NativeTextInputProps,
3
+ StyleProp,
4
+ ViewStyle,
5
+ TextStyle,
6
+ TextInput as RNTextInput,
7
+ } from 'react-native';
8
+ import type { IconName } from '@hero-design/rn';
9
+
10
+ export type TextInputHandles = Pick<
11
+ RNTextInput,
12
+ 'focus' | 'clear' | 'blur' | 'isFocused' | 'setNativeProps'
13
+ >;
14
+
15
+ export type TextInputVariant = 'text' | 'textarea';
16
+
17
+ export interface TextInputProps extends NativeTextInputProps {
18
+ /**
19
+ * Field label.
20
+ */
21
+ label?: string;
22
+ /**
23
+ * Name of Icon or ReactElement to render on the left side of the input, before the user's cursor.
24
+ */
25
+ prefix?: IconName | React.ReactElement;
26
+ /**
27
+ * Name of Icon or ReactElement to render on the right side of the input.
28
+ */
29
+ suffix?: IconName | React.ReactElement;
30
+ /**
31
+ * Additional wrapper style.
32
+ */
33
+ style?: StyleProp<ViewStyle>;
34
+ /**
35
+ * Input text style.
36
+ */
37
+ textStyle?: StyleProp<TextStyle>;
38
+ /**
39
+ * Testing id of the component.
40
+ */
41
+ testID?: string;
42
+ /**
43
+ * Accessibility label for the input (Android).
44
+ */
45
+ accessibilityLabelledBy?: string;
46
+ /**
47
+ * Error message to display.
48
+ */
49
+ error?: string;
50
+ /**
51
+ * Whether the input is required. When false, "(Optional)" will be appended to the label.
52
+ */
53
+ required?: boolean;
54
+ /**
55
+ * Placeholder text to display.
56
+ * */
57
+ placeholder?: string;
58
+ /**
59
+ * Whether the input is editable.
60
+ * */
61
+ editable?: boolean;
62
+ /**
63
+ * Whether the input is disabled.
64
+ */
65
+ disabled?: boolean;
66
+ /**
67
+ * Whether the input is loading.
68
+ */
69
+ loading?: boolean;
70
+ /**
71
+ * The max length of the input.
72
+ * If the max length is set, the input will display the current length and the max length.
73
+ * */
74
+ maxLength?: number;
75
+ /**
76
+ * Whether to hide the character count.
77
+ * */
78
+ hideCharacterCount?: boolean;
79
+ /**
80
+ * The helper text to display.
81
+ */
82
+ helpText?: string;
83
+ /**
84
+ * Customise input value renderer
85
+ */
86
+ renderInputValue?: (inputProps: NativeTextInputProps) => React.ReactNode;
87
+ /**
88
+ * Component ref.
89
+ */
90
+ ref?: React.Ref<TextInputHandles>;
91
+ /**
92
+ * Component variant.
93
+ */
94
+ variant?: TextInputVariant;
95
+ }
@@ -0,0 +1,15 @@
1
+ import '@emotion/react';
2
+ import '@emotion/native';
3
+ import type { Theme as WorkTheme } from './theme';
4
+
5
+ // Augment the emotion theme for both @emotion/react and @emotion/native
6
+ declare module '@emotion/react' {
7
+ // eslint-disable-next-line @typescript-eslint/no-empty-interface
8
+ export interface Theme extends WorkTheme {}
9
+ }
10
+
11
+ // This should make styled components automatically get the Theme type
12
+ declare module '@emotion/native' {
13
+ // eslint-disable-next-line @typescript-eslint/no-empty-interface
14
+ export interface Theme extends WorkTheme {}
15
+ }
package/src/index.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  // Re-export everything from @hero-design/rn except theme exports we want to override
2
+ import TextInput from './components/TextInput';
3
+
2
4
  export * from '@hero-design/rn';
3
5
 
4
6
  // Override theme exports with work-specific versions
@@ -12,3 +14,4 @@ export {
12
14
  } from './theme';
13
15
 
14
16
  export { default as theme } from './theme';
17
+ export { TextInput };
package/src/jest.d.ts ADDED
@@ -0,0 +1,24 @@
1
+ declare global {
2
+ namespace jest {
3
+ interface Matchers<R> {
4
+ toHaveProp(prop: string, value?: unknown): R;
5
+ toHaveStyle(style: Record<string, unknown>): R;
6
+ toBeDisabled(): R;
7
+ toBeEnabled(): R;
8
+ toBeVisible(): R;
9
+ toBeEmptyElement(): R;
10
+ toHaveTextContent(text: string | RegExp): R;
11
+ toHaveDisplayValue(value: string | RegExp): R;
12
+ toBeSelected(): R;
13
+ toBePartiallyChecked(): R;
14
+ toBeChecked(): R;
15
+ toHaveA11yLabel(label: string | RegExp): R;
16
+ toHaveA11yHint(hint: string | RegExp): R;
17
+ toHaveA11yRole(role: string): R;
18
+ toHaveA11yState(state: Record<string, boolean | string>): R;
19
+ toHaveA11yValue(value: Record<string, unknown>): R;
20
+ }
21
+ }
22
+ }
23
+
24
+ export {};
@@ -1317,7 +1317,7 @@ exports[`theme returns correct theme object 1`] = `
1317
1317
  "borderWidths": {
1318
1318
  "container": {
1319
1319
  "focused": 2,
1320
- "normal": 1,
1320
+ "normal": 2,
1321
1321
  },
1322
1322
  },
1323
1323
  "colors": {
@@ -1329,20 +1329,22 @@ exports[`theme returns correct theme object 1`] = `
1329
1329
  "readonly": "#808f91",
1330
1330
  },
1331
1331
  "borders": {
1332
- "default": "#001f23",
1332
+ "default": "#e8e9ea",
1333
1333
  "disabled": "#bfc1c5",
1334
1334
  "error": "#cb300a",
1335
- "filled": "#001f23",
1336
- "readonly": "#808f91",
1335
+ "filled": "#e8e9ea",
1336
+ "focused": "#001f23",
1337
+ "readonly": "#bfc1c5",
1337
1338
  },
1338
1339
  "containerBackground": "#ffffff",
1339
1340
  "error": "#cb300a",
1340
1341
  "labelBackground": "#ffffff",
1341
1342
  "labels": {
1342
- "default": "#001f23",
1343
+ "default": "#808f91",
1343
1344
  "disabled": "#bfc1c5",
1344
- "error": "#001f23",
1345
- "filled": "#001f23",
1345
+ "error": "#cb300a",
1346
+ "filled": "#808f91",
1347
+ "focused": "#001f23",
1346
1348
  "readonly": "#808f91",
1347
1349
  },
1348
1350
  "labelsInsideTextInput": {
@@ -1357,6 +1359,7 @@ exports[`theme returns correct theme object 1`] = `
1357
1359
  "disabled": "#bfc1c5",
1358
1360
  "error": "#cb300a",
1359
1361
  "filled": "#001f23",
1362
+ "focused": "#001f23",
1360
1363
  "readonly": "#808f91",
1361
1364
  },
1362
1365
  "placeholder": "#4d6265",
@@ -1380,8 +1383,10 @@ exports[`theme returns correct theme object 1`] = `
1380
1383
  "container": 8,
1381
1384
  },
1382
1385
  "sizes": {
1383
- "errorAndHelpTextContainerHeight": 15.692307692307693,
1386
+ "containerMinHeight": 54.92307692307692,
1387
+ "errorAndHelpTextContainerHeight": 0,
1384
1388
  "textInputMaxHeight": 141.23076923076923,
1389
+ "textInputMinHeight": 23.53846153846154,
1385
1390
  "textareaHeight": 141.23076923076923,
1386
1391
  },
1387
1392
  "space": {
@@ -1392,11 +1397,13 @@ exports[`theme returns correct theme object 1`] = `
1392
1397
  "errorContainerMarginRight": 3.9230769230769234,
1393
1398
  "errorMarginLeft": 3.9230769230769234,
1394
1399
  "inputHorizontalMargin": 7.846153846153847,
1400
+ "inputWrapperMarginVertical": 7.846153846153847,
1395
1401
  "labelHorizontalPadding": 3.9230769230769234,
1396
1402
  "labelInsideTextInputMarginTop": -1.9615384615384617,
1397
1403
  "labelLeft": 31.384615384615387,
1398
1404
  "labelPaddingBottom": 7.846153846153847,
1399
1405
  "labelTop": 10.461538461538462,
1406
+ "prefixAndInputContainerGap": 3.9230769230769234,
1400
1407
  },
1401
1408
  },
1402
1409
  "timePicker": {
@@ -8,12 +8,38 @@ const getTextInputTheme = (theme: Theme) => {
8
8
  ...baseTextInputTheme.colors,
9
9
  // Example: override specific colors
10
10
  // text: theme.colors.customTextColor,
11
+ borders: {
12
+ default: theme.colors.secondaryOutline,
13
+ error: theme.colors.onErrorSurface,
14
+ disabled: theme.colors.disabledOutline,
15
+ readonly: theme.colors.disabledOutline,
16
+ filled: theme.colors.secondaryOutline,
17
+ focused: theme.colors.primaryOutline,
18
+ },
19
+ labels: {
20
+ default: theme.colors.inactiveOnDefaultGlobalSurface,
21
+ error: theme.colors.onErrorSurface,
22
+ disabled: theme.colors.disabledOnDefaultGlobalSurface,
23
+ readonly: theme.colors.inactiveOnDefaultGlobalSurface,
24
+ filled: theme.colors.inactiveOnDefaultGlobalSurface,
25
+ focused: theme.colors.onDefaultGlobalSurface,
26
+ },
27
+ maxLengthLabels: {
28
+ default: theme.colors.onDefaultGlobalSurface,
29
+ error: theme.colors.onErrorSurface,
30
+ disabled: theme.colors.disabledOnDefaultGlobalSurface,
31
+ readonly: theme.colors.inactiveOnDefaultGlobalSurface,
32
+ filled: theme.colors.onDefaultGlobalSurface,
33
+ focused: theme.colors.onDefaultGlobalSurface,
34
+ },
11
35
  };
12
36
 
13
37
  const space = {
14
38
  ...baseTextInputTheme.space,
15
39
  // Example: override specific spacing
16
40
  // containerPadding: theme.space.large,
41
+ inputWrapperMarginVertical: theme.space.small,
42
+ prefixAndInputContainerGap: theme.space.xsmall,
17
43
  };
18
44
 
19
45
  const fonts = {
@@ -30,6 +56,10 @@ const getTextInputTheme = (theme: Theme) => {
30
56
 
31
57
  const borderWidths = {
32
58
  ...baseTextInputTheme.borderWidths,
59
+ container: {
60
+ ...baseTextInputTheme.borderWidths.container,
61
+ normal: theme.borderWidths.medium,
62
+ },
33
63
  };
34
64
 
35
65
  const radii = {
@@ -38,6 +68,9 @@ const getTextInputTheme = (theme: Theme) => {
38
68
 
39
69
  const sizes = {
40
70
  ...baseTextInputTheme.sizes,
71
+ containerMinHeight: theme.sizes.xxxxlarge,
72
+ errorAndHelpTextContainerHeight: 0,
73
+ textInputMinHeight: baseTextInputTheme.fontSizes.text + theme.space.small,
41
74
  };
42
75
 
43
76
  const lineHeights = {