@mpxjs/webpack-plugin 2.9.72 → 2.10.0
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/file-loader.js +5 -0
- package/lib/index.js +21 -3
- package/lib/platform/template/wx/component-config/input.js +1 -1
- package/lib/platform/template/wx/component-config/textarea.js +1 -1
- package/lib/platform/template/wx/component-config/unsupported.js +1 -1
- package/lib/platform/template/wx/component-config/video.js +28 -1
- package/lib/platform/template/wx/index.js +2 -2
- package/lib/react/processScript.js +6 -4
- package/lib/react/processTemplate.js +5 -3
- package/lib/runtime/components/react/KeyboardAvoidingView.tsx +108 -0
- package/lib/runtime/components/react/context.ts +18 -2
- package/lib/runtime/components/react/dist/KeyboardAvoidingView.jsx +89 -0
- package/lib/runtime/components/react/dist/context.js +1 -0
- package/lib/runtime/components/react/dist/getInnerListeners.js +1 -2
- package/lib/runtime/components/react/dist/mpx-button.jsx +1 -1
- 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-icon/index.jsx +50 -0
- package/lib/runtime/components/react/dist/mpx-image.jsx +19 -18
- package/lib/runtime/components/react/dist/mpx-input.jsx +48 -19
- package/lib/runtime/components/react/dist/mpx-movable-view.jsx +16 -14
- package/lib/runtime/components/react/dist/mpx-picker/time.jsx +2 -1
- package/lib/runtime/components/react/dist/mpx-portal/index.jsx +30 -0
- package/lib/runtime/components/react/dist/mpx-portal/portal-host.jsx +112 -0
- package/lib/runtime/components/react/dist/mpx-portal/portal-manager.jsx +41 -0
- package/lib/runtime/components/react/dist/mpx-root-portal.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +19 -7
- package/lib/runtime/components/react/dist/mpx-swiper.jsx +3 -2
- package/lib/runtime/components/react/dist/mpx-textarea.jsx +11 -3
- package/lib/runtime/components/react/dist/mpx-video.jsx +248 -0
- package/lib/runtime/components/react/dist/mpx-web-view.jsx +149 -50
- package/lib/runtime/components/react/dist/useAnimationHooks.js +4 -4
- package/lib/runtime/components/react/dist/utils.jsx +8 -3
- package/lib/runtime/components/react/getInnerListeners.ts +1 -2
- package/lib/runtime/components/react/mpx-button.tsx +1 -1
- package/lib/runtime/components/react/mpx-icon/icons/cancel.png +0 -0
- package/lib/runtime/components/react/mpx-icon/icons/clear.png +0 -0
- package/lib/runtime/components/react/mpx-icon/icons/download.png +0 -0
- package/lib/runtime/components/react/mpx-icon/icons/info.png +0 -0
- package/lib/runtime/components/react/mpx-icon/icons/search.png +0 -0
- package/lib/runtime/components/react/mpx-icon/icons/success.png +0 -0
- package/lib/runtime/components/react/mpx-icon/icons/success_no_circle.png +0 -0
- package/lib/runtime/components/react/mpx-icon/icons/waiting.png +0 -0
- package/lib/runtime/components/react/mpx-icon/icons/warn.png +0 -0
- package/lib/runtime/components/react/mpx-icon/index.tsx +111 -0
- package/lib/runtime/components/react/mpx-image.tsx +26 -14
- package/lib/runtime/components/react/mpx-input.tsx +52 -20
- package/lib/runtime/components/react/mpx-movable-view.tsx +19 -16
- package/lib/runtime/components/react/mpx-picker/time.tsx +2 -1
- package/lib/runtime/components/react/mpx-portal/index.tsx +39 -0
- package/lib/runtime/components/react/mpx-portal/portal-host.tsx +141 -0
- package/lib/runtime/components/react/mpx-portal/portal-manager.tsx +64 -0
- package/lib/runtime/components/react/mpx-root-portal.tsx +1 -1
- package/lib/runtime/components/react/mpx-scroll-view.tsx +20 -8
- package/lib/runtime/components/react/mpx-swiper.tsx +3 -2
- package/lib/runtime/components/react/mpx-textarea.tsx +13 -3
- package/lib/runtime/components/react/mpx-video.tsx +388 -0
- package/lib/runtime/components/react/mpx-web-view.tsx +180 -49
- package/lib/runtime/components/react/types/getInnerListeners.d.ts +1 -1
- package/lib/runtime/components/react/types/global.d.ts +8 -0
- package/lib/runtime/components/react/useAnimationHooks.ts +4 -4
- package/lib/runtime/components/react/utils.tsx +12 -6
- package/lib/script-setup-compiler/index.js +6 -2
- package/lib/style-compiler/index.js +3 -4
- package/lib/style-compiler/strip-conditional-loader.js +127 -0
- package/lib/template-compiler/compiler.js +23 -9
- package/lib/template-compiler/index.js +4 -4
- package/lib/web/processTemplate.js +7 -5
- package/lib/wxs/loader.js +2 -2
- package/lib/wxs/pre-loader.js +2 -2
- package/package.json +7 -5
- package/lib/runtime/components/react/dist/mpx-icon.jsx +0 -41
- package/lib/runtime/components/react/mpx-icon.tsx +0 -102
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ✔ type
|
|
3
|
+
* ✔ size
|
|
4
|
+
* ✔ color
|
|
5
|
+
*/
|
|
6
|
+
import { JSX, forwardRef, useRef, createElement } from 'react'
|
|
7
|
+
import { Text, TextStyle, Image } from 'react-native'
|
|
8
|
+
import useInnerProps from '../getInnerListeners'
|
|
9
|
+
import useNodesRef, { HandlerRef } from '../useNodesRef'
|
|
10
|
+
import { useLayout, useTransformStyle, extendObject } from '../utils'
|
|
11
|
+
import Success from './icons/success.png'
|
|
12
|
+
import SuccessNoCircle from './icons/success_no_circle.png'
|
|
13
|
+
import Info from './icons/info.png'
|
|
14
|
+
import Warn from './icons/warn.png'
|
|
15
|
+
import Waiting from './icons/waiting.png'
|
|
16
|
+
import Cancel from './icons/cancel.png'
|
|
17
|
+
import Download from './icons/download.png'
|
|
18
|
+
import Search from './icons/search.png'
|
|
19
|
+
import Clear from './icons/clear.png'
|
|
20
|
+
|
|
21
|
+
export type IconType =
|
|
22
|
+
| 'success'
|
|
23
|
+
| 'success_no_circle'
|
|
24
|
+
| 'info'
|
|
25
|
+
| 'warn'
|
|
26
|
+
| 'waiting'
|
|
27
|
+
| 'cancel'
|
|
28
|
+
| 'download'
|
|
29
|
+
| 'search'
|
|
30
|
+
| 'clear'
|
|
31
|
+
|
|
32
|
+
export interface IconProps {
|
|
33
|
+
type: IconType
|
|
34
|
+
size?: number
|
|
35
|
+
color?: string
|
|
36
|
+
style?: TextStyle & Record<string, any>
|
|
37
|
+
'enable-offset'?: boolean
|
|
38
|
+
'enable-var'?: boolean
|
|
39
|
+
'external-var-context'?: Record<string, any>
|
|
40
|
+
'parent-font-size'?: number
|
|
41
|
+
'parent-width'?: number
|
|
42
|
+
'parent-height'?: number
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const IconTypeMap = new Map<IconType, string>([
|
|
46
|
+
['success', Success],
|
|
47
|
+
['success_no_circle', SuccessNoCircle],
|
|
48
|
+
['info', Info],
|
|
49
|
+
['warn', Warn],
|
|
50
|
+
['waiting', Waiting],
|
|
51
|
+
['cancel', Cancel],
|
|
52
|
+
['download', Download],
|
|
53
|
+
['search', Search],
|
|
54
|
+
['clear', Clear]
|
|
55
|
+
])
|
|
56
|
+
|
|
57
|
+
const Icon = forwardRef<HandlerRef<Text, IconProps>, IconProps>(
|
|
58
|
+
(props, ref): JSX.Element => {
|
|
59
|
+
const {
|
|
60
|
+
type,
|
|
61
|
+
size = 23,
|
|
62
|
+
color,
|
|
63
|
+
style = {},
|
|
64
|
+
'enable-var': enableVar,
|
|
65
|
+
'external-var-context': externalVarContext,
|
|
66
|
+
'parent-font-size': parentFontSize,
|
|
67
|
+
'parent-width': parentWidth,
|
|
68
|
+
'parent-height': parentHeight
|
|
69
|
+
} = props
|
|
70
|
+
|
|
71
|
+
const source = IconTypeMap.get(type)
|
|
72
|
+
|
|
73
|
+
const defaultStyle = { width: ~~size, height: ~~size }
|
|
74
|
+
|
|
75
|
+
const styleObj = extendObject({}, defaultStyle, style)
|
|
76
|
+
|
|
77
|
+
const {
|
|
78
|
+
hasSelfPercent,
|
|
79
|
+
normalStyle,
|
|
80
|
+
setWidth,
|
|
81
|
+
setHeight
|
|
82
|
+
} = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight })
|
|
83
|
+
|
|
84
|
+
const nodeRef = useRef(null)
|
|
85
|
+
useNodesRef(props, ref, nodeRef, { style: normalStyle })
|
|
86
|
+
|
|
87
|
+
const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef })
|
|
88
|
+
|
|
89
|
+
const innerProps = useInnerProps(
|
|
90
|
+
props,
|
|
91
|
+
extendObject(
|
|
92
|
+
{
|
|
93
|
+
ref: nodeRef,
|
|
94
|
+
source,
|
|
95
|
+
style: extendObject({}, normalStyle, layoutStyle, { tintColor: color })
|
|
96
|
+
},
|
|
97
|
+
layoutProps
|
|
98
|
+
),
|
|
99
|
+
[],
|
|
100
|
+
{
|
|
101
|
+
layoutRef
|
|
102
|
+
}
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
return createElement(Image, innerProps)
|
|
106
|
+
}
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
Icon.displayName = 'MpxIcon'
|
|
110
|
+
|
|
111
|
+
export default Icon
|
|
@@ -49,7 +49,7 @@ export interface ImageProps {
|
|
|
49
49
|
mode?: Mode
|
|
50
50
|
svg?: boolean
|
|
51
51
|
style?: ImageStyle & Record<string, any>
|
|
52
|
-
'enable-offset'?: boolean
|
|
52
|
+
'enable-offset'?: boolean
|
|
53
53
|
'enable-var'?: boolean
|
|
54
54
|
'external-var-context'?: Record<string, any>
|
|
55
55
|
'parent-font-size'?: number
|
|
@@ -403,18 +403,23 @@ const Image = forwardRef<HandlerRef<RNImage, ImageProps>, ImageProps>((props, re
|
|
|
403
403
|
}
|
|
404
404
|
)
|
|
405
405
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
406
|
+
const SvgImage = createElement(
|
|
407
|
+
View,
|
|
408
|
+
innerProps,
|
|
409
|
+
createElement(SvgCssUri, {
|
|
410
|
+
uri: src,
|
|
411
|
+
onLayout: onSvgLoad,
|
|
412
|
+
onError: binderror && onSvgError,
|
|
413
|
+
style: extendObject(
|
|
414
|
+
{ transformOrigin: 'top left' },
|
|
415
|
+
modeStyle
|
|
416
|
+
)
|
|
417
|
+
})
|
|
418
|
+
)
|
|
419
|
+
|
|
420
|
+
const BaseImage = renderImage(
|
|
421
|
+
extendObject(
|
|
422
|
+
{
|
|
418
423
|
source: { uri: src },
|
|
419
424
|
resizeMode: resizeMode,
|
|
420
425
|
onLoad: bindload && onImageLoad,
|
|
@@ -427,8 +432,15 @@ const Image = forwardRef<HandlerRef<RNImage, ImageProps>, ImageProps>((props, re
|
|
|
427
432
|
},
|
|
428
433
|
isCropMode ? modeStyle : {}
|
|
429
434
|
)
|
|
430
|
-
},
|
|
435
|
+
},
|
|
436
|
+
isLayoutMode ? {} : innerProps
|
|
437
|
+
),
|
|
438
|
+
enableFastImage
|
|
431
439
|
)
|
|
440
|
+
|
|
441
|
+
const LayoutImage = createElement(View, innerProps, loaded && BaseImage)
|
|
442
|
+
|
|
443
|
+
return isSvg ? SvgImage : isLayoutMode ? LayoutImage : BaseImage
|
|
432
444
|
})
|
|
433
445
|
|
|
434
446
|
Image.displayName = 'mpx-image'
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* ✘ placeholder-class
|
|
8
8
|
* ✔ disabled
|
|
9
9
|
* ✔ maxlength
|
|
10
|
-
*
|
|
10
|
+
* ✔ cursor-spacing
|
|
11
11
|
* ✔ auto-focus
|
|
12
12
|
* ✔ focus
|
|
13
13
|
* ✔ confirm-type
|
|
@@ -37,9 +37,8 @@
|
|
|
37
37
|
* ✘ bind:keyboardcompositionend
|
|
38
38
|
* ✘ bind:onkeyboardheightchange
|
|
39
39
|
*/
|
|
40
|
-
import { JSX, forwardRef,
|
|
40
|
+
import { JSX, forwardRef, useRef, useState, useContext, useEffect, createElement } from 'react'
|
|
41
41
|
import {
|
|
42
|
-
KeyboardTypeOptions,
|
|
43
42
|
Platform,
|
|
44
43
|
TextInput,
|
|
45
44
|
TextStyle,
|
|
@@ -77,11 +76,12 @@ type Type = 'text' | 'number' | 'idcard' | 'digit'
|
|
|
77
76
|
export interface InputProps {
|
|
78
77
|
name?: string
|
|
79
78
|
style?: InputStyle & Record<string, any>
|
|
80
|
-
value?: string
|
|
79
|
+
value?: string | number
|
|
81
80
|
type?: Type
|
|
82
81
|
password?: boolean
|
|
83
82
|
placeholder?: string
|
|
84
83
|
disabled?: boolean
|
|
84
|
+
'cursor-spacing'?: number
|
|
85
85
|
maxlength?: number
|
|
86
86
|
'auto-focus'?: boolean
|
|
87
87
|
focus?: boolean
|
|
@@ -136,6 +136,7 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
|
|
|
136
136
|
'placeholder-style': placeholderStyle,
|
|
137
137
|
disabled,
|
|
138
138
|
maxlength = 140,
|
|
139
|
+
'cursor-spacing': cursorSpacing = 0,
|
|
139
140
|
'auto-focus': autoFocus,
|
|
140
141
|
focus,
|
|
141
142
|
'confirm-type': confirmType = 'done',
|
|
@@ -163,7 +164,7 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
|
|
|
163
164
|
|
|
164
165
|
const formContext = useContext(FormContext)
|
|
165
166
|
|
|
166
|
-
const
|
|
167
|
+
const keyboardAvoid = useContext(KeyboardAvoidContext)
|
|
167
168
|
|
|
168
169
|
let formValuesMap: Map<string, FormFieldValue> | undefined
|
|
169
170
|
|
|
@@ -171,8 +172,19 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
|
|
|
171
172
|
formValuesMap = formContext.formValuesMap
|
|
172
173
|
}
|
|
173
174
|
|
|
175
|
+
const parseValue = (value: string | number | undefined): string => {
|
|
176
|
+
if (typeof value === 'string') {
|
|
177
|
+
if (value.length > maxlength && maxlength >= 0) {
|
|
178
|
+
return value.slice(0, maxlength)
|
|
179
|
+
}
|
|
180
|
+
return value
|
|
181
|
+
}
|
|
182
|
+
if (typeof value === 'number') return value + ''
|
|
183
|
+
return ''
|
|
184
|
+
}
|
|
185
|
+
|
|
174
186
|
const keyboardType = keyboardTypeMap[type]
|
|
175
|
-
const defaultValue =
|
|
187
|
+
const defaultValue = parseValue(value)
|
|
176
188
|
const placeholderTextColor = parseInlineStyle(placeholderStyle)?.color
|
|
177
189
|
const textAlignVertical = multiline ? 'top' : 'auto'
|
|
178
190
|
|
|
@@ -182,6 +194,7 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
|
|
|
182
194
|
|
|
183
195
|
const [inputValue, setInputValue] = useState(defaultValue)
|
|
184
196
|
const [contentHeight, setContentHeight] = useState(0)
|
|
197
|
+
const [selection, setSelection] = useState({ start: -1, end: -1 })
|
|
185
198
|
|
|
186
199
|
const styleObj = extendObject(
|
|
187
200
|
{ padding: 0, backgroundColor: '#fff' },
|
|
@@ -207,15 +220,15 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
|
|
|
207
220
|
|
|
208
221
|
useEffect(() => {
|
|
209
222
|
if (inputValue !== value) {
|
|
210
|
-
setInputValue(value)
|
|
223
|
+
setInputValue(parseValue(value))
|
|
211
224
|
}
|
|
212
225
|
}, [value])
|
|
213
226
|
|
|
214
|
-
|
|
215
|
-
if (
|
|
216
|
-
|
|
217
|
-
} else if (
|
|
218
|
-
|
|
227
|
+
useEffect(() => {
|
|
228
|
+
if (typeof cursor === 'number') {
|
|
229
|
+
setSelection({ start: cursor, end: cursor })
|
|
230
|
+
} else if (selectionStart >= 0 && selectionEnd >= 0 && selectionStart !== selectionEnd) {
|
|
231
|
+
setSelection({ start: selectionStart, end: selectionEnd })
|
|
219
232
|
}
|
|
220
233
|
}, [cursor, selectionStart, selectionEnd])
|
|
221
234
|
|
|
@@ -253,8 +266,23 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
|
|
|
253
266
|
}
|
|
254
267
|
}
|
|
255
268
|
|
|
269
|
+
const setKeyboardAvoidContext = () => {
|
|
270
|
+
if (adjustPosition && keyboardAvoid?.current) {
|
|
271
|
+
extendObject(keyboardAvoid.current, {
|
|
272
|
+
cursorSpacing,
|
|
273
|
+
ref: nodeRef
|
|
274
|
+
})
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const onInputTouchStart = () => {
|
|
279
|
+
// sometimes the focus event occurs later than the keyboardWillShow event
|
|
280
|
+
setKeyboardAvoidContext()
|
|
281
|
+
}
|
|
282
|
+
|
|
256
283
|
const onInputFocus = (evt: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
|
257
|
-
|
|
284
|
+
setKeyboardAvoidContext()
|
|
285
|
+
bindfocus && bindfocus(
|
|
258
286
|
getCustomEvent(
|
|
259
287
|
'focus',
|
|
260
288
|
evt,
|
|
@@ -270,7 +298,7 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
|
|
|
270
298
|
}
|
|
271
299
|
|
|
272
300
|
const onInputBlur = (evt: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
|
273
|
-
bindblur
|
|
301
|
+
bindblur && bindblur(
|
|
274
302
|
getCustomEvent(
|
|
275
303
|
'blur',
|
|
276
304
|
evt,
|
|
@@ -320,7 +348,8 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
|
|
|
320
348
|
}
|
|
321
349
|
|
|
322
350
|
const onSelectionChange = (evt: NativeSyntheticEvent<TextInputSelectionChangeEventData>) => {
|
|
323
|
-
|
|
351
|
+
setSelection(evt.nativeEvent.selection)
|
|
352
|
+
bindselectionchange && bindselectionchange(
|
|
324
353
|
getCustomEvent(
|
|
325
354
|
'selectionchange',
|
|
326
355
|
evt,
|
|
@@ -387,8 +416,10 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
|
|
|
387
416
|
}, [])
|
|
388
417
|
|
|
389
418
|
useEffect(() => {
|
|
390
|
-
|
|
391
|
-
|
|
419
|
+
if (focus) {
|
|
420
|
+
setKeyboardAvoidContext()
|
|
421
|
+
}
|
|
422
|
+
}, [focus])
|
|
392
423
|
|
|
393
424
|
useUpdateEffect(() => {
|
|
394
425
|
if (!nodeRef?.current) {
|
|
@@ -424,11 +455,12 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
|
|
|
424
455
|
},
|
|
425
456
|
layoutProps,
|
|
426
457
|
{
|
|
427
|
-
|
|
428
|
-
|
|
458
|
+
onTouchStart: onInputTouchStart,
|
|
459
|
+
onFocus: onInputFocus,
|
|
460
|
+
onBlur: onInputBlur,
|
|
429
461
|
onKeyPress: bindconfirm && onKeyPress,
|
|
430
462
|
onSubmitEditing: bindconfirm && multiline && onSubmitEditing,
|
|
431
|
-
onSelectionChange:
|
|
463
|
+
onSelectionChange: onSelectionChange,
|
|
432
464
|
onTextInput: onTextInput,
|
|
433
465
|
onChange: onChange,
|
|
434
466
|
onContentSizeChange: onContentSizeChange
|
|
@@ -18,11 +18,11 @@
|
|
|
18
18
|
* ✔ vtouchmove
|
|
19
19
|
*/
|
|
20
20
|
import { useEffect, forwardRef, ReactNode, useContext, useCallback, useRef, useMemo, createElement } from 'react'
|
|
21
|
-
import { StyleSheet,
|
|
21
|
+
import { StyleSheet, View, LayoutChangeEvent } from 'react-native'
|
|
22
22
|
import useInnerProps, { getCustomEvent } from './getInnerListeners'
|
|
23
23
|
import useNodesRef, { HandlerRef } from './useNodesRef'
|
|
24
24
|
import { MovableAreaContext } from './context'
|
|
25
|
-
import { useTransformStyle, splitProps, splitStyle, HIDDEN_STYLE, wrapChildren, GestureHandler, flatGesture, extendObject, omit } from './utils'
|
|
25
|
+
import { useTransformStyle, splitProps, splitStyle, HIDDEN_STYLE, wrapChildren, GestureHandler, flatGesture, extendObject, omit, useNavigation } from './utils'
|
|
26
26
|
import { GestureDetector, Gesture, GestureTouchEvent, GestureStateChangeEvent, PanGestureHandlerEventPayload, PanGesture } from 'react-native-gesture-handler'
|
|
27
27
|
import Animated, {
|
|
28
28
|
useSharedValue,
|
|
@@ -126,6 +126,8 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
|
|
|
126
126
|
setHeight
|
|
127
127
|
} = useTransformStyle(Object.assign({}, style, styles.container), { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight })
|
|
128
128
|
|
|
129
|
+
const navigation = useNavigation()
|
|
130
|
+
|
|
129
131
|
const prevSimultaneousHandlersRef = useRef<Array<GestureHandler>>(originSimultaneousHandlers || [])
|
|
130
132
|
const prevWaitForHandlersRef = useRef<Array<GestureHandler>>(waitFor || [])
|
|
131
133
|
const gestureSwitch = useRef(false)
|
|
@@ -333,43 +335,44 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
|
|
|
333
335
|
setHeight(height || 0)
|
|
334
336
|
}
|
|
335
337
|
nodeRef.current?.measure((x: number, y: number, width: number, height: number) => {
|
|
336
|
-
|
|
338
|
+
const { y: navigationY = 0 } = navigation?.layout || {}
|
|
339
|
+
layoutRef.current = { x, y: y - navigationY, width, height, offsetLeft: 0, offsetTop: 0 }
|
|
337
340
|
resetBoundaryAndCheck({ width, height })
|
|
338
341
|
})
|
|
339
342
|
props.onLayout && props.onLayout(e)
|
|
340
343
|
}
|
|
341
344
|
|
|
342
|
-
const extendEvent = useCallback((e: any,
|
|
345
|
+
const extendEvent = useCallback((e: any, type: 'start'|'move'|'end') => {
|
|
346
|
+
const { y: navigationY = 0 } = navigation?.layout || {}
|
|
343
347
|
const touchArr = [e.changedTouches, e.allTouches]
|
|
344
348
|
touchArr.forEach(touches => {
|
|
345
|
-
touches && touches.forEach((item: { absoluteX: number; absoluteY: number; pageX: number; pageY: number }) => {
|
|
349
|
+
touches && touches.forEach((item: { absoluteX: number; absoluteY: number; pageX: number; pageY: number ; clientX: number; clientY: number}) => {
|
|
346
350
|
item.pageX = item.absoluteX
|
|
347
|
-
item.pageY = item.absoluteY
|
|
351
|
+
item.pageY = item.absoluteY - navigationY
|
|
352
|
+
item.clientX = item.absoluteX
|
|
353
|
+
item.clientY = item.absoluteY - navigationY
|
|
348
354
|
})
|
|
349
355
|
})
|
|
350
356
|
Object.assign(e, {
|
|
351
|
-
touches: e.allTouches,
|
|
352
|
-
detail: {
|
|
353
|
-
x: e.changedTouches[0].absoluteX,
|
|
354
|
-
y: e.changedTouches[0].absoluteY
|
|
355
|
-
},
|
|
357
|
+
touches: type === 'end' ? [] : e.allTouches,
|
|
356
358
|
currentTarget: {
|
|
357
359
|
id: props.id || '',
|
|
358
360
|
dataset: collectDataset(props),
|
|
359
361
|
offsetLeft: 0,
|
|
360
362
|
offsetTop: 0
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
+
},
|
|
364
|
+
detail: {}
|
|
365
|
+
})
|
|
363
366
|
}, [])
|
|
364
367
|
|
|
365
368
|
const triggerStartOnJS = ({ e }: { e: GestureTouchEvent }) => {
|
|
366
|
-
extendEvent(e)
|
|
369
|
+
extendEvent(e, 'start')
|
|
367
370
|
bindtouchstart && bindtouchstart(e)
|
|
368
371
|
catchtouchstart && catchtouchstart(e)
|
|
369
372
|
}
|
|
370
373
|
|
|
371
374
|
const triggerMoveOnJS = ({ e, hasTouchmove, hasCatchTouchmove, touchEvent }: { e: GestureTouchEvent; hasTouchmove: boolean; hasCatchTouchmove: boolean; touchEvent: string }) => {
|
|
372
|
-
extendEvent(e)
|
|
375
|
+
extendEvent(e, 'move')
|
|
373
376
|
if (hasTouchmove) {
|
|
374
377
|
if (touchEvent === 'htouchmove') {
|
|
375
378
|
bindhtouchmove && bindhtouchmove(e)
|
|
@@ -390,7 +393,7 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
|
|
|
390
393
|
}
|
|
391
394
|
|
|
392
395
|
const triggerEndOnJS = ({ e }: { e: GestureTouchEvent }) => {
|
|
393
|
-
extendEvent(e)
|
|
396
|
+
extendEvent(e, 'end')
|
|
394
397
|
bindtouchend && bindtouchend(e)
|
|
395
398
|
catchtouchend && catchtouchend(e)
|
|
396
399
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { View, Text, Modal, TouchableWithoutFeedback } from 'react-native'
|
|
2
|
-
import
|
|
2
|
+
import Portal from '../mpx-portal/index'
|
|
3
|
+
import { PickerView } from '@ant-design/react-native'
|
|
3
4
|
import React, { forwardRef, useState, useRef, useEffect } from 'react'
|
|
4
5
|
import useNodesRef, { HandlerRef } from '../useNodesRef' // 引入辅助函数
|
|
5
6
|
import { TimeProps } from './type'
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { ReactNode, useContext, useEffect, useRef } from 'react'
|
|
2
|
+
import { PortalContext, RouteContext, VarContext } from '../context'
|
|
3
|
+
import PortalHost, { portal } from './portal-host'
|
|
4
|
+
|
|
5
|
+
export type PortalProps = {
|
|
6
|
+
children?: ReactNode
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const Portal = ({ children }:PortalProps): null => {
|
|
10
|
+
const manager = useContext(PortalContext)
|
|
11
|
+
const keyRef = useRef<any>(null)
|
|
12
|
+
const { pageId } = useContext(RouteContext) || {}
|
|
13
|
+
const varContext = useContext(VarContext)
|
|
14
|
+
if (varContext) {
|
|
15
|
+
children = (<VarContext.Provider value={varContext} key='varContextWrap'>{children}</VarContext.Provider>)
|
|
16
|
+
}
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
manager.update(keyRef.current, children)
|
|
19
|
+
}, [children])
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
if (!manager) {
|
|
22
|
+
throw new Error(
|
|
23
|
+
'Looks like you forgot to wrap your root component with `PortalHost` component from `@mpxjs/webpack-plugin/lib/runtime/components/react/dist/mpx-portal/index`.\n\n'
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
keyRef.current = manager.mount(children, null, pageId)
|
|
27
|
+
return () => {
|
|
28
|
+
manager.unmount(keyRef.current)
|
|
29
|
+
}
|
|
30
|
+
}, [])
|
|
31
|
+
return null
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
Portal.Host = PortalHost
|
|
35
|
+
Portal.add = portal.add
|
|
36
|
+
Portal.remove = portal.remove
|
|
37
|
+
Portal.update = portal.update
|
|
38
|
+
|
|
39
|
+
export default Portal
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { useEffect, useRef, ReactNode, useMemo, useContext } from 'react'
|
|
2
|
+
import {
|
|
3
|
+
View,
|
|
4
|
+
DeviceEventEmitter,
|
|
5
|
+
NativeEventEmitter,
|
|
6
|
+
StyleSheet
|
|
7
|
+
} from 'react-native'
|
|
8
|
+
import PortalManager from './portal-manager'
|
|
9
|
+
import { PortalContext, RouteContext } from '../context'
|
|
10
|
+
|
|
11
|
+
type PortalHostProps = {
|
|
12
|
+
children: ReactNode,
|
|
13
|
+
pageId: number
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface PortalManagerContextValue {
|
|
17
|
+
mount: (key: number, children: React.ReactNode) => void
|
|
18
|
+
update: (key: number, children: React.ReactNode) => void
|
|
19
|
+
unmount: (key: number) => void
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type Operation =
|
|
23
|
+
| { type: 'mount'; key: number; children: ReactNode }
|
|
24
|
+
| { type: 'update'; key: number; children: ReactNode }
|
|
25
|
+
| { type: 'unmount'; key: number }
|
|
26
|
+
|
|
27
|
+
// events
|
|
28
|
+
const addType = 'MPX_RN_ADD_PORTAL'
|
|
29
|
+
const removeType = 'MPX_RN_REMOVE_PORTAL'
|
|
30
|
+
const updateType = 'MPX_RN_UPDATE_PORTAL'
|
|
31
|
+
// fix react native web does not support DeviceEventEmitter
|
|
32
|
+
const TopViewEventEmitter = DeviceEventEmitter || new NativeEventEmitter()
|
|
33
|
+
|
|
34
|
+
const styles = StyleSheet.create({
|
|
35
|
+
container: {
|
|
36
|
+
flex: 1
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
class PortalGuard {
|
|
41
|
+
private nextKey = 10000
|
|
42
|
+
add = (e: ReactNode, id: number|null) => {
|
|
43
|
+
const key = this.nextKey++
|
|
44
|
+
TopViewEventEmitter.emit(addType, e, key, id)
|
|
45
|
+
return key
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
remove = (key: number) => {
|
|
49
|
+
TopViewEventEmitter.emit(removeType, key)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
update = (key: number, e: ReactNode) => {
|
|
53
|
+
TopViewEventEmitter.emit(updateType, key, e)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* portal
|
|
58
|
+
*/
|
|
59
|
+
export const portal = new PortalGuard()
|
|
60
|
+
|
|
61
|
+
const PortalHost = ({ children } :PortalHostProps): JSX.Element => {
|
|
62
|
+
const _nextKey = useRef(0)
|
|
63
|
+
const manager = useRef<PortalManagerContextValue | null>(null)
|
|
64
|
+
const queue = useRef<Array<{ type: string, key: number; children: ReactNode }>>([])
|
|
65
|
+
const { pageId } = useContext(RouteContext) || {}
|
|
66
|
+
const mount = (children: ReactNode, _key?: number, id?: number|null) => {
|
|
67
|
+
if (id !== pageId) return
|
|
68
|
+
const key = _key || _nextKey.current++
|
|
69
|
+
if (manager.current) {
|
|
70
|
+
manager.current.mount(key, children)
|
|
71
|
+
} else {
|
|
72
|
+
queue.current.push({ type: 'mount', key, children })
|
|
73
|
+
}
|
|
74
|
+
return key
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const unmount = (key: number) => {
|
|
78
|
+
if (manager.current) {
|
|
79
|
+
manager.current.unmount(key)
|
|
80
|
+
} else {
|
|
81
|
+
queue.current.push({ type: 'unmount', key, children })
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const update = (key: number, children?: ReactNode) => {
|
|
86
|
+
if (manager.current) {
|
|
87
|
+
manager.current.update(key, children)
|
|
88
|
+
} else {
|
|
89
|
+
const operation = { type: 'mount', key, children }
|
|
90
|
+
const index = queue.current.findIndex((q) => q.type === 'mount' && q.key === key)
|
|
91
|
+
if (index > -1) {
|
|
92
|
+
queue.current[index] = operation
|
|
93
|
+
} else {
|
|
94
|
+
queue.current.push(operation)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const subScriptions = useMemo(() => {
|
|
99
|
+
return [
|
|
100
|
+
TopViewEventEmitter.addListener(addType, mount),
|
|
101
|
+
TopViewEventEmitter.addListener(removeType, unmount),
|
|
102
|
+
TopViewEventEmitter.addListener(updateType, update)
|
|
103
|
+
]
|
|
104
|
+
}, [])
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
while (queue.current.length && manager.current) {
|
|
107
|
+
const operation = queue.current.shift()
|
|
108
|
+
if (!operation) return
|
|
109
|
+
switch (operation.type) {
|
|
110
|
+
case 'mount':
|
|
111
|
+
manager.current.mount(operation.key, operation.children)
|
|
112
|
+
break
|
|
113
|
+
case 'unmount':
|
|
114
|
+
manager.current.unmount(operation.key)
|
|
115
|
+
break
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return () => {
|
|
120
|
+
subScriptions.forEach((subScription:any) => {
|
|
121
|
+
subScription.remove()
|
|
122
|
+
})
|
|
123
|
+
}
|
|
124
|
+
}, [])
|
|
125
|
+
return (
|
|
126
|
+
<PortalContext.Provider
|
|
127
|
+
value={{
|
|
128
|
+
mount,
|
|
129
|
+
update,
|
|
130
|
+
unmount
|
|
131
|
+
}}
|
|
132
|
+
>
|
|
133
|
+
<View style={styles.container} collapsable={false}>
|
|
134
|
+
{children}
|
|
135
|
+
</View>
|
|
136
|
+
<PortalManager ref={manager} />
|
|
137
|
+
</PortalContext.Provider>
|
|
138
|
+
)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export default PortalHost
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { useState, useCallback, forwardRef, ForwardedRef, useImperativeHandle, ReactNode, ReactElement } from 'react'
|
|
2
|
+
import { View, StyleSheet } from 'react-native'
|
|
3
|
+
import { extendObject } from '../utils'
|
|
4
|
+
|
|
5
|
+
export type State = {
|
|
6
|
+
portals: Array<{
|
|
7
|
+
key: number
|
|
8
|
+
children: ReactNode
|
|
9
|
+
}>
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type PortalManagerProps = {
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const _PortalManager = forwardRef((props: PortalManagerProps, ref:ForwardedRef<unknown>): ReactElement => {
|
|
16
|
+
const [state, setState] = useState<State>({
|
|
17
|
+
portals: []
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const mount = useCallback((key: number, children: ReactNode) => {
|
|
21
|
+
setState((prevState) => ({
|
|
22
|
+
portals: [...prevState.portals, { key, children }]
|
|
23
|
+
}))
|
|
24
|
+
}, [state])
|
|
25
|
+
|
|
26
|
+
const update = useCallback((key: number, children: ReactNode) => {
|
|
27
|
+
setState((prevState) => ({
|
|
28
|
+
portals: prevState.portals.map((item) => {
|
|
29
|
+
if (item.key === key) {
|
|
30
|
+
return extendObject({}, item, { children })
|
|
31
|
+
}
|
|
32
|
+
return item
|
|
33
|
+
})
|
|
34
|
+
}))
|
|
35
|
+
}, [state])
|
|
36
|
+
|
|
37
|
+
const unmount = useCallback((key: number) => {
|
|
38
|
+
setState((prevState) => ({
|
|
39
|
+
portals: prevState.portals.filter((item) => item.key !== key)
|
|
40
|
+
}))
|
|
41
|
+
}, [])
|
|
42
|
+
|
|
43
|
+
useImperativeHandle(ref, () => ({
|
|
44
|
+
mount,
|
|
45
|
+
update,
|
|
46
|
+
unmount,
|
|
47
|
+
portals: state.portals
|
|
48
|
+
}))
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<>
|
|
52
|
+
{state.portals.map(({ key, children }, i) => (
|
|
53
|
+
<View
|
|
54
|
+
key={key}
|
|
55
|
+
collapsable={false} // Need collapsable=false here to clip the elevations
|
|
56
|
+
style={[StyleSheet.absoluteFill, { zIndex: 1000 + i, pointerEvents: 'box-none' }]}>
|
|
57
|
+
{children}
|
|
58
|
+
</View>
|
|
59
|
+
))}
|
|
60
|
+
</>
|
|
61
|
+
)
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
export default _PortalManager
|