@vellira-ui/react-native 2.29.0 → 2.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +2 -2
  2. package/dist/index.js +330 -142
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -47,7 +47,7 @@ export function Example() {
47
47
 
48
48
  return (
49
49
  <View style={{ gap: 16 }}>
50
- <Input label='Email' value={email} onChange={setEmail} />
50
+ <Input label='Email' value={email} onValueChange={setEmail} />
51
51
  <Checkbox
52
52
  label='Accept terms'
53
53
  description='Required to create an account.'
@@ -100,7 +100,7 @@ export function RoleSelect() {
100
100
  <Select
101
101
  label='Role'
102
102
  value={role}
103
- onChange={setRole}
103
+ onValueChange={setRole}
104
104
  options={[
105
105
  { label: 'Admin', value: 'admin' },
106
106
  { label: 'Editor', value: 'editor' },
package/dist/index.js CHANGED
@@ -944,6 +944,7 @@ import { useControllableState as useControllableState2 } from "@vellira-ui/core"
944
944
  import { View as View11 } from "react-native";
945
945
 
946
946
  // src/patterns/FormField/FormField.tsx
947
+ import { useId } from "react";
947
948
  import { Text as Text6, View as View10 } from "react-native";
948
949
 
949
950
  // src/patterns/FormField/FormField.styles.ts
@@ -954,14 +955,14 @@ var createStyles12 = (theme) => StyleSheet12.create({
954
955
  width: "100%",
955
956
  minWidth: 0,
956
957
  alignSelf: "stretch",
957
- gap: theme.tokens.spacing[2]
958
+ gap: theme.components.formField.size.md.gap
958
959
  },
959
960
  label: {
960
961
  color: theme.components.formField.label.fg,
961
962
  fontFamily: theme.tokens.typography.family.medium,
962
- fontSize: theme.tokens.typography.size.md,
963
+ fontSize: theme.components.formField.size.md.labelFontSize,
963
964
  fontWeight: fontWeight(theme.tokens.typography.weight.medium),
964
- lineHeight: theme.tokens.typography.lineHeight.md
965
+ lineHeight: theme.components.formField.size.md.labelLineHeight
965
966
  },
966
967
  labelDisabled: {
967
968
  color: theme.components.formField.disabled.labelFg
@@ -970,11 +971,25 @@ var createStyles12 = (theme) => StyleSheet12.create({
970
971
  marginLeft: theme.tokens.spacing[1],
971
972
  color: theme.components.formField.requiredMark.fg
972
973
  },
974
+ optional: {
975
+ marginLeft: theme.components.formField.size.md.gap,
976
+ color: theme.components.formField.optional.fg,
977
+ fontFamily: theme.tokens.typography.family.regular,
978
+ fontSize: theme.components.formField.size.md.optionalFontSize,
979
+ lineHeight: theme.components.formField.size.md.optionalLineHeight
980
+ },
981
+ labelInfo: {
982
+ marginLeft: theme.components.formField.size.md.gap,
983
+ color: theme.components.formField.labelInfo.fg,
984
+ fontFamily: theme.tokens.typography.family.medium,
985
+ fontSize: theme.components.formField.size.md.labelInfoFontSize,
986
+ lineHeight: theme.components.formField.size.md.labelInfoSize
987
+ },
973
988
  description: {
974
989
  color: theme.components.formField.description.fg,
975
990
  fontFamily: theme.tokens.typography.family.regular,
976
- fontSize: theme.tokens.typography.size.sm,
977
- lineHeight: theme.tokens.typography.lineHeight.sm
991
+ fontSize: theme.components.formField.size.md.descriptionFontSize,
992
+ lineHeight: theme.components.formField.size.md.descriptionLineHeight
978
993
  },
979
994
  descriptionDisabled: {
980
995
  color: theme.components.formField.disabled.descriptionFg
@@ -992,22 +1007,32 @@ var createStyles12 = (theme) => StyleSheet12.create({
992
1007
  error: {
993
1008
  color: theme.components.formField.helperText.error.fg,
994
1009
  fontFamily: theme.tokens.typography.family.regular,
995
- fontSize: theme.tokens.typography.size.sm,
996
- lineHeight: theme.tokens.typography.lineHeight.sm
1010
+ fontSize: theme.components.formField.size.md.helperTextFontSize,
1011
+ lineHeight: theme.components.formField.size.md.helperTextLineHeight
997
1012
  },
998
1013
  helperTextDisabled: {
999
1014
  color: theme.components.formField.disabled.helperTextFg
1000
1015
  }
1001
1016
  });
1002
1017
 
1018
+ // src/patterns/FormField/FormFieldContext.ts
1019
+ import { createContext as createContext3, useContext as useContext3 } from "react";
1020
+ var FormFieldContext = createContext3(null);
1021
+ var useFormFieldContext = () => useContext3(FormFieldContext);
1022
+
1003
1023
  // src/patterns/FormField/FormField.tsx
1004
1024
  import { jsx as jsx14, jsxs as jsxs7 } from "react/jsx-runtime";
1005
1025
  function FormField({
1026
+ id,
1006
1027
  label,
1007
1028
  description,
1008
1029
  error,
1009
1030
  required = false,
1010
1031
  disabled = false,
1032
+ invalid = false,
1033
+ size = "md",
1034
+ labelInfo,
1035
+ optionalText,
1011
1036
  children,
1012
1037
  style,
1013
1038
  controlStyle,
@@ -1016,18 +1041,46 @@ function FormField({
1016
1041
  errorStyle,
1017
1042
  ...rest
1018
1043
  }) {
1044
+ const { theme } = useTheme();
1019
1045
  const styles = useThemeStyles(createStyles12);
1046
+ const sizeTokens = theme.components.formField.size[size];
1047
+ const generatedId = useId();
1048
+ const controlId = id ?? generatedId;
1049
+ const labelId = label ? `${controlId}-label` : void 0;
1050
+ const descriptionId = description ? `${controlId}-description` : void 0;
1051
+ const errorId = error ? `${controlId}-error` : void 0;
1052
+ const isInvalid = invalid || Boolean(error);
1053
+ const contextValue = {
1054
+ controlId,
1055
+ labelId,
1056
+ descriptionId,
1057
+ errorId,
1058
+ required,
1059
+ disabled,
1060
+ invalid: isInvalid,
1061
+ size,
1062
+ ariaLabelledBy: labelId,
1063
+ ariaDescribedBy: [descriptionId, errorId].filter(Boolean).join(" ") || void 0
1064
+ };
1020
1065
  return /* @__PURE__ */ jsxs7(
1021
1066
  View10,
1022
1067
  {
1023
1068
  ...rest,
1024
1069
  accessibilityState: disabled ? { disabled: true } : void 0,
1025
- style: [styles.root, style],
1070
+ style: [styles.root, { gap: sizeTokens.gap }, style],
1026
1071
  children: [
1027
1072
  label && (typeof label === "string" || typeof label === "number" ? /* @__PURE__ */ jsxs7(
1028
1073
  Text6,
1029
1074
  {
1030
- style: [styles.label, disabled && styles.labelDisabled, labelStyle],
1075
+ style: [
1076
+ styles.label,
1077
+ {
1078
+ fontSize: sizeTokens.labelFontSize,
1079
+ lineHeight: sizeTokens.labelLineHeight
1080
+ },
1081
+ disabled && styles.labelDisabled,
1082
+ labelStyle
1083
+ ],
1031
1084
  children: [
1032
1085
  label,
1033
1086
  required && /* @__PURE__ */ jsx14(
@@ -1038,6 +1091,32 @@ function FormField({
1038
1091
  importantForAccessibility: "no",
1039
1092
  children: " *"
1040
1093
  }
1094
+ ),
1095
+ !required && optionalText && /* @__PURE__ */ jsx14(
1096
+ Text6,
1097
+ {
1098
+ style: [
1099
+ styles.optional,
1100
+ {
1101
+ fontSize: sizeTokens.optionalFontSize,
1102
+ lineHeight: sizeTokens.optionalLineHeight
1103
+ }
1104
+ ],
1105
+ children: optionalText
1106
+ }
1107
+ ),
1108
+ labelInfo && /* @__PURE__ */ jsx14(
1109
+ Text6,
1110
+ {
1111
+ style: [
1112
+ styles.labelInfo,
1113
+ {
1114
+ fontSize: sizeTokens.labelInfoFontSize,
1115
+ lineHeight: sizeTokens.labelInfoSize
1116
+ }
1117
+ ],
1118
+ children: labelInfo
1119
+ }
1041
1120
  )
1042
1121
  ]
1043
1122
  }
@@ -1051,26 +1130,36 @@ function FormField({
1051
1130
  importantForAccessibility: "no",
1052
1131
  children: "*"
1053
1132
  }
1054
- )
1133
+ ),
1134
+ !required && optionalText,
1135
+ labelInfo
1055
1136
  ] })),
1056
1137
  description && (typeof description === "string" || typeof description === "number" ? /* @__PURE__ */ jsx14(
1057
1138
  Text6,
1058
1139
  {
1059
1140
  style: [
1060
1141
  styles.description,
1142
+ {
1143
+ fontSize: sizeTokens.descriptionFontSize,
1144
+ lineHeight: sizeTokens.descriptionLineHeight
1145
+ },
1061
1146
  disabled && styles.descriptionDisabled,
1062
1147
  descriptionStyle
1063
1148
  ],
1064
1149
  children: description
1065
1150
  }
1066
1151
  ) : description),
1067
- /* @__PURE__ */ jsx14(View10, { style: [styles.control, controlStyle], children }),
1152
+ /* @__PURE__ */ jsx14(FormFieldContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx14(View10, { style: [styles.control, { gap: sizeTokens.gap }, controlStyle], children }) }),
1068
1153
  error && (typeof error === "string" || typeof error === "number" ? /* @__PURE__ */ jsx14(
1069
1154
  Text6,
1070
1155
  {
1071
1156
  accessibilityLiveRegion: "polite",
1072
1157
  style: [
1073
1158
  styles.error,
1159
+ {
1160
+ fontSize: sizeTokens.helperTextFontSize,
1161
+ lineHeight: sizeTokens.helperTextLineHeight
1162
+ },
1074
1163
  disabled && styles.helperTextDisabled,
1075
1164
  errorStyle
1076
1165
  ],
@@ -1101,11 +1190,11 @@ var createStyles13 = (theme) => StyleSheet13.create({
1101
1190
  });
1102
1191
 
1103
1192
  // src/components/RadioGroup/RadioGroupContext.tsx
1104
- import { createContext as createContext3, useContext as useContext3 } from "react";
1105
- var RadioGroupContext = createContext3(null);
1193
+ import { createContext as createContext4, useContext as useContext4 } from "react";
1194
+ var RadioGroupContext = createContext4(null);
1106
1195
  var RadioGroupProvider = RadioGroupContext.Provider;
1107
1196
  function useRadioGroupContext() {
1108
- return useContext3(RadioGroupContext);
1197
+ return useContext4(RadioGroupContext);
1109
1198
  }
1110
1199
 
1111
1200
  // src/components/RadioGroup/RadioGroup.tsx
@@ -1459,8 +1548,11 @@ function Select({
1459
1548
  description,
1460
1549
  value,
1461
1550
  defaultValue,
1462
- onChange,
1463
- options,
1551
+ onValueChange,
1552
+ options: optionsProp,
1553
+ multiple = false,
1554
+ maxSelected,
1555
+ closeOnSelect,
1464
1556
  placeholder = "Select...",
1465
1557
  size = "md",
1466
1558
  required = false,
@@ -1475,24 +1567,39 @@ function Select({
1475
1567
  }) {
1476
1568
  const { theme } = useTheme();
1477
1569
  const styles = useThemeStyles(createStyles15);
1478
- const { selectedValue, setSelectedValue, selectedOption, isOpen, setIsOpen } = useSelect({
1570
+ const options = optionsProp ?? [];
1571
+ const {
1572
+ selectedValue,
1573
+ selectedValues,
1574
+ selectedOption,
1575
+ selectedOptions,
1576
+ isOpen,
1577
+ setIsOpen,
1578
+ selectValue
1579
+ } = useSelect({
1479
1580
  value,
1480
1581
  defaultValue,
1481
- onChange,
1582
+ onValueChange,
1482
1583
  options,
1584
+ multiple,
1585
+ maxSelected,
1586
+ closeOnSelect,
1483
1587
  disabled
1484
1588
  });
1485
- const [draftValue, setDraftValue] = useState2(selectedValue);
1589
+ const resolvedSelectedValues = selectedValues ?? [];
1590
+ const resolvedSelectedOptions = selectedOptions ?? [];
1591
+ const selectedValueText = Array.isArray(selectedValue) ? selectedValue[0] ?? "" : selectedValue ?? "";
1592
+ const [draftValue, setDraftValue] = useState2(selectedValueText);
1486
1593
  const hasError = !!error;
1487
1594
  useEffect2(() => {
1488
1595
  if (isOpen) {
1489
- setDraftValue(selectedValue);
1596
+ setDraftValue(selectedValueText);
1490
1597
  }
1491
- }, [isOpen, selectedValue]);
1598
+ }, [isOpen, selectedValueText]);
1492
1599
  const resolvedLabel = accessibilityLabel ?? label ?? selectedOption?.label ?? placeholder ?? "Select";
1493
1600
  const openPicker = () => {
1494
1601
  if (disabled) return;
1495
- setDraftValue(selectedValue);
1602
+ setDraftValue(selectedValueText);
1496
1603
  setIsOpen(true);
1497
1604
  };
1498
1605
  const closePicker = () => {
@@ -1511,9 +1618,10 @@ function Select({
1511
1618
  setIsOpen(false);
1512
1619
  return;
1513
1620
  }
1514
- setSelectedValue(draftValue);
1621
+ selectValue(draftValue);
1515
1622
  setIsOpen(false);
1516
1623
  };
1624
+ const displayText = multiple && resolvedSelectedOptions.length ? resolvedSelectedOptions.map((option) => option.label).join(", ") : selectedOption?.label ?? placeholder;
1517
1625
  return /* @__PURE__ */ jsxs9(
1518
1626
  FormField,
1519
1627
  {
@@ -1527,8 +1635,8 @@ function Select({
1527
1635
  /* @__PURE__ */ jsx17(
1528
1636
  SelectTrigger,
1529
1637
  {
1530
- displayText: selectedOption?.label ?? placeholder,
1531
- isPlaceholder: !selectedOption,
1638
+ displayText,
1639
+ isPlaceholder: resolvedSelectedValues.length === 0,
1532
1640
  isOpen,
1533
1641
  size,
1534
1642
  disabled,
@@ -1642,11 +1750,11 @@ Select.displayName = "Select";
1642
1750
  import { View as View14 } from "react-native";
1643
1751
 
1644
1752
  // src/components/Tabs/TabsContext.tsx
1645
- import { createContext as createContext4, useContext as useContext4 } from "react";
1646
- var TabsContext = createContext4(null);
1753
+ import { createContext as createContext5, useContext as useContext5 } from "react";
1754
+ var TabsContext = createContext5(null);
1647
1755
  var TabsProvider = TabsContext.Provider;
1648
1756
  var useTabs = () => {
1649
- const context = useContext4(TabsContext);
1757
+ const context = useContext5(TabsContext);
1650
1758
  if (!context) {
1651
1759
  throw new Error("Tabs components must be used inside <Tabs>.");
1652
1760
  }
@@ -2805,7 +2913,6 @@ import { Pressable as Pressable12, Text as Text13, TextInput, View as View21 } f
2805
2913
 
2806
2914
  // src/primitives/Input/Input.styles.ts
2807
2915
  import { StyleSheet as StyleSheet23 } from "react-native";
2808
- var getPlaceholderTextColor = (theme) => theme.components.input.default.placeholder;
2809
2916
  var getDisabledPlaceholderTextColor = (theme) => theme.components.input.disabled.placeholder;
2810
2917
  var resolveRingColor = (ring) => typeof ring === "string" ? ring : ring.color;
2811
2918
  var createStyles23 = (theme) => StyleSheet23.create({
@@ -2867,6 +2974,24 @@ var createStyles23 = (theme) => StyleSheet23.create({
2867
2974
  alignItems: "center",
2868
2975
  justifyContent: "center"
2869
2976
  },
2977
+ revealButton: {
2978
+ position: "absolute",
2979
+ right: theme.tokens.spacing[3],
2980
+ top: "50%",
2981
+ zIndex: 1,
2982
+ minWidth: 40,
2983
+ height: 28,
2984
+ marginTop: -14,
2985
+ borderRadius: theme.tokens.radius.sm,
2986
+ alignItems: "center",
2987
+ justifyContent: "center"
2988
+ },
2989
+ revealButtonText: {
2990
+ color: theme.components.input.icon.muted,
2991
+ fontFamily: theme.tokens.typography.family.medium,
2992
+ fontSize: theme.tokens.typography.size.xs,
2993
+ lineHeight: theme.tokens.typography.lineHeight.xs
2994
+ },
2870
2995
  clearButtonText: {
2871
2996
  color: theme.components.input.clearButton.fg,
2872
2997
  fontSize: 16,
@@ -2920,20 +3045,6 @@ var createStyles23 = (theme) => StyleSheet23.create({
2920
3045
  shadowRadius: 6,
2921
3046
  elevation: 1
2922
3047
  },
2923
- success: {
2924
- borderColor: theme.components.input.success.border
2925
- },
2926
- successFocused: {
2927
- borderColor: theme.components.input.success.border,
2928
- shadowColor: resolveRingColor(theme.components.input.success.ring),
2929
- shadowOffset: {
2930
- width: 0,
2931
- height: 0
2932
- },
2933
- shadowOpacity: 0.18,
2934
- shadowRadius: 6,
2935
- elevation: 1
2936
- },
2937
3048
  readOnly: {
2938
3049
  color: theme.components.input.readOnly.fg,
2939
3050
  borderColor: theme.components.input.readOnly.border,
@@ -2976,24 +3087,48 @@ var autoCorrectByInputType = {
2976
3087
  url: false,
2977
3088
  search: false
2978
3089
  };
3090
+ var applyPatternMask = (value, pattern) => {
3091
+ const digits = value.replace(/\D/g, "");
3092
+ let digitIndex = 0;
3093
+ let maskedValue = "";
3094
+ for (const character of pattern) {
3095
+ if (character === "#") {
3096
+ const nextDigit = digits[digitIndex];
3097
+ if (!nextDigit) break;
3098
+ maskedValue += nextDigit;
3099
+ digitIndex += 1;
3100
+ continue;
3101
+ }
3102
+ if (digitIndex < digits.length) {
3103
+ maskedValue += character;
3104
+ }
3105
+ }
3106
+ return maskedValue;
3107
+ };
3108
+ var applyMask = (value, mask) => {
3109
+ if (!mask) return value;
3110
+ return typeof mask === "function" ? mask(value) : applyPatternMask(value, mask);
3111
+ };
2979
3112
  var Input = forwardRef3(
2980
3113
  ({
2981
3114
  label,
2982
3115
  description,
2983
3116
  value,
2984
3117
  defaultValue,
2985
- onChange,
3118
+ onValueChange,
2986
3119
  placeholder,
2987
- size = "md",
3120
+ size,
2988
3121
  error,
3122
+ invalid = false,
2989
3123
  disabled = false,
2990
3124
  required = false,
3125
+ loading = false,
2991
3126
  readOnly = false,
2992
3127
  type = "text",
2993
- leftIcon,
2994
- rightIcon,
2995
- leftIconTone = "default",
2996
- rightIconTone = "default",
3128
+ startIcon,
3129
+ endIcon,
3130
+ startIconTone = "default",
3131
+ endIconTone = "default",
2997
3132
  clearIcon,
2998
3133
  clearIconTone = "danger",
2999
3134
  iconSize,
@@ -3012,19 +3147,38 @@ var Input = forwardRef3(
3012
3147
  maxLength,
3013
3148
  clearable,
3014
3149
  onClear,
3150
+ color = "primary",
3151
+ variant = "outline",
3152
+ revealPassword = false,
3153
+ showCounter: _showCounter,
3154
+ mask,
3155
+ format,
3156
+ parse,
3015
3157
  ...props
3016
3158
  }, ref) => {
3017
3159
  const { theme } = useTheme();
3018
3160
  const styles = useThemeStyles(createStyles23);
3161
+ const field = useFormFieldContext();
3162
+ const hasOwnField = Boolean(label || description || error);
3019
3163
  const [isFocused, setIsFocused] = useState6(false);
3020
3164
  const [uncontrolledValue, setUncontrolledValue] = useState6(
3021
3165
  defaultValue ?? ""
3022
3166
  );
3023
3167
  const isControlled = value !== void 0;
3024
3168
  const currentValue = isControlled ? value : uncontrolledValue;
3169
+ const displayValue = format ? format(currentValue) : currentValue;
3025
3170
  const hasValue = currentValue !== "";
3026
- const placeholderTextColor = disabled ? getDisabledPlaceholderTextColor(theme) : readOnly ? theme.components.input.readOnly.placeholder : getPlaceholderTextColor(theme);
3171
+ const resolvedSize = size ?? field?.size ?? "md";
3172
+ const inputColorPalette = theme.components.input[color];
3173
+ const inputPalette = inputColorPalette[variant];
3174
+ const inputState = isFocused ? inputPalette.focus : inputPalette.default;
3175
+ const isInvalid = invalid || Boolean(error) || !hasOwnField && Boolean(field?.invalid);
3176
+ const isDisabled = disabled || !hasOwnField && Boolean(field?.disabled);
3177
+ const isRequired = required || !hasOwnField && Boolean(field?.required);
3178
+ const isReadOnly = readOnly || loading;
3179
+ const placeholderTextColor = isDisabled ? getDisabledPlaceholderTextColor(theme) : readOnly ? theme.components.input.readOnly.placeholder : inputState.placeholder;
3027
3180
  const isPassword = type === "password";
3181
+ const [isPasswordRevealed, setIsPasswordRevealed] = useState6(false);
3028
3182
  const resolvedIconSize = iconSize ?? 16;
3029
3183
  const handleFocus = (event) => {
3030
3184
  setIsFocused(true);
@@ -3035,114 +3189,148 @@ var Input = forwardRef3(
3035
3189
  onBlur?.(event);
3036
3190
  };
3037
3191
  const handleChangeText = (nextValue) => {
3192
+ const parsedValue = parse ? parse(nextValue) : nextValue;
3193
+ const maskedValue = applyMask(parsedValue, mask);
3038
3194
  if (!isControlled) {
3039
- setUncontrolledValue(nextValue);
3195
+ setUncontrolledValue(maskedValue);
3040
3196
  }
3041
- onChange?.(nextValue);
3197
+ onValueChange?.(maskedValue);
3042
3198
  };
3043
3199
  const handleClear = () => {
3044
3200
  if (!isControlled) {
3045
3201
  setUncontrolledValue("");
3046
3202
  }
3203
+ onValueChange?.("");
3047
3204
  onClear?.();
3048
3205
  };
3049
- const showClearButton = clearable && hasValue && !disabled && !readOnly;
3050
- const showRightIcon = !showClearButton && Boolean(rightIcon);
3051
- const leftIconColor = disabled ? theme.components.input.disabled.icon : theme.components.input.icon[leftIconTone];
3052
- const rightIconColor = disabled ? theme.components.input.disabled.icon : theme.components.input.icon[rightIconTone];
3053
- const clearIconColor = disabled ? theme.components.input.disabled.icon : theme.components.input.icon[clearIconTone];
3206
+ const showClearButton = clearable && hasValue && !isDisabled && !isReadOnly;
3207
+ const showRevealButton = revealPassword && isPassword && !isDisabled;
3208
+ const showRightIcon = !showClearButton && !showRevealButton && Boolean(endIcon);
3209
+ const startIconColor = isDisabled ? theme.components.input.disabled.icon : theme.components.input.icon[startIconTone];
3210
+ const endIconColor = isDisabled ? theme.components.input.disabled.icon : theme.components.input.icon[endIconTone];
3211
+ const clearIconColor = isDisabled ? theme.components.input.disabled.icon : theme.components.input.icon[clearIconTone];
3212
+ const control = /* @__PURE__ */ jsxs14(View21, { style: styles.inputWrapper, children: [
3213
+ startIcon && /* @__PURE__ */ jsx25(
3214
+ View21,
3215
+ {
3216
+ pointerEvents: "none",
3217
+ style: styles.leftIcon,
3218
+ accessibilityElementsHidden: true,
3219
+ importantForAccessibility: "no",
3220
+ children: cloneElement6(startIcon, {
3221
+ color: startIconColor,
3222
+ size: resolvedIconSize
3223
+ })
3224
+ }
3225
+ ),
3226
+ /* @__PURE__ */ jsx25(
3227
+ TextInput,
3228
+ {
3229
+ ...props,
3230
+ ref,
3231
+ nativeID: props.nativeID ?? (!hasOwnField ? field?.controlId : void 0),
3232
+ value: displayValue,
3233
+ onChangeText: handleChangeText,
3234
+ editable: !isDisabled && !isReadOnly,
3235
+ placeholder,
3236
+ keyboardType: keyboardType ?? keyboardTypeByInputType[type],
3237
+ secureTextEntry: secureTextEntry ?? (isPassword && !isPasswordRevealed),
3238
+ autoCapitalize: autoCapitalize ?? autoCapitalizeByInputType[type],
3239
+ autoCorrect: autoCorrect ?? autoCorrectByInputType[type],
3240
+ onBlur: handleBlur,
3241
+ onFocus: handleFocus,
3242
+ autoFocus,
3243
+ maxLength,
3244
+ testID,
3245
+ placeholderTextColor,
3246
+ accessibilityLabel: accessibilityLabel ?? label,
3247
+ accessibilityHint,
3248
+ accessibilityState: { disabled: isDisabled },
3249
+ accessibilityLabelledBy: !hasOwnField ? field?.labelId : void 0,
3250
+ "aria-describedby": !hasOwnField ? field?.ariaDescribedBy : void 0,
3251
+ style: [
3252
+ styles.input,
3253
+ {
3254
+ color: inputState.fg,
3255
+ backgroundColor: inputState.bg,
3256
+ borderColor: inputState.border
3257
+ },
3258
+ styles[resolvedSize],
3259
+ inputStyle,
3260
+ startIcon && styles.inputWithLeftAdornment,
3261
+ (showRightIcon || showClearButton || showRevealButton) && styles.inputWithRightAdornment,
3262
+ isFocused && !isDisabled && !isReadOnly && {
3263
+ color: inputPalette.focus.fg,
3264
+ backgroundColor: inputPalette.focus.bg,
3265
+ borderColor: inputPalette.focus.border,
3266
+ shadowColor: inputColorPalette.ring,
3267
+ shadowOffset: {
3268
+ width: 0,
3269
+ height: 0
3270
+ },
3271
+ shadowOpacity: 0.18,
3272
+ shadowRadius: 6,
3273
+ elevation: 1
3274
+ },
3275
+ isInvalid && styles.error,
3276
+ isFocused && isInvalid && !isDisabled && !isReadOnly && styles.errorFocused,
3277
+ isReadOnly && !isDisabled && styles.readOnly,
3278
+ isDisabled && styles.disabled
3279
+ ]
3280
+ }
3281
+ ),
3282
+ showClearButton ? /* @__PURE__ */ jsx25(
3283
+ Pressable12,
3284
+ {
3285
+ accessibilityRole: "button",
3286
+ accessibilityLabel: "Clear input",
3287
+ hitSlop: 8,
3288
+ onPress: handleClear,
3289
+ style: styles.clearButton,
3290
+ children: clearIcon ? cloneElement6(clearIcon, {
3291
+ color: clearIconColor,
3292
+ size: resolvedIconSize
3293
+ }) : /* @__PURE__ */ jsx25(Text13, { style: [styles.clearButtonText, { color: clearIconColor }], children: "\xD7" })
3294
+ }
3295
+ ) : showRevealButton ? /* @__PURE__ */ jsx25(
3296
+ Pressable12,
3297
+ {
3298
+ accessibilityRole: "button",
3299
+ accessibilityLabel: isPasswordRevealed ? "Hide password" : "Show password",
3300
+ hitSlop: 8,
3301
+ onPress: () => setIsPasswordRevealed((revealed) => !revealed),
3302
+ style: styles.revealButton,
3303
+ children: /* @__PURE__ */ jsx25(Text13, { style: styles.revealButtonText, children: isPasswordRevealed ? "Hide" : "Show" })
3304
+ }
3305
+ ) : showRightIcon && endIcon && /* @__PURE__ */ jsx25(
3306
+ View21,
3307
+ {
3308
+ pointerEvents: "none",
3309
+ style: styles.rightIcon,
3310
+ accessibilityElementsHidden: true,
3311
+ importantForAccessibility: "no",
3312
+ children: cloneElement6(endIcon, {
3313
+ color: endIconColor,
3314
+ size: resolvedIconSize
3315
+ })
3316
+ }
3317
+ )
3318
+ ] });
3319
+ if (!hasOwnField && field) {
3320
+ return control;
3321
+ }
3054
3322
  return /* @__PURE__ */ jsx25(
3055
3323
  FormField,
3056
3324
  {
3057
3325
  label,
3058
3326
  description,
3059
3327
  error,
3060
- required,
3061
- disabled,
3328
+ required: isRequired,
3329
+ disabled: isDisabled,
3330
+ invalid: isInvalid,
3331
+ size: resolvedSize,
3062
3332
  style: containerStyle,
3063
- children: /* @__PURE__ */ jsxs14(View21, { style: styles.inputWrapper, children: [
3064
- leftIcon && /* @__PURE__ */ jsx25(
3065
- View21,
3066
- {
3067
- pointerEvents: "none",
3068
- style: styles.leftIcon,
3069
- accessibilityElementsHidden: true,
3070
- importantForAccessibility: "no",
3071
- children: cloneElement6(leftIcon, {
3072
- color: leftIconColor,
3073
- size: resolvedIconSize
3074
- })
3075
- }
3076
- ),
3077
- /* @__PURE__ */ jsx25(
3078
- TextInput,
3079
- {
3080
- ...props,
3081
- ref,
3082
- value: currentValue,
3083
- onChangeText: handleChangeText,
3084
- editable: !disabled && !readOnly,
3085
- placeholder,
3086
- keyboardType: keyboardType ?? keyboardTypeByInputType[type],
3087
- secureTextEntry: secureTextEntry ?? isPassword,
3088
- autoCapitalize: autoCapitalize ?? autoCapitalizeByInputType[type],
3089
- autoCorrect: autoCorrect ?? autoCorrectByInputType[type],
3090
- onBlur: handleBlur,
3091
- onFocus: handleFocus,
3092
- autoFocus,
3093
- maxLength,
3094
- testID,
3095
- placeholderTextColor,
3096
- accessibilityLabel: accessibilityLabel ?? label,
3097
- accessibilityHint,
3098
- accessibilityState: { disabled },
3099
- style: [
3100
- styles.input,
3101
- styles[size],
3102
- inputStyle,
3103
- leftIcon && styles.inputWithLeftAdornment,
3104
- (showRightIcon || showClearButton) && styles.inputWithRightAdornment,
3105
- isFocused && !disabled && !readOnly && styles.focused,
3106
- error && styles.error,
3107
- isFocused && error && !disabled && !readOnly && styles.errorFocused,
3108
- readOnly && !disabled && styles.readOnly,
3109
- disabled && styles.disabled
3110
- ]
3111
- }
3112
- ),
3113
- showClearButton ? /* @__PURE__ */ jsx25(
3114
- Pressable12,
3115
- {
3116
- accessibilityRole: "button",
3117
- accessibilityLabel: "Clear input",
3118
- hitSlop: 8,
3119
- onPress: handleClear,
3120
- style: styles.clearButton,
3121
- children: clearIcon ? cloneElement6(clearIcon, {
3122
- color: clearIconColor,
3123
- size: resolvedIconSize
3124
- }) : /* @__PURE__ */ jsx25(
3125
- Text13,
3126
- {
3127
- style: [styles.clearButtonText, { color: clearIconColor }],
3128
- children: "\xD7"
3129
- }
3130
- )
3131
- }
3132
- ) : showRightIcon && rightIcon && /* @__PURE__ */ jsx25(
3133
- View21,
3134
- {
3135
- pointerEvents: "none",
3136
- style: styles.rightIcon,
3137
- accessibilityElementsHidden: true,
3138
- importantForAccessibility: "no",
3139
- children: cloneElement6(rightIcon, {
3140
- color: rightIconColor,
3141
- size: resolvedIconSize
3142
- })
3143
- }
3144
- )
3145
- ] })
3333
+ children: control
3146
3334
  }
3147
3335
  );
3148
3336
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vellira-ui/react-native",
3
- "version": "2.29.0",
3
+ "version": "2.31.0",
4
4
  "description": "React Native components for Vellira Design System",
5
5
  "author": "Roman Bakurov",
6
6
  "license": "MIT",