@mpxjs/webpack-plugin 2.10.4-beta.19-input → 2.10.4-beta.19-input1
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/runtime/components/react/dist/getInnerListeners.js +22 -36
- package/lib/runtime/components/react/dist/mpx-button.jsx +2 -7
- package/lib/runtime/components/react/dist/mpx-canvas/Image.js +4 -2
- package/lib/runtime/components/react/dist/mpx-canvas/index.jsx +17 -20
- package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +2 -7
- package/lib/runtime/components/react/dist/mpx-checkbox.jsx +2 -7
- package/lib/runtime/components/react/dist/mpx-icon/index.jsx +2 -7
- package/lib/runtime/components/react/dist/mpx-image.jsx +20 -33
- package/lib/runtime/components/react/dist/mpx-input.jsx +9 -14
- package/lib/runtime/components/react/dist/mpx-label.jsx +2 -7
- package/lib/runtime/components/react/dist/mpx-movable-area.jsx +3 -8
- package/lib/runtime/components/react/dist/mpx-movable-view.jsx +79 -205
- package/lib/runtime/components/react/dist/mpx-picker/index.jsx +13 -11
- package/lib/runtime/components/react/dist/mpx-picker-view/index.jsx +7 -8
- package/lib/runtime/components/react/dist/mpx-picker-view-column/index.jsx +11 -29
- package/lib/runtime/components/react/dist/mpx-portal/portal-manager.jsx +5 -3
- package/lib/runtime/components/react/dist/mpx-radio-group.jsx +2 -9
- package/lib/runtime/components/react/dist/mpx-radio.jsx +2 -7
- package/lib/runtime/components/react/dist/mpx-rich-text/index.jsx +2 -10
- package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +51 -104
- package/lib/runtime/components/react/dist/mpx-sticky-header.jsx +1 -3
- package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +9 -11
- package/lib/runtime/components/react/dist/mpx-swiper.jsx +141 -203
- package/lib/runtime/components/react/dist/mpx-switch.jsx +2 -7
- package/lib/runtime/components/react/dist/mpx-text.jsx +2 -7
- package/lib/runtime/components/react/dist/mpx-video.jsx +2 -7
- package/lib/runtime/components/react/dist/mpx-view.jsx +26 -28
- package/lib/runtime/components/react/dist/mpx-web-view.jsx +29 -34
- package/lib/runtime/components/react/dist/useAnimationHooks.js +89 -12
- package/lib/runtime/components/react/dist/utils.jsx +114 -199
- package/package.json +1 -1
- package/lib/runtime/components/react/dist/mpx-async-suspense.jsx +0 -145
- package/lib/runtime/components/react/dist/mpx-progress.jsx +0 -163
- package/lib/runtime/components/react/dist/mpx-slider.jsx +0 -321
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* ✔ out-of-bounds
|
|
5
5
|
* ✔ x
|
|
6
6
|
* ✔ y
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* ✘ damping
|
|
8
|
+
* ✘ friction
|
|
9
9
|
* ✔ disabled
|
|
10
10
|
* ✘ scale
|
|
11
11
|
* ✘ scale-min
|
|
@@ -22,98 +22,10 @@ import { StyleSheet } from 'react-native';
|
|
|
22
22
|
import useInnerProps, { getCustomEvent } from './getInnerListeners';
|
|
23
23
|
import useNodesRef from './useNodesRef';
|
|
24
24
|
import { MovableAreaContext } from './context';
|
|
25
|
-
import { useTransformStyle, splitProps, splitStyle, HIDDEN_STYLE, wrapChildren, flatGesture, extendObject, omit, useNavigation
|
|
25
|
+
import { useTransformStyle, splitProps, splitStyle, HIDDEN_STYLE, wrapChildren, flatGesture, extendObject, omit, useNavigation } from './utils';
|
|
26
26
|
import { GestureDetector, Gesture } from 'react-native-gesture-handler';
|
|
27
|
-
import Animated, { useSharedValue, useAnimatedStyle, runOnJS, runOnUI,
|
|
27
|
+
import Animated, { useSharedValue, useAnimatedStyle, withDecay, runOnJS, runOnUI, useAnimatedReaction, withSpring } from 'react-native-reanimated';
|
|
28
28
|
import { collectDataset, noop } from '@mpxjs/utils';
|
|
29
|
-
// 超出边界处理函数,参考微信小程序的超出边界衰减效果
|
|
30
|
-
const applyBoundaryDecline = (newValue, range) => {
|
|
31
|
-
'worklet';
|
|
32
|
-
const decline = (distance) => {
|
|
33
|
-
'worklet';
|
|
34
|
-
return Math.sqrt(Math.abs(distance));
|
|
35
|
-
};
|
|
36
|
-
if (newValue < range[0]) {
|
|
37
|
-
const overDistance = range[0] - newValue;
|
|
38
|
-
return range[0] - decline(overDistance);
|
|
39
|
-
}
|
|
40
|
-
else if (newValue > range[1]) {
|
|
41
|
-
const overDistance = newValue - range[1];
|
|
42
|
-
return range[1] + decline(overDistance);
|
|
43
|
-
}
|
|
44
|
-
return newValue;
|
|
45
|
-
};
|
|
46
|
-
// 参考微信小程序的弹簧阻尼系统实现
|
|
47
|
-
const withWechatSpring = (toValue, dampingParam = 20, callback) => {
|
|
48
|
-
'worklet';
|
|
49
|
-
// 弹簧参数计算
|
|
50
|
-
const m = 1; // 质量
|
|
51
|
-
const k = 9 * Math.pow(dampingParam, 2) / 40; // 弹簧系数
|
|
52
|
-
const c = dampingParam; // 阻尼系数
|
|
53
|
-
// 判别式:r = c² - 4mk
|
|
54
|
-
const discriminant = c * c - 4 * m * k;
|
|
55
|
-
// 计算动画持续时间和缓动函数
|
|
56
|
-
let duration;
|
|
57
|
-
let easingFunction;
|
|
58
|
-
if (Math.abs(discriminant) < 0.01) {
|
|
59
|
-
// 临界阻尼 (discriminant ≈ 0)
|
|
60
|
-
// 使用cubic-out模拟临界阻尼的平滑过渡
|
|
61
|
-
duration = Math.max(350, Math.min(800, 2000 / dampingParam));
|
|
62
|
-
easingFunction = Easing.out(Easing.cubic);
|
|
63
|
-
}
|
|
64
|
-
else if (discriminant > 0) {
|
|
65
|
-
// 过阻尼 (discriminant > 0)
|
|
66
|
-
// 使用指数缓动模拟过阻尼的缓慢收敛
|
|
67
|
-
duration = Math.max(450, Math.min(1000, 2500 / dampingParam));
|
|
68
|
-
easingFunction = Easing.out(Easing.exp);
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
// 欠阻尼 (discriminant < 0) - 会产生振荡
|
|
72
|
-
// 计算振荡频率和衰减率
|
|
73
|
-
const dampingRatio = c / (2 * Math.sqrt(m * k)); // 阻尼比
|
|
74
|
-
// 根据阻尼比调整动画参数
|
|
75
|
-
if (dampingRatio < 0.7) {
|
|
76
|
-
// 明显振荡
|
|
77
|
-
duration = Math.max(600, Math.min(1200, 3000 / dampingParam));
|
|
78
|
-
// 创建带振荡的贝塞尔曲线
|
|
79
|
-
easingFunction = Easing.bezier(0.175, 0.885, 0.32, 1.275);
|
|
80
|
-
}
|
|
81
|
-
else {
|
|
82
|
-
// 轻微振荡
|
|
83
|
-
duration = Math.max(400, Math.min(800, 2000 / dampingParam));
|
|
84
|
-
easingFunction = Easing.bezier(0.25, 0.46, 0.45, 0.94);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
return withTiming(toValue, {
|
|
88
|
-
duration,
|
|
89
|
-
easing: easingFunction
|
|
90
|
-
}, callback);
|
|
91
|
-
};
|
|
92
|
-
// 参考微信小程序friction的惯性动画
|
|
93
|
-
const withWechatDecay = (velocity, currentPosition, clampRange, frictionValue = 2, callback) => {
|
|
94
|
-
'worklet';
|
|
95
|
-
// 微信小程序friction算法: delta = -1.5 * v² / a, 其中 a = -f * v / |v|
|
|
96
|
-
// 如果friction小于等于0,设置为默认值2
|
|
97
|
-
const validFriction = frictionValue <= 0 ? 2 : frictionValue;
|
|
98
|
-
const f = 1000 * validFriction;
|
|
99
|
-
const acceleration = velocity !== 0 ? -f * velocity / Math.abs(velocity) : 0;
|
|
100
|
-
const delta = acceleration !== 0 ? (-1.5 * velocity * velocity) / acceleration : 0;
|
|
101
|
-
let finalPosition = currentPosition + delta;
|
|
102
|
-
// 边界限制
|
|
103
|
-
if (finalPosition < clampRange[0]) {
|
|
104
|
-
finalPosition = clampRange[0];
|
|
105
|
-
}
|
|
106
|
-
else if (finalPosition > clampRange[1]) {
|
|
107
|
-
finalPosition = clampRange[1];
|
|
108
|
-
}
|
|
109
|
-
// 计算动画时长
|
|
110
|
-
const distance = Math.abs(finalPosition - currentPosition);
|
|
111
|
-
const duration = Math.min(1500, Math.max(200, distance * 8));
|
|
112
|
-
return withTiming(finalPosition, {
|
|
113
|
-
duration,
|
|
114
|
-
easing: Easing.out(Easing.cubic)
|
|
115
|
-
}, callback);
|
|
116
|
-
};
|
|
117
29
|
const styles = StyleSheet.create({
|
|
118
30
|
container: {
|
|
119
31
|
position: 'absolute',
|
|
@@ -129,7 +41,7 @@ const _MovableView = forwardRef((movableViewProps, ref) => {
|
|
|
129
41
|
const hasLayoutRef = useRef(false);
|
|
130
42
|
const propsRef = useRef({});
|
|
131
43
|
propsRef.current = (props || {});
|
|
132
|
-
const { x = 0, y = 0, inertia = false, disabled = false, animation = true,
|
|
44
|
+
const { x = 0, y = 0, inertia = false, disabled = false, animation = true, 'out-of-bounds': outOfBounds = false, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, direction = 'none', 'simultaneous-handlers': originSimultaneousHandlers = [], 'wait-for': waitFor = [], style = {}, bindtouchstart, catchtouchstart, bindhtouchmove, bindvtouchmove, bindtouchmove, catchhtouchmove, catchvtouchmove, catchtouchmove, bindtouchend, catchtouchend } = props;
|
|
133
45
|
const { hasSelfPercent, normalStyle, hasVarDec, varContextRef, setWidth, setHeight } = useTransformStyle(Object.assign({}, style, styles.container), { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
|
|
134
46
|
const navigation = useNavigation();
|
|
135
47
|
const prevSimultaneousHandlersRef = useRef(originSimultaneousHandlers || []);
|
|
@@ -149,8 +61,6 @@ const _MovableView = forwardRef((movableViewProps, ref) => {
|
|
|
149
61
|
const yInertialMotion = useSharedValue(false);
|
|
150
62
|
const isFirstTouch = useSharedValue(true);
|
|
151
63
|
const touchEvent = useSharedValue('');
|
|
152
|
-
const initialViewPosition = useSharedValue({ x: x || 0, y: y || 0 });
|
|
153
|
-
const lastChangeTime = useSharedValue(0);
|
|
154
64
|
const MovableAreaLayout = useContext(MovableAreaContext);
|
|
155
65
|
const simultaneousHandlers = flatGesture(originSimultaneousHandlers);
|
|
156
66
|
const waitForHandlers = flatGesture(waitFor);
|
|
@@ -194,21 +104,25 @@ const _MovableView = forwardRef((movableViewProps, ref) => {
|
|
|
194
104
|
const { x: newX, y: newY } = checkBoundaryPosition({ positionX: Number(x), positionY: Number(y) });
|
|
195
105
|
if (direction === 'horizontal' || direction === 'all') {
|
|
196
106
|
offsetX.value = animation
|
|
197
|
-
?
|
|
107
|
+
? withSpring(newX, {
|
|
108
|
+
duration: 1500,
|
|
109
|
+
dampingRatio: 0.8
|
|
110
|
+
})
|
|
198
111
|
: newX;
|
|
199
112
|
}
|
|
200
113
|
if (direction === 'vertical' || direction === 'all') {
|
|
201
114
|
offsetY.value = animation
|
|
202
|
-
?
|
|
115
|
+
? withSpring(newY, {
|
|
116
|
+
duration: 1500,
|
|
117
|
+
dampingRatio: 0.8
|
|
118
|
+
})
|
|
203
119
|
: newY;
|
|
204
120
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
});
|
|
211
|
-
}
|
|
121
|
+
runOnJS(handleTriggerChange)({
|
|
122
|
+
x: newX,
|
|
123
|
+
y: newY,
|
|
124
|
+
type: 'setData'
|
|
125
|
+
});
|
|
212
126
|
}
|
|
213
127
|
})();
|
|
214
128
|
}, [x, y]);
|
|
@@ -218,6 +132,16 @@ const _MovableView = forwardRef((movableViewProps, ref) => {
|
|
|
218
132
|
resetBoundaryAndCheck({ width, height });
|
|
219
133
|
}
|
|
220
134
|
}, [MovableAreaLayout.height, MovableAreaLayout.width]);
|
|
135
|
+
useAnimatedReaction(() => ({
|
|
136
|
+
offsetX: offsetX.value,
|
|
137
|
+
offsetY: offsetY.value
|
|
138
|
+
}), (currentValue) => {
|
|
139
|
+
const { offsetX, offsetY } = currentValue;
|
|
140
|
+
runOnJS(handleTriggerChange)({
|
|
141
|
+
x: offsetX,
|
|
142
|
+
y: offsetY
|
|
143
|
+
});
|
|
144
|
+
});
|
|
221
145
|
const getTouchSource = useCallback((offsetX, offsetY) => {
|
|
222
146
|
const hasOverBoundary = offsetX < draggableXRange.value[0] || offsetX > draggableXRange.value[1] ||
|
|
223
147
|
offsetY < draggableYRange.value[0] || offsetY > draggableYRange.value[1];
|
|
@@ -306,14 +230,14 @@ const _MovableView = forwardRef((movableViewProps, ref) => {
|
|
|
306
230
|
setHeight(height || 0);
|
|
307
231
|
}
|
|
308
232
|
nodeRef.current?.measure((x, y, width, height) => {
|
|
309
|
-
const {
|
|
233
|
+
const { y: navigationY = 0 } = navigation?.layout || {};
|
|
310
234
|
layoutRef.current = { x, y: y - navigationY, width, height, offsetLeft: 0, offsetTop: 0 };
|
|
311
235
|
resetBoundaryAndCheck({ width, height });
|
|
312
236
|
});
|
|
313
237
|
props.onLayout && props.onLayout(e);
|
|
314
238
|
};
|
|
315
239
|
const extendEvent = useCallback((e, type) => {
|
|
316
|
-
const {
|
|
240
|
+
const { y: navigationY = 0 } = navigation?.layout || {};
|
|
317
241
|
const touchArr = [e.changedTouches, e.allTouches];
|
|
318
242
|
touchArr.forEach(touches => {
|
|
319
243
|
touches && touches.forEach((item) => {
|
|
@@ -335,13 +259,11 @@ const _MovableView = forwardRef((movableViewProps, ref) => {
|
|
|
335
259
|
});
|
|
336
260
|
}, []);
|
|
337
261
|
const triggerStartOnJS = ({ e }) => {
|
|
338
|
-
const { bindtouchstart, catchtouchstart } = propsRef.current;
|
|
339
262
|
extendEvent(e, 'start');
|
|
340
263
|
bindtouchstart && bindtouchstart(e);
|
|
341
264
|
catchtouchstart && catchtouchstart(e);
|
|
342
265
|
};
|
|
343
266
|
const triggerMoveOnJS = ({ e, hasTouchmove, hasCatchTouchmove, touchEvent }) => {
|
|
344
|
-
const { bindhtouchmove, bindvtouchmove, bindtouchmove, catchhtouchmove, catchvtouchmove, catchtouchmove } = propsRef.current;
|
|
345
267
|
extendEvent(e, 'move');
|
|
346
268
|
if (hasTouchmove) {
|
|
347
269
|
if (touchEvent === 'htouchmove') {
|
|
@@ -363,34 +285,17 @@ const _MovableView = forwardRef((movableViewProps, ref) => {
|
|
|
363
285
|
}
|
|
364
286
|
};
|
|
365
287
|
const triggerEndOnJS = ({ e }) => {
|
|
366
|
-
const { bindtouchend, catchtouchend } = propsRef.current;
|
|
367
288
|
extendEvent(e, 'end');
|
|
368
289
|
bindtouchend && bindtouchend(e);
|
|
369
290
|
catchtouchend && catchtouchend(e);
|
|
370
291
|
};
|
|
371
|
-
const runOnJSCallbackRef = useRef({
|
|
372
|
-
handleTriggerChange,
|
|
373
|
-
triggerStartOnJS,
|
|
374
|
-
triggerMoveOnJS,
|
|
375
|
-
triggerEndOnJS
|
|
376
|
-
});
|
|
377
|
-
const runOnJSCallback = useRunOnJSCallback(runOnJSCallbackRef);
|
|
378
|
-
// 节流版本的change事件触发
|
|
379
|
-
const handleTriggerChangeThrottled = useCallback(({ x, y, type }) => {
|
|
380
|
-
'worklet';
|
|
381
|
-
const now = Date.now();
|
|
382
|
-
if (now - lastChangeTime.value >= changeThrottleTime) {
|
|
383
|
-
lastChangeTime.value = now;
|
|
384
|
-
runOnJS(runOnJSCallback)('handleTriggerChange', { x, y, type });
|
|
385
|
-
}
|
|
386
|
-
}, [changeThrottleTime]);
|
|
387
292
|
const gesture = useMemo(() => {
|
|
388
293
|
const handleTriggerMove = (e) => {
|
|
389
294
|
'worklet';
|
|
390
295
|
const hasTouchmove = !!bindhtouchmove || !!bindvtouchmove || !!bindtouchmove;
|
|
391
296
|
const hasCatchTouchmove = !!catchhtouchmove || !!catchvtouchmove || !!catchtouchmove;
|
|
392
297
|
if (hasTouchmove || hasCatchTouchmove) {
|
|
393
|
-
runOnJS(
|
|
298
|
+
runOnJS(triggerMoveOnJS)({
|
|
394
299
|
e,
|
|
395
300
|
touchEvent: touchEvent.value,
|
|
396
301
|
hasTouchmove,
|
|
@@ -408,15 +313,8 @@ const _MovableView = forwardRef((movableViewProps, ref) => {
|
|
|
408
313
|
y: changedTouches.y
|
|
409
314
|
};
|
|
410
315
|
if (bindtouchstart || catchtouchstart) {
|
|
411
|
-
runOnJS(
|
|
316
|
+
runOnJS(triggerStartOnJS)({ e });
|
|
412
317
|
}
|
|
413
|
-
})
|
|
414
|
-
.onStart(() => {
|
|
415
|
-
'worklet';
|
|
416
|
-
initialViewPosition.value = {
|
|
417
|
-
x: offsetX.value,
|
|
418
|
-
y: offsetY.value
|
|
419
|
-
};
|
|
420
318
|
})
|
|
421
319
|
.onTouchesMove((e) => {
|
|
422
320
|
'worklet';
|
|
@@ -427,111 +325,87 @@ const _MovableView = forwardRef((movableViewProps, ref) => {
|
|
|
427
325
|
isFirstTouch.value = false;
|
|
428
326
|
}
|
|
429
327
|
handleTriggerMove(e);
|
|
430
|
-
})
|
|
431
|
-
.onUpdate((e) => {
|
|
432
|
-
'worklet';
|
|
433
328
|
if (disabled)
|
|
434
329
|
return;
|
|
330
|
+
const changeX = changedTouches.x - startPosition.value.x;
|
|
331
|
+
const changeY = changedTouches.y - startPosition.value.y;
|
|
435
332
|
if (direction === 'horizontal' || direction === 'all') {
|
|
436
|
-
const newX =
|
|
333
|
+
const newX = offsetX.value + changeX;
|
|
437
334
|
if (!outOfBounds) {
|
|
438
335
|
const { x } = checkBoundaryPosition({ positionX: newX, positionY: offsetY.value });
|
|
439
336
|
offsetX.value = x;
|
|
440
337
|
}
|
|
441
338
|
else {
|
|
442
|
-
offsetX.value =
|
|
339
|
+
offsetX.value = newX;
|
|
443
340
|
}
|
|
444
341
|
}
|
|
445
342
|
if (direction === 'vertical' || direction === 'all') {
|
|
446
|
-
const newY =
|
|
343
|
+
const newY = offsetY.value + changeY;
|
|
447
344
|
if (!outOfBounds) {
|
|
448
345
|
const { y } = checkBoundaryPosition({ positionX: offsetX.value, positionY: newY });
|
|
449
346
|
offsetY.value = y;
|
|
450
347
|
}
|
|
451
348
|
else {
|
|
452
|
-
offsetY.value =
|
|
349
|
+
offsetY.value = newY;
|
|
453
350
|
}
|
|
454
351
|
}
|
|
455
|
-
if (bindchange) {
|
|
456
|
-
// 使用节流版本减少 runOnJS 调用
|
|
457
|
-
handleTriggerChangeThrottled({
|
|
458
|
-
x: offsetX.value,
|
|
459
|
-
y: offsetY.value
|
|
460
|
-
});
|
|
461
|
-
}
|
|
462
352
|
})
|
|
463
353
|
.onTouchesUp((e) => {
|
|
464
354
|
'worklet';
|
|
465
355
|
isFirstTouch.value = true;
|
|
466
356
|
isMoving.value = false;
|
|
467
357
|
if (bindtouchend || catchtouchend) {
|
|
468
|
-
runOnJS(
|
|
358
|
+
runOnJS(triggerEndOnJS)({ e });
|
|
469
359
|
}
|
|
470
|
-
})
|
|
471
|
-
.onEnd((e) => {
|
|
472
|
-
'worklet';
|
|
473
|
-
isMoving.value = false;
|
|
474
360
|
if (disabled)
|
|
475
361
|
return;
|
|
476
|
-
|
|
477
|
-
if (!inertia && outOfBounds) {
|
|
362
|
+
if (!inertia) {
|
|
478
363
|
const { x, y } = checkBoundaryPosition({ positionX: offsetX.value, positionY: offsetY.value });
|
|
479
|
-
if (x !== offsetX.value
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
:
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
offsetY.value = animation
|
|
487
|
-
? withWechatSpring(y, damping)
|
|
488
|
-
: y;
|
|
489
|
-
}
|
|
490
|
-
if (bindchange) {
|
|
491
|
-
runOnJS(runOnJSCallback)('handleTriggerChange', {
|
|
492
|
-
x,
|
|
493
|
-
y
|
|
494
|
-
});
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
else if (inertia) {
|
|
499
|
-
// 惯性处理 - 使用微信小程序friction算法
|
|
500
|
-
if (direction === 'horizontal' || direction === 'all') {
|
|
501
|
-
xInertialMotion.value = true;
|
|
502
|
-
offsetX.value = withWechatDecay(e.velocityX / 10, offsetX.value, draggableXRange.value, friction, () => {
|
|
503
|
-
xInertialMotion.value = false;
|
|
504
|
-
if (bindchange) {
|
|
505
|
-
runOnJS(runOnJSCallback)('handleTriggerChange', {
|
|
506
|
-
x: offsetX.value,
|
|
507
|
-
y: offsetY.value
|
|
508
|
-
});
|
|
509
|
-
}
|
|
510
|
-
});
|
|
364
|
+
if (x !== offsetX.value) {
|
|
365
|
+
offsetX.value = animation
|
|
366
|
+
? withSpring(x, {
|
|
367
|
+
duration: 1500,
|
|
368
|
+
dampingRatio: 0.8
|
|
369
|
+
})
|
|
370
|
+
: x;
|
|
511
371
|
}
|
|
512
|
-
if (
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
y: offsetY.value
|
|
520
|
-
});
|
|
521
|
-
}
|
|
522
|
-
});
|
|
372
|
+
if (y !== offsetY.value) {
|
|
373
|
+
offsetY.value = animation
|
|
374
|
+
? withSpring(y, {
|
|
375
|
+
duration: 1500,
|
|
376
|
+
dampingRatio: 0.8
|
|
377
|
+
})
|
|
378
|
+
: y;
|
|
523
379
|
}
|
|
524
380
|
}
|
|
525
381
|
})
|
|
526
|
-
.
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
382
|
+
.onFinalize((e) => {
|
|
383
|
+
'worklet';
|
|
384
|
+
isMoving.value = false;
|
|
385
|
+
if (!inertia || disabled || !animation)
|
|
386
|
+
return;
|
|
387
|
+
if (direction === 'horizontal' || direction === 'all') {
|
|
388
|
+
xInertialMotion.value = true;
|
|
389
|
+
offsetX.value = withDecay({
|
|
390
|
+
velocity: e.velocityX / 10,
|
|
391
|
+
rubberBandEffect: outOfBounds,
|
|
392
|
+
clamp: draggableXRange.value
|
|
393
|
+
}, () => {
|
|
394
|
+
xInertialMotion.value = false;
|
|
395
|
+
});
|
|
530
396
|
}
|
|
531
|
-
|
|
532
|
-
|
|
397
|
+
if (direction === 'vertical' || direction === 'all') {
|
|
398
|
+
yInertialMotion.value = true;
|
|
399
|
+
offsetY.value = withDecay({
|
|
400
|
+
velocity: e.velocityY / 10,
|
|
401
|
+
rubberBandEffect: outOfBounds,
|
|
402
|
+
clamp: draggableYRange.value
|
|
403
|
+
}, () => {
|
|
404
|
+
yInertialMotion.value = false;
|
|
405
|
+
});
|
|
533
406
|
}
|
|
534
|
-
}
|
|
407
|
+
})
|
|
408
|
+
.withRef(movableGestureRef);
|
|
535
409
|
if (simultaneousHandlers && simultaneousHandlers.length) {
|
|
536
410
|
gesturePan.simultaneousWithExternalGesture(...simultaneousHandlers);
|
|
537
411
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { forwardRef, useRef, useContext, useEffect
|
|
1
|
+
import React, { forwardRef, useRef, useContext, useEffect } from 'react';
|
|
2
2
|
import { StyleSheet, Text, TouchableWithoutFeedback, View } from 'react-native';
|
|
3
3
|
import { warn } from '@mpxjs/utils';
|
|
4
4
|
import PickerSelector from './selector';
|
|
@@ -9,7 +9,7 @@ import PickerRegion from './region';
|
|
|
9
9
|
import { FormContext, RouteContext } from '../context';
|
|
10
10
|
import useNodesRef from '../useNodesRef';
|
|
11
11
|
import useInnerProps, { getCustomEvent } from '../getInnerListeners';
|
|
12
|
-
import { extendObject
|
|
12
|
+
import { extendObject } from '../utils';
|
|
13
13
|
import { createPopupManager } from '../mpx-popup';
|
|
14
14
|
/**
|
|
15
15
|
* ✔ mode
|
|
@@ -109,18 +109,17 @@ const Picker = forwardRef((props, ref) => {
|
|
|
109
109
|
const buttonText = buttonTextMap[global.__mpx?.i18n?.locale || 'zh-CN'];
|
|
110
110
|
const pickerValue = useRef(value);
|
|
111
111
|
pickerValue.current = Array.isArray(value) ? value.slice() : value;
|
|
112
|
+
const innerLayout = useRef({});
|
|
112
113
|
const nodeRef = useRef(null);
|
|
113
114
|
const pickerRef = useRef(null);
|
|
114
115
|
const { open, show, hide, remove } = useRef(createPopupManager()).current;
|
|
115
116
|
useNodesRef(props, ref, nodeRef);
|
|
116
|
-
const { layoutRef, layoutProps } = useLayout({
|
|
117
|
-
props,
|
|
118
|
-
hasSelfPercent: false,
|
|
119
|
-
nodeRef
|
|
120
|
-
});
|
|
121
117
|
const innerProps = useInnerProps(extendObject({}, props, {
|
|
122
118
|
ref: nodeRef
|
|
123
|
-
}
|
|
119
|
+
}), [], { layoutRef: innerLayout });
|
|
120
|
+
const getInnerLayout = (layout) => {
|
|
121
|
+
innerLayout.current = layout.current;
|
|
122
|
+
};
|
|
124
123
|
useEffect(() => {
|
|
125
124
|
if (range && pickerRef.current && mode === "multiSelector" /* PickerMode.MULTI_SELECTOR */) {
|
|
126
125
|
pickerRef.current.updateRange?.(range);
|
|
@@ -163,7 +162,7 @@ const Picker = forwardRef((props, ref) => {
|
|
|
163
162
|
if (mode !== "multiSelector" /* PickerMode.MULTI_SELECTOR */) {
|
|
164
163
|
return;
|
|
165
164
|
}
|
|
166
|
-
const eventData = getCustomEvent('columnchange', {}, { detail: { column: columnIndex, value }, layoutRef });
|
|
165
|
+
const eventData = getCustomEvent('columnchange', {}, { detail: { column: columnIndex, value }, layoutRef: innerLayout });
|
|
167
166
|
props.bindcolumnchange?.(eventData);
|
|
168
167
|
};
|
|
169
168
|
const onCancel = () => {
|
|
@@ -171,7 +170,7 @@ const Picker = forwardRef((props, ref) => {
|
|
|
171
170
|
hide();
|
|
172
171
|
};
|
|
173
172
|
const onConfirm = () => {
|
|
174
|
-
const eventData = getCustomEvent('change', {}, { detail: { value: pickerValue.current }, layoutRef });
|
|
173
|
+
const eventData = getCustomEvent('change', {}, { detail: { value: pickerValue.current }, layoutRef: innerLayout });
|
|
175
174
|
bindchange?.(eventData);
|
|
176
175
|
hide();
|
|
177
176
|
};
|
|
@@ -180,6 +179,7 @@ const Picker = forwardRef((props, ref) => {
|
|
|
180
179
|
children,
|
|
181
180
|
bindchange: onChange,
|
|
182
181
|
bindcolumnchange: onColumnChange,
|
|
182
|
+
getInnerLayout,
|
|
183
183
|
getRange: () => range
|
|
184
184
|
});
|
|
185
185
|
const renderPickerContent = () => {
|
|
@@ -215,7 +215,9 @@ const Picker = forwardRef((props, ref) => {
|
|
|
215
215
|
remove();
|
|
216
216
|
};
|
|
217
217
|
}, []);
|
|
218
|
-
return
|
|
218
|
+
return (<TouchableWithoutFeedback onPress={show}>
|
|
219
|
+
{children}
|
|
220
|
+
</TouchableWithoutFeedback>);
|
|
219
221
|
});
|
|
220
222
|
Picker.displayName = 'MpxPicker';
|
|
221
223
|
export default Picker;
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { View } from 'react-native';
|
|
2
|
-
import React, {
|
|
2
|
+
import React, { forwardRef, useRef } from 'react';
|
|
3
3
|
import useInnerProps, { getCustomEvent } from '../getInnerListeners';
|
|
4
4
|
import useNodesRef from '../useNodesRef';
|
|
5
5
|
import { useLayout, splitProps, splitStyle, wrapChildren, useTransformStyle, extendObject } from '../utils';
|
|
6
6
|
import { PickerViewStyleContext } from './pickerVIewContext';
|
|
7
|
-
import Portal from '../mpx-portal';
|
|
8
7
|
const styles = {
|
|
9
8
|
wrapper: {
|
|
10
9
|
display: 'flex',
|
|
@@ -24,7 +23,7 @@ const _PickerView = forwardRef((props, ref) => {
|
|
|
24
23
|
const activeValueRef = useRef(value);
|
|
25
24
|
activeValueRef.current = value.slice();
|
|
26
25
|
const snapActiveValueRef = useRef(null);
|
|
27
|
-
const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, setWidth, setHeight
|
|
26
|
+
const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, setWidth, setHeight } = useTransformStyle(style, { enableVar, externalVarContext });
|
|
28
27
|
useNodesRef(props, ref, nodeRef, {
|
|
29
28
|
style: normalStyle
|
|
30
29
|
});
|
|
@@ -115,11 +114,11 @@ const _PickerView = forwardRef((props, ref) => {
|
|
|
115
114
|
onInitialChange(isInvalid, validValue);
|
|
116
115
|
return renderColumns;
|
|
117
116
|
};
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
117
|
+
return (<PickerViewStyleContext.Provider value={textStyle}>
|
|
118
|
+
<View {...innerProps}>
|
|
119
|
+
<View style={[styles.wrapper]}>{renderPickerColumns()}</View>
|
|
120
|
+
</View>
|
|
121
|
+
</PickerViewStyleContext.Provider>);
|
|
123
122
|
});
|
|
124
123
|
_PickerView.displayName = 'MpxPickerView';
|
|
125
124
|
export default _PickerView;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import React, { forwardRef, useRef, useState, useMemo, useEffect, useCallback
|
|
1
|
+
import React, { forwardRef, useRef, useState, useMemo, useEffect, useCallback } from 'react';
|
|
2
2
|
import { StyleSheet, View } from 'react-native';
|
|
3
3
|
import Reanimated, { useAnimatedRef, useScrollViewOffset } from 'react-native-reanimated';
|
|
4
|
-
import { useTransformStyle, splitStyle, splitProps, useLayout, usePrevious, isAndroid, isIOS, isHarmony
|
|
4
|
+
import { useTransformStyle, splitStyle, splitProps, useLayout, usePrevious, isAndroid, isIOS, isHarmony } from '../utils';
|
|
5
5
|
import useNodesRef from '../useNodesRef';
|
|
6
6
|
import PickerIndicator from './pickerViewIndicator';
|
|
7
7
|
import PickerMask from './pickerViewMask';
|
|
@@ -157,8 +157,8 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
157
157
|
}, [itemRawH, maxIndex, snapToOffsets, onMomentumScrollEnd, resetScrollPosition]);
|
|
158
158
|
const onScroll = useCallback((e) => {
|
|
159
159
|
// 全局注册的振动触感 hook
|
|
160
|
-
const
|
|
161
|
-
if (typeof
|
|
160
|
+
const pickerVibrate = global.__mpx?.config?.rnConfig?.pickerVibrate;
|
|
161
|
+
if (typeof pickerVibrate !== 'function') {
|
|
162
162
|
return;
|
|
163
163
|
}
|
|
164
164
|
const { y } = e.nativeEvent.contentOffset;
|
|
@@ -172,7 +172,7 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
172
172
|
y: currentId * itemRawH
|
|
173
173
|
};
|
|
174
174
|
// vibrateShort({ type: 'selection' })
|
|
175
|
-
|
|
175
|
+
pickerVibrate();
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
}
|
|
@@ -220,28 +220,11 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
220
220
|
return (<MpxPickerVIewColumnItem key={index} item={item} index={index} itemHeight={itemHeight} textStyle={textStyle} textProps={textProps} visibleCount={visibleCount} onItemLayout={onItemLayout}/>);
|
|
221
221
|
});
|
|
222
222
|
const renderScollView = () => {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
removeClippedSubviews: false,
|
|
229
|
-
showsVerticalScrollIndicator: false,
|
|
230
|
-
showsHorizontalScrollIndicator: false,
|
|
231
|
-
scrollEventThrottle: 16,
|
|
232
|
-
style: styles.scrollView,
|
|
233
|
-
decelerationRate: 'fast',
|
|
234
|
-
snapToOffsets: snapToOffsets,
|
|
235
|
-
onTouchEnd: onClickOnceItem,
|
|
236
|
-
onScroll,
|
|
237
|
-
onScrollBeginDrag,
|
|
238
|
-
onScrollEndDrag,
|
|
239
|
-
onMomentumScrollBegin,
|
|
240
|
-
onMomentumScrollEnd,
|
|
241
|
-
onContentSizeChange,
|
|
242
|
-
contentContainerStyle
|
|
243
|
-
});
|
|
244
|
-
return createElement(PickerViewColumnAnimationContext.Provider, { value: offsetYShared }, createElement(Reanimated.ScrollView, innerProps, renderInnerchild()));
|
|
223
|
+
return (<PickerViewColumnAnimationContext.Provider value={offsetYShared}>
|
|
224
|
+
<Reanimated.ScrollView ref={scrollViewRef} bounces={true} horizontal={false} nestedScrollEnabled={true} removeClippedSubviews={false} showsVerticalScrollIndicator={false} showsHorizontalScrollIndicator={false} scrollEventThrottle={16} {...layoutProps} onTouchEnd={onClickOnceItem} style={[{ width: '100%' }]} decelerationRate="fast" snapToOffsets={snapToOffsets} onScroll={onScroll} onScrollBeginDrag={onScrollBeginDrag} onScrollEndDrag={onScrollEndDrag} onMomentumScrollBegin={onMomentumScrollBegin} onMomentumScrollEnd={onMomentumScrollEnd} onContentSizeChange={onContentSizeChange} contentContainerStyle={contentContainerStyle}>
|
|
225
|
+
{renderInnerchild()}
|
|
226
|
+
</Reanimated.ScrollView>
|
|
227
|
+
</PickerViewColumnAnimationContext.Provider>);
|
|
245
228
|
};
|
|
246
229
|
const renderIndicator = () => (<PickerIndicator itemHeight={itemHeight} indicatorItemStyle={pickerIndicatorStyle}/>);
|
|
247
230
|
const renderMask = () => (<PickerMask itemHeight={itemHeight} maskContainerStyle={pickerMaskStyle}/>);
|
|
@@ -252,8 +235,7 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
252
235
|
</View>);
|
|
253
236
|
});
|
|
254
237
|
const styles = StyleSheet.create({
|
|
255
|
-
wrapper: { display: 'flex', flex: 1 }
|
|
256
|
-
scrollView: { width: '100%' }
|
|
238
|
+
wrapper: { display: 'flex', flex: 1 }
|
|
257
239
|
});
|
|
258
240
|
_PickerViewColumn.displayName = 'MpxPickerViewColumn';
|
|
259
241
|
export default _PickerViewColumn;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { useState, useCallback, forwardRef, useImperativeHandle
|
|
1
|
+
import { useState, useCallback, forwardRef, useImperativeHandle } from 'react';
|
|
2
|
+
import { View, StyleSheet } from 'react-native';
|
|
2
3
|
const _PortalManager = forwardRef((props, ref) => {
|
|
3
4
|
const [state, setState] = useState({
|
|
4
5
|
portals: []
|
|
@@ -30,9 +31,10 @@ const _PortalManager = forwardRef((props, ref) => {
|
|
|
30
31
|
portals: state.portals
|
|
31
32
|
}));
|
|
32
33
|
return (<>
|
|
33
|
-
{state.portals.map(({ key, children }) => (<
|
|
34
|
+
{state.portals.map(({ key, children }, i) => (<View key={key} collapsable={false} // Need collapsable=false here to clip the elevations
|
|
35
|
+
style={[StyleSheet.absoluteFill, { zIndex: 1000 + i, pointerEvents: 'box-none' }]}>
|
|
34
36
|
{children}
|
|
35
|
-
</
|
|
37
|
+
</View>))}
|
|
36
38
|
</>);
|
|
37
39
|
});
|
|
38
40
|
export default _PortalManager;
|
|
@@ -8,7 +8,6 @@ import { FormContext, RadioGroupContext } from './context';
|
|
|
8
8
|
import useInnerProps, { getCustomEvent } from './getInnerListeners';
|
|
9
9
|
import useNodesRef from './useNodesRef';
|
|
10
10
|
import { useLayout, useTransformStyle, wrapChildren, extendObject } from './utils';
|
|
11
|
-
import Portal from './mpx-portal';
|
|
12
11
|
const radioGroup = forwardRef((props, ref) => {
|
|
13
12
|
const { style = {}, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight } = props;
|
|
14
13
|
const propsRef = useRef({});
|
|
@@ -24,7 +23,7 @@ const radioGroup = forwardRef((props, ref) => {
|
|
|
24
23
|
flexWrap: 'wrap'
|
|
25
24
|
};
|
|
26
25
|
const styleObj = extendObject({}, defaultStyle, style);
|
|
27
|
-
const {
|
|
26
|
+
const { hasSelfPercent, normalStyle, hasVarDec, varContextRef, setWidth, setHeight } = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
|
|
28
27
|
const nodeRef = useRef(null);
|
|
29
28
|
useNodesRef(props, ref, nodeRef, { style: normalStyle });
|
|
30
29
|
const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef });
|
|
@@ -78,16 +77,10 @@ const radioGroup = forwardRef((props, ref) => {
|
|
|
78
77
|
}), ['name'], {
|
|
79
78
|
layoutRef
|
|
80
79
|
});
|
|
81
|
-
|
|
82
|
-
value: contextValue
|
|
83
|
-
}, wrapChildren(props, {
|
|
80
|
+
return createElement(View, innerProps, createElement(RadioGroupContext.Provider, { value: contextValue }, wrapChildren(props, {
|
|
84
81
|
hasVarDec,
|
|
85
82
|
varContext: varContextRef.current
|
|
86
83
|
})));
|
|
87
|
-
if (hasPositionFixed) {
|
|
88
|
-
return createElement(Portal, null, finalComponent);
|
|
89
|
-
}
|
|
90
|
-
return finalComponent;
|
|
91
84
|
});
|
|
92
85
|
radioGroup.displayName = 'MpxRadioGroup';
|
|
93
86
|
export default radioGroup;
|