@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.
@@ -1,7 +1,7 @@
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'> {
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['style'];
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, 'label' | 'error' | 'helperText' | 'containerStyle' | 'children'>): React.JSX.Element;
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;IAC/D,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;CACf;AASD;;GAEG;AACH,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,KAAK,EACL,UAAU,EACV,cAAc,EACd,QAAQ,GACT,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,OAAO,GAAG,YAAY,GAAG,gBAAgB,GAAG,UAAU,CAAC,qBAgCpF;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,UAAU,CAuE9C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,UAAU,CAoDtC,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 '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';
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
- {label && (<Text variant="body" weight="medium" style={styles.label}>
30
- {label}
31
- </Text>)}
32
- {children}
33
- {error && (<Text variant="caption" color="error" style={styles.helperText}>
34
- {error}
35
- </Text>)}
36
- {!error && helperText && (<Text variant="caption" color="secondary" style={styles.helperText}>
37
- {helperText}
38
- </Text>)}
39
- </View>);
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
- <View style={[
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: 'row',
78
- alignItems: 'center',
83
+ flexDirection: "row",
84
+ alignItems: "center",
79
85
  borderRadius: borderRadius.lg,
80
86
  },
81
87
  style,
82
88
  ]}>
83
- <TextInput placeholderTextColor={colors.foregroundSecondary} ref={inputRef} {...props} style={[
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
- <Button variant="ghost" icon={showPassword ? 'eye-off' : 'eye'} size="sm" onPress={() => setShowPassword(!showPassword)}/>
91
- </View>
92
- </BaseInput>);
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
- <TextInput placeholderTextColor={colors.foregroundSecondary} ref={inputRef} value={inputValue} onChangeText={inputOnChange} onBlur={inputOnBlur} onSubmitEditing={onSubmitEditing} {...props} style={[
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
- </BaseInput>);
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":"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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}\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;CACjB;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,GAAG,KAAK,EAAE,EAAE,aAAa,qBAoE5J"}
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
- {(error || controller?.fieldState.error?.message) && (<Text variant="caption" color="error" style={styles.helperText}>
48
- {error || controller?.fieldState.error?.message}
49
- </Text>)}
50
- {!error && !controller?.fieldState.error && helperText && (<Text variant="caption" color="secondary" style={styles.helperText}>
51
- {helperText}
52
- </Text>)}
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":"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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}\n\nexport function TextArea({ label, error, helperText, minHeight = 120, maxHeight, style, control, name, value, onChangeText, onBlur, ...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 },\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 {(error || controller?.fieldState.error?.message) && (\n <Text variant=\"caption\" color=\"error\" style={styles.helperText}>\n {error || controller?.fieldState.error?.message}\n </Text>\n )}\n {!error && !controller?.fieldState.error && helperText && (\n <Text variant=\"caption\" color=\"secondary\" style={styles.helperText}>\n {helperText}\n </Text>\n )}\n </View>\n );\n}\n"]}
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robin-ux/native",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Themeable React Native UI components for Expo projects",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -1,82 +1,95 @@
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';
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, '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;
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
- paddingHorizontal: spacing.md,
34
- paddingVertical: spacing.md,
35
- borderRadius: borderRadius.lg,
36
- fontSize: 16,
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
- label,
44
- error,
45
- helperText,
46
- containerStyle,
47
- children,
48
- }: Pick<InputProps, 'label' | 'error' | 'helperText' | 'containerStyle' | 'children'>) {
49
- const styles = useThemedStyles((colors) => ({
50
- label: {
51
- marginBottom: spacing.xs,
52
- color: colors.foregroundSecondary,
53
- fontSize: 14,
54
- },
55
- helperText: {
56
- marginTop: spacing.xs,
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
- return (
61
- <View style={containerStyle}>
62
- {label && (
63
- <Text variant="body" weight="medium" style={styles.label}>
64
- {label}
65
- </Text>
66
- )}
67
- {children}
68
- {error && (
69
- <Text variant="caption" color="error" style={styles.helperText}>
70
- {error}
71
- </Text>
72
- )}
73
- {!error && helperText && (
74
- <Text variant="caption" color="secondary" style={styles.helperText}>
75
- {helperText}
76
- </Text>
77
- )}
78
- </View>
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
- value,
104
- onChangeText,
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
- // Use useController if control and name are provided
117
- const controller = control && name ? useController({ control, name }) : null;
119
+ // Use useController if control and name are provided
120
+ const controller = control && name ? useController({ control, name }) : null;
118
121
 
119
- const inputValue = controller ? controller.field.value : value;
120
- const inputOnChange = controller ? controller.field.onChange : onChangeText;
121
- const inputOnBlur = controller ? controller.field.onBlur : props.onBlur;
122
- const inputRef = controller ? controller.field.ref : ref;
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
- const hasError = error || controller?.fieldState.error;
127
+ const hasError = error || controller?.fieldState.error;
125
128
 
126
- return (
127
- <BaseInput
128
- label={props.label}
129
- error={error || controller?.fieldState.error?.message}
130
- helperText={props.helperText}
131
- containerStyle={props.containerStyle}
132
- >
133
- <View
134
- style={[
135
- {
136
- backgroundColor: colors.backgroundSecondary,
137
- borderColor: hasError ? colors.error : colors.border,
138
- borderWidth: hasError ? 1 : 0,
139
- flexDirection: 'row',
140
- alignItems: 'center',
141
- borderRadius: borderRadius.lg,
142
- },
143
- style as ViewStyle,
144
- ]}
145
- >
146
- <TextInput
147
- placeholderTextColor={colors.foregroundSecondary}
148
- ref={inputRef as any}
149
- {...props}
150
- style={[
151
- inputStyles,
152
- {
153
- flex: 1,
154
- color: colors.foreground,
155
- },
156
- ]}
157
- value={inputValue}
158
- onChangeText={inputOnChange}
159
- autoCapitalize="none"
160
- onBlur={inputOnBlur}
161
- onSubmitEditing={onSubmitEditing}
162
- secureTextEntry={!showPassword}
163
- />
164
- <Button
165
- variant="ghost"
166
- icon={showPassword ? 'eye-off' : 'eye'}
167
- size="sm"
168
- onPress={() => setShowPassword(!showPassword)}
169
- />
170
- </View>
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
- value,
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
- // Use useController if control and name are provided
210
- const controller = control && name ? useController({ control, name }) : null;
200
+ // Use useController if control and name are provided
201
+ const controller = control && name ? useController({ control, name }) : null;
211
202
 
212
- const inputValue = controller ? controller.field.value : value;
213
- const inputOnChange = controller ? controller.field.onChange : onChangeText;
214
- const inputOnBlur = controller ? controller.field.onBlur : props.onBlur;
215
- const inputRef = controller ? controller.field.ref : ref;
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
- const hasError = error || controller?.fieldState.error;
208
+ const hasError = error || controller?.fieldState.error;
218
209
 
219
- return (
220
- <BaseInput
221
- label={props.label}
222
- error={error || controller?.fieldState.error?.message}
223
- helperText={props.helperText}
224
- containerStyle={props.containerStyle}
225
- >
226
- <TextInput
227
- placeholderTextColor={colors.foregroundSecondary}
228
- ref={inputRef as any}
229
- value={inputValue}
230
- onChangeText={inputOnChange}
231
- onBlur={inputOnBlur}
232
- onSubmitEditing={onSubmitEditing}
233
- {...props}
234
- style={[
235
- inputStyles,
236
- {
237
- backgroundColor: colors.backgroundSecondary,
238
- color: colors.foreground,
239
- borderColor: hasError ? colors.error : colors.border,
240
- borderWidth: hasError ? 1 : 0,
241
- borderRadius: borderRadius.lg,
242
- },
243
- style,
244
- ]}
245
- />
246
- </BaseInput>
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
- {(error || controller?.fieldState.error?.message) && (
76
- <Text variant="caption" color="error" style={styles.helperText}>
77
- {error || controller?.fieldState.error?.message}
78
- </Text>
79
- )}
80
- {!error && !controller?.fieldState.error && helperText && (
81
- <Text variant="caption" color="secondary" style={styles.helperText}>
82
- {helperText}
83
- </Text>
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
  }