@webority-technologies/mobile 0.0.22 → 0.0.24

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 (249) hide show
  1. package/lib/commonjs/components/Accordion/Accordion.js +9 -7
  2. package/lib/commonjs/components/AnimatePresence/AnimatePresence.js +69 -0
  3. package/lib/commonjs/components/AnimatePresence/index.js +13 -0
  4. package/lib/commonjs/components/AppBar/AppBar.js +9 -6
  5. package/lib/commonjs/components/Avatar/Avatar.js +4 -2
  6. package/lib/commonjs/components/Badge/Badge.js +5 -5
  7. package/lib/commonjs/components/Banner/Banner.js +20 -6
  8. package/lib/commonjs/components/BottomNavigation/BottomNavigation.js +6 -4
  9. package/lib/commonjs/components/BottomSheet/BottomSheet.js +8 -9
  10. package/lib/commonjs/components/Box/Box.js +162 -0
  11. package/lib/commonjs/components/Box/index.js +37 -0
  12. package/lib/commonjs/components/Button/Button.js +7 -7
  13. package/lib/commonjs/components/Card/Card.js +3 -3
  14. package/lib/commonjs/components/Carousel/Carousel.js +4 -2
  15. package/lib/commonjs/components/Checkbox/Checkbox.js +17 -7
  16. package/lib/commonjs/components/Chip/Chip.js +4 -2
  17. package/lib/commonjs/components/DatePicker/DatePicker.js +31 -24
  18. package/lib/commonjs/components/DateRangePicker/DateRangePicker.js +16 -11
  19. package/lib/commonjs/components/Dialog/Dialog.js +6 -4
  20. package/lib/commonjs/components/Drawer/Drawer.js +4 -2
  21. package/lib/commonjs/components/FieldBase/FieldBase.js +8 -4
  22. package/lib/commonjs/components/FloatingActionButton/FloatingActionButton.js +23 -13
  23. package/lib/commonjs/components/FormField/FormField.js +61 -25
  24. package/lib/commonjs/components/ImageGallery/ImageGallery.js +17 -15
  25. package/lib/commonjs/components/Input/Input.js +41 -29
  26. package/lib/commonjs/components/KeyboardAwareScrollView/KeyboardAwareScrollView.js +102 -0
  27. package/lib/commonjs/components/KeyboardAwareScrollView/index.js +13 -0
  28. package/lib/commonjs/components/KeyboardToolbar/KeyboardToolbar.js +130 -0
  29. package/lib/commonjs/components/KeyboardToolbar/index.js +13 -0
  30. package/lib/commonjs/components/ListItem/ListItem.js +4 -3
  31. package/lib/commonjs/components/Modal/Modal.js +21 -9
  32. package/lib/commonjs/components/NumberInput/NumberInput.js +38 -29
  33. package/lib/commonjs/components/OTPInput/OTPInput.js +37 -22
  34. package/lib/commonjs/components/Radio/Radio.js +9 -8
  35. package/lib/commonjs/components/Radio/RadioGroup.js +10 -3
  36. package/lib/commonjs/components/Rating/Rating.js +4 -3
  37. package/lib/commonjs/components/SearchBar/SearchBar.js +11 -6
  38. package/lib/commonjs/components/SegmentedControl/SegmentedControl.js +23 -12
  39. package/lib/commonjs/components/Select/Select.js +40 -36
  40. package/lib/commonjs/components/Skeleton/SkeletonContent.js +5 -2
  41. package/lib/commonjs/components/Slider/Slider.js +241 -225
  42. package/lib/commonjs/components/Spinner/Spinner.js +5 -5
  43. package/lib/commonjs/components/Stepper/Stepper.js +6 -5
  44. package/lib/commonjs/components/Swipeable/Swipeable.js +8 -9
  45. package/lib/commonjs/components/Switch/Switch.js +29 -16
  46. package/lib/commonjs/components/Tabs/Tabs.js +8 -5
  47. package/lib/commonjs/components/Text/Text.js +142 -0
  48. package/lib/commonjs/components/Text/index.js +13 -0
  49. package/lib/commonjs/components/TimePicker/TimePicker.js +23 -15
  50. package/lib/commonjs/components/Toast/Toast.js +22 -10
  51. package/lib/commonjs/components/Tooltip/Tooltip.js +6 -2
  52. package/lib/commonjs/components/index.js +156 -103
  53. package/lib/commonjs/form/FormContext.js +40 -0
  54. package/lib/commonjs/form/index.js +68 -0
  55. package/lib/commonjs/form/path.js +79 -0
  56. package/lib/commonjs/form/rules.js +67 -0
  57. package/lib/commonjs/form/types.js +2 -0
  58. package/lib/commonjs/form/useField.js +54 -0
  59. package/lib/commonjs/form/useForm.js +316 -0
  60. package/lib/commonjs/hooks/index.js +14 -0
  61. package/lib/commonjs/hooks/useControllableState.js +30 -0
  62. package/lib/commonjs/hooks/useReducedMotion.js +31 -0
  63. package/lib/commonjs/index.js +96 -11
  64. package/lib/commonjs/theme/ThemeContext.js +30 -2
  65. package/lib/commonjs/theme/tokens.js +12 -0
  66. package/lib/commonjs/utils/hapticUtils.js +11 -1
  67. package/lib/commonjs/utils/index.js +6 -0
  68. package/lib/module/components/Accordion/Accordion.js +10 -8
  69. package/lib/module/components/AnimatePresence/AnimatePresence.js +63 -0
  70. package/lib/module/components/AnimatePresence/index.js +4 -0
  71. package/lib/module/components/AppBar/AppBar.js +10 -7
  72. package/lib/module/components/Avatar/Avatar.js +4 -2
  73. package/lib/module/components/Badge/Badge.js +5 -5
  74. package/lib/module/components/Banner/Banner.js +20 -6
  75. package/lib/module/components/BottomNavigation/BottomNavigation.js +6 -4
  76. package/lib/module/components/BottomSheet/BottomSheet.js +8 -9
  77. package/lib/module/components/Box/Box.js +156 -0
  78. package/lib/module/components/Box/index.js +4 -0
  79. package/lib/module/components/Button/Button.js +7 -7
  80. package/lib/module/components/Card/Card.js +4 -4
  81. package/lib/module/components/Carousel/Carousel.js +4 -2
  82. package/lib/module/components/Checkbox/Checkbox.js +18 -8
  83. package/lib/module/components/Chip/Chip.js +5 -3
  84. package/lib/module/components/DatePicker/DatePicker.js +32 -25
  85. package/lib/module/components/DateRangePicker/DateRangePicker.js +17 -12
  86. package/lib/module/components/Dialog/Dialog.js +7 -5
  87. package/lib/module/components/Drawer/Drawer.js +5 -3
  88. package/lib/module/components/FieldBase/FieldBase.js +8 -4
  89. package/lib/module/components/FloatingActionButton/FloatingActionButton.js +24 -14
  90. package/lib/module/components/FormField/FormField.js +62 -26
  91. package/lib/module/components/ImageGallery/ImageGallery.js +18 -16
  92. package/lib/module/components/Input/Input.js +41 -29
  93. package/lib/module/components/KeyboardAwareScrollView/KeyboardAwareScrollView.js +98 -0
  94. package/lib/module/components/KeyboardAwareScrollView/index.js +4 -0
  95. package/lib/module/components/KeyboardToolbar/KeyboardToolbar.js +125 -0
  96. package/lib/module/components/KeyboardToolbar/index.js +4 -0
  97. package/lib/module/components/ListItem/ListItem.js +5 -4
  98. package/lib/module/components/Modal/Modal.js +22 -10
  99. package/lib/module/components/NumberInput/NumberInput.js +36 -27
  100. package/lib/module/components/OTPInput/OTPInput.js +37 -22
  101. package/lib/module/components/Radio/Radio.js +10 -9
  102. package/lib/module/components/Radio/RadioGroup.js +10 -3
  103. package/lib/module/components/Rating/Rating.js +5 -4
  104. package/lib/module/components/SearchBar/SearchBar.js +12 -7
  105. package/lib/module/components/SegmentedControl/SegmentedControl.js +24 -13
  106. package/lib/module/components/Select/Select.js +41 -37
  107. package/lib/module/components/Skeleton/SkeletonContent.js +5 -2
  108. package/lib/module/components/Slider/Slider.js +244 -228
  109. package/lib/module/components/Spinner/Spinner.js +5 -5
  110. package/lib/module/components/Stepper/Stepper.js +7 -6
  111. package/lib/module/components/Swipeable/Swipeable.js +9 -10
  112. package/lib/module/components/Switch/Switch.js +29 -16
  113. package/lib/module/components/Tabs/Tabs.js +9 -6
  114. package/lib/module/components/Text/Text.js +138 -0
  115. package/lib/module/components/Text/index.js +4 -0
  116. package/lib/module/components/TimePicker/TimePicker.js +24 -16
  117. package/lib/module/components/Toast/Toast.js +22 -10
  118. package/lib/module/components/Tooltip/Tooltip.js +6 -2
  119. package/lib/module/components/index.js +5 -0
  120. package/lib/module/form/FormContext.js +32 -0
  121. package/lib/module/form/index.js +12 -0
  122. package/lib/module/form/path.js +72 -0
  123. package/lib/module/form/rules.js +52 -0
  124. package/lib/module/form/types.js +2 -0
  125. package/lib/module/form/useField.js +49 -0
  126. package/lib/module/form/useForm.js +312 -0
  127. package/lib/module/hooks/index.js +2 -0
  128. package/lib/module/hooks/useControllableState.js +26 -0
  129. package/lib/module/hooks/useReducedMotion.js +27 -0
  130. package/lib/module/index.js +3 -1
  131. package/lib/module/theme/ThemeContext.js +30 -2
  132. package/lib/module/theme/tokens.js +12 -0
  133. package/lib/module/utils/hapticUtils.js +9 -0
  134. package/lib/module/utils/index.js +1 -1
  135. package/lib/typescript/commonjs/components/Accordion/Accordion.d.ts +3 -0
  136. package/lib/typescript/commonjs/components/AnimatePresence/AnimatePresence.d.ts +30 -0
  137. package/lib/typescript/commonjs/components/AnimatePresence/index.d.ts +3 -0
  138. package/lib/typescript/commonjs/components/AppBar/AppBar.d.ts +6 -0
  139. package/lib/typescript/commonjs/components/Banner/Banner.d.ts +3 -0
  140. package/lib/typescript/commonjs/components/BottomNavigation/BottomNavigation.d.ts +1 -1
  141. package/lib/typescript/commonjs/components/Box/Box.d.ts +60 -0
  142. package/lib/typescript/commonjs/components/Box/index.d.ts +3 -0
  143. package/lib/typescript/commonjs/components/Button/Button.d.ts +1 -1
  144. package/lib/typescript/commonjs/components/Card/Card.d.ts +3 -0
  145. package/lib/typescript/commonjs/components/Checkbox/Checkbox.d.ts +4 -2
  146. package/lib/typescript/commonjs/components/Chip/Chip.d.ts +3 -0
  147. package/lib/typescript/commonjs/components/DatePicker/DatePicker.d.ts +6 -3
  148. package/lib/typescript/commonjs/components/DateRangePicker/DateRangePicker.d.ts +6 -0
  149. package/lib/typescript/commonjs/components/Dialog/Dialog.d.ts +5 -2
  150. package/lib/typescript/commonjs/components/Drawer/Drawer.d.ts +3 -0
  151. package/lib/typescript/commonjs/components/FloatingActionButton/FloatingActionButton.d.ts +5 -0
  152. package/lib/typescript/commonjs/components/FormField/FormField.d.ts +13 -2
  153. package/lib/typescript/commonjs/components/ImageGallery/ImageGallery.d.ts +6 -0
  154. package/lib/typescript/commonjs/components/KeyboardAwareScrollView/KeyboardAwareScrollView.d.ts +20 -0
  155. package/lib/typescript/commonjs/components/KeyboardAwareScrollView/index.d.ts +3 -0
  156. package/lib/typescript/commonjs/components/KeyboardToolbar/KeyboardToolbar.d.ts +29 -0
  157. package/lib/typescript/commonjs/components/KeyboardToolbar/index.d.ts +3 -0
  158. package/lib/typescript/commonjs/components/ListItem/ListItem.d.ts +3 -0
  159. package/lib/typescript/commonjs/components/Modal/Modal.d.ts +6 -0
  160. package/lib/typescript/commonjs/components/NumberInput/NumberInput.d.ts +6 -2
  161. package/lib/typescript/commonjs/components/OTPInput/OTPInput.d.ts +9 -2
  162. package/lib/typescript/commonjs/components/Radio/Radio.d.ts +2 -2
  163. package/lib/typescript/commonjs/components/Radio/RadioGroup.d.ts +3 -2
  164. package/lib/typescript/commonjs/components/Rating/Rating.d.ts +6 -0
  165. package/lib/typescript/commonjs/components/SearchBar/SearchBar.d.ts +3 -0
  166. package/lib/typescript/commonjs/components/SegmentedControl/SegmentedControl.d.ts +6 -2
  167. package/lib/typescript/commonjs/components/Select/Select.d.ts +6 -0
  168. package/lib/typescript/commonjs/components/Slider/Slider.d.ts +9 -4
  169. package/lib/typescript/commonjs/components/Spinner/Spinner.d.ts +1 -1
  170. package/lib/typescript/commonjs/components/Stepper/Stepper.d.ts +6 -0
  171. package/lib/typescript/commonjs/components/Swipeable/Swipeable.d.ts +3 -0
  172. package/lib/typescript/commonjs/components/Switch/Switch.d.ts +3 -2
  173. package/lib/typescript/commonjs/components/Tabs/Tabs.d.ts +3 -0
  174. package/lib/typescript/commonjs/components/Text/Text.d.ts +25 -0
  175. package/lib/typescript/commonjs/components/Text/index.d.ts +3 -0
  176. package/lib/typescript/commonjs/components/TimePicker/TimePicker.d.ts +6 -3
  177. package/lib/typescript/commonjs/components/index.d.ts +10 -0
  178. package/lib/typescript/commonjs/form/FormContext.d.ts +17 -0
  179. package/lib/typescript/commonjs/form/index.d.ts +9 -0
  180. package/lib/typescript/commonjs/form/path.d.ts +10 -0
  181. package/lib/typescript/commonjs/form/rules.d.ts +31 -0
  182. package/lib/typescript/commonjs/form/types.d.ts +94 -0
  183. package/lib/typescript/commonjs/form/useField.d.ts +27 -0
  184. package/lib/typescript/commonjs/form/useForm.d.ts +10 -0
  185. package/lib/typescript/commonjs/hooks/index.d.ts +3 -0
  186. package/lib/typescript/commonjs/hooks/useControllableState.d.ts +17 -0
  187. package/lib/typescript/commonjs/hooks/useReducedMotion.d.ts +8 -0
  188. package/lib/typescript/commonjs/index.d.ts +4 -2
  189. package/lib/typescript/commonjs/theme/types.d.ts +17 -67
  190. package/lib/typescript/commonjs/utils/hapticUtils.d.ts +8 -0
  191. package/lib/typescript/commonjs/utils/index.d.ts +1 -1
  192. package/lib/typescript/module/components/Accordion/Accordion.d.ts +3 -0
  193. package/lib/typescript/module/components/AnimatePresence/AnimatePresence.d.ts +30 -0
  194. package/lib/typescript/module/components/AnimatePresence/index.d.ts +3 -0
  195. package/lib/typescript/module/components/AppBar/AppBar.d.ts +6 -0
  196. package/lib/typescript/module/components/Banner/Banner.d.ts +3 -0
  197. package/lib/typescript/module/components/BottomNavigation/BottomNavigation.d.ts +1 -1
  198. package/lib/typescript/module/components/Box/Box.d.ts +60 -0
  199. package/lib/typescript/module/components/Box/index.d.ts +3 -0
  200. package/lib/typescript/module/components/Button/Button.d.ts +1 -1
  201. package/lib/typescript/module/components/Card/Card.d.ts +3 -0
  202. package/lib/typescript/module/components/Checkbox/Checkbox.d.ts +4 -2
  203. package/lib/typescript/module/components/Chip/Chip.d.ts +3 -0
  204. package/lib/typescript/module/components/DatePicker/DatePicker.d.ts +6 -3
  205. package/lib/typescript/module/components/DateRangePicker/DateRangePicker.d.ts +6 -0
  206. package/lib/typescript/module/components/Dialog/Dialog.d.ts +5 -2
  207. package/lib/typescript/module/components/Drawer/Drawer.d.ts +3 -0
  208. package/lib/typescript/module/components/FloatingActionButton/FloatingActionButton.d.ts +5 -0
  209. package/lib/typescript/module/components/FormField/FormField.d.ts +13 -2
  210. package/lib/typescript/module/components/ImageGallery/ImageGallery.d.ts +6 -0
  211. package/lib/typescript/module/components/KeyboardAwareScrollView/KeyboardAwareScrollView.d.ts +20 -0
  212. package/lib/typescript/module/components/KeyboardAwareScrollView/index.d.ts +3 -0
  213. package/lib/typescript/module/components/KeyboardToolbar/KeyboardToolbar.d.ts +29 -0
  214. package/lib/typescript/module/components/KeyboardToolbar/index.d.ts +3 -0
  215. package/lib/typescript/module/components/ListItem/ListItem.d.ts +3 -0
  216. package/lib/typescript/module/components/Modal/Modal.d.ts +6 -0
  217. package/lib/typescript/module/components/NumberInput/NumberInput.d.ts +6 -2
  218. package/lib/typescript/module/components/OTPInput/OTPInput.d.ts +9 -2
  219. package/lib/typescript/module/components/Radio/Radio.d.ts +2 -2
  220. package/lib/typescript/module/components/Radio/RadioGroup.d.ts +3 -2
  221. package/lib/typescript/module/components/Rating/Rating.d.ts +6 -0
  222. package/lib/typescript/module/components/SearchBar/SearchBar.d.ts +3 -0
  223. package/lib/typescript/module/components/SegmentedControl/SegmentedControl.d.ts +6 -2
  224. package/lib/typescript/module/components/Select/Select.d.ts +6 -0
  225. package/lib/typescript/module/components/Slider/Slider.d.ts +9 -4
  226. package/lib/typescript/module/components/Spinner/Spinner.d.ts +1 -1
  227. package/lib/typescript/module/components/Stepper/Stepper.d.ts +6 -0
  228. package/lib/typescript/module/components/Swipeable/Swipeable.d.ts +3 -0
  229. package/lib/typescript/module/components/Switch/Switch.d.ts +3 -2
  230. package/lib/typescript/module/components/Tabs/Tabs.d.ts +3 -0
  231. package/lib/typescript/module/components/Text/Text.d.ts +25 -0
  232. package/lib/typescript/module/components/Text/index.d.ts +3 -0
  233. package/lib/typescript/module/components/TimePicker/TimePicker.d.ts +6 -3
  234. package/lib/typescript/module/components/index.d.ts +10 -0
  235. package/lib/typescript/module/form/FormContext.d.ts +17 -0
  236. package/lib/typescript/module/form/index.d.ts +9 -0
  237. package/lib/typescript/module/form/path.d.ts +10 -0
  238. package/lib/typescript/module/form/rules.d.ts +31 -0
  239. package/lib/typescript/module/form/types.d.ts +94 -0
  240. package/lib/typescript/module/form/useField.d.ts +27 -0
  241. package/lib/typescript/module/form/useForm.d.ts +10 -0
  242. package/lib/typescript/module/hooks/index.d.ts +3 -0
  243. package/lib/typescript/module/hooks/useControllableState.d.ts +17 -0
  244. package/lib/typescript/module/hooks/useReducedMotion.d.ts +8 -0
  245. package/lib/typescript/module/index.d.ts +4 -2
  246. package/lib/typescript/module/theme/types.d.ts +17 -67
  247. package/lib/typescript/module/utils/hapticUtils.d.ts +8 -0
  248. package/lib/typescript/module/utils/index.d.ts +1 -1
  249. package/package.json +1 -1
@@ -4,6 +4,7 @@ import React, { forwardRef, useCallback, useEffect, useMemo, useRef, useState }
4
4
  import { Animated, Easing, Pressable, StyleSheet, Text, TextInput, View } from 'react-native';
5
5
  import { createAnimatedValue, fontFor, setNativeValue, useTheme } from "../../theme/index.js";
6
6
  import { triggerHaptic } from "../../utils/index.js";
7
+ import { useReducedMotion } from "../../hooks/index.js";
7
8
  import { FieldBase, resolveFieldSize, resolveFieldTextStyle, resolveVariantColors } from "../FieldBase/FieldBase.js";
8
9
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
9
10
  // FieldBase carries every dimension except `multilineMinHeight` — Input owns
@@ -79,26 +80,31 @@ const Input = /*#__PURE__*/forwardRef((props, ref) => {
79
80
 
80
81
  // Floating label animation
81
82
  useEffect(() => {
82
- Animated.timing(labelAnim, {
83
+ const anim = Animated.timing(labelAnim, {
83
84
  toValue: shouldFloat ? 1 : 0,
84
85
  duration: theme.motion.duration.fast,
85
86
  easing: Easing.bezier(...theme.motion.easing.standard),
86
87
  useNativeDriver: false
87
- }).start();
88
+ });
89
+ anim.start();
90
+ return () => anim.stop();
88
91
  }, [shouldFloat, labelAnim, theme.motion.duration.fast, theme.motion.easing.standard]);
89
92
 
90
93
  // Helper / error fade
91
94
  useEffect(() => {
92
- Animated.timing(messageAnim, {
95
+ const anim = Animated.timing(messageAnim, {
93
96
  toValue: hasError || Boolean(helperText) ? 1 : 0,
94
- duration: 150,
97
+ duration: theme.motion.duration.fast,
95
98
  easing: Easing.bezier(...theme.motion.easing.standard),
96
99
  useNativeDriver: true
97
- }).start();
98
- }, [hasError, helperText, messageAnim, theme.motion.easing.standard]);
100
+ });
101
+ anim.start();
102
+ return () => anim.stop();
103
+ }, [hasError, helperText, messageAnim, theme.motion.duration.fast, theme.motion.easing.standard]);
99
104
 
100
105
  // Error shake — off by default; consumers opt in via
101
106
  // theme.components.input.shakeOnError. The haptic ships with the shake.
107
+ const reduceMotion = useReducedMotion();
102
108
  const shakeOnError = theme.components.input?.shakeOnError ?? false;
103
109
  const prevErrorRef = useRef(hasError);
104
110
  useEffect(() => {
@@ -106,33 +112,39 @@ const Input = /*#__PURE__*/forwardRef((props, ref) => {
106
112
  prevErrorRef.current = hasError;
107
113
  return;
108
114
  }
115
+ let anim;
109
116
  if (hasError && !prevErrorRef.current) {
110
- setNativeValue(shakeAnim, 0);
111
- Animated.sequence([Animated.timing(shakeAnim, {
112
- toValue: 1,
113
- duration: 50,
114
- useNativeDriver: true
115
- }), Animated.timing(shakeAnim, {
116
- toValue: -1,
117
- duration: 50,
118
- useNativeDriver: true
119
- }), Animated.timing(shakeAnim, {
120
- toValue: 1,
121
- duration: 50,
122
- useNativeDriver: true
123
- }), Animated.timing(shakeAnim, {
124
- toValue: -1,
125
- duration: 50,
126
- useNativeDriver: true
127
- }), Animated.timing(shakeAnim, {
128
- toValue: 0,
129
- duration: 100,
130
- useNativeDriver: true
131
- })]).start();
117
+ // Reduce Motion: keep the error haptic, skip the shake.
118
+ if (!reduceMotion) {
119
+ setNativeValue(shakeAnim, 0);
120
+ anim = Animated.sequence([Animated.timing(shakeAnim, {
121
+ toValue: 1,
122
+ duration: 50,
123
+ useNativeDriver: true
124
+ }), Animated.timing(shakeAnim, {
125
+ toValue: -1,
126
+ duration: 50,
127
+ useNativeDriver: true
128
+ }), Animated.timing(shakeAnim, {
129
+ toValue: 1,
130
+ duration: 50,
131
+ useNativeDriver: true
132
+ }), Animated.timing(shakeAnim, {
133
+ toValue: -1,
134
+ duration: 50,
135
+ useNativeDriver: true
136
+ }), Animated.timing(shakeAnim, {
137
+ toValue: 0,
138
+ duration: 100,
139
+ useNativeDriver: true
140
+ })]);
141
+ anim.start();
142
+ }
132
143
  triggerHaptic('notificationError');
133
144
  }
134
145
  prevErrorRef.current = hasError;
135
- }, [hasError, shakeAnim, shakeOnError]);
146
+ return () => anim?.stop();
147
+ }, [hasError, shakeAnim, shakeOnError, reduceMotion]);
136
148
  const handleFocus = useCallback(e => {
137
149
  setIsFocused(true);
138
150
  onFocus?.(e);
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+
3
+ import React, { forwardRef, useCallback, useEffect, useRef, useState } from 'react';
4
+ import { findNodeHandle, Keyboard, Platform, ScrollView, TextInput } from 'react-native';
5
+ import { jsx as _jsx } from "react/jsx-runtime";
6
+ /**
7
+ * A ScrollView that keeps the focused input visible above the keyboard — no
8
+ * native dependency. On keyboard show it pads the content by the keyboard
9
+ * height and scrolls the focused TextInput so its bottom sits `extraScrollHeight`
10
+ * above the keyboard, but only when it would otherwise be covered (so already-
11
+ * visible fields don't jump). The classic measure-and-scroll approach, in pure RN.
12
+ */
13
+ const KeyboardAwareScrollView = /*#__PURE__*/forwardRef((props, ref) => {
14
+ const {
15
+ children,
16
+ extraScrollHeight = 24,
17
+ disabled = false,
18
+ contentContainerStyle,
19
+ onScroll,
20
+ onLayout,
21
+ ...rest
22
+ } = props;
23
+ const scrollRef = useRef(null);
24
+ const scrollYRef = useRef(0);
25
+ const viewportHeightRef = useRef(0);
26
+ const [keyboardHeight, setKeyboardHeight] = useState(0);
27
+ const setRefs = useCallback(node => {
28
+ scrollRef.current = node;
29
+ if (typeof ref === 'function') ref(node);else if (ref) ref.current = node;
30
+ }, [ref]);
31
+ const scrollFocusedIntoView = useCallback(kbHeight => {
32
+ const scroll = scrollRef.current;
33
+ const scrollNode = scroll ? findNodeHandle(scroll) : null;
34
+ const stateApi = TextInput?.State;
35
+ const focused = stateApi?.currentlyFocusedInput?.();
36
+ if (!scroll || scrollNode == null || !focused?.measureLayout) return;
37
+ focused.measureLayout(scrollNode, (_left, top, _width, height) => {
38
+ const scrollY = scrollYRef.current;
39
+ const viewportH = viewportHeightRef.current;
40
+ if (viewportH <= 0) return;
41
+ const keyboardTop = viewportH - kbHeight - extraScrollHeight;
42
+ const fieldBottomInViewport = top - scrollY + height;
43
+ if (fieldBottomInViewport > keyboardTop) {
44
+ const delta = fieldBottomInViewport - keyboardTop;
45
+ scroll.scrollTo({
46
+ y: scrollY + delta,
47
+ animated: true
48
+ });
49
+ }
50
+ }, () => undefined);
51
+ }, [extraScrollHeight]);
52
+ useEffect(() => {
53
+ if (disabled) return undefined;
54
+ // iOS exposes the will* events (smoother); Android only fires did*.
55
+ const showEvent = Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow';
56
+ const hideEvent = Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide';
57
+ let rafId;
58
+ const showSub = Keyboard.addListener(showEvent, e => {
59
+ const height = e.endCoordinates?.height ?? 0;
60
+ setKeyboardHeight(height);
61
+ // Wait a frame so the padding is applied before we scroll. Tracked so
62
+ // it can be cancelled on unmount (never runs against a torn-down tree).
63
+ if (rafId != null) cancelAnimationFrame(rafId);
64
+ rafId = requestAnimationFrame(() => scrollFocusedIntoView(height));
65
+ });
66
+ const hideSub = Keyboard.addListener(hideEvent, () => setKeyboardHeight(0));
67
+ return () => {
68
+ if (rafId != null) cancelAnimationFrame(rafId);
69
+ showSub.remove();
70
+ hideSub.remove();
71
+ };
72
+ }, [disabled, scrollFocusedIntoView]);
73
+ const handleScroll = useCallback(e => {
74
+ scrollYRef.current = e.nativeEvent.contentOffset.y;
75
+ onScroll?.(e);
76
+ }, [onScroll]);
77
+ const handleLayout = useCallback(e => {
78
+ viewportHeightRef.current = e.nativeEvent.layout.height;
79
+ onLayout?.(e);
80
+ }, [onLayout]);
81
+ return /*#__PURE__*/_jsx(ScrollView, {
82
+ ref: setRefs,
83
+ onScroll: handleScroll,
84
+ onLayout: handleLayout,
85
+ scrollEventThrottle: 16,
86
+ keyboardShouldPersistTaps: "handled",
87
+ keyboardDismissMode: Platform.OS === 'ios' ? 'interactive' : 'on-drag',
88
+ contentContainerStyle: [contentContainerStyle, {
89
+ paddingBottom: keyboardHeight
90
+ }],
91
+ ...rest,
92
+ children: children
93
+ });
94
+ });
95
+ KeyboardAwareScrollView.displayName = 'KeyboardAwareScrollView';
96
+ export { KeyboardAwareScrollView };
97
+ export default KeyboardAwareScrollView;
98
+ //# sourceMappingURL=KeyboardAwareScrollView.js.map
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+
3
+ export { KeyboardAwareScrollView } from "./KeyboardAwareScrollView.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+
3
+ import React, { useEffect, useState } from 'react';
4
+ import { Keyboard, Platform, Pressable, StyleSheet, View } from 'react-native';
5
+ import { useTheme } from "../../theme/index.js";
6
+ import { useOptionalFormContext } from "../../form/FormContext.js";
7
+ import { Text } from "../Text/index.js";
8
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
9
+ const NavButton = ({
10
+ label,
11
+ accessibilityLabel,
12
+ onPress,
13
+ theme
14
+ }) => /*#__PURE__*/_jsx(Pressable, {
15
+ onPress: onPress,
16
+ disabled: !onPress,
17
+ accessibilityRole: "button",
18
+ accessibilityLabel: accessibilityLabel,
19
+ hitSlop: 8,
20
+ style: {
21
+ paddingHorizontal: theme.spacing.sm,
22
+ opacity: onPress ? 1 : 0.4
23
+ },
24
+ children: /*#__PURE__*/_jsx(Text, {
25
+ variant: "h2",
26
+ color: onPress ? 'link' : 'disabled',
27
+ children: label
28
+ })
29
+ });
30
+
31
+ /**
32
+ * An accessory bar pinned just above the keyboard — pure RN, no native
33
+ * dependency. Shows a Done (dismiss) button and optional prev/next chevrons
34
+ * that, inside a `<Form>`, walk the registered field order. Render it at the
35
+ * screen root (a `flex: 1` ancestor) so its `bottom: keyboardHeight` offset
36
+ * lands it on top of the keyboard. Renders nothing while the keyboard is hidden.
37
+ */
38
+ const KeyboardToolbar = props => {
39
+ const {
40
+ doneLabel = 'Done',
41
+ showNavigation,
42
+ onDone,
43
+ onNext,
44
+ onPrev,
45
+ leading,
46
+ style,
47
+ testID
48
+ } = props;
49
+ const theme = useTheme();
50
+ const form = useOptionalFormContext();
51
+ const [keyboardHeight, setKeyboardHeight] = useState(0);
52
+ useEffect(() => {
53
+ const showEvent = Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow';
54
+ const hideEvent = Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide';
55
+ const showSub = Keyboard.addListener(showEvent, e => setKeyboardHeight(e.endCoordinates?.height ?? 0));
56
+ const hideSub = Keyboard.addListener(hideEvent, () => setKeyboardHeight(0));
57
+ return () => {
58
+ showSub.remove();
59
+ hideSub.remove();
60
+ };
61
+ }, []);
62
+ if (keyboardHeight <= 0) return null;
63
+ const handleDone = onDone ?? (() => Keyboard.dismiss());
64
+ const handlePrev = onPrev ?? form?.focusPrev;
65
+ const handleNext = onNext ?? form?.focusNext;
66
+ const navEnabled = showNavigation ?? Boolean(handlePrev || handleNext);
67
+ return /*#__PURE__*/_jsxs(View, {
68
+ testID: testID,
69
+ accessibilityRole: "toolbar",
70
+ style: [styles.bar, {
71
+ bottom: keyboardHeight,
72
+ backgroundColor: theme.colors.background.elevated,
73
+ borderTopColor: theme.colors.border.primary,
74
+ paddingHorizontal: theme.spacing.md
75
+ }, style],
76
+ children: [navEnabled ? /*#__PURE__*/_jsxs(View, {
77
+ style: styles.nav,
78
+ children: [/*#__PURE__*/_jsx(NavButton, {
79
+ label: "\u2039",
80
+ accessibilityLabel: "Previous field",
81
+ onPress: handlePrev,
82
+ theme: theme
83
+ }), /*#__PURE__*/_jsx(NavButton, {
84
+ label: "\u203A",
85
+ accessibilityLabel: "Next field",
86
+ onPress: handleNext,
87
+ theme: theme
88
+ })]
89
+ }) : /*#__PURE__*/_jsx(View, {}), leading, /*#__PURE__*/_jsx(View, {
90
+ style: styles.spacer
91
+ }), /*#__PURE__*/_jsx(Pressable, {
92
+ onPress: handleDone,
93
+ accessibilityRole: "button",
94
+ accessibilityLabel: doneLabel,
95
+ hitSlop: 8,
96
+ children: /*#__PURE__*/_jsx(Text, {
97
+ variant: "body",
98
+ weight: "semibold",
99
+ color: "link",
100
+ children: doneLabel
101
+ })
102
+ })]
103
+ });
104
+ };
105
+ const styles = StyleSheet.create({
106
+ bar: {
107
+ position: 'absolute',
108
+ left: 0,
109
+ right: 0,
110
+ height: 44,
111
+ flexDirection: 'row',
112
+ alignItems: 'center',
113
+ borderTopWidth: StyleSheet.hairlineWidth
114
+ },
115
+ nav: {
116
+ flexDirection: 'row',
117
+ alignItems: 'center'
118
+ },
119
+ spacer: {
120
+ flex: 1
121
+ }
122
+ });
123
+ export { KeyboardToolbar };
124
+ export default KeyboardToolbar;
125
+ //# sourceMappingURL=KeyboardToolbar.js.map
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+
3
+ export { KeyboardToolbar } from "./KeyboardToolbar.js";
4
+ //# sourceMappingURL=index.js.map
@@ -4,7 +4,7 @@ import React, { forwardRef, useMemo } from 'react';
4
4
  import { Animated, Pressable, StyleSheet, Text, View } from 'react-native';
5
5
  import { fontFor, useTheme } from "../../theme/index.js";
6
6
  import { usePressAnimation } from "../../hooks/usePressAnimation.js";
7
- import { triggerHaptic } from "../../utils/hapticUtils.js";
7
+ import { resolveHaptic, triggerHaptic } from "../../utils/hapticUtils.js";
8
8
  import { Swipeable } from "../Swipeable/index.js";
9
9
  import { Skeleton } from "../Skeleton/index.js";
10
10
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
@@ -64,6 +64,7 @@ const ListItem = /*#__PURE__*/forwardRef((props, ref) => {
64
64
  left,
65
65
  right,
66
66
  onPress,
67
+ haptic,
67
68
  selected = false,
68
69
  disabled = false,
69
70
  size = 'md',
@@ -83,7 +84,6 @@ const ListItem = /*#__PURE__*/forwardRef((props, ref) => {
83
84
  testID
84
85
  } = props;
85
86
  const theme = useTheme();
86
- const pressHaptic = theme.components.listItem?.pressHaptic ?? false;
87
87
  const sz = useMemo(() => sizeFor(theme, size), [theme, size]);
88
88
  const styles = useMemo(() => buildStyles(theme), [theme]);
89
89
  const isInteractive = !!onPress && !disabled;
@@ -96,7 +96,8 @@ const ListItem = /*#__PURE__*/forwardRef((props, ref) => {
96
96
  });
97
97
  const handlePress = event => {
98
98
  if (!isInteractive) return;
99
- if (pressHaptic) triggerHaptic('selection');
99
+ const h = resolveHaptic(haptic, 'selection');
100
+ if (h) triggerHaptic(h);
100
101
  onPress?.(event);
101
102
  };
102
103
  const a11yLabel = accessibilityLabel ?? title;
@@ -291,7 +292,7 @@ const buildStyles = theme => StyleSheet.create({
291
292
  backgroundColor: theme.colors.surface.pressed
292
293
  },
293
294
  disabled: {
294
- opacity: 0.6
295
+ opacity: 0.55
295
296
  },
296
297
  leftSlot: {
297
298
  marginRight: theme.spacing.md,
@@ -4,7 +4,7 @@ import React, { forwardRef, useCallback, useEffect, useMemo, useRef } from 'reac
4
4
  import { AccessibilityInfo, Animated, Dimensions, findNodeHandle, Modal as RNModal, Pressable, StyleSheet, View } from 'react-native';
5
5
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
6
6
  import { useTheme, createAnimatedValue, setNativeValue } from "../../theme/index.js";
7
- import { triggerHaptic } from "../../utils/hapticUtils.js";
7
+ import { triggerHaptic, resolveHaptic } from "../../utils/hapticUtils.js";
8
8
 
9
9
  // Local shape mirror — see types.ts ModalTokens for the canonical definition.
10
10
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
@@ -22,6 +22,7 @@ const Modal = /*#__PURE__*/forwardRef((props, ref) => {
22
22
  contentStyle,
23
23
  backdropStyle,
24
24
  restoreFocusRef,
25
+ haptic,
25
26
  testID
26
27
  } = props;
27
28
  const theme = useTheme();
@@ -30,7 +31,6 @@ const Modal = /*#__PURE__*/forwardRef((props, ref) => {
30
31
  const screenHeight = Dimensions.get('window').height;
31
32
  const modalTokens = theme.components.modal;
32
33
  const scaleStartValue = modalTokens?.scaleStartValue ?? 0.9;
33
- const backdropHaptic = modalTokens?.backdropHaptic ?? false;
34
34
  const backdropAnim = useRef(createAnimatedValue(0)).current;
35
35
  const scaleAnim = useRef(createAnimatedValue(scaleStartValue)).current;
36
36
  const opacityAnim = useRef(createAnimatedValue(0)).current;
@@ -39,6 +39,7 @@ const Modal = /*#__PURE__*/forwardRef((props, ref) => {
39
39
  const wasVisibleRef = useRef(false);
40
40
  const styles = useMemo(() => buildStyles(theme), [theme]);
41
41
  useEffect(() => {
42
+ const running = [];
42
43
  if (visible) {
43
44
  // Two Fabric quirks force this combination: backdrop View needs
44
45
  // `collapsable={false}` (see render) so flattening doesn't drop it,
@@ -46,21 +47,25 @@ const Modal = /*#__PURE__*/forwardRef((props, ref) => {
46
47
  // Animated.View that also sets backgroundColor inline renders as 0 on
47
48
  // RN 0.85 / Fabric / iOS, leaving the dim layer invisible. Single
48
49
  // 240ms tween — JS thread cost is negligible.
49
- Animated.timing(backdropAnim, {
50
+ const backdrop = Animated.timing(backdropAnim, {
50
51
  toValue: 1,
51
52
  duration,
52
53
  useNativeDriver: false
53
- }).start();
54
+ });
55
+ backdrop.start();
56
+ running.push(backdrop);
54
57
  if (presentation === 'bottom') {
55
- Animated.spring(translateYAnim, {
58
+ const slide = Animated.spring(translateYAnim, {
56
59
  toValue: 0,
57
60
  damping: theme.motion.spring.gentle.damping,
58
61
  stiffness: theme.motion.spring.gentle.stiffness,
59
62
  mass: theme.motion.spring.gentle.mass,
60
63
  useNativeDriver: true
61
- }).start();
64
+ });
65
+ slide.start();
66
+ running.push(slide);
62
67
  } else {
63
- Animated.parallel([Animated.spring(scaleAnim, {
68
+ const enter = Animated.parallel([Animated.spring(scaleAnim, {
64
69
  toValue: 1,
65
70
  damping: theme.motion.spring.gentle.damping,
66
71
  stiffness: theme.motion.spring.gentle.stiffness,
@@ -70,7 +75,9 @@ const Modal = /*#__PURE__*/forwardRef((props, ref) => {
70
75
  toValue: 1,
71
76
  duration,
72
77
  useNativeDriver: true
73
- })]).start();
78
+ })]);
79
+ enter.start();
80
+ running.push(enter);
74
81
  }
75
82
  } else {
76
83
  // backdropAnim is JS-driven (see note above) — reset directly so a
@@ -80,6 +87,10 @@ const Modal = /*#__PURE__*/forwardRef((props, ref) => {
80
87
  setNativeValue(opacityAnim, 0);
81
88
  setNativeValue(translateYAnim, screenHeight);
82
89
  }
90
+ // Stop in-flight tweens on unmount / visibility flip so an enter animation
91
+ // never resolves against a torn-down tree (fixes the jest async leak and
92
+ // the equivalent post-unmount work in the real app).
93
+ return () => running.forEach(animation => animation.stop());
83
94
  }, [visible, presentation, duration, backdropAnim, scaleAnim, opacityAnim, translateYAnim, screenHeight, theme.motion.spring.gentle.damping, theme.motion.spring.gentle.stiffness, theme.motion.spring.gentle.mass, scaleStartValue]);
84
95
 
85
96
  // Accessibility focus trap: when the modal opens, push screen-reader focus
@@ -115,9 +126,10 @@ const Modal = /*#__PURE__*/forwardRef((props, ref) => {
115
126
  }, [visible, duration, restoreFocusRef]);
116
127
  const handleBackdropPress = useCallback(() => {
117
128
  if (!backdropPressClose) return;
118
- if (backdropHaptic) triggerHaptic('selection');
129
+ const h = resolveHaptic(haptic, 'selection');
130
+ if (h) triggerHaptic(h);
119
131
  onRequestClose();
120
- }, [backdropPressClose, onRequestClose, backdropHaptic]);
132
+ }, [backdropPressClose, onRequestClose, haptic]);
121
133
  const handleHardwareBack = useCallback(() => {
122
134
  if (hardwareBackPress) {
123
135
  onRequestClose();
@@ -2,8 +2,9 @@
2
2
 
3
3
  import React, { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from 'react';
4
4
  import { Pressable, StyleSheet, Text, TextInput, View } from 'react-native';
5
+ import { useControllableState } from "../../hooks/index.js";
5
6
  import { useTheme } from "../../theme/index.js";
6
- import { triggerHaptic } from "../../utils/index.js";
7
+ import { resolveHaptic, triggerHaptic } from "../../utils/index.js";
7
8
  import { FieldBase, resolveFieldSize, resolveFieldTextStyle } from "../FieldBase/FieldBase.js";
8
9
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
9
10
  const DEFAULT_LONG_PRESS_DELAY = 500;
@@ -43,6 +44,7 @@ const sanitizeTyped = (raw, allowDecimal) => {
43
44
  const NumberInput = /*#__PURE__*/forwardRef((props, ref) => {
44
45
  const {
45
46
  value,
47
+ defaultValue,
46
48
  onChange,
47
49
  min = Number.NEGATIVE_INFINITY,
48
50
  max = Number.POSITIVE_INFINITY,
@@ -56,6 +58,7 @@ const NumberInput = /*#__PURE__*/forwardRef((props, ref) => {
56
58
  size = 'md',
57
59
  variant = 'inline',
58
60
  unit,
61
+ haptic,
59
62
  accessibilityLabel,
60
63
  style,
61
64
  containerStyle,
@@ -66,6 +69,11 @@ const NumberInput = /*#__PURE__*/forwardRef((props, ref) => {
66
69
  textInputProps,
67
70
  testID
68
71
  } = props;
72
+ const [current, setCurrent] = useControllableState({
73
+ value,
74
+ defaultValue: defaultValue ?? props.min ?? 0,
75
+ onChange
76
+ });
69
77
  const theme = useTheme();
70
78
  const sizeTokens = resolveFieldSize(theme, size);
71
79
  const fieldText = resolveFieldTextStyle(theme, {
@@ -74,9 +82,8 @@ const NumberInput = /*#__PURE__*/forwardRef((props, ref) => {
74
82
  const styles = useMemo(() => buildStyles(theme), [theme]);
75
83
  const longPressDelay = theme.components.numberInput?.longPressDelayMs ?? DEFAULT_LONG_PRESS_DELAY;
76
84
  const longPressInterval = theme.components.numberInput?.longPressIntervalMs ?? DEFAULT_LONG_PRESS_INTERVAL;
77
- const pressHaptic = theme.components.numberInput?.pressHaptic ?? false;
78
85
  const inputRef = useRef(null);
79
- const [draft, setDraft] = useState(formatValue(value, allowDecimal, precision));
86
+ const [draft, setDraft] = useState(formatValue(current, allowDecimal, precision));
80
87
  const [editing, setEditing] = useState(false);
81
88
  const [focused, setFocused] = useState(false);
82
89
  const repeatTimeoutRef = useRef(null);
@@ -94,41 +101,43 @@ const NumberInput = /*#__PURE__*/forwardRef((props, ref) => {
94
101
  useEffect(() => clearRepeat, [clearRepeat]);
95
102
  useEffect(() => {
96
103
  if (!editing) {
97
- setDraft(formatValue(value, allowDecimal, precision));
104
+ setDraft(formatValue(current, allowDecimal, precision));
98
105
  }
99
- }, [value, allowDecimal, precision, editing]);
100
- const atMin = value <= min;
101
- const atMax = value >= max;
106
+ }, [current, allowDecimal, precision, editing]);
107
+ const atMin = current <= min;
108
+ const atMax = current >= max;
102
109
  const interactive = !disabled;
103
110
  const setExternal = useCallback(next => {
104
111
  const rounded = roundToPrecision(next, allowDecimal ? precision : 0);
105
112
  const clamped = clamp(rounded, min, max);
106
- if (clamped !== value) {
107
- onChange(clamped);
113
+ if (clamped !== current) {
114
+ setCurrent(clamped);
108
115
  }
109
- }, [allowDecimal, max, min, onChange, precision, value]);
116
+ }, [allowDecimal, max, min, setCurrent, precision, current]);
110
117
  const decrement = useCallback(() => {
111
118
  if (!interactive || atMin) return;
112
- if (pressHaptic) triggerHaptic('impactLight');
113
- setExternal(value - step);
114
- }, [atMin, interactive, pressHaptic, setExternal, step, value]);
119
+ const h = resolveHaptic(haptic, 'selection');
120
+ if (h) triggerHaptic(h);
121
+ setExternal(current - step);
122
+ }, [atMin, interactive, haptic, setExternal, step, current]);
115
123
  const increment = useCallback(() => {
116
124
  if (!interactive || atMax) return;
117
- if (pressHaptic) triggerHaptic('impactLight');
118
- setExternal(value + step);
119
- }, [atMax, interactive, pressHaptic, setExternal, step, value]);
125
+ const h = resolveHaptic(haptic, 'selection');
126
+ if (h) triggerHaptic(h);
127
+ setExternal(current + step);
128
+ }, [atMax, interactive, haptic, setExternal, step, current]);
120
129
  React.useImperativeHandle(ref, () => ({
121
130
  focus: () => inputRef.current?.focus(),
122
131
  blur: () => inputRef.current?.blur(),
123
132
  clear: () => {
124
133
  setDraft('');
125
134
  if (Number.isFinite(min) && min > 0) {
126
- onChange(min);
135
+ setCurrent(min);
127
136
  } else {
128
- onChange(0 < min ? min : 0 > max ? max : 0);
137
+ setCurrent(0 < min ? min : 0 > max ? max : 0);
129
138
  }
130
139
  }
131
- }), [max, min, onChange]);
140
+ }), [max, min, setCurrent]);
132
141
  const startRepeating = useCallback(direction => {
133
142
  if (!interactive) return;
134
143
  clearRepeat();
@@ -148,27 +157,27 @@ const NumberInput = /*#__PURE__*/forwardRef((props, ref) => {
148
157
  const parsed = Number(cleaned);
149
158
  if (cleaned !== '' && cleaned !== '-' && cleaned !== '.' && Number.isFinite(parsed)) {
150
159
  if (parsed >= min && parsed <= max) {
151
- if (parsed !== value) {
152
- onChange(roundToPrecision(parsed, allowDecimal ? precision : 0));
160
+ if (parsed !== current) {
161
+ setCurrent(roundToPrecision(parsed, allowDecimal ? precision : 0));
153
162
  }
154
163
  }
155
164
  }
156
- }, [allowDecimal, max, min, onChange, precision, value]);
165
+ }, [allowDecimal, max, min, setCurrent, precision, current]);
157
166
  const handleBlur = useCallback(() => {
158
167
  setEditing(false);
159
168
  setFocused(false);
160
169
  const parsed = Number(draft);
161
170
  if (draft === '' || !Number.isFinite(parsed)) {
162
- setDraft(formatValue(value, allowDecimal, precision));
171
+ setDraft(formatValue(current, allowDecimal, precision));
163
172
  return;
164
173
  }
165
174
  const rounded = roundToPrecision(parsed, allowDecimal ? precision : 0);
166
175
  const clamped = clamp(rounded, min, max);
167
- if (clamped !== value) {
168
- onChange(clamped);
176
+ if (clamped !== current) {
177
+ setCurrent(clamped);
169
178
  }
170
179
  setDraft(formatValue(clamped, allowDecimal, precision));
171
- }, [allowDecimal, draft, max, min, onChange, precision, value]);
180
+ }, [allowDecimal, draft, max, min, setCurrent, precision, current]);
172
181
  const handleFocus = useCallback(() => {
173
182
  setEditing(true);
174
183
  setFocused(true);
@@ -232,7 +241,7 @@ const NumberInput = /*#__PURE__*/forwardRef((props, ref) => {
232
241
  accessibilityRole: "adjustable",
233
242
  accessibilityLabel: accessibleInputLabel,
234
243
  accessibilityValue: {
235
- now: Number.isFinite(value) ? value : 0
244
+ now: Number.isFinite(current) ? current : 0
236
245
  },
237
246
  accessibilityState: {
238
247
  disabled