@mpxjs/webpack-plugin 2.9.17 → 2.9.19-react.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.
Files changed (66) hide show
  1. package/lib/config.js +59 -97
  2. package/lib/dependencies/ResolveDependency.js +2 -2
  3. package/lib/helpers.js +5 -1
  4. package/lib/index.js +27 -19
  5. package/lib/loader.js +56 -118
  6. package/lib/native-loader.js +43 -20
  7. package/lib/platform/index.js +3 -0
  8. package/lib/platform/style/wx/index.js +413 -0
  9. package/lib/platform/template/wx/component-config/button.js +36 -0
  10. package/lib/platform/template/wx/component-config/cover-view.js +1 -1
  11. package/lib/platform/template/wx/component-config/image.js +15 -0
  12. package/lib/platform/template/wx/component-config/input.js +36 -0
  13. package/lib/platform/template/wx/component-config/scroll-view.js +27 -1
  14. package/lib/platform/template/wx/component-config/swiper-item.js +13 -1
  15. package/lib/platform/template/wx/component-config/swiper.js +25 -1
  16. package/lib/platform/template/wx/component-config/text.js +17 -1
  17. package/lib/platform/template/wx/component-config/textarea.js +39 -0
  18. package/lib/platform/template/wx/component-config/unsupported.js +18 -0
  19. package/lib/platform/template/wx/component-config/view.js +15 -1
  20. package/lib/platform/template/wx/index.js +89 -7
  21. package/lib/react/index.js +92 -0
  22. package/lib/react/processJSON.js +362 -0
  23. package/lib/react/processScript.js +40 -0
  24. package/lib/react/processStyles.js +63 -0
  25. package/lib/react/processTemplate.js +151 -0
  26. package/lib/react/script-helper.js +79 -0
  27. package/lib/react/style-helper.js +91 -0
  28. package/lib/runtime/components/react/event.config.ts +32 -0
  29. package/lib/runtime/components/react/getInnerListeners.ts +289 -0
  30. package/lib/runtime/components/react/getInnerListeners.type.ts +68 -0
  31. package/lib/runtime/components/react/mpx-button.tsx +402 -0
  32. package/lib/runtime/components/react/mpx-image/index.tsx +351 -0
  33. package/lib/runtime/components/react/mpx-image/svg.tsx +21 -0
  34. package/lib/runtime/components/react/mpx-input.tsx +389 -0
  35. package/lib/runtime/components/react/mpx-scroll-view.tsx +412 -0
  36. package/lib/runtime/components/react/mpx-swiper/carouse.tsx +407 -0
  37. package/lib/runtime/components/react/mpx-swiper/index.tsx +68 -0
  38. package/lib/runtime/components/react/mpx-swiper/type.ts +69 -0
  39. package/lib/runtime/components/react/mpx-swiper-item.tsx +42 -0
  40. package/lib/runtime/components/react/mpx-text.tsx +106 -0
  41. package/lib/runtime/components/react/mpx-textarea.tsx +46 -0
  42. package/lib/runtime/components/react/mpx-view.tsx +397 -0
  43. package/lib/runtime/components/react/utils.ts +92 -0
  44. package/lib/runtime/components/web/event.js +100 -0
  45. package/lib/runtime/components/web/getInnerListeners.js +0 -78
  46. package/lib/runtime/components/web/mpx-button.vue +1 -1
  47. package/lib/runtime/components/web/mpx-navigator.vue +1 -1
  48. package/lib/runtime/components/web/mpx-scroll-view.vue +113 -37
  49. package/lib/runtime/oc.wxs +16 -0
  50. package/lib/runtime/optionProcessor.js +1 -1
  51. package/lib/runtime/stringify.wxs +3 -7
  52. package/lib/runtime/useNodesRef.ts +39 -0
  53. package/lib/style-compiler/index.js +2 -1
  54. package/lib/template-compiler/compiler.js +544 -121
  55. package/lib/template-compiler/gen-node-react.js +95 -0
  56. package/lib/template-compiler/index.js +19 -31
  57. package/lib/utils/env.js +17 -0
  58. package/lib/utils/make-map.js +1 -1
  59. package/lib/utils/shallow-stringify.js +17 -0
  60. package/lib/utils/ts-loader-watch-run-loader-filter.js +4 -1
  61. package/lib/web/index.js +122 -0
  62. package/lib/web/processMainScript.js +6 -4
  63. package/lib/web/processScript.js +9 -5
  64. package/lib/web/processTemplate.js +14 -14
  65. package/lib/web/script-helper.js +11 -19
  66. package/package.json +7 -3
@@ -0,0 +1,407 @@
1
+ /**
2
+ * swiper 实现
3
+ */
4
+ import { View, ScrollView, Dimensions, LayoutChangeEvent, NativeSyntheticEvent, NativeScrollEvent, NativeScrollPoint } from 'react-native'
5
+ import React, { forwardRef, useState, useRef, useEffect, ReactNode } from 'react'
6
+ import { CarouseProps, CarouseState } from './type'
7
+ import { getCustomEvent } from '../getInnerListeners'
8
+ import useNodesRef, { HandlerRef } from '../../../useNodesRef' // 引入辅助函数
9
+
10
+ /**
11
+ * 默认的Style类型
12
+ */
13
+ const styles: { [key: string]: Object } = {
14
+ container_x: {
15
+ position: 'relative',
16
+ },
17
+ container_y: {
18
+ position: 'relative',
19
+ },
20
+ pagination_x: {
21
+ position: 'absolute',
22
+ bottom: 25,
23
+ left: 0,
24
+ right: 0,
25
+ flexDirection: 'row',
26
+ flex: 1,
27
+ justifyContent: 'center',
28
+ alignItems: 'center',
29
+ },
30
+
31
+ pagination_y: {
32
+ position: 'absolute',
33
+ right: 15,
34
+ top: 0,
35
+ bottom: 0,
36
+ flexDirection: 'column',
37
+ flex: 1,
38
+ justifyContent: 'center',
39
+ alignItems: 'center',
40
+ }
41
+ }
42
+
43
+
44
+ const _Carouse = forwardRef<HandlerRef<ScrollView, CarouseProps>, CarouseProps>((props , ref): React.JSX.Element => {
45
+ // 默认取水平方向的width
46
+ const { width } = Dimensions.get('window')
47
+ const defaultHeight = 150
48
+ const dir = props.horizontal === false ? 'y' : 'x'
49
+ // state的offset默认值
50
+ const defaultX = width * (props.circular ? props.current + 1 : props.current) || 0
51
+ const defaultY = defaultHeight * (props.circular ? props.current + 1 : props.current) || 0
52
+ // 内部存储上一次的offset值
53
+ const newChild = Array.isArray(props.children) ? props.children.filter(child => child) : props.children
54
+ // 默认设置为初次渲染
55
+ const initRenderRef = useRef(true)
56
+ const autoplayTimerRef = useRef<ReturnType <typeof setTimeout> | null>(null)
57
+ let loopJumpTimerRef = useRef<ReturnType <typeof setTimeout> | null>(null)
58
+ const { nodeRef: scrollViewRef } = useNodesRef<ScrollView, CarouseProps>(props, ref, {
59
+ })
60
+ const autoplayEndRef = useRef(false)
61
+ // 存储layout布局信息
62
+ const layoutRef = useRef({})
63
+ // 内部存储上一次的偏移量
64
+ const internalsRef = useRef({
65
+ offset: {
66
+ x: defaultX || 0,
67
+ y: defaultY || 0
68
+ },
69
+ isScrolling: false
70
+ })
71
+ const [state, setState] = useState({
72
+ children: newChild,
73
+ width: width || 375,
74
+ height: defaultHeight,
75
+ index: 0,
76
+ total: Array.isArray(newChild) ? newChild.length : ( newChild ? 1 : 0),
77
+ offset: {
78
+ x: dir === 'x' ? defaultX : 0,
79
+ y: dir === 'y' ? defaultY: 0
80
+ },
81
+ loopJump: false,
82
+ dir
83
+ } as CarouseState);
84
+
85
+ useEffect(() => {
86
+ // 确认这个是变化的props变化的时候才执行,还是初始化的时候就执行
87
+ if (props.autoplay) {
88
+ startAutoPlay()
89
+ } else {
90
+ startSwiperLoop()
91
+ }
92
+ }, [props.autoplay, props.current, state.index]);
93
+
94
+ /**
95
+ * 更新index,以视图的offset计算当前的索引
96
+ */
97
+ function updateIndex (scrollViewOffset: NativeScrollPoint) {
98
+ const diff = scrollViewOffset[dir] - internalsRef.current.offset[state.dir]
99
+ if (!diff) return
100
+
101
+ const step = dir === 'x' ? state.width : state.height
102
+ let loopJump = false
103
+ let newIndex = state.index + Math.round(diff / step)
104
+ // 若是循环circular
105
+ // 1. 当前索引-1, 初始化为最后一个索引, 且scrollView的偏移量设置为 每个元素的步长 * 一共多少个元素, 这里为什么不减一呢
106
+ // 2. 当前索引>total, 初始化为第一个元素,且scrollView的偏移量设置为一个元素的步长
107
+ if (props.circular) {
108
+ if (state.index <= -1) {
109
+ newIndex = state.total - 1
110
+ scrollViewOffset[state.dir] = step * state.total
111
+ loopJump = true
112
+ } else if (newIndex >= state.total) {
113
+ newIndex = 0
114
+ scrollViewOffset[state.dir] = step
115
+ loopJump = true
116
+ }
117
+ }
118
+ // 存储当前的偏移量
119
+ internalsRef.current.offset = scrollViewOffset
120
+ // 这里需不需要区分是否loop,初始化????
121
+ setState((preState) => {
122
+ const newState = {
123
+ ...preState,
124
+ index: newIndex,
125
+ offset: scrollViewOffset,
126
+ loopJump
127
+ }
128
+ return newState
129
+ })
130
+ internalsRef.current.isScrolling = false
131
+ // getCustomEvent
132
+ const eventData = getCustomEvent('change', {}, { detail: {current: newIndex, source: 'touch' }, layoutRef: layoutRef })
133
+ props.bindchange && props.bindchange(eventData)
134
+ // 更新完状态之后, 开启新的loop
135
+ }
136
+
137
+ /**
138
+ * 用户手动点击播放
139
+ * 触发scrollView的onScrollEnd事件 => 然后更新索引 => 通过useEffect事件 => startSwiperLoop => 主动更新scrollView到指定的位置
140
+ * 若是circular, 到最后一个索引会更新为0,但是视觉要scrollView到下一个
141
+ * 若是circular, 到第一个再往前索引会更新为total-1, 但是视觉是展示的最后一个
142
+ */
143
+ function startSwiperLoop () {
144
+ loopJumpTimerRef.current = setTimeout(() => {
145
+ let offset = { x: 0, y: 0, animated: false}
146
+ if (state.index > 0){
147
+ offset = props.horizontal ? { x: state.width * state.index, y: 0, animated: false } : { x: 0, y: state.height * state.index, animated: false }
148
+ }
149
+ if (props.circular) {
150
+ offset = props.horizontal ? { x: state.width * (state.index + 1), y: 0, animated: false } : { x: 0, y: state.height * (state.index + 1), animated: false }
151
+ }
152
+ scrollViewRef.current?.scrollTo(offset)
153
+ internalsRef.current.offset = offset
154
+ }, props.duration || 500)
155
+ }
156
+
157
+ /**
158
+ * 开启自动轮播
159
+ * 每间隔interval scrollView的offset更改到下一个位置,通过onScrollEnd来获取contentOffset再计算要更新的索引index
160
+ */
161
+ function startAutoPlay () {
162
+ // 已经开启过autopaly则不重新创建
163
+ if (!Array.isArray(state.children) || !props.autoplay || internalsRef.current.isScrolling || autoplayEndRef.current) {
164
+ return
165
+ }
166
+ autoplayTimerRef.current && clearTimeout(autoplayTimerRef.current)
167
+ // 非循环自动播放的形式下 到最后一帧 结束自动播放
168
+ if (!props.circular && state.index === state.total -1) {
169
+ autoplayEndRef.current = true
170
+ return
171
+ }
172
+
173
+ // 开启自动播放
174
+ autoplayTimerRef.current = setTimeout(() => {
175
+ if (state.total < 2) return
176
+ const nexStep = 1
177
+ const toIndex = (props.circular ? 1 : 0) + nexStep + state.index
178
+ let x = 0
179
+ let y = 0
180
+ if (state.dir === 'x') x = toIndex * state.width
181
+ if (state.dir === 'y') y = toIndex * state.height
182
+ // animated会影响切换的offset,先改为false
183
+ scrollViewRef.current?.scrollTo({ x, y, animated: false })
184
+
185
+ internalsRef.current.isScrolling = true
186
+
187
+ autoplayEndRef.current = false
188
+ updateIndex({ x, y })
189
+ }, props.interval || 5000)
190
+ }
191
+
192
+ /**
193
+ * 当用户开始拖动此视图时调用此函数, 更新当前在滚动态
194
+ */
195
+ function onScrollBegin () {
196
+ internalsRef.current.isScrolling = true
197
+ }
198
+ function onScrollEnd (event: NativeSyntheticEvent<NativeScrollEvent>) {
199
+ internalsRef.current.isScrolling = false
200
+
201
+ // 用户手动滑动更新索引后,如果开启了自动轮播等重新开始
202
+ updateIndex(event.nativeEvent.contentOffset)
203
+ }
204
+
205
+ /**
206
+ * 当拖拽结束时,检测是否可滚动
207
+ */
208
+ function onScrollEndDrag (event: NativeSyntheticEvent<NativeScrollEvent>) {
209
+ const { contentOffset } = event.nativeEvent
210
+ const { index, total } = state
211
+
212
+ const internalOffset = internalsRef.current.offset
213
+ const previousOffset = props.horizontal ? internalOffset.x : internalOffset.y
214
+ const newOffset = props.horizontal ? contentOffset.x : contentOffset.y
215
+
216
+ if (previousOffset === newOffset && (index === 0 || index === total - 1)) {
217
+ internalsRef.current.isScrolling = false
218
+ }
219
+ }
220
+ /**
221
+ * 垂直方向时,获取单个元素的布局,更新
222
+ */
223
+ function onItemLayout (event: LayoutChangeEvent) {
224
+ if (!initRenderRef.current || state.dir === 'x') return
225
+ const { width, height } = event.nativeEvent.layout
226
+ if (state.total > 1) {
227
+ internalsRef.current.offset[state.dir] = (state.dir === 'y' ? height * state.index : state.width * state.index)
228
+ }
229
+
230
+ if (!state.offset.x && !state.offset.y) {
231
+ state.offset = internalsRef.current.offset
232
+ }
233
+
234
+ if (initRenderRef.current && state.total > 1) {
235
+ scrollViewRef.current?.scrollTo({ ...internalsRef.current.offset, animated: false })
236
+ initRenderRef.current = false
237
+ }
238
+ setState((preState) => {
239
+ return {
240
+ ...preState,
241
+ height
242
+ }
243
+ })
244
+ }
245
+ /**
246
+ * 水平方向时,获取单个元素的布局,更新
247
+ */
248
+ function onWrapperLayout () {
249
+ if (props.enableOffset) {
250
+ // @ts-ignore
251
+ scrollViewRef.current?.measure((x: number, y: number, width: number, height: number, offsetLeft: number, offsetTop: number) => {
252
+ layoutRef.current = { x, y, width, height, offsetLeft, offsetTop }
253
+ props.getInnerLayout && props.getInnerLayout(layoutRef)
254
+ })
255
+ }
256
+ if (state.dir === 'y') return
257
+ if (!state.offset.x && !state.offset.y) {
258
+ state.offset = internalsRef.current.offset
259
+ }
260
+ if (!initRenderRef.current && state.total > 1) {
261
+ scrollViewRef.current?.scrollTo({ ...state.offset, animated: false })
262
+ initRenderRef.current = false
263
+ }
264
+ }
265
+
266
+ function renderScrollView (pages: ReactNode) {
267
+ let scrollElementProps = {
268
+ ref: scrollViewRef,
269
+ horizontal: props.horizontal,
270
+ pagingEnabled: true,
271
+ showsHorizontalScrollIndicator: false,
272
+ showsVerticalScrollIndicator: false,
273
+ bounces: false,
274
+ scrollsToTop: false,
275
+ removeClippedSubviews: true,
276
+ automaticallyAdjustContentInsets: false
277
+ }
278
+ return (
279
+ <ScrollView
280
+ {...scrollElementProps}
281
+ overScrollMode="always"
282
+ contentOffset={state.offset}
283
+ onScrollBeginDrag={onScrollBegin}
284
+ onMomentumScrollEnd={onScrollEnd}
285
+ onScrollEndDrag={onScrollEndDrag}
286
+ >
287
+ {pages}
288
+ </ScrollView>
289
+ )
290
+ }
291
+
292
+ function renderPagination () {
293
+ if (state.total <= 1) return null
294
+ let dots: Array<ReactNode> = []
295
+ const ActiveDot = (
296
+ <View
297
+ style={[
298
+ {
299
+ backgroundColor: props.activeDotColor || '#007aff',
300
+ width: 8,
301
+ height: 8,
302
+ borderRadius: 4,
303
+ marginLeft: 3,
304
+ marginRight: 3,
305
+ marginTop: 3,
306
+ marginBottom: 3
307
+ }
308
+ ]}
309
+ />
310
+ )
311
+ const Dot = (
312
+ <View
313
+ style={[
314
+ {
315
+ backgroundColor: props.dotColor || 'rgba(0,0,0,.2)',
316
+ width: 8,
317
+ height: 8,
318
+ borderRadius: 4,
319
+ marginLeft: 3,
320
+ marginRight: 3,
321
+ marginTop: 3,
322
+ marginBottom: 3
323
+ }
324
+ ]}
325
+ />
326
+ )
327
+ for (let i = 0; i < state.total; i++) {
328
+ let curDot = (i === state.index ? React.cloneElement(ActiveDot, { key: i }) : React.cloneElement(Dot, { key: i }))
329
+ dots.push(curDot)
330
+ }
331
+ return (
332
+ <View
333
+ pointerEvents="none"
334
+ style={[styles['pagination_' + state.dir]]}
335
+ >
336
+ {dots}
337
+ </View>
338
+ )
339
+ }
340
+
341
+ function renderPages () {
342
+ const { width, height, total, children } = state
343
+ const { circular, previousMargin, nextMargin, innerProps } = props
344
+ const pageStyle = { width: width, height: height }
345
+ if (total > 1 && Array.isArray(children)) {
346
+ let arrElements: (Array<ReactNode>) = []
347
+ // pages = ["2", "0", "1", "2", "0"]
348
+ let pages = Array.isArray(children) && Object.keys(children) || []
349
+ /* 无限循环的时候 */
350
+ if (circular) {
351
+ pages.unshift(total - 1 + '')
352
+ pages.push('0')
353
+ }
354
+ arrElements = pages.map((page, i) => {
355
+ let pageStyle2 = { width: width, height: height }
356
+ const extraStyle = {} as {
357
+ left? : number;
358
+ marginLeft?: number;
359
+ paddingLeft?: number
360
+ }
361
+
362
+ if (previousMargin) {
363
+ extraStyle.left = +previousMargin
364
+ }
365
+ if (nextMargin && state.index === i - 1) {
366
+ const half = Math.floor(+nextMargin / 2)
367
+ extraStyle.marginLeft = - half
368
+ extraStyle.paddingLeft = half
369
+ }
370
+ return (
371
+ <View style={[pageStyle2, extraStyle]} key={ 'page' + i} onLayout={onItemLayout}>
372
+ {children[+page]}
373
+ </View>
374
+ )
375
+ })
376
+ return pages
377
+ } else {
378
+ return (
379
+ <View style={pageStyle} key={0}>
380
+ {children}
381
+ </View>
382
+ )
383
+ }
384
+ }
385
+
386
+ const vStyle = {} as { height: number }
387
+ if (dir === 'y') {
388
+ vStyle.height = defaultHeight
389
+ }
390
+ const pages: Array<ReactNode> | ReactNode = renderPages()
391
+ const strStyle: string = 'container_' + state.dir
392
+ const eventProps = props.innerProps || {}
393
+
394
+ return (
395
+ <View
396
+ style={[styles[strStyle], vStyle]}
397
+ {...eventProps}
398
+ onLayout={onWrapperLayout}>
399
+ {renderScrollView(pages)}
400
+ {props.showsPagination && renderPagination()}
401
+ </View>)
402
+
403
+ })
404
+
405
+ _Carouse.displayName = '_Carouse';
406
+
407
+ export default _Carouse
@@ -0,0 +1,68 @@
1
+ import { View, ScrollView } from 'react-native'
2
+ import React, { forwardRef, useRef } from 'react'
3
+ import { default as Carouse } from './carouse'
4
+ import { SwiperProps } from './type'
5
+ import useInnerProps from '../getInnerListeners'
6
+ import useNodesRef, { HandlerRef } from '../../../useNodesRef' // 引入辅助函数
7
+ /**
8
+ * ✔ indicator-dots
9
+ * ✔ indicator-color
10
+ * ✔ indicator-active-color
11
+ * ✔ autoplay
12
+ * ✔ current
13
+ * ✔ interval
14
+ * ✔ duration
15
+ * ✔ circular
16
+ * ✔ vertical
17
+ * ✘ display-multiple-items
18
+ * ✔ previous-margin
19
+ * ✔ next-margin
20
+ * ✘ snap-to-edge
21
+ */
22
+ const _SwiperWrapper = forwardRef<HandlerRef<ScrollView, SwiperProps>, SwiperProps>((props: SwiperProps, ref): React.JSX.Element => {
23
+ const { children } = props
24
+ let innerLayout = useRef({})
25
+ const swiperProp = {
26
+ circular: props.circular || false,
27
+ current: props.current || 0,
28
+ autoplay: props.autoplay || false,
29
+ duration: props.duration || 500,
30
+ interval: props.interval || 5000,
31
+ showsPagination: props['indicator-dots'],
32
+ dotColor: props['indicator-color'] || "rgba(0, 0, 0, .3)",
33
+ activeDotColor: props['indicator-active-color'] || '#000000',
34
+ horizontal: props.vertical !== undefined ? !props.vertical : true,
35
+ style: props.style,
36
+ previousMargin: props['previous-margin'] ? parseInt(props['previous-margin']) : 0,
37
+ nextMargin: props['next-margin'] ? parseInt(props['next-margin']) : 0,
38
+ enableOffset: props['enable-offset'] || false,
39
+ bindchange: props.bindchange
40
+ }
41
+ const { nodeRef } = useNodesRef<ScrollView, SwiperProps>(props, ref, {
42
+ })
43
+ const innerProps = useInnerProps(props, {
44
+ ref: nodeRef
45
+ }, [
46
+ 'indicator-dots',
47
+ 'indicator-color',
48
+ 'indicator-active-color',
49
+ 'previous-margin',
50
+ 'next-margin'
51
+ ], { layoutRef: innerLayout })
52
+
53
+ const getInnerLayout = (layout: React.MutableRefObject<{}>) => {
54
+ innerLayout.current = layout.current
55
+ }
56
+
57
+ return <Carouse
58
+ getInnerLayout={getInnerLayout}
59
+ innerProps={innerProps}
60
+ {...swiperProp}
61
+ {...innerProps}>
62
+ {children}
63
+ </Carouse>
64
+
65
+ })
66
+ _SwiperWrapper.displayName = 'mpx-swiper';
67
+
68
+ export default _SwiperWrapper
@@ -0,0 +1,69 @@
1
+ import { ReactNode } from 'react'
2
+ import { NativeSyntheticEvent } from 'react-native'
3
+ export interface SwiperProps {
4
+ children?: ReactNode;
5
+ circular?: boolean;
6
+ current?: number;
7
+ interval?: number;
8
+ autoplay?: boolean;
9
+ duration?: number;
10
+ 'indicator-dots'?: boolean;
11
+ 'indicator-color'?: string;
12
+ 'indicator-active-color'?: string;
13
+ vertical?: boolean;
14
+ style?: string;
15
+ easingFunction?: string;
16
+ 'previous-margin'?: string;
17
+ 'next-margin'?: string;
18
+ 'enable-offset'?: boolean;
19
+ bindchange?: (event: NativeSyntheticEvent<TouchEvent> | unknown) => void;
20
+ }
21
+
22
+ export interface CarouseProps {
23
+ children?: ReactNode;
24
+ circular?: boolean;
25
+ current: number;
26
+ autoplay?: boolean;
27
+ duration?: number;
28
+ interval?: number;
29
+ showsPagination?: boolean;
30
+ dotColor?: string;
31
+ activeDotColor?: string;
32
+ horizontal?: boolean;
33
+ style?: string;
34
+ easingFunction?: string;
35
+ previousMargin?: number;
36
+ nextMargin?: number;
37
+ enableOffset?: boolean;
38
+ bindchange?: (event: NativeSyntheticEvent<TouchEvent> | unknown) => void;
39
+ getInnerLayout: Function,
40
+ innerProps: Object;
41
+ }
42
+
43
+ export interface CarouseState {
44
+ children: Array<ReactNode> | ReactNode,
45
+ width: number;
46
+ height: number;
47
+ index: number;
48
+ total: number;
49
+ // 设置scrollView初始的滚动坐标,contentOffset
50
+ offset: {
51
+ x: number,
52
+ y: number
53
+ };
54
+ // 是否结束自动轮播,手动设置滚动到具体位置时结束
55
+ autoplayEnd: boolean;
56
+ loopJump: boolean;
57
+ dir: 'x' | 'y';
58
+ }
59
+
60
+ export interface ScrollElementProps {
61
+ pagingEnabled: boolean,
62
+ showsHorizontalScrollIndicator: boolean,
63
+ showsVerticalScrollIndicator: boolean,
64
+ bounces: boolean,
65
+ scrollsToTop: boolean,
66
+ removeClippedSubviews: boolean,
67
+ automaticallyAdjustContentInsets: boolean,
68
+ horizontal: boolean
69
+ }
@@ -0,0 +1,42 @@
1
+ import { View } from 'react-native'
2
+ import React, { forwardRef, useRef } from 'react'
3
+ import useInnerProps from './getInnerListeners'
4
+ import useNodesRef, { HandlerRef } from '../../useNodesRef' // 引入辅助函数
5
+
6
+ interface SwiperItemProps {
7
+ 'item-id'?: string;
8
+ 'enable-offset'?: boolean;
9
+ children?: React.ReactNode;
10
+ }
11
+
12
+ const _SwiperItem = forwardRef<HandlerRef<View, SwiperItemProps>, SwiperItemProps>((props: SwiperItemProps, ref) => {
13
+ const { children, 'enable-offset': enableOffset } = props
14
+ const layoutRef = useRef({})
15
+ const { nodeRef } = useNodesRef(props, ref, {})
16
+
17
+ const onLayout = () => {
18
+ nodeRef.current?.measure((x: number, y: number, width: number, height: number, offsetLeft: number, offsetTop: number) => {
19
+ layoutRef.current = { x, y, width, height, offsetLeft, offsetTop }
20
+ })
21
+ }
22
+
23
+ const innerProps = useInnerProps(props, {
24
+ ...(enableOffset ? { onLayout } : {}),
25
+ }, [
26
+ 'children',
27
+ 'enable-offset'
28
+ ], { layoutRef })
29
+
30
+ return (
31
+ <View
32
+ ref={nodeRef}
33
+ data-itemId={props['item-id']}
34
+ {...innerProps}>
35
+ {children}
36
+ </View>
37
+ )
38
+ })
39
+
40
+ _SwiperItem.displayName = 'mpx-swiper-item';
41
+
42
+ export default _SwiperItem
@@ -0,0 +1,106 @@
1
+
2
+ /**
3
+ * ✔ selectable
4
+ * ✘ space
5
+ * ✘ decode
6
+ */
7
+ import { Text, TextStyle, TextProps, StyleSheet } from 'react-native'
8
+ import { useRef, useEffect, forwardRef, ReactNode, ForwardedRef, JSX } from 'react';
9
+ import useInnerProps from './getInnerListeners'
10
+ // @ts-ignore
11
+ import useNodesRef, { HandlerRef } from '../../useNodesRef' // 引入辅助函数
12
+ import { PERCENT_REGX } from './utils'
13
+
14
+
15
+ interface _TextProps extends TextProps {
16
+ style?: TextStyle
17
+ children?: ReactNode
18
+ selectable?: boolean
19
+ 'enable-offset'?: boolean
20
+ 'user-select'?: boolean
21
+ userSelect?: boolean
22
+ ['disable-default-style']?: boolean
23
+ }
24
+
25
+ const DEFAULT_STYLE = {
26
+ fontSize: 16
27
+ }
28
+
29
+ const transformStyle = (styleObj: TextStyle) => {
30
+ let { lineHeight } = styleObj
31
+ if (typeof lineHeight === 'string' && PERCENT_REGX.test(lineHeight)) {
32
+ lineHeight = (parseFloat(lineHeight)/100) * (styleObj.fontSize || DEFAULT_STYLE.fontSize)
33
+ styleObj.lineHeight = lineHeight
34
+ }
35
+ }
36
+
37
+ const _Text = forwardRef<HandlerRef<Text, _TextProps>, _TextProps>((props, ref): JSX.Element => {
38
+ const {
39
+ style = [],
40
+ children,
41
+ selectable,
42
+ 'enable-offset': enableOffset,
43
+ 'user-select': userSelect,
44
+ 'disable-default-style': disableDefaultStyle = false,
45
+ } = props
46
+
47
+ const layoutRef = useRef({})
48
+
49
+ const styleObj: TextStyle = StyleSheet.flatten<TextStyle>(style)
50
+
51
+ let defaultStyle = {}
52
+
53
+ if (!disableDefaultStyle) {
54
+ defaultStyle = DEFAULT_STYLE
55
+ transformStyle(styleObj)
56
+ }
57
+
58
+ const { nodeRef } = useNodesRef<Text, _TextProps>(props, ref, {
59
+ defaultStyle
60
+ })
61
+
62
+ const innerProps = useInnerProps(props, {
63
+ ref: nodeRef
64
+ }, [
65
+ 'style',
66
+ 'children',
67
+ 'selectable',
68
+ 'user-select',
69
+ 'useInherit',
70
+ 'enable-offset'
71
+ ], {
72
+ layoutRef
73
+ })
74
+
75
+ useEffect(() => {
76
+ let measureTimeout: ReturnType<typeof setTimeout> | null = null
77
+ if (enableOffset) {
78
+ measureTimeout = setTimeout(() => {
79
+ nodeRef.current?.measure((x: number, y: number, width: number, height: number, offsetLeft: number, offsetTop: number) => {
80
+ layoutRef.current = { x, y, width, height, offsetLeft, offsetTop }
81
+ })
82
+ })
83
+ return () => {
84
+ if (measureTimeout) {
85
+ clearTimeout(measureTimeout)
86
+ measureTimeout = null
87
+ }
88
+ }
89
+ }
90
+ }, [])
91
+
92
+
93
+ return (
94
+ <Text
95
+ style={{...defaultStyle, ...styleObj}}
96
+ selectable={!!selectable || !!userSelect}
97
+ {...innerProps}
98
+ >
99
+ {children}
100
+ </Text>
101
+ )
102
+ })
103
+
104
+ _Text.displayName = 'mpx-text'
105
+
106
+ export default _Text