@mpxjs/webpack-plugin 2.10.7-beta.9 → 2.10.7

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 (40) hide show
  1. package/LICENSE +433 -0
  2. package/lib/dependencies/RecordPageConfigsMapDependency.js +1 -1
  3. package/lib/index.js +5 -6
  4. package/lib/platform/style/wx/index.js +0 -7
  5. package/lib/platform/template/wx/component-config/index.js +1 -5
  6. package/lib/platform/template/wx/component-config/movable-view.js +10 -1
  7. package/lib/platform/template/wx/index.js +2 -1
  8. package/lib/runtime/components/react/context.ts +4 -23
  9. package/lib/runtime/components/react/dist/context.js +2 -5
  10. package/lib/runtime/components/react/dist/getInnerListeners.js +1 -1
  11. package/lib/runtime/components/react/dist/mpx-button.jsx +2 -2
  12. package/lib/runtime/components/react/dist/mpx-movable-area.jsx +9 -63
  13. package/lib/runtime/components/react/dist/mpx-movable-view.jsx +63 -308
  14. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +15 -31
  15. package/lib/runtime/components/react/dist/mpx-swiper.jsx +27 -53
  16. package/lib/runtime/components/react/dist/mpx-web-view.jsx +14 -28
  17. package/lib/runtime/components/react/dist/useAnimationHooks.js +2 -87
  18. package/lib/runtime/components/react/getInnerListeners.ts +1 -1
  19. package/lib/runtime/components/react/mpx-button.tsx +2 -3
  20. package/lib/runtime/components/react/mpx-movable-area.tsx +11 -98
  21. package/lib/runtime/components/react/mpx-movable-view.tsx +64 -358
  22. package/lib/runtime/components/react/mpx-scroll-view.tsx +59 -84
  23. package/lib/runtime/components/react/mpx-swiper.tsx +25 -53
  24. package/lib/runtime/components/react/mpx-web-view.tsx +13 -33
  25. package/lib/runtime/components/react/types/global.d.ts +15 -0
  26. package/lib/runtime/components/react/useAnimationHooks.ts +2 -85
  27. package/lib/runtime/components/web/mpx-scroll-view.vue +4 -18
  28. package/lib/template-compiler/bind-this.js +1 -2
  29. package/lib/template-compiler/compiler.js +2 -2
  30. package/package.json +4 -4
  31. package/lib/platform/template/wx/component-config/sticky-header.js +0 -23
  32. package/lib/platform/template/wx/component-config/sticky-section.js +0 -23
  33. package/lib/runtime/components/react/AsyncContainer.tsx +0 -189
  34. package/lib/runtime/components/react/dist/AsyncContainer.jsx +0 -141
  35. package/lib/runtime/components/react/dist/mpx-sticky-header.jsx +0 -117
  36. package/lib/runtime/components/react/dist/mpx-sticky-section.jsx +0 -45
  37. package/lib/runtime/components/react/mpx-sticky-header.tsx +0 -181
  38. package/lib/runtime/components/react/mpx-sticky-section.tsx +0 -96
  39. package/lib/runtime/components/web/mpx-sticky-header.vue +0 -99
  40. package/lib/runtime/components/web/mpx-sticky-section.vue +0 -15
@@ -1,87 +1,33 @@
1
1
  /**
2
- * scale-area
2
+ * scale-area
3
3
  */
4
4
  import { View } from 'react-native';
5
- import { forwardRef, useRef, useMemo, useCallback, createElement } from 'react';
6
- import { GestureDetector, Gesture } from 'react-native-gesture-handler';
7
- import { useSharedValue } from 'react-native-reanimated';
5
+ import { forwardRef, useRef, useMemo, createElement } from 'react';
8
6
  import useNodesRef from './useNodesRef';
9
7
  import useInnerProps from './getInnerListeners';
10
8
  import { MovableAreaContext } from './context';
11
9
  import { useTransformStyle, wrapChildren, useLayout, extendObject } from './utils';
12
10
  import Portal from './mpx-portal';
13
11
  const _MovableArea = forwardRef((props, ref) => {
14
- const { style = {}, 'scale-area': scaleArea = false, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight } = props;
12
+ const { style = {}, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight } = props;
15
13
  const { hasSelfPercent, normalStyle, hasVarDec, varContextRef, hasPositionFixed, setWidth, setHeight } = useTransformStyle(style, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
16
- const movableAreaRef = useRef(null);
17
- const movableViewsValue = useSharedValue({});
18
- useNodesRef(props, ref, movableAreaRef, {
14
+ const movableViewRef = useRef(null);
15
+ useNodesRef(props, ref, movableViewRef, {
19
16
  style: normalStyle
20
17
  });
21
- // 注册/注销 MovableView 的回调
22
- const registerMovableView = useCallback((id, callbacks) => {
23
- movableViewsValue.value = extendObject(movableViewsValue.value, { [id]: callbacks });
24
- }, []);
25
- const unregisterMovableView = useCallback((id) => {
26
- delete movableViewsValue.value[id];
27
- }, []);
28
- // 处理区域缩放手势
29
- const handleAreaScale = useCallback((scaleInfo) => {
30
- 'worklet';
31
- if (scaleArea) {
32
- // 将缩放信息广播给所有注册的 MovableView
33
- Object.values(movableViewsValue.value).forEach((callbacks) => {
34
- callbacks.onScale && callbacks.onScale(scaleInfo);
35
- });
36
- }
37
- }, [scaleArea]);
38
- // 处理区域缩放结束
39
- const handleAreaScaleEnd = useCallback(() => {
40
- 'worklet';
41
- if (scaleArea) {
42
- // 通知所有注册的 MovableView 缩放结束
43
- Object.values(movableViewsValue.value).forEach((callbacks) => {
44
- callbacks.onScaleEnd && callbacks.onScaleEnd();
45
- });
46
- }
47
- }, [scaleArea]);
48
18
  const contextValue = useMemo(() => ({
49
19
  height: normalStyle.height || 10,
50
- width: normalStyle.width || 10,
51
- scaleArea,
52
- registerMovableView,
53
- unregisterMovableView
54
- }), [normalStyle.width, normalStyle.height, scaleArea]);
55
- const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: movableAreaRef });
56
- // 创建缩放手势
57
- const scaleGesture = useMemo(() => {
58
- if (!scaleArea)
59
- return null;
60
- return Gesture.Pinch()
61
- .onUpdate((e) => {
62
- 'worklet';
63
- handleAreaScale(e);
64
- })
65
- .onEnd(() => {
66
- 'worklet';
67
- handleAreaScaleEnd();
68
- });
69
- }, [scaleArea]);
20
+ width: normalStyle.width || 10
21
+ }), [normalStyle.width, normalStyle.height]);
22
+ const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: movableViewRef });
70
23
  const innerProps = useInnerProps(extendObject({}, props, layoutProps, {
71
24
  style: extendObject({ height: contextValue.height, width: contextValue.width }, normalStyle, layoutStyle),
72
- ref: movableAreaRef
25
+ ref: movableViewRef
73
26
  }), [], { layoutRef });
74
27
  let movableComponent = createElement(MovableAreaContext.Provider, { value: contextValue }, createElement(View, innerProps, wrapChildren(props, {
75
28
  hasVarDec,
76
29
  varContext: varContextRef.current
77
30
  })));
78
- // 如果启用了 scale-area,包装一个 GestureDetector
79
- if (scaleArea && scaleGesture) {
80
- movableComponent = createElement(MovableAreaContext.Provider, { value: contextValue }, createElement(GestureDetector, { gesture: scaleGesture }, createElement(View, innerProps, wrapChildren(props, {
81
- hasVarDec,
82
- varContext: varContextRef.current
83
- }))));
84
- }
85
31
  if (hasPositionFixed) {
86
32
  movableComponent = createElement(Portal, null, movableComponent);
87
33
  }
@@ -7,13 +7,13 @@
7
7
  * ✘ damping
8
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
  */
@@ -24,7 +24,7 @@ import useNodesRef from './useNodesRef';
24
24
  import { MovableAreaContext } from './context';
25
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, withDecay, runOnJS, runOnUI, withSpring, withTiming } from 'react-native-reanimated';
27
+ import Animated, { useSharedValue, useAnimatedStyle, withDecay, runOnJS, runOnUI, withSpring } from 'react-native-reanimated';
28
28
  import { collectDataset, noop } from '@mpxjs/utils';
29
29
  const styles = StyleSheet.create({
30
30
  container: {
@@ -41,8 +41,8 @@ const _MovableView = forwardRef((movableViewProps, ref) => {
41
41
  const hasLayoutRef = useRef(false);
42
42
  const propsRef = useRef({});
43
43
  propsRef.current = (props || {});
44
- const { x = 0, y = 0, inertia = false, disabled = false, animation = true, scale = false, 'scale-min': scaleMin = 0.1, 'scale-max': scaleMax = 10, 'scale-value': scaleValue = 1, 'out-of-bounds': outOfBounds = false, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, direction = 'none', 'disable-event-passthrough': disableEventPassthrough = false, 'simultaneous-handlers': originSimultaneousHandlers = [], 'wait-for': waitFor = [], style = {}, changeThrottleTime = 60, bindtouchstart, catchtouchstart, bindhtouchmove, bindvtouchmove, bindtouchmove, catchhtouchmove, catchvtouchmove, catchtouchmove, bindtouchend, catchtouchend, bindscale, bindchange, onLayout: propsOnLayout } = props;
45
- const { hasSelfPercent, normalStyle, hasVarDec, varContextRef, setWidth, setHeight } = useTransformStyle(Object.assign({}, styles.container, style), { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
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 = {}, changeThrottleTime = 60, bindtouchstart, catchtouchstart, bindhtouchmove, bindvtouchmove, bindtouchmove, catchhtouchmove, catchvtouchmove, catchtouchmove, bindtouchend, catchtouchend, bindchange } = props;
45
+ const { hasSelfPercent, normalStyle, hasVarDec, varContextRef, setWidth, setHeight } = useTransformStyle(Object.assign({}, style, styles.container), { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
46
46
  const navigation = useNavigation();
47
47
  const prevSimultaneousHandlersRef = useRef(originSimultaneousHandlers || []);
48
48
  const prevWaitForHandlersRef = useRef(waitFor || []);
@@ -50,8 +50,6 @@ const _MovableView = forwardRef((movableViewProps, ref) => {
50
50
  const { textStyle, innerStyle } = splitStyle(normalStyle);
51
51
  const offsetX = useSharedValue(x);
52
52
  const offsetY = useSharedValue(y);
53
- const currentScale = useSharedValue(1);
54
- const layoutValue = useSharedValue({});
55
53
  const startPosition = useSharedValue({
56
54
  x: 0,
57
55
  y: 0
@@ -102,38 +100,6 @@ const _MovableView = forwardRef((movableViewProps, ref) => {
102
100
  layoutRef
103
101
  }, propsRef.current));
104
102
  }, []);
105
- const handleTriggerScale = useCallback(({ x, y, scale }) => {
106
- const { bindscale } = propsRef.current;
107
- if (!bindscale)
108
- return;
109
- bindscale(getCustomEvent('scale', {}, {
110
- detail: {
111
- x,
112
- y,
113
- scale
114
- },
115
- layoutRef
116
- }, propsRef.current));
117
- }, []);
118
- const checkBoundaryPosition = useCallback(({ positionX, positionY }) => {
119
- 'worklet';
120
- let x = positionX;
121
- let y = positionY;
122
- // 计算边界限制
123
- if (x > draggableXRange.value[1]) {
124
- x = draggableXRange.value[1];
125
- }
126
- else if (x < draggableXRange.value[0]) {
127
- x = draggableXRange.value[0];
128
- }
129
- if (y > draggableYRange.value[1]) {
130
- y = draggableYRange.value[1];
131
- }
132
- else if (y < draggableYRange.value[0]) {
133
- y = draggableYRange.value[0];
134
- }
135
- return { x, y };
136
- }, []);
137
103
  // 节流版本的 change 事件触发
138
104
  const handleTriggerChangeThrottled = useCallback(({ x, y, type }) => {
139
105
  'worklet';
@@ -173,193 +139,12 @@ const _MovableView = forwardRef((movableViewProps, ref) => {
173
139
  }
174
140
  })();
175
141
  }, [x, y]);
176
- // 提取通用的缩放边界计算函数
177
- const calculateScaleBoundaryPosition = useCallback(({ currentOffsetX, currentOffsetY, newScale, width, height }) => {
178
- 'worklet';
179
- const prevScale = currentScale.value;
180
- // 计算元素当前中心点(在屏幕上的位置)
181
- const currentCenterX = currentOffsetX + (width * prevScale) / 2;
182
- const currentCenterY = currentOffsetY + (height * prevScale) / 2;
183
- // 实现中心缩放:保持元素中心点不变
184
- // 计算缩放后为了保持中心点不变需要的新offset位置
185
- let newOffsetX = currentCenterX - (width * newScale) / 2;
186
- let newOffsetY = currentCenterY - (height * newScale) / 2;
187
- // 缩放过程中实时边界检测
188
- // 计算新的边界范围
189
- const top = (style.position === 'absolute' && style.top) || 0;
190
- const left = (style.position === 'absolute' && style.left) || 0;
191
- const scaledWidth = width * newScale;
192
- const scaledHeight = height * newScale;
193
- // 计算新缩放值下的边界限制
194
- const maxOffsetY = MovableAreaLayout.height - scaledHeight - top;
195
- const maxOffsetX = MovableAreaLayout.width - scaledWidth - left;
196
- let xMin, xMax, yMin, yMax;
197
- if (MovableAreaLayout.width < scaledWidth) {
198
- xMin = maxOffsetX;
199
- xMax = -left;
200
- }
201
- else {
202
- xMin = -left;
203
- xMax = maxOffsetX < 0 ? -left : maxOffsetX;
204
- }
205
- if (MovableAreaLayout.height < scaledHeight) {
206
- yMin = maxOffsetY;
207
- yMax = -top;
208
- }
209
- else {
210
- yMin = -top;
211
- yMax = maxOffsetY < 0 ? -top : maxOffsetY;
212
- }
213
- // 应用边界限制
214
- if (newOffsetX > xMax) {
215
- newOffsetX = xMax;
216
- }
217
- else if (newOffsetX < xMin) {
218
- newOffsetX = xMin;
219
- }
220
- if (newOffsetY > yMax) {
221
- newOffsetY = yMax;
222
- }
223
- else if (newOffsetY < yMin) {
224
- newOffsetY = yMin;
225
- }
226
- return { x: newOffsetX, y: newOffsetY };
227
- }, [MovableAreaLayout.height, MovableAreaLayout.width, style.position, style.top, style.left]);
228
- // 提取通用的缩放处理函数
229
- const handleScaleUpdate = useCallback((scaleInfo) => {
230
- 'worklet';
231
- if (disabled)
232
- return;
233
- // 判断缩放方向并计算新的缩放值
234
- const isZoomingIn = scaleInfo.scale > 1;
235
- const isZoomingOut = scaleInfo.scale < 1;
236
- let newScale;
237
- if (isZoomingIn) {
238
- // 放大:增加缩放值
239
- newScale = currentScale.value + (scaleInfo.scale - 1) * 0.5;
240
- }
241
- else if (isZoomingOut) {
242
- // 缩小:减少缩放值
243
- newScale = currentScale.value - (1 - scaleInfo.scale) * 0.5;
244
- }
245
- else {
246
- // 没有缩放变化
247
- newScale = currentScale.value;
248
- }
249
- // 限制缩放值在 scaleMin 和 scaleMax 之间
250
- newScale = Math.max(scaleMin, Math.min(scaleMax, newScale));
251
- // 只有当缩放值真正改变时才调整位置
252
- if (Math.abs(newScale - currentScale.value) > 0.01) {
253
- // 获取元素尺寸
254
- const { width = 0, height = 0 } = layoutValue.value;
255
- if (width > 0 && height > 0) {
256
- // 使用通用的边界计算函数
257
- const { x: newOffsetX, y: newOffsetY } = calculateScaleBoundaryPosition({
258
- currentOffsetX: offsetX.value,
259
- currentOffsetY: offsetY.value,
260
- newScale,
261
- width,
262
- height
263
- });
264
- offsetX.value = newOffsetX;
265
- offsetY.value = newOffsetY;
266
- // 更新缩放值
267
- currentScale.value = newScale;
268
- }
269
- }
270
- else {
271
- currentScale.value = newScale;
272
- }
273
- if (bindscale) {
274
- runOnJS(handleTriggerScale)({
275
- x: offsetX.value,
276
- y: offsetY.value,
277
- scale: newScale
278
- });
279
- }
280
- }, [disabled, scaleMin, scaleMax, bindscale, handleTriggerScale, calculateScaleBoundaryPosition, style.position, style.top, style.left, MovableAreaLayout.height, MovableAreaLayout.width]);
281
142
  useEffect(() => {
282
- runOnUI(() => {
283
- if (currentScale.value !== scaleValue) {
284
- // 限制缩放值在 scaleMin 和 scaleMax 之间
285
- const clampedScale = Math.max(scaleMin, Math.min(scaleMax, scaleValue));
286
- // 实现中心缩放的位置补偿
287
- const { width = 0, height = 0 } = layoutValue.value;
288
- if (width > 0 && height > 0) {
289
- // 使用通用的边界计算函数
290
- const { x: newOffsetX, y: newOffsetY } = calculateScaleBoundaryPosition({
291
- currentOffsetX: offsetX.value,
292
- currentOffsetY: offsetY.value,
293
- newScale: clampedScale,
294
- width,
295
- height
296
- });
297
- // 同时更新缩放值和位置
298
- if (animation) {
299
- currentScale.value = withTiming(clampedScale, {
300
- duration: 1000
301
- }, () => {
302
- handleRestBoundaryAndCheck();
303
- });
304
- offsetX.value = withTiming(newOffsetX, { duration: 1000 });
305
- offsetY.value = withTiming(newOffsetY, { duration: 1000 });
306
- }
307
- else {
308
- currentScale.value = clampedScale;
309
- offsetX.value = newOffsetX;
310
- offsetY.value = newOffsetY;
311
- handleRestBoundaryAndCheck();
312
- }
313
- }
314
- else {
315
- // 如果还没有尺寸信息,只更新缩放值
316
- if (animation) {
317
- currentScale.value = withTiming(clampedScale, {
318
- duration: 1000
319
- }, () => {
320
- handleRestBoundaryAndCheck();
321
- });
322
- }
323
- else {
324
- currentScale.value = clampedScale;
325
- handleRestBoundaryAndCheck();
326
- }
327
- }
328
- if (bindscale) {
329
- runOnJS(handleTriggerScale)({
330
- x: offsetX.value,
331
- y: offsetY.value,
332
- scale: clampedScale
333
- });
334
- }
335
- }
336
- })();
337
- }, [scaleValue, scaleMin, scaleMax, animation]);
338
- useEffect(() => {
339
- runOnUI(handleRestBoundaryAndCheck)();
340
- }, [MovableAreaLayout.height, MovableAreaLayout.width]);
341
- // 生成唯一 ID
342
- const viewId = useMemo(() => `movable-view-${Date.now()}-${Math.random()}`, []);
343
- // 注册到 MovableArea(如果启用了 scale-area)
344
- useEffect(() => {
345
- if (MovableAreaLayout.scaleArea && MovableAreaLayout.registerMovableView && MovableAreaLayout.unregisterMovableView) {
346
- const handleAreaScale = (scaleInfo) => {
347
- 'worklet';
348
- handleScaleUpdate({ scale: scaleInfo.scale });
349
- };
350
- const handleAreaScaleEnd = () => {
351
- 'worklet';
352
- handleRestBoundaryAndCheck();
353
- };
354
- MovableAreaLayout.registerMovableView?.(viewId, {
355
- onScale: scale ? handleAreaScale : noop,
356
- onScaleEnd: scale ? handleAreaScaleEnd : noop
357
- });
358
- return () => {
359
- MovableAreaLayout.unregisterMovableView?.(viewId);
360
- };
143
+ const { width, height } = layoutRef.current;
144
+ if (width && height) {
145
+ resetBoundaryAndCheck({ width, height });
361
146
  }
362
- }, [MovableAreaLayout.scaleArea, viewId, scale, handleScaleUpdate]);
147
+ }, [MovableAreaLayout.height, MovableAreaLayout.width]);
363
148
  const getTouchSource = useCallback((offsetX, offsetY) => {
364
149
  const hasOverBoundary = offsetX < draggableXRange.value[0] || offsetX > draggableXRange.value[1] ||
365
150
  offsetY < draggableYRange.value[0] || offsetY > draggableYRange.value[1];
@@ -384,45 +169,61 @@ const _MovableView = forwardRef((movableViewProps, ref) => {
384
169
  return source;
385
170
  }, []);
386
171
  const setBoundary = useCallback(({ width, height }) => {
387
- 'worklet';
388
172
  const top = (style.position === 'absolute' && style.top) || 0;
389
173
  const left = (style.position === 'absolute' && style.left) || 0;
390
- // 使用左上角缩放,计算offset位置的边界范围
391
- const currentScaleVal = currentScale.value;
392
- const scaledWidth = (width || 0) * currentScaleVal;
393
- const scaledHeight = (height || 0) * currentScaleVal;
394
- // offset位置的边界:左上角可以移动的范围
395
- const maxOffsetY = MovableAreaLayout.height - scaledHeight - top;
396
- const maxOffsetX = MovableAreaLayout.width - scaledWidth - left;
174
+ const scaledWidth = width || 0;
175
+ const scaledHeight = height || 0;
176
+ const maxY = MovableAreaLayout.height - scaledHeight - top;
177
+ const maxX = MovableAreaLayout.width - scaledWidth - left;
397
178
  let xRange;
398
179
  let yRange;
399
180
  if (MovableAreaLayout.width < scaledWidth) {
400
- xRange = [maxOffsetX, -left];
181
+ xRange = [maxX, 0];
401
182
  }
402
183
  else {
403
- xRange = [-left, maxOffsetX < 0 ? -left : maxOffsetX];
184
+ xRange = [left === 0 ? 0 : -left, maxX < 0 ? 0 : maxX];
404
185
  }
405
186
  if (MovableAreaLayout.height < scaledHeight) {
406
- yRange = [maxOffsetY, -top];
187
+ yRange = [maxY, 0];
407
188
  }
408
189
  else {
409
- yRange = [-top, maxOffsetY < 0 ? -top : maxOffsetY];
190
+ yRange = [top === 0 ? 0 : -top, maxY < 0 ? 0 : maxY];
410
191
  }
411
192
  draggableXRange.value = xRange;
412
193
  draggableYRange.value = yRange;
413
194
  }, [MovableAreaLayout.height, MovableAreaLayout.width, style.position, style.top, style.left]);
414
- const resetBoundaryAndCheck = ({ width, height }) => {
195
+ const checkBoundaryPosition = useCallback(({ positionX, positionY }) => {
415
196
  'worklet';
416
- setBoundary({ width, height });
417
- const positionX = offsetX.value;
418
- const positionY = offsetY.value;
419
- const { x: newX, y: newY } = checkBoundaryPosition({ positionX, positionY });
420
- if (positionX !== newX) {
421
- offsetX.value = newX;
197
+ let x = positionX;
198
+ let y = positionY;
199
+ // 计算边界限制
200
+ if (x > draggableXRange.value[1]) {
201
+ x = draggableXRange.value[1];
422
202
  }
423
- if (positionY !== newY) {
424
- offsetY.value = newY;
203
+ else if (x < draggableXRange.value[0]) {
204
+ x = draggableXRange.value[0];
205
+ }
206
+ if (y > draggableYRange.value[1]) {
207
+ y = draggableYRange.value[1];
208
+ }
209
+ else if (y < draggableYRange.value[0]) {
210
+ y = draggableYRange.value[0];
425
211
  }
212
+ return { x, y };
213
+ }, []);
214
+ const resetBoundaryAndCheck = ({ width, height }) => {
215
+ setBoundary({ width, height });
216
+ runOnUI(() => {
217
+ const positionX = offsetX.value;
218
+ const positionY = offsetY.value;
219
+ const { x: newX, y: newY } = checkBoundaryPosition({ positionX, positionY });
220
+ if (positionX !== newX) {
221
+ offsetX.value = newX;
222
+ }
223
+ if (positionY !== newY) {
224
+ offsetY.value = newY;
225
+ }
226
+ })();
426
227
  };
427
228
  const onLayout = (e) => {
428
229
  hasLayoutRef.current = true;
@@ -432,20 +233,15 @@ const _MovableView = forwardRef((movableViewProps, ref) => {
432
233
  setHeight(height || 0);
433
234
  }
434
235
  nodeRef.current?.measure((x, y, width, height) => {
435
- const { y: navigationY = 0 } = navigation?.layout || {};
236
+ const { top: navigationY = 0 } = navigation?.layout || {};
436
237
  layoutRef.current = { x, y: y - navigationY, width, height, offsetLeft: 0, offsetTop: 0 };
437
- // 同时更新 layoutValue,供缩放逻辑使用
438
- runOnUI(() => {
439
- layoutValue.value = { width, height };
440
- resetBoundaryAndCheck({ width: width, height: height });
441
- })();
238
+ resetBoundaryAndCheck({ width, height });
442
239
  });
443
- propsOnLayout && propsOnLayout(e);
240
+ props.onLayout && props.onLayout(e);
444
241
  };
445
242
  const extendEvent = useCallback((e, type) => {
446
- const { y: navigationY = 0 } = navigation?.layout || {};
243
+ const { top: navigationY = 0 } = navigation?.layout || {};
447
244
  const touchArr = [e.changedTouches, e.allTouches];
448
- const currentProps = propsRef.current;
449
245
  touchArr.forEach(touches => {
450
246
  touches && touches.forEach((item) => {
451
247
  item.pageX = item.absoluteX;
@@ -457,8 +253,8 @@ const _MovableView = forwardRef((movableViewProps, ref) => {
457
253
  Object.assign(e, {
458
254
  touches: type === 'end' ? [] : e.allTouches,
459
255
  currentTarget: {
460
- id: currentProps.id || '',
461
- dataset: collectDataset(currentProps),
256
+ id: props.id || '',
257
+ dataset: collectDataset(props),
462
258
  offsetLeft: 0,
463
259
  offsetTop: 0
464
260
  },
@@ -499,13 +295,6 @@ const _MovableView = forwardRef((movableViewProps, ref) => {
499
295
  bindtouchend && bindtouchend(e);
500
296
  catchtouchend && catchtouchend(e);
501
297
  };
502
- const handleRestBoundaryAndCheck = () => {
503
- 'worklet';
504
- const { width, height } = layoutValue.value;
505
- if (width && height) {
506
- resetBoundaryAndCheck({ width, height });
507
- }
508
- };
509
298
  const gesture = useMemo(() => {
510
299
  const handleTriggerMove = (e) => {
511
300
  'worklet';
@@ -521,8 +310,6 @@ const _MovableView = forwardRef((movableViewProps, ref) => {
521
310
  }
522
311
  };
523
312
  const gesturePan = Gesture.Pan()
524
- .minPointers(1)
525
- .maxPointers(1)
526
313
  .onTouchesDown((e) => {
527
314
  'worklet';
528
315
  const changedTouches = e.changedTouches[0] || { x: 0, y: 0 };
@@ -662,13 +449,11 @@ const _MovableView = forwardRef((movableViewProps, ref) => {
662
449
  }
663
450
  })
664
451
  .withRef(movableGestureRef);
665
- if (!disableEventPassthrough) {
666
- if (direction === 'horizontal') {
667
- gesturePan.activeOffsetX([-5, 5]).failOffsetY([-5, 5]);
668
- }
669
- else if (direction === 'vertical') {
670
- gesturePan.activeOffsetY([-5, 5]).failOffsetX([-5, 5]);
671
- }
452
+ if (direction === 'horizontal') {
453
+ gesturePan.activeOffsetX([-5, 5]).failOffsetY([-5, 5]);
454
+ }
455
+ else if (direction === 'vertical') {
456
+ gesturePan.activeOffsetY([-5, 5]).failOffsetX([-5, 5]);
672
457
  }
673
458
  if (simultaneousHandlers && simultaneousHandlers.length) {
674
459
  gesturePan.simultaneousWithExternalGesture(...simultaneousHandlers);
@@ -676,43 +461,13 @@ const _MovableView = forwardRef((movableViewProps, ref) => {
676
461
  if (waitForHandlers && waitForHandlers.length) {
677
462
  gesturePan.requireExternalGestureToFail(...waitForHandlers);
678
463
  }
679
- // 添加缩放手势支持
680
- if (scale && !MovableAreaLayout.scaleArea) {
681
- const gesturePinch = Gesture.Pinch()
682
- .onUpdate((e) => {
683
- 'worklet';
684
- handleScaleUpdate({ scale: e.scale });
685
- })
686
- .onEnd((e) => {
687
- 'worklet';
688
- if (disabled)
689
- return;
690
- // 确保最终缩放值在有效范围内
691
- const finalScale = Math.max(scaleMin, Math.min(scaleMax, currentScale.value));
692
- if (finalScale !== currentScale.value) {
693
- currentScale.value = finalScale;
694
- if (bindscale) {
695
- runOnJS(handleTriggerScale)({
696
- x: offsetX.value,
697
- y: offsetY.value,
698
- scale: finalScale
699
- });
700
- }
701
- }
702
- // 缩放结束后重新检查边界
703
- handleRestBoundaryAndCheck();
704
- });
705
- // 根据手指数量自动区分手势:一指移动,两指缩放
706
- return Gesture.Exclusive(gesturePan, gesturePinch);
707
- }
708
464
  return gesturePan;
709
- }, [disabled, direction, inertia, outOfBounds, scale, scaleMin, scaleMax, animation, gestureSwitch.current, handleScaleUpdate, MovableAreaLayout.scaleArea]);
465
+ }, [disabled, direction, inertia, outOfBounds, gestureSwitch.current]);
710
466
  const animatedStyles = useAnimatedStyle(() => {
711
467
  return {
712
468
  transform: [
713
469
  { translateX: offsetX.value },
714
- { translateY: offsetY.value },
715
- { scale: currentScale.value }
470
+ { translateY: offsetY.value }
716
471
  ]
717
472
  };
718
473
  });
@@ -749,7 +504,7 @@ const _MovableView = forwardRef((movableViewProps, ref) => {
749
504
  const innerProps = useInnerProps(extendObject({}, filterProps, {
750
505
  ref: nodeRef,
751
506
  onLayout: onLayout,
752
- style: [{ transformOrigin: 'top left' }, innerStyle, animatedStyles, layoutStyle]
507
+ style: [innerStyle, animatedStyles, layoutStyle]
753
508
  }, rewriteCatchEvent()));
754
509
  return createElement(GestureDetector, { gesture: gesture }, createElement(Animated.View, innerProps, wrapChildren(props, {
755
510
  hasVarDec,