@mpxjs/webpack-plugin 2.9.65 → 2.9.67

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/lib/dependencies/RecordGlobalComponentsDependency.js +11 -12
  2. package/lib/dependencies/RecordRuntimeInfoDependency.js +1 -1
  3. package/lib/index.js +28 -8
  4. package/lib/json-compiler/index.js +2 -11
  5. package/lib/loader.js +24 -45
  6. package/lib/native-loader.js +49 -64
  7. package/lib/platform/json/wx/index.js +3 -10
  8. package/lib/platform/style/wx/index.js +32 -56
  9. package/lib/react/index.js +4 -3
  10. package/lib/react/processJSON.js +5 -13
  11. package/lib/react/processMainScript.js +7 -3
  12. package/lib/react/processScript.js +3 -4
  13. package/lib/react/processTemplate.js +6 -4
  14. package/lib/resolver/AddModePlugin.js +17 -4
  15. package/lib/runtime/components/react/context.ts +8 -0
  16. package/lib/runtime/components/react/dist/context.js +1 -0
  17. package/lib/runtime/components/react/dist/mpx-button.jsx +1 -1
  18. package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +30 -17
  19. package/lib/runtime/components/react/dist/mpx-checkbox.jsx +1 -1
  20. package/lib/runtime/components/react/dist/mpx-form.jsx +33 -24
  21. package/lib/runtime/components/react/dist/mpx-icon.jsx +1 -1
  22. package/lib/runtime/components/react/dist/mpx-image/index.jsx +1 -1
  23. package/lib/runtime/components/react/dist/mpx-input.jsx +44 -38
  24. package/lib/runtime/components/react/dist/mpx-label.jsx +10 -7
  25. package/lib/runtime/components/react/dist/mpx-movable-area.jsx +10 -17
  26. package/lib/runtime/components/react/dist/mpx-movable-view.jsx +378 -294
  27. package/lib/runtime/components/react/dist/mpx-navigator.jsx +1 -1
  28. package/lib/runtime/components/react/dist/mpx-radio-group.jsx +30 -17
  29. package/lib/runtime/components/react/dist/mpx-radio.jsx +1 -1
  30. package/lib/runtime/components/react/dist/mpx-root-portal.jsx +1 -1
  31. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +58 -30
  32. package/lib/runtime/components/react/dist/mpx-swiper/carouse.jsx +77 -77
  33. package/lib/runtime/components/react/dist/mpx-swiper/index.jsx +1 -1
  34. package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +1 -1
  35. package/lib/runtime/components/react/dist/mpx-switch.jsx +8 -1
  36. package/lib/runtime/components/react/dist/mpx-text.jsx +1 -1
  37. package/lib/runtime/components/react/dist/mpx-textarea.jsx +1 -1
  38. package/lib/runtime/components/react/dist/mpx-view.jsx +31 -12
  39. package/lib/runtime/components/react/dist/mpx-web-view.jsx +2 -2
  40. package/lib/runtime/components/react/dist/useAnimationHooks.js +303 -0
  41. package/lib/runtime/components/react/dist/utils.jsx +13 -3
  42. package/lib/runtime/components/react/getInnerListeners.ts +1 -0
  43. package/lib/runtime/components/react/mpx-button.tsx +1 -1
  44. package/lib/runtime/components/react/mpx-checkbox-group.tsx +52 -29
  45. package/lib/runtime/components/react/mpx-checkbox.tsx +1 -1
  46. package/lib/runtime/components/react/mpx-form.tsx +42 -34
  47. package/lib/runtime/components/react/mpx-icon.tsx +1 -1
  48. package/lib/runtime/components/react/mpx-image/index.tsx +2 -3
  49. package/lib/runtime/components/react/mpx-input.tsx +68 -66
  50. package/lib/runtime/components/react/mpx-label.tsx +11 -8
  51. package/lib/runtime/components/react/mpx-movable-area.tsx +11 -19
  52. package/lib/runtime/components/react/mpx-movable-view.tsx +456 -334
  53. package/lib/runtime/components/react/mpx-navigator.tsx +1 -1
  54. package/lib/runtime/components/react/mpx-radio-group.tsx +55 -29
  55. package/lib/runtime/components/react/mpx-radio.tsx +1 -1
  56. package/lib/runtime/components/react/mpx-root-portal.tsx +1 -1
  57. package/lib/runtime/components/react/mpx-scroll-view.tsx +92 -37
  58. package/lib/runtime/components/react/mpx-swiper/carouse.tsx +77 -76
  59. package/lib/runtime/components/react/mpx-swiper/index.tsx +2 -1
  60. package/lib/runtime/components/react/mpx-swiper-item.tsx +1 -1
  61. package/lib/runtime/components/react/mpx-switch.tsx +10 -2
  62. package/lib/runtime/components/react/mpx-text.tsx +1 -1
  63. package/lib/runtime/components/react/mpx-textarea.tsx +1 -1
  64. package/lib/runtime/components/react/mpx-view.tsx +40 -20
  65. package/lib/runtime/components/react/mpx-web-view.tsx +2 -2
  66. package/lib/runtime/components/react/types/common.ts +8 -2
  67. package/lib/runtime/components/react/useAnimationHooks.ts +332 -0
  68. package/lib/runtime/components/react/useNodesRef.ts +1 -0
  69. package/lib/runtime/components/react/utils.tsx +23 -6
  70. package/lib/runtime/optionProcessorReact.js +0 -15
  71. package/lib/runtime/swanHelper.wxs +1 -1
  72. package/lib/style-compiler/index.js +1 -1
  73. package/lib/style-compiler/plugins/scope-id.js +1 -0
  74. package/lib/template-compiler/compiler.js +68 -33
  75. package/lib/template-compiler/index.js +4 -4
  76. package/lib/utils/pre-process-json.js +113 -0
  77. package/lib/web/index.js +5 -4
  78. package/lib/web/processJSON.js +5 -13
  79. package/lib/web/processTemplate.js +2 -2
  80. package/package.json +5 -4
@@ -1,27 +1,30 @@
1
1
  /**
2
2
  * ✔ direction
3
- * inertia
4
- * out-of-bounds
3
+ * inertia
4
+ * out-of-bounds
5
5
  * ✔ x
6
6
  * ✔ y
7
7
  * ✘ damping
8
- * friction
8
+ * friction
9
9
  * ✔ disabled
10
- * scale
11
- * scale-min
12
- * scale-max
13
- * scale-value
10
+ * scale
11
+ * scale-min
12
+ * scale-max
13
+ * scale-value
14
14
  * ✘ animation
15
15
  * ✔ bindchange
16
- * bindscale
16
+ * bindscale
17
17
  * ✔ htouchmove
18
18
  * ✔ vtouchmove
19
19
  */
20
- import { useRef, useEffect, forwardRef, useContext, useState, useMemo } from 'react';
21
- import { StyleSheet, Animated, PanResponder } from 'react-native';
22
- import useInnerProps, { getCustomEvent } from './getInnerListeners';
20
+ import { useEffect, forwardRef, useContext, useCallback, useRef, useMemo } from 'react';
21
+ import { StyleSheet } from 'react-native';
22
+ import { getCustomEvent } from './getInnerListeners';
23
23
  import useNodesRef from './useNodesRef';
24
24
  import { MovableAreaContext } from './context';
25
+ import { useTransformStyle, splitProps, splitStyle, HIDDEN_STYLE, wrapChildren, flatGesture } from './utils';
26
+ import { GestureDetector, Gesture } from 'react-native-gesture-handler';
27
+ import Animated, { useSharedValue, useAnimatedStyle, withDecay, runOnJS, runOnUI, useAnimatedReaction, withSpring } from 'react-native-reanimated';
25
28
  const styles = StyleSheet.create({
26
29
  container: {
27
30
  position: 'absolute',
@@ -29,319 +32,400 @@ const styles = StyleSheet.create({
29
32
  top: 0
30
33
  }
31
34
  });
32
- const _MovableView = forwardRef((props, ref) => {
33
- const { children, friction = 7, scale = false, direction = 'none', x = 0, y = 0, style = {}, 'scale-min': scaleMin = 0.1, 'scale-max': scaleMax = 10, 'scale-value': originScaleValue = 1, bindscale, bindchange } = props;
34
- const pan = useRef(new Animated.ValueXY());
35
- const scaleValue = useRef(new Animated.Value(1));
36
- const [transformOrigin, setTransformOrigin] = useState('0% 0%');
37
- const propsRef = useRef({});
35
+ const _MovableView = forwardRef((movableViewProps, ref) => {
36
+ const { textProps, innerProps: props = {} } = splitProps(movableViewProps);
37
+ const movableGestureRef = useRef();
38
38
  const layoutRef = useRef({});
39
- const MovableAreaLayout = useContext(MovableAreaContext);
40
- const movablePosition = useRef({
41
- x: Number(x),
42
- y: Number(y)
39
+ const changeSource = useRef('');
40
+ const hasLayoutRef = useRef(false);
41
+ const propsRef = useRef({});
42
+ propsRef.current = (props || {});
43
+ 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;
44
+ const { hasSelfPercent, normalStyle, hasVarDec, varContextRef, setWidth, setHeight } = useTransformStyle(Object.assign({}, style, styles.container), { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
45
+ const prevSimultaneousHandlersRef = useRef(originSimultaneousHandlers || []);
46
+ const prevWaitForHandlersRef = useRef(waitFor || []);
47
+ const gestureSwitch = useRef(false);
48
+ const { textStyle, innerStyle } = splitStyle(normalStyle);
49
+ const offsetX = useSharedValue(x);
50
+ const offsetY = useSharedValue(y);
51
+ const startPosition = useSharedValue({
52
+ x: 0,
53
+ y: 0
43
54
  });
55
+ const draggableXRange = useSharedValue([0, 0]);
56
+ const draggableYRange = useSharedValue([0, 0]);
57
+ const isMoving = useSharedValue(false);
58
+ const xInertialMotion = useSharedValue(false);
59
+ const yInertialMotion = useSharedValue(false);
60
+ const isFirstTouch = useSharedValue(true);
61
+ const touchEvent = useSharedValue('');
62
+ const MovableAreaLayout = useContext(MovableAreaContext);
63
+ const simultaneousHandlers = flatGesture(originSimultaneousHandlers);
64
+ const waitForHandlers = flatGesture(waitFor);
44
65
  const nodeRef = useRef(null);
45
66
  useNodesRef(props, ref, nodeRef, {
46
- defaultStyle: styles.container
67
+ defaultStyle: styles.container,
68
+ gestureRef: movableGestureRef
47
69
  });
48
- let panResponder = {};
49
- const isFirstTouch = useRef(true);
50
- const touchEvent = useRef('');
51
- const initialDistance = useRef(0);
52
- propsRef.current = props;
53
- useEffect(() => {
54
- if (scale && (scaleValue.current._value !== originScaleValue)) {
55
- const clampedScale = Math.min(scaleMax, Math.max(scaleMin, originScaleValue));
56
- Animated.spring(scaleValue.current, {
57
- toValue: clampedScale,
58
- friction,
59
- useNativeDriver: false
60
- }).start(() => {
61
- bindscale && bindscale(getCustomEvent('scale', {}, {
62
- detail: {
63
- x: pan.current.x._value,
64
- y: pan.current.y._value,
65
- scale: clampedScale
66
- },
67
- layoutRef
68
- }, props));
69
- });
70
+ const hasSimultaneousHandlersChanged = prevSimultaneousHandlersRef.current.length !== (originSimultaneousHandlers?.length || 0) ||
71
+ (originSimultaneousHandlers || []).some((handler, index) => handler !== prevSimultaneousHandlersRef.current[index]);
72
+ const hasWaitForHandlersChanged = prevWaitForHandlersRef.current.length !== (waitFor?.length || 0) ||
73
+ (waitFor || []).some((handler, index) => handler !== prevWaitForHandlersRef.current[index]);
74
+ if (hasSimultaneousHandlersChanged || hasWaitForHandlersChanged) {
75
+ gestureSwitch.current = !gestureSwitch.current;
76
+ }
77
+ prevSimultaneousHandlersRef.current = originSimultaneousHandlers || [];
78
+ prevWaitForHandlersRef.current = waitFor || [];
79
+ const handleTriggerChange = useCallback(({ x, y, type }) => {
80
+ const { bindchange } = propsRef.current;
81
+ if (!bindchange)
82
+ return;
83
+ let source = '';
84
+ if (type !== 'setData') {
85
+ source = getTouchSource(x, y);
70
86
  }
71
- }, [originScaleValue]);
72
- useEffect(() => {
73
- if (movablePosition.current.x !== Number(x) || movablePosition.current.y !== Number(y)) {
74
- const { x: newX, y: newY } = checkBoundaryPosition({
75
- clampedScale: scaleValue.current._value,
76
- width: layoutRef.current.width,
77
- height: layoutRef.current.height,
78
- positionX: Number(x),
79
- positionY: Number(y)
80
- });
81
- movablePosition.current = { x: newX, y: newY };
82
- Animated.spring(pan.current, {
83
- toValue: { x: newX, y: newY },
84
- useNativeDriver: false,
85
- friction
86
- }).start(() => {
87
- bindchange &&
88
- bindchange(getCustomEvent('change', {}, {
89
- detail: {
90
- x: newX,
91
- y: newY,
92
- source: ''
93
- },
94
- layoutRef
95
- }, props));
96
- });
87
+ else {
88
+ changeSource.current = '';
97
89
  }
98
- }, [x, y]);
99
- const handlePanReleaseOrTerminate = () => {
100
- pan.current.flattenOffset();
101
- isFirstTouch.current = true;
102
- initialDistance.current = 0;
103
- const { x, y } = checkBoundaryPosition({
104
- clampedScale: scaleValue.current._value,
105
- width: layoutRef.current.width,
106
- height: layoutRef.current.height,
107
- positionX: pan.current.x._value,
108
- positionY: pan.current.y._value
109
- });
110
- movablePosition.current = {
111
- x,
112
- y
113
- };
114
- const needChange = x !== pan.current.x._value || y !== pan.current.y._value;
115
- Animated.spring(pan.current, {
116
- toValue: { x, y },
117
- friction: 7,
118
- useNativeDriver: false
119
- }).start(() => {
120
- if (needChange) {
121
- bindchange && bindchange(getCustomEvent('change', {}, {
122
- detail: {
123
- x,
124
- y,
125
- source: 'out-of-bounds'
126
- },
127
- layoutRef
128
- }, propsRef.current));
129
- }
130
- });
131
- };
132
- panResponder = useMemo(() => {
133
- return PanResponder.create({
134
- onMoveShouldSetPanResponder: () => !propsRef.current.disabled,
135
- onMoveShouldSetPanResponderCapture: () => !propsRef.current.disabled,
136
- onPanResponderGrant: (e, gestureState) => {
137
- if (gestureState.numberActiveTouches === 1) {
138
- setTransformOrigin('0% 0%');
139
- pan.current.setOffset({
140
- x: direction === 'all' || direction === 'horizontal' ? pan.current.x._value : 0,
141
- y: direction === 'all' || direction === 'vertical' ? pan.current.y._value : 0
142
- });
143
- pan.current.setValue({ x: 0, y: 0 });
144
- }
145
- else {
146
- initialDistance.current = 0;
147
- setTransformOrigin('50% 50%');
148
- }
90
+ bindchange(getCustomEvent('change', {}, {
91
+ detail: {
92
+ x,
93
+ y,
94
+ source
149
95
  },
150
- onPanResponderMove: (e, gestureState) => {
151
- if (gestureState.numberActiveTouches === 2 && scale) {
152
- setTransformOrigin('50% 50%');
153
- const touch1 = e.nativeEvent.touches[0];
154
- const touch2 = e.nativeEvent.touches[1];
155
- const currentTouchDistance = Math.sqrt(Math.pow(touch1.pageX - touch2.pageX, 2) + Math.pow(touch1.pageY - touch2.pageY, 2));
156
- if (!initialDistance.current) {
157
- initialDistance.current = currentTouchDistance;
158
- }
159
- else {
160
- const newScale = currentTouchDistance / initialDistance.current;
161
- const clampedScale = Math.min(scaleMax, Math.max(scaleMin, newScale));
162
- Animated.spring(scaleValue.current, {
163
- toValue: clampedScale,
164
- friction: 7,
165
- useNativeDriver: false
166
- }).start();
167
- bindscale && bindscale(getCustomEvent('scale', e, {
168
- detail: {
169
- x: pan.current.x._value,
170
- y: pan.current.y._value,
171
- scale: clampedScale
172
- },
173
- layoutRef
174
- }, propsRef.current));
175
- }
96
+ layoutRef
97
+ }, propsRef.current));
98
+ }, []);
99
+ useEffect(() => {
100
+ runOnUI(() => {
101
+ if (offsetX.value !== x || offsetY.value !== y) {
102
+ const { x: newX, y: newY } = checkBoundaryPosition({ positionX: Number(x), positionY: Number(y) });
103
+ if (direction === 'horizontal' || direction === 'all') {
104
+ offsetX.value = animation
105
+ ? withSpring(newX, {
106
+ duration: 1500,
107
+ dampingRatio: 0.8
108
+ })
109
+ : newX;
176
110
  }
177
- else if (gestureState.numberActiveTouches === 1) {
178
- if (initialDistance.current) {
179
- return; // Skip processing if it's switching from a double touch
180
- }
181
- setTransformOrigin('0% 0%');
182
- if (isFirstTouch.current) {
183
- touchEvent.current = Math.abs(gestureState.dx) > Math.abs(gestureState.dy) ? 'htouchmove' : 'vtouchmove';
184
- isFirstTouch.current = false;
185
- }
186
- Animated.event([
187
- null,
188
- {
189
- dx: direction === 'all' || direction === 'horizontal' ? pan.current.x : new Animated.Value(0),
190
- dy: direction === 'all' || direction === 'vertical' ? pan.current.y : new Animated.Value(0)
191
- }
192
- ], {
193
- useNativeDriver: false
194
- })(e, gestureState);
195
- movablePosition.current = {
196
- x: pan.current.x.__getValue(),
197
- y: pan.current.y.__getValue()
198
- };
199
- bindchange && bindchange(getCustomEvent('change', e, {
200
- detail: {
201
- x: movablePosition.current.x,
202
- y: movablePosition.current.y,
203
- source: 'touch'
204
- },
205
- layoutRef
206
- }, propsRef.current));
111
+ if (direction === 'vertical' || direction === 'all') {
112
+ offsetY.value = animation
113
+ ? withSpring(newY, {
114
+ duration: 1500,
115
+ dampingRatio: 0.8
116
+ })
117
+ : newY;
207
118
  }
208
- },
209
- onPanResponderRelease: () => {
210
- handlePanReleaseOrTerminate();
211
- },
212
- onPanResponderTerminate: () => {
213
- handlePanReleaseOrTerminate();
119
+ runOnJS(handleTriggerChange)({
120
+ x: newX,
121
+ y: newY,
122
+ type: 'setData'
123
+ });
214
124
  }
125
+ })();
126
+ }, [x, y]);
127
+ useEffect(() => {
128
+ const { width, height } = layoutRef.current;
129
+ if (width && height) {
130
+ resetBoundaryAndCheck({ width, height });
131
+ }
132
+ }, [MovableAreaLayout.height, MovableAreaLayout.width]);
133
+ useAnimatedReaction(() => ({
134
+ offsetX: offsetX.value,
135
+ offsetY: offsetY.value
136
+ }), (currentValue) => {
137
+ const { offsetX, offsetY } = currentValue;
138
+ runOnJS(handleTriggerChange)({
139
+ x: offsetX,
140
+ y: offsetY
215
141
  });
216
- }, [MovableAreaLayout.width, MovableAreaLayout.height]);
217
- const onLayout = () => {
218
- nodeRef.current?.measure((x, y, width, height) => {
219
- layoutRef.current = { x, y, width, height, offsetLeft: 0, offsetTop: 0 };
220
- const clampedScale = Math.min(scaleMax, Math.max(scaleMin, originScaleValue));
221
- const { x: newX, y: nexY } = checkBoundaryPosition({
222
- clampedScale,
223
- width,
224
- height,
225
- positionX: movablePosition.current.x,
226
- positionY: movablePosition.current.y
227
- });
228
- Animated.spring(pan.current, {
229
- toValue: { x: newX, y: nexY },
230
- useNativeDriver: false,
231
- friction
232
- }).start(() => {
233
- movablePosition.current = { x: newX, y: nexY };
234
- bindchange &&
235
- bindchange(getCustomEvent('change', {}, {
236
- detail: {
237
- x: newX,
238
- y: nexY,
239
- source: ''
240
- },
241
- layoutRef
242
- }, props));
243
- });
244
- });
245
- };
246
- const onTouchMove = (e) => {
247
- const { bindhtouchmove, bindvtouchmove, bindtouchmove } = props;
248
- if (touchEvent.current === 'htouchmove') {
249
- bindhtouchmove && bindhtouchmove(e);
142
+ });
143
+ const getTouchSource = useCallback((offsetX, offsetY) => {
144
+ const hasOverBoundary = offsetX < draggableXRange.value[0] || offsetX > draggableXRange.value[1] ||
145
+ offsetY < draggableYRange.value[0] || offsetY > draggableYRange.value[1];
146
+ let source = changeSource.current;
147
+ if (hasOverBoundary) {
148
+ if (isMoving.value) {
149
+ source = 'touch-out-of-bounds';
150
+ }
151
+ else {
152
+ source = 'out-of-bounds';
153
+ }
250
154
  }
251
- else if (touchEvent.current === 'vtouchmove') {
252
- bindvtouchmove && bindvtouchmove(e);
155
+ else {
156
+ if (isMoving.value) {
157
+ source = 'touch';
158
+ }
159
+ else if ((xInertialMotion.value || yInertialMotion.value) && (changeSource.current === 'touch' || changeSource.current === 'friction')) {
160
+ source = 'friction';
161
+ }
253
162
  }
254
- bindtouchmove && bindtouchmove(e);
255
- };
256
- const onCatchTouchMove = (e) => {
257
- const { catchhtouchmove, catchvtouchmove, catchtouchmove } = props;
258
- if (touchEvent.current === 'htouchmove') {
259
- catchhtouchmove && catchhtouchmove(e);
163
+ changeSource.current = source;
164
+ return source;
165
+ }, []);
166
+ const setBoundary = useCallback(({ width, height }) => {
167
+ const top = (style.position === 'absolute' && style.top) || 0;
168
+ const left = (style.position === 'absolute' && style.left) || 0;
169
+ const scaledWidth = width || 0;
170
+ const scaledHeight = height || 0;
171
+ const maxY = MovableAreaLayout.height - scaledHeight - top;
172
+ const maxX = MovableAreaLayout.width - scaledWidth - left;
173
+ let xRange;
174
+ let yRange;
175
+ if (MovableAreaLayout.width < scaledWidth) {
176
+ xRange = [maxX, 0];
260
177
  }
261
- else if (touchEvent.current === 'vtouchmove') {
262
- catchvtouchmove && catchvtouchmove(e);
178
+ else {
179
+ xRange = [left === 0 ? 0 : -left, maxX < 0 ? 0 : maxX];
263
180
  }
264
- catchtouchmove && catchtouchmove(e);
265
- };
266
- const checkBoundaryPosition = ({ clampedScale, width, height, positionX, positionY }) => {
267
- // Calculate scaled element size
268
- const scaledWidth = width * clampedScale;
269
- const scaledHeight = height * clampedScale;
270
- // Calculate the boundary limits
181
+ if (MovableAreaLayout.height < scaledHeight) {
182
+ yRange = [maxY, 0];
183
+ }
184
+ else {
185
+ yRange = [top === 0 ? 0 : -top, maxY < 0 ? 0 : maxY];
186
+ }
187
+ draggableXRange.value = xRange;
188
+ draggableYRange.value = yRange;
189
+ }, [MovableAreaLayout.height, MovableAreaLayout.width, style.position, style.top, style.left]);
190
+ const checkBoundaryPosition = useCallback(({ positionX, positionY }) => {
191
+ 'worklet';
271
192
  let x = positionX;
272
193
  let y = positionY;
273
- // Correct y coordinate
274
- if (scaledHeight > MovableAreaLayout.height) {
275
- if (y >= 0) {
276
- y = 0;
194
+ // 计算边界限制
195
+ if (x > draggableXRange.value[1]) {
196
+ x = draggableXRange.value[1];
197
+ }
198
+ else if (x < draggableXRange.value[0]) {
199
+ x = draggableXRange.value[0];
200
+ }
201
+ if (y > draggableYRange.value[1]) {
202
+ y = draggableYRange.value[1];
203
+ }
204
+ else if (y < draggableYRange.value[0]) {
205
+ y = draggableYRange.value[0];
206
+ }
207
+ return { x, y };
208
+ }, []);
209
+ const resetBoundaryAndCheck = ({ width, height }) => {
210
+ setBoundary({ width, height });
211
+ runOnUI(() => {
212
+ const positionX = offsetX.value;
213
+ const positionY = offsetY.value;
214
+ const { x: newX, y: newY } = checkBoundaryPosition({ positionX, positionY });
215
+ if (positionX !== newX) {
216
+ offsetX.value = newX;
277
217
  }
278
- else if (y < MovableAreaLayout.height - scaledHeight) {
279
- y = MovableAreaLayout.height - scaledHeight;
218
+ if (positionY !== newY) {
219
+ offsetY.value = newY;
280
220
  }
221
+ })();
222
+ };
223
+ const onLayout = (e) => {
224
+ hasLayoutRef.current = true;
225
+ if (hasSelfPercent) {
226
+ const { width, height } = e?.nativeEvent?.layout || {};
227
+ setWidth(width || 0);
228
+ setHeight(height || 0);
281
229
  }
282
- else {
283
- if (y < 0) {
284
- y = 0;
230
+ nodeRef.current?.measure((x, y, width, height) => {
231
+ layoutRef.current = { x, y, width, height, offsetLeft: 0, offsetTop: 0 };
232
+ resetBoundaryAndCheck({ width, height });
233
+ });
234
+ props.onLayout && props.onLayout(e);
235
+ };
236
+ const extendEvent = useCallback((e) => {
237
+ 'worklet';
238
+ const touchArr = [e.changedTouches, e.allTouches];
239
+ touchArr.forEach(touches => {
240
+ touches && touches.forEach((item) => {
241
+ item.pageX = item.absoluteX;
242
+ item.pageY = item.absoluteY;
243
+ });
244
+ });
245
+ e.touches = e.allTouches;
246
+ }, []);
247
+ const gesture = useMemo(() => {
248
+ const handleTriggerStart = (e) => {
249
+ 'worklet';
250
+ extendEvent(e);
251
+ bindtouchstart && runOnJS(bindtouchstart)(e);
252
+ catchtouchstart && runOnJS(catchtouchstart)(e);
253
+ };
254
+ const handleTriggerMove = (e) => {
255
+ 'worklet';
256
+ extendEvent(e);
257
+ const hasTouchmove = !!bindhtouchmove || !!bindvtouchmove || !!bindtouchmove;
258
+ const hasCatchTouchmove = !!catchhtouchmove || !!catchvtouchmove || !!catchtouchmove;
259
+ if (hasTouchmove) {
260
+ if (touchEvent.value === 'htouchmove') {
261
+ bindhtouchmove && runOnJS(bindhtouchmove)(e);
262
+ }
263
+ else if (touchEvent.value === 'vtouchmove') {
264
+ bindvtouchmove && runOnJS(bindvtouchmove)(e);
265
+ }
266
+ bindtouchmove && runOnJS(bindtouchmove)(e);
285
267
  }
286
- else if (y > MovableAreaLayout.height - scaledHeight) {
287
- y = MovableAreaLayout.height - scaledHeight;
268
+ if (hasCatchTouchmove) {
269
+ if (touchEvent.value === 'htouchmove') {
270
+ catchhtouchmove && runOnJS(catchhtouchmove)(e);
271
+ }
272
+ else if (touchEvent.value === 'vtouchmove') {
273
+ catchvtouchmove && runOnJS(catchvtouchmove)(e);
274
+ }
275
+ catchtouchmove && runOnJS(catchtouchmove)(e);
288
276
  }
289
- }
290
- // Correct x coordinate
291
- if (scaledWidth > MovableAreaLayout.width) {
292
- if (x >= 0) {
293
- x = 0;
277
+ };
278
+ const handleTriggerEnd = (e) => {
279
+ 'worklet';
280
+ extendEvent(e);
281
+ bindtouchend && runOnJS(bindtouchend)(e);
282
+ catchtouchend && runOnJS(catchtouchend)(e);
283
+ };
284
+ const gesturePan = Gesture.Pan()
285
+ .onTouchesDown((e) => {
286
+ 'worklet';
287
+ const changedTouches = e.changedTouches[0] || { x: 0, y: 0 };
288
+ isMoving.value = false;
289
+ startPosition.value = {
290
+ x: changedTouches.x,
291
+ y: changedTouches.y
292
+ };
293
+ handleTriggerStart(e);
294
+ })
295
+ .onTouchesMove((e) => {
296
+ 'worklet';
297
+ isMoving.value = true;
298
+ const changedTouches = e.changedTouches[0] || { x: 0, y: 0 };
299
+ if (isFirstTouch.value) {
300
+ touchEvent.value = Math.abs(changedTouches.x - startPosition.value.x) > Math.abs(changedTouches.y - startPosition.value.y) ? 'htouchmove' : 'vtouchmove';
301
+ isFirstTouch.value = false;
294
302
  }
295
- else if (x < MovableAreaLayout.width - scaledWidth) {
296
- x = MovableAreaLayout.width - scaledWidth;
303
+ handleTriggerMove(e);
304
+ if (disabled)
305
+ return;
306
+ const changeX = changedTouches.x - startPosition.value.x;
307
+ const changeY = changedTouches.y - startPosition.value.y;
308
+ if (direction === 'horizontal' || direction === 'all') {
309
+ const newX = offsetX.value + changeX;
310
+ if (!outOfBounds) {
311
+ const { x } = checkBoundaryPosition({ positionX: newX, positionY: offsetY.value });
312
+ offsetX.value = x;
313
+ }
314
+ else {
315
+ offsetX.value = newX;
316
+ }
297
317
  }
298
- }
299
- else {
300
- if (x < 0) {
301
- x = 0;
318
+ if (direction === 'vertical' || direction === 'all') {
319
+ const newY = offsetY.value + changeY;
320
+ if (!outOfBounds) {
321
+ const { y } = checkBoundaryPosition({ positionX: offsetX.value, positionY: newY });
322
+ offsetY.value = y;
323
+ }
324
+ else {
325
+ offsetY.value = newY;
326
+ }
302
327
  }
303
- else if (x > MovableAreaLayout.width - scaledWidth) {
304
- x = MovableAreaLayout.width - scaledWidth;
328
+ })
329
+ .onTouchesUp((e) => {
330
+ 'worklet';
331
+ isFirstTouch.value = true;
332
+ isMoving.value = false;
333
+ handleTriggerEnd(e);
334
+ if (disabled)
335
+ return;
336
+ if (!inertia) {
337
+ const { x, y } = checkBoundaryPosition({ positionX: offsetX.value, positionY: offsetY.value });
338
+ if (x !== offsetX.value) {
339
+ offsetX.value = animation
340
+ ? withSpring(x, {
341
+ duration: 1500,
342
+ dampingRatio: 0.8
343
+ })
344
+ : x;
345
+ }
346
+ if (y !== offsetY.value) {
347
+ offsetY.value = animation
348
+ ? withSpring(y, {
349
+ duration: 1500,
350
+ dampingRatio: 0.8
351
+ })
352
+ : y;
353
+ }
354
+ }
355
+ })
356
+ .onFinalize((e) => {
357
+ 'worklet';
358
+ if (!inertia || disabled || !animation)
359
+ return;
360
+ isMoving.value = false;
361
+ if (direction === 'horizontal' || direction === 'all') {
362
+ xInertialMotion.value = true;
363
+ offsetX.value = withDecay({
364
+ velocity: e.velocityX / 10,
365
+ rubberBandEffect: outOfBounds,
366
+ clamp: draggableXRange.value
367
+ }, () => {
368
+ xInertialMotion.value = false;
369
+ });
305
370
  }
371
+ if (direction === 'vertical' || direction === 'all') {
372
+ yInertialMotion.value = true;
373
+ offsetY.value = withDecay({
374
+ velocity: e.velocityY / 10,
375
+ rubberBandEffect: outOfBounds,
376
+ clamp: draggableYRange.value
377
+ }, () => {
378
+ yInertialMotion.value = false;
379
+ });
380
+ }
381
+ })
382
+ .withRef(movableGestureRef);
383
+ if (simultaneousHandlers && simultaneousHandlers.length) {
384
+ gesturePan.simultaneousWithExternalGesture(...simultaneousHandlers);
385
+ }
386
+ if (waitForHandlers && waitForHandlers.length) {
387
+ gesturePan.requireExternalGestureToFail(...waitForHandlers);
306
388
  }
389
+ return gesturePan;
390
+ }, [disabled, direction, inertia, outOfBounds, gestureSwitch.current]);
391
+ const animatedStyles = useAnimatedStyle(() => {
307
392
  return {
308
- x,
309
- y
393
+ transform: [
394
+ { translateX: offsetX.value },
395
+ { translateY: offsetY.value }
396
+ ]
310
397
  };
398
+ });
399
+ const injectCatchEvent = (props) => {
400
+ const eventHandlers = {};
401
+ const catchEventList = [
402
+ { name: 'onTouchStart', value: ['catchtouchstart'] },
403
+ { name: 'onTouchMove', value: ['catchtouchmove', 'catchvtouchmove', 'catchhtouchmove'] },
404
+ { name: 'onTouchEnd', value: ['catchtouchend'] }
405
+ ];
406
+ catchEventList.forEach(event => {
407
+ event.value.forEach(name => {
408
+ if (props[name] && !eventHandlers[event.name]) {
409
+ eventHandlers[event.name] = (e) => {
410
+ e.stopPropagation();
411
+ };
412
+ }
413
+ });
414
+ });
415
+ return eventHandlers;
311
416
  };
312
- const [translateX, translateY] = [pan.current.x, pan.current.y];
313
- const transformStyle = { transform: [{ translateX }, { translateY }, { scale: scaleValue.current }], transformOrigin: transformOrigin };
314
- const hasTouchmove = () => !!props.bindhtouchmove || !!props.bindvtouchmove || !!props.bindtouchmove;
315
- const hasCatchTouchmove = () => !!props.catchhtouchmove || !!props.catchvtouchmove || !!props.catchtouchmove;
316
- const innerProps = useInnerProps(props, {
317
- ref: nodeRef,
318
- ...panResponder.panHandlers,
319
- onLayout,
320
- ...(hasTouchmove() ? { bindtouchmove: onTouchMove } : {}),
321
- ...(hasCatchTouchmove() ? { catchtouchmove: onCatchTouchMove } : {})
322
- }, [
323
- 'children',
324
- 'style',
325
- 'direction',
326
- 'x',
327
- 'y',
328
- 'scale',
329
- 'disabled',
330
- 'scale-value',
331
- 'scale-min',
332
- 'scale-max',
333
- 'bindchange',
334
- 'bindscale',
335
- 'htouchmove',
336
- 'vtouchmove'
337
- ], { layoutRef });
338
- return (<Animated.View {...innerProps} style={{
339
- ...styles.container,
340
- ...style,
341
- ...transformStyle
342
- }}>
343
- {children}
344
- </Animated.View>);
417
+ const catchEventHandlers = injectCatchEvent(props);
418
+ const layoutStyle = !hasLayoutRef.current && hasSelfPercent ? HIDDEN_STYLE : {};
419
+ return (<GestureDetector gesture={gesture}>
420
+ <Animated.View ref={nodeRef} onLayout={onLayout} style={[innerStyle, animatedStyles, layoutStyle]} {...catchEventHandlers}>
421
+ {wrapChildren(props, {
422
+ hasVarDec,
423
+ varContext: varContextRef.current,
424
+ textStyle,
425
+ textProps
426
+ })}
427
+ </Animated.View>
428
+ </GestureDetector>);
345
429
  });
346
- _MovableView.displayName = 'mpx-movable-view';
430
+ _MovableView.displayName = 'MpxMovableView';
347
431
  export default _MovableView;