@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.
- package/lib/commonjs/components/Accordion/Accordion.js +5 -5
- package/lib/commonjs/components/AnimatePresence/AnimatePresence.js +69 -0
- package/lib/commonjs/components/AnimatePresence/index.js +13 -0
- package/lib/commonjs/components/AppBar/AppBar.js +9 -6
- package/lib/commonjs/components/Autocomplete/Autocomplete.js +204 -0
- package/lib/commonjs/components/Autocomplete/index.js +13 -0
- package/lib/commonjs/components/Banner/Banner.js +12 -2
- package/lib/commonjs/components/BottomNavigation/BottomNavigation.js +1 -1
- package/lib/commonjs/components/Card/Card.js +3 -3
- package/lib/commonjs/components/Checkbox/Checkbox.js +3 -2
- package/lib/commonjs/components/Chip/Chip.js +4 -2
- package/lib/commonjs/components/Confetti/Confetti.js +170 -0
- package/lib/commonjs/components/Confetti/index.js +13 -0
- package/lib/commonjs/components/DatePicker/DatePicker.js +23 -18
- package/lib/commonjs/components/DateRangePicker/DateRangePicker.js +11 -9
- package/lib/commonjs/components/Dialog/Dialog.js +4 -2
- package/lib/commonjs/components/Drawer/Drawer.js +4 -2
- package/lib/commonjs/components/FieldBase/FieldBase.js +0 -2
- package/lib/commonjs/components/FloatingActionButton/FloatingActionButton.js +10 -8
- package/lib/commonjs/components/IconButton/IconButton.js +176 -0
- package/lib/commonjs/components/IconButton/index.js +13 -0
- package/lib/commonjs/components/ImageGallery/ImageGallery.js +17 -15
- package/lib/commonjs/components/ListItem/ListItem.js +4 -3
- package/lib/commonjs/components/Modal/Modal.js +4 -4
- package/lib/commonjs/components/NumberInput/NumberInput.js +7 -5
- package/lib/commonjs/components/OTPInput/OTPInput.js +7 -7
- package/lib/commonjs/components/ProgressBar/ProgressBar.js +32 -4
- package/lib/commonjs/components/Radio/Radio.js +2 -3
- package/lib/commonjs/components/Rating/Rating.js +4 -3
- package/lib/commonjs/components/SearchBar/SearchBar.js +7 -4
- package/lib/commonjs/components/SegmentedControl/SegmentedControl.js +4 -3
- package/lib/commonjs/components/Select/Select.js +7 -4
- package/lib/commonjs/components/SlideToConfirm/SlideToConfirm.js +224 -0
- package/lib/commonjs/components/SlideToConfirm/index.js +13 -0
- package/lib/commonjs/components/Slider/Slider.js +228 -228
- package/lib/commonjs/components/Stepper/Stepper.js +6 -5
- package/lib/commonjs/components/Swipeable/Swipeable.js +8 -9
- package/lib/commonjs/components/Tabs/Tabs.js +4 -3
- package/lib/commonjs/components/TimePicker/TimePicker.js +14 -9
- package/lib/commonjs/components/index.js +149 -114
- package/lib/commonjs/hooks/usePressAnimation.js +0 -1
- package/lib/commonjs/utils/hapticUtils.js +11 -1
- package/lib/commonjs/utils/index.js +6 -0
- package/lib/module/components/Accordion/Accordion.js +6 -6
- package/lib/module/components/AnimatePresence/AnimatePresence.js +63 -0
- package/lib/module/components/AnimatePresence/index.js +4 -0
- package/lib/module/components/AppBar/AppBar.js +10 -7
- package/lib/module/components/Autocomplete/Autocomplete.js +199 -0
- package/lib/module/components/Autocomplete/index.js +4 -0
- package/lib/module/components/Banner/Banner.js +12 -2
- package/lib/module/components/BottomNavigation/BottomNavigation.js +1 -1
- package/lib/module/components/Card/Card.js +4 -4
- package/lib/module/components/Checkbox/Checkbox.js +4 -3
- package/lib/module/components/Chip/Chip.js +5 -3
- package/lib/module/components/Confetti/Confetti.js +166 -0
- package/lib/module/components/Confetti/index.js +4 -0
- package/lib/module/components/DatePicker/DatePicker.js +24 -19
- package/lib/module/components/DateRangePicker/DateRangePicker.js +12 -10
- package/lib/module/components/Dialog/Dialog.js +5 -3
- package/lib/module/components/Drawer/Drawer.js +5 -3
- package/lib/module/components/FieldBase/FieldBase.js +0 -2
- package/lib/module/components/FloatingActionButton/FloatingActionButton.js +11 -9
- package/lib/module/components/IconButton/IconButton.js +172 -0
- package/lib/module/components/IconButton/index.js +4 -0
- package/lib/module/components/ImageGallery/ImageGallery.js +18 -16
- package/lib/module/components/ListItem/ListItem.js +5 -4
- package/lib/module/components/Modal/Modal.js +5 -5
- package/lib/module/components/NumberInput/NumberInput.js +8 -6
- package/lib/module/components/OTPInput/OTPInput.js +8 -8
- package/lib/module/components/ProgressBar/ProgressBar.js +33 -5
- package/lib/module/components/Radio/Radio.js +3 -4
- package/lib/module/components/Rating/Rating.js +5 -4
- package/lib/module/components/SearchBar/SearchBar.js +8 -5
- package/lib/module/components/SegmentedControl/SegmentedControl.js +5 -4
- package/lib/module/components/Select/Select.js +8 -5
- package/lib/module/components/SlideToConfirm/SlideToConfirm.js +220 -0
- package/lib/module/components/SlideToConfirm/index.js +4 -0
- package/lib/module/components/Slider/Slider.js +231 -231
- package/lib/module/components/Stepper/Stepper.js +7 -6
- package/lib/module/components/Swipeable/Swipeable.js +9 -10
- package/lib/module/components/Tabs/Tabs.js +5 -4
- package/lib/module/components/TimePicker/TimePicker.js +15 -10
- package/lib/module/components/index.js +5 -0
- package/lib/module/hooks/usePressAnimation.js +0 -1
- package/lib/module/utils/hapticUtils.js +9 -0
- package/lib/module/utils/index.js +1 -1
- package/lib/typescript/commonjs/components/Accordion/Accordion.d.ts +3 -0
- package/lib/typescript/commonjs/components/AnimatePresence/AnimatePresence.d.ts +30 -0
- package/lib/typescript/commonjs/components/AnimatePresence/index.d.ts +3 -0
- package/lib/typescript/commonjs/components/AppBar/AppBar.d.ts +6 -0
- package/lib/typescript/commonjs/components/Autocomplete/Autocomplete.d.ts +53 -0
- package/lib/typescript/commonjs/components/Autocomplete/index.d.ts +3 -0
- package/lib/typescript/commonjs/components/Banner/Banner.d.ts +3 -0
- package/lib/typescript/commonjs/components/Card/Card.d.ts +3 -0
- package/lib/typescript/commonjs/components/Checkbox/Checkbox.d.ts +1 -0
- package/lib/typescript/commonjs/components/Chip/Chip.d.ts +3 -0
- package/lib/typescript/commonjs/components/Confetti/Confetti.d.ts +41 -0
- package/lib/typescript/commonjs/components/Confetti/index.d.ts +3 -0
- package/lib/typescript/commonjs/components/DatePicker/DatePicker.d.ts +3 -0
- package/lib/typescript/commonjs/components/DateRangePicker/DateRangePicker.d.ts +6 -0
- package/lib/typescript/commonjs/components/Dialog/Dialog.d.ts +3 -0
- package/lib/typescript/commonjs/components/Drawer/Drawer.d.ts +3 -0
- package/lib/typescript/commonjs/components/FloatingActionButton/FloatingActionButton.d.ts +5 -0
- package/lib/typescript/commonjs/components/IconButton/IconButton.d.ts +34 -0
- package/lib/typescript/commonjs/components/IconButton/index.d.ts +3 -0
- package/lib/typescript/commonjs/components/ImageGallery/ImageGallery.d.ts +6 -0
- package/lib/typescript/commonjs/components/ListItem/ListItem.d.ts +3 -0
- package/lib/typescript/commonjs/components/Modal/Modal.d.ts +6 -0
- package/lib/typescript/commonjs/components/NumberInput/NumberInput.d.ts +3 -0
- package/lib/typescript/commonjs/components/OTPInput/OTPInput.d.ts +6 -0
- package/lib/typescript/commonjs/components/ProgressBar/ProgressBar.d.ts +12 -0
- package/lib/typescript/commonjs/components/ProgressBar/index.d.ts +1 -1
- package/lib/typescript/commonjs/components/Rating/Rating.d.ts +6 -0
- package/lib/typescript/commonjs/components/SearchBar/SearchBar.d.ts +3 -0
- package/lib/typescript/commonjs/components/SegmentedControl/SegmentedControl.d.ts +3 -0
- package/lib/typescript/commonjs/components/Select/Select.d.ts +6 -0
- package/lib/typescript/commonjs/components/SlideToConfirm/SlideToConfirm.d.ts +34 -0
- package/lib/typescript/commonjs/components/SlideToConfirm/index.d.ts +3 -0
- package/lib/typescript/commonjs/components/Slider/Slider.d.ts +3 -0
- package/lib/typescript/commonjs/components/Stepper/Stepper.d.ts +6 -0
- package/lib/typescript/commonjs/components/Swipeable/Swipeable.d.ts +3 -0
- package/lib/typescript/commonjs/components/Tabs/Tabs.d.ts +3 -0
- package/lib/typescript/commonjs/components/TimePicker/TimePicker.d.ts +3 -0
- package/lib/typescript/commonjs/components/index.d.ts +11 -1
- package/lib/typescript/commonjs/hooks/usePressAnimation.d.ts +1 -2
- package/lib/typescript/commonjs/theme/types.d.ts +2 -67
- package/lib/typescript/commonjs/utils/hapticUtils.d.ts +8 -0
- package/lib/typescript/commonjs/utils/index.d.ts +1 -1
- package/lib/typescript/module/components/Accordion/Accordion.d.ts +3 -0
- package/lib/typescript/module/components/AnimatePresence/AnimatePresence.d.ts +30 -0
- package/lib/typescript/module/components/AnimatePresence/index.d.ts +3 -0
- package/lib/typescript/module/components/AppBar/AppBar.d.ts +6 -0
- package/lib/typescript/module/components/Autocomplete/Autocomplete.d.ts +53 -0
- package/lib/typescript/module/components/Autocomplete/index.d.ts +3 -0
- package/lib/typescript/module/components/Banner/Banner.d.ts +3 -0
- package/lib/typescript/module/components/Card/Card.d.ts +3 -0
- package/lib/typescript/module/components/Checkbox/Checkbox.d.ts +1 -0
- package/lib/typescript/module/components/Chip/Chip.d.ts +3 -0
- package/lib/typescript/module/components/Confetti/Confetti.d.ts +41 -0
- package/lib/typescript/module/components/Confetti/index.d.ts +3 -0
- package/lib/typescript/module/components/DatePicker/DatePicker.d.ts +3 -0
- package/lib/typescript/module/components/DateRangePicker/DateRangePicker.d.ts +6 -0
- package/lib/typescript/module/components/Dialog/Dialog.d.ts +3 -0
- package/lib/typescript/module/components/Drawer/Drawer.d.ts +3 -0
- package/lib/typescript/module/components/FloatingActionButton/FloatingActionButton.d.ts +5 -0
- package/lib/typescript/module/components/IconButton/IconButton.d.ts +34 -0
- package/lib/typescript/module/components/IconButton/index.d.ts +3 -0
- package/lib/typescript/module/components/ImageGallery/ImageGallery.d.ts +6 -0
- package/lib/typescript/module/components/ListItem/ListItem.d.ts +3 -0
- package/lib/typescript/module/components/Modal/Modal.d.ts +6 -0
- package/lib/typescript/module/components/NumberInput/NumberInput.d.ts +3 -0
- package/lib/typescript/module/components/OTPInput/OTPInput.d.ts +6 -0
- package/lib/typescript/module/components/ProgressBar/ProgressBar.d.ts +12 -0
- package/lib/typescript/module/components/ProgressBar/index.d.ts +1 -1
- package/lib/typescript/module/components/Rating/Rating.d.ts +6 -0
- package/lib/typescript/module/components/SearchBar/SearchBar.d.ts +3 -0
- package/lib/typescript/module/components/SegmentedControl/SegmentedControl.d.ts +3 -0
- package/lib/typescript/module/components/Select/Select.d.ts +6 -0
- package/lib/typescript/module/components/SlideToConfirm/SlideToConfirm.d.ts +34 -0
- package/lib/typescript/module/components/SlideToConfirm/index.d.ts +3 -0
- package/lib/typescript/module/components/Slider/Slider.d.ts +3 -0
- package/lib/typescript/module/components/Stepper/Stepper.d.ts +6 -0
- package/lib/typescript/module/components/Swipeable/Swipeable.d.ts +3 -0
- package/lib/typescript/module/components/Tabs/Tabs.d.ts +3 -0
- package/lib/typescript/module/components/TimePicker/TimePicker.d.ts +3 -0
- package/lib/typescript/module/components/index.d.ts +11 -1
- package/lib/typescript/module/hooks/usePressAnimation.d.ts +1 -2
- package/lib/typescript/module/theme/types.d.ts +2 -67
- package/lib/typescript/module/utils/hapticUtils.d.ts +8 -0
- package/lib/typescript/module/utils/index.d.ts +1 -1
- 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 (
|
|
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 (
|
|
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,
|
|
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 (
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
335
|
+
}, [animateViewTransition, haptic]);
|
|
333
336
|
const pickDecade = useCallback(decadeStart => {
|
|
334
|
-
|
|
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,
|
|
343
|
+
}, [animateViewTransition, haptic]);
|
|
340
344
|
const pressDay = useCallback(cell => {
|
|
341
345
|
if (isDisabled(cell.date)) return;
|
|
342
|
-
|
|
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,
|
|
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 (
|
|
389
|
+
if (haptic !== false) triggerHaptic('selection');
|
|
385
390
|
handleClose();
|
|
386
|
-
}, [handleClose,
|
|
391
|
+
}, [handleClose, haptic]);
|
|
387
392
|
const handleConfirm = useCallback(() => {
|
|
388
393
|
if (!pendingDate) return;
|
|
389
|
-
if (
|
|
394
|
+
if (haptic !== false) triggerHaptic('notificationSuccess');
|
|
390
395
|
onChange?.(pendingDate);
|
|
391
396
|
handleClose();
|
|
392
|
-
}, [handleClose, onChange, pendingDate,
|
|
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 (
|
|
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
|
-
|
|
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 (
|
|
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,
|
|
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 (
|
|
279
|
+
if (haptic !== false) triggerHaptic('selection');
|
|
278
280
|
handleClose();
|
|
279
|
-
}, [handleClose,
|
|
281
|
+
}, [handleClose, haptic]);
|
|
280
282
|
const handleConfirm = useCallback(() => {
|
|
281
283
|
if (!pendingStart || !pendingEnd) return;
|
|
282
|
-
if (
|
|
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,
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
223
|
+
const h = resolveHaptic(haptic, 'selection');
|
|
224
|
+
if (h) triggerHaptic(h);
|
|
223
225
|
close();
|
|
224
|
-
}, [enableBackdropPress, close,
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
300
|
+
const h = resolveHaptic(haptic, 'impactLight');
|
|
301
|
+
if (h) triggerHaptic(h);
|
|
300
302
|
if (!isControlled) setInternalOpen(next);
|
|
301
303
|
onOpenChange?.(next);
|
|
302
|
-
}, [isControlled, onOpenChange,
|
|
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 (
|
|
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,
|
|
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
|
|
@@ -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
|
-
|
|
65
|
+
const h = resolveHaptic(haptic, 'selection');
|
|
66
|
+
if (h) triggerHaptic(h);
|
|
67
67
|
setLightboxOpen(true);
|
|
68
|
-
}, [enableLightbox,
|
|
68
|
+
}, [enableLightbox, haptic]);
|
|
69
69
|
const closeLightbox = useCallback(() => {
|
|
70
|
-
|
|
70
|
+
const h = resolveHaptic(haptic, 'selection');
|
|
71
|
+
if (h) triggerHaptic(h);
|
|
71
72
|
setLightboxOpen(false);
|
|
72
|
-
}, [
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
228
|
+
const h = resolveHaptic(haptic, 'selection');
|
|
229
|
+
if (h) triggerHaptic(h);
|
|
228
230
|
setActiveIndex(idx);
|
|
229
231
|
onIndexChange(idx);
|
|
230
232
|
}
|
|
231
|
-
}, [activeIndex, onIndexChange,
|
|
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
|
-
|
|
242
|
-
}), [activeIndex, enablePinchZoom, images.length, maxScale, minScale, doubleTapScale,
|
|
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
|
-
|
|
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 (
|
|
350
|
-
}, [
|
|
351
|
+
if (haptic !== false) triggerHaptic('impactLight');
|
|
352
|
+
}, [haptic]);
|
|
351
353
|
const pinch = useMemo(() => Gesture.Pinch().enabled(enabled).onStart(() => {
|
|
352
354
|
'worklet';
|
|
353
355
|
|