@mpxjs/webpack-plugin 2.10.4 → 2.10.5-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.
- package/lib/index.js +10 -1
- package/lib/json-compiler/helper.js +1 -4
- package/lib/platform/json/wx/index.js +0 -1
- package/lib/platform/style/wx/index.js +22 -21
- package/lib/platform/template/wx/component-config/button.js +1 -1
- package/lib/platform/template/wx/component-config/index.js +5 -1
- 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/index.js +21 -1
- package/lib/react/processJSON.js +7 -6
- package/lib/react/processScript.js +9 -1
- package/lib/react/script-helper.js +5 -1
- 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/event.config.js +0 -2
- package/lib/runtime/components/react/dist/getInnerListeners.js +127 -153
- package/lib/runtime/components/react/dist/mpx-button.jsx +11 -7
- package/lib/runtime/components/react/dist/mpx-canvas/Image.js +2 -4
- package/lib/runtime/components/react/dist/mpx-canvas/index.jsx +23 -21
- package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +9 -4
- package/lib/runtime/components/react/dist/mpx-checkbox.jsx +9 -5
- package/lib/runtime/components/react/dist/mpx-form.jsx +2 -2
- package/lib/runtime/components/react/dist/mpx-icon/index.jsx +9 -4
- package/lib/runtime/components/react/dist/mpx-image.jsx +11 -4
- package/lib/runtime/components/react/dist/mpx-input.jsx +24 -13
- package/lib/runtime/components/react/dist/mpx-keyboard-avoiding-view.jsx +23 -30
- package/lib/runtime/components/react/dist/mpx-label.jsx +9 -5
- package/lib/runtime/components/react/dist/mpx-movable-area.jsx +9 -4
- package/lib/runtime/components/react/dist/mpx-movable-view.jsx +77 -43
- package/lib/runtime/components/react/dist/mpx-navigator.jsx +11 -3
- package/lib/runtime/components/react/dist/mpx-picker/index.jsx +12 -14
- package/lib/runtime/components/react/dist/mpx-picker-view/index.jsx +10 -10
- package/lib/runtime/components/react/dist/mpx-picker-view-column/index.jsx +28 -10
- package/lib/runtime/components/react/dist/mpx-radio-group.jsx +11 -4
- package/lib/runtime/components/react/dist/mpx-radio.jsx +9 -5
- package/lib/runtime/components/react/dist/mpx-rich-text/index.jsx +9 -4
- package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +31 -11
- package/lib/runtime/components/react/dist/mpx-simple-text.jsx +3 -2
- package/lib/runtime/components/react/dist/mpx-simple-view.jsx +3 -3
- 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 +15 -14
- package/lib/runtime/components/react/dist/mpx-swiper.jsx +86 -40
- package/lib/runtime/components/react/dist/mpx-switch.jsx +10 -7
- package/lib/runtime/components/react/dist/mpx-text.jsx +11 -9
- package/lib/runtime/components/react/dist/mpx-video.jsx +9 -4
- package/lib/runtime/components/react/dist/mpx-view.jsx +15 -10
- package/lib/runtime/components/react/dist/mpx-web-view.jsx +13 -13
- package/lib/runtime/components/react/dist/useAnimationHooks.js +27 -4
- package/lib/runtime/components/react/dist/utils.jsx +99 -98
- package/lib/runtime/components/react/event.config.ts +1 -8
- package/lib/runtime/components/react/getInnerListeners.ts +146 -192
- package/lib/runtime/components/react/mpx-button.tsx +16 -8
- package/lib/runtime/components/react/mpx-canvas/Image.ts +4 -4
- package/lib/runtime/components/react/mpx-canvas/index.tsx +47 -32
- package/lib/runtime/components/react/mpx-checkbox-group.tsx +13 -4
- package/lib/runtime/components/react/mpx-checkbox.tsx +17 -10
- package/lib/runtime/components/react/mpx-form.tsx +25 -19
- package/lib/runtime/components/react/mpx-icon/index.tsx +13 -4
- package/lib/runtime/components/react/mpx-image.tsx +42 -22
- package/lib/runtime/components/react/mpx-input.tsx +32 -16
- package/lib/runtime/components/react/mpx-keyboard-avoiding-view.tsx +31 -42
- package/lib/runtime/components/react/mpx-label.tsx +13 -6
- package/lib/runtime/components/react/mpx-movable-area.tsx +29 -14
- package/lib/runtime/components/react/mpx-movable-view.tsx +121 -81
- package/lib/runtime/components/react/mpx-navigator.tsx +4 -6
- package/lib/runtime/components/react/mpx-picker/index.tsx +24 -19
- package/lib/runtime/components/react/mpx-picker-view/index.tsx +39 -22
- package/lib/runtime/components/react/mpx-picker-view-column/index.tsx +36 -32
- package/lib/runtime/components/react/mpx-radio-group.tsx +24 -12
- package/lib/runtime/components/react/mpx-radio.tsx +17 -10
- package/lib/runtime/components/react/mpx-rich-text/index.tsx +25 -8
- package/lib/runtime/components/react/mpx-scroll-view.tsx +95 -60
- package/lib/runtime/components/react/mpx-simple-text.tsx +10 -3
- package/lib/runtime/components/react/mpx-simple-view.tsx +10 -4
- 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 +42 -43
- package/lib/runtime/components/react/mpx-swiper.tsx +142 -79
- package/lib/runtime/components/react/mpx-switch.tsx +29 -16
- package/lib/runtime/components/react/mpx-text.tsx +26 -15
- package/lib/runtime/components/react/mpx-video.tsx +41 -35
- package/lib/runtime/components/react/mpx-view.tsx +38 -18
- package/lib/runtime/components/react/mpx-web-view.tsx +12 -12
- package/lib/runtime/components/react/types/getInnerListeners.d.ts +65 -35
- package/lib/runtime/components/react/useAnimationHooks.ts +30 -9
- package/lib/runtime/components/react/utils.tsx +107 -103
- 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/template-compiler/bind-this.js +8 -7
- package/lib/template-compiler/compiler.js +1 -1
- package/lib/wxs/pre-loader.js +1 -0
- package/package.json +3 -3
- package/LICENSE +0 -433
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { forwardRef, useRef, useContext, useEffect } from 'react';
|
|
1
|
+
import React, { forwardRef, useRef, useContext, useEffect, createElement } from 'react';
|
|
2
2
|
import { StyleSheet, Text, TouchableWithoutFeedback, View } from 'react-native';
|
|
3
3
|
import { warn } from '@mpxjs/utils';
|
|
4
4
|
import PickerSelector from './selector';
|
|
@@ -9,7 +9,7 @@ import PickerRegion from './region';
|
|
|
9
9
|
import { FormContext, RouteContext } from '../context';
|
|
10
10
|
import useNodesRef from '../useNodesRef';
|
|
11
11
|
import useInnerProps, { getCustomEvent } from '../getInnerListeners';
|
|
12
|
-
import { extendObject } from '../utils';
|
|
12
|
+
import { extendObject, useLayout } from '../utils';
|
|
13
13
|
import { createPopupManager } from '../mpx-popup';
|
|
14
14
|
/**
|
|
15
15
|
* ✔ mode
|
|
@@ -109,17 +109,18 @@ const Picker = forwardRef((props, ref) => {
|
|
|
109
109
|
const buttonText = buttonTextMap[global.__mpx?.i18n?.locale || 'zh-CN'];
|
|
110
110
|
const pickerValue = useRef(value);
|
|
111
111
|
pickerValue.current = Array.isArray(value) ? value.slice() : value;
|
|
112
|
-
const innerLayout = useRef({});
|
|
113
112
|
const nodeRef = useRef(null);
|
|
114
113
|
const pickerRef = useRef(null);
|
|
115
114
|
const { open, show, hide, remove } = useRef(createPopupManager()).current;
|
|
116
115
|
useNodesRef(props, ref, nodeRef);
|
|
117
|
-
const
|
|
116
|
+
const { layoutRef, layoutProps } = useLayout({
|
|
117
|
+
props,
|
|
118
|
+
hasSelfPercent: false,
|
|
119
|
+
nodeRef
|
|
120
|
+
});
|
|
121
|
+
const innerProps = useInnerProps(extendObject({}, props, {
|
|
118
122
|
ref: nodeRef
|
|
119
|
-
}, [], { layoutRef
|
|
120
|
-
const getInnerLayout = (layout) => {
|
|
121
|
-
innerLayout.current = layout.current;
|
|
122
|
-
};
|
|
123
|
+
}, layoutProps), [], { layoutRef });
|
|
123
124
|
useEffect(() => {
|
|
124
125
|
if (range && pickerRef.current && mode === "multiSelector" /* PickerMode.MULTI_SELECTOR */) {
|
|
125
126
|
pickerRef.current.updateRange?.(range);
|
|
@@ -162,7 +163,7 @@ const Picker = forwardRef((props, ref) => {
|
|
|
162
163
|
if (mode !== "multiSelector" /* PickerMode.MULTI_SELECTOR */) {
|
|
163
164
|
return;
|
|
164
165
|
}
|
|
165
|
-
const eventData = getCustomEvent('columnchange', {}, { detail: { column: columnIndex, value }, layoutRef
|
|
166
|
+
const eventData = getCustomEvent('columnchange', {}, { detail: { column: columnIndex, value }, layoutRef });
|
|
166
167
|
props.bindcolumnchange?.(eventData);
|
|
167
168
|
};
|
|
168
169
|
const onCancel = () => {
|
|
@@ -170,7 +171,7 @@ const Picker = forwardRef((props, ref) => {
|
|
|
170
171
|
hide();
|
|
171
172
|
};
|
|
172
173
|
const onConfirm = () => {
|
|
173
|
-
const eventData = getCustomEvent('change', {}, { detail: { value: pickerValue.current }, layoutRef
|
|
174
|
+
const eventData = getCustomEvent('change', {}, { detail: { value: pickerValue.current }, layoutRef });
|
|
174
175
|
bindchange?.(eventData);
|
|
175
176
|
hide();
|
|
176
177
|
};
|
|
@@ -179,7 +180,6 @@ const Picker = forwardRef((props, ref) => {
|
|
|
179
180
|
children,
|
|
180
181
|
bindchange: onChange,
|
|
181
182
|
bindcolumnchange: onColumnChange,
|
|
182
|
-
getInnerLayout,
|
|
183
183
|
getRange: () => range
|
|
184
184
|
});
|
|
185
185
|
const renderPickerContent = () => {
|
|
@@ -215,9 +215,7 @@ const Picker = forwardRef((props, ref) => {
|
|
|
215
215
|
remove();
|
|
216
216
|
};
|
|
217
217
|
}, []);
|
|
218
|
-
return (
|
|
219
|
-
{children}
|
|
220
|
-
</TouchableWithoutFeedback>);
|
|
218
|
+
return createElement(TouchableWithoutFeedback, { onPress: show }, createElement(View, innerProps, children));
|
|
221
219
|
});
|
|
222
220
|
Picker.displayName = 'MpxPicker';
|
|
223
221
|
export default Picker;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { View } from 'react-native';
|
|
2
|
-
import React, { forwardRef, useRef } from 'react';
|
|
2
|
+
import React, { createElement, forwardRef, useRef } from 'react';
|
|
3
3
|
import useInnerProps, { getCustomEvent } from '../getInnerListeners';
|
|
4
4
|
import useNodesRef from '../useNodesRef';
|
|
5
5
|
import { useLayout, splitProps, splitStyle, wrapChildren, useTransformStyle, extendObject } from '../utils';
|
|
6
6
|
import { PickerViewStyleContext } from './pickerVIewContext';
|
|
7
|
+
import Portal from '../mpx-portal';
|
|
7
8
|
const styles = {
|
|
8
9
|
wrapper: {
|
|
9
10
|
display: 'flex',
|
|
@@ -23,7 +24,7 @@ const _PickerView = forwardRef((props, ref) => {
|
|
|
23
24
|
const activeValueRef = useRef(value);
|
|
24
25
|
activeValueRef.current = value.slice();
|
|
25
26
|
const snapActiveValueRef = useRef(null);
|
|
26
|
-
const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, setWidth, setHeight } = useTransformStyle(style, { enableVar, externalVarContext });
|
|
27
|
+
const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, setWidth, setHeight, hasPositionFixed } = useTransformStyle(style, { enableVar, externalVarContext });
|
|
27
28
|
useNodesRef(props, ref, nodeRef, {
|
|
28
29
|
style: normalStyle
|
|
29
30
|
});
|
|
@@ -47,13 +48,12 @@ const _PickerView = forwardRef((props, ref) => {
|
|
|
47
48
|
snapActiveValueRef.current = value.slice();
|
|
48
49
|
}
|
|
49
50
|
};
|
|
50
|
-
const innerProps = useInnerProps(props,
|
|
51
|
+
const innerProps = useInnerProps(extendObject({}, props, layoutProps, {
|
|
51
52
|
ref: nodeRef,
|
|
52
53
|
style: extendObject({}, normalStyle, layoutStyle, {
|
|
53
54
|
position: 'relative',
|
|
54
55
|
overflow: 'hidden'
|
|
55
|
-
})
|
|
56
|
-
layoutProps
|
|
56
|
+
})
|
|
57
57
|
}), [
|
|
58
58
|
'enable-offset',
|
|
59
59
|
'indicator-style',
|
|
@@ -115,11 +115,11 @@ const _PickerView = forwardRef((props, ref) => {
|
|
|
115
115
|
onInitialChange(isInvalid, validValue);
|
|
116
116
|
return renderColumns;
|
|
117
117
|
};
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
118
|
+
const finalComponent = createElement(PickerViewStyleContext.Provider, { value: textStyle }, createElement(View, innerProps, createElement(View, { style: [styles.wrapper] }, renderPickerColumns())));
|
|
119
|
+
if (hasPositionFixed) {
|
|
120
|
+
return createElement(Portal, null, finalComponent);
|
|
121
|
+
}
|
|
122
|
+
return finalComponent;
|
|
123
123
|
});
|
|
124
124
|
_PickerView.displayName = 'MpxPickerView';
|
|
125
125
|
export default _PickerView;
|
|
@@ -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 { StyleSheet, View } from 'react-native';
|
|
3
3
|
import Reanimated, { useAnimatedRef, useScrollViewOffset } from 'react-native-reanimated';
|
|
4
|
-
import { useTransformStyle, splitStyle, splitProps, useLayout, usePrevious, isAndroid, isIOS } from '../utils';
|
|
4
|
+
import { useTransformStyle, splitStyle, splitProps, useLayout, usePrevious, isAndroid, isIOS, isHarmony, extendObject } from '../utils';
|
|
5
5
|
import useNodesRef from '../useNodesRef';
|
|
6
6
|
import PickerIndicator from './pickerViewIndicator';
|
|
7
7
|
import PickerMask from './pickerViewMask';
|
|
@@ -143,9 +143,9 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
143
143
|
}, [itemRawH]);
|
|
144
144
|
const onScrollEndDrag = useCallback((e) => {
|
|
145
145
|
dragging.current = false;
|
|
146
|
-
if (
|
|
146
|
+
if (!isAndroid) {
|
|
147
147
|
const { y } = e.nativeEvent.contentOffset;
|
|
148
|
-
if (y % itemRawH === 0) {
|
|
148
|
+
if (y % itemRawH === 0 || (isHarmony && y > snapToOffsets[maxIndex])) {
|
|
149
149
|
onMomentumScrollEnd({ nativeEvent: { contentOffset: { y } } });
|
|
150
150
|
}
|
|
151
151
|
else if (y > 0 && y < snapToOffsets[maxIndex]) {
|
|
@@ -220,11 +220,28 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
220
220
|
return (<MpxPickerVIewColumnItem key={index} item={item} index={index} itemHeight={itemHeight} textStyle={textStyle} textProps={textProps} visibleCount={visibleCount} onItemLayout={onItemLayout}/>);
|
|
221
221
|
});
|
|
222
222
|
const renderScollView = () => {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
223
|
+
const innerProps = extendObject({}, layoutProps, {
|
|
224
|
+
ref: scrollViewRef,
|
|
225
|
+
bounces: true,
|
|
226
|
+
horizontal: false,
|
|
227
|
+
nestedScrollEnabled: true,
|
|
228
|
+
removeClippedSubviews: false,
|
|
229
|
+
showsVerticalScrollIndicator: false,
|
|
230
|
+
showsHorizontalScrollIndicator: false,
|
|
231
|
+
scrollEventThrottle: 16,
|
|
232
|
+
style: styles.scrollView,
|
|
233
|
+
decelerationRate: 'fast',
|
|
234
|
+
snapToOffsets: snapToOffsets,
|
|
235
|
+
onTouchEnd: onClickOnceItem,
|
|
236
|
+
onScroll,
|
|
237
|
+
onScrollBeginDrag,
|
|
238
|
+
onScrollEndDrag,
|
|
239
|
+
onMomentumScrollBegin,
|
|
240
|
+
onMomentumScrollEnd,
|
|
241
|
+
onContentSizeChange,
|
|
242
|
+
contentContainerStyle
|
|
243
|
+
});
|
|
244
|
+
return createElement(PickerViewColumnAnimationContext.Provider, { value: offsetYShared }, createElement(Reanimated.ScrollView, innerProps, renderInnerchild()));
|
|
228
245
|
};
|
|
229
246
|
const renderIndicator = () => (<PickerIndicator itemHeight={itemHeight} indicatorItemStyle={pickerIndicatorStyle}/>);
|
|
230
247
|
const renderMask = () => (<PickerMask itemHeight={itemHeight} maskContainerStyle={pickerMaskStyle}/>);
|
|
@@ -235,7 +252,8 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
235
252
|
</View>);
|
|
236
253
|
});
|
|
237
254
|
const styles = StyleSheet.create({
|
|
238
|
-
wrapper: { display: 'flex', flex: 1 }
|
|
255
|
+
wrapper: { display: 'flex', flex: 1 },
|
|
256
|
+
scrollView: { width: '100%' }
|
|
239
257
|
});
|
|
240
258
|
_PickerViewColumn.displayName = 'MpxPickerViewColumn';
|
|
241
259
|
export default _PickerViewColumn;
|
|
@@ -8,6 +8,7 @@ import { FormContext, RadioGroupContext } from './context';
|
|
|
8
8
|
import useInnerProps, { getCustomEvent } from './getInnerListeners';
|
|
9
9
|
import useNodesRef from './useNodesRef';
|
|
10
10
|
import { useLayout, useTransformStyle, wrapChildren, extendObject } from './utils';
|
|
11
|
+
import Portal from './mpx-portal';
|
|
11
12
|
const radioGroup = forwardRef((props, ref) => {
|
|
12
13
|
const { style = {}, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight } = props;
|
|
13
14
|
const propsRef = useRef({});
|
|
@@ -23,7 +24,7 @@ const radioGroup = forwardRef((props, ref) => {
|
|
|
23
24
|
flexWrap: 'wrap'
|
|
24
25
|
};
|
|
25
26
|
const styleObj = extendObject({}, defaultStyle, style);
|
|
26
|
-
const { hasSelfPercent, normalStyle, hasVarDec, varContextRef, setWidth, setHeight } = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
|
|
27
|
+
const { hasPositionFixed, hasSelfPercent, normalStyle, hasVarDec, varContextRef, setWidth, setHeight } = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
|
|
27
28
|
const nodeRef = useRef(null);
|
|
28
29
|
useNodesRef(props, ref, nodeRef, { style: normalStyle });
|
|
29
30
|
const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef });
|
|
@@ -71,16 +72,22 @@ const radioGroup = forwardRef((props, ref) => {
|
|
|
71
72
|
notifyChange
|
|
72
73
|
};
|
|
73
74
|
}, []);
|
|
74
|
-
const innerProps = useInnerProps(props,
|
|
75
|
+
const innerProps = useInnerProps(extendObject({}, props, layoutProps, {
|
|
75
76
|
ref: nodeRef,
|
|
76
77
|
style: extendObject({}, normalStyle, layoutStyle)
|
|
77
|
-
}
|
|
78
|
+
}), ['name'], {
|
|
78
79
|
layoutRef
|
|
79
80
|
});
|
|
80
|
-
|
|
81
|
+
const finalComponent = createElement(View, innerProps, createElement(RadioGroupContext.Provider, {
|
|
82
|
+
value: contextValue
|
|
83
|
+
}, wrapChildren(props, {
|
|
81
84
|
hasVarDec,
|
|
82
85
|
varContext: varContextRef.current
|
|
83
86
|
})));
|
|
87
|
+
if (hasPositionFixed) {
|
|
88
|
+
return createElement(Portal, null, finalComponent);
|
|
89
|
+
}
|
|
90
|
+
return finalComponent;
|
|
84
91
|
});
|
|
85
92
|
radioGroup.displayName = 'MpxRadioGroup';
|
|
86
93
|
export default radioGroup;
|
|
@@ -12,6 +12,7 @@ import useInnerProps, { getCustomEvent } from './getInnerListeners';
|
|
|
12
12
|
import useNodesRef 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
|
const styles = StyleSheet.create({
|
|
16
17
|
container: {
|
|
17
18
|
flexDirection: 'row',
|
|
@@ -73,7 +74,7 @@ const Radio = forwardRef((radioProps, ref) => {
|
|
|
73
74
|
bindtap && bindtap(getCustomEvent('tap', evt, { layoutRef }, props));
|
|
74
75
|
onChange(evt);
|
|
75
76
|
};
|
|
76
|
-
const { hasSelfPercent, normalStyle, hasVarDec, varContextRef, setWidth, setHeight } = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
|
|
77
|
+
const { hasPositionFixed, hasSelfPercent, normalStyle, hasVarDec, varContextRef, setWidth, setHeight } = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
|
|
77
78
|
const { textStyle, backgroundStyle, innerStyle = {} } = splitStyle(normalStyle);
|
|
78
79
|
if (backgroundStyle) {
|
|
79
80
|
warn('Radio does not support background image-related styles!');
|
|
@@ -91,10 +92,9 @@ const Radio = forwardRef((radioProps, ref) => {
|
|
|
91
92
|
if (labelContext) {
|
|
92
93
|
labelContext.current.triggerChange = onChange;
|
|
93
94
|
}
|
|
94
|
-
const innerProps = useInnerProps(props,
|
|
95
|
+
const innerProps = useInnerProps(extendObject({}, props, layoutProps, {
|
|
95
96
|
ref: nodeRef,
|
|
96
|
-
style: extendObject({}, innerStyle, layoutStyle)
|
|
97
|
-
}, layoutProps, {
|
|
97
|
+
style: extendObject({}, innerStyle, layoutStyle),
|
|
98
98
|
bindtap: !disabled && onTap
|
|
99
99
|
}), [
|
|
100
100
|
'value',
|
|
@@ -124,7 +124,7 @@ const Radio = forwardRef((radioProps, ref) => {
|
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
}, [checked]);
|
|
127
|
-
|
|
127
|
+
const finalComponent = createElement(View, innerProps, createElement(View, { style: defaultStyle }, createElement(Icon, {
|
|
128
128
|
type: 'success',
|
|
129
129
|
size: 24,
|
|
130
130
|
color: disabled ? '#E1E1E1' : color,
|
|
@@ -135,6 +135,10 @@ const Radio = forwardRef((radioProps, ref) => {
|
|
|
135
135
|
textStyle,
|
|
136
136
|
textProps
|
|
137
137
|
}));
|
|
138
|
+
if (hasPositionFixed) {
|
|
139
|
+
return createElement(Portal, null, finalComponent);
|
|
140
|
+
}
|
|
141
|
+
return finalComponent;
|
|
138
142
|
});
|
|
139
143
|
Radio.displayName = 'MpxRadio';
|
|
140
144
|
export default Radio;
|
|
@@ -8,6 +8,7 @@ import useNodesRef from '../useNodesRef'; // 引入辅助函数
|
|
|
8
8
|
import { useTransformStyle, useLayout, extendObject } from '../utils';
|
|
9
9
|
import { WebView } from 'react-native-webview';
|
|
10
10
|
import { generateHTML } from './html';
|
|
11
|
+
import Portal from '../mpx-portal';
|
|
11
12
|
function jsonToHtmlStr(elements) {
|
|
12
13
|
let htmlStr = '';
|
|
13
14
|
for (const element of elements) {
|
|
@@ -30,7 +31,7 @@ const _RichText = forwardRef((props, ref) => {
|
|
|
30
31
|
const { style = {}, nodes, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight } = props;
|
|
31
32
|
const nodeRef = useRef(null);
|
|
32
33
|
const [webViewHeight, setWebViewHeight] = useState(0);
|
|
33
|
-
const { normalStyle, hasSelfPercent, setWidth, setHeight } = useTransformStyle(Object.assign({
|
|
34
|
+
const { normalStyle, hasSelfPercent, setWidth, setHeight, hasPositionFixed } = useTransformStyle(Object.assign({
|
|
34
35
|
width: '100%',
|
|
35
36
|
height: webViewHeight
|
|
36
37
|
}, style), {
|
|
@@ -44,19 +45,23 @@ const _RichText = forwardRef((props, ref) => {
|
|
|
44
45
|
useNodesRef(props, ref, nodeRef, {
|
|
45
46
|
layoutRef
|
|
46
47
|
});
|
|
47
|
-
const innerProps = useInnerProps(props,
|
|
48
|
+
const innerProps = useInnerProps(extendObject({}, props, layoutProps, {
|
|
48
49
|
ref: nodeRef,
|
|
49
50
|
style: extendObject(normalStyle, layoutStyle)
|
|
50
|
-
}
|
|
51
|
+
}), [], {
|
|
51
52
|
layoutRef
|
|
52
53
|
});
|
|
53
54
|
const html = typeof nodes === 'string' ? nodes : jsonToHtmlStr(nodes);
|
|
54
|
-
|
|
55
|
+
let finalComponent = createElement(View, innerProps, createElement(WebView, {
|
|
55
56
|
source: { html: generateHTML(html) },
|
|
56
57
|
onMessage: (event) => {
|
|
57
58
|
setWebViewHeight(+event.nativeEvent.data);
|
|
58
59
|
}
|
|
59
60
|
}));
|
|
61
|
+
if (hasPositionFixed) {
|
|
62
|
+
finalComponent = createElement(Portal, null, finalComponent);
|
|
63
|
+
}
|
|
64
|
+
return finalComponent;
|
|
60
65
|
});
|
|
61
66
|
_RichText.displayName = 'mpx-rich-text';
|
|
62
67
|
export default _RichText;
|
|
@@ -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(
|
|
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,
|
|
@@ -491,7 +506,7 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
|
|
|
491
506
|
pagingEnabled
|
|
492
507
|
});
|
|
493
508
|
}
|
|
494
|
-
const innerProps = useInnerProps(props, scrollAdditionalProps, [
|
|
509
|
+
const innerProps = useInnerProps(extendObject({}, props, scrollAdditionalProps), [
|
|
495
510
|
'id',
|
|
496
511
|
'scroll-x',
|
|
497
512
|
'scroll-y',
|
|
@@ -518,13 +533,14 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
|
|
|
518
533
|
'bindscrolltolower',
|
|
519
534
|
'bindrefresherrefresh'
|
|
520
535
|
], { layoutRef });
|
|
521
|
-
const
|
|
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(
|
|
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
|
-
|
|
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;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { Text } from 'react-native';
|
|
2
2
|
import { createElement } from 'react';
|
|
3
3
|
import useInnerProps from './getInnerListeners';
|
|
4
|
+
import { extendObject } from './utils';
|
|
4
5
|
const SimpleText = (props) => {
|
|
5
6
|
const { allowFontScaling = false, children } = props;
|
|
6
|
-
const innerProps = useInnerProps(props, {
|
|
7
|
+
const innerProps = useInnerProps(extendObject({}, props, {
|
|
7
8
|
allowFontScaling
|
|
8
|
-
}
|
|
9
|
+
}));
|
|
9
10
|
return createElement(Text, innerProps, children);
|
|
10
11
|
};
|
|
11
12
|
SimpleText.displayName = 'MpxSimpleText';
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { View } from 'react-native';
|
|
2
2
|
import { createElement } from 'react';
|
|
3
|
-
import { splitProps, splitStyle, wrapChildren } from './utils';
|
|
3
|
+
import { splitProps, splitStyle, wrapChildren, extendObject } from './utils';
|
|
4
4
|
import useInnerProps from './getInnerListeners';
|
|
5
5
|
const SimpleView = (simpleViewProps) => {
|
|
6
6
|
const { textProps, innerProps: props = {} } = splitProps(simpleViewProps);
|
|
7
7
|
const { textStyle, innerStyle = {} } = splitStyle(props.style || {});
|
|
8
|
-
const innerProps = useInnerProps(props, {
|
|
8
|
+
const innerProps = useInnerProps(extendObject({}, props, {
|
|
9
9
|
style: innerStyle
|
|
10
|
-
}
|
|
10
|
+
}));
|
|
11
11
|
return createElement(View, innerProps, wrapChildren(props, {
|
|
12
12
|
hasVarDec: false,
|
|
13
13
|
textStyle: textStyle,
|
|
@@ -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;
|