@mpxjs/webpack-plugin 2.9.69-beta.3 → 2.9.69-beta.5
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 +20 -57
- 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 +196 -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 +127 -0
- package/lib/runtime/components/react/mpx-portal/portal-manager.tsx +64 -0
- package/lib/runtime/components/react/mpx-portal.tsx +30 -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 +45 -11
- package/lib/runtime/components/react/mpx-swiper.tsx +743 -0
- package/lib/runtime/components/react/mpx-view.tsx +22 -65
- package/lib/runtime/components/react/mpx-web-view.tsx +144 -24
- package/lib/runtime/components/react/pickerFaces.ts +10 -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 +10 -1
- package/lib/runtime/components/react/useAnimationHooks.ts +31 -11
- package/lib/runtime/components/react/utils.tsx +139 -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/lib/wxss/loader.js +15 -2
- 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
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { useEffect, useRef, ReactNode } from 'react'
|
|
2
|
+
import {
|
|
3
|
+
View,
|
|
4
|
+
DeviceEventEmitter,
|
|
5
|
+
EventSubscription,
|
|
6
|
+
NativeEventEmitter,
|
|
7
|
+
StyleSheet
|
|
8
|
+
} from 'react-native'
|
|
9
|
+
import PortalManager from './portal-manager'
|
|
10
|
+
import { getFocusedNavigation } from '@mpxjs/utils'
|
|
11
|
+
import { PortalManagerContextValue, PortalContext } from '../context'
|
|
12
|
+
|
|
13
|
+
export type PortalHostProps = {
|
|
14
|
+
children: ReactNode
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
type addIdsMapsType = {
|
|
18
|
+
[key: number]: number[]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type Operation =
|
|
22
|
+
| { type: 'mount'; key: number; children: ReactNode }
|
|
23
|
+
| { type: 'update'; key: number; children: ReactNode }
|
|
24
|
+
| { type: 'unmount'; key: number }
|
|
25
|
+
|
|
26
|
+
// events
|
|
27
|
+
const addType = 'MPX_RN_ADD_PORTAL'
|
|
28
|
+
const removeType = 'MPX_RN_REMOVE_PORTAL'
|
|
29
|
+
const updateType = 'MPX_RN_UPDATE_PORTAL'
|
|
30
|
+
// fix react native web does not support DeviceEventEmitter
|
|
31
|
+
const TopViewEventEmitter = DeviceEventEmitter || new NativeEventEmitter()
|
|
32
|
+
|
|
33
|
+
const styles = StyleSheet.create({
|
|
34
|
+
container: {
|
|
35
|
+
flex: 1
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
class PortalGuard {
|
|
40
|
+
private nextKey = 10000
|
|
41
|
+
add = (e: ReactNode) => {
|
|
42
|
+
const key = this.nextKey++
|
|
43
|
+
TopViewEventEmitter.emit(addType, e, key)
|
|
44
|
+
return key
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
remove = (key: number) => {
|
|
48
|
+
TopViewEventEmitter.emit(removeType, key)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
update = (key: number, e: ReactNode) => {
|
|
52
|
+
TopViewEventEmitter.emit(updateType, key, e)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* portal
|
|
57
|
+
*/
|
|
58
|
+
export const portal = new PortalGuard()
|
|
59
|
+
|
|
60
|
+
const PortalHost = ({ children } :PortalHostProps): JSX.Element => {
|
|
61
|
+
const _nextKey = useRef(0)
|
|
62
|
+
const _queue = useRef<Operation[]>([])
|
|
63
|
+
const _addType = useRef<EventSubscription | null>(null)
|
|
64
|
+
const _removeType = useRef<EventSubscription | null>(null)
|
|
65
|
+
const _updateType = useRef<EventSubscription | null>(null)
|
|
66
|
+
const manager = useRef<PortalManagerContextValue | null>(null)
|
|
67
|
+
let currentPageId: number | undefined
|
|
68
|
+
const _mount = (children: ReactNode, _key?: number, curPageId?: number) => {
|
|
69
|
+
const navigation = getFocusedNavigation()
|
|
70
|
+
const pageId = navigation?.pageId
|
|
71
|
+
if (pageId !== (curPageId ?? currentPageId)) {
|
|
72
|
+
return
|
|
73
|
+
}
|
|
74
|
+
const key = _key || _nextKey.current++
|
|
75
|
+
if (manager.current) {
|
|
76
|
+
manager.current.mount(key, children)
|
|
77
|
+
}
|
|
78
|
+
return key
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const _unmount = (key: number) => {
|
|
82
|
+
if (manager.current) {
|
|
83
|
+
manager.current.unmount(key)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const _update = (key: number, children?: ReactNode, curPageId?: number) => {
|
|
88
|
+
const navigation = getFocusedNavigation()
|
|
89
|
+
const pageId = navigation?.pageId
|
|
90
|
+
if (pageId !== (curPageId ?? currentPageId)) {
|
|
91
|
+
return
|
|
92
|
+
}
|
|
93
|
+
if (manager.current) {
|
|
94
|
+
manager.current.update(key, children)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
const navigation = getFocusedNavigation()
|
|
100
|
+
currentPageId = navigation?.pageId
|
|
101
|
+
_addType.current = TopViewEventEmitter.addListener(addType, _mount)
|
|
102
|
+
_removeType.current = TopViewEventEmitter.addListener(removeType, _unmount)
|
|
103
|
+
_updateType.current = TopViewEventEmitter.addListener(updateType, _update)
|
|
104
|
+
|
|
105
|
+
return () => {
|
|
106
|
+
_addType.current?.remove()
|
|
107
|
+
_removeType.current?.remove()
|
|
108
|
+
_updateType.current?.remove()
|
|
109
|
+
}
|
|
110
|
+
}, [])
|
|
111
|
+
return (
|
|
112
|
+
<PortalContext.Provider
|
|
113
|
+
value={{
|
|
114
|
+
mount: _mount,
|
|
115
|
+
update: _update,
|
|
116
|
+
unmount: _unmount
|
|
117
|
+
}}
|
|
118
|
+
>
|
|
119
|
+
<View style={styles.container} collapsable={false}>
|
|
120
|
+
{children}
|
|
121
|
+
</View>
|
|
122
|
+
<PortalManager ref={manager} />
|
|
123
|
+
</PortalContext.Provider>
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
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
|
+
|
|
4
|
+
export type State = {
|
|
5
|
+
portals: Array<{
|
|
6
|
+
key: number
|
|
7
|
+
children: ReactNode
|
|
8
|
+
}>
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
type PortalManagerProps = {
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const _PortalManager = forwardRef((props: PortalManagerProps, ref:ForwardedRef<unknown>): ReactElement => {
|
|
15
|
+
const [state, setState] = useState<State>({
|
|
16
|
+
portals: []
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
const mount = useCallback((key: number, children: ReactNode) => {
|
|
20
|
+
setState((prevState) => ({
|
|
21
|
+
portals: [...prevState.portals, { key, children }]
|
|
22
|
+
}))
|
|
23
|
+
}, [state])
|
|
24
|
+
|
|
25
|
+
const update = useCallback((key: number, children: ReactNode) => {
|
|
26
|
+
setState((prevState) => ({
|
|
27
|
+
portals: prevState.portals.map((item) => {
|
|
28
|
+
if (item.key === key) {
|
|
29
|
+
return { ...item, children }
|
|
30
|
+
}
|
|
31
|
+
return item
|
|
32
|
+
})
|
|
33
|
+
}))
|
|
34
|
+
}, [state])
|
|
35
|
+
|
|
36
|
+
const unmount = useCallback((key: number) => {
|
|
37
|
+
setState((prevState) => ({
|
|
38
|
+
portals: prevState.portals.filter((item) => item.key !== key)
|
|
39
|
+
}))
|
|
40
|
+
}, [])
|
|
41
|
+
|
|
42
|
+
useImperativeHandle(ref, () => ({
|
|
43
|
+
mount,
|
|
44
|
+
update,
|
|
45
|
+
unmount,
|
|
46
|
+
portals: state.portals
|
|
47
|
+
}))
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<>
|
|
51
|
+
{state.portals.map(({ key, children }, i) => (
|
|
52
|
+
<View
|
|
53
|
+
key={key}
|
|
54
|
+
collapsable={false} // Need collapsable=false here to clip the elevations
|
|
55
|
+
pointerEvents="box-none"
|
|
56
|
+
style={[StyleSheet.absoluteFill, { zIndex: 1000 + i }]}>
|
|
57
|
+
{children}
|
|
58
|
+
</View>
|
|
59
|
+
))}
|
|
60
|
+
</>
|
|
61
|
+
)
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
export default _PortalManager
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { ReactNode } from 'react'
|
|
2
|
+
import { PortalContext, PortalContextValue } from './context'
|
|
3
|
+
import PortalConsumer from './mpx-portal/portal-consumer'
|
|
4
|
+
import PortalHost, { portal } from './mpx-portal/portal-host'
|
|
5
|
+
|
|
6
|
+
export type PortalProps = {
|
|
7
|
+
/**
|
|
8
|
+
* Content of the `Portal`.
|
|
9
|
+
*/
|
|
10
|
+
children?: ReactNode
|
|
11
|
+
key?: string
|
|
12
|
+
manager?: PortalContextValue
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const Portal = ({ children }:PortalProps): JSX.Element => {
|
|
16
|
+
return (
|
|
17
|
+
<PortalContext.Consumer>
|
|
18
|
+
{(manager) => (
|
|
19
|
+
<PortalConsumer manager={manager}>{children}</PortalConsumer>
|
|
20
|
+
)}
|
|
21
|
+
</PortalContext.Consumer>
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
Portal.Host = PortalHost
|
|
26
|
+
Portal.add = portal.add
|
|
27
|
+
Portal.remove = portal.remove
|
|
28
|
+
Portal.update = portal.update
|
|
29
|
+
|
|
30
|
+
export default Portal
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { ReactNode, createContext, useMemo } from 'react'
|
|
2
|
+
import LocaleProvider, { LocaleContextProps } from './locale-provider'
|
|
3
|
+
import Portal from './mpx-portal'
|
|
4
|
+
import { extendObject } from './utils'
|
|
5
|
+
|
|
6
|
+
export type Theme = typeof defaultTheme & { [key: string]: any }
|
|
7
|
+
|
|
8
|
+
export interface ProviderProps {
|
|
9
|
+
locale?: LocaleContextProps
|
|
10
|
+
theme?: Partial<Theme>
|
|
11
|
+
children: ReactNode
|
|
12
|
+
}
|
|
13
|
+
const defaultTheme = {
|
|
14
|
+
color_text_base: '#000000', // 基本
|
|
15
|
+
color_text_base_inverse: '#ffffff', // 基本 _ 反色
|
|
16
|
+
color_text_secondary: '#a4a9b0', // 辅助色
|
|
17
|
+
color_text_placeholder: '#bbbbbb', // 文本框提示
|
|
18
|
+
color_text_disabled: '#bbbbbb', // 失效
|
|
19
|
+
color_text_caption: '#888888', // 辅助描述
|
|
20
|
+
color_text_paragraph: '#333333', // 段落
|
|
21
|
+
color_error: '#ff4d4f', // 错误(form validate)
|
|
22
|
+
color_warning: '#faad14', // 警告
|
|
23
|
+
color_success: '#52c41a',
|
|
24
|
+
color_primary: '#1677ff'
|
|
25
|
+
}
|
|
26
|
+
export const ThemeContext = createContext(defaultTheme)
|
|
27
|
+
|
|
28
|
+
export type PartialTheme = Partial<Theme>
|
|
29
|
+
|
|
30
|
+
export interface ThemeProviderProps {
|
|
31
|
+
value?: PartialTheme
|
|
32
|
+
children?: React.ReactNode
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const ThemeProvider = (props: ThemeProviderProps) => {
|
|
36
|
+
const { value, children } = props
|
|
37
|
+
const theme = useMemo(() => (extendObject({}, defaultTheme, value)), [value])
|
|
38
|
+
return <ThemeContext.Provider value={theme}>{children}</ThemeContext.Provider>
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const Provider = ({ locale, theme, children }:ProviderProps): JSX.Element => {
|
|
42
|
+
return (
|
|
43
|
+
<LocaleProvider locale={locale}>
|
|
44
|
+
<ThemeProvider value={theme}>
|
|
45
|
+
<Portal.Host>{children}</Portal.Host>
|
|
46
|
+
</ThemeProvider>
|
|
47
|
+
</LocaleProvider>
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export default Provider
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
* ✔ nodes
|
|
4
4
|
*/
|
|
5
5
|
import { View, ViewProps, ViewStyle } from 'react-native'
|
|
6
|
-
import { useRef, forwardRef, JSX, useState } from 'react'
|
|
6
|
+
import { useRef, forwardRef, JSX, useState, createElement } from 'react'
|
|
7
7
|
import useInnerProps from '../getInnerListeners'
|
|
8
8
|
import useNodesRef, { HandlerRef } from '../useNodesRef' // 引入辅助函数
|
|
9
|
-
import { useTransformStyle, useLayout } from '../utils'
|
|
9
|
+
import { useTransformStyle, useLayout, extendObject } from '../utils'
|
|
10
10
|
import { WebView, WebViewMessageEvent } from 'react-native-webview'
|
|
11
11
|
import { generateHTML } from './html'
|
|
12
12
|
|
|
@@ -91,28 +91,22 @@ const _RichText = forwardRef<HandlerRef<View, _RichTextProps>, _RichTextProps>((
|
|
|
91
91
|
layoutRef
|
|
92
92
|
})
|
|
93
93
|
|
|
94
|
-
const innerProps = useInnerProps(props, {
|
|
94
|
+
const innerProps = useInnerProps(props, extendObject({
|
|
95
95
|
ref: nodeRef,
|
|
96
|
-
style:
|
|
97
|
-
|
|
98
|
-
}, [], {
|
|
96
|
+
style: extendObject(normalStyle, layoutStyle)
|
|
97
|
+
}, layoutProps), [], {
|
|
99
98
|
layoutRef
|
|
100
99
|
})
|
|
101
100
|
|
|
102
101
|
const html: string = typeof nodes === 'string' ? nodes : jsonToHtmlStr(nodes)
|
|
103
102
|
|
|
104
|
-
return (
|
|
105
|
-
|
|
106
|
-
{
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
setWebViewHeight(+event.nativeEvent.data)
|
|
112
|
-
}}
|
|
113
|
-
>
|
|
114
|
-
</WebView>
|
|
115
|
-
</View>
|
|
103
|
+
return createElement(View, innerProps,
|
|
104
|
+
createElement(WebView, {
|
|
105
|
+
source: { html: generateHTML(html) },
|
|
106
|
+
onMessage: (event: WebViewMessageEvent) => {
|
|
107
|
+
setWebViewHeight(+event.nativeEvent.data)
|
|
108
|
+
}
|
|
109
|
+
})
|
|
116
110
|
)
|
|
117
111
|
})
|
|
118
112
|
|
|
@@ -32,15 +32,14 @@
|
|
|
32
32
|
* ✔ bindscroll
|
|
33
33
|
*/
|
|
34
34
|
import { ScrollView } from 'react-native-gesture-handler'
|
|
35
|
-
import { View, RefreshControl, NativeSyntheticEvent, NativeScrollEvent, LayoutChangeEvent, ViewStyle } from 'react-native'
|
|
36
|
-
import { JSX, ReactNode, RefObject, useRef, useState, useEffect, forwardRef, useContext, createElement } from 'react'
|
|
35
|
+
import { View, RefreshControl, NativeSyntheticEvent, NativeScrollEvent, LayoutChangeEvent, ViewStyle, Platform } from 'react-native'
|
|
36
|
+
import { JSX, ReactNode, RefObject, useRef, useState, useEffect, forwardRef, useContext, createElement, useMemo } from 'react'
|
|
37
37
|
import { useAnimatedRef } from 'react-native-reanimated'
|
|
38
38
|
import { warn } from '@mpxjs/utils'
|
|
39
39
|
import useInnerProps, { getCustomEvent } from './getInnerListeners'
|
|
40
40
|
import useNodesRef, { HandlerRef } from './useNodesRef'
|
|
41
41
|
import { splitProps, splitStyle, useTransformStyle, useLayout, wrapChildren, extendObject, flatGesture, GestureHandler } from './utils'
|
|
42
|
-
import { IntersectionObserverContext } from './context'
|
|
43
|
-
|
|
42
|
+
import { IntersectionObserverContext, ScrollViewContext } from './context'
|
|
44
43
|
interface ScrollViewProps {
|
|
45
44
|
children?: ReactNode;
|
|
46
45
|
enhanced?: boolean;
|
|
@@ -194,6 +193,12 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
|
|
|
194
193
|
gestureRef: scrollViewRef
|
|
195
194
|
})
|
|
196
195
|
|
|
196
|
+
const contextValue = useMemo(() => {
|
|
197
|
+
return {
|
|
198
|
+
gestureRef: scrollViewRef
|
|
199
|
+
}
|
|
200
|
+
}, [])
|
|
201
|
+
|
|
197
202
|
const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: scrollViewRef, onLayout })
|
|
198
203
|
|
|
199
204
|
if (scrollX && scrollY) {
|
|
@@ -332,11 +337,6 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
|
|
|
332
337
|
}, props)
|
|
333
338
|
)
|
|
334
339
|
updateScrollOptions(e, { scrollLeft, scrollTop })
|
|
335
|
-
if (enableTriggerIntersectionObserver && intersectionObservers) {
|
|
336
|
-
for (const key in intersectionObservers) {
|
|
337
|
-
intersectionObservers[key].throttleMeasure()
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
340
|
}
|
|
341
341
|
|
|
342
342
|
function onScrollEnd (e: NativeSyntheticEvent<NativeScrollEvent>) {
|
|
@@ -358,8 +358,15 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
|
|
|
358
358
|
updateScrollOptions(e, { scrollLeft, scrollTop })
|
|
359
359
|
onStartReached(e)
|
|
360
360
|
onEndReached(e)
|
|
361
|
+
updateIntersection()
|
|
362
|
+
}
|
|
363
|
+
function updateIntersection () {
|
|
364
|
+
if (enableTriggerIntersectionObserver && intersectionObservers) {
|
|
365
|
+
for (const key in intersectionObservers) {
|
|
366
|
+
intersectionObservers[key].throttleMeasure();
|
|
367
|
+
}
|
|
368
|
+
}
|
|
361
369
|
}
|
|
362
|
-
|
|
363
370
|
function scrollToOffset (x = 0, y = 0) {
|
|
364
371
|
if (scrollViewRef.current) {
|
|
365
372
|
scrollViewRef.current.scrollTo({ x, y, animated: !!scrollWithAnimation })
|
|
@@ -429,6 +436,7 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
|
|
|
429
436
|
function onScrollDrag (e: NativeSyntheticEvent<NativeScrollEvent>) {
|
|
430
437
|
const { x: scrollLeft, y: scrollTop } = e.nativeEvent.contentOffset
|
|
431
438
|
updateScrollOptions(e, { scrollLeft, scrollTop })
|
|
439
|
+
updateIntersection()
|
|
432
440
|
}
|
|
433
441
|
|
|
434
442
|
const scrollAdditionalProps: ScrollAdditionalProps = extendObject(
|
|
@@ -507,14 +515,17 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
|
|
|
507
515
|
}, (refresherDefaultStyle && refresherDefaultStyle !== 'none' ? { colors: refreshColor[refresherDefaultStyle] } : null)))
|
|
508
516
|
: undefined
|
|
509
517
|
}),
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
+
createElement(ScrollViewContext.Provider,
|
|
519
|
+
{ value: contextValue },
|
|
520
|
+
wrapChildren(
|
|
521
|
+
props,
|
|
522
|
+
{
|
|
523
|
+
hasVarDec,
|
|
524
|
+
varContext: varContextRef.current,
|
|
525
|
+
textStyle,
|
|
526
|
+
textProps
|
|
527
|
+
}
|
|
528
|
+
)
|
|
518
529
|
)
|
|
519
530
|
)
|
|
520
531
|
})
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { View
|
|
2
|
-
import {
|
|
1
|
+
import { View } from 'react-native'
|
|
2
|
+
import Animated, { useAnimatedStyle, interpolate, SharedValue } from 'react-native-reanimated'
|
|
3
|
+
import { ReactNode, forwardRef, useRef, useContext } from 'react'
|
|
3
4
|
import useInnerProps from './getInnerListeners'
|
|
4
5
|
import useNodesRef, { HandlerRef } from './useNodesRef' // 引入辅助函数
|
|
5
6
|
import { useTransformStyle, splitStyle, splitProps, wrapChildren, useLayout } from './utils'
|
|
7
|
+
import { SwiperContext } from './context'
|
|
6
8
|
|
|
7
9
|
interface SwiperItemProps {
|
|
8
10
|
'item-id'?: string;
|
|
@@ -14,15 +16,31 @@ interface SwiperItemProps {
|
|
|
14
16
|
'parent-height'?: number;
|
|
15
17
|
children?: ReactNode;
|
|
16
18
|
style?: Object;
|
|
19
|
+
customStyle: Object;
|
|
20
|
+
itemIndex: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface ContextType {
|
|
24
|
+
offset: SharedValue<number>;
|
|
25
|
+
step: SharedValue<number>;
|
|
26
|
+
scale: boolean;
|
|
27
|
+
dir: string;
|
|
17
28
|
}
|
|
18
29
|
|
|
19
30
|
const _SwiperItem = forwardRef<HandlerRef<View, SwiperItemProps>, SwiperItemProps>((props: SwiperItemProps, ref) => {
|
|
20
31
|
const {
|
|
21
32
|
'enable-var': enableVar,
|
|
22
33
|
'external-var-context': externalVarContext,
|
|
23
|
-
style
|
|
34
|
+
style,
|
|
35
|
+
customStyle,
|
|
36
|
+
itemIndex
|
|
24
37
|
} = props
|
|
25
38
|
|
|
39
|
+
const contextValue = useContext(SwiperContext) as ContextType
|
|
40
|
+
const offset = contextValue.offset || 0
|
|
41
|
+
const step = contextValue.step || 0
|
|
42
|
+
const scale = contextValue.scale || false
|
|
43
|
+
const dir = contextValue.dir || 'x'
|
|
26
44
|
const { textProps } = splitProps(props)
|
|
27
45
|
const nodeRef = useRef(null)
|
|
28
46
|
|
|
@@ -47,19 +65,35 @@ const _SwiperItem = forwardRef<HandlerRef<View, SwiperItemProps>, SwiperItemProp
|
|
|
47
65
|
} = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: nodeRef })
|
|
48
66
|
|
|
49
67
|
const innerProps = useInnerProps(props, {
|
|
50
|
-
style: { ...innerStyle, ...layoutStyle },
|
|
51
68
|
ref: nodeRef,
|
|
52
69
|
...layoutProps
|
|
53
70
|
}, [
|
|
54
71
|
'children',
|
|
55
|
-
'enable-offset'
|
|
72
|
+
'enable-offset',
|
|
73
|
+
'style'
|
|
56
74
|
], { layoutRef })
|
|
57
|
-
|
|
75
|
+
const itemAnimatedStyle = useAnimatedStyle(() => {
|
|
76
|
+
if (!step.value) return {}
|
|
77
|
+
const inputRange = [step.value, 0]
|
|
78
|
+
const outputRange = [0.7, 1]
|
|
79
|
+
// 实现元素的宽度跟随step从0到真实宽度,且不能触发重新渲染整个组件,通过AnimatedStyle的方式实现
|
|
80
|
+
const outerLayoutStyle = dir === 'x' ? { width: step.value, height: '100%' } : { width: '100%', height: step.value }
|
|
81
|
+
const transformStyle = []
|
|
82
|
+
if (scale) {
|
|
83
|
+
transformStyle.push({
|
|
84
|
+
scale: interpolate(Math.abs(Math.abs(offset.value) - itemIndex * step.value), inputRange, outputRange)
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
return Object.assign(outerLayoutStyle, {
|
|
88
|
+
transform: transformStyle
|
|
89
|
+
})
|
|
90
|
+
})
|
|
58
91
|
return (
|
|
59
|
-
<View
|
|
60
|
-
|
|
61
|
-
{
|
|
62
|
-
|
|
92
|
+
<Animated.View
|
|
93
|
+
{...innerProps}
|
|
94
|
+
style={[innerStyle, layoutStyle, itemAnimatedStyle, customStyle]}
|
|
95
|
+
data-itemId={props['item-id']}>
|
|
96
|
+
{
|
|
63
97
|
wrapChildren(
|
|
64
98
|
props,
|
|
65
99
|
{
|
|
@@ -70,7 +104,7 @@ const _SwiperItem = forwardRef<HandlerRef<View, SwiperItemProps>, SwiperItemProp
|
|
|
70
104
|
}
|
|
71
105
|
)
|
|
72
106
|
}
|
|
73
|
-
</View>
|
|
107
|
+
</Animated.View>
|
|
74
108
|
)
|
|
75
109
|
})
|
|
76
110
|
|