@mpxjs/webpack-plugin 2.9.69-beta.3 → 2.9.69-beta.4
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 +17 -1
- package/lib/platform/style/wx/index.js +18 -18
- package/lib/platform/template/wx/component-config/movable-view.js +8 -1
- package/lib/platform/template/wx/component-config/scroll-view.js +1 -1
- package/lib/react/processScript.js +1 -1
- package/lib/resolver/AddEnvPlugin.js +1 -0
- package/lib/resolver/AddModePlugin.js +1 -0
- package/lib/runtime/components/react/context.ts +25 -0
- package/lib/runtime/components/react/dist/context.js +2 -0
- package/lib/runtime/components/react/dist/getInnerListeners.js +2 -2
- package/lib/runtime/components/react/dist/locale-provider.jsx +15 -0
- package/lib/runtime/components/react/dist/mpx-button.jsx +9 -37
- package/lib/runtime/components/react/dist/mpx-image.jsx +13 -9
- package/lib/runtime/components/react/dist/mpx-picker/time.jsx +2 -1
- package/lib/runtime/components/react/dist/mpx-picker-view-column.jsx +12 -13
- package/lib/runtime/components/react/dist/mpx-portal/portal-consumer.jsx +23 -0
- package/lib/runtime/components/react/dist/mpx-portal/portal-host.jsx +124 -0
- package/lib/runtime/components/react/dist/mpx-portal/portal-manager.jsx +40 -0
- package/lib/runtime/components/react/dist/mpx-portal.jsx +12 -0
- package/lib/runtime/components/react/dist/mpx-provider.jsx +31 -0
- package/lib/runtime/components/react/dist/mpx-root-portal.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +10 -16
- package/lib/runtime/components/react/dist/mpx-swiper.jsx +10 -5
- package/lib/runtime/components/react/dist/mpx-view.jsx +15 -21
- package/lib/runtime/components/react/dist/mpx-web-view.jsx +78 -20
- package/lib/runtime/components/react/dist/pickerFaces.js +1 -1
- package/lib/runtime/components/react/dist/useAnimationHooks.js +14 -2
- package/lib/runtime/components/react/getInnerListeners.ts +5 -7
- package/lib/runtime/components/react/locale-provider.tsx +83 -0
- package/lib/runtime/components/react/mpx-button.tsx +13 -49
- package/lib/runtime/components/react/mpx-image.tsx +41 -25
- package/lib/runtime/components/react/mpx-input.tsx +1 -1
- package/lib/runtime/components/react/mpx-movable-view.tsx +1 -1
- package/lib/runtime/components/react/mpx-picker/time.tsx +2 -1
- package/lib/runtime/components/react/mpx-picker-view-column-item.tsx +88 -0
- package/lib/runtime/components/react/mpx-picker-view-column.tsx +180 -163
- package/lib/runtime/components/react/mpx-picker-view.tsx +35 -37
- package/lib/runtime/components/react/mpx-portal/portal-consumer.tsx +32 -0
- package/lib/runtime/components/react/mpx-portal/portal-host.tsx +158 -0
- package/lib/runtime/components/react/mpx-portal/portal-manager.tsx +64 -0
- package/lib/runtime/components/react/mpx-portal.tsx +29 -0
- package/lib/runtime/components/react/mpx-provider.tsx +51 -0
- package/lib/runtime/components/react/mpx-rich-text/index.tsx +12 -18
- package/lib/runtime/components/react/mpx-root-portal.tsx +1 -1
- package/lib/runtime/components/react/mpx-scroll-view.tsx +29 -18
- package/lib/runtime/components/react/mpx-swiper-item.tsx +38 -10
- package/lib/runtime/components/react/mpx-swiper.tsx +696 -0
- package/lib/runtime/components/react/mpx-view.tsx +25 -71
- package/lib/runtime/components/react/mpx-web-view.tsx +156 -23
- package/lib/runtime/components/react/pickerFaces.ts +15 -7
- package/lib/runtime/components/react/pickerVIewContext.ts +18 -0
- package/lib/runtime/components/react/pickerViewMask.tsx +30 -0
- package/lib/runtime/components/react/{pickerOverlay.tsx → pickerViewOverlay.tsx} +5 -3
- package/lib/runtime/components/react/types/global.d.ts +6 -1
- package/lib/runtime/components/react/useAnimationHooks.ts +20 -4
- package/lib/runtime/components/react/utils.tsx +75 -5
- package/lib/style-compiler/index.js +3 -4
- package/lib/style-compiler/strip-conditional-loader.js +118 -0
- package/lib/template-compiler/compiler.js +9 -14
- package/lib/utils/hump-dash.js +1 -1
- package/lib/utils/pre-process-json.js +5 -9
- package/package.json +1 -1
- package/lib/runtime/components/react/mpx-swiper/carouse.tsx +0 -527
- package/lib/runtime/components/react/mpx-swiper/index.tsx +0 -80
- package/lib/runtime/components/react/mpx-swiper/type.ts +0 -87
package/lib/index.js
CHANGED
|
@@ -54,11 +54,13 @@ const wxssLoaderPath = normalize.lib('wxss/index')
|
|
|
54
54
|
const wxmlLoaderPath = normalize.lib('wxml/loader')
|
|
55
55
|
const wxsLoaderPath = normalize.lib('wxs/loader')
|
|
56
56
|
const styleCompilerPath = normalize.lib('style-compiler/index')
|
|
57
|
+
const styleStripConditaionalPath = normalize.lib('style-compiler/strip-conditional-loader')
|
|
57
58
|
const templateCompilerPath = normalize.lib('template-compiler/index')
|
|
58
59
|
const jsonCompilerPath = normalize.lib('json-compiler/index')
|
|
59
60
|
const jsonThemeCompilerPath = normalize.lib('json-compiler/theme')
|
|
60
61
|
const jsonPluginCompilerPath = normalize.lib('json-compiler/plugin')
|
|
61
62
|
const extractorPath = normalize.lib('extractor')
|
|
63
|
+
const selectorPath = normalize.lib('selector')
|
|
62
64
|
const async = require('async')
|
|
63
65
|
const { parseQuery } = require('loader-utils')
|
|
64
66
|
const stringifyLoadersAndResource = require('./utils/stringify-loaders-resource')
|
|
@@ -1775,7 +1777,7 @@ try {
|
|
|
1775
1777
|
})
|
|
1776
1778
|
|
|
1777
1779
|
const typeLoaderProcessInfo = {
|
|
1778
|
-
styles: ['node_modules/css-loader', wxssLoaderPath, styleCompilerPath],
|
|
1780
|
+
styles: ['node_modules/css-loader', wxssLoaderPath, styleCompilerPath, styleStripConditaionalPath],
|
|
1779
1781
|
template: ['node_modules/html-loader', wxmlLoaderPath, templateCompilerPath]
|
|
1780
1782
|
}
|
|
1781
1783
|
|
|
@@ -1833,6 +1835,20 @@ try {
|
|
|
1833
1835
|
loader: extractorPath
|
|
1834
1836
|
})
|
|
1835
1837
|
}
|
|
1838
|
+
if (type === 'styles') {
|
|
1839
|
+
// 判断最后一个loader是否是 selectorPath, 如果是,则在sectorPath之前插入strip-conditional
|
|
1840
|
+
const lastLoader = loaders[loaders.length - 1]
|
|
1841
|
+
if (lastLoader.loader.includes(selectorPath)) {
|
|
1842
|
+
loaders.splice(loaders.length - 1, 0, {
|
|
1843
|
+
loader: styleStripConditaionalPath
|
|
1844
|
+
})
|
|
1845
|
+
} else {
|
|
1846
|
+
// 在最后一个插入strip-conditional
|
|
1847
|
+
loaders.push({
|
|
1848
|
+
loader: styleStripConditaionalPath
|
|
1849
|
+
})
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1836
1852
|
createData.resource = addQuery(createData.resource, { mpx: MPX_PROCESSED_FLAG }, true)
|
|
1837
1853
|
}
|
|
1838
1854
|
// mpxStyleOptions 为 mpx style 文件的标识,避免 Vue 文件插入 styleCompiler 后导致 vue scoped 样式隔离失效
|
|
@@ -374,11 +374,11 @@ module.exports = function getSpec ({ warn, error }) {
|
|
|
374
374
|
// transform 转换
|
|
375
375
|
const formatTransform = ({ prop, value, selector }, { mode }) => {
|
|
376
376
|
// css var & 数组直接返回
|
|
377
|
-
if (Array.isArray(value) ||
|
|
377
|
+
if (Array.isArray(value) || cssVariableExp.test(value)) return { prop, value }
|
|
378
378
|
const values = parseValues(value)
|
|
379
379
|
const transform = []
|
|
380
380
|
values.forEach(item => {
|
|
381
|
-
const match = item.match(/([/\w]+)\((
|
|
381
|
+
const match = item.match(/([/\w]+)\((.+)\)/)
|
|
382
382
|
if (match && match.length >= 3) {
|
|
383
383
|
let key = match[1]
|
|
384
384
|
const val = match[2]
|
|
@@ -407,23 +407,23 @@ module.exports = function getSpec ({ warn, error }) {
|
|
|
407
407
|
case 'rotate3d': // x y z angle
|
|
408
408
|
case 'translate3d': // x y 支持 z不支持
|
|
409
409
|
case 'scale3d': // x y 支持 z不支持
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
}
|
|
418
|
-
const xyz = ['X', 'Y', 'Z']
|
|
419
|
-
transform.push(...vals.map((v, index) => {
|
|
420
|
-
if (key !== 'rotate' && index > 1) {
|
|
421
|
-
unsupportedPropError({ prop: `${key}Z`, value, selector }, { mode })
|
|
422
|
-
}
|
|
423
|
-
return { [`${key}${xyz[index] || ''}`]: v.trim() }
|
|
424
|
-
}))
|
|
425
|
-
break
|
|
410
|
+
{
|
|
411
|
+
// 2 个以上的值处理
|
|
412
|
+
key = key.replace('3d', '')
|
|
413
|
+
const vals = parseValues(val, ',').splice(0, key === 'rotate' ? 4 : 3)
|
|
414
|
+
// scale(.5) === scaleX(.5) scaleY(.5)
|
|
415
|
+
if (vals.length === 1 && key === 'scale') {
|
|
416
|
+
vals.push(vals[0])
|
|
426
417
|
}
|
|
418
|
+
const xyz = ['X', 'Y', 'Z']
|
|
419
|
+
transform.push(...vals.map((v, index) => {
|
|
420
|
+
if (key !== 'rotate' && index > 1) {
|
|
421
|
+
unsupportedPropError({ prop: `${key}Z`, value, selector }, { mode })
|
|
422
|
+
}
|
|
423
|
+
return { [`${key}${xyz[index] || ''}`]: v.trim() }
|
|
424
|
+
}))
|
|
425
|
+
break
|
|
426
|
+
}
|
|
427
427
|
case 'translateZ':
|
|
428
428
|
case 'scaleZ':
|
|
429
429
|
default:
|
|
@@ -2,6 +2,8 @@ const TAG_NAME = 'movable-view'
|
|
|
2
2
|
|
|
3
3
|
module.exports = function ({ print }) {
|
|
4
4
|
const aliEventLog = print({ platform: 'ali', tag: TAG_NAME, isError: false, type: 'event' })
|
|
5
|
+
const androidEventLog = print({ platform: 'android', tag: TAG_NAME, isError: false, type: 'event' })
|
|
6
|
+
const iosEventLog = print({ platform: 'ios', tag: TAG_NAME, isError: false, type: 'event' })
|
|
5
7
|
const qaPropLog = print({ platform: 'qa', tag: TAG_NAME, isError: false })
|
|
6
8
|
const androidPropLog = print({ platform: 'android', tag: TAG_NAME, isError: false })
|
|
7
9
|
const iosPropLog = print({ platform: 'ios', tag: TAG_NAME, isError: false })
|
|
@@ -27,7 +29,7 @@ module.exports = function ({ print }) {
|
|
|
27
29
|
android: androidPropLog
|
|
28
30
|
},
|
|
29
31
|
{
|
|
30
|
-
test: /^(
|
|
32
|
+
test: /^(damping|friction|scale|scale-min|scale-max|scale-value)$/,
|
|
31
33
|
ios: iosPropLog,
|
|
32
34
|
android: androidPropLog
|
|
33
35
|
}
|
|
@@ -36,6 +38,11 @@ module.exports = function ({ print }) {
|
|
|
36
38
|
{
|
|
37
39
|
test: /^(htouchmove|vtouchmove)$/,
|
|
38
40
|
ali: aliEventLog
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
test: /^(bindscale)$/,
|
|
44
|
+
ios: iosEventLog,
|
|
45
|
+
android: androidEventLog
|
|
39
46
|
}
|
|
40
47
|
]
|
|
41
48
|
}
|
|
@@ -53,7 +53,7 @@ module.exports = function ({ print }) {
|
|
|
53
53
|
qa: qaPropLog
|
|
54
54
|
},
|
|
55
55
|
{
|
|
56
|
-
test: /^(
|
|
56
|
+
test: /^(refresher-threshold|enable-passive|scroll-anchoring|using-sticky|fast-deceleration|enable-flex)$/,
|
|
57
57
|
android: androidPropLog,
|
|
58
58
|
ios: iosPropLog
|
|
59
59
|
},
|
|
@@ -26,7 +26,7 @@ module.exports = function (script, {
|
|
|
26
26
|
import { getComponent } from ${stringifyRequest(loaderContext, optionProcessorPath)}
|
|
27
27
|
import { NavigationContainer, StackActions } from '@react-navigation/native'
|
|
28
28
|
import { createStackNavigator } from '@react-navigation/stack'
|
|
29
|
-
import
|
|
29
|
+
import Provider from '@mpxjs/webpack-plugin/lib/runtime/components/react/dist/mpx-provider'
|
|
30
30
|
import { SafeAreaProvider, useSafeAreaInsets } from 'react-native-safe-area-context'
|
|
31
31
|
import { GestureHandlerRootView } from 'react-native-gesture-handler'
|
|
32
32
|
|
|
@@ -34,6 +34,7 @@ module.exports = class AddEnvPlugin {
|
|
|
34
34
|
if (!extname || !matchCondition(resourcePath, this.fileConditionRules)) return callback()
|
|
35
35
|
const queryObj = parseQuery(request.query || '?')
|
|
36
36
|
queryObj.infix = `${queryObj.infix || ''}.${env}`
|
|
37
|
+
// css | stylus | less | sass 中 import file 过滤query,避免在对应的 loader 中无法读取到文件
|
|
37
38
|
obj.query = stringifyQuery(queryObj)
|
|
38
39
|
obj.path = addInfix(resourcePath, env, extname)
|
|
39
40
|
obj.relativePath = request.relativePath && addInfix(request.relativePath, env, extname)
|
|
@@ -43,6 +43,7 @@ module.exports = class AddModePlugin {
|
|
|
43
43
|
resolver.doResolve(target, Object.assign({}, request, obj), 'add mode: ' + mode, resolveContext, (err, result) => {
|
|
44
44
|
if (defaultMode && !result) {
|
|
45
45
|
queryObj.infix = `${queryInfix || ''}.${defaultMode}`
|
|
46
|
+
// css | stylus | less | sass 中 import file 过滤query,避免在对应的 loader 中无法读取到文件
|
|
46
47
|
obj.query = stringifyQuery(queryObj)
|
|
47
48
|
obj.path = addInfix(resourcePath, defaultMode, extname)
|
|
48
49
|
resolver.doResolve(target, Object.assign({}, request, obj), 'add mode: ' + defaultMode, resolveContext, (err, result) => {
|
|
@@ -32,6 +32,23 @@ export interface IntersectionObserver {
|
|
|
32
32
|
throttleMeasure: () => void
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
|
+
export interface PortalManagerContextValue {
|
|
36
|
+
mount: (key: number, children: React.ReactNode) => void
|
|
37
|
+
update: (key: number, children: React.ReactNode) => void
|
|
38
|
+
unmount: (key: number) => void,
|
|
39
|
+
portals: Array<{key: number, children: React.ReactNode}>
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface PortalContextValue {
|
|
43
|
+
mount: (children: React.ReactNode, key?: number, pageId?: number|null) => number| undefined
|
|
44
|
+
update: (key: number, children: React.ReactNode, pageId?: number|null) => void
|
|
45
|
+
unmount: (key: number, pageId?: number|null) => void
|
|
46
|
+
manager?: PortalManagerContextValue
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface ScrollViewContextValue {
|
|
50
|
+
gestureRef: React.RefObject<any> | null
|
|
51
|
+
}
|
|
35
52
|
|
|
36
53
|
export const MovableAreaContext = createContext({ width: 0, height: 0 })
|
|
37
54
|
|
|
@@ -51,4 +68,12 @@ export const IntersectionObserverContext = createContext<IntersectionObserver |
|
|
|
51
68
|
|
|
52
69
|
export const RouteContext = createContext<number | null>(null)
|
|
53
70
|
|
|
71
|
+
export const SwiperContext = createContext({})
|
|
72
|
+
|
|
54
73
|
export const KeyboardAvoidContext = createContext<KeyboardAvoidContextValue | null>(null)
|
|
74
|
+
|
|
75
|
+
export const ScrollViewContext = createContext<ScrollViewContextValue>({ gestureRef: null })
|
|
76
|
+
|
|
77
|
+
export const PortalContext = createContext<PortalContextValue>(null as any)
|
|
78
|
+
|
|
79
|
+
export const PortalManagerContext = createContext<PortalManagerContextValue| null>(null)
|
|
@@ -11,3 +11,5 @@ export const RouteContext = createContext(null);
|
|
|
11
11
|
export const SwiperContext = createContext({});
|
|
12
12
|
export const KeyboardAvoidContext = createContext(null);
|
|
13
13
|
export const ScrollViewContext = createContext({ gestureRef: null });
|
|
14
|
+
export const PortalContext = createContext(null);
|
|
15
|
+
export const PortalManagerContext = createContext(null);
|
|
@@ -82,8 +82,8 @@ function checkIsNeedPress(e, type, ref) {
|
|
|
82
82
|
const nativeEvent = e.nativeEvent;
|
|
83
83
|
const currentPageX = nativeEvent.changedTouches[0].pageX;
|
|
84
84
|
const currentPageY = nativeEvent.changedTouches[0].pageY;
|
|
85
|
-
if (Math.abs(currentPageX - tapDetailInfo.x) >
|
|
86
|
-
Math.abs(currentPageY - tapDetailInfo.y) >
|
|
85
|
+
if (Math.abs(currentPageX - tapDetailInfo.x) > 3 ||
|
|
86
|
+
Math.abs(currentPageY - tapDetailInfo.y) > 3) {
|
|
87
87
|
ref.current.needPress[type] = false;
|
|
88
88
|
ref.current.startTimer[type] &&
|
|
89
89
|
clearTimeout(ref.current.startTimer[type]);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createContext, useMemo, memo } from 'react';
|
|
2
|
+
import { extendObject } from './utils';
|
|
3
|
+
export const LocaleContext = createContext(undefined);
|
|
4
|
+
const LocaleProvider = (props) => {
|
|
5
|
+
const locale = useMemo(() => {
|
|
6
|
+
return {
|
|
7
|
+
antLocale: extendObject({}, props.locale, { exist: true })
|
|
8
|
+
};
|
|
9
|
+
}, [props.locale]);
|
|
10
|
+
return (<LocaleContext.Provider value={locale}>
|
|
11
|
+
{props.children}
|
|
12
|
+
</LocaleContext.Provider>);
|
|
13
|
+
};
|
|
14
|
+
LocaleProvider.displayName = 'LocaleProvider';
|
|
15
|
+
export default memo(LocaleProvider);
|
|
@@ -34,10 +34,11 @@
|
|
|
34
34
|
* ✘ bindagreeprivacyauthorization
|
|
35
35
|
* ✔ bindtap
|
|
36
36
|
*/
|
|
37
|
-
import { createElement, useEffect, useRef,
|
|
37
|
+
import { createElement, useEffect, useRef, forwardRef, useContext } from 'react';
|
|
38
38
|
import { View, StyleSheet, Animated, Easing } from 'react-native';
|
|
39
39
|
import { warn } from '@mpxjs/utils';
|
|
40
|
-
import {
|
|
40
|
+
import { GestureDetector } from 'react-native-gesture-handler';
|
|
41
|
+
import { getCurrentPage, splitProps, splitStyle, useLayout, useTransformStyle, wrapChildren, extendObject, useHoverStyle } from './utils';
|
|
41
42
|
import useInnerProps, { getCustomEvent } from './getInnerListeners';
|
|
42
43
|
import useNodesRef from './useNodesRef';
|
|
43
44
|
import { RouteContext, FormContext } from './context';
|
|
@@ -128,20 +129,16 @@ const Loading = ({ alone = false }) => {
|
|
|
128
129
|
};
|
|
129
130
|
const Button = forwardRef((buttonProps, ref) => {
|
|
130
131
|
const { textProps, innerProps: props = {} } = splitProps(buttonProps);
|
|
131
|
-
const { size = 'default', type = 'default', plain = false, disabled = false, loading = false, 'hover-class': hoverClass, 'hover-style': hoverStyle = {}, 'hover-start-time': hoverStartTime = 20, 'hover-stay-time': hoverStayTime = 70, 'open-type': openType, 'form-type': formType, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, style = {}, children, bindgetuserinfo, bindtap
|
|
132
|
+
const { size = 'default', type = 'default', plain = false, disabled = false, loading = false, 'hover-class': hoverClass, 'hover-style': hoverStyle = {}, 'hover-start-time': hoverStartTime = 20, 'hover-stay-time': hoverStayTime = 70, 'open-type': openType, 'form-type': formType, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, style = {}, children, bindgetuserinfo, bindtap } = props;
|
|
132
133
|
const pageId = useContext(RouteContext);
|
|
133
134
|
const formContext = useContext(FormContext);
|
|
135
|
+
const { isHover, enableHoverStyle, gesture } = useHoverStyle({ hoverStyle, hoverStartTime, hoverStayTime, disabled });
|
|
134
136
|
let submitFn;
|
|
135
137
|
let resetFn;
|
|
136
138
|
if (formContext) {
|
|
137
139
|
submitFn = formContext.submit;
|
|
138
140
|
resetFn = formContext.reset;
|
|
139
141
|
}
|
|
140
|
-
const refs = useRef({
|
|
141
|
-
hoverStartTimer: undefined,
|
|
142
|
-
hoverStayTimer: undefined
|
|
143
|
-
});
|
|
144
|
-
const [isHover, setIsHover] = useState(false);
|
|
145
142
|
const isMiniSize = size === 'mini';
|
|
146
143
|
const applyHoverEffect = isHover && hoverClass !== 'none';
|
|
147
144
|
const [color, hoverColor, plainColor, disabledColor] = TypeColorMap[type];
|
|
@@ -224,32 +221,6 @@ const Button = forwardRef((buttonProps, ref) => {
|
|
|
224
221
|
});
|
|
225
222
|
}
|
|
226
223
|
};
|
|
227
|
-
const setStayTimer = () => {
|
|
228
|
-
clearTimeout(refs.current.hoverStayTimer);
|
|
229
|
-
refs.current.hoverStayTimer = setTimeout(() => {
|
|
230
|
-
setIsHover(false);
|
|
231
|
-
clearTimeout(refs.current.hoverStayTimer);
|
|
232
|
-
}, hoverStayTime);
|
|
233
|
-
};
|
|
234
|
-
const setStartTimer = () => {
|
|
235
|
-
clearTimeout(refs.current.hoverStartTimer);
|
|
236
|
-
refs.current.hoverStartTimer = setTimeout(() => {
|
|
237
|
-
setIsHover(true);
|
|
238
|
-
clearTimeout(refs.current.hoverStartTimer);
|
|
239
|
-
}, hoverStartTime);
|
|
240
|
-
};
|
|
241
|
-
const onTouchStart = (evt) => {
|
|
242
|
-
bindtouchstart && bindtouchstart(evt);
|
|
243
|
-
if (disabled)
|
|
244
|
-
return;
|
|
245
|
-
setStartTimer();
|
|
246
|
-
};
|
|
247
|
-
const onTouchEnd = (evt) => {
|
|
248
|
-
bindtouchend && bindtouchend(evt);
|
|
249
|
-
if (disabled)
|
|
250
|
-
return;
|
|
251
|
-
setStayTimer();
|
|
252
|
-
};
|
|
253
224
|
const handleFormTypeFn = () => {
|
|
254
225
|
if (formType === 'submit') {
|
|
255
226
|
submitFn && submitFn();
|
|
@@ -269,8 +240,6 @@ const Button = forwardRef((buttonProps, ref) => {
|
|
|
269
240
|
ref: nodeRef,
|
|
270
241
|
style: extendObject({}, innerStyle, layoutStyle)
|
|
271
242
|
}, layoutProps, {
|
|
272
|
-
bindtouchstart: (bindtouchstart || !disabled) && onTouchStart,
|
|
273
|
-
bindtouchend: (bindtouchend || !disabled) && onTouchEnd,
|
|
274
243
|
bindtap: !disabled && onTap
|
|
275
244
|
}), [
|
|
276
245
|
'disabled',
|
|
@@ -288,12 +257,15 @@ const Button = forwardRef((buttonProps, ref) => {
|
|
|
288
257
|
layoutRef,
|
|
289
258
|
disableTap: disabled
|
|
290
259
|
});
|
|
291
|
-
|
|
260
|
+
const baseButton = createElement(View, innerProps, loading && createElement(Loading, { alone: !children }), wrapChildren(props, {
|
|
292
261
|
hasVarDec,
|
|
293
262
|
varContext: varContextRef.current,
|
|
294
263
|
textStyle,
|
|
295
264
|
textProps
|
|
296
265
|
}));
|
|
266
|
+
return enableHoverStyle
|
|
267
|
+
? createElement(GestureDetector, { gesture }, baseButton)
|
|
268
|
+
: baseButton;
|
|
297
269
|
});
|
|
298
270
|
Button.displayName = 'MpxButton';
|
|
299
271
|
export default Button;
|
|
@@ -268,14 +268,8 @@ const Image = forwardRef((props, ref) => {
|
|
|
268
268
|
], {
|
|
269
269
|
layoutRef
|
|
270
270
|
});
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
uri: src,
|
|
274
|
-
onLayout: onSvgLoad,
|
|
275
|
-
onError: binderror && onSvgError,
|
|
276
|
-
style: extendObject({ transformOrigin: 'top left' }, modeStyle)
|
|
277
|
-
})
|
|
278
|
-
: loaded && renderImage({
|
|
271
|
+
const createBaseImage = (innerProps = {}) => {
|
|
272
|
+
return renderImage(extendObject({
|
|
279
273
|
source: { uri: src },
|
|
280
274
|
resizeMode: resizeMode,
|
|
281
275
|
onLoad: bindload && onImageLoad,
|
|
@@ -285,7 +279,17 @@ const Image = forwardRef((props, ref) => {
|
|
|
285
279
|
width: isCropMode ? imageWidth : '100%',
|
|
286
280
|
height: isCropMode ? imageHeight : '100%'
|
|
287
281
|
}, isCropMode ? modeStyle : {})
|
|
288
|
-
}, enableFastImage)
|
|
282
|
+
}, innerProps), enableFastImage);
|
|
283
|
+
};
|
|
284
|
+
const SvgImage = createElement(View, innerProps, createElement(SvgCssUri, {
|
|
285
|
+
uri: src,
|
|
286
|
+
onLayout: onSvgLoad,
|
|
287
|
+
onError: binderror && onSvgError,
|
|
288
|
+
style: extendObject({ transformOrigin: 'top left' }, modeStyle)
|
|
289
|
+
}));
|
|
290
|
+
const BaseImage = createBaseImage(innerProps);
|
|
291
|
+
const LayoutImage = createElement(View, innerProps, loaded && createBaseImage());
|
|
292
|
+
return isSvg ? SvgImage : isLayoutMode ? LayoutImage : BaseImage;
|
|
289
293
|
});
|
|
290
294
|
Image.displayName = 'mpx-image';
|
|
291
295
|
export default Image;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { View, Text, Modal, TouchableWithoutFeedback } from 'react-native';
|
|
2
|
-
import
|
|
2
|
+
import Portal from '../mpx-portal';
|
|
3
|
+
import { PickerView } from '@ant-design/react-native';
|
|
3
4
|
import React, { forwardRef, useState, useRef, useEffect } from 'react';
|
|
4
5
|
import useNodesRef from '../useNodesRef'; // 引入辅助函数
|
|
5
6
|
// 可见应用窗口的大小。
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { forwardRef, useRef, useState, useMemo, useEffect, useCallback } from 'react';
|
|
2
2
|
import { SafeAreaView, StyleSheet } from 'react-native';
|
|
3
3
|
import Reanimated, { useAnimatedRef, useScrollViewOffset } from 'react-native-reanimated';
|
|
4
|
-
import { useTransformStyle, splitStyle, splitProps, useLayout, usePrevious, isAndroid, useDebounceCallback, useStableCallback
|
|
4
|
+
import { useTransformStyle, splitStyle, splitProps, useLayout, usePrevious, isAndroid, isIOS, useDebounceCallback, useStableCallback } from './utils';
|
|
5
5
|
import useNodesRef from './useNodesRef';
|
|
6
6
|
import PickerOverlay from './pickerViewOverlay';
|
|
7
7
|
import PickerMask from './pickerViewMask';
|
|
@@ -49,7 +49,7 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
49
49
|
return index * itemRawH;
|
|
50
50
|
}, [itemRawH]);
|
|
51
51
|
const stableResetScrollPosition = useStableCallback((y) => {
|
|
52
|
-
console.log('[mpx-picker-view-column], reset --->', 'columnIndex=', columnIndex, 'y=', y, touching.current, scrolling.current)
|
|
52
|
+
// console.log('[mpx-picker-view-column], reset --->', 'columnIndex=', columnIndex, 'y=', y, touching.current, scrolling.current, itemRawH, 'snapToOffsets=', snapToOffsets)
|
|
53
53
|
if (touching.current || scrolling.current) {
|
|
54
54
|
return;
|
|
55
55
|
}
|
|
@@ -95,8 +95,9 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
95
95
|
};
|
|
96
96
|
const onItemLayout = (e) => {
|
|
97
97
|
const { height: rawH } = e.nativeEvent.layout;
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
const roundedH = Math.round(rawH);
|
|
99
|
+
if (roundedH && roundedH !== itemRawH) {
|
|
100
|
+
setItemRawH(roundedH);
|
|
100
101
|
}
|
|
101
102
|
};
|
|
102
103
|
const onScrollBeginDrag = () => {
|
|
@@ -111,7 +112,7 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
111
112
|
touching.current = false;
|
|
112
113
|
const { y } = e.nativeEvent.contentOffset;
|
|
113
114
|
if (isIOS) {
|
|
114
|
-
if (y
|
|
115
|
+
if (y >= 0 && y <= snapToOffsets[maxIndex]) {
|
|
115
116
|
debounceResetScrollPosition(y);
|
|
116
117
|
}
|
|
117
118
|
}
|
|
@@ -123,25 +124,23 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
123
124
|
const onMomentumScrollEnd = (e) => {
|
|
124
125
|
scrolling.current = false;
|
|
125
126
|
const { y: scrollY } = e.nativeEvent.contentOffset;
|
|
127
|
+
// console.log('[mpx-picker-view-column], onMomentumScrollEnd --->', 'columnIndex=', columnIndex, scrollY, itemRawH)
|
|
126
128
|
if (isIOS && scrollY % itemRawH !== 0) {
|
|
127
129
|
return debounceResetScrollPosition(scrollY);
|
|
128
130
|
}
|
|
129
131
|
const calcIndex = getIndex(scrollY);
|
|
130
|
-
activeIndex.current
|
|
131
|
-
|
|
132
|
+
if (calcIndex !== activeIndex.current) {
|
|
133
|
+
activeIndex.current = calcIndex;
|
|
132
134
|
onSelectChange(calcIndex);
|
|
133
135
|
}
|
|
134
136
|
};
|
|
135
137
|
const onScroll = (e) => {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
// 全局注册的震动触感 hook
|
|
141
|
-
const pickerVibrate = global.__mpx.config.rnConfig.pickerVibrate;
|
|
138
|
+
// 全局注册的振动触感 hook
|
|
139
|
+
const pickerVibrate = global.__mpx?.config?.rnConfig?.pickerVibrate;
|
|
142
140
|
if (typeof pickerVibrate !== 'function') {
|
|
143
141
|
return;
|
|
144
142
|
}
|
|
143
|
+
const { y } = e.nativeEvent.contentOffset;
|
|
145
144
|
const { index: prevIndex, y: _y } = prevScrollingInfo.current;
|
|
146
145
|
if (touching.current || scrolling.current) {
|
|
147
146
|
if (Math.abs(y - _y) >= itemRawH) {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react';
|
|
2
|
+
import { getFocusedNavigation } from '@mpxjs/utils';
|
|
3
|
+
const PortalConsumer = ({ manager, children }) => {
|
|
4
|
+
const keyRef = useRef(null);
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
const navigation = getFocusedNavigation();
|
|
7
|
+
const curPageId = navigation?.pageId;
|
|
8
|
+
manager.update(keyRef.current, children, curPageId);
|
|
9
|
+
}, [children]);
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (!manager) {
|
|
12
|
+
throw new Error('Looks like you forgot to wrap your root component with `Provider` component from `@mpxjs/webpack-plugin/lib/runtime/components/react/dist/mpx-portal`.\n\n');
|
|
13
|
+
}
|
|
14
|
+
const navigation = getFocusedNavigation();
|
|
15
|
+
const curPageId = navigation?.pageId;
|
|
16
|
+
keyRef.current = manager.mount(children, undefined, curPageId);
|
|
17
|
+
return () => {
|
|
18
|
+
manager.unmount(keyRef.current, curPageId);
|
|
19
|
+
};
|
|
20
|
+
}, []);
|
|
21
|
+
return null;
|
|
22
|
+
};
|
|
23
|
+
export default PortalConsumer;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react';
|
|
2
|
+
import { View, DeviceEventEmitter, NativeEventEmitter, StyleSheet } from 'react-native';
|
|
3
|
+
import PortalManager from './portal-manager';
|
|
4
|
+
import { getFocusedNavigation } from '@mpxjs/utils';
|
|
5
|
+
import { PortalContext } from '../context';
|
|
6
|
+
// events
|
|
7
|
+
const addType = 'MPX_RN_ADD_PORTAL';
|
|
8
|
+
const removeType = 'MPX_RN_REMOVE_PORTAL';
|
|
9
|
+
// fix react native web does not support DeviceEventEmitter
|
|
10
|
+
const TopViewEventEmitter = DeviceEventEmitter || new NativeEventEmitter();
|
|
11
|
+
const styles = StyleSheet.create({
|
|
12
|
+
container: {
|
|
13
|
+
flex: 1
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
class PortalGuard {
|
|
17
|
+
nextKey = 10000;
|
|
18
|
+
add = (e) => {
|
|
19
|
+
const key = this.nextKey++;
|
|
20
|
+
TopViewEventEmitter.emit(addType, e, key);
|
|
21
|
+
return key;
|
|
22
|
+
};
|
|
23
|
+
remove = (key) => {
|
|
24
|
+
TopViewEventEmitter.emit(removeType, key);
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* portal
|
|
29
|
+
*/
|
|
30
|
+
export const portal = new PortalGuard();
|
|
31
|
+
const PortalHost = ({ children }) => {
|
|
32
|
+
const _nextKey = useRef(0);
|
|
33
|
+
const _queue = useRef([]);
|
|
34
|
+
const _addType = useRef(null);
|
|
35
|
+
const _removeType = useRef(null);
|
|
36
|
+
const manager = useRef(null);
|
|
37
|
+
let currentPageId;
|
|
38
|
+
const _mount = (children, _key, curPageId) => {
|
|
39
|
+
const navigation = getFocusedNavigation();
|
|
40
|
+
const pageId = navigation?.pageId;
|
|
41
|
+
if (pageId !== (curPageId ?? currentPageId)) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const key = _key || _nextKey.current++;
|
|
45
|
+
if (manager.current) {
|
|
46
|
+
manager.current.mount(key, children);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
_queue.current.push({ type: 'mount', key, children });
|
|
50
|
+
}
|
|
51
|
+
return key;
|
|
52
|
+
};
|
|
53
|
+
const _unmount = (key, curPageId) => {
|
|
54
|
+
const navigation = getFocusedNavigation();
|
|
55
|
+
const pageId = navigation?.pageId;
|
|
56
|
+
if (pageId !== (curPageId ?? currentPageId)) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (manager.current) {
|
|
60
|
+
manager.current.unmount(key);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
_queue.current.push({ type: 'unmount', key });
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
const _update = (key, children, curPageId) => {
|
|
67
|
+
const navigation = getFocusedNavigation();
|
|
68
|
+
const pageId = navigation?.pageId;
|
|
69
|
+
if (pageId !== (curPageId ?? currentPageId)) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (manager.current) {
|
|
73
|
+
manager.current.update(key, children);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
const op = { type: 'mount', key, children };
|
|
77
|
+
const index = _queue.current.findIndex((o) => o.type === 'mount' || (o.type === 'update' && o.key === key));
|
|
78
|
+
if (index > -1) {
|
|
79
|
+
_queue.current[index] = op;
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
_queue.current.push(op);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
const navigation = getFocusedNavigation();
|
|
88
|
+
currentPageId = navigation?.pageId;
|
|
89
|
+
_addType.current = TopViewEventEmitter.addListener(addType, _mount);
|
|
90
|
+
_removeType.current = TopViewEventEmitter.addListener(removeType, _unmount);
|
|
91
|
+
return () => {
|
|
92
|
+
while (_queue.current.length && manager.current) {
|
|
93
|
+
const action = _queue.current.pop();
|
|
94
|
+
if (!action) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
// tslint:disable-next-line:switch-default
|
|
98
|
+
switch (action.type) {
|
|
99
|
+
case 'mount':
|
|
100
|
+
manager.current?.mount(action.key, action.children);
|
|
101
|
+
break;
|
|
102
|
+
case 'update':
|
|
103
|
+
manager.current?.update(action.key, action.children);
|
|
104
|
+
break;
|
|
105
|
+
case 'unmount':
|
|
106
|
+
manager.current?.unmount(action.key);
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
}, []);
|
|
112
|
+
return (<PortalContext.Provider value={{
|
|
113
|
+
mount: _mount,
|
|
114
|
+
update: _update,
|
|
115
|
+
unmount: _unmount
|
|
116
|
+
}}>
|
|
117
|
+
{/* Need collapsable=false here to clip the elevations, otherwise they appear above Portal components */}
|
|
118
|
+
<View style={styles.container} collapsable={false}>
|
|
119
|
+
{children}
|
|
120
|
+
</View>
|
|
121
|
+
<PortalManager ref={manager}/>
|
|
122
|
+
</PortalContext.Provider>);
|
|
123
|
+
};
|
|
124
|
+
export default PortalHost;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { useState, useCallback, forwardRef, useImperativeHandle } from 'react';
|
|
2
|
+
import { View, StyleSheet } from 'react-native';
|
|
3
|
+
const _PortalManager = forwardRef((props, ref) => {
|
|
4
|
+
const [state, setState] = useState({
|
|
5
|
+
portals: []
|
|
6
|
+
});
|
|
7
|
+
const mount = useCallback((key, children) => {
|
|
8
|
+
setState((prevState) => ({
|
|
9
|
+
portals: [...prevState.portals, { key, children }]
|
|
10
|
+
}));
|
|
11
|
+
}, [state]);
|
|
12
|
+
const update = useCallback((key, children) => {
|
|
13
|
+
setState((prevState) => ({
|
|
14
|
+
portals: prevState.portals.map((item) => {
|
|
15
|
+
if (item.key === key) {
|
|
16
|
+
return { ...item, children };
|
|
17
|
+
}
|
|
18
|
+
return item;
|
|
19
|
+
})
|
|
20
|
+
}));
|
|
21
|
+
}, [state]);
|
|
22
|
+
const unmount = useCallback((key) => {
|
|
23
|
+
setState((prevState) => ({
|
|
24
|
+
portals: prevState.portals.filter((item) => item.key !== key)
|
|
25
|
+
}));
|
|
26
|
+
}, []);
|
|
27
|
+
useImperativeHandle(ref, () => ({
|
|
28
|
+
mount,
|
|
29
|
+
update,
|
|
30
|
+
unmount,
|
|
31
|
+
portals: state.portals
|
|
32
|
+
}));
|
|
33
|
+
return (<>
|
|
34
|
+
{state.portals.map(({ key, children }, i) => (<View key={key} collapsable={false} // Need collapsable=false here to clip the elevations
|
|
35
|
+
pointerEvents="box-none" style={[StyleSheet.absoluteFill, { zIndex: 1000 + i }]}>
|
|
36
|
+
{children}
|
|
37
|
+
</View>))}
|
|
38
|
+
</>);
|
|
39
|
+
});
|
|
40
|
+
export default _PortalManager;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { PortalContext } from './context';
|
|
2
|
+
import PortalConsumer from './mpx-portal/portal-consumer';
|
|
3
|
+
import PortalHost, { portal } from './mpx-portal/portal-host';
|
|
4
|
+
const Portal = ({ children }) => {
|
|
5
|
+
return (<PortalContext.Consumer>
|
|
6
|
+
{(manager) => (<PortalConsumer manager={manager}>{children}</PortalConsumer>)}
|
|
7
|
+
</PortalContext.Consumer>);
|
|
8
|
+
};
|
|
9
|
+
Portal.Host = PortalHost;
|
|
10
|
+
Portal.add = portal.add;
|
|
11
|
+
Portal.remove = portal.remove;
|
|
12
|
+
export default Portal;
|