@mpxjs/webpack-plugin 2.10.18-beta.11 → 2.10.18-beta.13
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/platform/template/wx/component-config/index.js +1 -5
- package/lib/react/style-helper.js +7 -16
- package/lib/runtime/components/ali/mpx-section-list.mpx +1 -1
- package/lib/runtime/components/extends/section-list.mpx +1 -0
- package/lib/runtime/components/extends/sticky-heder.mpx +1 -0
- package/lib/runtime/components/extends/sticky-section.mpx +1 -0
- package/lib/runtime/components/react/animationHooks/useTransitionHooks.ts +48 -6
- package/lib/runtime/components/react/dist/animationHooks/useTransitionHooks.js +44 -6
- package/lib/runtime/components/react/dist/mpx-icon/icons/cancel.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/clear.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/download.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/info.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/search.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/success.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/success_no_circle.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/waiting.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/warn.png +0 -0
- package/lib/runtime/components/react/dist/mpx-input.jsx +3 -8
- package/lib/runtime/components/react/dist/mpx-picker-view-column/index.jsx +9 -0
- package/lib/runtime/components/react/dist/mpx-section-list.d.ts +5 -2
- package/lib/runtime/components/react/dist/mpx-section-list.jsx +31 -15
- package/lib/runtime/components/react/dist/mpx-swiper.d.ts +1 -0
- package/lib/runtime/components/react/dist/mpx-swiper.jsx +15 -3
- package/lib/runtime/components/react/dist/utils.jsx +1 -1
- package/lib/runtime/components/react/mpx-section-list.tsx +56 -30
- package/lib/runtime/components/web/mpx-section-list.vue +1 -1
- package/package.json +1 -1
- package/lib/platform/template/wx/component-config/sticky-header.js +0 -23
- package/lib/platform/template/wx/component-config/sticky-section.js +0 -23
|
@@ -42,8 +42,6 @@ const wxs = require('./wxs')
|
|
|
42
42
|
const component = require('./component')
|
|
43
43
|
const fixComponentName = require('./fix-component-name')
|
|
44
44
|
const rootPortal = require('./root-portal')
|
|
45
|
-
const stickyHeader = require('./sticky-header')
|
|
46
|
-
const stickySection = require('./sticky-section')
|
|
47
45
|
|
|
48
46
|
module.exports = function getComponentConfigs ({ warn, error }) {
|
|
49
47
|
/**
|
|
@@ -127,8 +125,6 @@ module.exports = function getComponentConfigs ({ warn, error }) {
|
|
|
127
125
|
hyphenTagName({ print }),
|
|
128
126
|
label({ print }),
|
|
129
127
|
component(),
|
|
130
|
-
rootPortal({ print })
|
|
131
|
-
stickyHeader({ print }),
|
|
132
|
-
stickySection({ print })
|
|
128
|
+
rootPortal({ print })
|
|
133
129
|
]
|
|
134
130
|
}
|
|
@@ -135,27 +135,18 @@ function getClassMap ({ content, filename, mode, srcMode, ctorType, formatValueN
|
|
|
135
135
|
if (classMapKeys.length) {
|
|
136
136
|
classMapKeys.forEach((key) => {
|
|
137
137
|
if (Object.keys(classMapValue).length) {
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
// set css defalut value
|
|
139
|
+
const val = classMap[key] || {}
|
|
140
|
+
classMap[key] = Object.assign(val, classMapValue)
|
|
141
|
+
|
|
142
|
+
// set css media
|
|
140
143
|
if (isMedia) {
|
|
141
|
-
|
|
142
|
-
_default = _default || {}
|
|
143
|
-
_media = _media || []
|
|
144
|
+
const _media = classMap[key]?._media || []
|
|
144
145
|
_media.push({
|
|
145
146
|
options,
|
|
146
147
|
value: classMapValue
|
|
147
148
|
})
|
|
148
|
-
classMap[key] =
|
|
149
|
-
_media,
|
|
150
|
-
_default
|
|
151
|
-
}
|
|
152
|
-
} else if (_default) {
|
|
153
|
-
// 已有媒体查询数据,此次非媒体查询
|
|
154
|
-
Object.assign(_default, classMapValue)
|
|
155
|
-
} else {
|
|
156
|
-
// 无媒体查询
|
|
157
|
-
const val = classMap[key] || {}
|
|
158
|
-
classMap[key] = Object.assign(val, classMapValue)
|
|
149
|
+
classMap[key]._media = _media
|
|
159
150
|
}
|
|
160
151
|
}
|
|
161
152
|
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<!-- section-list 占位文件-->
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<!-- sticky-header 占位文件-->
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<!-- sticky-section 占位文件-->
|
|
@@ -144,7 +144,7 @@ function parseTransitionStyle (originalStyle: ExtendedViewStyle) {
|
|
|
144
144
|
const transitionMap = transitionData.reduce((acc, cur) => {
|
|
145
145
|
// hasOwn(transitionSupportedProperty, dash2hump(val)) || val === Transform
|
|
146
146
|
const { property = '', duration = 0, delay = 0, easing = Easing.inOut(Easing.ease) } = cur
|
|
147
|
-
if ((hasOwn(transitionSupportedProperty, dash2hump(property)) || property === 'transform') && duration
|
|
147
|
+
if ((hasOwn(transitionSupportedProperty, dash2hump(property)) || property === 'transform') && duration >= 0) {
|
|
148
148
|
acc[property] = {
|
|
149
149
|
duration,
|
|
150
150
|
delay,
|
|
@@ -157,17 +157,59 @@ function parseTransitionStyle (originalStyle: ExtendedViewStyle) {
|
|
|
157
157
|
return transitionMap
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
+
const transitionKeys = ['transition', 'transitionDuration', 'transitionTimingFunction', 'transitionDelay', 'transitionProperty'] as const
|
|
161
|
+
|
|
162
|
+
function getTransitionPropertyKeys (map: TransitionMap): string {
|
|
163
|
+
return Object.keys(map).sort().join(',')
|
|
164
|
+
}
|
|
165
|
+
|
|
160
166
|
export default function useTransitionHooks<T, P> (props: AnimationHooksPropsType) {
|
|
161
167
|
// console.log(`useTransitionHooks, props=`, props)
|
|
162
168
|
const { style: originalStyle = {}, transitionend } = props
|
|
163
169
|
// style变更标识(首次render不执行),初始值为0,首次渲染后为1
|
|
164
170
|
const animationDeps = useRef(0)
|
|
165
|
-
//
|
|
166
|
-
|
|
167
|
-
|
|
171
|
+
// transition 时序属性动态更新追踪
|
|
172
|
+
const transitionMapVersionRef = useRef(0)
|
|
173
|
+
const lastTransitionStyleRef = useRef<Record<string, any>>(
|
|
174
|
+
transitionKeys.reduce((acc, key) => { acc[key] = originalStyle[key]; return acc }, {} as Record<string, any>)
|
|
175
|
+
)
|
|
176
|
+
const initialPropertyKeysRef = useRef('')
|
|
177
|
+
const prevTransitionMapRef = useRef<TransitionMap>({})
|
|
178
|
+
// 检测 transition 时序属性变化,返回版本号驱动 transitionMap 重新计算
|
|
179
|
+
const transitionMapVersion = useMemo(() => {
|
|
180
|
+
const prevStyle = lastTransitionStyleRef.current
|
|
181
|
+
const hasChanged = transitionKeys.some(key => prevStyle[key] !== originalStyle[key])
|
|
182
|
+
if (hasChanged) {
|
|
183
|
+
transitionKeys.forEach(key => { lastTransitionStyleRef.current[key] = originalStyle[key] })
|
|
184
|
+
transitionMapVersionRef.current++
|
|
185
|
+
}
|
|
186
|
+
return transitionMapVersionRef.current
|
|
187
|
+
}, [originalStyle])
|
|
188
|
+
// ** 从 style 中获取动画数据(支持动态更新 transitionDuration/transitionDelay/transitionTimingFunction)
|
|
168
189
|
const transitionMap = useMemo(() => {
|
|
169
|
-
|
|
170
|
-
|
|
190
|
+
const newTransitionMap = parseTransitionStyle(originalStyle)
|
|
191
|
+
const newPropertyKeys = getTransitionPropertyKeys(newTransitionMap)
|
|
192
|
+
if (!initialPropertyKeysRef.current) {
|
|
193
|
+
// 首次计算,记录初始属性集合
|
|
194
|
+
initialPropertyKeysRef.current = newPropertyKeys
|
|
195
|
+
prevTransitionMapRef.current = newTransitionMap
|
|
196
|
+
return newTransitionMap
|
|
197
|
+
}
|
|
198
|
+
// 检测 transitionProperty 是否变化
|
|
199
|
+
if (newPropertyKeys !== initialPropertyKeysRef.current) {
|
|
200
|
+
error('[Mpx runtime error]: dynamic setting transitionProperty is not supported')
|
|
201
|
+
// 保留初始属性集合,仅更新已有属性的时序
|
|
202
|
+
const prevMap = prevTransitionMapRef.current
|
|
203
|
+
const result = Object.keys(prevMap).reduce((map, property) => {
|
|
204
|
+
map[property] = newTransitionMap[property] || prevMap[property]
|
|
205
|
+
return map
|
|
206
|
+
}, {} as TransitionMap)
|
|
207
|
+
prevTransitionMapRef.current = result
|
|
208
|
+
return result
|
|
209
|
+
}
|
|
210
|
+
prevTransitionMapRef.current = newTransitionMap
|
|
211
|
+
return newTransitionMap
|
|
212
|
+
}, [transitionMapVersion])
|
|
171
213
|
// ** style prop sharedValue interpolateOutput: SharedValue<InterpolateOutput>
|
|
172
214
|
const { shareValMap, animatedKeys, animatedStyleKeys } = useMemo(() => {
|
|
173
215
|
// 记录需要执行动画的 propName
|
|
@@ -117,7 +117,7 @@ function parseTransitionStyle(originalStyle) {
|
|
|
117
117
|
const transitionMap = transitionData.reduce((acc, cur) => {
|
|
118
118
|
// hasOwn(transitionSupportedProperty, dash2hump(val)) || val === Transform
|
|
119
119
|
const { property = '', duration = 0, delay = 0, easing = Easing.inOut(Easing.ease) } = cur;
|
|
120
|
-
if ((hasOwn(transitionSupportedProperty, dash2hump(property)) || property === 'transform') && duration
|
|
120
|
+
if ((hasOwn(transitionSupportedProperty, dash2hump(property)) || property === 'transform') && duration >= 0) {
|
|
121
121
|
acc[property] = {
|
|
122
122
|
duration,
|
|
123
123
|
delay,
|
|
@@ -129,17 +129,55 @@ function parseTransitionStyle(originalStyle) {
|
|
|
129
129
|
// console.log(`parseTransitionStyle transitionMap=`, transitionMap)
|
|
130
130
|
return transitionMap;
|
|
131
131
|
}
|
|
132
|
+
const transitionKeys = ['transition', 'transitionDuration', 'transitionTimingFunction', 'transitionDelay', 'transitionProperty'];
|
|
133
|
+
function getTransitionPropertyKeys(map) {
|
|
134
|
+
return Object.keys(map).sort().join(',');
|
|
135
|
+
}
|
|
132
136
|
export default function useTransitionHooks(props) {
|
|
133
137
|
// console.log(`useTransitionHooks, props=`, props)
|
|
134
138
|
const { style: originalStyle = {}, transitionend } = props;
|
|
135
139
|
// style变更标识(首次render不执行),初始值为0,首次渲染后为1
|
|
136
140
|
const animationDeps = useRef(0);
|
|
137
|
-
//
|
|
138
|
-
|
|
139
|
-
|
|
141
|
+
// transition 时序属性动态更新追踪
|
|
142
|
+
const transitionMapVersionRef = useRef(0);
|
|
143
|
+
const lastTransitionStyleRef = useRef(transitionKeys.reduce((acc, key) => { acc[key] = originalStyle[key]; return acc; }, {}));
|
|
144
|
+
const initialPropertyKeysRef = useRef('');
|
|
145
|
+
const prevTransitionMapRef = useRef({});
|
|
146
|
+
// 检测 transition 时序属性变化,返回版本号驱动 transitionMap 重新计算
|
|
147
|
+
const transitionMapVersion = useMemo(() => {
|
|
148
|
+
const prevStyle = lastTransitionStyleRef.current;
|
|
149
|
+
const hasChanged = transitionKeys.some(key => prevStyle[key] !== originalStyle[key]);
|
|
150
|
+
if (hasChanged) {
|
|
151
|
+
transitionKeys.forEach(key => { lastTransitionStyleRef.current[key] = originalStyle[key]; });
|
|
152
|
+
transitionMapVersionRef.current++;
|
|
153
|
+
}
|
|
154
|
+
return transitionMapVersionRef.current;
|
|
155
|
+
}, [originalStyle]);
|
|
156
|
+
// ** 从 style 中获取动画数据(支持动态更新 transitionDuration/transitionDelay/transitionTimingFunction)
|
|
140
157
|
const transitionMap = useMemo(() => {
|
|
141
|
-
|
|
142
|
-
|
|
158
|
+
const newTransitionMap = parseTransitionStyle(originalStyle);
|
|
159
|
+
const newPropertyKeys = getTransitionPropertyKeys(newTransitionMap);
|
|
160
|
+
if (!initialPropertyKeysRef.current) {
|
|
161
|
+
// 首次计算,记录初始属性集合
|
|
162
|
+
initialPropertyKeysRef.current = newPropertyKeys;
|
|
163
|
+
prevTransitionMapRef.current = newTransitionMap;
|
|
164
|
+
return newTransitionMap;
|
|
165
|
+
}
|
|
166
|
+
// 检测 transitionProperty 是否变化
|
|
167
|
+
if (newPropertyKeys !== initialPropertyKeysRef.current) {
|
|
168
|
+
error('[Mpx runtime error]: dynamic setting transitionProperty is not supported');
|
|
169
|
+
// 保留初始属性集合,仅更新已有属性的时序
|
|
170
|
+
const prevMap = prevTransitionMapRef.current;
|
|
171
|
+
const result = Object.keys(prevMap).reduce((map, property) => {
|
|
172
|
+
map[property] = newTransitionMap[property] || prevMap[property];
|
|
173
|
+
return map;
|
|
174
|
+
}, {});
|
|
175
|
+
prevTransitionMapRef.current = result;
|
|
176
|
+
return result;
|
|
177
|
+
}
|
|
178
|
+
prevTransitionMapRef.current = newTransitionMap;
|
|
179
|
+
return newTransitionMap;
|
|
180
|
+
}, [transitionMapVersion]);
|
|
143
181
|
// ** style prop sharedValue interpolateOutput: SharedValue<InterpolateOutput>
|
|
144
182
|
const { shareValMap, animatedKeys, animatedStyleKeys } = useMemo(() => {
|
|
145
183
|
// 记录需要执行动画的 propName
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
import { forwardRef, useRef, useState, useContext, useEffect, createElement } from 'react';
|
|
41
41
|
import { TextInput } from 'react-native';
|
|
42
42
|
import { warn } from '@mpxjs/utils';
|
|
43
|
-
import { useUpdateEffect, useTransformStyle, useLayout, extendObject
|
|
43
|
+
import { useUpdateEffect, useTransformStyle, useLayout, extendObject } from './utils';
|
|
44
44
|
import useInnerProps, { getCustomEvent } from './getInnerListeners';
|
|
45
45
|
import useNodesRef from './useNodesRef';
|
|
46
46
|
import { FormContext, KeyboardAvoidContext } from './context';
|
|
@@ -285,11 +285,6 @@ const Input = forwardRef((props, ref) => {
|
|
|
285
285
|
? nodeRef.current?.focus()
|
|
286
286
|
: nodeRef.current?.blur();
|
|
287
287
|
}, [isAutoFocus]);
|
|
288
|
-
// 使用 multiline 来修复光标位置问题
|
|
289
|
-
// React Native 的 TextInput 在 textAlign center + placeholder 时光标会跑到右边
|
|
290
|
-
// 这个问题只在 Android 上出现
|
|
291
|
-
// 参考:https://github.com/facebook/react-native/issues/28794 (Android only)
|
|
292
|
-
const needMultilineFix = isAndroid && !multiline;
|
|
293
288
|
const innerProps = useInnerProps(extendObject({}, props, layoutProps, {
|
|
294
289
|
ref: nodeRef,
|
|
295
290
|
style: extendObject({}, normalStyle, layoutStyle),
|
|
@@ -308,7 +303,7 @@ const Input = forwardRef((props, ref) => {
|
|
|
308
303
|
underlineColorAndroid: 'rgba(0,0,0,0)',
|
|
309
304
|
textAlignVertical: textAlignVertical,
|
|
310
305
|
placeholderTextColor: placeholderStyle?.color,
|
|
311
|
-
multiline: multiline
|
|
306
|
+
multiline: !!multiline,
|
|
312
307
|
onTouchStart,
|
|
313
308
|
onTouchEnd,
|
|
314
309
|
onFocus,
|
|
@@ -317,7 +312,7 @@ const Input = forwardRef((props, ref) => {
|
|
|
317
312
|
onSelectionChange,
|
|
318
313
|
onContentSizeChange,
|
|
319
314
|
onSubmitEditing: bindconfirm && onSubmitEditing
|
|
320
|
-
},
|
|
315
|
+
}, !!multiline && confirmType === 'return' ? {} : { enterKeyHint: confirmType }), [
|
|
321
316
|
'type',
|
|
322
317
|
'password',
|
|
323
318
|
'placeholder-style',
|
|
@@ -73,6 +73,15 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
73
73
|
clearTimerScrollTo();
|
|
74
74
|
};
|
|
75
75
|
}, []);
|
|
76
|
+
// `contentOffset` prop sets visual position but does not fire scroll events,
|
|
77
|
+
// so `offsetYShared` (from `useScrollViewOffset`) stays at 0 until the user scrolls.
|
|
78
|
+
// Directly sync it whenever `itemRawH` is established so wheel animation renders correctly.
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
if (!itemRawH || dragging.current || scrolling.current) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
offsetYShared.value = activeIndex.current * itemRawH;
|
|
84
|
+
}, [itemRawH]);
|
|
76
85
|
useEffect(() => {
|
|
77
86
|
if (!scrollViewRef.current ||
|
|
78
87
|
!itemRawH ||
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { GestureHandler } from './utils';
|
|
2
3
|
interface ListItem {
|
|
3
4
|
isSectionHeader?: boolean;
|
|
4
5
|
_originalItemIndex?: number;
|
|
@@ -39,10 +40,12 @@ interface SectionListProps {
|
|
|
39
40
|
'refresher-enabled'?: boolean;
|
|
40
41
|
'show-scrollbar'?: boolean;
|
|
41
42
|
'refresher-triggered'?: boolean;
|
|
43
|
+
'wait-for'?: Array<GestureHandler>;
|
|
44
|
+
'simultaneous-handlers'?: Array<GestureHandler>;
|
|
42
45
|
bindrefresherrefresh?: (event: any) => void;
|
|
43
46
|
bindscrolltolower?: (event: any) => void;
|
|
44
47
|
bindscroll?: (event: any) => void;
|
|
45
48
|
[key: string]: any;
|
|
46
49
|
}
|
|
47
|
-
declare const _SectionList:
|
|
50
|
+
declare const _SectionList: import("react").ForwardRefExoticComponent<Omit<SectionListProps, "ref"> & import("react").RefAttributes<any>>;
|
|
48
51
|
export default _SectionList;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { forwardRef, useRef, useState, useEffect, useMemo, createElement, useImperativeHandle, memo } from 'react';
|
|
2
2
|
import { SectionList, RefreshControl } from 'react-native';
|
|
3
|
+
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
|
|
3
4
|
import useInnerProps, { getCustomEvent } from './getInnerListeners';
|
|
4
|
-
import { extendObject, useLayout, useTransformStyle } from './utils';
|
|
5
|
+
import { extendObject, useLayout, useTransformStyle, flatGesture } from './utils';
|
|
5
6
|
const getGeneric = (generichash, generickey) => {
|
|
6
7
|
if (!generichash || !generickey)
|
|
7
8
|
return null;
|
|
@@ -15,9 +16,10 @@ const getGeneric = (generichash, generickey) => {
|
|
|
15
16
|
}));
|
|
16
17
|
};
|
|
17
18
|
const _SectionList = forwardRef((props = {}, ref) => {
|
|
18
|
-
const { enhanced = false, bounces = true, scrollEventThrottle = 0, height, width, listData, generichash, style = {}, itemHeight = {}, sectionHeaderHeight = {}, listHeaderHeight = {}, listHeaderData = null, useListHeader = false, listFooterData = null, useListFooter = false, 'genericrecycle-item': genericrecycleItem, 'genericsection-header': genericsectionHeader, 'genericlist-header': genericListHeader, 'genericlist-footer': genericListFooter, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, 'enable-sticky': enableSticky = false, 'enable-back-to-top': enableBackToTop = false, 'end-reached-threshold': onEndReachedThreshold = 0.1, 'refresher-enabled': refresherEnabled, 'show-scrollbar': showScrollbar = true, 'refresher-triggered': refresherTriggered } = props;
|
|
19
|
+
const { enhanced = false, bounces = true, scrollEventThrottle = 0, height, width, listData, generichash, style = {}, itemHeight = {}, sectionHeaderHeight = {}, listHeaderHeight = {}, listHeaderData = null, useListHeader = false, listFooterData = null, useListFooter = false, 'genericrecycle-item': genericrecycleItem, 'genericsection-header': genericsectionHeader, 'genericlist-header': genericListHeader, 'genericlist-footer': genericListFooter, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, 'enable-sticky': enableSticky = false, 'enable-back-to-top': enableBackToTop = false, 'end-reached-threshold': onEndReachedThreshold = 0.1, 'refresher-enabled': refresherEnabled, 'show-scrollbar': showScrollbar = true, 'refresher-triggered': refresherTriggered, 'simultaneous-handlers': originSimultaneousHandlers, 'wait-for': waitFor } = props;
|
|
19
20
|
const [refreshing, setRefreshing] = useState(!!refresherTriggered);
|
|
20
21
|
const scrollViewRef = useRef(null);
|
|
22
|
+
const sectionListGestureRef = useRef();
|
|
21
23
|
const indexMap = useRef({});
|
|
22
24
|
const reverseIndexMap = useRef({});
|
|
23
25
|
const { hasSelfPercent, setWidth, setHeight } = useTransformStyle(style, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
|
|
@@ -176,13 +178,13 @@ const _SectionList = forwardRef((props = {}, ref) => {
|
|
|
176
178
|
offset += headerHeight;
|
|
177
179
|
// 添加该 section 中所有 items 的位置信息
|
|
178
180
|
section.data.forEach((item, itemIndex) => {
|
|
179
|
-
const
|
|
181
|
+
const contentHeight = getItemHeight({ sectionIndex, rowIndex: itemIndex });
|
|
180
182
|
layouts.push({
|
|
181
|
-
length:
|
|
183
|
+
length: contentHeight,
|
|
182
184
|
offset,
|
|
183
185
|
index: layouts.length
|
|
184
186
|
});
|
|
185
|
-
offset +=
|
|
187
|
+
offset += contentHeight;
|
|
186
188
|
});
|
|
187
189
|
// 添加该 section 尾部位置信息
|
|
188
190
|
// 因为即使 sectionList 没传 renderSectionFooter,getItemLayout 中的 index 的计算也会包含尾部节点
|
|
@@ -210,21 +212,33 @@ const _SectionList = forwardRef((props = {}, ref) => {
|
|
|
210
212
|
onScroll: onScroll,
|
|
211
213
|
onEndReached: onEndReached
|
|
212
214
|
}, layoutProps);
|
|
215
|
+
const nativeGesture = useMemo(() => {
|
|
216
|
+
const simultaneousHandlers = flatGesture(originSimultaneousHandlers);
|
|
217
|
+
const waitForHandlers = flatGesture(waitFor);
|
|
218
|
+
const gesture = Gesture.Native().withRef(sectionListGestureRef);
|
|
219
|
+
if (simultaneousHandlers && simultaneousHandlers.length) {
|
|
220
|
+
gesture.simultaneousWithExternalGesture(...simultaneousHandlers);
|
|
221
|
+
}
|
|
222
|
+
if (waitForHandlers && waitForHandlers.length) {
|
|
223
|
+
gesture.requireExternalGestureToFail(...waitForHandlers);
|
|
224
|
+
}
|
|
225
|
+
return gesture;
|
|
226
|
+
}, [originSimultaneousHandlers, waitFor]);
|
|
213
227
|
if (enhanced) {
|
|
214
|
-
|
|
228
|
+
extendObject(scrollAdditionalProps, {
|
|
215
229
|
bounces
|
|
216
230
|
});
|
|
217
231
|
}
|
|
218
232
|
if (refresherEnabled) {
|
|
219
|
-
|
|
233
|
+
extendObject(scrollAdditionalProps, {
|
|
220
234
|
refreshing: refreshing
|
|
221
235
|
});
|
|
222
236
|
}
|
|
223
237
|
useImperativeHandle(ref, () => {
|
|
224
|
-
return {
|
|
225
|
-
|
|
238
|
+
return extendObject({}, props, {
|
|
239
|
+
gestureRef: sectionListGestureRef,
|
|
226
240
|
scrollToIndex
|
|
227
|
-
};
|
|
241
|
+
});
|
|
228
242
|
});
|
|
229
243
|
const innerProps = useInnerProps(extendObject({}, props, scrollAdditionalProps), [
|
|
230
244
|
'id',
|
|
@@ -232,7 +246,9 @@ const _SectionList = forwardRef((props = {}, ref) => {
|
|
|
232
246
|
'lower-threshold',
|
|
233
247
|
'refresher-triggered',
|
|
234
248
|
'refresher-enabled',
|
|
235
|
-
'bindrefresherrefresh'
|
|
249
|
+
'bindrefresherrefresh',
|
|
250
|
+
'simultaneous-handlers',
|
|
251
|
+
'wait-for'
|
|
236
252
|
], { layoutRef });
|
|
237
253
|
// 使用 ref 保存最新的数据,避免数据变化时组件销毁重建
|
|
238
254
|
const listHeaderDataRef = useRef(listHeaderData);
|
|
@@ -272,7 +288,7 @@ const _SectionList = forwardRef((props = {}, ref) => {
|
|
|
272
288
|
return null;
|
|
273
289
|
return () => createElement(ListFooterGenericComponent, { listFooterData: listFooterDataRef.current });
|
|
274
290
|
}, [useListFooter, generichash, genericListFooter]);
|
|
275
|
-
return createElement(SectionList, extendObject({
|
|
291
|
+
return createElement(GestureDetector, { gesture: nativeGesture }, createElement(SectionList, extendObject({
|
|
276
292
|
style: [{ height, width }, style, layoutStyle],
|
|
277
293
|
sections: convertedListData,
|
|
278
294
|
renderItem: renderItem,
|
|
@@ -281,12 +297,12 @@ const _SectionList = forwardRef((props = {}, ref) => {
|
|
|
281
297
|
ListFooterComponent: useListFooter ? ListFooterComponent : null,
|
|
282
298
|
renderSectionHeader: renderSectionHeader,
|
|
283
299
|
refreshControl: refresherEnabled
|
|
284
|
-
?
|
|
300
|
+
? createElement(RefreshControl, {
|
|
285
301
|
onRefresh: onRefresh,
|
|
286
302
|
refreshing: refreshing
|
|
287
303
|
})
|
|
288
304
|
: undefined
|
|
289
|
-
}, innerProps));
|
|
305
|
+
}, innerProps)));
|
|
290
306
|
});
|
|
291
307
|
_SectionList.displayName = 'MpxSectionList';
|
|
292
308
|
export default _SectionList;
|
|
@@ -58,6 +58,7 @@ interface SwiperProps {
|
|
|
58
58
|
disableGesture?: boolean;
|
|
59
59
|
'display-multiple-items'?: number;
|
|
60
60
|
bindchange?: (event: NativeSyntheticEvent<TouchEvent> | unknown) => void;
|
|
61
|
+
bindchangestart?: (event: NativeSyntheticEvent<TouchEvent> | unknown) => void;
|
|
61
62
|
}
|
|
62
63
|
declare const SwiperWrapper: React.ForwardRefExoticComponent<SwiperProps & React.RefAttributes<HandlerRef<View, SwiperProps>>>;
|
|
63
64
|
export default SwiperWrapper;
|
|
@@ -61,7 +61,7 @@ const easeMap = {
|
|
|
61
61
|
easeInOutCubic: Easing.inOut(Easing.cubic)
|
|
62
62
|
};
|
|
63
63
|
const SwiperWrapper = forwardRef((props, ref) => {
|
|
64
|
-
const { 'indicator-dots': showPagination, 'indicator-color': dotColor = 'rgba(0, 0, 0, .3)', 'indicator-width': dotWidth = 8, 'indicator-height': dotHeight = 8, 'indicator-radius': dotRadius = 4, 'indicator-spacing': dotSpacing = 4, 'indicator-margin': paginationMargin = 10, '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, current: propCurrent = 0, bindchange } = props;
|
|
64
|
+
const { 'indicator-dots': showPagination, 'indicator-color': dotColor = 'rgba(0, 0, 0, .3)', 'indicator-width': dotWidth = 8, 'indicator-height': dotHeight = 8, 'indicator-radius': dotRadius = 4, 'indicator-spacing': dotSpacing = 4, 'indicator-margin': paginationMargin = 10, '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, current: propCurrent = 0, bindchange, bindchangestart } = props;
|
|
65
65
|
const dotCommonStyle = {
|
|
66
66
|
width: dotWidth,
|
|
67
67
|
height: dotHeight,
|
|
@@ -300,6 +300,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
300
300
|
nextIndex += 1;
|
|
301
301
|
// targetOffset = -nextIndex * step.value - preMarginShared.value
|
|
302
302
|
targetOffset = -nextIndex * step.value;
|
|
303
|
+
runOnJSCallback('handleSwiperChangeStart', nextIndex);
|
|
303
304
|
offset.value = withTiming(targetOffset, {
|
|
304
305
|
duration: easeDuration,
|
|
305
306
|
easing: easeMap[easeingFunc]
|
|
@@ -314,6 +315,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
314
315
|
nextIndex = 0;
|
|
315
316
|
targetOffset = -(childrenLength.value + patchElmNumShared.value) * step.value + preMarginShared.value;
|
|
316
317
|
// 执行动画到下一帧
|
|
318
|
+
runOnJSCallback('handleSwiperChangeStart', nextIndex);
|
|
317
319
|
offset.value = withTiming(targetOffset, {
|
|
318
320
|
duration: easeDuration
|
|
319
321
|
}, () => {
|
|
@@ -328,6 +330,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
328
330
|
nextIndex = currentIndex.value + 1;
|
|
329
331
|
targetOffset = -(nextIndex + patchElmNumShared.value) * step.value + preMarginShared.value;
|
|
330
332
|
// 执行动画到下一帧
|
|
333
|
+
runOnJSCallback('handleSwiperChangeStart', nextIndex);
|
|
331
334
|
offset.value = withTiming(targetOffset, {
|
|
332
335
|
duration: easeDuration,
|
|
333
336
|
easing: easeMap[easeingFunc]
|
|
@@ -362,11 +365,16 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
362
365
|
const eventData = getCustomEvent('change', {}, { detail: { current, source: 'touch' }, layoutRef: layoutRef });
|
|
363
366
|
bindchange && bindchange(eventData);
|
|
364
367
|
}
|
|
368
|
+
function handleSwiperChangeStart(current) {
|
|
369
|
+
const eventData = getCustomEvent('changestart', {}, { detail: { current }, layoutRef: layoutRef });
|
|
370
|
+
bindchangestart && bindchangestart(eventData);
|
|
371
|
+
}
|
|
365
372
|
const runOnJSCallbackRef = useRef({
|
|
366
373
|
loop,
|
|
367
374
|
pauseLoop,
|
|
368
375
|
resumeLoop,
|
|
369
|
-
handleSwiperChange
|
|
376
|
+
handleSwiperChange,
|
|
377
|
+
handleSwiperChangeStart
|
|
370
378
|
});
|
|
371
379
|
const runOnJSCallback = useRunOnJSCallback(runOnJSCallbackRef);
|
|
372
380
|
function getOffset(index, stepValue) {
|
|
@@ -387,6 +395,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
387
395
|
if (targetOffset !== offset.value) {
|
|
388
396
|
// 内部基于props.current!==currentIndex.value决定是否使用动画及更新currentIndex.value
|
|
389
397
|
if (propCurrent !== undefined && propCurrent !== currentIndex.value) {
|
|
398
|
+
runOnJSCallback('handleSwiperChangeStart', propCurrent);
|
|
390
399
|
offset.value = withTiming(targetOffset, {
|
|
391
400
|
duration: easeDuration,
|
|
392
401
|
easing: easeMap[easeingFunc]
|
|
@@ -686,7 +695,10 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
686
695
|
const offsetHalf = computeHalf();
|
|
687
696
|
if (childrenLength.value > 1 && offsetHalf) {
|
|
688
697
|
const { selectedIndex } = getTargetPosition({ transdir: moveDistance });
|
|
689
|
-
currentIndex.value
|
|
698
|
+
if (selectedIndex !== currentIndex.value) {
|
|
699
|
+
currentIndex.value = selectedIndex;
|
|
700
|
+
runOnJS(runOnJSCallback)('handleSwiperChangeStart', selectedIndex);
|
|
701
|
+
}
|
|
690
702
|
}
|
|
691
703
|
// 2. 非循环: 处理用户一直拖拽到临界点的场景,如果放到onFinalize无法阻止offset.value更新为越界的值
|
|
692
704
|
if (!circularShared.value) {
|
|
@@ -285,7 +285,7 @@ export function parseValues(str, char = ' ') {
|
|
|
285
285
|
function parseTransform(transformStr) {
|
|
286
286
|
const values = parseValues(transformStr);
|
|
287
287
|
// Todo transform 排序不一致时,transform动画会闪烁,故这里同样的排序输出 transform
|
|
288
|
-
values.sort()
|
|
288
|
+
// values.sort()
|
|
289
289
|
const transform = [];
|
|
290
290
|
values.forEach(item => {
|
|
291
291
|
const match = item.match(/([/\w]+)\((.+)\)/);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { forwardRef, useRef, useState, useEffect, useMemo, createElement, useImperativeHandle, memo } from 'react'
|
|
2
2
|
import { SectionList, RefreshControl, NativeSyntheticEvent, NativeScrollEvent } from 'react-native'
|
|
3
|
+
import { Gesture, GestureDetector } from 'react-native-gesture-handler'
|
|
3
4
|
import useInnerProps, { getCustomEvent } from './getInnerListeners'
|
|
4
|
-
import { extendObject, useLayout, useTransformStyle } from './utils'
|
|
5
|
+
import { extendObject, useLayout, useTransformStyle, GestureHandler, flatGesture } from './utils'
|
|
5
6
|
interface ListItem {
|
|
6
7
|
isSectionHeader?: boolean;
|
|
7
8
|
_originalItemIndex?: number;
|
|
@@ -51,6 +52,8 @@ interface SectionListProps {
|
|
|
51
52
|
'refresher-enabled'?: boolean;
|
|
52
53
|
'show-scrollbar'?: boolean;
|
|
53
54
|
'refresher-triggered'?: boolean;
|
|
55
|
+
'wait-for'?: Array<GestureHandler>;
|
|
56
|
+
'simultaneous-handlers'?: Array<GestureHandler>;
|
|
54
57
|
bindrefresherrefresh?: (event: any) => void;
|
|
55
58
|
bindscrolltolower?: (event: any) => void;
|
|
56
59
|
bindscroll?: (event: any) => void;
|
|
@@ -107,12 +110,16 @@ const _SectionList = forwardRef<any, SectionListProps>((props = {}, ref) => {
|
|
|
107
110
|
'end-reached-threshold': onEndReachedThreshold = 0.1,
|
|
108
111
|
'refresher-enabled': refresherEnabled,
|
|
109
112
|
'show-scrollbar': showScrollbar = true,
|
|
110
|
-
'refresher-triggered': refresherTriggered
|
|
113
|
+
'refresher-triggered': refresherTriggered,
|
|
114
|
+
'simultaneous-handlers': originSimultaneousHandlers,
|
|
115
|
+
'wait-for': waitFor
|
|
111
116
|
} = props
|
|
112
117
|
|
|
113
118
|
const [refreshing, setRefreshing] = useState(!!refresherTriggered)
|
|
114
119
|
|
|
115
120
|
const scrollViewRef = useRef<any>(null)
|
|
121
|
+
const sectionListGestureRef = useRef<any>()
|
|
122
|
+
|
|
116
123
|
|
|
117
124
|
const indexMap = useRef<{ [key: string]: string | number }>({})
|
|
118
125
|
|
|
@@ -295,13 +302,13 @@ const _SectionList = forwardRef<any, SectionListProps>((props = {}, ref) => {
|
|
|
295
302
|
|
|
296
303
|
// 添加该 section 中所有 items 的位置信息
|
|
297
304
|
section.data.forEach((item: ListItem, itemIndex: number) => {
|
|
298
|
-
const
|
|
305
|
+
const contentHeight = getItemHeight({ sectionIndex, rowIndex: itemIndex })
|
|
299
306
|
layouts.push({
|
|
300
|
-
length:
|
|
307
|
+
length: contentHeight,
|
|
301
308
|
offset,
|
|
302
309
|
index: layouts.length
|
|
303
310
|
})
|
|
304
|
-
offset +=
|
|
311
|
+
offset += contentHeight
|
|
305
312
|
})
|
|
306
313
|
|
|
307
314
|
// 添加该 section 尾部位置信息
|
|
@@ -335,22 +342,35 @@ const _SectionList = forwardRef<any, SectionListProps>((props = {}, ref) => {
|
|
|
335
342
|
layoutProps
|
|
336
343
|
)
|
|
337
344
|
|
|
345
|
+
const nativeGesture = useMemo(() => {
|
|
346
|
+
const simultaneousHandlers = flatGesture(originSimultaneousHandlers)
|
|
347
|
+
const waitForHandlers = flatGesture(waitFor)
|
|
348
|
+
const gesture = Gesture.Native().withRef(sectionListGestureRef as any)
|
|
349
|
+
if (simultaneousHandlers && simultaneousHandlers.length) {
|
|
350
|
+
gesture.simultaneousWithExternalGesture(...simultaneousHandlers)
|
|
351
|
+
}
|
|
352
|
+
if (waitForHandlers && waitForHandlers.length) {
|
|
353
|
+
gesture.requireExternalGestureToFail(...waitForHandlers)
|
|
354
|
+
}
|
|
355
|
+
return gesture
|
|
356
|
+
}, [originSimultaneousHandlers, waitFor])
|
|
357
|
+
|
|
338
358
|
if (enhanced) {
|
|
339
|
-
|
|
359
|
+
extendObject(scrollAdditionalProps, {
|
|
340
360
|
bounces
|
|
341
361
|
})
|
|
342
362
|
}
|
|
343
363
|
if (refresherEnabled) {
|
|
344
|
-
|
|
364
|
+
extendObject(scrollAdditionalProps, {
|
|
345
365
|
refreshing: refreshing
|
|
346
366
|
})
|
|
347
367
|
}
|
|
348
368
|
|
|
349
369
|
useImperativeHandle(ref, () => {
|
|
350
|
-
return {
|
|
351
|
-
|
|
370
|
+
return extendObject({}, props, {
|
|
371
|
+
gestureRef: sectionListGestureRef,
|
|
352
372
|
scrollToIndex
|
|
353
|
-
}
|
|
373
|
+
})
|
|
354
374
|
})
|
|
355
375
|
|
|
356
376
|
const innerProps = useInnerProps(extendObject({}, props, scrollAdditionalProps), [
|
|
@@ -359,7 +379,9 @@ const _SectionList = forwardRef<any, SectionListProps>((props = {}, ref) => {
|
|
|
359
379
|
'lower-threshold',
|
|
360
380
|
'refresher-triggered',
|
|
361
381
|
'refresher-enabled',
|
|
362
|
-
'bindrefresherrefresh'
|
|
382
|
+
'bindrefresherrefresh',
|
|
383
|
+
'simultaneous-handlers',
|
|
384
|
+
'wait-for'
|
|
363
385
|
], { layoutRef })
|
|
364
386
|
|
|
365
387
|
// 使用 ref 保存最新的数据,避免数据变化时组件销毁重建
|
|
@@ -412,24 +434,28 @@ const _SectionList = forwardRef<any, SectionListProps>((props = {}, ref) => {
|
|
|
412
434
|
)
|
|
413
435
|
|
|
414
436
|
return createElement(
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
?
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
437
|
+
GestureDetector,
|
|
438
|
+
{ gesture: nativeGesture },
|
|
439
|
+
createElement(
|
|
440
|
+
SectionList,
|
|
441
|
+
extendObject(
|
|
442
|
+
{
|
|
443
|
+
style: [{ height, width }, style, layoutStyle],
|
|
444
|
+
sections: convertedListData,
|
|
445
|
+
renderItem: renderItem,
|
|
446
|
+
getItemLayout: getItemLayout,
|
|
447
|
+
ListHeaderComponent: useListHeader ? ListHeaderComponent : null,
|
|
448
|
+
ListFooterComponent: useListFooter ? ListFooterComponent : null,
|
|
449
|
+
renderSectionHeader: renderSectionHeader,
|
|
450
|
+
refreshControl: refresherEnabled
|
|
451
|
+
? createElement(RefreshControl, {
|
|
452
|
+
onRefresh: onRefresh,
|
|
453
|
+
refreshing: refreshing
|
|
454
|
+
})
|
|
455
|
+
: undefined
|
|
456
|
+
},
|
|
457
|
+
innerProps
|
|
458
|
+
)
|
|
433
459
|
)
|
|
434
460
|
)
|
|
435
461
|
})
|
package/package.json
CHANGED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
const TAG_NAME = 'sticky-header'
|
|
2
|
-
|
|
3
|
-
module.exports = function ({ print }) {
|
|
4
|
-
return {
|
|
5
|
-
test: TAG_NAME,
|
|
6
|
-
android (tag, { el }) {
|
|
7
|
-
el.isBuiltIn = true
|
|
8
|
-
return 'mpx-sticky-header'
|
|
9
|
-
},
|
|
10
|
-
ios (tag, { el }) {
|
|
11
|
-
el.isBuiltIn = true
|
|
12
|
-
return 'mpx-sticky-header'
|
|
13
|
-
},
|
|
14
|
-
harmony (tag, { el }) {
|
|
15
|
-
el.isBuiltIn = true
|
|
16
|
-
return 'mpx-sticky-header'
|
|
17
|
-
},
|
|
18
|
-
web (tag, { el }) {
|
|
19
|
-
el.isBuiltIn = true
|
|
20
|
-
return 'mpx-sticky-header'
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
const TAG_NAME = 'sticky-section'
|
|
2
|
-
|
|
3
|
-
module.exports = function ({ print }) {
|
|
4
|
-
return {
|
|
5
|
-
test: TAG_NAME,
|
|
6
|
-
android (tag, { el }) {
|
|
7
|
-
el.isBuiltIn = true
|
|
8
|
-
return 'mpx-sticky-section'
|
|
9
|
-
},
|
|
10
|
-
ios (tag, { el }) {
|
|
11
|
-
el.isBuiltIn = true
|
|
12
|
-
return 'mpx-sticky-section'
|
|
13
|
-
},
|
|
14
|
-
harmony (tag, { el }) {
|
|
15
|
-
el.isBuiltIn = true
|
|
16
|
-
return 'mpx-sticky-section'
|
|
17
|
-
},
|
|
18
|
-
web (tag, { el }) {
|
|
19
|
-
el.isBuiltIn = true
|
|
20
|
-
return 'mpx-sticky-section'
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|