@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,7 +4,7 @@ import React, { forwardRef, useCallback, useEffect, useMemo, useRef, useState }
4
4
  import { AccessibilityInfo, Animated, Easing, Modal, Pressable, StyleSheet, Text, 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/index.js";
7
+ import { triggerHaptic, resolveHaptic } from "../../utils/index.js";
8
8
  import { PickerTrigger } from "../PickerTrigger/index.js";
9
9
 
10
10
  /**
@@ -103,6 +103,7 @@ const DateRangePicker = /*#__PURE__*/forwardRef((props, ref) => {
103
103
  confirmLabel = 'Confirm',
104
104
  cancelLabel = 'Cancel',
105
105
  maxRange,
106
+ haptic,
106
107
  style,
107
108
  containerStyle,
108
109
  headerLabelStyle,
@@ -147,10 +148,11 @@ const DateRangePicker = /*#__PURE__*/forwardRef((props, ref) => {
147
148
  // Modal open / close animation. Backdrop opacity uses JS driver — see
148
149
  // Modal.tsx for the Fabric reason. Sheet transform stays native.
149
150
  useEffect(() => {
151
+ let anim;
150
152
  if (open) {
151
153
  backdrop.setValue(0);
152
154
  setNativeValue(sheet, 0);
153
- Animated.parallel([Animated.timing(backdrop, {
155
+ anim = Animated.parallel([Animated.timing(backdrop, {
154
156
  toValue: 1,
155
157
  duration: theme.motion.duration.normal,
156
158
  easing: Easing.out(Easing.cubic),
@@ -161,8 +163,10 @@ const DateRangePicker = /*#__PURE__*/forwardRef((props, ref) => {
161
163
  stiffness: theme.motion.spring.gentle.stiffness,
162
164
  mass: theme.motion.spring.gentle.mass,
163
165
  useNativeDriver: true
164
- })]).start();
166
+ })]);
167
+ anim.start();
165
168
  }
169
+ return () => anim?.stop();
166
170
  }, [open, backdrop, sheet, theme.motion]);
167
171
  const disabledIsoSet = useMemo(() => {
168
172
  const set = new Set();
@@ -181,7 +185,7 @@ const DateRangePicker = /*#__PURE__*/forwardRef((props, ref) => {
181
185
  const headerLabel = useMemo(() => formatMonthYear(anchor, locale), [anchor, locale]);
182
186
  const weekdays = useMemo(() => weekdayLabels(locale, weekStartsOn), [locale, weekStartsOn]);
183
187
  const animateMonthChange = useCallback(delta => {
184
- if (theme.components.dateRangePicker?.haptic) triggerHaptic('impactLight');
188
+ if (haptic !== false) triggerHaptic('impactLight');
185
189
  const direction = delta > 0 ? 1 : -1;
186
190
  const distance = theme.components.dateRangePicker?.monthSlideDistance ?? 32;
187
191
  const outDuration = theme.components.dateRangePicker?.monthSlideOutDuration ?? theme.motion.duration.fast ?? 140;
@@ -212,12 +216,13 @@ const DateRangePicker = /*#__PURE__*/forwardRef((props, ref) => {
212
216
  const next = addMonths(anchor, delta);
213
217
  setAnchor(next);
214
218
  AccessibilityInfo.announceForAccessibility(formatMonthYear(next, locale));
215
- }, [anchor, locale, monthFade, monthSlide, theme.components.dateRangePicker, theme.motion.duration.fast]);
219
+ }, [anchor, haptic, locale, monthFade, monthSlide, theme.components.dateRangePicker, theme.motion.duration.fast]);
216
220
  const goPrev = useCallback(() => animateMonthChange(-1), [animateMonthChange]);
217
221
  const goNext = useCallback(() => animateMonthChange(1), [animateMonthChange]);
218
222
  const pressDay = useCallback(cell => {
219
223
  if (isDisabled(cell.date)) return;
220
- if (theme.components.dateRangePicker?.haptic) triggerHaptic('selection');
224
+ const h = resolveHaptic(haptic, 'selection');
225
+ if (h) triggerHaptic(h);
221
226
  const target = cell.date;
222
227
 
223
228
  // First tap: pick start. Or, when there's already a complete range, restart.
@@ -236,7 +241,7 @@ const DateRangePicker = /*#__PURE__*/forwardRef((props, ref) => {
236
241
  } else {
237
242
  if (maxRange && daysBetween(pendingStart, target) + 1 > maxRange) {
238
243
  // Reject ranges longer than maxRange — restart from the new tap.
239
- if (theme.components.dateRangePicker?.haptic) triggerHaptic('notificationWarning');
244
+ if (haptic !== false) triggerHaptic('notificationWarning');
240
245
  setPendingStart(target);
241
246
  setPendingEnd(null);
242
247
  return;
@@ -247,7 +252,7 @@ const DateRangePicker = /*#__PURE__*/forwardRef((props, ref) => {
247
252
  if (!cell.inMonth) {
248
253
  setAnchor(new Date(cell.date.getFullYear(), cell.date.getMonth(), 1));
249
254
  }
250
- }, [isDisabled, pendingStart, pendingEnd, maxRange, theme.components.dateRangePicker]);
255
+ }, [isDisabled, pendingStart, pendingEnd, maxRange, haptic]);
251
256
  const handleCloseModal = useCallback(() => {
252
257
  if (isControlled) {
253
258
  onClose?.();
@@ -271,18 +276,18 @@ const DateRangePicker = /*#__PURE__*/forwardRef((props, ref) => {
271
276
  });
272
277
  }, [backdrop, handleCloseModal, sheet, theme.motion.duration.fast]);
273
278
  const handleCancel = useCallback(() => {
274
- if (theme.components.dateRangePicker?.haptic) triggerHaptic('selection');
279
+ if (haptic !== false) triggerHaptic('selection');
275
280
  handleClose();
276
- }, [handleClose, theme.components.dateRangePicker]);
281
+ }, [handleClose, haptic]);
277
282
  const handleConfirm = useCallback(() => {
278
283
  if (!pendingStart || !pendingEnd) return;
279
- if (theme.components.dateRangePicker?.haptic) triggerHaptic('notificationSuccess');
284
+ if (haptic !== false) triggerHaptic('notificationSuccess');
280
285
  onChange?.({
281
286
  start: pendingStart,
282
287
  end: pendingEnd
283
288
  });
284
289
  handleClose();
285
- }, [handleClose, onChange, pendingStart, pendingEnd, theme.components.dateRangePicker]);
290
+ }, [handleClose, onChange, pendingStart, pendingEnd, haptic]);
286
291
  const sheetTranslate = sheet.interpolate({
287
292
  inputRange: [0, 1],
288
293
  outputRange: [320, 0]
@@ -3,7 +3,7 @@
3
3
  import React, { useCallback, useMemo } from 'react';
4
4
  import { ActivityIndicator, Pressable, StyleSheet, Text, View } from 'react-native';
5
5
  import { fontFor, useTheme } from "../../theme/index.js";
6
- import { triggerHaptic } from "../../utils/hapticUtils.js";
6
+ import { resolveHaptic, triggerHaptic } from "../../utils/hapticUtils.js";
7
7
  import { Modal } from "../Modal/Modal.js";
8
8
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
9
9
  const Dialog = props => {
@@ -25,6 +25,7 @@ const Dialog = props => {
25
25
  actionsRowStyle,
26
26
  actionButtonStyle,
27
27
  actionTextStyle,
28
+ haptic,
28
29
  testID
29
30
  } = props;
30
31
  const theme = useTheme();
@@ -36,12 +37,13 @@ const Dialog = props => {
36
37
  const actionButtonMinHeight = dialogTokens?.actionButtonMinHeight ?? 44;
37
38
  const handleAction = useCallback(action => {
38
39
  if (action.loading) return;
39
- if (dialogTokens?.actionHaptic) triggerHaptic('selection');
40
+ const h = resolveHaptic(haptic, 'selection');
41
+ if (h) triggerHaptic(h);
40
42
  action.onPress();
41
43
  if (dismissOnAction) {
42
44
  onClose();
43
45
  }
44
- }, [dismissOnAction, onClose, dialogTokens?.actionHaptic]);
46
+ }, [dismissOnAction, onClose, haptic]);
45
47
  return /*#__PURE__*/_jsx(Modal, {
46
48
  visible: visible,
47
49
  onRequestClose: onClose,
@@ -144,7 +146,7 @@ const tintForVariant = (theme, variant) => {
144
146
  base: theme.colors.warning,
145
147
  muted: theme.colors.background.secondary
146
148
  };
147
- case 'danger':
149
+ case 'error':
148
150
  return {
149
151
  base: theme.colors.error,
150
152
  muted: theme.colors.background.secondary
@@ -175,7 +177,7 @@ const actionStyleFor = (theme, tone, variant) => {
175
177
  textColor: theme.colors.text.inverse
176
178
  };
177
179
  }
178
- case 'danger':
180
+ case 'error':
179
181
  return {
180
182
  backgroundColor: theme.colors.error,
181
183
  borderColor: 'transparent',
@@ -26,7 +26,7 @@ import { Gesture, GestureDetector } from 'react-native-gesture-handler';
26
26
  import Animated, { Extrapolation, interpolate, runOnJS, useAnimatedStyle, useSharedValue, withSpring } from 'react-native-reanimated';
27
27
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
28
28
  import { useTheme } from "../../theme/index.js";
29
- import { triggerHaptic } from "../../utils/index.js";
29
+ import { resolveHaptic, triggerHaptic } from "../../utils/index.js";
30
30
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
31
31
  const DEFAULT_CLOSE_VELOCITY_THRESHOLD = 1000;
32
32
  const DEFAULT_DRAG_ACTIVATION_OFFSET = 10;
@@ -40,6 +40,7 @@ const Drawer = /*#__PURE__*/forwardRef((props, ref) => {
40
40
  enableSwipe = true,
41
41
  enableBackdropPress = true,
42
42
  backdropOpacity = 0.5,
43
+ haptic,
43
44
  containerStyle,
44
45
  children,
45
46
  accessibilityLabel,
@@ -219,9 +220,10 @@ const Drawer = /*#__PURE__*/forwardRef((props, ref) => {
219
220
  const styles = useMemo(() => buildStyles(theme), [theme]);
220
221
  const handleBackdropPress = useCallback(() => {
221
222
  if (!enableBackdropPress) return;
222
- if (drawerTokens?.backdropPressHaptic) triggerHaptic('selection');
223
+ const h = resolveHaptic(haptic, 'selection');
224
+ if (h) triggerHaptic(h);
223
225
  close();
224
- }, [enableBackdropPress, close, drawerTokens?.backdropPressHaptic]);
226
+ }, [enableBackdropPress, close, haptic]);
225
227
 
226
228
  // Per-side container layout — must be a hook on every render path so we
227
229
  // can't gate it on the lazy-mount early-return below.
@@ -286,20 +286,24 @@ export const FieldBase = props => {
286
286
  const focusAnim = useRef(createAnimatedValue(focused ? 1 : 0)).current;
287
287
  const errorAnim = useRef(createAnimatedValue(error ? 1 : 0)).current;
288
288
  useEffect(() => {
289
- Animated.timing(focusAnim, {
289
+ const anim = Animated.timing(focusAnim, {
290
290
  toValue: focused ? 1 : 0,
291
291
  duration: theme.motion.duration.fast,
292
292
  easing: Easing.bezier(...theme.motion.easing.standard),
293
293
  useNativeDriver: false
294
- }).start();
294
+ });
295
+ anim.start();
296
+ return () => anim.stop();
295
297
  }, [focused, focusAnim, theme.motion.duration.fast, theme.motion.easing.standard]);
296
298
  useEffect(() => {
297
- Animated.timing(errorAnim, {
299
+ const anim = Animated.timing(errorAnim, {
298
300
  toValue: error ? 1 : 0,
299
301
  duration: theme.motion.duration.fast,
300
302
  easing: Easing.bezier(...theme.motion.easing.standard),
301
303
  useNativeDriver: false
302
- }).start();
304
+ });
305
+ anim.start();
306
+ return () => anim.stop();
303
307
  }, [error, errorAnim, theme.motion.duration.fast, theme.motion.easing.standard]);
304
308
 
305
309
  // Resting border + fill (pre-animation). Error wins over focus when both
@@ -5,7 +5,7 @@ import { Animated, Easing, Pressable, StyleSheet, Text, View } from 'react-nativ
5
5
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
6
6
  import { useTheme, createAnimatedValue, setNativeValue } from "../../theme/index.js";
7
7
  import { usePressAnimation } from "../../hooks/usePressAnimation.js";
8
- import { triggerHaptic } from "../../utils/hapticUtils.js";
8
+ import { triggerHaptic, resolveHaptic } from "../../utils/hapticUtils.js";
9
9
 
10
10
  // Local shape mirror — see types.ts FloatingActionButtonTokens for the canonical
11
11
  // definition. Declared here so the component can read tokens before types.ts is
@@ -64,6 +64,7 @@ const FloatingActionButton = /*#__PURE__*/forwardRef((props, ref) => {
64
64
  isScrolling = false,
65
65
  accessibilityLabel,
66
66
  accessibilityHint,
67
+ haptic,
67
68
  style,
68
69
  containerStyle,
69
70
  labelStyle,
@@ -83,19 +84,20 @@ const FloatingActionButton = /*#__PURE__*/forwardRef((props, ref) => {
83
84
  const fabTokens = theme.components.floatingActionButton;
84
85
  const edgeOffset = fabTokens?.edgeOffset ?? 24;
85
86
  const defaultBottomOffset = fabTokens?.bottomOffset ?? 24;
86
- const pressHaptic = fabTokens?.pressHaptic ?? false;
87
87
  const hideAnim = useRef(createAnimatedValue(0)).current;
88
88
  useEffect(() => {
89
89
  if (!hideOnScroll) {
90
90
  setNativeValue(hideAnim, 0);
91
91
  return;
92
92
  }
93
- Animated.timing(hideAnim, {
93
+ const anim = Animated.timing(hideAnim, {
94
94
  toValue: isScrolling ? 1 : 0,
95
95
  duration: theme.motion.duration.normal,
96
96
  easing: Easing.bezier(...theme.motion.easing.standard),
97
97
  useNativeDriver: true
98
- }).start();
98
+ });
99
+ anim.start();
100
+ return () => anim.stop();
99
101
  }, [hideOnScroll, isScrolling, hideAnim, theme.motion.duration.normal, theme.motion.easing.standard]);
100
102
  const hideTranslateY = hideAnim.interpolate({
101
103
  inputRange: [0, 1],
@@ -107,7 +109,8 @@ const FloatingActionButton = /*#__PURE__*/forwardRef((props, ref) => {
107
109
  });
108
110
  const handlePress = _event => {
109
111
  if (disabled) return;
110
- if (pressHaptic) triggerHaptic('impactLight');
112
+ const h = resolveHaptic(haptic, 'impactLight');
113
+ if (h) triggerHaptic(h);
111
114
  onPress();
112
115
  };
113
116
  const renderedIcon = icon;
@@ -176,7 +179,7 @@ const FloatingActionButton = /*#__PURE__*/forwardRef((props, ref) => {
176
179
  borderRadius: sizeStyles.diameter / 2
177
180
  }, theme.shadows.lg, {
178
181
  backgroundColor,
179
- opacity: disabled ? 0.7 : 1
182
+ opacity: disabled ? 0.55 : 1
180
183
  }],
181
184
  children: [renderedIcon, isExtended ? /*#__PURE__*/_jsx(Text, {
182
185
  style: [styles.label, {
@@ -222,6 +225,7 @@ const FloatingActionButtonGroup = props => {
222
225
  bottomOffset,
223
226
  size = 'md',
224
227
  accessibilityLabel = 'Quick actions',
228
+ haptic,
225
229
  containerStyle,
226
230
  secondaryActionStyle,
227
231
  labelPillStyle,
@@ -237,7 +241,6 @@ const FloatingActionButtonGroup = props => {
237
241
  const defaultBottomOffset = fabTokens?.bottomOffset ?? 24;
238
242
  const secondaryGap = fabTokens?.secondaryGap ?? 16;
239
243
  const staggerMs = fabTokens?.staggerMs ?? 50;
240
- const pressHaptic = fabTokens?.pressHaptic ?? false;
241
244
  const isControlled = typeof controlledOpen === 'boolean';
242
245
  const [internalOpen, setInternalOpen] = useState(defaultOpen);
243
246
  const isOpen = isControlled ? controlledOpen : internalOpen;
@@ -271,12 +274,13 @@ const FloatingActionButtonGroup = props => {
271
274
  // eslint-disable-next-line react-hooks/exhaustive-deps
272
275
  }, [actions.length]);
273
276
  useEffect(() => {
274
- Animated.timing(progress, {
277
+ const progressAnim = Animated.timing(progress, {
275
278
  toValue: isOpen ? 1 : 0,
276
279
  duration: theme.motion.duration.normal,
277
280
  easing: Easing.bezier(...theme.motion.easing.standard),
278
281
  useNativeDriver: true
279
- }).start();
282
+ });
283
+ progressAnim.start();
280
284
  const animations = itemAnims.current.map(value => Animated.timing(value, {
281
285
  toValue: isOpen ? 1 : 0,
282
286
  duration: theme.motion.duration.normal,
@@ -285,23 +289,29 @@ const FloatingActionButtonGroup = props => {
285
289
  }));
286
290
  // Reverse stagger order on close so items closest to primary collapse last
287
291
  const ordered = isOpen ? animations : [...animations].reverse();
288
- Animated.stagger(staggerMs, ordered).start();
292
+ const staggerAnim = Animated.stagger(staggerMs, ordered);
293
+ staggerAnim.start();
294
+ return () => {
295
+ progressAnim.stop();
296
+ staggerAnim.stop();
297
+ };
289
298
  }, [isOpen, progress, theme.motion.duration.normal, theme.motion.easing.standard, actions.length, itemAnimsVersion, staggerMs]);
290
299
  const setOpen = useCallback(next => {
291
- if (pressHaptic) triggerHaptic('impactLight');
300
+ const h = resolveHaptic(haptic, 'impactLight');
301
+ if (h) triggerHaptic(h);
292
302
  if (!isControlled) setInternalOpen(next);
293
303
  onOpenChange?.(next);
294
- }, [isControlled, onOpenChange, pressHaptic]);
304
+ }, [isControlled, onOpenChange, haptic]);
295
305
  const handlePrimaryPress = useCallback(() => {
296
306
  setOpen(!isOpen);
297
307
  }, [isOpen, setOpen]);
298
308
  const handleActionPress = useCallback(action => {
299
- if (pressHaptic) triggerHaptic('selection');
309
+ if (haptic !== false) triggerHaptic('selection');
300
310
  action.onPress();
301
311
  // Close after action runs
302
312
  if (!isControlled) setInternalOpen(false);
303
313
  onOpenChange?.(false);
304
- }, [isControlled, onOpenChange, pressHaptic]);
314
+ }, [isControlled, onOpenChange, haptic]);
305
315
  const handleBackdropPress = useCallback(() => {
306
316
  if (isOpen) setOpen(false);
307
317
  }, [isOpen, setOpen]);
@@ -3,13 +3,15 @@
3
3
  import React, { forwardRef, useEffect, useMemo, useRef } from 'react';
4
4
  import { Animated, StyleSheet, Text, View } from 'react-native';
5
5
  import { fontFor, useTheme, createAnimatedValue } from "../../theme/index.js";
6
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
6
+ import { useOptionalFormContext } from "../../form/FormContext.js";
7
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
7
8
  const FormField = /*#__PURE__*/forwardRef((props, ref) => {
8
9
  const {
9
10
  label,
10
11
  helperText,
11
12
  error,
12
13
  required = false,
14
+ name,
13
15
  children,
14
16
  layout = 'stacked',
15
17
  labelStyle,
@@ -22,19 +24,32 @@ const FormField = /*#__PURE__*/forwardRef((props, ref) => {
22
24
  } = props;
23
25
  const theme = useTheme();
24
26
  const styles = useMemo(() => buildStyles(theme), [theme]);
25
- const errorOpacity = useRef(createAnimatedValue(error ? 1 : 0)).current;
27
+ const formCtx = useOptionalFormContext();
28
+ const isConnected = name != null && formCtx != null;
29
+ const field = isConnected ? formCtx.getFieldProps(name) : null;
30
+ const isRenderProp = typeof children === 'function';
31
+
32
+ // Error the FormField renders itself. When connected to an element child the
33
+ // child (Input/Select etc.) shows the injected error, so FormField stays
34
+ // quiet to avoid a duplicate message; the render-prop form keeps it here.
35
+ const ownError = isConnected ? isRenderProp ? field?.error : undefined : error;
36
+ // Error used purely for assistive tech — always reflects the real error.
37
+ const a11yError = isConnected ? field?.error : error;
38
+ const errorOpacity = useRef(createAnimatedValue(ownError ? 1 : 0)).current;
26
39
  useEffect(() => {
27
- Animated.timing(errorOpacity, {
28
- toValue: error ? 1 : 0,
29
- duration: 150,
40
+ const anim = Animated.timing(errorOpacity, {
41
+ toValue: ownError ? 1 : 0,
42
+ duration: theme.motion.duration.fast,
30
43
  useNativeDriver: true
31
- }).start();
32
- }, [error, errorOpacity]);
44
+ });
45
+ anim.start();
46
+ return () => anim.stop();
47
+ }, [ownError, errorOpacity, theme.motion.duration.fast]);
33
48
  const computedAccessibilityLabel = useMemo(() => {
34
49
  if (accessibilityLabel) return accessibilityLabel;
35
50
  if (!label) return undefined;
36
- return error ? `${label}, error: ${error}` : label;
37
- }, [accessibilityLabel, label, error]);
51
+ return a11yError ? `${label}, error: ${a11yError}` : label;
52
+ }, [accessibilityLabel, label, a11yError]);
38
53
  const labelNode = label ? /*#__PURE__*/_jsxs(Text, {
39
54
  style: [styles.label, layout === 'inline' ? styles.labelInline : null, labelStyle],
40
55
  children: [label, required ? /*#__PURE__*/_jsx(Text, {
@@ -43,39 +58,60 @@ const FormField = /*#__PURE__*/forwardRef((props, ref) => {
43
58
  }) : null]
44
59
  }) : null;
45
60
  const inputContainerStyle = layout === 'inline' ? styles.inputInline : styles.inputStacked;
46
- const showError = Boolean(error);
61
+ const showError = Boolean(ownError);
47
62
  const showHelper = !showError && Boolean(helperText);
63
+ const renderedChildren = (() => {
64
+ if (isRenderProp) {
65
+ return field ? children(field) : null;
66
+ }
67
+ if (isConnected && field && /*#__PURE__*/React.isValidElement(children)) {
68
+ const child = children;
69
+ const childOnChangeText = child.props.onChangeText;
70
+ const childOnBlur = child.props.onBlur;
71
+ const childOnFocus = child.props.onFocus;
72
+ return /*#__PURE__*/React.cloneElement(child, {
73
+ value: field.value,
74
+ onChangeText: text => {
75
+ field.onChangeText(text);
76
+ childOnChangeText?.(text);
77
+ },
78
+ onBlur: e => {
79
+ field.onBlur();
80
+ childOnBlur?.(e);
81
+ },
82
+ onFocus: e => {
83
+ field.onFocus();
84
+ childOnFocus?.(e);
85
+ },
86
+ error: field.error,
87
+ ref: node => formCtx.registerField(name, node ?? null)
88
+ });
89
+ }
90
+ return children;
91
+ })();
48
92
  return /*#__PURE__*/_jsxs(View, {
49
93
  ref: ref,
50
94
  style: [layout === 'inline' ? styles.rootInline : styles.rootStacked, containerStyle],
51
95
  accessibilityLabel: computedAccessibilityLabel
52
- // Surface the invalid state to assistive tech via the hint. RN's
53
- // AccessibilityState type does not expose an `invalid` field, so the
54
- // error message itself is folded into the label and hint.
96
+ // RN's AccessibilityState type has no `invalid` field, so the error is
97
+ // folded into the label and surfaced again via the hint.
55
98
  ,
56
- accessibilityHint: error ? error : undefined,
99
+ accessibilityHint: a11yError ? a11yError : undefined,
57
100
  testID: testID,
58
- children: [layout === 'inline' ? /*#__PURE__*/_jsxs(_Fragment, {
59
- children: [labelNode, /*#__PURE__*/_jsx(View, {
60
- style: [inputContainerStyle, inputContainerStyleProp],
61
- children: children
62
- })]
63
- }) : /*#__PURE__*/_jsxs(_Fragment, {
64
- children: [labelNode, /*#__PURE__*/_jsx(View, {
65
- style: [inputContainerStyle, inputContainerStyleProp],
66
- children: children
67
- })]
101
+ children: [labelNode, /*#__PURE__*/_jsx(View, {
102
+ style: [inputContainerStyle, inputContainerStyleProp],
103
+ children: renderedChildren
68
104
  }), showHelper ? /*#__PURE__*/_jsx(Text, {
69
105
  style: [styles.helper, helperStyle],
70
106
  numberOfLines: 2,
71
107
  children: helperText
72
- }) : null, error ? /*#__PURE__*/_jsx(Animated.Text, {
108
+ }) : null, ownError ? /*#__PURE__*/_jsx(Animated.Text, {
73
109
  style: [styles.error, {
74
110
  opacity: errorOpacity
75
111
  }, errorStyle],
76
112
  numberOfLines: 2,
77
113
  accessibilityLiveRegion: "polite",
78
- children: error
114
+ children: ownError
79
115
  }) : null]
80
116
  });
81
117
  });
@@ -26,7 +26,7 @@ import Animated, { runOnJS, useAnimatedStyle, useSharedValue, withSpring, withTi
26
26
  import { Carousel } from "../Carousel/index.js";
27
27
  import { Skeleton } from "../Skeleton/index.js";
28
28
  import { useTheme } from "../../theme/index.js";
29
- import { triggerHaptic } from "../../utils/index.js";
29
+ import { resolveHaptic, triggerHaptic } from "../../utils/index.js";
30
30
 
31
31
  // Local shape mirror — see types.ts ImageGalleryTokens for the canonical definition.
32
32
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
@@ -46,6 +46,7 @@ const ImageGallery = ({
46
46
  enableLightbox = true,
47
47
  enablePinchZoom = true,
48
48
  onIndexChange,
49
+ haptic,
49
50
  loading = false,
50
51
  accessibilityLabel,
51
52
  containerStyle,
@@ -53,8 +54,6 @@ const ImageGallery = ({
53
54
  }) => {
54
55
  const theme = useTheme();
55
56
  const styles = useMemo(() => buildStyles(theme), [theme]);
56
- const galleryTokens = theme.components.imageGallery;
57
- const pressHaptic = galleryTokens?.pressHaptic ?? false;
58
57
  const [currentIndex, setCurrentIndex] = useState(clamp(initialIndex, 0, Math.max(0, images.length - 1)));
59
58
  const [lightboxOpen, setLightboxOpen] = useState(false);
60
59
  const handleIndexChange = useCallback(idx => {
@@ -63,13 +62,15 @@ const ImageGallery = ({
63
62
  }, [onIndexChange]);
64
63
  const openLightbox = useCallback(() => {
65
64
  if (!enableLightbox) return;
66
- if (pressHaptic) triggerHaptic('selection');
65
+ const h = resolveHaptic(haptic, 'selection');
66
+ if (h) triggerHaptic(h);
67
67
  setLightboxOpen(true);
68
- }, [enableLightbox, pressHaptic]);
68
+ }, [enableLightbox, haptic]);
69
69
  const closeLightbox = useCallback(() => {
70
- if (pressHaptic) triggerHaptic('selection');
70
+ const h = resolveHaptic(haptic, 'selection');
71
+ if (h) triggerHaptic(h);
71
72
  setLightboxOpen(false);
72
- }, [pressHaptic]);
73
+ }, [haptic]);
73
74
  const renderImage = useCallback((image, idx) => {
74
75
  const a11y = image.alt ?? `Image ${idx + 1} of ${images.length}`;
75
76
  return /*#__PURE__*/_jsx(Pressable, {
@@ -123,7 +124,7 @@ const ImageGallery = ({
123
124
  showCounter: showCounter,
124
125
  onClose: closeLightbox,
125
126
  onIndexChange: handleIndexChange,
126
- pressHaptic: pressHaptic
127
+ haptic: haptic
127
128
  }) : null]
128
129
  });
129
130
  if (loading) {
@@ -212,7 +213,7 @@ const Lightbox = ({
212
213
  showCounter,
213
214
  onClose,
214
215
  onIndexChange,
215
- pressHaptic
216
+ haptic
216
217
  }) => {
217
218
  const theme = useTheme();
218
219
  const styles = useMemo(() => buildLightboxStyles(theme), [theme]);
@@ -224,11 +225,12 @@ const Lightbox = ({
224
225
  const [activeIndex, setActiveIndex] = useState(initialIndex);
225
226
  const handleSwipe = useCallback(idx => {
226
227
  if (idx !== activeIndex) {
227
- if (pressHaptic) triggerHaptic('selection');
228
+ const h = resolveHaptic(haptic, 'selection');
229
+ if (h) triggerHaptic(h);
228
230
  setActiveIndex(idx);
229
231
  onIndexChange(idx);
230
232
  }
231
- }, [activeIndex, onIndexChange, pressHaptic]);
233
+ }, [activeIndex, onIndexChange, haptic]);
232
234
  const renderItem = useCallback((image, idx) => /*#__PURE__*/_jsx(ZoomableImage, {
233
235
  image: image,
234
236
  index: idx,
@@ -238,8 +240,8 @@ const Lightbox = ({
238
240
  maxScale: maxScale,
239
241
  minScale: minScale,
240
242
  doubleTapScale: doubleTapScale,
241
- pressHaptic: pressHaptic
242
- }), [activeIndex, enablePinchZoom, images.length, maxScale, minScale, doubleTapScale, pressHaptic]);
243
+ haptic: haptic
244
+ }), [activeIndex, enablePinchZoom, images.length, maxScale, minScale, doubleTapScale, haptic]);
243
245
  const caption = images[activeIndex]?.caption;
244
246
  return /*#__PURE__*/_jsx(RNModal, {
245
247
  visible: visible,
@@ -310,7 +312,7 @@ const ZoomableImage = ({
310
312
  maxScale,
311
313
  minScale,
312
314
  doubleTapScale,
313
- pressHaptic
315
+ haptic
314
316
  }) => {
315
317
  const screen = Dimensions.get('window');
316
318
  const scale = useSharedValue(1);
@@ -346,8 +348,8 @@ const ZoomableImage = ({
346
348
  }
347
349
  }, [active, scale, translateX, translateY, savedScale, savedTranslateX, savedTranslateY]);
348
350
  const triggerImpact = useCallback(() => {
349
- if (pressHaptic) triggerHaptic('impactLight');
350
- }, [pressHaptic]);
351
+ if (haptic !== false) triggerHaptic('impactLight');
352
+ }, [haptic]);
351
353
  const pinch = useMemo(() => Gesture.Pinch().enabled(enabled).onStart(() => {
352
354
  'worklet';
353
355