@mpxjs/webpack-plugin 2.10.5 → 2.10.6-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/dependencies/WriteVfsDependency.js +46 -0
- package/lib/index.js +22 -6
- package/lib/json-compiler/helper.js +1 -4
- package/lib/platform/index.js +4 -2
- package/lib/platform/json/wx/index.js +0 -1
- package/lib/platform/template/wx/component-config/button.js +1 -1
- package/lib/platform/template/wx/component-config/index.js +7 -3
- package/lib/platform/template/wx/component-config/input.js +1 -1
- package/lib/platform/template/wx/component-config/sticky-header.js +23 -0
- package/lib/platform/template/wx/component-config/sticky-section.js +23 -0
- package/lib/platform/template/wx/component-config/template.js +26 -1
- package/lib/platform/template/wx/index.js +31 -4
- package/lib/react/processJSON.js +7 -6
- package/lib/resolver/PackageEntryPlugin.js +3 -1
- package/lib/runtime/components/react/context.ts +12 -3
- package/lib/runtime/components/react/dist/context.js +4 -1
- package/lib/runtime/components/react/dist/mpx-button.jsx +9 -4
- package/lib/runtime/components/react/dist/mpx-canvas/Image.js +2 -4
- package/lib/runtime/components/react/dist/mpx-canvas/index.jsx +20 -17
- package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +7 -2
- package/lib/runtime/components/react/dist/mpx-checkbox.jsx +7 -2
- package/lib/runtime/components/react/dist/mpx-icon/index.jsx +7 -2
- package/lib/runtime/components/react/dist/mpx-image.jsx +9 -2
- package/lib/runtime/components/react/dist/mpx-input.jsx +7 -2
- package/lib/runtime/components/react/dist/mpx-keyboard-avoiding-view.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-label.jsx +7 -2
- package/lib/runtime/components/react/dist/mpx-movable-area.jsx +8 -3
- package/lib/runtime/components/react/dist/mpx-movable-view.jsx +100 -62
- package/lib/runtime/components/react/dist/mpx-picker/index.jsx +11 -13
- package/lib/runtime/components/react/dist/mpx-picker-view/index.jsx +8 -7
- package/lib/runtime/components/react/dist/mpx-picker-view-column/index.jsx +26 -8
- package/lib/runtime/components/react/dist/mpx-radio-group.jsx +9 -2
- package/lib/runtime/components/react/dist/mpx-radio.jsx +7 -2
- package/lib/runtime/components/react/dist/mpx-rich-text/index.jsx +7 -2
- package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +30 -10
- package/lib/runtime/components/react/dist/mpx-sticky-header.jsx +115 -0
- package/lib/runtime/components/react/dist/mpx-sticky-section.jsx +45 -0
- package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +11 -9
- package/lib/runtime/components/react/dist/mpx-swiper.jsx +82 -36
- package/lib/runtime/components/react/dist/mpx-switch.jsx +7 -2
- package/lib/runtime/components/react/dist/mpx-text.jsx +7 -2
- package/lib/runtime/components/react/dist/mpx-video.jsx +7 -2
- package/lib/runtime/components/react/dist/mpx-view.jsx +2 -4
- package/lib/runtime/components/react/dist/mpx-web-view.jsx +13 -13
- package/lib/runtime/components/react/dist/utils.jsx +14 -3
- package/lib/runtime/components/react/mpx-button.tsx +12 -3
- package/lib/runtime/components/react/mpx-canvas/Image.ts +4 -4
- package/lib/runtime/components/react/mpx-canvas/index.tsx +24 -17
- package/lib/runtime/components/react/mpx-checkbox-group.tsx +9 -1
- package/lib/runtime/components/react/mpx-checkbox.tsx +9 -1
- package/lib/runtime/components/react/mpx-icon/index.tsx +9 -1
- package/lib/runtime/components/react/mpx-image.tsx +38 -19
- package/lib/runtime/components/react/mpx-input.tsx +10 -1
- package/lib/runtime/components/react/mpx-keyboard-avoiding-view.tsx +1 -1
- package/lib/runtime/components/react/mpx-label.tsx +9 -1
- package/lib/runtime/components/react/mpx-movable-area.tsx +8 -2
- package/lib/runtime/components/react/mpx-movable-view.tsx +100 -62
- package/lib/runtime/components/react/mpx-picker/index.tsx +18 -16
- package/lib/runtime/components/react/mpx-picker-view/index.tsx +22 -8
- package/lib/runtime/components/react/mpx-picker-view-column/index.tsx +34 -30
- package/lib/runtime/components/react/mpx-radio-group.tsx +20 -9
- package/lib/runtime/components/react/mpx-radio.tsx +9 -1
- package/lib/runtime/components/react/mpx-rich-text/index.tsx +10 -2
- package/lib/runtime/components/react/mpx-scroll-view.tsx +82 -53
- package/lib/runtime/components/react/mpx-sticky-header.tsx +179 -0
- package/lib/runtime/components/react/mpx-sticky-section.tsx +96 -0
- package/lib/runtime/components/react/mpx-swiper-item.tsx +11 -19
- package/lib/runtime/components/react/mpx-swiper.tsx +95 -38
- package/lib/runtime/components/react/mpx-switch.tsx +10 -2
- package/lib/runtime/components/react/mpx-text.tsx +10 -2
- package/lib/runtime/components/react/mpx-video.tsx +7 -2
- package/lib/runtime/components/react/mpx-view.tsx +8 -4
- package/lib/runtime/components/react/mpx-web-view.tsx +12 -12
- package/lib/runtime/components/react/utils.tsx +16 -5
- package/lib/runtime/components/web/mpx-scroll-view.vue +21 -4
- package/lib/runtime/components/web/mpx-sticky-header.vue +91 -0
- package/lib/runtime/components/web/mpx-sticky-section.vue +15 -0
- package/lib/runtime/components/web/mpx-web-view.vue +1 -1
- package/lib/runtime/mpxGlobal.js +1 -0
- package/lib/runtime/optionProcessor.d.ts +5 -0
- package/lib/runtime/optionProcessor.js +2 -2
- package/lib/template-compiler/bind-this.js +8 -7
- package/lib/template-compiler/compiler.js +59 -9
- package/lib/utils/get-template-content.js +47 -0
- package/lib/web/index.js +2 -0
- package/lib/web/processScript.js +29 -7
- package/lib/web/processTemplate.js +10 -4
- package/lib/web/template2vue.js +280 -0
- package/lib/web/wxml-template-loader.js +29 -0
- package/lib/wxs/pre-loader.js +1 -0
- package/package.json +4 -4
- package/LICENSE +0 -433
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import React, { forwardRef, useRef, useState, useMemo, useEffect, useCallback } from 'react'
|
|
1
|
+
import React, { forwardRef, useRef, useState, useMemo, useEffect, useCallback, createElement } from 'react'
|
|
2
2
|
import { GestureResponderEvent, LayoutChangeEvent, NativeScrollEvent, NativeSyntheticEvent, ScrollView, StyleSheet, View } from 'react-native'
|
|
3
3
|
import Reanimated, { AnimatedRef, useAnimatedRef, useScrollViewOffset } from 'react-native-reanimated'
|
|
4
|
-
import { useTransformStyle, splitStyle, splitProps, useLayout, usePrevious, isAndroid, isIOS, isHarmony } from '../utils'
|
|
4
|
+
import { useTransformStyle, splitStyle, splitProps, useLayout, usePrevious, isAndroid, isIOS, isHarmony, extendObject } from '../utils'
|
|
5
5
|
import useNodesRef, { HandlerRef } from '../useNodesRef'
|
|
6
6
|
import PickerIndicator from './pickerViewIndicator'
|
|
7
7
|
import PickerMask from './pickerViewMask'
|
|
@@ -302,33 +302,36 @@ const _PickerViewColumn = forwardRef<HandlerRef<ScrollView & View, ColumnProps>,
|
|
|
302
302
|
})
|
|
303
303
|
|
|
304
304
|
const renderScollView = () => {
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
305
|
+
const innerProps = extendObject({}, layoutProps, {
|
|
306
|
+
ref: scrollViewRef,
|
|
307
|
+
bounces: true,
|
|
308
|
+
horizontal: false,
|
|
309
|
+
nestedScrollEnabled: true,
|
|
310
|
+
removeClippedSubviews: false,
|
|
311
|
+
showsVerticalScrollIndicator: false,
|
|
312
|
+
showsHorizontalScrollIndicator: false,
|
|
313
|
+
scrollEventThrottle: 16,
|
|
314
|
+
style: styles.scrollView,
|
|
315
|
+
decelerationRate: 'fast',
|
|
316
|
+
snapToOffsets: snapToOffsets,
|
|
317
|
+
onTouchEnd: onClickOnceItem,
|
|
318
|
+
onScroll,
|
|
319
|
+
onScrollBeginDrag,
|
|
320
|
+
onScrollEndDrag,
|
|
321
|
+
onMomentumScrollBegin,
|
|
322
|
+
onMomentumScrollEnd,
|
|
323
|
+
onContentSizeChange,
|
|
324
|
+
contentContainerStyle
|
|
325
|
+
}) as React.ComponentProps<typeof Reanimated.ScrollView>
|
|
326
|
+
|
|
327
|
+
return createElement(
|
|
328
|
+
PickerViewColumnAnimationContext.Provider,
|
|
329
|
+
{ value: offsetYShared },
|
|
330
|
+
createElement(
|
|
331
|
+
Reanimated.ScrollView,
|
|
332
|
+
innerProps,
|
|
333
|
+
renderInnerchild()
|
|
334
|
+
)
|
|
332
335
|
)
|
|
333
336
|
}
|
|
334
337
|
|
|
@@ -356,7 +359,8 @@ const _PickerViewColumn = forwardRef<HandlerRef<ScrollView & View, ColumnProps>,
|
|
|
356
359
|
})
|
|
357
360
|
|
|
358
361
|
const styles = StyleSheet.create({
|
|
359
|
-
wrapper: { display: 'flex', flex: 1 }
|
|
362
|
+
wrapper: { display: 'flex', flex: 1 },
|
|
363
|
+
scrollView: { width: '100%' }
|
|
360
364
|
})
|
|
361
365
|
|
|
362
366
|
_PickerViewColumn.displayName = 'MpxPickerViewColumn'
|
|
@@ -22,6 +22,7 @@ import { FormContext, FormFieldValue, RadioGroupContext, GroupValue } from './co
|
|
|
22
22
|
import useInnerProps, { getCustomEvent } from './getInnerListeners'
|
|
23
23
|
import useNodesRef, { HandlerRef } from './useNodesRef'
|
|
24
24
|
import { useLayout, useTransformStyle, wrapChildren, extendObject } from './utils'
|
|
25
|
+
import Portal from './mpx-portal'
|
|
25
26
|
|
|
26
27
|
export interface RadioGroupProps {
|
|
27
28
|
name: string
|
|
@@ -71,6 +72,7 @@ const radioGroup = forwardRef<
|
|
|
71
72
|
const styleObj = extendObject({}, defaultStyle, style)
|
|
72
73
|
|
|
73
74
|
const {
|
|
75
|
+
hasPositionFixed,
|
|
74
76
|
hasSelfPercent,
|
|
75
77
|
normalStyle,
|
|
76
78
|
hasVarDec,
|
|
@@ -156,18 +158,27 @@ const radioGroup = forwardRef<
|
|
|
156
158
|
}
|
|
157
159
|
)
|
|
158
160
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
wrapChildren(
|
|
163
|
-
props,
|
|
161
|
+
const finalComponent = createElement(View, innerProps,
|
|
162
|
+
createElement(
|
|
163
|
+
RadioGroupContext.Provider,
|
|
164
164
|
{
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
165
|
+
value: contextValue
|
|
166
|
+
},
|
|
167
|
+
wrapChildren(
|
|
168
|
+
props,
|
|
169
|
+
{
|
|
170
|
+
hasVarDec,
|
|
171
|
+
varContext: varContextRef.current
|
|
172
|
+
}
|
|
173
|
+
)
|
|
168
174
|
)
|
|
169
175
|
)
|
|
170
|
-
|
|
176
|
+
|
|
177
|
+
if (hasPositionFixed) {
|
|
178
|
+
return createElement(Portal, null, finalComponent)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return finalComponent
|
|
171
182
|
})
|
|
172
183
|
|
|
173
184
|
radioGroup.displayName = 'MpxRadioGroup'
|
|
@@ -12,6 +12,7 @@ import useInnerProps, { getCustomEvent } from './getInnerListeners'
|
|
|
12
12
|
import useNodesRef, { HandlerRef } from './useNodesRef'
|
|
13
13
|
import { splitProps, splitStyle, useLayout, useTransformStyle, wrapChildren, extendObject } from './utils'
|
|
14
14
|
import Icon from './mpx-icon'
|
|
15
|
+
import Portal from './mpx-portal'
|
|
15
16
|
|
|
16
17
|
export interface RadioProps {
|
|
17
18
|
value?: string
|
|
@@ -117,6 +118,7 @@ const Radio = forwardRef<HandlerRef<View, RadioProps>, RadioProps>(
|
|
|
117
118
|
}
|
|
118
119
|
|
|
119
120
|
const {
|
|
121
|
+
hasPositionFixed,
|
|
120
122
|
hasSelfPercent,
|
|
121
123
|
normalStyle,
|
|
122
124
|
hasVarDec,
|
|
@@ -192,7 +194,7 @@ const Radio = forwardRef<HandlerRef<View, RadioProps>, RadioProps>(
|
|
|
192
194
|
}
|
|
193
195
|
}, [checked])
|
|
194
196
|
|
|
195
|
-
|
|
197
|
+
const finalComponent = createElement(View, innerProps,
|
|
196
198
|
createElement(
|
|
197
199
|
View,
|
|
198
200
|
{ style: defaultStyle },
|
|
@@ -213,6 +215,12 @@ const Radio = forwardRef<HandlerRef<View, RadioProps>, RadioProps>(
|
|
|
213
215
|
}
|
|
214
216
|
)
|
|
215
217
|
)
|
|
218
|
+
|
|
219
|
+
if (hasPositionFixed) {
|
|
220
|
+
return createElement(Portal, null, finalComponent)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return finalComponent
|
|
216
224
|
}
|
|
217
225
|
)
|
|
218
226
|
|
|
@@ -9,6 +9,7 @@ import useNodesRef, { HandlerRef } from '../useNodesRef' // 引入辅助函数
|
|
|
9
9
|
import { useTransformStyle, useLayout, extendObject } from '../utils'
|
|
10
10
|
import { WebView, WebViewMessageEvent } from 'react-native-webview'
|
|
11
11
|
import { generateHTML } from './html'
|
|
12
|
+
import Portal from '../mpx-portal'
|
|
12
13
|
|
|
13
14
|
type Node = {
|
|
14
15
|
type: 'node' | 'text'
|
|
@@ -69,7 +70,8 @@ const _RichText = forwardRef<HandlerRef<View, _RichTextProps>, _RichTextProps>((
|
|
|
69
70
|
normalStyle,
|
|
70
71
|
hasSelfPercent,
|
|
71
72
|
setWidth,
|
|
72
|
-
setHeight
|
|
73
|
+
setHeight,
|
|
74
|
+
hasPositionFixed
|
|
73
75
|
} = useTransformStyle(Object.assign({
|
|
74
76
|
width: '100%',
|
|
75
77
|
height: webViewHeight
|
|
@@ -109,7 +111,7 @@ const _RichText = forwardRef<HandlerRef<View, _RichTextProps>, _RichTextProps>((
|
|
|
109
111
|
|
|
110
112
|
const html: string = typeof nodes === 'string' ? nodes : jsonToHtmlStr(nodes)
|
|
111
113
|
|
|
112
|
-
|
|
114
|
+
let finalComponent: JSX.Element = createElement(View, innerProps,
|
|
113
115
|
createElement(WebView, {
|
|
114
116
|
source: { html: generateHTML(html) },
|
|
115
117
|
onMessage: (event: WebViewMessageEvent) => {
|
|
@@ -117,6 +119,12 @@ const _RichText = forwardRef<HandlerRef<View, _RichTextProps>, _RichTextProps>((
|
|
|
117
119
|
}
|
|
118
120
|
})
|
|
119
121
|
)
|
|
122
|
+
|
|
123
|
+
if (hasPositionFixed) {
|
|
124
|
+
finalComponent = createElement(Portal, null, finalComponent)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return finalComponent
|
|
120
128
|
})
|
|
121
129
|
|
|
122
130
|
_RichText.displayName = 'mpx-rich-text'
|
|
@@ -32,58 +32,59 @@
|
|
|
32
32
|
* ✔ bindscroll
|
|
33
33
|
*/
|
|
34
34
|
import { ScrollView, RefreshControl, Gesture, GestureDetector } from 'react-native-gesture-handler'
|
|
35
|
-
import { View, NativeSyntheticEvent, NativeScrollEvent, LayoutChangeEvent, ViewStyle } from 'react-native'
|
|
35
|
+
import { View, NativeSyntheticEvent, NativeScrollEvent, LayoutChangeEvent, ViewStyle, Animated as RNAnimated } from 'react-native'
|
|
36
36
|
import { isValidElement, Children, JSX, ReactNode, RefObject, useRef, useState, useEffect, forwardRef, useContext, useMemo, createElement } from 'react'
|
|
37
37
|
import Animated, { useAnimatedRef, useSharedValue, withTiming, useAnimatedStyle, runOnJS } from 'react-native-reanimated'
|
|
38
|
-
import { warn } from '@mpxjs/utils'
|
|
38
|
+
import { warn, hasOwn } from '@mpxjs/utils'
|
|
39
39
|
import useInnerProps, { getCustomEvent } from './getInnerListeners'
|
|
40
40
|
import useNodesRef, { HandlerRef } from './useNodesRef'
|
|
41
41
|
import { splitProps, splitStyle, useTransformStyle, useLayout, wrapChildren, extendObject, flatGesture, GestureHandler, HIDDEN_STYLE } from './utils'
|
|
42
42
|
import { IntersectionObserverContext, ScrollViewContext } from './context'
|
|
43
|
+
import Portal from './mpx-portal'
|
|
43
44
|
|
|
44
45
|
interface ScrollViewProps {
|
|
45
|
-
children?: ReactNode
|
|
46
|
-
enhanced?: boolean
|
|
47
|
-
bounces?: boolean
|
|
48
|
-
style?: ViewStyle
|
|
49
|
-
|
|
50
|
-
'scroll-
|
|
51
|
-
'
|
|
52
|
-
'
|
|
53
|
-
'
|
|
54
|
-
'
|
|
55
|
-
'
|
|
56
|
-
'
|
|
57
|
-
'
|
|
58
|
-
'refresher-
|
|
59
|
-
'refresher-
|
|
60
|
-
'refresher-
|
|
61
|
-
'refresher-
|
|
62
|
-
'
|
|
63
|
-
'scroll-
|
|
64
|
-
'
|
|
65
|
-
'
|
|
66
|
-
'
|
|
67
|
-
'enable-
|
|
68
|
-
'
|
|
69
|
-
'
|
|
70
|
-
'parent-
|
|
71
|
-
'parent-
|
|
72
|
-
'
|
|
73
|
-
'wait-for'?: Array<GestureHandler
|
|
74
|
-
'simultaneous-handlers'?: Array<GestureHandler
|
|
75
|
-
'scroll-event-throttle'?:
|
|
76
|
-
bindscrolltoupper?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void
|
|
77
|
-
bindscrolltolower?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void
|
|
78
|
-
bindscroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void
|
|
79
|
-
bindrefresherrefresh?: (event: NativeSyntheticEvent<unknown>) => void
|
|
80
|
-
binddragstart?: (event: NativeSyntheticEvent<DragEvent>) => void
|
|
81
|
-
binddragging?: (event: NativeSyntheticEvent<DragEvent>) => void
|
|
82
|
-
binddragend?: (event: NativeSyntheticEvent<DragEvent>) => void
|
|
83
|
-
bindtouchstart?: (event: NativeSyntheticEvent<TouchEvent>) => void
|
|
84
|
-
bindtouchmove?: (event: NativeSyntheticEvent<TouchEvent>) => void
|
|
85
|
-
bindtouchend?: (event: NativeSyntheticEvent<TouchEvent>) => void
|
|
86
|
-
bindscrollend?: (event: NativeSyntheticEvent<TouchEvent>) => void
|
|
46
|
+
children?: ReactNode;
|
|
47
|
+
enhanced?: boolean;
|
|
48
|
+
bounces?: boolean;
|
|
49
|
+
style?: ViewStyle;
|
|
50
|
+
'scroll-x'?: boolean;
|
|
51
|
+
'scroll-y'?: boolean;
|
|
52
|
+
'enable-back-to-top'?: boolean;
|
|
53
|
+
'show-scrollbar'?: boolean;
|
|
54
|
+
'paging-enabled'?: boolean;
|
|
55
|
+
'upper-threshold'?: number;
|
|
56
|
+
'lower-threshold'?: number;
|
|
57
|
+
'scroll-with-animation'?: boolean;
|
|
58
|
+
'refresher-triggered'?: boolean;
|
|
59
|
+
'refresher-enabled'?: boolean;
|
|
60
|
+
'refresher-default-style'?: 'black' | 'white' | 'none';
|
|
61
|
+
'refresher-background'?: string;
|
|
62
|
+
'refresher-threshold'?: number;
|
|
63
|
+
'scroll-top'?: number;
|
|
64
|
+
'scroll-left'?: number;
|
|
65
|
+
'enable-offset'?: boolean;
|
|
66
|
+
'scroll-into-view'?: string;
|
|
67
|
+
'enable-trigger-intersection-observer'?: boolean;
|
|
68
|
+
'enable-var'?: boolean;
|
|
69
|
+
'external-var-context'?: Record<string, any>;
|
|
70
|
+
'parent-font-size'?: number;
|
|
71
|
+
'parent-width'?: number;
|
|
72
|
+
'parent-height'?: number;
|
|
73
|
+
'enable-sticky'?: boolean;
|
|
74
|
+
'wait-for'?: Array<GestureHandler>;
|
|
75
|
+
'simultaneous-handlers'?: Array<GestureHandler>;
|
|
76
|
+
'scroll-event-throttle'?:number;
|
|
77
|
+
bindscrolltoupper?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
|
|
78
|
+
bindscrolltolower?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
|
|
79
|
+
bindscroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
|
|
80
|
+
bindrefresherrefresh?: (event: NativeSyntheticEvent<unknown>) => void;
|
|
81
|
+
binddragstart?: (event: NativeSyntheticEvent<DragEvent>) => void;
|
|
82
|
+
binddragging?: (event: NativeSyntheticEvent<DragEvent>) => void;
|
|
83
|
+
binddragend?: (event: NativeSyntheticEvent<DragEvent>) => void;
|
|
84
|
+
bindtouchstart?: (event: NativeSyntheticEvent<TouchEvent>) => void;
|
|
85
|
+
bindtouchmove?: (event: NativeSyntheticEvent<TouchEvent>) => void;
|
|
86
|
+
bindtouchend?: (event: NativeSyntheticEvent<TouchEvent>) => void;
|
|
87
|
+
bindscrollend?: (event: NativeSyntheticEvent<TouchEvent>) => void;
|
|
87
88
|
__selectRef?: (selector: string, nodeType: 'node' | 'component', all?: boolean) => HandlerRef<any, any>
|
|
88
89
|
}
|
|
89
90
|
type ScrollAdditionalProps = {
|
|
@@ -108,6 +109,8 @@ type ScrollAdditionalProps = {
|
|
|
108
109
|
onMomentumScrollEnd?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void
|
|
109
110
|
}
|
|
110
111
|
|
|
112
|
+
const AnimatedScrollView = RNAnimated.createAnimatedComponent(ScrollView) as React.ComponentType<any>
|
|
113
|
+
|
|
111
114
|
const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, ScrollViewProps>((scrollViewProps: ScrollViewProps = {}, ref): JSX.Element => {
|
|
112
115
|
const { textProps, innerProps: props = {} } = splitProps(scrollViewProps)
|
|
113
116
|
const {
|
|
@@ -144,10 +147,13 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
|
|
|
144
147
|
'parent-height': parentHeight,
|
|
145
148
|
'simultaneous-handlers': originSimultaneousHandlers,
|
|
146
149
|
'wait-for': waitFor,
|
|
150
|
+
'enable-sticky': enableSticky,
|
|
147
151
|
'scroll-event-throttle': scrollEventThrottle = 0,
|
|
148
152
|
__selectRef
|
|
149
153
|
} = props
|
|
150
154
|
|
|
155
|
+
const scrollOffset = useRef(new RNAnimated.Value(0)).current
|
|
156
|
+
|
|
151
157
|
const simultaneousHandlers = flatGesture(originSimultaneousHandlers)
|
|
152
158
|
const waitForHandlers = flatGesture(waitFor)
|
|
153
159
|
|
|
@@ -194,6 +200,7 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
|
|
|
194
200
|
hasVarDec,
|
|
195
201
|
varContextRef,
|
|
196
202
|
hasSelfPercent,
|
|
203
|
+
hasPositionFixed,
|
|
197
204
|
setWidth,
|
|
198
205
|
setHeight
|
|
199
206
|
} = useTransformStyle(style, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight })
|
|
@@ -216,14 +223,15 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
|
|
|
216
223
|
gestureRef: scrollViewRef
|
|
217
224
|
})
|
|
218
225
|
|
|
226
|
+
const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: scrollViewRef, onLayout })
|
|
227
|
+
|
|
219
228
|
const contextValue = useMemo(() => {
|
|
220
229
|
return {
|
|
221
|
-
gestureRef: scrollViewRef
|
|
230
|
+
gestureRef: scrollViewRef,
|
|
231
|
+
scrollOffset
|
|
222
232
|
}
|
|
223
233
|
}, [])
|
|
224
234
|
|
|
225
|
-
const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: scrollViewRef, onLayout })
|
|
226
|
-
|
|
227
235
|
const hasRefresherLayoutRef = useRef(false)
|
|
228
236
|
|
|
229
237
|
// layout 完成前先隐藏,避免安卓闪烁问题
|
|
@@ -485,6 +493,16 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
|
|
|
485
493
|
updateIntersection()
|
|
486
494
|
}
|
|
487
495
|
|
|
496
|
+
const scrollHandler = RNAnimated.event(
|
|
497
|
+
[{ nativeEvent: { contentOffset: { y: scrollOffset } } }],
|
|
498
|
+
{
|
|
499
|
+
useNativeDriver: true,
|
|
500
|
+
listener: (event: NativeSyntheticEvent<NativeScrollEvent>) => {
|
|
501
|
+
onScroll(event)
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
)
|
|
505
|
+
|
|
488
506
|
function onScrollDragStart (e: NativeSyntheticEvent<NativeScrollEvent>) {
|
|
489
507
|
hasCallScrollToLower.current = false
|
|
490
508
|
hasCallScrollToUpper.current = false
|
|
@@ -643,7 +661,11 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
|
|
|
643
661
|
|
|
644
662
|
const scrollAdditionalProps: ScrollAdditionalProps = extendObject(
|
|
645
663
|
{
|
|
646
|
-
style: extendObject(
|
|
664
|
+
style: extendObject(hasOwn(innerStyle, 'flex') || hasOwn(innerStyle, 'flexGrow')
|
|
665
|
+
? {}
|
|
666
|
+
: {
|
|
667
|
+
flexGrow: 0
|
|
668
|
+
}, innerStyle, layoutStyle),
|
|
647
669
|
pinchGestureEnabled: false,
|
|
648
670
|
alwaysBounceVertical: false,
|
|
649
671
|
alwaysBounceHorizontal: false,
|
|
@@ -655,7 +677,7 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
|
|
|
655
677
|
scrollEnabled: !enableScroll ? false : !!(scrollX || scrollY),
|
|
656
678
|
bounces: false,
|
|
657
679
|
ref: scrollViewRef,
|
|
658
|
-
onScroll: onScroll,
|
|
680
|
+
onScroll: enableSticky ? scrollHandler : onScroll,
|
|
659
681
|
onContentSizeChange: onContentSizeChange,
|
|
660
682
|
bindtouchstart: ((enhanced && binddragstart) || bindtouchstart) && onScrollTouchStart,
|
|
661
683
|
bindtouchmove: ((enhanced && binddragging) || bindtouchmove) && onScrollTouchMove,
|
|
@@ -710,11 +732,13 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
|
|
|
710
732
|
'bindrefresherrefresh'
|
|
711
733
|
], { layoutRef })
|
|
712
734
|
|
|
735
|
+
const ScrollViewComponent = enableSticky ? AnimatedScrollView : ScrollView
|
|
736
|
+
|
|
713
737
|
const withRefresherScrollView = createElement(
|
|
714
738
|
GestureDetector,
|
|
715
739
|
{ gesture: panGesture },
|
|
716
740
|
createElement(
|
|
717
|
-
|
|
741
|
+
ScrollViewComponent,
|
|
718
742
|
innerProps,
|
|
719
743
|
createElement(
|
|
720
744
|
Animated.View,
|
|
@@ -742,8 +766,8 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
|
|
|
742
766
|
)
|
|
743
767
|
|
|
744
768
|
const commonScrollView = createElement(
|
|
745
|
-
|
|
746
|
-
extendObject(innerProps, {
|
|
769
|
+
ScrollViewComponent,
|
|
770
|
+
extendObject({}, innerProps, {
|
|
747
771
|
refreshControl: refresherEnabled
|
|
748
772
|
? createElement(RefreshControl, extendObject({
|
|
749
773
|
progressBackgroundColor: refresherBackground,
|
|
@@ -764,7 +788,12 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
|
|
|
764
788
|
)
|
|
765
789
|
)
|
|
766
790
|
|
|
767
|
-
|
|
791
|
+
let scrollViewComponent = hasRefresher ? withRefresherScrollView : commonScrollView
|
|
792
|
+
|
|
793
|
+
if (hasPositionFixed) {
|
|
794
|
+
scrollViewComponent = createElement(Portal, null, scrollViewComponent)
|
|
795
|
+
}
|
|
796
|
+
return scrollViewComponent
|
|
768
797
|
})
|
|
769
798
|
|
|
770
799
|
_ScrollView.displayName = 'MpxScrollView'
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { useEffect, useRef, useContext, forwardRef, useMemo, createElement, ReactNode, useId } from 'react'
|
|
2
|
+
import { Animated, StyleSheet, View, NativeSyntheticEvent, ViewStyle, LayoutChangeEvent, useAnimatedValue } from 'react-native'
|
|
3
|
+
import { ScrollViewContext, StickyContext } from './context'
|
|
4
|
+
import useNodesRef, { HandlerRef } 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
|
+
|
|
9
|
+
interface StickyHeaderProps {
|
|
10
|
+
children?: ReactNode;
|
|
11
|
+
style?: ViewStyle;
|
|
12
|
+
padding?: [number, number, number, number];
|
|
13
|
+
'offset-top'?: number;
|
|
14
|
+
'enable-var'?: boolean;
|
|
15
|
+
'external-var-context'?: Record<string, any>;
|
|
16
|
+
'parent-font-size'?: number;
|
|
17
|
+
'parent-width'?: number;
|
|
18
|
+
'parent-height'?: number;
|
|
19
|
+
bindstickontopchange?: (e: NativeSyntheticEvent<unknown>) => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const _StickyHeader = forwardRef<HandlerRef<View, StickyHeaderProps>, StickyHeaderProps>((stickyHeaderProps: StickyHeaderProps = {}, ref): JSX.Element => {
|
|
23
|
+
const { textProps, innerProps: props = {} } = splitProps(stickyHeaderProps)
|
|
24
|
+
const {
|
|
25
|
+
style,
|
|
26
|
+
bindstickontopchange,
|
|
27
|
+
padding = [0, 0, 0, 0],
|
|
28
|
+
'offset-top': offsetTop = 0,
|
|
29
|
+
'enable-var': enableVar,
|
|
30
|
+
'external-var-context': externalVarContext,
|
|
31
|
+
'parent-font-size': parentFontSize,
|
|
32
|
+
'parent-width': parentWidth,
|
|
33
|
+
'parent-height': parentHeight
|
|
34
|
+
} = props
|
|
35
|
+
|
|
36
|
+
const scrollViewContext = useContext(ScrollViewContext)
|
|
37
|
+
const stickyContext = useContext(StickyContext)
|
|
38
|
+
const { scrollOffset } = scrollViewContext
|
|
39
|
+
const { registerStickyHeader, unregisterStickyHeader } = stickyContext
|
|
40
|
+
const headerRef = useRef<View>(null)
|
|
41
|
+
const isStickOnTopRef = useRef(false)
|
|
42
|
+
const id = useId()
|
|
43
|
+
|
|
44
|
+
const {
|
|
45
|
+
normalStyle,
|
|
46
|
+
hasVarDec,
|
|
47
|
+
varContextRef,
|
|
48
|
+
hasSelfPercent,
|
|
49
|
+
setWidth,
|
|
50
|
+
setHeight
|
|
51
|
+
} = useTransformStyle(style, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight })
|
|
52
|
+
|
|
53
|
+
const { layoutRef, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: headerRef, onLayout })
|
|
54
|
+
|
|
55
|
+
const { textStyle, innerStyle = {} } = splitStyle(normalStyle)
|
|
56
|
+
|
|
57
|
+
const headerTopAnimated = useAnimatedValue(0)
|
|
58
|
+
// harmony animatedValue 不支持通过 _value 访问
|
|
59
|
+
const headerTopRef = useRef(0)
|
|
60
|
+
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
registerStickyHeader({ key: id, updatePosition })
|
|
63
|
+
return () => {
|
|
64
|
+
unregisterStickyHeader(id)
|
|
65
|
+
}
|
|
66
|
+
}, [])
|
|
67
|
+
|
|
68
|
+
function updatePosition () {
|
|
69
|
+
if (headerRef.current) {
|
|
70
|
+
const scrollViewRef = scrollViewContext.gestureRef
|
|
71
|
+
if (scrollViewRef && scrollViewRef.current) {
|
|
72
|
+
headerRef.current.measureLayout(
|
|
73
|
+
scrollViewRef.current,
|
|
74
|
+
(left: number, top: number) => {
|
|
75
|
+
Animated.timing(headerTopAnimated, {
|
|
76
|
+
toValue: top,
|
|
77
|
+
duration: 0,
|
|
78
|
+
useNativeDriver: true
|
|
79
|
+
}).start()
|
|
80
|
+
headerTopRef.current = top
|
|
81
|
+
}
|
|
82
|
+
)
|
|
83
|
+
} else {
|
|
84
|
+
error('StickyHeader measureLayout error: scrollViewRef is not a valid native component reference')
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function onLayout (e: LayoutChangeEvent) {
|
|
90
|
+
updatePosition()
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
useNodesRef(props, ref, headerRef, {
|
|
94
|
+
style: normalStyle
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
if (!bindstickontopchange) return
|
|
99
|
+
|
|
100
|
+
const listener = scrollOffset.addListener((state: { value: number }) => {
|
|
101
|
+
const currentScrollValue = state.value
|
|
102
|
+
const newIsStickOnTop = currentScrollValue > headerTopRef.current
|
|
103
|
+
if (newIsStickOnTop !== isStickOnTopRef.current) {
|
|
104
|
+
isStickOnTopRef.current = newIsStickOnTop
|
|
105
|
+
bindstickontopchange(
|
|
106
|
+
getCustomEvent('stickontopchange', {}, {
|
|
107
|
+
detail: {
|
|
108
|
+
isStickOnTop: newIsStickOnTop
|
|
109
|
+
},
|
|
110
|
+
layoutRef
|
|
111
|
+
}, props))
|
|
112
|
+
}
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
return () => {
|
|
116
|
+
scrollOffset.removeListener(listener)
|
|
117
|
+
}
|
|
118
|
+
}, [])
|
|
119
|
+
|
|
120
|
+
const animatedStyle = useMemo(() => {
|
|
121
|
+
const translateY = Animated.subtract(scrollOffset, headerTopAnimated).interpolate({
|
|
122
|
+
inputRange: [0, 1],
|
|
123
|
+
outputRange: [0, 1],
|
|
124
|
+
extrapolateLeft: 'clamp',
|
|
125
|
+
extrapolateRight: 'extend'
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
const finalTranslateY = offsetTop === 0
|
|
129
|
+
? translateY
|
|
130
|
+
: Animated.add(
|
|
131
|
+
translateY,
|
|
132
|
+
Animated.subtract(scrollOffset, headerTopAnimated).interpolate({
|
|
133
|
+
inputRange: [0, 1],
|
|
134
|
+
outputRange: [0, offsetTop],
|
|
135
|
+
extrapolate: 'clamp'
|
|
136
|
+
})
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
transform: [{ translateY: finalTranslateY }]
|
|
141
|
+
}
|
|
142
|
+
}, [scrollOffset, headerTopAnimated, offsetTop])
|
|
143
|
+
|
|
144
|
+
const innerProps = useInnerProps(extendObject({}, props, {
|
|
145
|
+
ref: headerRef,
|
|
146
|
+
style: extendObject({}, styles.content, innerStyle, animatedStyle, {
|
|
147
|
+
paddingTop: padding[0] || 0,
|
|
148
|
+
paddingRight: padding[1] || 0,
|
|
149
|
+
paddingBottom: padding[2] || 0,
|
|
150
|
+
paddingLeft: padding[3] || 0
|
|
151
|
+
})
|
|
152
|
+
}, layoutProps), [], { layoutRef })
|
|
153
|
+
|
|
154
|
+
return (
|
|
155
|
+
createElement(
|
|
156
|
+
Animated.View,
|
|
157
|
+
innerProps,
|
|
158
|
+
wrapChildren(
|
|
159
|
+
props,
|
|
160
|
+
{
|
|
161
|
+
hasVarDec,
|
|
162
|
+
varContext: varContextRef.current,
|
|
163
|
+
textStyle,
|
|
164
|
+
textProps
|
|
165
|
+
}
|
|
166
|
+
)
|
|
167
|
+
)
|
|
168
|
+
)
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
const styles = StyleSheet.create({
|
|
172
|
+
content: {
|
|
173
|
+
width: '100%',
|
|
174
|
+
zIndex: 10
|
|
175
|
+
}
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
_StickyHeader.displayName = 'MpxStickyHeader'
|
|
179
|
+
export default _StickyHeader
|