@robin-ux/native 0.1.4 → 0.1.5
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.
- package/build/components/Input.d.ts +8 -6
- package/build/components/Input.d.ts.map +1 -1
- package/build/components/Input.js +36 -30
- package/build/components/Input.js.map +1 -1
- package/build/components/TextArea.d.ts +2 -1
- package/build/components/TextArea.d.ts.map +1 -1
- package/build/components/TextArea.js +19 -7
- package/build/components/TextArea.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Input.tsx +177 -183
- package/src/components/TextArea.tsx +26 -11
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import React from
|
|
2
|
-
import { Control } from
|
|
3
|
-
import { TextInput, TextInputProps, ViewStyle } from
|
|
4
|
-
export interface InputProps extends Omit<TextInputProps,
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Control } from "react-hook-form";
|
|
3
|
+
import { TextInput, TextInputProps, ViewStyle } from "react-native";
|
|
4
|
+
export interface InputProps extends Omit<TextInputProps, "style"> {
|
|
5
5
|
/** Field label */
|
|
6
6
|
label?: string;
|
|
7
7
|
/** Error message to display */
|
|
@@ -9,7 +9,7 @@ export interface InputProps extends Omit<TextInputProps, 'style'> {
|
|
|
9
9
|
/** Helper text below input */
|
|
10
10
|
helperText?: string;
|
|
11
11
|
/** Custom input style */
|
|
12
|
-
style?: TextInputProps[
|
|
12
|
+
style?: TextInputProps["style"];
|
|
13
13
|
/** Container style */
|
|
14
14
|
containerStyle?: ViewStyle;
|
|
15
15
|
/** Input ref */
|
|
@@ -22,11 +22,13 @@ export interface InputProps extends Omit<TextInputProps, 'style'> {
|
|
|
22
22
|
control?: Control<any>;
|
|
23
23
|
/** Field name for React Hook Form (optional) */
|
|
24
24
|
name?: string;
|
|
25
|
+
maxLength?: number;
|
|
26
|
+
required?: boolean;
|
|
25
27
|
}
|
|
26
28
|
/**
|
|
27
29
|
* Base input wrapper providing label, error, and helper text layout.
|
|
28
30
|
*/
|
|
29
|
-
export declare function BaseInput({ label, error, helperText, containerStyle, children, }: Pick<InputProps,
|
|
31
|
+
export declare function BaseInput({ label, error, helperText, containerStyle, children, maxLength, value, required, }: Pick<InputProps, "label" | "error" | "helperText" | "containerStyle" | "children" | "maxLength" | "value" | "required">): React.JSX.Element;
|
|
30
32
|
/**
|
|
31
33
|
* Password input with visibility toggle.
|
|
32
34
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Input.d.ts","sourceRoot":"","sources":["../../src/components/Input.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AACxC,OAAO,EAAE,OAAO,EAAiB,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,cAAc,EAAQ,SAAS,EAAE,MAAM,cAAc,CAAC;AAM1E,MAAM,WAAW,UAAW,SAAQ,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"Input.d.ts","sourceRoot":"","sources":["../../src/components/Input.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AACxC,OAAO,EAAE,OAAO,EAAiB,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,cAAc,EAAQ,SAAS,EAAE,MAAM,cAAc,CAAC;AAM1E,MAAM,WAAW,UAAW,SAAQ,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC;IAC7D,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+BAA+B;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8BAA8B;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yBAAyB;IACzB,KAAK,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC;IAChC,sBAAsB;IACtB,cAAc,CAAC,EAAE,SAAS,CAAC;IAC3B,gBAAgB;IAChB,GAAG,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IACxC,gDAAgD;IAChD,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC7B,qBAAqB;IACrB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,gDAAgD;IAChD,OAAO,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IACvB,gDAAgD;IAChD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB;AASD;;GAEG;AACH,wBAAgB,SAAS,CAAC,EACtB,KAAK,EACL,KAAK,EACL,UAAU,EACV,cAAc,EACd,QAAQ,EACR,SAAS,EACT,KAAK,EACL,QAAQ,GACX,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,OAAO,GAAG,YAAY,GAAG,gBAAgB,GAAG,UAAU,GAAG,WAAW,GAAG,OAAO,GAAG,UAAU,CAAC,qBAwCzH;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,UAAU,CA2D9C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,UAAU,CA6CtC,CAAC"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import React, { useState } from
|
|
2
|
-
import { useController } from
|
|
3
|
-
import { TextInput, View } from
|
|
4
|
-
import { useThemeSafe } from
|
|
5
|
-
import { borderRadius, spacing, useThemedStyles } from
|
|
6
|
-
import { Button } from
|
|
7
|
-
import { Text } from
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { useController } from "react-hook-form";
|
|
3
|
+
import { TextInput, View } from "react-native";
|
|
4
|
+
import { useThemeSafe } from "../theme";
|
|
5
|
+
import { borderRadius, spacing, useThemedStyles } from "../utils/styles";
|
|
6
|
+
import { Button } from "./Button";
|
|
7
|
+
import { Text } from "./Text";
|
|
8
8
|
const inputStyles = {
|
|
9
9
|
paddingHorizontal: spacing.md,
|
|
10
10
|
paddingVertical: spacing.md,
|
|
@@ -14,7 +14,7 @@ const inputStyles = {
|
|
|
14
14
|
/**
|
|
15
15
|
* Base input wrapper providing label, error, and helper text layout.
|
|
16
16
|
*/
|
|
17
|
-
export function BaseInput({ label, error, helperText, containerStyle, children, }) {
|
|
17
|
+
export function BaseInput({ label, error, helperText, containerStyle, children, maxLength, value, required, }) {
|
|
18
18
|
const styles = useThemedStyles((colors) => ({
|
|
19
19
|
label: {
|
|
20
20
|
marginBottom: spacing.xs,
|
|
@@ -24,19 +24,25 @@ export function BaseInput({ label, error, helperText, containerStyle, children,
|
|
|
24
24
|
helperText: {
|
|
25
25
|
marginTop: spacing.xs,
|
|
26
26
|
},
|
|
27
|
+
charCount: {
|
|
28
|
+
textAlign: "right",
|
|
29
|
+
},
|
|
27
30
|
}));
|
|
28
31
|
return (<View style={containerStyle}>
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
32
|
+
{label && (<Text variant="body" weight="medium" style={styles.label}>
|
|
33
|
+
{label} {required && <Text color="error">*</Text>}
|
|
34
|
+
</Text>)}
|
|
35
|
+
{children}
|
|
36
|
+
{error && (<Text variant="caption" color="error" style={styles.helperText}>
|
|
37
|
+
{error}
|
|
38
|
+
</Text>)}
|
|
39
|
+
{!error && helperText && (<Text variant="caption" color="secondary" style={styles.helperText}>
|
|
40
|
+
{helperText}
|
|
41
|
+
</Text>)}
|
|
42
|
+
{maxLength && (<Text variant="label" color="tertiary" style={styles.charCount}>
|
|
43
|
+
{value?.length || 0}/{maxLength} characters
|
|
44
|
+
</Text>)}
|
|
45
|
+
</View>);
|
|
40
46
|
}
|
|
41
47
|
/**
|
|
42
48
|
* Password input with visibility toggle.
|
|
@@ -68,28 +74,28 @@ export const PasswordInput = ({ value, onChangeText, style, onSubmitEditing, ref
|
|
|
68
74
|
const inputOnBlur = controller ? controller.field.onBlur : props.onBlur;
|
|
69
75
|
const inputRef = controller ? controller.field.ref : ref;
|
|
70
76
|
const hasError = error || controller?.fieldState.error;
|
|
71
|
-
return (<BaseInput label={props.label} error={error || controller?.fieldState.error?.message} helperText={props.helperText} containerStyle={props.containerStyle}>
|
|
72
|
-
|
|
77
|
+
return (<BaseInput value={inputValue} label={props.label} error={error || controller?.fieldState.error?.message} helperText={props.helperText} containerStyle={props.containerStyle} required={props.required} maxLength={props.maxLength}>
|
|
78
|
+
<View style={[
|
|
73
79
|
{
|
|
74
80
|
backgroundColor: colors.backgroundSecondary,
|
|
75
81
|
borderColor: hasError ? colors.error : colors.border,
|
|
76
82
|
borderWidth: hasError ? 1 : 0,
|
|
77
|
-
flexDirection:
|
|
78
|
-
alignItems:
|
|
83
|
+
flexDirection: "row",
|
|
84
|
+
alignItems: "center",
|
|
79
85
|
borderRadius: borderRadius.lg,
|
|
80
86
|
},
|
|
81
87
|
style,
|
|
82
88
|
]}>
|
|
83
|
-
|
|
89
|
+
<TextInput placeholderTextColor={colors.foregroundSecondary} ref={inputRef} {...props} style={[
|
|
84
90
|
inputStyles,
|
|
85
91
|
{
|
|
86
92
|
flex: 1,
|
|
87
93
|
color: colors.foreground,
|
|
88
94
|
},
|
|
89
95
|
]} value={inputValue} onChangeText={inputOnChange} autoCapitalize="none" onBlur={inputOnBlur} onSubmitEditing={onSubmitEditing} secureTextEntry={!showPassword}/>
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
96
|
+
<Button variant="ghost" icon={showPassword ? "eye-off" : "eye"} size="sm" onPress={() => setShowPassword(!showPassword)}/>
|
|
97
|
+
</View>
|
|
98
|
+
</BaseInput>);
|
|
93
99
|
};
|
|
94
100
|
/**
|
|
95
101
|
* Text input component with label, error, and helper text support.
|
|
@@ -121,8 +127,8 @@ export const Input = ({ value, error, onChangeText, onSubmitEditing, style, ref,
|
|
|
121
127
|
const inputOnBlur = controller ? controller.field.onBlur : props.onBlur;
|
|
122
128
|
const inputRef = controller ? controller.field.ref : ref;
|
|
123
129
|
const hasError = error || controller?.fieldState.error;
|
|
124
|
-
return (<BaseInput label={props.label} error={error || controller?.fieldState.error?.message} helperText={props.helperText} containerStyle={props.containerStyle}>
|
|
125
|
-
|
|
130
|
+
return (<BaseInput label={props.label} value={inputValue} error={error || controller?.fieldState.error?.message} helperText={props.helperText} containerStyle={props.containerStyle} required={props.required} maxLength={props.maxLength}>
|
|
131
|
+
<TextInput placeholderTextColor={colors.foregroundSecondary} ref={inputRef} value={inputValue} onChangeText={inputOnChange} onBlur={inputOnBlur} onSubmitEditing={onSubmitEditing} {...props} style={[
|
|
126
132
|
inputStyles,
|
|
127
133
|
{
|
|
128
134
|
backgroundColor: colors.backgroundSecondary,
|
|
@@ -133,6 +139,6 @@ export const Input = ({ value, error, onChangeText, onSubmitEditing, style, ref,
|
|
|
133
139
|
},
|
|
134
140
|
style,
|
|
135
141
|
]}/>
|
|
136
|
-
|
|
142
|
+
</BaseInput>);
|
|
137
143
|
};
|
|
138
144
|
//# sourceMappingURL=Input.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Input.js","sourceRoot":"","sources":["../../src/components/Input.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACxC,OAAO,EAAW,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,SAAS,EAAkB,IAAI,EAAa,MAAM,cAAc,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACzE,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAyB9B,MAAM,WAAW,GAAG;IAClB,iBAAiB,EAAE,OAAO,CAAC,EAAE;IAC7B,eAAe,EAAE,OAAO,CAAC,EAAE;IAC3B,YAAY,EAAE,YAAY,CAAC,EAAE;IAC7B,QAAQ,EAAE,EAAE;CACb,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,EACxB,KAAK,EACL,KAAK,EACL,UAAU,EACV,cAAc,EACd,QAAQ,GAC2E;IACnF,MAAM,MAAM,GAAG,eAAe,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC1C,KAAK,EAAE;YACL,YAAY,EAAE,OAAO,CAAC,EAAE;YACxB,KAAK,EAAE,MAAM,CAAC,mBAAmB;YACjC,QAAQ,EAAE,EAAE;SACb;QACD,UAAU,EAAE;YACV,SAAS,EAAE,OAAO,CAAC,EAAE;SACtB;KACF,CAAC,CAAC,CAAC;IAEJ,OAAO,CACL,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,cAAc,CAAC,CAC1B;MAAA,CAAC,KAAK,IAAI,CACR,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CACvD;UAAA,CAAC,KAAK,CACR;QAAA,EAAE,IAAI,CAAC,CACR,CACD;MAAA,CAAC,QAAQ,CACT;MAAA,CAAC,KAAK,IAAI,CACR,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAC7D;UAAA,CAAC,KAAK,CACR;QAAA,EAAE,IAAI,CAAC,CACR,CACD;MAAA,CAAC,CAAC,KAAK,IAAI,UAAU,IAAI,CACvB,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CACjE;UAAA,CAAC,UAAU,CACb;QAAA,EAAE,IAAI,CAAC,CACR,CACH;IAAA,EAAE,IAAI,CAAC,CACR,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,aAAa,GAAyB,CAAC,EAClD,KAAK,EACL,YAAY,EACZ,KAAK,EACL,eAAe,EACf,GAAG,EACH,KAAK,EACL,OAAO,EACP,IAAI,EACJ,GAAG,KAAK,EACT,EAAE,EAAE;IACH,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACxD,MAAM,EAAE,MAAM,EAAE,GAAG,YAAY,EAAE,CAAC;IAElC,qDAAqD;IACrD,MAAM,UAAU,GAAG,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAE7E,MAAM,UAAU,GAAG,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;IAC/D,MAAM,aAAa,GAAG,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC;IAC5E,MAAM,WAAW,GAAG,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;IACxE,MAAM,QAAQ,GAAG,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IAEzD,MAAM,QAAQ,GAAG,KAAK,IAAI,UAAU,EAAE,UAAU,CAAC,KAAK,CAAC;IAEvD,OAAO,CACL,CAAC,SAAS,CACR,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CACnB,KAAK,CAAC,CAAC,KAAK,IAAI,UAAU,EAAE,UAAU,CAAC,KAAK,EAAE,OAAO,CAAC,CACtD,UAAU,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAC7B,cAAc,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAErC;MAAA,CAAC,IAAI,CACH,KAAK,CAAC,CAAC;YACL;gBACE,eAAe,EAAE,MAAM,CAAC,mBAAmB;gBAC3C,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM;gBACpD,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC7B,aAAa,EAAE,KAAK;gBACpB,UAAU,EAAE,QAAQ;gBACpB,YAAY,EAAE,YAAY,CAAC,EAAE;aAC9B;YACD,KAAkB;SACnB,CAAC,CAEF;QAAA,CAAC,SAAS,CACR,oBAAoB,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,CACjD,GAAG,CAAC,CAAC,QAAe,CAAC,CACrB,IAAI,KAAK,CAAC,CACV,KAAK,CAAC,CAAC;YACL,WAAW;YACX;gBACE,IAAI,EAAE,CAAC;gBACP,KAAK,EAAE,MAAM,CAAC,UAAU;aACzB;SACF,CAAC,CACF,KAAK,CAAC,CAAC,UAAU,CAAC,CAClB,YAAY,CAAC,CAAC,aAAa,CAAC,CAC5B,cAAc,CAAC,MAAM,CACrB,MAAM,CAAC,CAAC,WAAW,CAAC,CACpB,eAAe,CAAC,CAAC,eAAe,CAAC,CACjC,eAAe,CAAC,CAAC,CAAC,YAAY,CAAC,EAEjC;QAAA,CAAC,MAAM,CACL,OAAO,CAAC,OAAO,CACf,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CACvC,IAAI,CAAC,IAAI,CACT,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,CAAC,YAAY,CAAC,CAAC,EAElD;MAAA,EAAE,IAAI,CACR;IAAA,EAAE,SAAS,CAAC,CACb,CAAC;AACJ,CAAC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,MAAM,KAAK,GAAyB,CAAC,EAC1C,KAAK,EACL,KAAK,EACL,YAAY,EACZ,eAAe,EACf,KAAK,EACL,GAAG,EACH,OAAO,EACP,IAAI,EACJ,GAAG,KAAK,EACT,EAAE,EAAE;IACH,MAAM,EAAE,MAAM,EAAE,GAAG,YAAY,EAAE,CAAC;IAElC,qDAAqD;IACrD,MAAM,UAAU,GAAG,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAE7E,MAAM,UAAU,GAAG,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;IAC/D,MAAM,aAAa,GAAG,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC;IAC5E,MAAM,WAAW,GAAG,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;IACxE,MAAM,QAAQ,GAAG,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IAEzD,MAAM,QAAQ,GAAG,KAAK,IAAI,UAAU,EAAE,UAAU,CAAC,KAAK,CAAC;IAEvD,OAAO,CACL,CAAC,SAAS,CACR,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CACnB,KAAK,CAAC,CAAC,KAAK,IAAI,UAAU,EAAE,UAAU,CAAC,KAAK,EAAE,OAAO,CAAC,CACtD,UAAU,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAC7B,cAAc,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAErC;MAAA,CAAC,SAAS,CACR,oBAAoB,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,CACjD,GAAG,CAAC,CAAC,QAAe,CAAC,CACrB,KAAK,CAAC,CAAC,UAAU,CAAC,CAClB,YAAY,CAAC,CAAC,aAAa,CAAC,CAC5B,MAAM,CAAC,CAAC,WAAW,CAAC,CACpB,eAAe,CAAC,CAAC,eAAe,CAAC,CACjC,IAAI,KAAK,CAAC,CACV,KAAK,CAAC,CAAC;YACL,WAAW;YACX;gBACE,eAAe,EAAE,MAAM,CAAC,mBAAmB;gBAC3C,KAAK,EAAE,MAAM,CAAC,UAAU;gBACxB,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM;gBACpD,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC7B,YAAY,EAAE,YAAY,CAAC,EAAE;aAC9B;YACD,KAAK;SACN,CAAC,EAEN;IAAA,EAAE,SAAS,CAAC,CACb,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import React, { useState } from 'react';\nimport { Control, useController } from 'react-hook-form';\nimport { TextInput, TextInputProps, View, ViewStyle } from 'react-native';\nimport { useThemeSafe } from '../theme';\nimport { borderRadius, spacing, useThemedStyles } from '../utils/styles';\nimport { Button } from './Button';\nimport { Text } from './Text';\n\nexport interface InputProps extends Omit<TextInputProps, 'style'> {\n /** Field label */\n label?: string;\n /** Error message to display */\n error?: string;\n /** Helper text below input */\n helperText?: string;\n /** Custom input style */\n style?: TextInputProps['style'];\n /** Container style */\n containerStyle?: ViewStyle;\n /** Input ref */\n ref?: React.RefObject<TextInput | null>;\n /** Element to render at the end of the input */\n endElement?: React.ReactNode;\n /** Child elements */\n children?: React.ReactNode;\n /** React Hook Form control object (optional) */\n control?: Control<any>;\n /** Field name for React Hook Form (optional) */\n name?: string;\n}\n\nconst inputStyles = {\n paddingHorizontal: spacing.md,\n paddingVertical: spacing.md,\n borderRadius: borderRadius.lg,\n fontSize: 16,\n};\n\n/**\n * Base input wrapper providing label, error, and helper text layout.\n */\nexport function BaseInput({\n label,\n error,\n helperText,\n containerStyle,\n children,\n}: Pick<InputProps, 'label' | 'error' | 'helperText' | 'containerStyle' | 'children'>) {\n const styles = useThemedStyles((colors) => ({\n label: {\n marginBottom: spacing.xs,\n color: colors.foregroundSecondary,\n fontSize: 14,\n },\n helperText: {\n marginTop: spacing.xs,\n },\n }));\n\n return (\n <View style={containerStyle}>\n {label && (\n <Text variant=\"body\" weight=\"medium\" style={styles.label}>\n {label}\n </Text>\n )}\n {children}\n {error && (\n <Text variant=\"caption\" color=\"error\" style={styles.helperText}>\n {error}\n </Text>\n )}\n {!error && helperText && (\n <Text variant=\"caption\" color=\"secondary\" style={styles.helperText}>\n {helperText}\n </Text>\n )}\n </View>\n );\n}\n\n/**\n * Password input with visibility toggle.\n *\n * @example\n * ```tsx\n * <PasswordInput\n * label=\"Password\"\n * placeholder=\"Enter your password\"\n * value={password}\n * onChangeText={setPassword}\n * />\n *\n * // With React Hook Form\n * <PasswordInput\n * label=\"Password\"\n * control={control}\n * name=\"password\"\n * />\n * ```\n */\nexport const PasswordInput: React.FC<InputProps> = ({\n value,\n onChangeText,\n style,\n onSubmitEditing,\n ref,\n error,\n control,\n name,\n ...props\n}) => {\n const [showPassword, setShowPassword] = useState(false);\n const { colors } = useThemeSafe();\n\n // Use useController if control and name are provided\n const controller = control && name ? useController({ control, name }) : null;\n\n const inputValue = controller ? controller.field.value : value;\n const inputOnChange = controller ? controller.field.onChange : onChangeText;\n const inputOnBlur = controller ? controller.field.onBlur : props.onBlur;\n const inputRef = controller ? controller.field.ref : ref;\n\n const hasError = error || controller?.fieldState.error;\n\n return (\n <BaseInput\n label={props.label}\n error={error || controller?.fieldState.error?.message}\n helperText={props.helperText}\n containerStyle={props.containerStyle}\n >\n <View\n style={[\n {\n backgroundColor: colors.backgroundSecondary,\n borderColor: hasError ? colors.error : colors.border,\n borderWidth: hasError ? 1 : 0,\n flexDirection: 'row',\n alignItems: 'center',\n borderRadius: borderRadius.lg,\n },\n style as ViewStyle,\n ]}\n >\n <TextInput\n placeholderTextColor={colors.foregroundSecondary}\n ref={inputRef as any}\n {...props}\n style={[\n inputStyles,\n {\n flex: 1,\n color: colors.foreground,\n },\n ]}\n value={inputValue}\n onChangeText={inputOnChange}\n autoCapitalize=\"none\"\n onBlur={inputOnBlur}\n onSubmitEditing={onSubmitEditing}\n secureTextEntry={!showPassword}\n />\n <Button\n variant=\"ghost\"\n icon={showPassword ? 'eye-off' : 'eye'}\n size=\"sm\"\n onPress={() => setShowPassword(!showPassword)}\n />\n </View>\n </BaseInput>\n );\n};\n\n/**\n * Text input component with label, error, and helper text support.\n *\n * @example\n * ```tsx\n * <Input\n * label=\"Email\"\n * placeholder=\"Enter your email\"\n * value={email}\n * onChangeText={setEmail}\n * keyboardType=\"email-address\"\n * />\n *\n * // With React Hook Form\n * <Input\n * label=\"Email\"\n * control={control}\n * name=\"email\"\n * />\n * ```\n */\nexport const Input: React.FC<InputProps> = ({\n value,\n error,\n onChangeText,\n onSubmitEditing,\n style,\n ref,\n control,\n name,\n ...props\n}) => {\n const { colors } = useThemeSafe();\n\n // Use useController if control and name are provided\n const controller = control && name ? useController({ control, name }) : null;\n\n const inputValue = controller ? controller.field.value : value;\n const inputOnChange = controller ? controller.field.onChange : onChangeText;\n const inputOnBlur = controller ? controller.field.onBlur : props.onBlur;\n const inputRef = controller ? controller.field.ref : ref;\n\n const hasError = error || controller?.fieldState.error;\n\n return (\n <BaseInput\n label={props.label}\n error={error || controller?.fieldState.error?.message}\n helperText={props.helperText}\n containerStyle={props.containerStyle}\n >\n <TextInput\n placeholderTextColor={colors.foregroundSecondary}\n ref={inputRef as any}\n value={inputValue}\n onChangeText={inputOnChange}\n onBlur={inputOnBlur}\n onSubmitEditing={onSubmitEditing}\n {...props}\n style={[\n inputStyles,\n {\n backgroundColor: colors.backgroundSecondary,\n color: colors.foreground,\n borderColor: hasError ? colors.error : colors.border,\n borderWidth: hasError ? 1 : 0,\n borderRadius: borderRadius.lg,\n },\n style,\n ]}\n />\n </BaseInput>\n );\n};\n"]}
|
|
1
|
+
{"version":3,"file":"Input.js","sourceRoot":"","sources":["../../src/components/Input.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useState } from \"react\";\nimport { Control, useController } from \"react-hook-form\";\nimport { TextInput, TextInputProps, View, ViewStyle } from \"react-native\";\nimport { useThemeSafe } from \"../theme\";\nimport { borderRadius, spacing, useThemedStyles } from \"../utils/styles\";\nimport { Button } from \"./Button\";\nimport { Text } from \"./Text\";\n\nexport interface InputProps extends Omit<TextInputProps, \"style\"> {\n /** Field label */\n label?: string;\n /** Error message to display */\n error?: string;\n /** Helper text below input */\n helperText?: string;\n /** Custom input style */\n style?: TextInputProps[\"style\"];\n /** Container style */\n containerStyle?: ViewStyle;\n /** Input ref */\n ref?: React.RefObject<TextInput | null>;\n /** Element to render at the end of the input */\n endElement?: React.ReactNode;\n /** Child elements */\n children?: React.ReactNode;\n /** React Hook Form control object (optional) */\n control?: Control<any>;\n /** Field name for React Hook Form (optional) */\n name?: string;\n maxLength?: number;\n required?: boolean;\n}\n\nconst inputStyles = {\n paddingHorizontal: spacing.md,\n paddingVertical: spacing.md,\n borderRadius: borderRadius.lg,\n fontSize: 16,\n};\n\n/**\n * Base input wrapper providing label, error, and helper text layout.\n */\nexport function BaseInput({\n label,\n error,\n helperText,\n containerStyle,\n children,\n maxLength,\n value,\n required,\n}: Pick<InputProps, \"label\" | \"error\" | \"helperText\" | \"containerStyle\" | \"children\" | \"maxLength\" | \"value\" | \"required\">) {\n const styles = useThemedStyles((colors) => ({\n label: {\n marginBottom: spacing.xs,\n color: colors.foregroundSecondary,\n fontSize: 14,\n },\n helperText: {\n marginTop: spacing.xs,\n },\n charCount: {\n textAlign: \"right\",\n },\n }));\n\n return (\n <View style={containerStyle}>\n {label && (\n <Text variant=\"body\" weight=\"medium\" style={styles.label}>\n {label} {required && <Text color=\"error\">*</Text>}\n </Text>\n )}\n {children}\n {error && (\n <Text variant=\"caption\" color=\"error\" style={styles.helperText}>\n {error}\n </Text>\n )}\n {!error && helperText && (\n <Text variant=\"caption\" color=\"secondary\" style={styles.helperText}>\n {helperText}\n </Text>\n )}\n {maxLength && (\n <Text variant=\"label\" color=\"tertiary\" style={styles.charCount}>\n {value?.length || 0}/{maxLength} characters\n </Text>\n )}\n </View>\n );\n}\n\n/**\n * Password input with visibility toggle.\n *\n * @example\n * ```tsx\n * <PasswordInput\n * label=\"Password\"\n * placeholder=\"Enter your password\"\n * value={password}\n * onChangeText={setPassword}\n * />\n *\n * // With React Hook Form\n * <PasswordInput\n * label=\"Password\"\n * control={control}\n * name=\"password\"\n * />\n * ```\n */\nexport const PasswordInput: React.FC<InputProps> = ({ value, onChangeText, style, onSubmitEditing, ref, error, control, name, ...props }) => {\n const [showPassword, setShowPassword] = useState(false);\n const { colors } = useThemeSafe();\n\n // Use useController if control and name are provided\n const controller = control && name ? useController({ control, name }) : null;\n\n const inputValue = controller ? controller.field.value : value;\n const inputOnChange = controller ? controller.field.onChange : onChangeText;\n const inputOnBlur = controller ? controller.field.onBlur : props.onBlur;\n const inputRef = controller ? controller.field.ref : ref;\n\n const hasError = error || controller?.fieldState.error;\n\n return (\n <BaseInput\n value={inputValue}\n label={props.label}\n error={error || controller?.fieldState.error?.message}\n helperText={props.helperText}\n containerStyle={props.containerStyle}\n required={props.required}\n maxLength={props.maxLength}\n >\n <View\n style={[\n {\n backgroundColor: colors.backgroundSecondary,\n borderColor: hasError ? colors.error : colors.border,\n borderWidth: hasError ? 1 : 0,\n flexDirection: \"row\",\n alignItems: \"center\",\n borderRadius: borderRadius.lg,\n },\n style as ViewStyle,\n ]}\n >\n <TextInput\n placeholderTextColor={colors.foregroundSecondary}\n ref={inputRef as any}\n {...props}\n style={[\n inputStyles,\n {\n flex: 1,\n color: colors.foreground,\n },\n ]}\n value={inputValue}\n onChangeText={inputOnChange}\n autoCapitalize=\"none\"\n onBlur={inputOnBlur}\n onSubmitEditing={onSubmitEditing}\n secureTextEntry={!showPassword}\n />\n <Button variant=\"ghost\" icon={showPassword ? \"eye-off\" : \"eye\"} size=\"sm\" onPress={() => setShowPassword(!showPassword)} />\n </View>\n </BaseInput>\n );\n};\n\n/**\n * Text input component with label, error, and helper text support.\n *\n * @example\n * ```tsx\n * <Input\n * label=\"Email\"\n * placeholder=\"Enter your email\"\n * value={email}\n * onChangeText={setEmail}\n * keyboardType=\"email-address\"\n * />\n *\n * // With React Hook Form\n * <Input\n * label=\"Email\"\n * control={control}\n * name=\"email\"\n * />\n * ```\n */\nexport const Input: React.FC<InputProps> = ({ value, error, onChangeText, onSubmitEditing, style, ref, control, name, ...props }) => {\n const { colors } = useThemeSafe();\n\n // Use useController if control and name are provided\n const controller = control && name ? useController({ control, name }) : null;\n\n const inputValue = controller ? controller.field.value : value;\n const inputOnChange = controller ? controller.field.onChange : onChangeText;\n const inputOnBlur = controller ? controller.field.onBlur : props.onBlur;\n const inputRef = controller ? controller.field.ref : ref;\n\n const hasError = error || controller?.fieldState.error;\n\n return (\n <BaseInput\n label={props.label}\n value={inputValue}\n error={error || controller?.fieldState.error?.message}\n helperText={props.helperText}\n containerStyle={props.containerStyle}\n required={props.required}\n maxLength={props.maxLength}\n >\n <TextInput\n placeholderTextColor={colors.foregroundSecondary}\n ref={inputRef as any}\n value={inputValue}\n onChangeText={inputOnChange}\n onBlur={inputOnBlur}\n onSubmitEditing={onSubmitEditing}\n {...props}\n style={[\n inputStyles,\n {\n backgroundColor: colors.backgroundSecondary,\n color: colors.foreground,\n borderColor: hasError ? colors.error : colors.border,\n borderWidth: hasError ? 1 : 0,\n borderRadius: borderRadius.lg,\n },\n style,\n ]}\n />\n </BaseInput>\n );\n};\n"]}
|
|
@@ -10,6 +10,7 @@ export interface TextAreaProps extends Omit<TextInputProps, "style"> {
|
|
|
10
10
|
style?: StyleProp<ViewStyle>;
|
|
11
11
|
control?: Control<any>;
|
|
12
12
|
name?: string;
|
|
13
|
+
maxLength?: number;
|
|
13
14
|
}
|
|
14
|
-
export declare function TextArea({ label, error, helperText, minHeight, maxHeight, style, control, name, value, onChangeText, onBlur, ...props }: TextAreaProps): React.JSX.Element;
|
|
15
|
+
export declare function TextArea({ label, error, helperText, minHeight, maxHeight, style, control, name, value, onChangeText, onBlur, maxLength, ...props }: TextAreaProps): React.JSX.Element;
|
|
15
16
|
//# sourceMappingURL=TextArea.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextArea.d.ts","sourceRoot":"","sources":["../../src/components/TextArea.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,OAAO,EAAiB,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,SAAS,EAAa,cAAc,EAAQ,SAAS,EAAE,MAAM,cAAc,CAAC;AAKrF,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC;IAChE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"TextArea.d.ts","sourceRoot":"","sources":["../../src/components/TextArea.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,OAAO,EAAiB,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,SAAS,EAAa,cAAc,EAAQ,SAAS,EAAE,MAAM,cAAc,CAAC;AAKrF,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC;IAChE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,QAAQ,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,SAAe,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,aAAa,qBAkFvK"}
|
|
@@ -4,7 +4,7 @@ import { TextInput, View } from "react-native";
|
|
|
4
4
|
import { useTheme } from "../theme";
|
|
5
5
|
import { borderRadius, spacing, useThemedStyles } from "../utils";
|
|
6
6
|
import { Text } from "./Text";
|
|
7
|
-
export function TextArea({ label, error, helperText, minHeight = 120, maxHeight, style, control, name, value, onChangeText, onBlur, ...props }) {
|
|
7
|
+
export function TextArea({ label, error, helperText, minHeight = 120, maxHeight, style, control, name, value, onChangeText, onBlur, maxLength, ...props }) {
|
|
8
8
|
const { colors } = useTheme();
|
|
9
9
|
// Use useController if control and name are provided
|
|
10
10
|
const controller = control && name ? useController({ control, name }) : null;
|
|
@@ -37,6 +37,13 @@ export function TextArea({ label, error, helperText, minHeight = 120, maxHeight,
|
|
|
37
37
|
helperText: {
|
|
38
38
|
marginTop: spacing.xs,
|
|
39
39
|
fontSize: 12,
|
|
40
|
+
flexDirection: "row",
|
|
41
|
+
justifyContent: "space-between",
|
|
42
|
+
paddingHorizontal: spacing.xs,
|
|
43
|
+
},
|
|
44
|
+
charCount: {
|
|
45
|
+
marginTop: spacing.xs,
|
|
46
|
+
fontSize: 12,
|
|
40
47
|
},
|
|
41
48
|
}));
|
|
42
49
|
return (<View style={[styles.container, style]}>
|
|
@@ -44,12 +51,17 @@ export function TextArea({ label, error, helperText, minHeight = 120, maxHeight,
|
|
|
44
51
|
{label}
|
|
45
52
|
</Text>)}
|
|
46
53
|
<TextInput ref={inputRef} value={inputValue} onChangeText={inputOnChange} onBlur={inputOnBlur} placeholderTextColor={colors.foregroundSecondary} multiline {...props} style={styles.textArea}/>
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
54
|
+
<View style={styles.helperText}>
|
|
55
|
+
{(error || controller?.fieldState.error?.message) && (<Text variant="caption" color="error">
|
|
56
|
+
{error || controller?.fieldState.error?.message}
|
|
57
|
+
</Text>)}
|
|
58
|
+
{!error && !controller?.fieldState.error && helperText && (<Text variant="caption" color="secondary">
|
|
59
|
+
{helperText}
|
|
60
|
+
</Text>)}
|
|
61
|
+
{maxLength && (<Text variant="caption" color="tertiary">
|
|
62
|
+
{inputValue.length}/{maxLength}
|
|
63
|
+
</Text>)}
|
|
64
|
+
</View>
|
|
53
65
|
</View>);
|
|
54
66
|
}
|
|
55
67
|
//# sourceMappingURL=TextArea.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextArea.js","sourceRoot":"","sources":["../../src/components/TextArea.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAW,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAa,SAAS,EAAkB,IAAI,EAAa,MAAM,cAAc,CAAC;AACrF,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"TextArea.js","sourceRoot":"","sources":["../../src/components/TextArea.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from \"react\";\nimport { Control, useController } from \"react-hook-form\";\nimport { StyleProp, TextInput, TextInputProps, View, ViewStyle } from \"react-native\";\nimport { useTheme } from \"../theme\";\nimport { borderRadius, spacing, useThemedStyles } from \"../utils\";\nimport { Text } from \"./Text\";\n\nexport interface TextAreaProps extends Omit<TextInputProps, \"style\"> {\n label?: string;\n error?: string;\n helperText?: string;\n minHeight?: number;\n maxHeight?: number;\n style?: StyleProp<ViewStyle>;\n control?: Control<any>;\n name?: string;\n maxLength?: number;\n}\n\nexport function TextArea({ label, error, helperText, minHeight = 120, maxHeight, style, control, name, value, onChangeText, onBlur, maxLength, ...props }: TextAreaProps) {\n const { colors } = useTheme();\n\n // Use useController if control and name are provided\n const controller = control && name ? useController({ control, name }) : null;\n\n const inputValue = controller ? controller.field.value : value;\n const inputOnChange = controller ? controller.field.onChange : onChangeText;\n const inputOnBlur = controller ? controller.field.onBlur : onBlur;\n const inputRef = controller ? controller.field.ref : undefined;\n\n const styles = useThemedStyles((colors) => ({\n container: {\n width: \"100%\",\n },\n label: {\n marginBottom: spacing.xs,\n color: colors.foregroundSecondary,\n fontSize: 14,\n },\n textArea: {\n backgroundColor: colors.backgroundSecondary,\n borderRadius: borderRadius.lg,\n paddingHorizontal: spacing.md,\n paddingVertical: spacing.md,\n color: colors.foreground,\n fontSize: 16,\n minHeight: minHeight,\n maxHeight: maxHeight,\n textAlignVertical: \"top\",\n borderWidth: error || controller?.fieldState.error ? 1 : 0,\n borderColor: error || controller?.fieldState.error ? colors.error : \"transparent\",\n },\n helperText: {\n marginTop: spacing.xs,\n fontSize: 12,\n flexDirection: \"row\",\n justifyContent: \"space-between\",\n paddingHorizontal: spacing.xs,\n },\n charCount: {\n marginTop: spacing.xs,\n fontSize: 12,\n },\n }));\n\n return (\n <View style={[styles.container, style]}>\n {label && (\n <Text variant=\"body\" weight=\"medium\" style={styles.label}>\n {label}\n </Text>\n )}\n <TextInput\n ref={inputRef as any}\n value={inputValue}\n onChangeText={inputOnChange}\n onBlur={inputOnBlur}\n placeholderTextColor={colors.foregroundSecondary}\n multiline\n {...props}\n style={styles.textArea}\n />\n <View style={styles.helperText}>\n {(error || controller?.fieldState.error?.message) && (\n <Text variant=\"caption\" color=\"error\">\n {error || controller?.fieldState.error?.message}\n </Text>\n )}\n {!error && !controller?.fieldState.error && helperText && (\n <Text variant=\"caption\" color=\"secondary\">\n {helperText}\n </Text>\n )}\n {maxLength && (\n <Text variant=\"caption\" color=\"tertiary\">\n {inputValue.length}/{maxLength}\n </Text>\n )}\n </View>\n </View>\n );\n}\n"]}
|
package/package.json
CHANGED
package/src/components/Input.tsx
CHANGED
|
@@ -1,82 +1,95 @@
|
|
|
1
|
-
import React, { useState } from
|
|
2
|
-
import { Control, useController } from
|
|
3
|
-
import { TextInput, TextInputProps, View, ViewStyle } from
|
|
4
|
-
import { useThemeSafe } from
|
|
5
|
-
import { borderRadius, spacing, useThemedStyles } from
|
|
6
|
-
import { Button } from
|
|
7
|
-
import { Text } from
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { Control, useController } from "react-hook-form";
|
|
3
|
+
import { TextInput, TextInputProps, View, ViewStyle } from "react-native";
|
|
4
|
+
import { useThemeSafe } from "../theme";
|
|
5
|
+
import { borderRadius, spacing, useThemedStyles } from "../utils/styles";
|
|
6
|
+
import { Button } from "./Button";
|
|
7
|
+
import { Text } from "./Text";
|
|
8
8
|
|
|
9
|
-
export interface InputProps extends Omit<TextInputProps,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
9
|
+
export interface InputProps extends Omit<TextInputProps, "style"> {
|
|
10
|
+
/** Field label */
|
|
11
|
+
label?: string;
|
|
12
|
+
/** Error message to display */
|
|
13
|
+
error?: string;
|
|
14
|
+
/** Helper text below input */
|
|
15
|
+
helperText?: string;
|
|
16
|
+
/** Custom input style */
|
|
17
|
+
style?: TextInputProps["style"];
|
|
18
|
+
/** Container style */
|
|
19
|
+
containerStyle?: ViewStyle;
|
|
20
|
+
/** Input ref */
|
|
21
|
+
ref?: React.RefObject<TextInput | null>;
|
|
22
|
+
/** Element to render at the end of the input */
|
|
23
|
+
endElement?: React.ReactNode;
|
|
24
|
+
/** Child elements */
|
|
25
|
+
children?: React.ReactNode;
|
|
26
|
+
/** React Hook Form control object (optional) */
|
|
27
|
+
control?: Control<any>;
|
|
28
|
+
/** Field name for React Hook Form (optional) */
|
|
29
|
+
name?: string;
|
|
30
|
+
maxLength?: number;
|
|
31
|
+
required?: boolean;
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
const inputStyles = {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
paddingHorizontal: spacing.md,
|
|
36
|
+
paddingVertical: spacing.md,
|
|
37
|
+
borderRadius: borderRadius.lg,
|
|
38
|
+
fontSize: 16,
|
|
37
39
|
};
|
|
38
40
|
|
|
39
41
|
/**
|
|
40
42
|
* Base input wrapper providing label, error, and helper text layout.
|
|
41
43
|
*/
|
|
42
44
|
export function BaseInput({
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
45
|
+
label,
|
|
46
|
+
error,
|
|
47
|
+
helperText,
|
|
48
|
+
containerStyle,
|
|
49
|
+
children,
|
|
50
|
+
maxLength,
|
|
51
|
+
value,
|
|
52
|
+
required,
|
|
53
|
+
}: Pick<InputProps, "label" | "error" | "helperText" | "containerStyle" | "children" | "maxLength" | "value" | "required">) {
|
|
54
|
+
const styles = useThemedStyles((colors) => ({
|
|
55
|
+
label: {
|
|
56
|
+
marginBottom: spacing.xs,
|
|
57
|
+
color: colors.foregroundSecondary,
|
|
58
|
+
fontSize: 14,
|
|
59
|
+
},
|
|
60
|
+
helperText: {
|
|
61
|
+
marginTop: spacing.xs,
|
|
62
|
+
},
|
|
63
|
+
charCount: {
|
|
64
|
+
textAlign: "right",
|
|
65
|
+
},
|
|
66
|
+
}));
|
|
59
67
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
68
|
+
return (
|
|
69
|
+
<View style={containerStyle}>
|
|
70
|
+
{label && (
|
|
71
|
+
<Text variant="body" weight="medium" style={styles.label}>
|
|
72
|
+
{label} {required && <Text color="error">*</Text>}
|
|
73
|
+
</Text>
|
|
74
|
+
)}
|
|
75
|
+
{children}
|
|
76
|
+
{error && (
|
|
77
|
+
<Text variant="caption" color="error" style={styles.helperText}>
|
|
78
|
+
{error}
|
|
79
|
+
</Text>
|
|
80
|
+
)}
|
|
81
|
+
{!error && helperText && (
|
|
82
|
+
<Text variant="caption" color="secondary" style={styles.helperText}>
|
|
83
|
+
{helperText}
|
|
84
|
+
</Text>
|
|
85
|
+
)}
|
|
86
|
+
{maxLength && (
|
|
87
|
+
<Text variant="label" color="tertiary" style={styles.charCount}>
|
|
88
|
+
{value?.length || 0}/{maxLength} characters
|
|
89
|
+
</Text>
|
|
90
|
+
)}
|
|
91
|
+
</View>
|
|
92
|
+
);
|
|
80
93
|
}
|
|
81
94
|
|
|
82
95
|
/**
|
|
@@ -99,77 +112,65 @@ export function BaseInput({
|
|
|
99
112
|
* />
|
|
100
113
|
* ```
|
|
101
114
|
*/
|
|
102
|
-
export const PasswordInput: React.FC<InputProps> = ({
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
style,
|
|
106
|
-
onSubmitEditing,
|
|
107
|
-
ref,
|
|
108
|
-
error,
|
|
109
|
-
control,
|
|
110
|
-
name,
|
|
111
|
-
...props
|
|
112
|
-
}) => {
|
|
113
|
-
const [showPassword, setShowPassword] = useState(false);
|
|
114
|
-
const { colors } = useThemeSafe();
|
|
115
|
+
export const PasswordInput: React.FC<InputProps> = ({ value, onChangeText, style, onSubmitEditing, ref, error, control, name, ...props }) => {
|
|
116
|
+
const [showPassword, setShowPassword] = useState(false);
|
|
117
|
+
const { colors } = useThemeSafe();
|
|
115
118
|
|
|
116
|
-
|
|
117
|
-
|
|
119
|
+
// Use useController if control and name are provided
|
|
120
|
+
const controller = control && name ? useController({ control, name }) : null;
|
|
118
121
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
122
|
+
const inputValue = controller ? controller.field.value : value;
|
|
123
|
+
const inputOnChange = controller ? controller.field.onChange : onChangeText;
|
|
124
|
+
const inputOnBlur = controller ? controller.field.onBlur : props.onBlur;
|
|
125
|
+
const inputRef = controller ? controller.field.ref : ref;
|
|
123
126
|
|
|
124
|
-
|
|
127
|
+
const hasError = error || controller?.fieldState.error;
|
|
125
128
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
</BaseInput>
|
|
172
|
-
);
|
|
129
|
+
return (
|
|
130
|
+
<BaseInput
|
|
131
|
+
value={inputValue}
|
|
132
|
+
label={props.label}
|
|
133
|
+
error={error || controller?.fieldState.error?.message}
|
|
134
|
+
helperText={props.helperText}
|
|
135
|
+
containerStyle={props.containerStyle}
|
|
136
|
+
required={props.required}
|
|
137
|
+
maxLength={props.maxLength}
|
|
138
|
+
>
|
|
139
|
+
<View
|
|
140
|
+
style={[
|
|
141
|
+
{
|
|
142
|
+
backgroundColor: colors.backgroundSecondary,
|
|
143
|
+
borderColor: hasError ? colors.error : colors.border,
|
|
144
|
+
borderWidth: hasError ? 1 : 0,
|
|
145
|
+
flexDirection: "row",
|
|
146
|
+
alignItems: "center",
|
|
147
|
+
borderRadius: borderRadius.lg,
|
|
148
|
+
},
|
|
149
|
+
style as ViewStyle,
|
|
150
|
+
]}
|
|
151
|
+
>
|
|
152
|
+
<TextInput
|
|
153
|
+
placeholderTextColor={colors.foregroundSecondary}
|
|
154
|
+
ref={inputRef as any}
|
|
155
|
+
{...props}
|
|
156
|
+
style={[
|
|
157
|
+
inputStyles,
|
|
158
|
+
{
|
|
159
|
+
flex: 1,
|
|
160
|
+
color: colors.foreground,
|
|
161
|
+
},
|
|
162
|
+
]}
|
|
163
|
+
value={inputValue}
|
|
164
|
+
onChangeText={inputOnChange}
|
|
165
|
+
autoCapitalize="none"
|
|
166
|
+
onBlur={inputOnBlur}
|
|
167
|
+
onSubmitEditing={onSubmitEditing}
|
|
168
|
+
secureTextEntry={!showPassword}
|
|
169
|
+
/>
|
|
170
|
+
<Button variant="ghost" icon={showPassword ? "eye-off" : "eye"} size="sm" onPress={() => setShowPassword(!showPassword)} />
|
|
171
|
+
</View>
|
|
172
|
+
</BaseInput>
|
|
173
|
+
);
|
|
173
174
|
};
|
|
174
175
|
|
|
175
176
|
/**
|
|
@@ -193,56 +194,49 @@ export const PasswordInput: React.FC<InputProps> = ({
|
|
|
193
194
|
* />
|
|
194
195
|
* ```
|
|
195
196
|
*/
|
|
196
|
-
export const Input: React.FC<InputProps> = ({
|
|
197
|
-
|
|
198
|
-
error,
|
|
199
|
-
onChangeText,
|
|
200
|
-
onSubmitEditing,
|
|
201
|
-
style,
|
|
202
|
-
ref,
|
|
203
|
-
control,
|
|
204
|
-
name,
|
|
205
|
-
...props
|
|
206
|
-
}) => {
|
|
207
|
-
const { colors } = useThemeSafe();
|
|
197
|
+
export const Input: React.FC<InputProps> = ({ value, error, onChangeText, onSubmitEditing, style, ref, control, name, ...props }) => {
|
|
198
|
+
const { colors } = useThemeSafe();
|
|
208
199
|
|
|
209
|
-
|
|
210
|
-
|
|
200
|
+
// Use useController if control and name are provided
|
|
201
|
+
const controller = control && name ? useController({ control, name }) : null;
|
|
211
202
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
203
|
+
const inputValue = controller ? controller.field.value : value;
|
|
204
|
+
const inputOnChange = controller ? controller.field.onChange : onChangeText;
|
|
205
|
+
const inputOnBlur = controller ? controller.field.onBlur : props.onBlur;
|
|
206
|
+
const inputRef = controller ? controller.field.ref : ref;
|
|
216
207
|
|
|
217
|
-
|
|
208
|
+
const hasError = error || controller?.fieldState.error;
|
|
218
209
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
210
|
+
return (
|
|
211
|
+
<BaseInput
|
|
212
|
+
label={props.label}
|
|
213
|
+
value={inputValue}
|
|
214
|
+
error={error || controller?.fieldState.error?.message}
|
|
215
|
+
helperText={props.helperText}
|
|
216
|
+
containerStyle={props.containerStyle}
|
|
217
|
+
required={props.required}
|
|
218
|
+
maxLength={props.maxLength}
|
|
219
|
+
>
|
|
220
|
+
<TextInput
|
|
221
|
+
placeholderTextColor={colors.foregroundSecondary}
|
|
222
|
+
ref={inputRef as any}
|
|
223
|
+
value={inputValue}
|
|
224
|
+
onChangeText={inputOnChange}
|
|
225
|
+
onBlur={inputOnBlur}
|
|
226
|
+
onSubmitEditing={onSubmitEditing}
|
|
227
|
+
{...props}
|
|
228
|
+
style={[
|
|
229
|
+
inputStyles,
|
|
230
|
+
{
|
|
231
|
+
backgroundColor: colors.backgroundSecondary,
|
|
232
|
+
color: colors.foreground,
|
|
233
|
+
borderColor: hasError ? colors.error : colors.border,
|
|
234
|
+
borderWidth: hasError ? 1 : 0,
|
|
235
|
+
borderRadius: borderRadius.lg,
|
|
236
|
+
},
|
|
237
|
+
style,
|
|
238
|
+
]}
|
|
239
|
+
/>
|
|
240
|
+
</BaseInput>
|
|
241
|
+
);
|
|
248
242
|
};
|
|
@@ -14,9 +14,10 @@ export interface TextAreaProps extends Omit<TextInputProps, "style"> {
|
|
|
14
14
|
style?: StyleProp<ViewStyle>;
|
|
15
15
|
control?: Control<any>;
|
|
16
16
|
name?: string;
|
|
17
|
+
maxLength?: number;
|
|
17
18
|
}
|
|
18
19
|
|
|
19
|
-
export function TextArea({ label, error, helperText, minHeight = 120, maxHeight, style, control, name, value, onChangeText, onBlur, ...props }: TextAreaProps) {
|
|
20
|
+
export function TextArea({ label, error, helperText, minHeight = 120, maxHeight, style, control, name, value, onChangeText, onBlur, maxLength, ...props }: TextAreaProps) {
|
|
20
21
|
const { colors } = useTheme();
|
|
21
22
|
|
|
22
23
|
// Use useController if control and name are provided
|
|
@@ -52,6 +53,13 @@ export function TextArea({ label, error, helperText, minHeight = 120, maxHeight,
|
|
|
52
53
|
helperText: {
|
|
53
54
|
marginTop: spacing.xs,
|
|
54
55
|
fontSize: 12,
|
|
56
|
+
flexDirection: "row",
|
|
57
|
+
justifyContent: "space-between",
|
|
58
|
+
paddingHorizontal: spacing.xs,
|
|
59
|
+
},
|
|
60
|
+
charCount: {
|
|
61
|
+
marginTop: spacing.xs,
|
|
62
|
+
fontSize: 12,
|
|
55
63
|
},
|
|
56
64
|
}));
|
|
57
65
|
|
|
@@ -72,16 +80,23 @@ export function TextArea({ label, error, helperText, minHeight = 120, maxHeight,
|
|
|
72
80
|
{...props}
|
|
73
81
|
style={styles.textArea}
|
|
74
82
|
/>
|
|
75
|
-
{
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
<View style={styles.helperText}>
|
|
84
|
+
{(error || controller?.fieldState.error?.message) && (
|
|
85
|
+
<Text variant="caption" color="error">
|
|
86
|
+
{error || controller?.fieldState.error?.message}
|
|
87
|
+
</Text>
|
|
88
|
+
)}
|
|
89
|
+
{!error && !controller?.fieldState.error && helperText && (
|
|
90
|
+
<Text variant="caption" color="secondary">
|
|
91
|
+
{helperText}
|
|
92
|
+
</Text>
|
|
93
|
+
)}
|
|
94
|
+
{maxLength && (
|
|
95
|
+
<Text variant="caption" color="tertiary">
|
|
96
|
+
{inputValue.length}/{maxLength}
|
|
97
|
+
</Text>
|
|
98
|
+
)}
|
|
99
|
+
</View>
|
|
85
100
|
</View>
|
|
86
101
|
);
|
|
87
102
|
}
|