@webority-technologies/mobile 0.0.12 → 0.0.14
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/Badge/Badge.js +1 -1
- package/lib/commonjs/components/BottomNavigation/BottomNavigation.js +11 -3
- package/lib/commonjs/components/BottomSheet/BottomSheet.js +45 -6
- package/lib/commonjs/components/DatePicker/DatePicker.js +18 -12
- package/lib/commonjs/components/DateRangePicker/DateRangePicker.js +14 -9
- package/lib/commonjs/components/FloatingActionButton/FloatingActionButton.js +1 -1
- package/lib/commonjs/components/Input/Input.js +1 -1
- package/lib/commonjs/components/Modal/Modal.js +4 -4
- package/lib/commonjs/components/OTPInput/OTPInput.js +29 -9
- package/lib/commonjs/components/ProgressBar/ProgressBar.js +1 -1
- package/lib/commonjs/components/SegmentedControl/SegmentedControl.js +23 -28
- package/lib/commonjs/components/Skeleton/Skeleton.js +1 -1
- package/lib/commonjs/components/Slider/Slider.js +11 -11
- package/lib/commonjs/components/Stepper/Stepper.js +10 -4
- package/lib/commonjs/components/Tabs/Tabs.js +7 -5
- package/lib/commonjs/components/TimePicker/TimePicker.js +3 -3
- package/lib/commonjs/components/Toast/Toast.js +2 -2
- package/lib/commonjs/theme/animatedValue.js +20 -1
- package/lib/commonjs/theme/index.js +8 -1
- package/lib/module/components/Badge/Badge.js +2 -2
- package/lib/module/components/BottomNavigation/BottomNavigation.js +11 -3
- package/lib/module/components/BottomSheet/BottomSheet.js +47 -8
- package/lib/module/components/DatePicker/DatePicker.js +19 -13
- package/lib/module/components/DateRangePicker/DateRangePicker.js +15 -10
- package/lib/module/components/FloatingActionButton/FloatingActionButton.js +2 -2
- package/lib/module/components/Input/Input.js +2 -2
- package/lib/module/components/Modal/Modal.js +5 -5
- package/lib/module/components/OTPInput/OTPInput.js +30 -10
- package/lib/module/components/ProgressBar/ProgressBar.js +2 -2
- package/lib/module/components/SegmentedControl/SegmentedControl.js +24 -29
- package/lib/module/components/Skeleton/Skeleton.js +2 -2
- package/lib/module/components/Slider/Slider.js +12 -12
- package/lib/module/components/Stepper/Stepper.js +10 -4
- package/lib/module/components/Tabs/Tabs.js +7 -5
- package/lib/module/components/TimePicker/TimePicker.js +4 -4
- package/lib/module/components/Toast/Toast.js +3 -3
- package/lib/module/theme/animatedValue.js +18 -0
- package/lib/module/theme/index.js +1 -1
- package/lib/typescript/commonjs/components/BottomNavigation/BottomNavigation.d.ts +7 -0
- package/lib/typescript/commonjs/components/BottomSheet/BottomSheet.d.ts +10 -0
- package/lib/typescript/commonjs/theme/animatedValue.d.ts +11 -0
- package/lib/typescript/commonjs/theme/index.d.ts +1 -1
- package/lib/typescript/module/components/BottomNavigation/BottomNavigation.d.ts +7 -0
- package/lib/typescript/module/components/BottomSheet/BottomSheet.d.ts +10 -0
- package/lib/typescript/module/theme/animatedValue.d.ts +11 -0
- package/lib/typescript/module/theme/index.d.ts +1 -1
- package/package.json +1 -1
|
@@ -47,15 +47,17 @@ const Tabs = exports.Tabs = /*#__PURE__*/(0, _react.forwardRef)((props, ref) =>
|
|
|
47
47
|
(0, _react.useEffect)(() => {
|
|
48
48
|
if (!activeLayout) return;
|
|
49
49
|
const spring = theme.motion.spring.snappy;
|
|
50
|
-
_reactNative.Animated.parallel([
|
|
50
|
+
_reactNative.Animated.parallel([
|
|
51
|
+
// Both must use the JS driver: width can't run on native, and mixing
|
|
52
|
+
// drivers on the same view (transform native + width JS) trips RN's
|
|
53
|
+
// "node already moved to native" guard under the new architecture.
|
|
54
|
+
_reactNative.Animated.spring(indicatorTranslateX, {
|
|
51
55
|
toValue: activeLayout.x,
|
|
52
56
|
damping: spring.damping,
|
|
53
57
|
stiffness: spring.stiffness,
|
|
54
58
|
mass: spring.mass,
|
|
55
|
-
useNativeDriver:
|
|
56
|
-
}),
|
|
57
|
-
// width is a layout prop — must run on JS thread (useNativeDriver: false).
|
|
58
|
-
_reactNative.Animated.spring(indicatorWidth, {
|
|
59
|
+
useNativeDriver: false
|
|
60
|
+
}), _reactNative.Animated.spring(indicatorWidth, {
|
|
59
61
|
toValue: activeLayout.width,
|
|
60
62
|
damping: spring.damping,
|
|
61
63
|
stiffness: spring.stiffness,
|
|
@@ -74,7 +74,7 @@ const Wheel = ({
|
|
|
74
74
|
if (lastIndexRef.current !== selectedIndex) {
|
|
75
75
|
lastIndexRef.current = selectedIndex;
|
|
76
76
|
const offset = selectedIndex * ITEM_HEIGHT;
|
|
77
|
-
|
|
77
|
+
(0, _index.setNativeValue)(scrollY, offset);
|
|
78
78
|
// Defer to next frame so FlatList has measured.
|
|
79
79
|
requestAnimationFrame(() => {
|
|
80
80
|
listRef.current?.scrollToOffset({
|
|
@@ -281,8 +281,8 @@ const TimePicker = ({
|
|
|
281
281
|
useNativeDriver: true
|
|
282
282
|
})]).start();
|
|
283
283
|
} else {
|
|
284
|
-
|
|
285
|
-
|
|
284
|
+
(0, _index.setNativeValue)(opacity, 0);
|
|
285
|
+
(0, _index.setNativeValue)(translateY, 40);
|
|
286
286
|
}
|
|
287
287
|
}, [visible, opacity, translateY, theme.motion]);
|
|
288
288
|
const announce = (0, _react.useCallback)(msg => {
|
|
@@ -73,9 +73,9 @@ const Toast = ({
|
|
|
73
73
|
const panResponder = (0, _react.useMemo)(() => _reactNative.PanResponder.create({
|
|
74
74
|
onMoveShouldSetPanResponder: (_evt, gesture) => Math.abs(gesture.dx) > Math.abs(gesture.dy) && Math.abs(gesture.dx) > 6,
|
|
75
75
|
onPanResponderMove: (_evt, gesture) => {
|
|
76
|
-
|
|
76
|
+
(0, _index.setNativeValue)(translateX, gesture.dx);
|
|
77
77
|
const fade = 1 - Math.min(Math.abs(gesture.dx) / 200, 1) * 0.7;
|
|
78
|
-
|
|
78
|
+
(0, _index.setNativeValue)(opacity, fade);
|
|
79
79
|
},
|
|
80
80
|
onPanResponderRelease: (_evt, gesture) => {
|
|
81
81
|
if (Math.abs(gesture.dx) > SWIPE_DISMISS_THRESHOLD || Math.abs(gesture.vx) > SWIPE_VELOCITY_THRESHOLD) {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.createAnimatedValue = void 0;
|
|
6
|
+
exports.setNativeValue = exports.createAnimatedValue = void 0;
|
|
7
7
|
var _reactNative = require("react-native");
|
|
8
8
|
/**
|
|
9
9
|
* Create an `Animated.Value` that survives RN 0.85's dev-mode prop deepFreeze.
|
|
@@ -24,5 +24,24 @@ var _reactNative = require("react-native");
|
|
|
24
24
|
* Use everywhere the library would otherwise call `new Animated.Value(...)`.
|
|
25
25
|
*/
|
|
26
26
|
const createAnimatedValue = (initial, config) => Object.seal(new _reactNative.Animated.Value(initial, config));
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Set an `Animated.Value` to a target without going through JS.
|
|
30
|
+
*
|
|
31
|
+
* Once a value has been driven by `useNativeDriver: true`, the underlying
|
|
32
|
+
* native node owns it — calling `value.setValue(x)` from JS throws
|
|
33
|
+
* "Attempting to run JS driven animation on animated node that has been moved to native".
|
|
34
|
+
* Use this helper for any value that is *also* used in a native-driven
|
|
35
|
+
* `Animated.timing/spring`. A zero-duration native timing routes the update
|
|
36
|
+
* through the same driver and stays valid across re-mounts and re-runs.
|
|
37
|
+
*/
|
|
27
38
|
exports.createAnimatedValue = createAnimatedValue;
|
|
39
|
+
const setNativeValue = (value, to) => {
|
|
40
|
+
_reactNative.Animated.timing(value, {
|
|
41
|
+
toValue: to,
|
|
42
|
+
duration: 0,
|
|
43
|
+
useNativeDriver: true
|
|
44
|
+
}).start();
|
|
45
|
+
};
|
|
46
|
+
exports.setNativeValue = setNativeValue;
|
|
28
47
|
//# sourceMappingURL=animatedValue.js.map
|
|
@@ -52,7 +52,14 @@ Object.defineProperty(exports, "mergeTheme", {
|
|
|
52
52
|
return _merge.mergeTheme;
|
|
53
53
|
}
|
|
54
54
|
});
|
|
55
|
-
exports.
|
|
55
|
+
exports.setColorMode = exports.resetTheme = void 0;
|
|
56
|
+
Object.defineProperty(exports, "setNativeValue", {
|
|
57
|
+
enumerable: true,
|
|
58
|
+
get: function () {
|
|
59
|
+
return _animatedValue.setNativeValue;
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
exports.subscribeTheme = exports.setTheme = void 0;
|
|
56
63
|
Object.defineProperty(exports, "useTheme", {
|
|
57
64
|
enumerable: true,
|
|
58
65
|
get: function () {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import React, { forwardRef, useEffect, useMemo, useRef } from 'react';
|
|
4
4
|
import { Animated, Easing, StyleSheet, Text, View } from 'react-native';
|
|
5
|
-
import { fontFor, useTheme, createAnimatedValue } from "../../theme/index.js";
|
|
5
|
+
import { fontFor, useTheme, createAnimatedValue, setNativeValue } from "../../theme/index.js";
|
|
6
6
|
import { SkeletonContent } from "../Skeleton/index.js";
|
|
7
7
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
8
8
|
const toneFor = (theme, tone) => {
|
|
@@ -126,7 +126,7 @@ const Badge = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
126
126
|
const pulseScale = useRef(createAnimatedValue(1)).current;
|
|
127
127
|
useEffect(() => {
|
|
128
128
|
if (!pulse || !shouldRender) {
|
|
129
|
-
pulseScale
|
|
129
|
+
setNativeValue(pulseScale, 1);
|
|
130
130
|
return;
|
|
131
131
|
}
|
|
132
132
|
const loop = Animated.loop(Animated.sequence([Animated.timing(pulseScale, {
|
|
@@ -48,6 +48,7 @@ const BottomNavigation = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
48
48
|
haptic = 'selection',
|
|
49
49
|
showLabels = true,
|
|
50
50
|
variant = 'pill',
|
|
51
|
+
indicatorPosition = 'bottom',
|
|
51
52
|
style,
|
|
52
53
|
indicatorStyle,
|
|
53
54
|
labelStyle,
|
|
@@ -193,7 +194,7 @@ const BottomNavigation = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
193
194
|
}, tab.key);
|
|
194
195
|
}), variant === 'underline' && tabWidth > 0 ? /*#__PURE__*/_jsx(Animated.View, {
|
|
195
196
|
pointerEvents: "none",
|
|
196
|
-
style: [styles.underline, {
|
|
197
|
+
style: [styles.underline, indicatorPosition === 'top' ? styles.underlineTop : styles.underlineBottom, {
|
|
197
198
|
width: tabWidth,
|
|
198
199
|
backgroundColor: theme.colors.primary,
|
|
199
200
|
transform: [{
|
|
@@ -243,12 +244,19 @@ const buildStyles = theme => StyleSheet.create({
|
|
|
243
244
|
},
|
|
244
245
|
underline: {
|
|
245
246
|
position: 'absolute',
|
|
246
|
-
bottom: -6,
|
|
247
247
|
left: 0,
|
|
248
|
-
height: UNDERLINE_HEIGHT
|
|
248
|
+
height: UNDERLINE_HEIGHT
|
|
249
|
+
},
|
|
250
|
+
underlineBottom: {
|
|
251
|
+
bottom: -6,
|
|
249
252
|
borderTopLeftRadius: 2,
|
|
250
253
|
borderTopRightRadius: 2
|
|
251
254
|
},
|
|
255
|
+
underlineTop: {
|
|
256
|
+
top: -6,
|
|
257
|
+
borderBottomLeftRadius: 2,
|
|
258
|
+
borderBottomRightRadius: 2
|
|
259
|
+
},
|
|
252
260
|
badgePill: {
|
|
253
261
|
position: 'absolute',
|
|
254
262
|
top: -4,
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
|
|
23
|
-
import { Dimensions, Keyboard, Platform, Pressable, StyleSheet, View } from 'react-native';
|
|
24
|
-
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
|
|
23
|
+
import { Dimensions, Keyboard, Modal, Platform, Pressable, StyleSheet, View } from 'react-native';
|
|
24
|
+
import { Gesture, GestureDetector, GestureHandlerRootView } from 'react-native-gesture-handler';
|
|
25
25
|
import Animated, { Extrapolation, interpolate, runOnJS, useAnimatedStyle, useSharedValue, withSpring, withTiming } from 'react-native-reanimated';
|
|
26
26
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
27
27
|
import { useTheme } from "../../theme/index.js";
|
|
@@ -44,6 +44,7 @@ const BottomSheet = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
44
44
|
enableBackdropPress = true,
|
|
45
45
|
backdropOpacity = 0.5,
|
|
46
46
|
keyboardBehavior = 'none',
|
|
47
|
+
mode = 'modal',
|
|
47
48
|
handleIndicatorStyle,
|
|
48
49
|
containerStyle,
|
|
49
50
|
children,
|
|
@@ -79,6 +80,10 @@ const BottomSheet = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
79
80
|
const currentIndexShared = useSharedValue(-1);
|
|
80
81
|
const [currentIndex, setCurrentIndex] = useState(-1);
|
|
81
82
|
const isAnimatingRef = useRef(false);
|
|
83
|
+
// Drives the native <Modal>'s visible prop in modal mode. We mount the modal
|
|
84
|
+
// synchronously on open and unmount only after the close animation finishes
|
|
85
|
+
// so the slide-down stays visible.
|
|
86
|
+
const [modalVisible, setModalVisible] = useState(false);
|
|
82
87
|
|
|
83
88
|
// Convert a snap-point index → translateY position. -1 = closed.
|
|
84
89
|
const yForIndex = useCallback(idx => {
|
|
@@ -106,14 +111,26 @@ const BottomSheet = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
106
111
|
}, [onAnimate, translateY]);
|
|
107
112
|
const markAnimationDone = useCallback(() => {
|
|
108
113
|
isAnimatingRef.current = false;
|
|
109
|
-
|
|
114
|
+
// If we just finished a close animation, unmount the modal wrapper.
|
|
115
|
+
if (mode === 'modal' && currentIndexShared.value < 0) {
|
|
116
|
+
setModalVisible(false);
|
|
117
|
+
}
|
|
118
|
+
}, [mode, currentIndexShared]);
|
|
110
119
|
const expand = useCallback(idx => {
|
|
111
120
|
const target = typeof idx === 'number' ? clamp(idx, 0, resolvedSnapPoints.length - 1) : currentIndex >= 0 ? currentIndex : 0;
|
|
112
121
|
const fromIndex = currentIndexShared.value;
|
|
113
122
|
const to = yForIndex(target);
|
|
123
|
+
// Mount the Modal before kicking off the spring so the sheet has a
|
|
124
|
+
// host to animate into.
|
|
125
|
+
if (mode === 'modal') setModalVisible(true);
|
|
126
|
+
// Reset translateY to the closed position so the first open animates
|
|
127
|
+
// up from off-screen rather than snapping in place.
|
|
128
|
+
if (fromIndex < 0) {
|
|
129
|
+
translateY.value = closedY;
|
|
130
|
+
}
|
|
114
131
|
setIndexJS(target);
|
|
115
132
|
animateTo(to, fromIndex, target);
|
|
116
|
-
}, [animateTo, currentIndex, currentIndexShared, resolvedSnapPoints.length, setIndexJS, yForIndex]);
|
|
133
|
+
}, [animateTo, closedY, currentIndex, currentIndexShared, mode, resolvedSnapPoints.length, setIndexJS, translateY, yForIndex]);
|
|
117
134
|
const collapse = useCallback(() => {
|
|
118
135
|
if (resolvedSnapPoints.length === 0) return;
|
|
119
136
|
const fromIndex = currentIndexShared.value;
|
|
@@ -295,16 +312,19 @@ const BottomSheet = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
295
312
|
}, [enableBackdropPress, close]);
|
|
296
313
|
|
|
297
314
|
// Don't render the heavy gesture tree at all when nothing's been opened yet.
|
|
298
|
-
//
|
|
299
|
-
//
|
|
315
|
+
// For inline mode we keep the legacy "mount on first open" behavior; modal
|
|
316
|
+
// mode is gated entirely by `modalVisible`.
|
|
300
317
|
const everOpenedRef = useRef(false);
|
|
301
318
|
if (isExpanded || controlledIndex !== undefined) {
|
|
302
319
|
everOpenedRef.current = true;
|
|
303
320
|
}
|
|
304
|
-
if (!everOpenedRef.current) {
|
|
321
|
+
if (mode === 'inline' && !everOpenedRef.current) {
|
|
322
|
+
return null;
|
|
323
|
+
}
|
|
324
|
+
if (mode === 'modal' && !modalVisible) {
|
|
305
325
|
return null;
|
|
306
326
|
}
|
|
307
|
-
|
|
327
|
+
const sheetTree = /*#__PURE__*/_jsxs(View, {
|
|
308
328
|
style: StyleSheet.absoluteFill,
|
|
309
329
|
pointerEvents: "box-none",
|
|
310
330
|
testID: testID,
|
|
@@ -351,6 +371,22 @@ const BottomSheet = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
351
371
|
})
|
|
352
372
|
})]
|
|
353
373
|
});
|
|
374
|
+
if (mode === 'modal') {
|
|
375
|
+
return /*#__PURE__*/_jsx(Modal, {
|
|
376
|
+
transparent: true,
|
|
377
|
+
visible: modalVisible,
|
|
378
|
+
onRequestClose: close,
|
|
379
|
+
statusBarTranslucent: true,
|
|
380
|
+
presentationStyle: "overFullScreen",
|
|
381
|
+
animationType: "none",
|
|
382
|
+
supportedOrientations: ['portrait', 'landscape'],
|
|
383
|
+
children: /*#__PURE__*/_jsx(GestureHandlerRootView, {
|
|
384
|
+
style: styles.modalRoot,
|
|
385
|
+
children: sheetTree
|
|
386
|
+
})
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
return sheetTree;
|
|
354
390
|
});
|
|
355
391
|
BottomSheet.displayName = 'BottomSheet';
|
|
356
392
|
|
|
@@ -390,6 +426,9 @@ const buildStyles = _theme => StyleSheet.create({
|
|
|
390
426
|
},
|
|
391
427
|
content: {
|
|
392
428
|
flex: 1
|
|
429
|
+
},
|
|
430
|
+
modalRoot: {
|
|
431
|
+
flex: 1
|
|
393
432
|
}
|
|
394
433
|
});
|
|
395
434
|
export { BottomSheet };
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
4
4
|
import { AccessibilityInfo, Animated, Easing, Modal, Pressable, StyleSheet, Text, View } from 'react-native';
|
|
5
|
-
import { useTheme, createAnimatedValue } from "../../theme/index.js";
|
|
5
|
+
import { useTheme, createAnimatedValue, setNativeValue } from "../../theme/index.js";
|
|
6
6
|
import { triggerHaptic } from "../../utils/index.js";
|
|
7
7
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
8
8
|
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
@@ -130,8 +130,8 @@ const DatePicker = props => {
|
|
|
130
130
|
useEffect(() => {
|
|
131
131
|
if (mode !== 'modal') return;
|
|
132
132
|
if (visible) {
|
|
133
|
-
backdrop
|
|
134
|
-
sheet
|
|
133
|
+
setNativeValue(backdrop, 0);
|
|
134
|
+
setNativeValue(sheet, 0);
|
|
135
135
|
Animated.parallel([Animated.timing(backdrop, {
|
|
136
136
|
toValue: 1,
|
|
137
137
|
duration: theme.motion.duration.normal,
|
|
@@ -243,8 +243,8 @@ const DatePicker = props => {
|
|
|
243
243
|
|
|
244
244
|
// View-mode transition: fade + scale (200ms, native driver).
|
|
245
245
|
const animateViewTransition = useCallback(() => {
|
|
246
|
-
viewFade
|
|
247
|
-
viewScale
|
|
246
|
+
setNativeValue(viewFade, 0);
|
|
247
|
+
setNativeValue(viewScale, 0.9);
|
|
248
248
|
Animated.parallel([Animated.timing(viewFade, {
|
|
249
249
|
toValue: 1,
|
|
250
250
|
duration: 200,
|
|
@@ -295,7 +295,7 @@ const DatePicker = props => {
|
|
|
295
295
|
if (!cell.inMonth) {
|
|
296
296
|
setAnchor(new Date(cell.date.getFullYear(), cell.date.getMonth(), 1));
|
|
297
297
|
}
|
|
298
|
-
selectScale
|
|
298
|
+
setNativeValue(selectScale, 0.7);
|
|
299
299
|
Animated.spring(selectScale, {
|
|
300
300
|
toValue: 1,
|
|
301
301
|
damping: theme.motion.spring.bouncy.damping,
|
|
@@ -377,11 +377,16 @@ const DatePicker = props => {
|
|
|
377
377
|
opacity: viewMode === 'days' ? monthFade : 1
|
|
378
378
|
}],
|
|
379
379
|
children: [/*#__PURE__*/_jsx(Animated.Text, {
|
|
380
|
-
style: [styles.headerLabel,
|
|
380
|
+
style: [styles.headerLabel,
|
|
381
|
+
// Always include the transform — passing null/undefined as a
|
|
382
|
+
// transform value confuses Animated's processTransform on Fabric.
|
|
383
|
+
// When the month slide isn't active we still drive translateX
|
|
384
|
+
// through the same value, just with target 0.
|
|
385
|
+
{
|
|
381
386
|
transform: [{
|
|
382
|
-
translateX: monthSlide
|
|
387
|
+
translateX: viewMode === 'days' ? monthSlide : 0
|
|
383
388
|
}]
|
|
384
|
-
}
|
|
389
|
+
}],
|
|
385
390
|
accessibilityLiveRegion: "polite",
|
|
386
391
|
children: headerLabel
|
|
387
392
|
}), /*#__PURE__*/_jsx(Text, {
|
|
@@ -447,11 +452,12 @@ const DatePicker = props => {
|
|
|
447
452
|
backgroundColor: cellBg,
|
|
448
453
|
borderColor,
|
|
449
454
|
borderWidth: todayCell && !selected ? 1.5 : 0,
|
|
450
|
-
opacity
|
|
451
|
-
|
|
455
|
+
opacity
|
|
456
|
+
}, selected ? {
|
|
457
|
+
transform: [{
|
|
452
458
|
scale: selectScale
|
|
453
|
-
}]
|
|
454
|
-
}],
|
|
459
|
+
}]
|
|
460
|
+
} : null],
|
|
455
461
|
children: /*#__PURE__*/_jsx(Text, {
|
|
456
462
|
style: [styles.dayText, {
|
|
457
463
|
color: textColor
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import React, { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
4
4
|
import { AccessibilityInfo, Animated, Easing, Modal, Pressable, StyleSheet, Text, View } from 'react-native';
|
|
5
|
-
import { useTheme, createAnimatedValue } from "../../theme/index.js";
|
|
5
|
+
import { useTheme, createAnimatedValue, setNativeValue } from "../../theme/index.js";
|
|
6
6
|
import { triggerHaptic } from "../../utils/index.js";
|
|
7
7
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
8
8
|
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
@@ -115,8 +115,8 @@ const DateRangePicker = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
115
115
|
// Modal open / close animation.
|
|
116
116
|
useEffect(() => {
|
|
117
117
|
if (visible) {
|
|
118
|
-
backdrop
|
|
119
|
-
sheet
|
|
118
|
+
setNativeValue(backdrop, 0);
|
|
119
|
+
setNativeValue(sheet, 0);
|
|
120
120
|
Animated.parallel([Animated.timing(backdrop, {
|
|
121
121
|
toValue: 1,
|
|
122
122
|
duration: theme.motion.duration.normal,
|
|
@@ -556,26 +556,31 @@ const buildStyles = theme => {
|
|
|
556
556
|
aspectRatio: 1,
|
|
557
557
|
alignItems: 'center',
|
|
558
558
|
justifyContent: 'center',
|
|
559
|
-
padding
|
|
559
|
+
// No horizontal padding so the connector bars on adjacent cells meet
|
|
560
|
+
// without a gap. Vertical breathing room comes from dayInner's height.
|
|
561
|
+
padding: 0,
|
|
560
562
|
position: 'relative'
|
|
561
563
|
},
|
|
564
|
+
// Bars sit BEHIND dayInner and bridge the start/end circles to mid-range
|
|
565
|
+
// cells. Their height mirrors dayInner (~90% of cell height) so the visual
|
|
566
|
+
// pill is one continuous shape across multiple cells.
|
|
562
567
|
barLeft: {
|
|
563
568
|
position: 'absolute',
|
|
564
569
|
left: 0,
|
|
565
570
|
right: '50%',
|
|
566
|
-
top: '
|
|
567
|
-
bottom: '
|
|
571
|
+
top: '5%',
|
|
572
|
+
bottom: '5%'
|
|
568
573
|
},
|
|
569
574
|
barRight: {
|
|
570
575
|
position: 'absolute',
|
|
571
576
|
left: '50%',
|
|
572
577
|
right: 0,
|
|
573
|
-
top: '
|
|
574
|
-
bottom: '
|
|
578
|
+
top: '5%',
|
|
579
|
+
bottom: '5%'
|
|
575
580
|
},
|
|
576
581
|
dayInner: {
|
|
577
|
-
width: '
|
|
578
|
-
height: '
|
|
582
|
+
width: '90%',
|
|
583
|
+
height: '90%',
|
|
579
584
|
alignItems: 'center',
|
|
580
585
|
justifyContent: 'center'
|
|
581
586
|
},
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import React, { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
4
4
|
import { Animated, Easing, Pressable, StyleSheet, Text, View } from 'react-native';
|
|
5
5
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
6
|
-
import { useTheme, createAnimatedValue } from "../../theme/index.js";
|
|
6
|
+
import { useTheme, createAnimatedValue, setNativeValue } from "../../theme/index.js";
|
|
7
7
|
import { usePressAnimation } from "../../hooks/usePressAnimation.js";
|
|
8
8
|
import { triggerHaptic } from "../../utils/hapticUtils.js";
|
|
9
9
|
import { AppIcon } from "../AppIcon/index.js";
|
|
@@ -81,7 +81,7 @@ const FloatingActionButton = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
81
81
|
const hideAnim = useRef(createAnimatedValue(0)).current;
|
|
82
82
|
useEffect(() => {
|
|
83
83
|
if (!hideOnScroll) {
|
|
84
|
-
hideAnim
|
|
84
|
+
setNativeValue(hideAnim, 0);
|
|
85
85
|
return;
|
|
86
86
|
}
|
|
87
87
|
Animated.timing(hideAnim, {
|
|
@@ -5,7 +5,7 @@ import { Animated, Easing, Pressable, StyleSheet, Text, TextInput, View } from '
|
|
|
5
5
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
6
6
|
// @ts-ignore - react-native-vector-icons ships no bundled types in this version
|
|
7
7
|
import Feather from 'react-native-vector-icons/Feather';
|
|
8
|
-
import { createAnimatedValue, fontFor, useTheme } from "../../theme/index.js";
|
|
8
|
+
import { createAnimatedValue, fontFor, setNativeValue, useTheme } from "../../theme/index.js";
|
|
9
9
|
import { triggerHaptic } from "../../utils/index.js";
|
|
10
10
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
11
11
|
const sizeMap = {
|
|
@@ -140,7 +140,7 @@ const Input = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
140
140
|
const prevErrorRef = useRef(hasError);
|
|
141
141
|
useEffect(() => {
|
|
142
142
|
if (hasError && !prevErrorRef.current) {
|
|
143
|
-
shakeAnim
|
|
143
|
+
setNativeValue(shakeAnim, 0);
|
|
144
144
|
Animated.sequence([Animated.timing(shakeAnim, {
|
|
145
145
|
toValue: 1,
|
|
146
146
|
duration: 50,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import React, { forwardRef, useCallback, useEffect, useMemo, useRef } from 'react';
|
|
4
4
|
import { AccessibilityInfo, Animated, Dimensions, findNodeHandle, Modal as RNModal, Pressable, StyleSheet, View } from 'react-native';
|
|
5
|
-
import { useTheme, createAnimatedValue } from "../../theme/index.js";
|
|
5
|
+
import { useTheme, createAnimatedValue, setNativeValue } from "../../theme/index.js";
|
|
6
6
|
import { triggerHaptic } from "../../utils/hapticUtils.js";
|
|
7
7
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
8
8
|
const Modal = /*#__PURE__*/forwardRef((props, ref) => {
|
|
@@ -60,10 +60,10 @@ const Modal = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
60
60
|
})]).start();
|
|
61
61
|
}
|
|
62
62
|
} else {
|
|
63
|
-
backdropAnim
|
|
64
|
-
scaleAnim
|
|
65
|
-
opacityAnim
|
|
66
|
-
translateYAnim
|
|
63
|
+
setNativeValue(backdropAnim, 0);
|
|
64
|
+
setNativeValue(scaleAnim, 0.9);
|
|
65
|
+
setNativeValue(opacityAnim, 0);
|
|
66
|
+
setNativeValue(translateYAnim, screenHeight);
|
|
67
67
|
}
|
|
68
68
|
}, [visible, presentation, duration, backdropAnim, scaleAnim, opacityAnim, translateYAnim, screenHeight, theme.motion.spring.gentle.damping, theme.motion.spring.gentle.stiffness, theme.motion.spring.gentle.mass]);
|
|
69
69
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
|
|
4
4
|
import { Animated, Easing, Pressable, StyleSheet, Text, TextInput, View } from 'react-native';
|
|
5
|
-
import { fontFor, useTheme, createAnimatedValue } from "../../theme/index.js";
|
|
5
|
+
import { fontFor, useTheme, createAnimatedValue, setNativeValue } from "../../theme/index.js";
|
|
6
6
|
import { triggerHaptic } from "../../utils/index.js";
|
|
7
7
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
8
8
|
const sizeMap = {
|
|
@@ -84,7 +84,7 @@ const OTPInput = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
84
84
|
const isFirstRun = previousErrorRef.current === null;
|
|
85
85
|
if (!isFirstRun && hasError && !previousErrorRef.current) {
|
|
86
86
|
triggerHaptic('notificationError');
|
|
87
|
-
shake
|
|
87
|
+
setNativeValue(shake, 0);
|
|
88
88
|
Animated.sequence([Animated.timing(shake, {
|
|
89
89
|
toValue: 1,
|
|
90
90
|
duration: 75,
|
|
@@ -170,16 +170,27 @@ const OTPInput = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
170
170
|
}
|
|
171
171
|
}, [length, onChange, onComplete, value]);
|
|
172
172
|
const handleChangeText = useCallback((index, raw) => {
|
|
173
|
-
|
|
173
|
+
// Strip the ZWSP placeholder (used so iOS fires onKeyPress/Backspace on otherwise-empty cells).
|
|
174
|
+
const stripped = raw.replace(/\u200B/g, '');
|
|
175
|
+
const sanitized = sanitizeChar(stripped, keyboardType);
|
|
174
176
|
if (!sanitized) {
|
|
175
|
-
//
|
|
177
|
+
// Cell was cleared (delete / cut). Clear this cell and step focus back.
|
|
176
178
|
const chars = cells.slice();
|
|
179
|
+
const wasFilled = (chars[index] ?? '').length > 0;
|
|
177
180
|
chars[index] = '';
|
|
178
181
|
updateValue(chars.join('').slice(0, length));
|
|
182
|
+
if (!wasFilled && index > 0) {
|
|
183
|
+
// Empty cell + backspace → also clear and focus the previous cell.
|
|
184
|
+
const prev = cells.slice();
|
|
185
|
+
prev[index - 1] = '';
|
|
186
|
+
updateValue(prev.join(''));
|
|
187
|
+
focusCell(index - 1);
|
|
188
|
+
}
|
|
179
189
|
return;
|
|
180
190
|
}
|
|
181
191
|
|
|
182
192
|
// Fill cells from current index onward (handles paste of multi-char text).
|
|
193
|
+
// For single-character typing, this overwrites the current cell and advances.
|
|
183
194
|
const chars = cells.slice();
|
|
184
195
|
let writeIndex = index;
|
|
185
196
|
for (let i = 0; i < sanitized.length && writeIndex < length; i += 1) {
|
|
@@ -196,7 +207,6 @@ const OTPInput = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
196
207
|
// Move focus to the next empty cell or last cell.
|
|
197
208
|
const nextFocus = Math.min(writeIndex, length - 1);
|
|
198
209
|
if (writeIndex >= length) {
|
|
199
|
-
// All filled — blur last cell.
|
|
200
210
|
inputsRef.current[length - 1]?.blur();
|
|
201
211
|
} else {
|
|
202
212
|
focusCell(nextFocus);
|
|
@@ -205,9 +215,12 @@ const OTPInput = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
205
215
|
const handleKeyPress = useCallback((index, e) => {
|
|
206
216
|
const key = e.nativeEvent.key;
|
|
207
217
|
if (key !== 'Backspace') return;
|
|
218
|
+
// Backspace on a non-empty cell — clear it. Backspace on an empty cell —
|
|
219
|
+
// step back and clear the previous cell. handleChangeText also covers the
|
|
220
|
+
// empty-cell case via the ZWSP placeholder, so this branch only matters
|
|
221
|
+
// when the platform fires onKeyPress without firing onChangeText.
|
|
208
222
|
const current = cells[index] ?? '';
|
|
209
223
|
if (current.length === 0) {
|
|
210
|
-
// Move back, clear previous cell.
|
|
211
224
|
if (index > 0) {
|
|
212
225
|
const chars = cells.slice();
|
|
213
226
|
chars[index - 1] = '';
|
|
@@ -283,8 +296,11 @@ const OTPInput = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
283
296
|
children: [/*#__PURE__*/_jsx(TextInput, {
|
|
284
297
|
ref: node => {
|
|
285
298
|
inputsRef.current[index] = node;
|
|
286
|
-
}
|
|
287
|
-
|
|
299
|
+
}
|
|
300
|
+
// Always render at least the ZWSP placeholder so iOS keeps
|
|
301
|
+
// firing onChangeText/onKeyPress for Backspace on empty cells.
|
|
302
|
+
,
|
|
303
|
+
value: (secure && isFilled ? '' : char) || '\u200B',
|
|
288
304
|
onChangeText: t => handleChangeText(index, t),
|
|
289
305
|
onKeyPress: e => handleKeyPress(index, e),
|
|
290
306
|
onFocus: () => handleFocus(index),
|
|
@@ -292,8 +308,12 @@ const OTPInput = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
292
308
|
keyboardType: keyboardType,
|
|
293
309
|
editable: !disabled,
|
|
294
310
|
selectTextOnFocus: true,
|
|
295
|
-
caretHidden: isFilled
|
|
296
|
-
|
|
311
|
+
caretHidden: isFilled
|
|
312
|
+
// Only the first cell accepts paste-like multi-char input
|
|
313
|
+
// (e.g., when SMS autofill or clipboard delivers the full code);
|
|
314
|
+
// every other cell is single-char so typing always overwrites.
|
|
315
|
+
,
|
|
316
|
+
maxLength: index === 0 ? length : 2,
|
|
297
317
|
textContentType: index === 0 ? 'oneTimeCode' : 'none',
|
|
298
318
|
autoComplete: index === 0 ? 'sms-otp' : 'off',
|
|
299
319
|
importantForAutofill: index === 0 ? 'yes' : 'no',
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import React, { forwardRef, useEffect, useMemo, useRef } from 'react';
|
|
4
4
|
import { Animated, Easing, StyleSheet, View } from 'react-native';
|
|
5
|
-
import { useTheme, createAnimatedValue } from "../../theme/index.js";
|
|
5
|
+
import { useTheme, createAnimatedValue, setNativeValue } from "../../theme/index.js";
|
|
6
6
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
7
7
|
const toneColor = (theme, tone) => {
|
|
8
8
|
switch (tone) {
|
|
@@ -62,7 +62,7 @@ const ProgressBar = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
62
62
|
}, [animated, clamped, fillAnim, isIndeterminate, theme]);
|
|
63
63
|
useEffect(() => {
|
|
64
64
|
if (!isIndeterminate) return;
|
|
65
|
-
loopAnim
|
|
65
|
+
setNativeValue(loopAnim, 0);
|
|
66
66
|
const animation = Animated.loop(Animated.timing(loopAnim, {
|
|
67
67
|
toValue: 1,
|
|
68
68
|
duration: 1500,
|