@webority-technologies/mobile 0.0.23 → 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.
- 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/Banner/Banner.js +12 -2
- 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/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/FloatingActionButton/FloatingActionButton.js +10 -8
- 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 -3
- package/lib/commonjs/components/NumberInput/NumberInput.js +7 -5
- package/lib/commonjs/components/OTPInput/OTPInput.js +7 -7
- 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/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 +121 -114
- 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/Banner/Banner.js +12 -2
- 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/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/FloatingActionButton/FloatingActionButton.js +11 -9
- 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 -4
- package/lib/module/components/NumberInput/NumberInput.js +8 -6
- package/lib/module/components/OTPInput/OTPInput.js +8 -8
- 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/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 +1 -0
- 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/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/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/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/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/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 +2 -0
- 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/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/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/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/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/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 +2 -0
- 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
|
@@ -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
|
|
|
@@ -4,7 +4,7 @@ import React, { forwardRef, useMemo } from 'react';
|
|
|
4
4
|
import { Animated, Pressable, StyleSheet, Text, View } from 'react-native';
|
|
5
5
|
import { fontFor, useTheme } from "../../theme/index.js";
|
|
6
6
|
import { usePressAnimation } from "../../hooks/usePressAnimation.js";
|
|
7
|
-
import { triggerHaptic } from "../../utils/hapticUtils.js";
|
|
7
|
+
import { resolveHaptic, triggerHaptic } from "../../utils/hapticUtils.js";
|
|
8
8
|
import { Swipeable } from "../Swipeable/index.js";
|
|
9
9
|
import { Skeleton } from "../Skeleton/index.js";
|
|
10
10
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
@@ -64,6 +64,7 @@ const ListItem = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
64
64
|
left,
|
|
65
65
|
right,
|
|
66
66
|
onPress,
|
|
67
|
+
haptic,
|
|
67
68
|
selected = false,
|
|
68
69
|
disabled = false,
|
|
69
70
|
size = 'md',
|
|
@@ -83,7 +84,6 @@ const ListItem = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
83
84
|
testID
|
|
84
85
|
} = props;
|
|
85
86
|
const theme = useTheme();
|
|
86
|
-
const pressHaptic = theme.components.listItem?.pressHaptic ?? false;
|
|
87
87
|
const sz = useMemo(() => sizeFor(theme, size), [theme, size]);
|
|
88
88
|
const styles = useMemo(() => buildStyles(theme), [theme]);
|
|
89
89
|
const isInteractive = !!onPress && !disabled;
|
|
@@ -96,7 +96,8 @@ const ListItem = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
96
96
|
});
|
|
97
97
|
const handlePress = event => {
|
|
98
98
|
if (!isInteractive) return;
|
|
99
|
-
|
|
99
|
+
const h = resolveHaptic(haptic, 'selection');
|
|
100
|
+
if (h) triggerHaptic(h);
|
|
100
101
|
onPress?.(event);
|
|
101
102
|
};
|
|
102
103
|
const a11yLabel = accessibilityLabel ?? title;
|
|
@@ -291,7 +292,7 @@ const buildStyles = theme => StyleSheet.create({
|
|
|
291
292
|
backgroundColor: theme.colors.surface.pressed
|
|
292
293
|
},
|
|
293
294
|
disabled: {
|
|
294
|
-
opacity: 0.
|
|
295
|
+
opacity: 0.55
|
|
295
296
|
},
|
|
296
297
|
leftSlot: {
|
|
297
298
|
marginRight: theme.spacing.md,
|
|
@@ -4,7 +4,7 @@ import React, { forwardRef, useCallback, useEffect, useMemo, useRef } from 'reac
|
|
|
4
4
|
import { AccessibilityInfo, Animated, Dimensions, findNodeHandle, Modal as RNModal, Pressable, StyleSheet, View } from 'react-native';
|
|
5
5
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
6
6
|
import { useTheme, createAnimatedValue, setNativeValue } from "../../theme/index.js";
|
|
7
|
-
import { triggerHaptic } from "../../utils/hapticUtils.js";
|
|
7
|
+
import { triggerHaptic, resolveHaptic } from "../../utils/hapticUtils.js";
|
|
8
8
|
|
|
9
9
|
// Local shape mirror — see types.ts ModalTokens for the canonical definition.
|
|
10
10
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
@@ -22,6 +22,7 @@ const Modal = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
22
22
|
contentStyle,
|
|
23
23
|
backdropStyle,
|
|
24
24
|
restoreFocusRef,
|
|
25
|
+
haptic,
|
|
25
26
|
testID
|
|
26
27
|
} = props;
|
|
27
28
|
const theme = useTheme();
|
|
@@ -30,7 +31,6 @@ const Modal = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
30
31
|
const screenHeight = Dimensions.get('window').height;
|
|
31
32
|
const modalTokens = theme.components.modal;
|
|
32
33
|
const scaleStartValue = modalTokens?.scaleStartValue ?? 0.9;
|
|
33
|
-
const backdropHaptic = modalTokens?.backdropHaptic ?? false;
|
|
34
34
|
const backdropAnim = useRef(createAnimatedValue(0)).current;
|
|
35
35
|
const scaleAnim = useRef(createAnimatedValue(scaleStartValue)).current;
|
|
36
36
|
const opacityAnim = useRef(createAnimatedValue(0)).current;
|
|
@@ -126,9 +126,10 @@ const Modal = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
126
126
|
}, [visible, duration, restoreFocusRef]);
|
|
127
127
|
const handleBackdropPress = useCallback(() => {
|
|
128
128
|
if (!backdropPressClose) return;
|
|
129
|
-
|
|
129
|
+
const h = resolveHaptic(haptic, 'selection');
|
|
130
|
+
if (h) triggerHaptic(h);
|
|
130
131
|
onRequestClose();
|
|
131
|
-
}, [backdropPressClose, onRequestClose,
|
|
132
|
+
}, [backdropPressClose, onRequestClose, haptic]);
|
|
132
133
|
const handleHardwareBack = useCallback(() => {
|
|
133
134
|
if (hardwareBackPress) {
|
|
134
135
|
onRequestClose();
|
|
@@ -4,7 +4,7 @@ import React, { forwardRef, useCallback, useEffect, useMemo, useRef, useState }
|
|
|
4
4
|
import { Pressable, StyleSheet, Text, TextInput, View } from 'react-native';
|
|
5
5
|
import { useControllableState } from "../../hooks/index.js";
|
|
6
6
|
import { useTheme } from "../../theme/index.js";
|
|
7
|
-
import { triggerHaptic } from "../../utils/index.js";
|
|
7
|
+
import { resolveHaptic, triggerHaptic } from "../../utils/index.js";
|
|
8
8
|
import { FieldBase, resolveFieldSize, resolveFieldTextStyle } from "../FieldBase/FieldBase.js";
|
|
9
9
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
10
10
|
const DEFAULT_LONG_PRESS_DELAY = 500;
|
|
@@ -58,6 +58,7 @@ const NumberInput = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
58
58
|
size = 'md',
|
|
59
59
|
variant = 'inline',
|
|
60
60
|
unit,
|
|
61
|
+
haptic,
|
|
61
62
|
accessibilityLabel,
|
|
62
63
|
style,
|
|
63
64
|
containerStyle,
|
|
@@ -81,7 +82,6 @@ const NumberInput = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
81
82
|
const styles = useMemo(() => buildStyles(theme), [theme]);
|
|
82
83
|
const longPressDelay = theme.components.numberInput?.longPressDelayMs ?? DEFAULT_LONG_PRESS_DELAY;
|
|
83
84
|
const longPressInterval = theme.components.numberInput?.longPressIntervalMs ?? DEFAULT_LONG_PRESS_INTERVAL;
|
|
84
|
-
const pressHaptic = theme.components.numberInput?.pressHaptic ?? false;
|
|
85
85
|
const inputRef = useRef(null);
|
|
86
86
|
const [draft, setDraft] = useState(formatValue(current, allowDecimal, precision));
|
|
87
87
|
const [editing, setEditing] = useState(false);
|
|
@@ -116,14 +116,16 @@ const NumberInput = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
116
116
|
}, [allowDecimal, max, min, setCurrent, precision, current]);
|
|
117
117
|
const decrement = useCallback(() => {
|
|
118
118
|
if (!interactive || atMin) return;
|
|
119
|
-
|
|
119
|
+
const h = resolveHaptic(haptic, 'selection');
|
|
120
|
+
if (h) triggerHaptic(h);
|
|
120
121
|
setExternal(current - step);
|
|
121
|
-
}, [atMin, interactive,
|
|
122
|
+
}, [atMin, interactive, haptic, setExternal, step, current]);
|
|
122
123
|
const increment = useCallback(() => {
|
|
123
124
|
if (!interactive || atMax) return;
|
|
124
|
-
|
|
125
|
+
const h = resolveHaptic(haptic, 'selection');
|
|
126
|
+
if (h) triggerHaptic(h);
|
|
125
127
|
setExternal(current + step);
|
|
126
|
-
}, [atMax, interactive,
|
|
128
|
+
}, [atMax, interactive, haptic, setExternal, step, current]);
|
|
127
129
|
React.useImperativeHandle(ref, () => ({
|
|
128
130
|
focus: () => inputRef.current?.focus(),
|
|
129
131
|
blur: () => inputRef.current?.blur(),
|
|
@@ -4,7 +4,7 @@ import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo
|
|
|
4
4
|
import { Animated, Easing, Pressable, StyleSheet, Text, TextInput, View } from 'react-native';
|
|
5
5
|
import { fontFor, useTheme, createAnimatedValue, setNativeValue } from "../../theme/index.js";
|
|
6
6
|
import { useReducedMotion, useControllableState } from "../../hooks/index.js";
|
|
7
|
-
import { triggerHaptic } from "../../utils/index.js";
|
|
7
|
+
import { triggerHaptic, resolveHaptic } from "../../utils/index.js";
|
|
8
8
|
import { FieldBase } from "../FieldBase/FieldBase.js";
|
|
9
9
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
10
10
|
const sizeMap = {
|
|
@@ -47,6 +47,7 @@ const OTPInput = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
47
47
|
error,
|
|
48
48
|
size = 'md',
|
|
49
49
|
secure = false,
|
|
50
|
+
haptic,
|
|
50
51
|
accessibilityLabel,
|
|
51
52
|
style,
|
|
52
53
|
cellStyle,
|
|
@@ -89,8 +90,6 @@ const OTPInput = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
89
90
|
const previousFocusedIndexRef = useRef(-1);
|
|
90
91
|
const shakeOnError = theme.components.otpInput?.shakeOnError ?? false;
|
|
91
92
|
const reduceMotion = useReducedMotion();
|
|
92
|
-
const errorHaptic = theme.components.otpInput?.errorHaptic ?? false;
|
|
93
|
-
const selectionHaptic = theme.components.otpInput?.selectionHaptic ?? false;
|
|
94
93
|
const hasError = Boolean(error);
|
|
95
94
|
const errorMessage = typeof error === 'string' ? error : undefined;
|
|
96
95
|
|
|
@@ -100,7 +99,7 @@ const OTPInput = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
100
99
|
const isFirstRun = previousErrorRef.current === null;
|
|
101
100
|
let anim;
|
|
102
101
|
if (!isFirstRun && hasError && !previousErrorRef.current) {
|
|
103
|
-
if (
|
|
102
|
+
if (haptic !== false) triggerHaptic('notificationError');
|
|
104
103
|
if (shakeOnError && !reduceMotion) {
|
|
105
104
|
setNativeValue(shake, 0);
|
|
106
105
|
anim = Animated.sequence([Animated.timing(shake, {
|
|
@@ -129,7 +128,7 @@ const OTPInput = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
129
128
|
}
|
|
130
129
|
previousErrorRef.current = hasError;
|
|
131
130
|
return () => anim?.stop();
|
|
132
|
-
}, [hasError, shake, shakeOnError,
|
|
131
|
+
}, [hasError, shake, shakeOnError, haptic]);
|
|
133
132
|
|
|
134
133
|
// Animate underline opacity for the focused cell. Skip on first mount
|
|
135
134
|
// (no prior focus state) — values are already at 0 and there's nothing to animate.
|
|
@@ -225,8 +224,9 @@ const OTPInput = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
225
224
|
const next = chars.join('').slice(0, length);
|
|
226
225
|
const previousLength = current.length;
|
|
227
226
|
updateValue(next);
|
|
228
|
-
if (next.length !== previousLength
|
|
229
|
-
|
|
227
|
+
if (next.length !== previousLength) {
|
|
228
|
+
const h = resolveHaptic(haptic, 'selection');
|
|
229
|
+
if (h) triggerHaptic(h);
|
|
230
230
|
}
|
|
231
231
|
|
|
232
232
|
// Move focus to the next empty cell or last cell.
|
|
@@ -236,7 +236,7 @@ const OTPInput = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
236
236
|
} else {
|
|
237
237
|
focusCell(nextFocus);
|
|
238
238
|
}
|
|
239
|
-
}, [cells, focusCell, keyboardType, length,
|
|
239
|
+
}, [cells, focusCell, keyboardType, length, haptic, updateValue, current]);
|
|
240
240
|
const handleKeyPress = useCallback((index, e) => {
|
|
241
241
|
const key = e.nativeEvent.key;
|
|
242
242
|
if (key !== 'Backspace') return;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import React, { createContext, forwardRef, useContext, useEffect, useMemo, useRef } from 'react';
|
|
4
4
|
import { Animated, Pressable, StyleSheet, Text, View } from 'react-native';
|
|
5
5
|
import { useTheme, createAnimatedValue } from "../../theme/index.js";
|
|
6
|
-
import { triggerHaptic } from "../../utils/hapticUtils.js";
|
|
6
|
+
import { triggerHaptic, resolveHaptic } from "../../utils/hapticUtils.js";
|
|
7
7
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
8
8
|
export const RadioGroupContext = /*#__PURE__*/createContext(null);
|
|
9
9
|
export const useRadioGroup = () => useContext(RadioGroupContext);
|
|
@@ -64,8 +64,6 @@ const Radio = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
64
64
|
const inner = sizeOverrides?.inner ?? sizeMap[size].inner;
|
|
65
65
|
const radioBorderWidth = theme.colors.border.width;
|
|
66
66
|
const radioLabelGap = theme.components.radio?.labelGap ?? 10;
|
|
67
|
-
const pressHapticEnabled = theme.components.radio?.pressHaptic ?? false;
|
|
68
|
-
const resolvedHaptic = haptic === undefined ? pressHapticEnabled ? 'selection' : false : haptic;
|
|
69
67
|
const progress = useRef(createAnimatedValue(selected ? 1 : 0)).current;
|
|
70
68
|
useEffect(() => {
|
|
71
69
|
const anim = Animated.spring(progress, {
|
|
@@ -84,7 +82,8 @@ const Radio = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
84
82
|
});
|
|
85
83
|
const handlePress = event => {
|
|
86
84
|
if (disabled) return;
|
|
87
|
-
|
|
85
|
+
const h = resolveHaptic(haptic, 'selection');
|
|
86
|
+
if (h) triggerHaptic(h);
|
|
88
87
|
if (ctx) {
|
|
89
88
|
ctx.onChange(value);
|
|
90
89
|
} else {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import React, { forwardRef, useCallback, useMemo, useRef } from 'react';
|
|
4
4
|
import { Animated, Easing, Pressable, StyleSheet, Text, View } from 'react-native';
|
|
5
5
|
import { useTheme } from "../../theme/index.js";
|
|
6
|
-
import { triggerHaptic } from "../../utils/hapticUtils.js";
|
|
6
|
+
import { resolveHaptic, triggerHaptic } from "../../utils/hapticUtils.js";
|
|
7
7
|
import { Skeleton } from "../Skeleton/index.js";
|
|
8
8
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
9
9
|
const sizePxMap = {
|
|
@@ -80,6 +80,7 @@ const Rating = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
80
80
|
tone = 'warning',
|
|
81
81
|
label,
|
|
82
82
|
loading = false,
|
|
83
|
+
haptic,
|
|
83
84
|
accessibilityLabel,
|
|
84
85
|
style,
|
|
85
86
|
containerStyle,
|
|
@@ -116,7 +117,6 @@ const Rating = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
116
117
|
}, [max]);
|
|
117
118
|
const pulseOnPress = theme.components.rating?.pulseOnPress ?? false;
|
|
118
119
|
const pulseScale = theme.components.rating?.pulseScale ?? 1.2;
|
|
119
|
-
const pressHapticEnabled = theme.components.rating?.pressHaptic ?? false;
|
|
120
120
|
const pulse = useCallback(idx => {
|
|
121
121
|
const v = scaleRefs[idx];
|
|
122
122
|
if (!v) return;
|
|
@@ -136,10 +136,11 @@ const Rating = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
136
136
|
const commit = useCallback((next, animatedIndex) => {
|
|
137
137
|
if (!interactive || !onChange) return;
|
|
138
138
|
const cleaned = clampToStep(next, max, step);
|
|
139
|
-
|
|
139
|
+
const h = resolveHaptic(haptic, 'selection');
|
|
140
|
+
if (h) triggerHaptic(h);
|
|
140
141
|
if (pulseOnPress && typeof animatedIndex === 'number') pulse(animatedIndex);
|
|
141
142
|
onChange(cleaned);
|
|
142
|
-
}, [interactive, onChange, max, step, pulse,
|
|
143
|
+
}, [interactive, onChange, max, step, pulse, haptic, pulseOnPress]);
|
|
143
144
|
const handleStarPress = useCallback(index => e => {
|
|
144
145
|
if (!interactive) return;
|
|
145
146
|
const w = starWidthRef.current || starSize;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import React, { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
4
4
|
import { Animated, Easing, Pressable, StyleSheet, Text, TextInput, View } from 'react-native';
|
|
5
5
|
import { fontFor, useTheme, createAnimatedValue } from "../../theme/index.js";
|
|
6
|
-
import { triggerHaptic } from "../../utils/hapticUtils.js";
|
|
6
|
+
import { resolveHaptic, triggerHaptic } from "../../utils/hapticUtils.js";
|
|
7
7
|
import { useDebounce } from "../../hooks/useDebounce.js";
|
|
8
8
|
import { FieldBase, resolveFieldSize, resolveFieldTextStyle, resolveVariantColors } from "../FieldBase/FieldBase.js";
|
|
9
9
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
@@ -24,6 +24,7 @@ const SearchBar = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
24
24
|
size = 'md',
|
|
25
25
|
variant: variantProp,
|
|
26
26
|
cancelLabel = 'Cancel',
|
|
27
|
+
haptic,
|
|
27
28
|
style,
|
|
28
29
|
accessibilityLabel,
|
|
29
30
|
testID,
|
|
@@ -92,16 +93,18 @@ const SearchBar = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
92
93
|
onChangeText(text);
|
|
93
94
|
}, [debounceMs, onChangeText]);
|
|
94
95
|
const handleClear = useCallback(() => {
|
|
95
|
-
|
|
96
|
+
const h = resolveHaptic(haptic, 'selection');
|
|
97
|
+
if (h) triggerHaptic(h);
|
|
96
98
|
if (debounceMs !== undefined) {
|
|
97
99
|
setInternalValue('');
|
|
98
100
|
lastSentRef.current = '';
|
|
99
101
|
}
|
|
100
102
|
onChangeText('');
|
|
101
103
|
onClear?.();
|
|
102
|
-
}, [debounceMs, onChangeText, onClear]);
|
|
104
|
+
}, [haptic, debounceMs, onChangeText, onClear]);
|
|
103
105
|
const handleCancel = useCallback(() => {
|
|
104
|
-
|
|
106
|
+
const h = resolveHaptic(haptic, 'selection');
|
|
107
|
+
if (h) triggerHaptic(h);
|
|
105
108
|
if (debounceMs !== undefined) {
|
|
106
109
|
setInternalValue('');
|
|
107
110
|
lastSentRef.current = '';
|
|
@@ -109,7 +112,7 @@ const SearchBar = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
109
112
|
onChangeText('');
|
|
110
113
|
setIsFocused(false);
|
|
111
114
|
onCancel?.();
|
|
112
|
-
}, [debounceMs, onChangeText, onCancel]);
|
|
115
|
+
}, [haptic, debounceMs, onChangeText, onCancel]);
|
|
113
116
|
const handleSubmit = useCallback(() => {
|
|
114
117
|
onSubmit?.(debounceMs !== undefined ? internalValue : value);
|
|
115
118
|
}, [onSubmit, debounceMs, internalValue, value]);
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
import React, { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
12
12
|
import { Animated, Pressable, StyleSheet, Text, View } from 'react-native';
|
|
13
13
|
import { useTheme, createAnimatedValue } from "../../theme/index.js";
|
|
14
|
-
import { triggerHaptic } from "../../utils/index.js";
|
|
14
|
+
import { triggerHaptic, resolveHaptic } from "../../utils/index.js";
|
|
15
15
|
import { useControllableState } from "../../hooks/index.js";
|
|
16
16
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
17
17
|
const sizeMap = {
|
|
@@ -37,6 +37,7 @@ const SegmentedControl = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
37
37
|
fullWidth = true,
|
|
38
38
|
disabled = false,
|
|
39
39
|
tone = 'primary',
|
|
40
|
+
haptic,
|
|
40
41
|
accessibilityLabel,
|
|
41
42
|
style,
|
|
42
43
|
containerStyle,
|
|
@@ -61,7 +62,6 @@ const SegmentedControl = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
61
62
|
paddingHorizontal: segTheme?.[size]?.paddingHorizontal ?? baseSize.paddingHorizontal
|
|
62
63
|
};
|
|
63
64
|
const trackPadding = segTheme?.trackPadding ?? TRACK_PADDING;
|
|
64
|
-
const changeHapticEnabled = segTheme?.changeHaptic ?? false;
|
|
65
65
|
|
|
66
66
|
// Track width is measured from onLayout. Thumb width is a regular number (not
|
|
67
67
|
// animated) — `width` cannot be driven by the native animated module, and mixing
|
|
@@ -102,9 +102,10 @@ const SegmentedControl = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
102
102
|
const handlePress = useCallback(segment => {
|
|
103
103
|
if (disabled) return;
|
|
104
104
|
if (segment.value === current) return;
|
|
105
|
-
|
|
105
|
+
const h = resolveHaptic(haptic, 'selection');
|
|
106
|
+
if (h) triggerHaptic(h);
|
|
106
107
|
setCurrent(segment.value);
|
|
107
|
-
}, [disabled, setCurrent, current,
|
|
108
|
+
}, [disabled, setCurrent, current, haptic]);
|
|
108
109
|
const thumbBg = tone === 'primary' ? theme.colors.background.elevated : theme.colors.background.elevated;
|
|
109
110
|
const activeTextColor = tone === 'primary' ? theme.colors.text.primary : theme.colors.text.primary;
|
|
110
111
|
return /*#__PURE__*/_jsxs(View, {
|
|
@@ -12,7 +12,7 @@ import React, { forwardRef, useCallback, useEffect, useMemo, useRef, useState }
|
|
|
12
12
|
import { Animated, Dimensions, Easing, FlatList, Modal, Pressable, StyleSheet, Text, TextInput, View } from 'react-native';
|
|
13
13
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
14
14
|
import { useTheme, createAnimatedValue } from "../../theme/index.js";
|
|
15
|
-
import { triggerHaptic } from "../../utils/index.js";
|
|
15
|
+
import { resolveHaptic, triggerHaptic } from "../../utils/index.js";
|
|
16
16
|
import { FieldBase, resolveFieldSize, resolveFieldTextStyle, resolveVariantColors } from "../FieldBase/FieldBase.js";
|
|
17
17
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
18
18
|
// `unknown` here keeps the forwardRef signature non-generic — consumers who
|
|
@@ -27,6 +27,7 @@ const Select = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
27
27
|
getOptionDescription,
|
|
28
28
|
placeholder,
|
|
29
29
|
searchable = false,
|
|
30
|
+
haptic,
|
|
30
31
|
label,
|
|
31
32
|
error,
|
|
32
33
|
disabled = false,
|
|
@@ -114,9 +115,10 @@ const Select = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
114
115
|
}, [searchable, query, options, labelOf, descriptionOf]);
|
|
115
116
|
const handleOpen = useCallback(() => {
|
|
116
117
|
if (disabled) return;
|
|
117
|
-
|
|
118
|
+
const h = resolveHaptic(haptic, 'selection');
|
|
119
|
+
if (h) triggerHaptic(h);
|
|
118
120
|
setOpen(true);
|
|
119
|
-
}, [disabled]);
|
|
121
|
+
}, [disabled, haptic]);
|
|
120
122
|
const handleClose = useCallback(() => {
|
|
121
123
|
setOpen(false);
|
|
122
124
|
setQuery('');
|
|
@@ -124,7 +126,8 @@ const Select = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
124
126
|
const handleSelect = useCallback(option => {
|
|
125
127
|
if (disabledOf(option)) return;
|
|
126
128
|
const optValue = valueOf(option);
|
|
127
|
-
|
|
129
|
+
const h = resolveHaptic(haptic, 'selection');
|
|
130
|
+
if (h) triggerHaptic(h);
|
|
128
131
|
if (multi) {
|
|
129
132
|
const current = props.value ?? [];
|
|
130
133
|
const next = current.includes(optValue) ? current.filter(v => v !== optValue) : [...current, optValue];
|
|
@@ -133,7 +136,7 @@ const Select = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
133
136
|
}
|
|
134
137
|
props.onChange(optValue);
|
|
135
138
|
handleClose();
|
|
136
|
-
}, [multi, props, handleClose, disabledOf, valueOf]);
|
|
139
|
+
}, [multi, props, handleClose, disabledOf, valueOf, haptic]);
|
|
137
140
|
|
|
138
141
|
// Trigger label / placeholder text.
|
|
139
142
|
const triggerText = selectedOptions.length === 0 ? placeholder ?? 'Select…' : selectedOptions.map(o => labelOf(o)).join(', ');
|