@mpxjs/webpack-plugin 2.10.5 → 2.10.6-beta.1

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 (81) hide show
  1. package/lib/index.js +16 -6
  2. package/lib/json-compiler/helper.js +1 -4
  3. package/lib/platform/json/wx/index.js +0 -1
  4. package/lib/platform/template/wx/component-config/button.js +1 -1
  5. package/lib/platform/template/wx/component-config/index.js +5 -1
  6. package/lib/platform/template/wx/component-config/input.js +1 -1
  7. package/lib/platform/template/wx/component-config/sticky-header.js +23 -0
  8. package/lib/platform/template/wx/component-config/sticky-section.js +23 -0
  9. package/lib/platform/template/wx/index.js +21 -1
  10. package/lib/react/processJSON.js +7 -6
  11. package/lib/resolver/PackageEntryPlugin.js +3 -1
  12. package/lib/runtime/components/react/context.ts +12 -3
  13. package/lib/runtime/components/react/dist/context.js +4 -1
  14. package/lib/runtime/components/react/dist/mpx-button.jsx +9 -4
  15. package/lib/runtime/components/react/dist/mpx-canvas/Image.js +2 -4
  16. package/lib/runtime/components/react/dist/mpx-canvas/index.jsx +20 -17
  17. package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +7 -2
  18. package/lib/runtime/components/react/dist/mpx-checkbox.jsx +7 -2
  19. package/lib/runtime/components/react/dist/mpx-icon/index.jsx +7 -2
  20. package/lib/runtime/components/react/dist/mpx-image.jsx +9 -2
  21. package/lib/runtime/components/react/dist/mpx-input.jsx +7 -2
  22. package/lib/runtime/components/react/dist/mpx-keyboard-avoiding-view.jsx +1 -1
  23. package/lib/runtime/components/react/dist/mpx-label.jsx +7 -2
  24. package/lib/runtime/components/react/dist/mpx-movable-area.jsx +8 -3
  25. package/lib/runtime/components/react/dist/mpx-movable-view.jsx +100 -62
  26. package/lib/runtime/components/react/dist/mpx-picker/index.jsx +11 -13
  27. package/lib/runtime/components/react/dist/mpx-picker-view/index.jsx +8 -7
  28. package/lib/runtime/components/react/dist/mpx-picker-view-column/index.jsx +26 -8
  29. package/lib/runtime/components/react/dist/mpx-radio-group.jsx +9 -2
  30. package/lib/runtime/components/react/dist/mpx-radio.jsx +7 -2
  31. package/lib/runtime/components/react/dist/mpx-rich-text/index.jsx +7 -2
  32. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +30 -10
  33. package/lib/runtime/components/react/dist/mpx-sticky-header.jsx +115 -0
  34. package/lib/runtime/components/react/dist/mpx-sticky-section.jsx +45 -0
  35. package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +11 -9
  36. package/lib/runtime/components/react/dist/mpx-swiper.jsx +82 -36
  37. package/lib/runtime/components/react/dist/mpx-switch.jsx +7 -2
  38. package/lib/runtime/components/react/dist/mpx-text.jsx +7 -2
  39. package/lib/runtime/components/react/dist/mpx-video.jsx +7 -2
  40. package/lib/runtime/components/react/dist/mpx-view.jsx +2 -4
  41. package/lib/runtime/components/react/dist/mpx-web-view.jsx +13 -13
  42. package/lib/runtime/components/react/dist/utils.jsx +14 -3
  43. package/lib/runtime/components/react/mpx-button.tsx +12 -3
  44. package/lib/runtime/components/react/mpx-canvas/Image.ts +4 -4
  45. package/lib/runtime/components/react/mpx-canvas/index.tsx +24 -17
  46. package/lib/runtime/components/react/mpx-checkbox-group.tsx +9 -1
  47. package/lib/runtime/components/react/mpx-checkbox.tsx +9 -1
  48. package/lib/runtime/components/react/mpx-icon/index.tsx +9 -1
  49. package/lib/runtime/components/react/mpx-image.tsx +38 -19
  50. package/lib/runtime/components/react/mpx-input.tsx +10 -1
  51. package/lib/runtime/components/react/mpx-keyboard-avoiding-view.tsx +1 -1
  52. package/lib/runtime/components/react/mpx-label.tsx +9 -1
  53. package/lib/runtime/components/react/mpx-movable-area.tsx +8 -2
  54. package/lib/runtime/components/react/mpx-movable-view.tsx +100 -62
  55. package/lib/runtime/components/react/mpx-picker/index.tsx +18 -16
  56. package/lib/runtime/components/react/mpx-picker-view/index.tsx +22 -8
  57. package/lib/runtime/components/react/mpx-picker-view-column/index.tsx +34 -30
  58. package/lib/runtime/components/react/mpx-radio-group.tsx +20 -9
  59. package/lib/runtime/components/react/mpx-radio.tsx +9 -1
  60. package/lib/runtime/components/react/mpx-rich-text/index.tsx +10 -2
  61. package/lib/runtime/components/react/mpx-scroll-view.tsx +82 -53
  62. package/lib/runtime/components/react/mpx-sticky-header.tsx +179 -0
  63. package/lib/runtime/components/react/mpx-sticky-section.tsx +96 -0
  64. package/lib/runtime/components/react/mpx-swiper-item.tsx +11 -19
  65. package/lib/runtime/components/react/mpx-swiper.tsx +95 -38
  66. package/lib/runtime/components/react/mpx-switch.tsx +10 -2
  67. package/lib/runtime/components/react/mpx-text.tsx +10 -2
  68. package/lib/runtime/components/react/mpx-video.tsx +7 -2
  69. package/lib/runtime/components/react/mpx-view.tsx +8 -4
  70. package/lib/runtime/components/react/mpx-web-view.tsx +12 -12
  71. package/lib/runtime/components/react/utils.tsx +16 -5
  72. package/lib/runtime/components/web/mpx-scroll-view.vue +21 -4
  73. package/lib/runtime/components/web/mpx-sticky-header.vue +91 -0
  74. package/lib/runtime/components/web/mpx-sticky-section.vue +15 -0
  75. package/lib/runtime/components/web/mpx-web-view.vue +1 -1
  76. package/lib/runtime/mpxGlobal.js +1 -0
  77. package/lib/runtime/optionProcessor.d.ts +5 -0
  78. package/lib/template-compiler/bind-this.js +8 -7
  79. package/lib/wxs/pre-loader.js +1 -0
  80. package/package.json +4 -4
  81. package/LICENSE +0 -433
@@ -32,16 +32,20 @@
32
32
  * ✔ bindscroll
33
33
  */
34
34
  import { ScrollView, RefreshControl, Gesture, GestureDetector } from 'react-native-gesture-handler';
35
+ import { Animated as RNAnimated } from 'react-native';
35
36
  import { isValidElement, Children, useRef, useState, useEffect, forwardRef, useContext, useMemo, createElement } from 'react';
36
37
  import Animated, { useAnimatedRef, useSharedValue, withTiming, useAnimatedStyle, runOnJS } from 'react-native-reanimated';
37
- import { warn } from '@mpxjs/utils';
38
+ import { warn, hasOwn } from '@mpxjs/utils';
38
39
  import useInnerProps, { getCustomEvent } from './getInnerListeners';
39
40
  import useNodesRef from './useNodesRef';
40
41
  import { splitProps, splitStyle, useTransformStyle, useLayout, wrapChildren, extendObject, flatGesture, HIDDEN_STYLE } from './utils';
41
42
  import { IntersectionObserverContext, ScrollViewContext } from './context';
43
+ import Portal from './mpx-portal';
44
+ const AnimatedScrollView = RNAnimated.createAnimatedComponent(ScrollView);
42
45
  const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
43
46
  const { textProps, innerProps: props = {} } = splitProps(scrollViewProps);
44
- const { enhanced = false, bounces = true, style = {}, binddragstart, binddragging, binddragend, bindtouchstart, bindtouchmove, bindtouchend, 'scroll-x': scrollX = false, 'scroll-y': scrollY = false, 'enable-back-to-top': enableBackToTop = false, 'enable-trigger-intersection-observer': enableTriggerIntersectionObserver = false, 'paging-enabled': pagingEnabled = false, 'upper-threshold': upperThreshold = 50, 'lower-threshold': lowerThreshold = 50, 'scroll-with-animation': scrollWithAnimation = false, 'refresher-enabled': refresherEnabled, 'refresher-default-style': refresherDefaultStyle, 'refresher-background': refresherBackground, 'refresher-threshold': refresherThreshold = 45, 'show-scrollbar': showScrollbar = true, 'scroll-into-view': scrollIntoView = '', 'scroll-top': scrollTop = 0, 'scroll-left': scrollLeft = 0, 'refresher-triggered': refresherTriggered, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, 'simultaneous-handlers': originSimultaneousHandlers, 'wait-for': waitFor, 'scroll-event-throttle': scrollEventThrottle = 0, __selectRef } = props;
47
+ const { enhanced = false, bounces = true, style = {}, binddragstart, binddragging, binddragend, bindtouchstart, bindtouchmove, bindtouchend, 'scroll-x': scrollX = false, 'scroll-y': scrollY = false, 'enable-back-to-top': enableBackToTop = false, 'enable-trigger-intersection-observer': enableTriggerIntersectionObserver = false, 'paging-enabled': pagingEnabled = false, 'upper-threshold': upperThreshold = 50, 'lower-threshold': lowerThreshold = 50, 'scroll-with-animation': scrollWithAnimation = false, 'refresher-enabled': refresherEnabled, 'refresher-default-style': refresherDefaultStyle, 'refresher-background': refresherBackground, 'refresher-threshold': refresherThreshold = 45, 'show-scrollbar': showScrollbar = true, 'scroll-into-view': scrollIntoView = '', 'scroll-top': scrollTop = 0, 'scroll-left': scrollLeft = 0, 'refresher-triggered': refresherTriggered, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, 'simultaneous-handlers': originSimultaneousHandlers, 'wait-for': waitFor, 'enable-sticky': enableSticky, 'scroll-event-throttle': scrollEventThrottle = 0, __selectRef } = props;
48
+ const scrollOffset = useRef(new RNAnimated.Value(0)).current;
45
49
  const simultaneousHandlers = flatGesture(originSimultaneousHandlers);
46
50
  const waitForHandlers = flatGesture(waitFor);
47
51
  const snapScrollTop = useRef(0);
@@ -72,7 +76,7 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
72
76
  };
73
77
  const { refresherContent, otherContent } = getRefresherContent(props.children);
74
78
  const hasRefresher = refresherContent && refresherEnabled;
75
- const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, setWidth, setHeight } = useTransformStyle(style, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
79
+ const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, hasPositionFixed, setWidth, setHeight } = useTransformStyle(style, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
76
80
  const { textStyle, innerStyle = {} } = splitStyle(normalStyle);
77
81
  const scrollViewRef = useAnimatedRef();
78
82
  useNodesRef(props, ref, scrollViewRef, {
@@ -89,12 +93,13 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
89
93
  },
90
94
  gestureRef: scrollViewRef
91
95
  });
96
+ const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: scrollViewRef, onLayout });
92
97
  const contextValue = useMemo(() => {
93
98
  return {
94
- gestureRef: scrollViewRef
99
+ gestureRef: scrollViewRef,
100
+ scrollOffset
95
101
  };
96
102
  }, []);
97
- const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: scrollViewRef, onLayout });
98
103
  const hasRefresherLayoutRef = useRef(false);
99
104
  // layout 完成前先隐藏,避免安卓闪烁问题
100
105
  const refresherLayoutStyle = useMemo(() => { return !hasRefresherLayoutRef.current ? HIDDEN_STYLE : {}; }, [hasRefresherLayoutRef.current]);
@@ -320,6 +325,12 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
320
325
  updateScrollOptions(e, { scrollLeft, scrollTop });
321
326
  updateIntersection();
322
327
  }
328
+ const scrollHandler = RNAnimated.event([{ nativeEvent: { contentOffset: { y: scrollOffset } } }], {
329
+ useNativeDriver: true,
330
+ listener: (event) => {
331
+ onScroll(event);
332
+ }
333
+ });
323
334
  function onScrollDragStart(e) {
324
335
  hasCallScrollToLower.current = false;
325
336
  hasCallScrollToUpper.current = false;
@@ -464,7 +475,11 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
464
475
  })
465
476
  .simultaneousWithExternalGesture(scrollViewRef);
466
477
  const scrollAdditionalProps = extendObject({
467
- style: extendObject({}, innerStyle, layoutStyle),
478
+ style: extendObject(hasOwn(innerStyle, 'flex') || hasOwn(innerStyle, 'flexGrow')
479
+ ? {}
480
+ : {
481
+ flexGrow: 0
482
+ }, innerStyle, layoutStyle),
468
483
  pinchGestureEnabled: false,
469
484
  alwaysBounceVertical: false,
470
485
  alwaysBounceHorizontal: false,
@@ -476,7 +491,7 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
476
491
  scrollEnabled: !enableScroll ? false : !!(scrollX || scrollY),
477
492
  bounces: false,
478
493
  ref: scrollViewRef,
479
- onScroll: onScroll,
494
+ onScroll: enableSticky ? scrollHandler : onScroll,
480
495
  onContentSizeChange: onContentSizeChange,
481
496
  bindtouchstart: ((enhanced && binddragstart) || bindtouchstart) && onScrollTouchStart,
482
497
  bindtouchmove: ((enhanced && binddragging) || bindtouchmove) && onScrollTouchMove,
@@ -518,13 +533,14 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
518
533
  'bindscrolltolower',
519
534
  'bindrefresherrefresh'
520
535
  ], { layoutRef });
521
- const withRefresherScrollView = createElement(GestureDetector, { gesture: panGesture }, createElement(ScrollView, innerProps, createElement(Animated.View, { style: [refresherAnimatedStyle, refresherLayoutStyle], onLayout: onRefresherLayout }, refresherContent), createElement(Animated.View, { style: contentAnimatedStyle }, createElement(ScrollViewContext.Provider, { value: contextValue }, wrapChildren(extendObject({}, props, { children: otherContent }), {
536
+ const ScrollViewComponent = enableSticky ? AnimatedScrollView : ScrollView;
537
+ const withRefresherScrollView = createElement(GestureDetector, { gesture: panGesture }, createElement(ScrollViewComponent, innerProps, createElement(Animated.View, { style: [refresherAnimatedStyle, refresherLayoutStyle], onLayout: onRefresherLayout }, refresherContent), createElement(Animated.View, { style: contentAnimatedStyle }, createElement(ScrollViewContext.Provider, { value: contextValue }, wrapChildren(extendObject({}, props, { children: otherContent }), {
522
538
  hasVarDec,
523
539
  varContext: varContextRef.current,
524
540
  textStyle,
525
541
  textProps
526
542
  })))));
527
- const commonScrollView = createElement(ScrollView, extendObject(innerProps, {
543
+ const commonScrollView = createElement(ScrollViewComponent, extendObject({}, innerProps, {
528
544
  refreshControl: refresherEnabled
529
545
  ? createElement(RefreshControl, extendObject({
530
546
  progressBackgroundColor: refresherBackground,
@@ -540,7 +556,11 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
540
556
  textStyle,
541
557
  textProps
542
558
  })));
543
- return hasRefresher ? withRefresherScrollView : commonScrollView;
559
+ let scrollViewComponent = hasRefresher ? withRefresherScrollView : commonScrollView;
560
+ if (hasPositionFixed) {
561
+ scrollViewComponent = createElement(Portal, null, scrollViewComponent);
562
+ }
563
+ return scrollViewComponent;
544
564
  });
545
565
  _ScrollView.displayName = 'MpxScrollView';
546
566
  export default _ScrollView;
@@ -0,0 +1,115 @@
1
+ import { useEffect, useRef, useContext, forwardRef, useMemo, createElement, useId } from 'react';
2
+ import { Animated, StyleSheet, useAnimatedValue } from 'react-native';
3
+ import { ScrollViewContext, StickyContext } from './context';
4
+ import useNodesRef from './useNodesRef';
5
+ import { splitProps, splitStyle, useTransformStyle, wrapChildren, useLayout, extendObject } from './utils';
6
+ import { error } from '@mpxjs/utils';
7
+ import useInnerProps, { getCustomEvent } from './getInnerListeners';
8
+ const _StickyHeader = forwardRef((stickyHeaderProps = {}, ref) => {
9
+ const { textProps, innerProps: props = {} } = splitProps(stickyHeaderProps);
10
+ const { style, bindstickontopchange, padding = [0, 0, 0, 0], 'offset-top': offsetTop = 0, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight } = props;
11
+ const scrollViewContext = useContext(ScrollViewContext);
12
+ const stickyContext = useContext(StickyContext);
13
+ const { scrollOffset } = scrollViewContext;
14
+ const { registerStickyHeader, unregisterStickyHeader } = stickyContext;
15
+ const headerRef = useRef(null);
16
+ const isStickOnTopRef = useRef(false);
17
+ const id = useId();
18
+ const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, setWidth, setHeight } = useTransformStyle(style, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
19
+ const { layoutRef, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: headerRef, onLayout });
20
+ const { textStyle, innerStyle = {} } = splitStyle(normalStyle);
21
+ const headerTopAnimated = useAnimatedValue(0);
22
+ // harmony animatedValue 不支持通过 _value 访问
23
+ const headerTopRef = useRef(0);
24
+ useEffect(() => {
25
+ registerStickyHeader({ key: id, updatePosition });
26
+ return () => {
27
+ unregisterStickyHeader(id);
28
+ };
29
+ }, []);
30
+ function updatePosition() {
31
+ if (headerRef.current) {
32
+ const scrollViewRef = scrollViewContext.gestureRef;
33
+ if (scrollViewRef && scrollViewRef.current) {
34
+ headerRef.current.measureLayout(scrollViewRef.current, (left, top) => {
35
+ Animated.timing(headerTopAnimated, {
36
+ toValue: top,
37
+ duration: 0,
38
+ useNativeDriver: true
39
+ }).start();
40
+ headerTopRef.current = top;
41
+ });
42
+ }
43
+ else {
44
+ error('StickyHeader measureLayout error: scrollViewRef is not a valid native component reference');
45
+ }
46
+ }
47
+ }
48
+ function onLayout(e) {
49
+ updatePosition();
50
+ }
51
+ useNodesRef(props, ref, headerRef, {
52
+ style: normalStyle
53
+ });
54
+ useEffect(() => {
55
+ if (!bindstickontopchange)
56
+ return;
57
+ const listener = scrollOffset.addListener((state) => {
58
+ const currentScrollValue = state.value;
59
+ const newIsStickOnTop = currentScrollValue > headerTopRef.current;
60
+ if (newIsStickOnTop !== isStickOnTopRef.current) {
61
+ isStickOnTopRef.current = newIsStickOnTop;
62
+ bindstickontopchange(getCustomEvent('stickontopchange', {}, {
63
+ detail: {
64
+ isStickOnTop: newIsStickOnTop
65
+ },
66
+ layoutRef
67
+ }, props));
68
+ }
69
+ });
70
+ return () => {
71
+ scrollOffset.removeListener(listener);
72
+ };
73
+ }, []);
74
+ const animatedStyle = useMemo(() => {
75
+ const translateY = Animated.subtract(scrollOffset, headerTopAnimated).interpolate({
76
+ inputRange: [0, 1],
77
+ outputRange: [0, 1],
78
+ extrapolateLeft: 'clamp',
79
+ extrapolateRight: 'extend'
80
+ });
81
+ const finalTranslateY = offsetTop === 0
82
+ ? translateY
83
+ : Animated.add(translateY, Animated.subtract(scrollOffset, headerTopAnimated).interpolate({
84
+ inputRange: [0, 1],
85
+ outputRange: [0, offsetTop],
86
+ extrapolate: 'clamp'
87
+ }));
88
+ return {
89
+ transform: [{ translateY: finalTranslateY }]
90
+ };
91
+ }, [scrollOffset, headerTopAnimated, offsetTop]);
92
+ const innerProps = useInnerProps(extendObject({}, props, {
93
+ ref: headerRef,
94
+ style: extendObject({}, styles.content, innerStyle, animatedStyle, {
95
+ paddingTop: padding[0] || 0,
96
+ paddingRight: padding[1] || 0,
97
+ paddingBottom: padding[2] || 0,
98
+ paddingLeft: padding[3] || 0
99
+ })
100
+ }, layoutProps), [], { layoutRef });
101
+ return (createElement(Animated.View, innerProps, wrapChildren(props, {
102
+ hasVarDec,
103
+ varContext: varContextRef.current,
104
+ textStyle,
105
+ textProps
106
+ })));
107
+ });
108
+ const styles = StyleSheet.create({
109
+ content: {
110
+ width: '100%',
111
+ zIndex: 10
112
+ }
113
+ });
114
+ _StickyHeader.displayName = 'MpxStickyHeader';
115
+ export default _StickyHeader;
@@ -0,0 +1,45 @@
1
+ import { useRef, forwardRef, createElement, useCallback, useMemo } from 'react';
2
+ import { View } from 'react-native';
3
+ import useNodesRef from './useNodesRef';
4
+ import { splitProps, splitStyle, useTransformStyle, wrapChildren, useLayout, extendObject } from './utils';
5
+ import { StickyContext } from './context';
6
+ import useInnerProps from './getInnerListeners';
7
+ const _StickySection = forwardRef((stickySectionProps = {}, ref) => {
8
+ const { textProps, innerProps: props = {} } = splitProps(stickySectionProps);
9
+ const { style, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight } = props;
10
+ const sectionRef = useRef(null);
11
+ const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, setWidth, setHeight } = useTransformStyle(style, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
12
+ const { layoutRef, layoutProps, layoutStyle } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: sectionRef, onLayout });
13
+ const { textStyle, innerStyle = {} } = splitStyle(normalStyle);
14
+ const stickyHeaders = useRef(new Map());
15
+ const registerStickyHeader = useCallback((item) => {
16
+ stickyHeaders.current.set(item.id, item);
17
+ }, []);
18
+ const unregisterStickyHeader = useCallback((id) => {
19
+ stickyHeaders.current.delete(id);
20
+ }, []);
21
+ const contextValue = useMemo(() => ({
22
+ registerStickyHeader,
23
+ unregisterStickyHeader
24
+ }), []);
25
+ useNodesRef(props, ref, sectionRef, {
26
+ style: normalStyle
27
+ });
28
+ function onLayout() {
29
+ stickyHeaders.current.forEach(item => {
30
+ item.updatePosition();
31
+ });
32
+ }
33
+ const innerProps = useInnerProps(extendObject({}, props, {
34
+ style: extendObject(innerStyle, layoutStyle),
35
+ ref: sectionRef
36
+ }, layoutProps), [], { layoutRef });
37
+ return (createElement(View, innerProps, createElement(StickyContext.Provider, { value: contextValue }, wrapChildren(props, {
38
+ hasVarDec,
39
+ varContext: varContextRef.current,
40
+ textStyle,
41
+ textProps
42
+ }))));
43
+ });
44
+ _StickySection.displayName = 'MpxStickySection';
45
+ export default _StickySection;
@@ -1,5 +1,5 @@
1
1
  import Animated, { useAnimatedStyle, interpolate } from 'react-native-reanimated';
2
- import { forwardRef, useRef, useContext } from 'react';
2
+ import { forwardRef, useRef, useContext, createElement } from 'react';
3
3
  import useInnerProps from './getInnerListeners';
4
4
  import useNodesRef from './useNodesRef'; // 引入辅助函数
5
5
  import { useTransformStyle, splitStyle, splitProps, wrapChildren, useLayout, extendObject } from './utils';
@@ -45,14 +45,16 @@ const _SwiperItem = forwardRef((props, ref) => {
45
45
  transform: transformStyle
46
46
  });
47
47
  });
48
- return (<Animated.View {...innerProps} style={[innerStyle, layoutStyle, itemAnimatedStyle, customStyle]} data-itemId={props['item-id']}>
49
- {wrapChildren(props, {
50
- hasVarDec,
51
- varContext: varContextRef.current,
52
- textStyle,
53
- textProps
54
- })}
55
- </Animated.View>);
48
+ const mergeProps = extendObject({}, innerProps, {
49
+ style: [innerStyle, layoutStyle, itemAnimatedStyle, customStyle],
50
+ 'data-itemId': props['item-id']
51
+ });
52
+ return createElement(Animated.View, mergeProps, wrapChildren(props, {
53
+ hasVarDec,
54
+ varContext: varContextRef.current,
55
+ textStyle,
56
+ textProps
57
+ }));
56
58
  });
57
59
  _SwiperItem.displayName = 'MpxSwiperItem';
58
60
  export default _SwiperItem;
@@ -1,11 +1,12 @@
1
1
  import { View } from 'react-native';
2
2
  import { GestureDetector, Gesture } from 'react-native-gesture-handler';
3
3
  import Animated, { useAnimatedStyle, useSharedValue, withTiming, Easing, runOnJS, useAnimatedReaction, cancelAnimation } from 'react-native-reanimated';
4
- import React, { forwardRef, useRef, useEffect, useMemo } from 'react';
4
+ import React, { forwardRef, useRef, useEffect, useMemo, createElement } from 'react';
5
5
  import useInnerProps, { getCustomEvent } from './getInnerListeners';
6
6
  import useNodesRef from './useNodesRef'; // 引入辅助函数
7
- import { useTransformStyle, splitStyle, splitProps, useLayout, wrapChildren, extendObject } from './utils';
7
+ import { useTransformStyle, splitStyle, splitProps, useLayout, wrapChildren, extendObject, flatGesture } from './utils';
8
8
  import { SwiperContext } from './context';
9
+ import Portal from './mpx-portal';
9
10
  /**
10
11
  * 默认的Style类型
11
12
  */
@@ -70,14 +71,19 @@ const easeMap = {
70
71
  easeInOutCubic: Easing.inOut(Easing.cubic)
71
72
  };
72
73
  const SwiperWrapper = forwardRef((props, ref) => {
73
- const { 'indicator-dots': showsPagination, 'indicator-color': dotColor = 'rgba(0, 0, 0, .3)', 'indicator-active-color': activeDotColor = '#000000', 'enable-var': enableVar = false, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, 'external-var-context': externalVarContext, style = {}, autoplay = false, circular = false } = props;
74
+ const { 'indicator-dots': showPagination, 'indicator-color': dotColor = 'rgba(0, 0, 0, .3)', 'indicator-active-color': activeDotColor = '#000000', 'enable-var': enableVar = false, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, 'external-var-context': externalVarContext, 'simultaneous-handlers': originSimultaneousHandlers = [], 'wait-for': waitFor = [], style = {}, autoplay = false, circular = false, disableGesture = false } = props;
74
75
  const easeingFunc = props['easing-function'] || 'default';
75
76
  const easeDuration = props.duration || 500;
76
77
  const horizontal = props.vertical !== undefined ? !props.vertical : true;
77
78
  const nodeRef = useRef(null);
78
- useNodesRef(props, ref, nodeRef, {});
79
+ // 手势协同gesture 1.0
80
+ const swiperGestureRef = useRef();
81
+ useNodesRef(props, ref, nodeRef, {
82
+ // scrollView内部会过滤是否绑定了gestureRef,withRef(swiperGestureRef)给gesture对象设置一个ref(2.0版本)
83
+ gestureRef: swiperGestureRef
84
+ });
79
85
  // 计算transfrom之类的
80
- const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, setWidth, setHeight } = useTransformStyle(style, {
86
+ const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, hasPositionFixed, setWidth, setHeight } = useTransformStyle(style, {
81
87
  enableVar,
82
88
  externalVarContext,
83
89
  parentFontSize,
@@ -121,6 +127,23 @@ const SwiperWrapper = forwardRef((props, ref) => {
121
127
  const moveTime = useSharedValue(0);
122
128
  const timerId = useRef(0);
123
129
  const intervalTimer = props.interval || 500;
130
+ const simultaneousHandlers = flatGesture(originSimultaneousHandlers);
131
+ const waitForHandlers = flatGesture(waitFor);
132
+ // 判断gesture手势是否需要协同处理、等待手势失败响应
133
+ const gestureSwitch = useRef(false);
134
+ // 初始化上一次的手势
135
+ const prevSimultaneousHandlersRef = useRef(originSimultaneousHandlers || []);
136
+ const prevWaitForHandlersRef = useRef(waitFor || []);
137
+ const hasSimultaneousHandlersChanged = prevSimultaneousHandlersRef.current.length !== (originSimultaneousHandlers?.length || 0) ||
138
+ (originSimultaneousHandlers || []).some((handler, index) => handler !== prevSimultaneousHandlersRef.current[index]);
139
+ const hasWaitForHandlersChanged = prevWaitForHandlersRef.current.length !== (waitFor?.length || 0) ||
140
+ (waitFor || []).some((handler, index) => handler !== prevWaitForHandlersRef.current[index]);
141
+ if (hasSimultaneousHandlersChanged || hasWaitForHandlersChanged) {
142
+ gestureSwitch.current = !gestureSwitch.current;
143
+ }
144
+ // 存储上一次的手势
145
+ prevSimultaneousHandlersRef.current = originSimultaneousHandlers || [];
146
+ prevWaitForHandlersRef.current = waitFor || [];
124
147
  const {
125
148
  // 存储layout布局信息
126
149
  layoutRef, layoutProps, layoutStyle } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef, onLayout: onWrapperLayout });
@@ -164,8 +187,6 @@ const SwiperWrapper = forwardRef((props, ref) => {
164
187
  }
165
188
  });
166
189
  function renderPagination() {
167
- if (children.length <= 1)
168
- return null;
169
190
  const activeColor = activeDotColor || '#007aff';
170
191
  const unActionColor = dotColor || 'rgba(0,0,0,.2)';
171
192
  // 正常渲染所有dots
@@ -490,6 +511,15 @@ const SwiperWrapper = forwardRef((props, ref) => {
490
511
  });
491
512
  }
492
513
  }
514
+ function handleBackInit() {
515
+ 'worklet';
516
+ // 微信的效果
517
+ // 1. 只有一个元素,即使设置了circular,也不会产生循环的效果,2. 可以响应手势,但是会有回弹的效果
518
+ offset.value = withTiming(0, {
519
+ duration: easeDuration,
520
+ easing: easeMap[easeingFunc]
521
+ });
522
+ }
493
523
  function handleBack(eventData) {
494
524
  'worklet';
495
525
  const { translation } = eventData;
@@ -596,7 +626,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
596
626
  return;
597
627
  }
598
628
  const { isBoundary, resetOffset } = reachBoundary(eventData);
599
- if (isBoundary && circularShared.value) {
629
+ if (childrenLength.value > 1 && isBoundary && circularShared.value) {
600
630
  offset.value = resetOffset;
601
631
  }
602
632
  else {
@@ -614,6 +644,9 @@ const SwiperWrapper = forwardRef((props, ref) => {
614
644
  const eventData = {
615
645
  translation: moveDistance
616
646
  };
647
+ if (childrenLength.value === 1) {
648
+ return handleBackInit();
649
+ }
617
650
  // 用户手指按下起来, 需要计算正确的位置, 比如在滑动过程中突然按下然后起来,需要计算到正确的位置
618
651
  if (!circularShared.value && !canMove(eventData)) {
619
652
  return;
@@ -625,11 +658,26 @@ const SwiperWrapper = forwardRef((props, ref) => {
625
658
  else {
626
659
  handleEnd(eventData);
627
660
  }
628
- });
661
+ })
662
+ .withRef(swiperGestureRef);
663
+ // swiper横向,当y轴滑动5像素手势失效;swiper纵向只响应swiper的滑动事件
664
+ if (dir === 'x') {
665
+ gesturePan.activeOffsetX([-2, 2]).failOffsetY([-5, 5]);
666
+ }
667
+ else {
668
+ gesturePan.activeOffsetY([-2, 2]).failOffsetX([-5, 5]);
669
+ }
670
+ // 手势协同2.0
671
+ if (simultaneousHandlers && simultaneousHandlers.length) {
672
+ gesturePan.simultaneousWithExternalGesture(...simultaneousHandlers);
673
+ }
674
+ if (waitForHandlers && waitForHandlers.length) {
675
+ gesturePan.requireExternalGestureToFail(...waitForHandlers);
676
+ }
629
677
  return {
630
678
  gestureHandler: gesturePan
631
679
  };
632
- }, []);
680
+ }, [gestureSwitch.current]);
633
681
  const animatedStyles = useAnimatedStyle(() => {
634
682
  if (dir === 'x') {
635
683
  return { transform: [{ translateX: offset.value }], opacity: step.value > 0 ? 1 : 0 };
@@ -638,34 +686,32 @@ const SwiperWrapper = forwardRef((props, ref) => {
638
686
  return { transform: [{ translateY: offset.value }], opacity: step.value > 0 ? 1 : 0 };
639
687
  }
640
688
  });
641
- function renderSwiper() {
642
- const arrPages = renderItems();
643
- return (<View style={[normalStyle, layoutStyle, styles.swiper]} {...layoutProps} {...innerProps}>
644
- <Animated.View style={[{
645
- flexDirection: dir === 'x' ? 'row' : 'column',
646
- width: '100%',
647
- height: '100%'
648
- }, animatedStyles]}>
649
- {wrapChildren({
650
- children: arrPages
651
- }, {
652
- hasVarDec,
653
- varContext: varContextRef.current,
654
- textStyle,
655
- textProps
656
- })}
657
- </Animated.View>
658
- {showsPagination && renderPagination()}
659
- </View>);
660
- }
661
- if (children.length === 1) {
662
- return renderSwiper();
689
+ let finalComponent;
690
+ const arrPages = renderItems();
691
+ const mergeProps = Object.assign({
692
+ style: [normalStyle, layoutStyle, styles.swiper]
693
+ }, layoutProps, innerProps);
694
+ const animateComponent = createElement(Animated.View, {
695
+ style: [{ flexDirection: dir === 'x' ? 'row' : 'column', width: '100%', height: '100%' }, animatedStyles]
696
+ }, wrapChildren({
697
+ children: arrPages
698
+ }, {
699
+ hasVarDec,
700
+ varContext: varContextRef.current,
701
+ textStyle,
702
+ textProps
703
+ }));
704
+ const renderChildrens = showPagination ? [animateComponent, renderPagination()] : animateComponent;
705
+ finalComponent = createElement(View, mergeProps, renderChildrens);
706
+ if (!disableGesture) {
707
+ finalComponent = createElement(GestureDetector, {
708
+ gesture: gestureHandler
709
+ }, finalComponent);
663
710
  }
664
- else {
665
- return (<GestureDetector gesture={gestureHandler}>
666
- {renderSwiper()}
667
- </GestureDetector>);
711
+ if (hasPositionFixed) {
712
+ finalComponent = createElement(Portal, null, finalComponent);
668
713
  }
714
+ return finalComponent;
669
715
  });
670
716
  SwiperWrapper.displayName = 'MpxSwiperWrapper';
671
717
  export default SwiperWrapper;
@@ -10,6 +10,7 @@ import { warn } from '@mpxjs/utils';
10
10
  import useNodesRef from './useNodesRef'; // 引入辅助函数
11
11
  import useInnerProps, { getCustomEvent } from './getInnerListeners';
12
12
  import CheckBox from './mpx-checkbox';
13
+ import Portal from './mpx-portal';
13
14
  import { FormContext } from './context';
14
15
  import { useTransformStyle, useLayout, extendObject } from './utils';
15
16
  const _Switch = forwardRef((props, ref) => {
@@ -21,7 +22,7 @@ const _Switch = forwardRef((props, ref) => {
21
22
  if (formContext) {
22
23
  formValuesMap = formContext.formValuesMap;
23
24
  }
24
- const { normalStyle, hasSelfPercent, setWidth, setHeight } = useTransformStyle(style, {
25
+ const { normalStyle, hasSelfPercent, setWidth, setHeight, hasPositionFixed } = useTransformStyle(style, {
25
26
  enableVar,
26
27
  externalVarContext,
27
28
  parentFontSize,
@@ -83,13 +84,17 @@ const _Switch = forwardRef((props, ref) => {
83
84
  checked: isChecked
84
85
  }));
85
86
  }
86
- return createElement(Switch, extendObject({}, innerProps, {
87
+ let finalComponent = createElement(Switch, extendObject({}, innerProps, {
87
88
  style: normalStyle,
88
89
  value: isChecked,
89
90
  trackColor: { false: '#FFF', true: color },
90
91
  thumbColor: isChecked ? '#FFF' : '#f4f3f4',
91
92
  ios_backgroundColor: '#FFF'
92
93
  }));
94
+ if (hasPositionFixed) {
95
+ finalComponent = createElement(Portal, null, finalComponent);
96
+ }
97
+ return finalComponent;
93
98
  });
94
99
  _Switch.displayName = 'MpxSwitch';
95
100
  export default _Switch;
@@ -5,12 +5,13 @@
5
5
  */
6
6
  import { Text } from 'react-native';
7
7
  import { useRef, forwardRef, createElement } from 'react';
8
+ import Portal from './mpx-portal';
8
9
  import useInnerProps from './getInnerListeners';
9
10
  import useNodesRef from './useNodesRef'; // 引入辅助函数
10
11
  import { useTransformStyle, wrapChildren, extendObject } from './utils';
11
12
  const _Text = forwardRef((props, ref) => {
12
13
  const { style = {}, allowFontScaling = false, selectable, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'user-select': userSelect, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight } = props;
13
- const { normalStyle, hasVarDec, varContextRef } = useTransformStyle(style, {
14
+ const { normalStyle, hasVarDec, varContextRef, hasPositionFixed } = useTransformStyle(style, {
14
15
  enableVar,
15
16
  externalVarContext,
16
17
  parentFontSize,
@@ -29,10 +30,14 @@ const _Text = forwardRef((props, ref) => {
29
30
  }), [
30
31
  'user-select'
31
32
  ]);
32
- return createElement(Text, innerProps, wrapChildren(props, {
33
+ let finalComponent = createElement(Text, innerProps, wrapChildren(props, {
33
34
  hasVarDec,
34
35
  varContext: varContextRef.current
35
36
  }));
37
+ if (hasPositionFixed) {
38
+ finalComponent = createElement(Portal, null, finalComponent);
39
+ }
40
+ return finalComponent;
36
41
  });
37
42
  _Text.displayName = 'MpxText';
38
43
  export default _Text;
@@ -68,6 +68,7 @@ import { StyleSheet, View } from 'react-native';
68
68
  import { splitProps, useTransformStyle, useLayout, extendObject } from './utils';
69
69
  import useInnerProps, { getCustomEvent } from './getInnerListeners';
70
70
  import useNodesRef from './useNodesRef';
71
+ import Portal from './mpx-portal';
71
72
  const styles = StyleSheet.create({
72
73
  container: {
73
74
  width: 300,
@@ -85,7 +86,7 @@ const MpxVideo = forwardRef((videoProps, ref) => {
85
86
  const videoInfoRef = useRef({});
86
87
  const propsRef = useRef({});
87
88
  propsRef.current = props;
88
- const { normalStyle, hasSelfPercent, setWidth, setHeight } = useTransformStyle(extendObject({}, styles.container, style), {
89
+ const { normalStyle, hasSelfPercent, setWidth, setHeight, hasPositionFixed } = useTransformStyle(extendObject({}, styles.container, style), {
89
90
  enableVar,
90
91
  externalVarContext,
91
92
  parentFontSize,
@@ -243,6 +244,10 @@ const MpxVideo = forwardRef((videoProps, ref) => {
243
244
  'bindcontrolstoggle',
244
245
  'bindseekcomplete'
245
246
  ], { layoutRef });
246
- return createElement(View, { style: extendObject({}, normalStyle, layoutStyle), ref: viewRef }, createElement(Video, innerProps));
247
+ let videoComponent = createElement(View, { style: extendObject({}, normalStyle, layoutStyle), ref: viewRef }, createElement(Video, innerProps));
248
+ if (hasPositionFixed) {
249
+ videoComponent = createElement(Portal, null, videoComponent);
250
+ }
251
+ return videoComponent;
247
252
  });
248
253
  export default MpxVideo;
@@ -523,10 +523,8 @@ function useWrapImage(imageStyle, innerStyle, enableFastImage) {
523
523
  setShow(true);
524
524
  }
525
525
  };
526
- return <View key='backgroundImage' {...needLayout ? { onLayout } : null} style={{ ...inheritStyle(innerStyle), ...StyleSheet.absoluteFillObject, overflow: 'hidden' }}>
527
- {show && type === 'linear' && <LinearGradient useAngle={true} {...imageStyleToProps(preImageInfo, sizeInfo.current, layoutInfo.current)}/>}
528
- {show && type === 'image' && (renderImage(imageStyleToProps(preImageInfo, sizeInfo.current, layoutInfo.current), enableFastImage))}
529
- </View>;
526
+ const backgroundProps = extendObject({ key: 'backgroundImage' }, needLayout ? { onLayout } : {}, { style: extendObject({}, inheritStyle(innerStyle), StyleSheet.absoluteFillObject, { overflow: 'hidden' }) });
527
+ return createElement(View, backgroundProps, show && type === 'linear' && createElement(LinearGradient, extendObject({ useAngle: true }, imageStyleToProps(preImageInfo, sizeInfo.current, layoutInfo.current))), show && type === 'image' && renderImage(imageStyleToProps(preImageInfo, sizeInfo.current, layoutInfo.current), enableFastImage));
530
528
  }
531
529
  function wrapWithChildren(props, { hasVarDec, enableBackground, textStyle, backgroundStyle, varContext, textProps, innerStyle, enableFastImage }) {
532
530
  const children = wrapChildren(props, {