@webority-technologies/mobile 0.0.23 → 0.0.25

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 (171) hide show
  1. package/lib/commonjs/components/Accordion/Accordion.js +5 -5
  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/Autocomplete/Autocomplete.js +204 -0
  6. package/lib/commonjs/components/Autocomplete/index.js +13 -0
  7. package/lib/commonjs/components/Banner/Banner.js +12 -2
  8. package/lib/commonjs/components/BottomNavigation/BottomNavigation.js +1 -1
  9. package/lib/commonjs/components/Card/Card.js +3 -3
  10. package/lib/commonjs/components/Checkbox/Checkbox.js +3 -2
  11. package/lib/commonjs/components/Chip/Chip.js +4 -2
  12. package/lib/commonjs/components/Confetti/Confetti.js +170 -0
  13. package/lib/commonjs/components/Confetti/index.js +13 -0
  14. package/lib/commonjs/components/DatePicker/DatePicker.js +23 -18
  15. package/lib/commonjs/components/DateRangePicker/DateRangePicker.js +11 -9
  16. package/lib/commonjs/components/Dialog/Dialog.js +4 -2
  17. package/lib/commonjs/components/Drawer/Drawer.js +4 -2
  18. package/lib/commonjs/components/FieldBase/FieldBase.js +0 -2
  19. package/lib/commonjs/components/FloatingActionButton/FloatingActionButton.js +10 -8
  20. package/lib/commonjs/components/IconButton/IconButton.js +176 -0
  21. package/lib/commonjs/components/IconButton/index.js +13 -0
  22. package/lib/commonjs/components/ImageGallery/ImageGallery.js +17 -15
  23. package/lib/commonjs/components/ListItem/ListItem.js +4 -3
  24. package/lib/commonjs/components/Modal/Modal.js +4 -4
  25. package/lib/commonjs/components/NumberInput/NumberInput.js +7 -5
  26. package/lib/commonjs/components/OTPInput/OTPInput.js +7 -7
  27. package/lib/commonjs/components/ProgressBar/ProgressBar.js +32 -4
  28. package/lib/commonjs/components/Radio/Radio.js +2 -3
  29. package/lib/commonjs/components/Rating/Rating.js +4 -3
  30. package/lib/commonjs/components/SearchBar/SearchBar.js +7 -4
  31. package/lib/commonjs/components/SegmentedControl/SegmentedControl.js +4 -3
  32. package/lib/commonjs/components/Select/Select.js +7 -4
  33. package/lib/commonjs/components/SlideToConfirm/SlideToConfirm.js +224 -0
  34. package/lib/commonjs/components/SlideToConfirm/index.js +13 -0
  35. package/lib/commonjs/components/Slider/Slider.js +228 -228
  36. package/lib/commonjs/components/Stepper/Stepper.js +6 -5
  37. package/lib/commonjs/components/Swipeable/Swipeable.js +8 -9
  38. package/lib/commonjs/components/Tabs/Tabs.js +4 -3
  39. package/lib/commonjs/components/TimePicker/TimePicker.js +14 -9
  40. package/lib/commonjs/components/index.js +149 -114
  41. package/lib/commonjs/hooks/usePressAnimation.js +0 -1
  42. package/lib/commonjs/utils/hapticUtils.js +11 -1
  43. package/lib/commonjs/utils/index.js +6 -0
  44. package/lib/module/components/Accordion/Accordion.js +6 -6
  45. package/lib/module/components/AnimatePresence/AnimatePresence.js +63 -0
  46. package/lib/module/components/AnimatePresence/index.js +4 -0
  47. package/lib/module/components/AppBar/AppBar.js +10 -7
  48. package/lib/module/components/Autocomplete/Autocomplete.js +199 -0
  49. package/lib/module/components/Autocomplete/index.js +4 -0
  50. package/lib/module/components/Banner/Banner.js +12 -2
  51. package/lib/module/components/BottomNavigation/BottomNavigation.js +1 -1
  52. package/lib/module/components/Card/Card.js +4 -4
  53. package/lib/module/components/Checkbox/Checkbox.js +4 -3
  54. package/lib/module/components/Chip/Chip.js +5 -3
  55. package/lib/module/components/Confetti/Confetti.js +166 -0
  56. package/lib/module/components/Confetti/index.js +4 -0
  57. package/lib/module/components/DatePicker/DatePicker.js +24 -19
  58. package/lib/module/components/DateRangePicker/DateRangePicker.js +12 -10
  59. package/lib/module/components/Dialog/Dialog.js +5 -3
  60. package/lib/module/components/Drawer/Drawer.js +5 -3
  61. package/lib/module/components/FieldBase/FieldBase.js +0 -2
  62. package/lib/module/components/FloatingActionButton/FloatingActionButton.js +11 -9
  63. package/lib/module/components/IconButton/IconButton.js +172 -0
  64. package/lib/module/components/IconButton/index.js +4 -0
  65. package/lib/module/components/ImageGallery/ImageGallery.js +18 -16
  66. package/lib/module/components/ListItem/ListItem.js +5 -4
  67. package/lib/module/components/Modal/Modal.js +5 -5
  68. package/lib/module/components/NumberInput/NumberInput.js +8 -6
  69. package/lib/module/components/OTPInput/OTPInput.js +8 -8
  70. package/lib/module/components/ProgressBar/ProgressBar.js +33 -5
  71. package/lib/module/components/Radio/Radio.js +3 -4
  72. package/lib/module/components/Rating/Rating.js +5 -4
  73. package/lib/module/components/SearchBar/SearchBar.js +8 -5
  74. package/lib/module/components/SegmentedControl/SegmentedControl.js +5 -4
  75. package/lib/module/components/Select/Select.js +8 -5
  76. package/lib/module/components/SlideToConfirm/SlideToConfirm.js +220 -0
  77. package/lib/module/components/SlideToConfirm/index.js +4 -0
  78. package/lib/module/components/Slider/Slider.js +231 -231
  79. package/lib/module/components/Stepper/Stepper.js +7 -6
  80. package/lib/module/components/Swipeable/Swipeable.js +9 -10
  81. package/lib/module/components/Tabs/Tabs.js +5 -4
  82. package/lib/module/components/TimePicker/TimePicker.js +15 -10
  83. package/lib/module/components/index.js +5 -0
  84. package/lib/module/hooks/usePressAnimation.js +0 -1
  85. package/lib/module/utils/hapticUtils.js +9 -0
  86. package/lib/module/utils/index.js +1 -1
  87. package/lib/typescript/commonjs/components/Accordion/Accordion.d.ts +3 -0
  88. package/lib/typescript/commonjs/components/AnimatePresence/AnimatePresence.d.ts +30 -0
  89. package/lib/typescript/commonjs/components/AnimatePresence/index.d.ts +3 -0
  90. package/lib/typescript/commonjs/components/AppBar/AppBar.d.ts +6 -0
  91. package/lib/typescript/commonjs/components/Autocomplete/Autocomplete.d.ts +53 -0
  92. package/lib/typescript/commonjs/components/Autocomplete/index.d.ts +3 -0
  93. package/lib/typescript/commonjs/components/Banner/Banner.d.ts +3 -0
  94. package/lib/typescript/commonjs/components/Card/Card.d.ts +3 -0
  95. package/lib/typescript/commonjs/components/Checkbox/Checkbox.d.ts +1 -0
  96. package/lib/typescript/commonjs/components/Chip/Chip.d.ts +3 -0
  97. package/lib/typescript/commonjs/components/Confetti/Confetti.d.ts +41 -0
  98. package/lib/typescript/commonjs/components/Confetti/index.d.ts +3 -0
  99. package/lib/typescript/commonjs/components/DatePicker/DatePicker.d.ts +3 -0
  100. package/lib/typescript/commonjs/components/DateRangePicker/DateRangePicker.d.ts +6 -0
  101. package/lib/typescript/commonjs/components/Dialog/Dialog.d.ts +3 -0
  102. package/lib/typescript/commonjs/components/Drawer/Drawer.d.ts +3 -0
  103. package/lib/typescript/commonjs/components/FloatingActionButton/FloatingActionButton.d.ts +5 -0
  104. package/lib/typescript/commonjs/components/IconButton/IconButton.d.ts +34 -0
  105. package/lib/typescript/commonjs/components/IconButton/index.d.ts +3 -0
  106. package/lib/typescript/commonjs/components/ImageGallery/ImageGallery.d.ts +6 -0
  107. package/lib/typescript/commonjs/components/ListItem/ListItem.d.ts +3 -0
  108. package/lib/typescript/commonjs/components/Modal/Modal.d.ts +6 -0
  109. package/lib/typescript/commonjs/components/NumberInput/NumberInput.d.ts +3 -0
  110. package/lib/typescript/commonjs/components/OTPInput/OTPInput.d.ts +6 -0
  111. package/lib/typescript/commonjs/components/ProgressBar/ProgressBar.d.ts +12 -0
  112. package/lib/typescript/commonjs/components/ProgressBar/index.d.ts +1 -1
  113. package/lib/typescript/commonjs/components/Rating/Rating.d.ts +6 -0
  114. package/lib/typescript/commonjs/components/SearchBar/SearchBar.d.ts +3 -0
  115. package/lib/typescript/commonjs/components/SegmentedControl/SegmentedControl.d.ts +3 -0
  116. package/lib/typescript/commonjs/components/Select/Select.d.ts +6 -0
  117. package/lib/typescript/commonjs/components/SlideToConfirm/SlideToConfirm.d.ts +34 -0
  118. package/lib/typescript/commonjs/components/SlideToConfirm/index.d.ts +3 -0
  119. package/lib/typescript/commonjs/components/Slider/Slider.d.ts +3 -0
  120. package/lib/typescript/commonjs/components/Stepper/Stepper.d.ts +6 -0
  121. package/lib/typescript/commonjs/components/Swipeable/Swipeable.d.ts +3 -0
  122. package/lib/typescript/commonjs/components/Tabs/Tabs.d.ts +3 -0
  123. package/lib/typescript/commonjs/components/TimePicker/TimePicker.d.ts +3 -0
  124. package/lib/typescript/commonjs/components/index.d.ts +11 -1
  125. package/lib/typescript/commonjs/hooks/usePressAnimation.d.ts +1 -2
  126. package/lib/typescript/commonjs/theme/types.d.ts +2 -67
  127. package/lib/typescript/commonjs/utils/hapticUtils.d.ts +8 -0
  128. package/lib/typescript/commonjs/utils/index.d.ts +1 -1
  129. package/lib/typescript/module/components/Accordion/Accordion.d.ts +3 -0
  130. package/lib/typescript/module/components/AnimatePresence/AnimatePresence.d.ts +30 -0
  131. package/lib/typescript/module/components/AnimatePresence/index.d.ts +3 -0
  132. package/lib/typescript/module/components/AppBar/AppBar.d.ts +6 -0
  133. package/lib/typescript/module/components/Autocomplete/Autocomplete.d.ts +53 -0
  134. package/lib/typescript/module/components/Autocomplete/index.d.ts +3 -0
  135. package/lib/typescript/module/components/Banner/Banner.d.ts +3 -0
  136. package/lib/typescript/module/components/Card/Card.d.ts +3 -0
  137. package/lib/typescript/module/components/Checkbox/Checkbox.d.ts +1 -0
  138. package/lib/typescript/module/components/Chip/Chip.d.ts +3 -0
  139. package/lib/typescript/module/components/Confetti/Confetti.d.ts +41 -0
  140. package/lib/typescript/module/components/Confetti/index.d.ts +3 -0
  141. package/lib/typescript/module/components/DatePicker/DatePicker.d.ts +3 -0
  142. package/lib/typescript/module/components/DateRangePicker/DateRangePicker.d.ts +6 -0
  143. package/lib/typescript/module/components/Dialog/Dialog.d.ts +3 -0
  144. package/lib/typescript/module/components/Drawer/Drawer.d.ts +3 -0
  145. package/lib/typescript/module/components/FloatingActionButton/FloatingActionButton.d.ts +5 -0
  146. package/lib/typescript/module/components/IconButton/IconButton.d.ts +34 -0
  147. package/lib/typescript/module/components/IconButton/index.d.ts +3 -0
  148. package/lib/typescript/module/components/ImageGallery/ImageGallery.d.ts +6 -0
  149. package/lib/typescript/module/components/ListItem/ListItem.d.ts +3 -0
  150. package/lib/typescript/module/components/Modal/Modal.d.ts +6 -0
  151. package/lib/typescript/module/components/NumberInput/NumberInput.d.ts +3 -0
  152. package/lib/typescript/module/components/OTPInput/OTPInput.d.ts +6 -0
  153. package/lib/typescript/module/components/ProgressBar/ProgressBar.d.ts +12 -0
  154. package/lib/typescript/module/components/ProgressBar/index.d.ts +1 -1
  155. package/lib/typescript/module/components/Rating/Rating.d.ts +6 -0
  156. package/lib/typescript/module/components/SearchBar/SearchBar.d.ts +3 -0
  157. package/lib/typescript/module/components/SegmentedControl/SegmentedControl.d.ts +3 -0
  158. package/lib/typescript/module/components/Select/Select.d.ts +6 -0
  159. package/lib/typescript/module/components/SlideToConfirm/SlideToConfirm.d.ts +34 -0
  160. package/lib/typescript/module/components/SlideToConfirm/index.d.ts +3 -0
  161. package/lib/typescript/module/components/Slider/Slider.d.ts +3 -0
  162. package/lib/typescript/module/components/Stepper/Stepper.d.ts +6 -0
  163. package/lib/typescript/module/components/Swipeable/Swipeable.d.ts +3 -0
  164. package/lib/typescript/module/components/Tabs/Tabs.d.ts +3 -0
  165. package/lib/typescript/module/components/TimePicker/TimePicker.d.ts +3 -0
  166. package/lib/typescript/module/components/index.d.ts +11 -1
  167. package/lib/typescript/module/hooks/usePressAnimation.d.ts +1 -2
  168. package/lib/typescript/module/theme/types.d.ts +2 -67
  169. package/lib/typescript/module/utils/hapticUtils.d.ts +8 -0
  170. package/lib/typescript/module/utils/index.d.ts +1 -1
  171. package/package.json +1 -1
@@ -4,7 +4,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
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 { resolveHaptic, triggerHaptic } from "../../utils/index.js";
8
8
  import { PickerTrigger } from "../PickerTrigger/index.js";
9
9
 
10
10
  /**
@@ -115,6 +115,7 @@ const DatePicker = props => {
115
115
  headerLabelStyle,
116
116
  navButtonStyle,
117
117
  footerButtonStyle,
118
+ haptic,
118
119
  testID,
119
120
  label,
120
121
  placeholder,
@@ -230,7 +231,7 @@ const DatePicker = props => {
230
231
  return false;
231
232
  }, [minDay, maxDay]);
232
233
  const animateMonthChange = useCallback(delta => {
233
- if (theme.components.datePicker?.haptic) triggerHaptic('impactLight');
234
+ if (haptic !== false) triggerHaptic('impactLight');
234
235
  const direction = delta > 0 ? 1 : -1;
235
236
  const distance = theme.components.datePicker?.monthSlideDistance ?? 32;
236
237
  const outDuration = theme.components.datePicker?.monthSlideOutDuration ?? theme.motion.duration.fast ?? 140;
@@ -261,31 +262,31 @@ const DatePicker = props => {
261
262
  const next = addMonths(anchor, delta);
262
263
  setAnchor(next);
263
264
  AccessibilityInfo.announceForAccessibility(formatMonthYear(next, locale));
264
- }, [anchor, locale, monthFade, monthSlide, theme.components.datePicker, theme.motion.duration.fast]);
265
+ }, [anchor, haptic, locale, monthFade, monthSlide, theme.components.datePicker, theme.motion.duration.fast]);
265
266
  const goPrev = useCallback(() => {
266
267
  if (viewMode === 'days') {
267
268
  animateMonthChange(-1);
268
269
  return;
269
270
  }
270
- if (theme.components.datePicker?.haptic) triggerHaptic('impactLight');
271
+ if (haptic !== false) triggerHaptic('impactLight');
271
272
  if (viewMode === 'years') {
272
273
  setAnchor(prev => new Date(prev.getFullYear() - GRID_SIZE, prev.getMonth(), 1));
273
274
  } else {
274
275
  setAnchor(prev => new Date(prev.getFullYear() - GRID_SIZE * DECADE_SPAN, prev.getMonth(), 1));
275
276
  }
276
- }, [animateMonthChange, viewMode, theme.components.datePicker]);
277
+ }, [animateMonthChange, viewMode, haptic]);
277
278
  const goNext = useCallback(() => {
278
279
  if (viewMode === 'days') {
279
280
  animateMonthChange(1);
280
281
  return;
281
282
  }
282
- if (theme.components.datePicker?.haptic) triggerHaptic('impactLight');
283
+ if (haptic !== false) triggerHaptic('impactLight');
283
284
  if (viewMode === 'years') {
284
285
  setAnchor(prev => new Date(prev.getFullYear() + GRID_SIZE, prev.getMonth(), 1));
285
286
  } else {
286
287
  setAnchor(prev => new Date(prev.getFullYear() + GRID_SIZE * DECADE_SPAN, prev.getMonth(), 1));
287
288
  }
288
- }, [animateMonthChange, viewMode, theme.components.datePicker]);
289
+ }, [animateMonthChange, viewMode, haptic]);
289
290
 
290
291
  // View-mode transition: fade + scale, native driver.
291
292
  const animateViewTransition = useCallback(() => {
@@ -305,7 +306,8 @@ const DatePicker = props => {
305
306
  })]).start();
306
307
  }, [viewFade, viewScale, theme.components.datePicker, theme.motion.duration.normal]);
307
308
  const cycleViewMode = useCallback(() => {
308
- if (theme.components.datePicker?.haptic) triggerHaptic('selection');
309
+ const h = resolveHaptic(haptic, 'selection');
310
+ if (h) triggerHaptic(h);
309
311
  const pressDur = theme.components.datePicker?.headerPressDuration ?? 80;
310
312
  const releaseDur = theme.components.datePicker?.headerReleaseDuration ?? 100;
311
313
  Animated.sequence([Animated.timing(headerScale, {
@@ -323,23 +325,26 @@ const DatePicker = props => {
323
325
  return 'years';
324
326
  });
325
327
  animateViewTransition();
326
- }, [animateViewTransition, headerScale, theme.components.datePicker]);
328
+ }, [animateViewTransition, headerScale, haptic, theme.components.datePicker]);
327
329
  const pickYear = useCallback(year => {
328
- if (theme.components.datePicker?.haptic) triggerHaptic('selection');
330
+ const h = resolveHaptic(haptic, 'selection');
331
+ if (h) triggerHaptic(h);
329
332
  setAnchor(prev => new Date(year, prev.getMonth(), 1));
330
333
  setViewMode('days');
331
334
  animateViewTransition();
332
- }, [animateViewTransition, theme.components.datePicker]);
335
+ }, [animateViewTransition, haptic]);
333
336
  const pickDecade = useCallback(decadeStart => {
334
- if (theme.components.datePicker?.haptic) triggerHaptic('selection');
337
+ const h = resolveHaptic(haptic, 'selection');
338
+ if (h) triggerHaptic(h);
335
339
  // Anchor mid-decade so the year grid centers nicely on this decade.
336
340
  setAnchor(prev => new Date(decadeStart + 4, prev.getMonth(), 1));
337
341
  setViewMode('years');
338
342
  animateViewTransition();
339
- }, [animateViewTransition, theme.components.datePicker]);
343
+ }, [animateViewTransition, haptic]);
340
344
  const pressDay = useCallback(cell => {
341
345
  if (isDisabled(cell.date)) return;
342
- if (theme.components.datePicker?.haptic) triggerHaptic('selection');
346
+ const h = resolveHaptic(haptic, 'selection');
347
+ if (h) triggerHaptic(h);
343
348
  setPendingDate(cell.date);
344
349
  if (!cell.inMonth) {
345
350
  setAnchor(new Date(cell.date.getFullYear(), cell.date.getMonth(), 1));
@@ -352,7 +357,7 @@ const DatePicker = props => {
352
357
  mass: theme.motion.spring.bouncy.mass,
353
358
  useNativeDriver: true
354
359
  }).start();
355
- }, [isDisabled, selectScale, theme.motion.spring.bouncy, theme.components.datePicker]);
360
+ }, [isDisabled, selectScale, theme.motion.spring.bouncy, haptic]);
356
361
  const finalizeClose = useCallback(() => {
357
362
  if (isControlled) {
358
363
  onClose?.();
@@ -381,15 +386,15 @@ const DatePicker = props => {
381
386
  });
382
387
  }, [backdrop, mode, finalizeClose, sheet, theme.motion.duration.fast]);
383
388
  const handleCancel = useCallback(() => {
384
- if (theme.components.datePicker?.haptic) triggerHaptic('selection');
389
+ if (haptic !== false) triggerHaptic('selection');
385
390
  handleClose();
386
- }, [handleClose, theme.components.datePicker]);
391
+ }, [handleClose, haptic]);
387
392
  const handleConfirm = useCallback(() => {
388
393
  if (!pendingDate) return;
389
- if (theme.components.datePicker?.haptic) triggerHaptic('notificationSuccess');
394
+ if (haptic !== false) triggerHaptic('notificationSuccess');
390
395
  onChange?.(pendingDate);
391
396
  handleClose();
392
- }, [handleClose, onChange, pendingDate, theme.components.datePicker]);
397
+ }, [handleClose, onChange, pendingDate, haptic]);
393
398
  const sheetTranslate = sheet.interpolate({
394
399
  inputRange: [0, 1],
395
400
  outputRange: [320, 0]
@@ -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,
@@ -184,7 +185,7 @@ const DateRangePicker = /*#__PURE__*/forwardRef((props, ref) => {
184
185
  const headerLabel = useMemo(() => formatMonthYear(anchor, locale), [anchor, locale]);
185
186
  const weekdays = useMemo(() => weekdayLabels(locale, weekStartsOn), [locale, weekStartsOn]);
186
187
  const animateMonthChange = useCallback(delta => {
187
- if (theme.components.dateRangePicker?.haptic) triggerHaptic('impactLight');
188
+ if (haptic !== false) triggerHaptic('impactLight');
188
189
  const direction = delta > 0 ? 1 : -1;
189
190
  const distance = theme.components.dateRangePicker?.monthSlideDistance ?? 32;
190
191
  const outDuration = theme.components.dateRangePicker?.monthSlideOutDuration ?? theme.motion.duration.fast ?? 140;
@@ -215,12 +216,13 @@ const DateRangePicker = /*#__PURE__*/forwardRef((props, ref) => {
215
216
  const next = addMonths(anchor, delta);
216
217
  setAnchor(next);
217
218
  AccessibilityInfo.announceForAccessibility(formatMonthYear(next, locale));
218
- }, [anchor, locale, monthFade, monthSlide, theme.components.dateRangePicker, theme.motion.duration.fast]);
219
+ }, [anchor, haptic, locale, monthFade, monthSlide, theme.components.dateRangePicker, theme.motion.duration.fast]);
219
220
  const goPrev = useCallback(() => animateMonthChange(-1), [animateMonthChange]);
220
221
  const goNext = useCallback(() => animateMonthChange(1), [animateMonthChange]);
221
222
  const pressDay = useCallback(cell => {
222
223
  if (isDisabled(cell.date)) return;
223
- if (theme.components.dateRangePicker?.haptic) triggerHaptic('selection');
224
+ const h = resolveHaptic(haptic, 'selection');
225
+ if (h) triggerHaptic(h);
224
226
  const target = cell.date;
225
227
 
226
228
  // First tap: pick start. Or, when there's already a complete range, restart.
@@ -239,7 +241,7 @@ const DateRangePicker = /*#__PURE__*/forwardRef((props, ref) => {
239
241
  } else {
240
242
  if (maxRange && daysBetween(pendingStart, target) + 1 > maxRange) {
241
243
  // Reject ranges longer than maxRange — restart from the new tap.
242
- if (theme.components.dateRangePicker?.haptic) triggerHaptic('notificationWarning');
244
+ if (haptic !== false) triggerHaptic('notificationWarning');
243
245
  setPendingStart(target);
244
246
  setPendingEnd(null);
245
247
  return;
@@ -250,7 +252,7 @@ const DateRangePicker = /*#__PURE__*/forwardRef((props, ref) => {
250
252
  if (!cell.inMonth) {
251
253
  setAnchor(new Date(cell.date.getFullYear(), cell.date.getMonth(), 1));
252
254
  }
253
- }, [isDisabled, pendingStart, pendingEnd, maxRange, theme.components.dateRangePicker]);
255
+ }, [isDisabled, pendingStart, pendingEnd, maxRange, haptic]);
254
256
  const handleCloseModal = useCallback(() => {
255
257
  if (isControlled) {
256
258
  onClose?.();
@@ -274,18 +276,18 @@ const DateRangePicker = /*#__PURE__*/forwardRef((props, ref) => {
274
276
  });
275
277
  }, [backdrop, handleCloseModal, sheet, theme.motion.duration.fast]);
276
278
  const handleCancel = useCallback(() => {
277
- if (theme.components.dateRangePicker?.haptic) triggerHaptic('selection');
279
+ if (haptic !== false) triggerHaptic('selection');
278
280
  handleClose();
279
- }, [handleClose, theme.components.dateRangePicker]);
281
+ }, [handleClose, haptic]);
280
282
  const handleConfirm = useCallback(() => {
281
283
  if (!pendingStart || !pendingEnd) return;
282
- if (theme.components.dateRangePicker?.haptic) triggerHaptic('notificationSuccess');
284
+ if (haptic !== false) triggerHaptic('notificationSuccess');
283
285
  onChange?.({
284
286
  start: pendingStart,
285
287
  end: pendingEnd
286
288
  });
287
289
  handleClose();
288
- }, [handleClose, onChange, pendingStart, pendingEnd, theme.components.dateRangePicker]);
290
+ }, [handleClose, onChange, pendingStart, pendingEnd, haptic]);
289
291
  const sheetTranslate = sheet.interpolate({
290
292
  inputRange: [0, 1],
291
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,
@@ -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.
@@ -28,8 +28,6 @@ import React, { useEffect, useMemo, useRef } from 'react';
28
28
  import { Animated, Easing, Pressable, StyleSheet, View } from 'react-native';
29
29
  import { useTheme, createAnimatedValue, fontFor } from "../../theme/index.js";
30
30
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
31
- const SIDES = ['top', 'right', 'bottom', 'left'];
32
-
33
31
  /** Map a single colour string to all four sides (shorthand expansion). */
34
32
  const expandColorSides = value => {
35
33
  if (typeof value === 'string') {
@@ -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,7 +84,6 @@ 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) {
@@ -109,7 +109,8 @@ const FloatingActionButton = /*#__PURE__*/forwardRef((props, ref) => {
109
109
  });
110
110
  const handlePress = _event => {
111
111
  if (disabled) return;
112
- if (pressHaptic) triggerHaptic('impactLight');
112
+ const h = resolveHaptic(haptic, 'impactLight');
113
+ if (h) triggerHaptic(h);
113
114
  onPress();
114
115
  };
115
116
  const renderedIcon = icon;
@@ -178,7 +179,7 @@ const FloatingActionButton = /*#__PURE__*/forwardRef((props, ref) => {
178
179
  borderRadius: sizeStyles.diameter / 2
179
180
  }, theme.shadows.lg, {
180
181
  backgroundColor,
181
- opacity: disabled ? 0.7 : 1
182
+ opacity: disabled ? 0.55 : 1
182
183
  }],
183
184
  children: [renderedIcon, isExtended ? /*#__PURE__*/_jsx(Text, {
184
185
  style: [styles.label, {
@@ -224,6 +225,7 @@ const FloatingActionButtonGroup = props => {
224
225
  bottomOffset,
225
226
  size = 'md',
226
227
  accessibilityLabel = 'Quick actions',
228
+ haptic,
227
229
  containerStyle,
228
230
  secondaryActionStyle,
229
231
  labelPillStyle,
@@ -239,7 +241,6 @@ const FloatingActionButtonGroup = props => {
239
241
  const defaultBottomOffset = fabTokens?.bottomOffset ?? 24;
240
242
  const secondaryGap = fabTokens?.secondaryGap ?? 16;
241
243
  const staggerMs = fabTokens?.staggerMs ?? 50;
242
- const pressHaptic = fabTokens?.pressHaptic ?? false;
243
244
  const isControlled = typeof controlledOpen === 'boolean';
244
245
  const [internalOpen, setInternalOpen] = useState(defaultOpen);
245
246
  const isOpen = isControlled ? controlledOpen : internalOpen;
@@ -296,20 +297,21 @@ const FloatingActionButtonGroup = props => {
296
297
  };
297
298
  }, [isOpen, progress, theme.motion.duration.normal, theme.motion.easing.standard, actions.length, itemAnimsVersion, staggerMs]);
298
299
  const setOpen = useCallback(next => {
299
- if (pressHaptic) triggerHaptic('impactLight');
300
+ const h = resolveHaptic(haptic, 'impactLight');
301
+ if (h) triggerHaptic(h);
300
302
  if (!isControlled) setInternalOpen(next);
301
303
  onOpenChange?.(next);
302
- }, [isControlled, onOpenChange, pressHaptic]);
304
+ }, [isControlled, onOpenChange, haptic]);
303
305
  const handlePrimaryPress = useCallback(() => {
304
306
  setOpen(!isOpen);
305
307
  }, [isOpen, setOpen]);
306
308
  const handleActionPress = useCallback(action => {
307
- if (pressHaptic) triggerHaptic('selection');
309
+ if (haptic !== false) triggerHaptic('selection');
308
310
  action.onPress();
309
311
  // Close after action runs
310
312
  if (!isControlled) setInternalOpen(false);
311
313
  onOpenChange?.(false);
312
- }, [isControlled, onOpenChange, pressHaptic]);
314
+ }, [isControlled, onOpenChange, haptic]);
313
315
  const handleBackdropPress = useCallback(() => {
314
316
  if (isOpen) setOpen(false);
315
317
  }, [isOpen, setOpen]);
@@ -0,0 +1,172 @@
1
+ "use strict";
2
+
3
+ import React, { forwardRef } from 'react';
4
+ import { Animated, Pressable, StyleSheet } from 'react-native';
5
+ import { useTheme } from "../../theme/index.js";
6
+ import { usePressAnimation } from "../../hooks/usePressAnimation.js";
7
+ import { resolveHaptic, triggerHaptic } from "../../utils/index.js";
8
+ import { Spinner } from "../Spinner/index.js";
9
+ import { jsx as _jsx } from "react/jsx-runtime";
10
+ const SIZE_MAP = {
11
+ sm: {
12
+ diameter: 32,
13
+ icon: 16
14
+ },
15
+ md: {
16
+ diameter: 40,
17
+ icon: 20
18
+ },
19
+ lg: {
20
+ diameter: 48,
21
+ icon: 24
22
+ }
23
+ };
24
+ const toneFor = (theme, tone) => {
25
+ switch (tone) {
26
+ case 'secondary':
27
+ return {
28
+ base: theme.colors.secondary,
29
+ on: theme.colors.onSecondary,
30
+ fg: theme.colors.secondary
31
+ };
32
+ case 'success':
33
+ return {
34
+ base: theme.colors.success,
35
+ on: theme.colors.onSuccess,
36
+ fg: theme.colors.success
37
+ };
38
+ case 'warning':
39
+ return {
40
+ base: theme.colors.warning,
41
+ on: theme.colors.onWarning,
42
+ fg: theme.colors.warning
43
+ };
44
+ case 'error':
45
+ return {
46
+ base: theme.colors.error,
47
+ on: theme.colors.onError,
48
+ fg: theme.colors.error
49
+ };
50
+ case 'neutral':
51
+ return {
52
+ base: theme.colors.background.tertiary,
53
+ on: theme.colors.text.primary,
54
+ fg: theme.colors.text.primary
55
+ };
56
+ case 'primary':
57
+ default:
58
+ return {
59
+ base: theme.colors.primary,
60
+ on: theme.colors.onPrimary,
61
+ fg: theme.colors.primary
62
+ };
63
+ }
64
+ };
65
+ const IconButton = /*#__PURE__*/forwardRef((props, ref) => {
66
+ const {
67
+ icon,
68
+ onPress,
69
+ accessibilityLabel,
70
+ tone = 'primary',
71
+ variant = 'solid',
72
+ size = 'md',
73
+ shape = 'circle',
74
+ active = false,
75
+ disabled = false,
76
+ loading = false,
77
+ haptic,
78
+ style,
79
+ testID
80
+ } = props;
81
+ const theme = useTheme();
82
+ const sizeCfg = SIZE_MAP[size];
83
+ const isDisabled = disabled || loading;
84
+ const {
85
+ scale,
86
+ pressIn,
87
+ pressOut
88
+ } = usePressAnimation({
89
+ scaleTo: 0.92,
90
+ enabled: !isDisabled
91
+ });
92
+ const {
93
+ base,
94
+ on,
95
+ fg
96
+ } = toneFor(theme, tone);
97
+ const effectiveVariant = active ? 'solid' : variant;
98
+ let backgroundColor = 'transparent';
99
+ let borderColor = 'transparent';
100
+ let borderWidth = 0;
101
+ let iconColor = isDisabled ? theme.colors.text.disabled : fg;
102
+ if (effectiveVariant === 'solid') {
103
+ backgroundColor = isDisabled ? theme.colors.surface.disabled : base;
104
+ iconColor = isDisabled ? theme.colors.text.disabled : on;
105
+ } else if (effectiveVariant === 'soft') {
106
+ backgroundColor = isDisabled ? theme.colors.surface.disabled : `${base}22`;
107
+ } else if (effectiveVariant === 'outline') {
108
+ borderColor = isDisabled ? theme.colors.border.primary : base;
109
+ borderWidth = theme.colors.border.width;
110
+ }
111
+ const radius = shape === 'circle' ? sizeCfg.diameter / 2 : theme.radius.md;
112
+ const handlePress = e => {
113
+ if (isDisabled) return;
114
+ const h = resolveHaptic(haptic, 'selection');
115
+ if (h) triggerHaptic(h);
116
+ onPress?.(e);
117
+ };
118
+ return /*#__PURE__*/_jsx(Pressable, {
119
+ ref: ref,
120
+ onPress: handlePress,
121
+ onPressIn: pressIn,
122
+ onPressOut: pressOut,
123
+ disabled: isDisabled,
124
+ accessibilityRole: "button",
125
+ accessibilityLabel: accessibilityLabel,
126
+ accessibilityState: {
127
+ disabled: isDisabled,
128
+ selected: active
129
+ },
130
+ hitSlop: 6,
131
+ testID: testID,
132
+ style: ({
133
+ pressed
134
+ }) => [styles.base, {
135
+ width: sizeCfg.diameter,
136
+ height: sizeCfg.diameter,
137
+ borderRadius: radius,
138
+ backgroundColor,
139
+ borderColor,
140
+ borderWidth,
141
+ opacity: pressed && effectiveVariant !== 'solid' ? 0.7 : 1
142
+ }, style],
143
+ children: /*#__PURE__*/_jsx(Animated.View, {
144
+ style: [styles.content, {
145
+ transform: [{
146
+ scale
147
+ }]
148
+ }],
149
+ children: loading ? /*#__PURE__*/_jsx(Spinner, {
150
+ size: "sm",
151
+ color: iconColor
152
+ }) : typeof icon === 'function' ? icon({
153
+ color: iconColor,
154
+ size: sizeCfg.icon
155
+ }) : icon
156
+ })
157
+ });
158
+ });
159
+ IconButton.displayName = 'IconButton';
160
+ const styles = StyleSheet.create({
161
+ base: {
162
+ alignItems: 'center',
163
+ justifyContent: 'center'
164
+ },
165
+ content: {
166
+ alignItems: 'center',
167
+ justifyContent: 'center'
168
+ }
169
+ });
170
+ export { IconButton };
171
+ export default IconButton;
172
+ //# sourceMappingURL=IconButton.js.map
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+
3
+ export { IconButton } from "./IconButton.js";
4
+ //# sourceMappingURL=index.js.map
@@ -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