@webority-technologies/mobile 0.0.15 → 0.0.20

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 (202) hide show
  1. package/lib/commonjs/components/Accordion/Accordion.js +60 -19
  2. package/lib/commonjs/components/AppBar/AppBar.js +29 -20
  3. package/lib/commonjs/components/Avatar/Avatar.js +38 -8
  4. package/lib/commonjs/components/Badge/Badge.js +66 -4
  5. package/lib/commonjs/components/Banner/Banner.js +146 -66
  6. package/lib/commonjs/components/BottomNavigation/BottomNavigation.js +37 -15
  7. package/lib/commonjs/components/BottomSheet/BottomSheet.js +78 -53
  8. package/lib/commonjs/components/Button/Button.js +12 -5
  9. package/lib/commonjs/components/Card/Card.js +106 -16
  10. package/lib/commonjs/components/Carousel/Carousel.js +66 -12
  11. package/lib/commonjs/components/Checkbox/Checkbox.js +11 -7
  12. package/lib/commonjs/components/Chip/Chip.js +44 -12
  13. package/lib/commonjs/components/DatePicker/DatePicker.js +185 -76
  14. package/lib/commonjs/components/DateRangePicker/DateRangePicker.js +133 -59
  15. package/lib/commonjs/components/Dialog/Dialog.js +16 -10
  16. package/lib/commonjs/components/Drawer/Drawer.js +13 -10
  17. package/lib/commonjs/components/FieldBase/FieldBase.js +306 -0
  18. package/lib/commonjs/components/FieldBase/index.js +32 -0
  19. package/lib/commonjs/components/FloatingActionButton/FloatingActionButton.js +69 -44
  20. package/lib/commonjs/components/ForceUpdateDialog/ForceUpdateDialog.js +8 -2
  21. package/lib/commonjs/components/FormField/FormField.js +3 -2
  22. package/lib/commonjs/components/ImageGallery/ImageGallery.js +132 -44
  23. package/lib/commonjs/components/Input/Input.js +144 -181
  24. package/lib/commonjs/components/ListItem/ListItem.js +90 -11
  25. package/lib/commonjs/components/Modal/Modal.js +55 -27
  26. package/lib/commonjs/components/NumberInput/NumberInput.js +60 -106
  27. package/lib/commonjs/components/OTPInput/OTPInput.js +65 -58
  28. package/lib/commonjs/components/PickerTrigger/PickerTrigger.js +185 -0
  29. package/lib/commonjs/components/{AppIcon → PickerTrigger}/index.js +4 -4
  30. package/lib/commonjs/components/ProgressBar/ProgressBar.js +19 -11
  31. package/lib/commonjs/components/Radio/Radio.js +11 -6
  32. package/lib/commonjs/components/Rating/Rating.js +85 -19
  33. package/lib/commonjs/components/SearchBar/SearchBar.js +84 -107
  34. package/lib/commonjs/components/SegmentedControl/SegmentedControl.js +22 -11
  35. package/lib/commonjs/components/Select/Select.js +62 -91
  36. package/lib/commonjs/components/Skeleton/Skeleton.js +131 -174
  37. package/lib/commonjs/components/Skeleton/SkeletonClock.js +117 -0
  38. package/lib/commonjs/components/Skeleton/SkeletonContent.js +164 -81
  39. package/lib/commonjs/components/Skeleton/SkeletonProvider.js +72 -10
  40. package/lib/commonjs/components/Skeleton/index.js +17 -16
  41. package/lib/commonjs/components/Slider/Slider.js +44 -25
  42. package/lib/commonjs/components/Stepper/Stepper.js +199 -29
  43. package/lib/commonjs/components/Swipeable/Swipeable.js +36 -19
  44. package/lib/commonjs/components/Switch/Switch.js +9 -2
  45. package/lib/commonjs/components/Tabs/Tabs.js +84 -21
  46. package/lib/commonjs/components/TimePicker/TimePicker.js +123 -45
  47. package/lib/commonjs/components/Toast/Toast.js +27 -16
  48. package/lib/commonjs/components/Tooltip/Tooltip.js +56 -32
  49. package/lib/commonjs/components/index.js +37 -37
  50. package/lib/commonjs/theme/tokens.js +55 -7
  51. package/lib/module/components/Accordion/Accordion.js +61 -20
  52. package/lib/module/components/AppBar/AppBar.js +29 -20
  53. package/lib/module/components/Avatar/Avatar.js +39 -9
  54. package/lib/module/components/Badge/Badge.js +67 -5
  55. package/lib/module/components/Banner/Banner.js +147 -67
  56. package/lib/module/components/BottomNavigation/BottomNavigation.js +37 -15
  57. package/lib/module/components/BottomSheet/BottomSheet.js +80 -55
  58. package/lib/module/components/Button/Button.js +12 -5
  59. package/lib/module/components/Card/Card.js +107 -17
  60. package/lib/module/components/Carousel/Carousel.js +67 -13
  61. package/lib/module/components/Checkbox/Checkbox.js +11 -7
  62. package/lib/module/components/Chip/Chip.js +45 -13
  63. package/lib/module/components/DatePicker/DatePicker.js +185 -76
  64. package/lib/module/components/DateRangePicker/DateRangePicker.js +134 -60
  65. package/lib/module/components/Dialog/Dialog.js +16 -10
  66. package/lib/module/components/Drawer/Drawer.js +13 -10
  67. package/lib/module/components/FieldBase/FieldBase.js +297 -0
  68. package/lib/module/components/FieldBase/index.js +4 -0
  69. package/lib/module/components/FloatingActionButton/FloatingActionButton.js +69 -44
  70. package/lib/module/components/ForceUpdateDialog/ForceUpdateDialog.js +8 -2
  71. package/lib/module/components/FormField/FormField.js +3 -2
  72. package/lib/module/components/ImageGallery/ImageGallery.js +128 -40
  73. package/lib/module/components/Input/Input.js +144 -179
  74. package/lib/module/components/ListItem/ListItem.js +91 -12
  75. package/lib/module/components/Modal/Modal.js +55 -27
  76. package/lib/module/components/NumberInput/NumberInput.js +60 -106
  77. package/lib/module/components/OTPInput/OTPInput.js +65 -58
  78. package/lib/module/components/PickerTrigger/PickerTrigger.js +181 -0
  79. package/lib/module/components/PickerTrigger/index.js +4 -0
  80. package/lib/module/components/ProgressBar/ProgressBar.js +19 -11
  81. package/lib/module/components/Radio/Radio.js +11 -6
  82. package/lib/module/components/Rating/Rating.js +86 -20
  83. package/lib/module/components/SearchBar/SearchBar.js +84 -107
  84. package/lib/module/components/SegmentedControl/SegmentedControl.js +22 -11
  85. package/lib/module/components/Select/Select.js +62 -91
  86. package/lib/module/components/Skeleton/Skeleton.js +135 -175
  87. package/lib/module/components/Skeleton/SkeletonClock.js +110 -0
  88. package/lib/module/components/Skeleton/SkeletonContent.js +167 -84
  89. package/lib/module/components/Skeleton/SkeletonProvider.js +71 -10
  90. package/lib/module/components/Skeleton/index.js +3 -2
  91. package/lib/module/components/Slider/Slider.js +44 -25
  92. package/lib/module/components/Stepper/Stepper.js +201 -31
  93. package/lib/module/components/Swipeable/Swipeable.js +36 -19
  94. package/lib/module/components/Switch/Switch.js +9 -2
  95. package/lib/module/components/Tabs/Tabs.js +84 -21
  96. package/lib/module/components/TimePicker/TimePicker.js +123 -45
  97. package/lib/module/components/Toast/Toast.js +27 -16
  98. package/lib/module/components/Tooltip/Tooltip.js +56 -32
  99. package/lib/module/components/index.js +2 -2
  100. package/lib/module/theme/tokens.js +55 -7
  101. package/lib/typescript/commonjs/components/Accordion/Accordion.d.ts +10 -5
  102. package/lib/typescript/commonjs/components/AppBar/AppBar.d.ts +8 -0
  103. package/lib/typescript/commonjs/components/Avatar/Avatar.d.ts +12 -6
  104. package/lib/typescript/commonjs/components/Badge/Badge.d.ts +7 -6
  105. package/lib/typescript/commonjs/components/Banner/Banner.d.ts +17 -6
  106. package/lib/typescript/commonjs/components/BottomSheet/BottomSheet.d.ts +7 -0
  107. package/lib/typescript/commonjs/components/Card/Card.d.ts +17 -6
  108. package/lib/typescript/commonjs/components/Carousel/Carousel.d.ts +7 -6
  109. package/lib/typescript/commonjs/components/Checkbox/Checkbox.d.ts +9 -1
  110. package/lib/typescript/commonjs/components/Chip/Chip.d.ts +13 -6
  111. package/lib/typescript/commonjs/components/DatePicker/DatePicker.d.ts +38 -3
  112. package/lib/typescript/commonjs/components/DateRangePicker/DateRangePicker.d.ts +36 -3
  113. package/lib/typescript/commonjs/components/Dialog/Dialog.d.ts +13 -1
  114. package/lib/typescript/commonjs/components/FieldBase/FieldBase.d.ts +141 -0
  115. package/lib/typescript/commonjs/components/FieldBase/index.d.ts +3 -0
  116. package/lib/typescript/commonjs/components/FloatingActionButton/FloatingActionButton.d.ts +8 -6
  117. package/lib/typescript/commonjs/components/FloatingActionButton/index.d.ts +1 -1
  118. package/lib/typescript/commonjs/components/ForceUpdateDialog/ForceUpdateDialog.d.ts +7 -0
  119. package/lib/typescript/commonjs/components/FormField/FormField.d.ts +7 -0
  120. package/lib/typescript/commonjs/components/ImageGallery/ImageGallery.d.ts +6 -4
  121. package/lib/typescript/commonjs/components/Input/Input.d.ts +6 -0
  122. package/lib/typescript/commonjs/components/ListItem/ListItem.d.ts +13 -6
  123. package/lib/typescript/commonjs/components/NumberInput/NumberInput.d.ts +3 -0
  124. package/lib/typescript/commonjs/components/PickerTrigger/PickerTrigger.d.ts +57 -0
  125. package/lib/typescript/commonjs/components/PickerTrigger/index.d.ts +3 -0
  126. package/lib/typescript/commonjs/components/ProgressBar/ProgressBar.d.ts +2 -0
  127. package/lib/typescript/commonjs/components/Radio/Radio.d.ts +3 -0
  128. package/lib/typescript/commonjs/components/Rating/Rating.d.ts +9 -6
  129. package/lib/typescript/commonjs/components/SegmentedControl/SegmentedControl.d.ts +3 -0
  130. package/lib/typescript/commonjs/components/Skeleton/Skeleton.d.ts +49 -20
  131. package/lib/typescript/commonjs/components/Skeleton/SkeletonClock.d.ts +60 -0
  132. package/lib/typescript/commonjs/components/Skeleton/SkeletonContent.d.ts +80 -19
  133. package/lib/typescript/commonjs/components/Skeleton/SkeletonProvider.d.ts +39 -5
  134. package/lib/typescript/commonjs/components/Skeleton/index.d.ts +6 -4
  135. package/lib/typescript/commonjs/components/Slider/Slider.d.ts +12 -1
  136. package/lib/typescript/commonjs/components/Stepper/Stepper.d.ts +18 -6
  137. package/lib/typescript/commonjs/components/Swipeable/Swipeable.d.ts +2 -0
  138. package/lib/typescript/commonjs/components/Switch/Switch.d.ts +1 -0
  139. package/lib/typescript/commonjs/components/Tabs/Tabs.d.ts +26 -2
  140. package/lib/typescript/commonjs/components/TimePicker/TimePicker.d.ts +36 -3
  141. package/lib/typescript/commonjs/components/Toast/Toast.d.ts +8 -0
  142. package/lib/typescript/commonjs/components/Tooltip/Tooltip.d.ts +7 -1
  143. package/lib/typescript/commonjs/components/index.d.ts +5 -5
  144. package/lib/typescript/commonjs/index.d.ts +1 -1
  145. package/lib/typescript/commonjs/theme/index.d.ts +1 -1
  146. package/lib/typescript/commonjs/theme/types.d.ts +553 -11
  147. package/lib/typescript/module/components/Accordion/Accordion.d.ts +10 -5
  148. package/lib/typescript/module/components/AppBar/AppBar.d.ts +8 -0
  149. package/lib/typescript/module/components/Avatar/Avatar.d.ts +12 -6
  150. package/lib/typescript/module/components/Badge/Badge.d.ts +7 -6
  151. package/lib/typescript/module/components/Banner/Banner.d.ts +17 -6
  152. package/lib/typescript/module/components/BottomSheet/BottomSheet.d.ts +7 -0
  153. package/lib/typescript/module/components/Card/Card.d.ts +17 -6
  154. package/lib/typescript/module/components/Carousel/Carousel.d.ts +7 -6
  155. package/lib/typescript/module/components/Checkbox/Checkbox.d.ts +9 -1
  156. package/lib/typescript/module/components/Chip/Chip.d.ts +13 -6
  157. package/lib/typescript/module/components/DatePicker/DatePicker.d.ts +38 -3
  158. package/lib/typescript/module/components/DateRangePicker/DateRangePicker.d.ts +36 -3
  159. package/lib/typescript/module/components/Dialog/Dialog.d.ts +13 -1
  160. package/lib/typescript/module/components/FieldBase/FieldBase.d.ts +141 -0
  161. package/lib/typescript/module/components/FieldBase/index.d.ts +3 -0
  162. package/lib/typescript/module/components/FloatingActionButton/FloatingActionButton.d.ts +8 -6
  163. package/lib/typescript/module/components/FloatingActionButton/index.d.ts +1 -1
  164. package/lib/typescript/module/components/ForceUpdateDialog/ForceUpdateDialog.d.ts +7 -0
  165. package/lib/typescript/module/components/FormField/FormField.d.ts +7 -0
  166. package/lib/typescript/module/components/ImageGallery/ImageGallery.d.ts +6 -4
  167. package/lib/typescript/module/components/Input/Input.d.ts +6 -0
  168. package/lib/typescript/module/components/ListItem/ListItem.d.ts +13 -6
  169. package/lib/typescript/module/components/NumberInput/NumberInput.d.ts +3 -0
  170. package/lib/typescript/module/components/PickerTrigger/PickerTrigger.d.ts +57 -0
  171. package/lib/typescript/module/components/PickerTrigger/index.d.ts +3 -0
  172. package/lib/typescript/module/components/ProgressBar/ProgressBar.d.ts +2 -0
  173. package/lib/typescript/module/components/Radio/Radio.d.ts +3 -0
  174. package/lib/typescript/module/components/Rating/Rating.d.ts +9 -6
  175. package/lib/typescript/module/components/SegmentedControl/SegmentedControl.d.ts +3 -0
  176. package/lib/typescript/module/components/Skeleton/Skeleton.d.ts +49 -20
  177. package/lib/typescript/module/components/Skeleton/SkeletonClock.d.ts +60 -0
  178. package/lib/typescript/module/components/Skeleton/SkeletonContent.d.ts +80 -19
  179. package/lib/typescript/module/components/Skeleton/SkeletonProvider.d.ts +39 -5
  180. package/lib/typescript/module/components/Skeleton/index.d.ts +6 -4
  181. package/lib/typescript/module/components/Slider/Slider.d.ts +12 -1
  182. package/lib/typescript/module/components/Stepper/Stepper.d.ts +18 -6
  183. package/lib/typescript/module/components/Swipeable/Swipeable.d.ts +2 -0
  184. package/lib/typescript/module/components/Switch/Switch.d.ts +1 -0
  185. package/lib/typescript/module/components/Tabs/Tabs.d.ts +26 -2
  186. package/lib/typescript/module/components/TimePicker/TimePicker.d.ts +36 -3
  187. package/lib/typescript/module/components/Toast/Toast.d.ts +8 -0
  188. package/lib/typescript/module/components/Tooltip/Tooltip.d.ts +7 -1
  189. package/lib/typescript/module/components/index.d.ts +5 -5
  190. package/lib/typescript/module/index.d.ts +1 -1
  191. package/lib/typescript/module/theme/index.d.ts +1 -1
  192. package/lib/typescript/module/theme/types.d.ts +553 -11
  193. package/package.json +2 -6
  194. package/lib/commonjs/components/AppIcon/AppIcon.js +0 -120
  195. package/lib/commonjs/types/vector-icons.d.js +0 -2
  196. package/lib/module/components/AppIcon/AppIcon.js +0 -111
  197. package/lib/module/components/AppIcon/index.js +0 -4
  198. package/lib/module/types/vector-icons.d.js +0 -2
  199. package/lib/typescript/commonjs/components/AppIcon/AppIcon.d.ts +0 -20
  200. package/lib/typescript/commonjs/components/AppIcon/index.d.ts +0 -3
  201. package/lib/typescript/module/components/AppIcon/AppIcon.d.ts +0 -20
  202. package/lib/typescript/module/components/AppIcon/index.d.ts +0 -3
@@ -2,40 +2,16 @@
2
2
 
3
3
  import React, { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from 'react';
4
4
  import { Animated, Easing, Pressable, StyleSheet, Text, TextInput, View } from 'react-native';
5
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
6
- // @ts-ignore - react-native-vector-icons ships no bundled types in this version
7
- import Feather from 'react-native-vector-icons/Feather';
8
5
  import { createAnimatedValue, fontFor, setNativeValue, useTheme } from "../../theme/index.js";
9
6
  import { triggerHaptic } from "../../utils/index.js";
7
+ import { FieldBase, resolveFieldSize, resolveFieldTextStyle, resolveVariantColors } from "../FieldBase/FieldBase.js";
10
8
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
- const sizeMap = {
12
- sm: {
13
- paddingHorizontal: 12,
14
- paddingVertical: 8,
15
- minHeight: 38,
16
- multilineMinHeight: 72,
17
- fontSize: 13,
18
- borderRadius: 10,
19
- iconSize: 16
20
- },
21
- md: {
22
- paddingHorizontal: 14,
23
- paddingVertical: 11,
24
- minHeight: 46,
25
- multilineMinHeight: 92,
26
- fontSize: 15,
27
- borderRadius: 12,
28
- iconSize: 18
29
- },
30
- lg: {
31
- paddingHorizontal: 16,
32
- paddingVertical: 14,
33
- minHeight: 54,
34
- multilineMinHeight: 110,
35
- fontSize: 16,
36
- borderRadius: 14,
37
- iconSize: 20
38
- }
9
+ // FieldBase carries every dimension except `multilineMinHeight` — Input owns
10
+ // the multiline height ramp, so we keep a tiny per-size table for that one key.
11
+ const multilineMinHeightMap = {
12
+ sm: 72,
13
+ md: 92,
14
+ lg: 110
39
15
  };
40
16
  const Input = /*#__PURE__*/forwardRef((props, ref) => {
41
17
  const {
@@ -59,8 +35,11 @@ const Input = /*#__PURE__*/forwardRef((props, ref) => {
59
35
  format,
60
36
  parse,
61
37
  style,
38
+ containerStyle,
62
39
  inputStyle,
63
40
  labelStyle,
41
+ messageStyle,
42
+ borderRadius: borderRadiusProp,
64
43
  onFocus,
65
44
  onBlur,
66
45
  accessibilityLabel,
@@ -70,13 +49,16 @@ const Input = /*#__PURE__*/forwardRef((props, ref) => {
70
49
  } = props;
71
50
  const theme = useTheme();
72
51
  const styles = useMemo(() => buildStyles(theme), [theme]);
73
- const sizeStyles = {
74
- ...sizeMap[size],
75
- ...(theme.components.input?.[size] ?? {})
76
- };
52
+ const sizeTokens = resolveFieldSize(theme, size);
53
+ const multilineMinHeight = multilineMinHeightMap[size];
77
54
 
78
- // Per-call-site prop wins; otherwise theme defaults; otherwise library defaults.
79
- const variant = variantProp ?? theme.components.input?.defaultVariant ?? 'outlined';
55
+ // Resolution chain: caller prop component-specific token
56
+ // (`components.input.defaultVariant`) shared field-family token
57
+ // (`components.field.defaultVariant`) → library default. The middle step lets
58
+ // brands flip every input-style control (Input, Select, SearchBar, …) in one
59
+ // place; the per-component slot still wins when a brand needs a different
60
+ // default for Input specifically.
61
+ const variant = variantProp ?? theme.components.input?.defaultVariant ?? theme.components.field?.defaultVariant ?? 'outlined';
80
62
  const labelMode = labelModeProp ?? theme.components.input?.defaultLabelMode ?? 'float';
81
63
  const [isFocused, setIsFocused] = useState(false);
82
64
  const [isPasswordVisible, setIsPasswordVisible] = useState(false);
@@ -89,41 +71,20 @@ const Input = /*#__PURE__*/forwardRef((props, ref) => {
89
71
  // above the field — the staticLabel branch below handles both.
90
72
  const showFloatingLabel = Boolean(label) && !multiline && labelMode === 'float';
91
73
 
92
- // Animations
93
- const focusAnim = useRef(createAnimatedValue(0)).current;
94
- const errorAnim = useRef(createAnimatedValue(0)).current;
74
+ // Animations local to Input: floating label, shake, helper/error fade.
75
+ // Border + fill animations now live inside FieldBase.
95
76
  const labelAnim = useRef(createAnimatedValue(shouldFloat ? 1 : 0)).current;
96
77
  const shakeAnim = useRef(createAnimatedValue(0)).current;
97
78
  const messageAnim = useRef(createAnimatedValue(hasError || helperText ? 1 : 0)).current;
98
79
 
99
- // Focus border animation
100
- useEffect(() => {
101
- Animated.timing(focusAnim, {
102
- toValue: isFocused ? 1 : 0,
103
- duration: theme.motion.duration.fast,
104
- easing: Easing.bezier(...theme.motion.easing.standard),
105
- useNativeDriver: false
106
- }).start();
107
- }, [isFocused, focusAnim, theme.motion.duration.fast, theme.motion.easing.standard]);
108
-
109
- // Error border + message animation
110
- useEffect(() => {
111
- Animated.timing(errorAnim, {
112
- toValue: hasError ? 1 : 0,
113
- duration: theme.motion.duration.fast,
114
- easing: Easing.bezier(...theme.motion.easing.standard),
115
- useNativeDriver: false
116
- }).start();
117
- }, [hasError, errorAnim, theme.motion.duration.fast, theme.motion.easing.standard]);
118
-
119
80
  // Floating label animation
120
81
  useEffect(() => {
121
- Animated.parallel([Animated.timing(labelAnim, {
82
+ Animated.timing(labelAnim, {
122
83
  toValue: shouldFloat ? 1 : 0,
123
84
  duration: theme.motion.duration.fast,
124
85
  easing: Easing.bezier(...theme.motion.easing.standard),
125
86
  useNativeDriver: false
126
- })]).start();
87
+ }).start();
127
88
  }, [shouldFloat, labelAnim, theme.motion.duration.fast, theme.motion.easing.standard]);
128
89
 
129
90
  // Helper / error fade
@@ -136,9 +97,15 @@ const Input = /*#__PURE__*/forwardRef((props, ref) => {
136
97
  }).start();
137
98
  }, [hasError, helperText, messageAnim, theme.motion.easing.standard]);
138
99
 
139
- // Error shake
100
+ // Error shake — off by default; consumers opt in via
101
+ // theme.components.input.shakeOnError. The haptic ships with the shake.
102
+ const shakeOnError = theme.components.input?.shakeOnError ?? false;
140
103
  const prevErrorRef = useRef(hasError);
141
104
  useEffect(() => {
105
+ if (!shakeOnError) {
106
+ prevErrorRef.current = hasError;
107
+ return;
108
+ }
142
109
  if (hasError && !prevErrorRef.current) {
143
110
  setNativeValue(shakeAnim, 0);
144
111
  Animated.sequence([Animated.timing(shakeAnim, {
@@ -165,7 +132,7 @@ const Input = /*#__PURE__*/forwardRef((props, ref) => {
165
132
  triggerHaptic('notificationError');
166
133
  }
167
134
  prevErrorRef.current = hasError;
168
- }, [hasError, shakeAnim]);
135
+ }, [hasError, shakeAnim, shakeOnError]);
169
136
  const handleFocus = useCallback(e => {
170
137
  setIsFocused(true);
171
138
  onFocus?.(e);
@@ -179,19 +146,25 @@ const Input = /*#__PURE__*/forwardRef((props, ref) => {
179
146
  setIsPasswordVisible(prev => !prev);
180
147
  }, []);
181
148
 
182
- // Derived border + background colors with smooth interpolation
183
- const blurredBorderColor = variant === 'filled' ? 'transparent' : theme.colors.border.primary;
184
- const focusedBorderColor = theme.colors.border.focus;
185
- const errorBorderColor = theme.colors.border.error;
186
- const baseBorderColor = focusAnim.interpolate({
187
- inputRange: [0, 1],
188
- outputRange: [blurredBorderColor, focusedBorderColor]
189
- });
190
- const animatedBorderColor = errorAnim.interpolate({
191
- inputRange: [0, 1],
192
- outputRange: [baseBorderColor, errorBorderColor]
193
- });
194
- const containerBackgroundColor = disabled ? theme.colors.surface.disabled : variant === 'filled' ? theme.colors.background.secondary : theme.colors.background.primary;
149
+ // Bridge legacy Input fill-colour API (theme.components.input.fillColors[variant])
150
+ // onto FieldBase's FieldVariantTokens shape. Keeps consumer overrides working.
151
+ const fillOverrides = useMemo(() => {
152
+ const legacy = theme.components.input?.fillColors?.[variant];
153
+ if (!legacy) return undefined;
154
+ const overrides = {};
155
+ if (legacy.idleEmpty !== undefined) overrides.backgroundIdleEmpty = legacy.idleEmpty;
156
+ if (legacy.idleFilled !== undefined) overrides.backgroundIdleFilled = legacy.idleFilled;
157
+ if (legacy.focus !== undefined) overrides.backgroundFocused = legacy.focus;
158
+ if (legacy.error !== undefined) overrides.backgroundError = legacy.error;
159
+ if (legacy.disabled !== undefined) overrides.backgroundDisabled = legacy.disabled;
160
+ return Object.keys(overrides).length > 0 ? overrides : undefined;
161
+ }, [theme.components.input?.fillColors, variant]);
162
+
163
+ // Selection / caret / handle colour walks the same resolution chain as the
164
+ // focused border so brands that override `components.field.<variant>.borderFocused`
165
+ // get a matching selection tint without also having to update root `border.focus`.
166
+ const selectionColor = useMemo(() => resolveVariantColors(theme, variant, fillOverrides).borderFocused, [theme, variant, fillOverrides]);
167
+ const borderRadiusOverride = borderRadiusProp ?? theme.components.input?.borderRadius;
195
168
 
196
169
  // Floating label styles
197
170
  const labelTranslateY = labelAnim.interpolate({
@@ -202,24 +175,53 @@ const Input = /*#__PURE__*/forwardRef((props, ref) => {
202
175
  inputRange: [0, 1],
203
176
  outputRange: [1, 0.85]
204
177
  });
205
- const labelColor = hasError ? theme.colors.text.tertiary : isFocused ? theme.colors.border.focus : theme.colors.text.secondary;
178
+ // Single source of truth for label colour used by BOTH static-top and
179
+ // floating modes. Label stays its resting colour on focus unless the consumer
180
+ // opts in via theme.components.input.tintLabelOnFocus.
181
+ const tintLabelOnFocus = theme.components.input?.tintLabelOnFocus ?? false;
182
+ const labelColor = hasError ? theme.colors.error : isFocused && tintLabelOnFocus ? theme.colors.border.focus : theme.colors.text.secondary;
206
183
  const shakeTranslateX = shakeAnim.interpolate({
207
184
  inputRange: [-1, 0, 1],
208
185
  outputRange: [-6, 0, 6]
209
186
  });
210
- const inputTextColor = disabled ? theme.colors.text.disabled : theme.colors.text.primary;
211
- const placeholderTextColor = theme.colors.text.tertiary;
187
+ const fieldText = resolveFieldTextStyle(theme, {
188
+ disabled
189
+ });
190
+ const inputTextColor = fieldText.color;
191
+ const placeholderTextColor = fieldText.placeholderColor;
212
192
  const messageText = hasError ? error : helperText;
213
193
  const messageColor = hasError ? theme.colors.error : theme.colors.text.secondary;
214
194
  const a11yLabel = accessibilityLabel ?? label ?? placeholder;
215
-
216
- // Padding adjustments to leave room for icons
217
- const leftPad = leftIcon ? sizeStyles.paddingHorizontal + sizeStyles.iconSize + theme.spacing.xs : sizeStyles.paddingHorizontal;
218
- const rightPadIcon = showPasswordToggle && secureTextEntry || rightIcon;
219
- const rightPad = rightPadIcon ? sizeStyles.paddingHorizontal + sizeStyles.iconSize + theme.spacing.xs : sizeStyles.paddingHorizontal;
220
-
221
- // Floating label positioning depends on size; when floated it sits above the field.
222
- const floatedLabelTopOffset = -(sizeStyles.fontSize - 2);
195
+ const iconColor = disabled ? theme.colors.text.disabled : theme.colors.text.secondary;
196
+ const trailing = (() => {
197
+ if (showPasswordToggle && secureTextEntry) {
198
+ const renderer = isPasswordVisible ? theme.icons?.eyeOff : theme.icons?.eye;
199
+ return /*#__PURE__*/_jsx(Pressable, {
200
+ onPress: togglePasswordVisibility,
201
+ disabled: !isEditable,
202
+ hitSlop: 8,
203
+ accessibilityRole: "button",
204
+ accessibilityLabel: isPasswordVisible ? 'Hide password' : 'Show password',
205
+ children: renderer ? renderer({
206
+ size: sizeTokens.iconSize,
207
+ color: iconColor
208
+ }) : /*#__PURE__*/_jsx(Text, {
209
+ style: {
210
+ fontSize: sizeTokens.iconSize,
211
+ color: iconColor
212
+ },
213
+ children: isPasswordVisible ? '✕' : '○'
214
+ })
215
+ });
216
+ }
217
+ if (rightIcon) return /*#__PURE__*/_jsx(View, {
218
+ children: rightIcon
219
+ });
220
+ return null;
221
+ })();
222
+ const leading = leftIcon ? /*#__PURE__*/_jsx(View, {
223
+ children: leftIcon
224
+ }) : null;
223
225
  return /*#__PURE__*/_jsxs(Animated.View, {
224
226
  style: [styles.container, {
225
227
  transform: [{
@@ -228,7 +230,7 @@ const Input = /*#__PURE__*/forwardRef((props, ref) => {
228
230
  }, style],
229
231
  children: [label && !showFloatingLabel ? /*#__PURE__*/_jsxs(Text, {
230
232
  style: [styles.staticLabel, {
231
- color: hasError ? theme.colors.error : isFocused ? theme.colors.border.focus : theme.colors.text.secondary,
233
+ color: labelColor,
232
234
  fontSize: theme.typography.fontSize.sm,
233
235
  ...fontFor(theme, 'medium'),
234
236
  marginBottom: theme.spacing.xxs
@@ -239,31 +241,58 @@ const Input = /*#__PURE__*/forwardRef((props, ref) => {
239
241
  },
240
242
  children: " *"
241
243
  }) : null]
242
- }) : null, /*#__PURE__*/_jsxs(Animated.View, {
243
- style: [styles.inputWrapper, {
244
- minHeight: multiline ? sizeStyles.multilineMinHeight : sizeStyles.minHeight,
245
- borderRadius: sizeStyles.borderRadius,
246
- borderWidth: variant === 'outlined' ? 1.5 : 0,
247
- borderColor: animatedBorderColor,
248
- backgroundColor: containerBackgroundColor,
249
- opacity: disabled ? 0.65 : 1,
250
- paddingLeft: leftPad,
251
- paddingRight: rightPad
252
- }],
253
- children: [leftIcon ? /*#__PURE__*/_jsx(View, {
254
- style: [styles.leftIconWrap, {
255
- left: sizeStyles.paddingHorizontal - 2,
256
- height: sizeStyles.minHeight
257
- }],
258
- pointerEvents: "none",
259
- children: leftIcon
260
- }) : null, showFloatingLabel ? /*#__PURE__*/_jsxs(Animated.Text, {
244
+ }) : null, /*#__PURE__*/_jsxs(View, {
245
+ style: styles.fieldWrapper,
246
+ children: [/*#__PURE__*/_jsx(FieldBase, {
247
+ size: size,
248
+ variant: variant,
249
+ focused: isFocused,
250
+ disabled: disabled,
251
+ error: hasError,
252
+ filled: hasValue,
253
+ minHeight: multiline ? multilineMinHeight : undefined,
254
+ borderRadius: borderRadiusOverride,
255
+ fillOverrides: fillOverrides,
256
+ leading: leading,
257
+ trailing: trailing,
258
+ style: containerStyle,
259
+ children: /*#__PURE__*/_jsx(TextInput, {
260
+ ref: ref,
261
+ style: [styles.input, {
262
+ color: inputTextColor,
263
+ fontSize: sizeTokens.fontSize,
264
+ ...fieldText.weightStyle,
265
+ minHeight: multiline ? multilineMinHeight - sizeTokens.paddingVertical * 2 : undefined,
266
+ textAlignVertical: multiline ? 'top' : 'center'
267
+ }, inputStyle],
268
+ placeholder: showFloatingLabel && !shouldFloat ? undefined : placeholder,
269
+ placeholderTextColor: placeholderTextColor,
270
+ value: format && value != null ? format(value) : value,
271
+ onChangeText: text => {
272
+ if (!onChangeText) return;
273
+ onChangeText(parse ? parse(text) : text);
274
+ },
275
+ onFocus: handleFocus,
276
+ onBlur: handleBlur,
277
+ editable: isEditable,
278
+ secureTextEntry: secureTextEntry && !isPasswordVisible,
279
+ multiline: multiline,
280
+ maxLength: maxLength,
281
+ selectionColor: selectionColor,
282
+ accessibilityLabel: a11yLabel,
283
+ accessibilityState: {
284
+ disabled
285
+ },
286
+ testID: testID,
287
+ ...rest
288
+ })
289
+ }), showFloatingLabel ? /*#__PURE__*/_jsxs(Animated.Text, {
261
290
  pointerEvents: "none",
262
291
  style: [styles.floatingLabel, {
263
- top: sizeStyles.paddingVertical,
264
- left: leftPad,
292
+ top: sizeTokens.paddingVertical,
293
+ left: sizeTokens.paddingHorizontal + (leftIcon ? sizeTokens.iconSize + theme.spacing.sm : 0),
265
294
  color: labelColor,
266
- fontSize: sizeStyles.fontSize,
295
+ fontSize: sizeTokens.fontSize,
267
296
  ...fontFor(theme, 'medium'),
268
297
  backgroundColor: shouldFloat && variant === 'outlined' ? theme.colors.background.primary : 'transparent',
269
298
  paddingHorizontal: shouldFloat && variant === 'outlined' ? 4 : 0,
@@ -279,57 +308,6 @@ const Input = /*#__PURE__*/forwardRef((props, ref) => {
279
308
  },
280
309
  children: " *"
281
310
  }) : null]
282
- }) : null, /*#__PURE__*/_jsx(TextInput, {
283
- ref: ref,
284
- style: [styles.input, {
285
- color: inputTextColor,
286
- fontSize: sizeStyles.fontSize,
287
- paddingVertical: sizeStyles.paddingVertical,
288
- minHeight: multiline ? sizeStyles.multilineMinHeight : sizeStyles.minHeight,
289
- textAlignVertical: multiline ? 'top' : 'center'
290
- }, inputStyle],
291
- placeholder: showFloatingLabel && !shouldFloat ? undefined : placeholder,
292
- placeholderTextColor: placeholderTextColor,
293
- value: format && value != null ? format(value) : value,
294
- onChangeText: text => {
295
- if (!onChangeText) return;
296
- onChangeText(parse ? parse(text) : text);
297
- },
298
- onFocus: handleFocus,
299
- onBlur: handleBlur,
300
- editable: isEditable,
301
- secureTextEntry: secureTextEntry && !isPasswordVisible,
302
- multiline: multiline,
303
- maxLength: maxLength,
304
- selectionColor: theme.colors.border.focus,
305
- accessibilityLabel: a11yLabel,
306
- accessibilityState: {
307
- disabled
308
- },
309
- testID: testID,
310
- ...rest
311
- }), showPasswordToggle && secureTextEntry ? /*#__PURE__*/_jsx(Pressable, {
312
- onPress: togglePasswordVisibility,
313
- disabled: !isEditable,
314
- hitSlop: 8,
315
- accessibilityRole: "button",
316
- accessibilityLabel: isPasswordVisible ? 'Hide password' : 'Show password',
317
- style: [styles.rightIconWrap, {
318
- right: sizeStyles.paddingHorizontal - 2,
319
- height: multiline ? sizeStyles.multilineMinHeight : sizeStyles.minHeight
320
- }],
321
- children: /*#__PURE__*/_jsx(Feather, {
322
- name: isPasswordVisible ? 'eye-off' : 'eye',
323
- size: sizeStyles.iconSize,
324
- color: disabled ? theme.colors.text.disabled : theme.colors.text.secondary
325
- })
326
- }) : rightIcon ? /*#__PURE__*/_jsx(View, {
327
- style: [styles.rightIconWrap, {
328
- right: sizeStyles.paddingHorizontal - 2,
329
- height: multiline ? sizeStyles.multilineMinHeight : sizeStyles.minHeight
330
- }],
331
- pointerEvents: "box-none",
332
- children: rightIcon
333
311
  }) : null]
334
312
  }), messageText ? /*#__PURE__*/_jsx(Animated.Text, {
335
313
  style: [styles.messageText, {
@@ -337,7 +315,7 @@ const Input = /*#__PURE__*/forwardRef((props, ref) => {
337
315
  fontSize: theme.typography.fontSize.xs,
338
316
  marginTop: theme.spacing.xxs,
339
317
  opacity: messageAnim
340
- }],
318
+ }, messageStyle],
341
319
  accessibilityLiveRegion: hasError ? 'polite' : 'none',
342
320
  children: messageText
343
321
  }) : null, typeof maxLength === 'number' && typeof value === 'string' ? /*#__PURE__*/_jsx(Text, {
@@ -358,9 +336,9 @@ const buildStyles = _theme => StyleSheet.create({
358
336
  staticLabel: {
359
337
  includeFontPadding: false
360
338
  },
361
- inputWrapper: {
362
- flexDirection: 'row',
363
- alignItems: 'center',
339
+ // Wraps FieldBase + the absolutely-positioned floating label so the label
340
+ // can sit over the field's top border without being clipped.
341
+ fieldWrapper: {
364
342
  position: 'relative',
365
343
  overflow: 'visible'
366
344
  },
@@ -374,19 +352,6 @@ const buildStyles = _theme => StyleSheet.create({
374
352
  position: 'absolute',
375
353
  zIndex: 1
376
354
  },
377
- leftIconWrap: {
378
- position: 'absolute',
379
- top: 0,
380
- justifyContent: 'center',
381
- alignItems: 'center'
382
- },
383
- rightIconWrap: {
384
- position: 'absolute',
385
- top: 0,
386
- justifyContent: 'center',
387
- alignItems: 'center',
388
- paddingHorizontal: 4
389
- },
390
355
  messageText: {
391
356
  includeFontPadding: false
392
357
  },
@@ -6,7 +6,7 @@ import { fontFor, useTheme } from "../../theme/index.js";
6
6
  import { usePressAnimation } from "../../hooks/usePressAnimation.js";
7
7
  import { triggerHaptic } from "../../utils/hapticUtils.js";
8
8
  import { Swipeable } from "../Swipeable/index.js";
9
- import { SkeletonContent } from "../Skeleton/index.js";
9
+ import { Skeleton } from "../Skeleton/index.js";
10
10
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
11
  const SIZE_FALLBACK = {
12
12
  sm: {
@@ -74,9 +74,16 @@ const ListItem = /*#__PURE__*/forwardRef((props, ref) => {
74
74
  accessibilityLabel,
75
75
  accessibilityHint,
76
76
  style,
77
+ containerStyle,
78
+ titleStyle,
79
+ subtitleStyle,
80
+ descriptionStyle,
81
+ leftSlotStyle,
82
+ rightSlotStyle,
77
83
  testID
78
84
  } = props;
79
85
  const theme = useTheme();
86
+ const pressHaptic = theme.components.listItem?.pressHaptic ?? false;
80
87
  const sz = useMemo(() => sizeFor(theme, size), [theme, size]);
81
88
  const styles = useMemo(() => buildStyles(theme), [theme]);
82
89
  const isInteractive = !!onPress && !disabled;
@@ -89,7 +96,7 @@ const ListItem = /*#__PURE__*/forwardRef((props, ref) => {
89
96
  });
90
97
  const handlePress = event => {
91
98
  if (!isInteractive) return;
92
- triggerHaptic('selection');
99
+ if (pressHaptic) triggerHaptic('selection');
93
100
  onPress?.(event);
94
101
  };
95
102
  const a11yLabel = accessibilityLabel ?? title;
@@ -98,9 +105,9 @@ const ListItem = /*#__PURE__*/forwardRef((props, ref) => {
98
105
  paddingVertical: sz.paddingVertical,
99
106
  minHeight: sz.minHeight,
100
107
  backgroundColor: selected ? theme.colors.surface.selected : 'transparent'
101
- }, divider ? styles.divider : null, disabled ? styles.disabled : null],
108
+ }, divider ? styles.divider : null, disabled ? styles.disabled : null, containerStyle],
102
109
  children: [left ? /*#__PURE__*/_jsx(View, {
103
- style: styles.leftSlot,
110
+ style: [styles.leftSlot, leftSlotStyle],
104
111
  children: left
105
112
  }) : null, /*#__PURE__*/_jsxs(View, {
106
113
  style: styles.middle,
@@ -109,26 +116,26 @@ const ListItem = /*#__PURE__*/forwardRef((props, ref) => {
109
116
  fontSize: sz.titleSize,
110
117
  ...fontFor(theme, 'medium'),
111
118
  color: disabled ? theme.colors.text.disabled : theme.colors.text.primary
112
- }],
119
+ }, titleStyle],
113
120
  numberOfLines: 1,
114
121
  children: title ?? ' '
115
122
  }), subtitle ? /*#__PURE__*/_jsx(Text, {
116
123
  style: [styles.subtitle, {
117
124
  fontSize: sz.subtitleSize,
118
125
  color: disabled ? theme.colors.text.disabled : theme.colors.text.secondary
119
- }],
126
+ }, subtitleStyle],
120
127
  numberOfLines: 1,
121
128
  children: subtitle
122
129
  }) : null, description ? /*#__PURE__*/_jsx(Text, {
123
130
  style: [styles.description, {
124
131
  fontSize: sz.subtitleSize,
125
132
  color: disabled ? theme.colors.text.disabled : theme.colors.text.tertiary
126
- }],
133
+ }, descriptionStyle],
127
134
  numberOfLines: 2,
128
135
  children: description
129
136
  }) : null]
130
137
  }), right || chevron ? /*#__PURE__*/_jsxs(View, {
131
- style: styles.rightSlot,
138
+ style: [styles.rightSlot, rightSlotStyle],
132
139
  children: [right, chevron ? /*#__PURE__*/_jsx(View, {
133
140
  style: right ? styles.chevronWithRight : null,
134
141
  children: /*#__PURE__*/_jsx(Chevron, {
@@ -189,15 +196,87 @@ const ListItem = /*#__PURE__*/forwardRef((props, ref) => {
189
196
  children: rendered
190
197
  }) : rendered;
191
198
  if (loading) {
192
- return /*#__PURE__*/_jsx(SkeletonContent, {
193
- loading: true,
194
- mode: "auto",
195
- children: final
199
+ return /*#__PURE__*/_jsx(ListItemSkeleton, {
200
+ ...props
196
201
  });
197
202
  }
198
203
  return final;
199
204
  });
200
205
  ListItem.displayName = 'ListItem';
206
+
207
+ /**
208
+ * Placeholder shape for `<ListItem>`. Mirrors the row anatomy: optional
209
+ * leading slot (avatar/icon), title + subtitle/description stack, optional
210
+ * trailing chevron. Heights respect the configured `size`.
211
+ */
212
+ const ListItemSkeleton = ({
213
+ subtitle,
214
+ description,
215
+ left,
216
+ right,
217
+ chevron,
218
+ size = 'md',
219
+ containerStyle,
220
+ style
221
+ }) => {
222
+ const theme = useTheme();
223
+ const sz = sizeFor(theme, size);
224
+ const titleHeight = Math.round(sz.titleSize * 1.15);
225
+ const subtitleHeight = Math.round(sz.subtitleSize * 1.15);
226
+ return /*#__PURE__*/_jsxs(View, {
227
+ style: [{
228
+ flexDirection: 'row',
229
+ alignItems: 'center',
230
+ paddingHorizontal: theme.spacing.md,
231
+ paddingVertical: sz.paddingVertical,
232
+ minHeight: sz.minHeight
233
+ }, containerStyle, style],
234
+ children: [left !== undefined ? /*#__PURE__*/_jsx(View, {
235
+ style: {
236
+ marginRight: theme.spacing.sm
237
+ },
238
+ children: /*#__PURE__*/_jsx(Skeleton, {
239
+ shape: "circle",
240
+ width: 40,
241
+ height: 40
242
+ })
243
+ }) : null, /*#__PURE__*/_jsxs(View, {
244
+ style: {
245
+ flex: 1
246
+ },
247
+ children: [/*#__PURE__*/_jsx(Skeleton, {
248
+ shape: "text",
249
+ width: "70%",
250
+ height: titleHeight,
251
+ style: {
252
+ marginBottom: theme.spacing.xs
253
+ }
254
+ }), subtitle !== undefined ? /*#__PURE__*/_jsx(Skeleton, {
255
+ shape: "text",
256
+ width: "50%",
257
+ height: subtitleHeight,
258
+ style: description !== undefined ? {
259
+ marginBottom: theme.spacing.xs
260
+ } : undefined
261
+ }) : null, description !== undefined ? /*#__PURE__*/_jsx(Skeleton, {
262
+ shape: "text",
263
+ width: "85%",
264
+ height: subtitleHeight
265
+ }) : null]
266
+ }), right !== undefined || chevron ? /*#__PURE__*/_jsx(View, {
267
+ style: {
268
+ marginLeft: theme.spacing.sm
269
+ },
270
+ children: /*#__PURE__*/_jsx(Skeleton, {
271
+ width: 20,
272
+ height: 20,
273
+ radius: "sm"
274
+ })
275
+ }) : null]
276
+ });
277
+ };
278
+ ListItemSkeleton.displayName = 'ListItemSkeleton';
279
+ ListItem.Skeleton = ListItemSkeleton;
201
280
  const buildStyles = theme => StyleSheet.create({
202
281
  row: {
203
282
  flexDirection: 'row',