@mpxjs/webpack-plugin 2.10.4-beta.2 → 2.10.4-beta.20

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 (88) hide show
  1. package/lib/parser.js +1 -1
  2. package/lib/platform/json/wx/index.js +0 -1
  3. package/lib/platform/style/wx/index.js +22 -21
  4. package/lib/platform/template/wx/component-config/button.js +1 -1
  5. package/lib/platform/template/wx/component-config/index.js +5 -1
  6. package/lib/platform/template/wx/component-config/input.js +1 -1
  7. package/lib/platform/template/wx/component-config/sticky-header.js +23 -0
  8. package/lib/platform/template/wx/component-config/sticky-section.js +23 -0
  9. package/lib/react/processJSON.js +7 -6
  10. package/lib/runtime/components/react/context.ts +12 -3
  11. package/lib/runtime/components/react/dist/context.js +4 -1
  12. package/lib/runtime/components/react/dist/event.config.js +0 -2
  13. package/lib/runtime/components/react/dist/getInnerListeners.js +127 -153
  14. package/lib/runtime/components/react/dist/mpx-button.jsx +4 -5
  15. package/lib/runtime/components/react/dist/mpx-canvas/index.jsx +3 -4
  16. package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +2 -2
  17. package/lib/runtime/components/react/dist/mpx-checkbox.jsx +2 -3
  18. package/lib/runtime/components/react/dist/mpx-form.jsx +2 -2
  19. package/lib/runtime/components/react/dist/mpx-icon/index.jsx +2 -2
  20. package/lib/runtime/components/react/dist/mpx-image.jsx +2 -2
  21. package/lib/runtime/components/react/dist/mpx-input.jsx +8 -5
  22. package/lib/runtime/components/react/dist/mpx-keyboard-avoiding-view.jsx +23 -30
  23. package/lib/runtime/components/react/dist/mpx-label.jsx +2 -3
  24. package/lib/runtime/components/react/dist/mpx-movable-area.jsx +2 -2
  25. package/lib/runtime/components/react/dist/mpx-movable-view.jsx +1 -1
  26. package/lib/runtime/components/react/dist/mpx-navigator.jsx +11 -3
  27. package/lib/runtime/components/react/dist/mpx-picker/index.jsx +2 -2
  28. package/lib/runtime/components/react/dist/mpx-picker-view/index.jsx +2 -3
  29. package/lib/runtime/components/react/dist/mpx-picker-view-column/index.jsx +3 -3
  30. package/lib/runtime/components/react/dist/mpx-radio-group.jsx +2 -2
  31. package/lib/runtime/components/react/dist/mpx-radio.jsx +2 -3
  32. package/lib/runtime/components/react/dist/mpx-rich-text/index.jsx +2 -2
  33. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +32 -16
  34. package/lib/runtime/components/react/dist/mpx-simple-text.jsx +3 -2
  35. package/lib/runtime/components/react/dist/mpx-simple-view.jsx +3 -3
  36. package/lib/runtime/components/react/dist/mpx-sticky-header.jsx +115 -0
  37. package/lib/runtime/components/react/dist/mpx-sticky-section.jsx +45 -0
  38. package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +5 -6
  39. package/lib/runtime/components/react/dist/mpx-swiper.jsx +99 -37
  40. package/lib/runtime/components/react/dist/mpx-switch.jsx +3 -5
  41. package/lib/runtime/components/react/dist/mpx-text.jsx +4 -7
  42. package/lib/runtime/components/react/dist/mpx-video.jsx +2 -2
  43. package/lib/runtime/components/react/dist/mpx-view.jsx +23 -9
  44. package/lib/runtime/components/react/dist/mpx-web-view.jsx +13 -13
  45. package/lib/runtime/components/react/dist/useAnimationHooks.js +26 -4
  46. package/lib/runtime/components/react/dist/utils.jsx +12 -1
  47. package/lib/runtime/components/react/event.config.ts +1 -8
  48. package/lib/runtime/components/react/getInnerListeners.ts +146 -192
  49. package/lib/runtime/components/react/mpx-button.tsx +7 -7
  50. package/lib/runtime/components/react/mpx-canvas/index.tsx +23 -15
  51. package/lib/runtime/components/react/mpx-checkbox-group.tsx +4 -3
  52. package/lib/runtime/components/react/mpx-checkbox.tsx +8 -9
  53. package/lib/runtime/components/react/mpx-form.tsx +25 -19
  54. package/lib/runtime/components/react/mpx-icon/index.tsx +4 -3
  55. package/lib/runtime/components/react/mpx-image.tsx +4 -3
  56. package/lib/runtime/components/react/mpx-input.tsx +14 -9
  57. package/lib/runtime/components/react/mpx-keyboard-avoiding-view.tsx +31 -42
  58. package/lib/runtime/components/react/mpx-label.tsx +4 -5
  59. package/lib/runtime/components/react/mpx-movable-area.tsx +22 -13
  60. package/lib/runtime/components/react/mpx-movable-view.tsx +47 -40
  61. package/lib/runtime/components/react/mpx-navigator.tsx +4 -6
  62. package/lib/runtime/components/react/mpx-picker/index.tsx +7 -4
  63. package/lib/runtime/components/react/mpx-picker-view/index.tsx +17 -14
  64. package/lib/runtime/components/react/mpx-picker-view-column/index.tsx +3 -3
  65. package/lib/runtime/components/react/mpx-radio-group.tsx +4 -3
  66. package/lib/runtime/components/react/mpx-radio.tsx +8 -9
  67. package/lib/runtime/components/react/mpx-rich-text/index.tsx +15 -6
  68. package/lib/runtime/components/react/mpx-scroll-view.tsx +97 -66
  69. package/lib/runtime/components/react/mpx-simple-text.tsx +10 -3
  70. package/lib/runtime/components/react/mpx-simple-view.tsx +10 -4
  71. package/lib/runtime/components/react/mpx-sticky-header.tsx +179 -0
  72. package/lib/runtime/components/react/mpx-sticky-section.tsx +96 -0
  73. package/lib/runtime/components/react/mpx-swiper-item.tsx +32 -25
  74. package/lib/runtime/components/react/mpx-swiper.tsx +166 -88
  75. package/lib/runtime/components/react/mpx-switch.tsx +19 -14
  76. package/lib/runtime/components/react/mpx-text.tsx +16 -13
  77. package/lib/runtime/components/react/mpx-video.tsx +34 -33
  78. package/lib/runtime/components/react/mpx-view.tsx +41 -17
  79. package/lib/runtime/components/react/mpx-web-view.tsx +12 -12
  80. package/lib/runtime/components/react/types/getInnerListeners.d.ts +65 -35
  81. package/lib/runtime/components/react/useAnimationHooks.ts +29 -9
  82. package/lib/runtime/components/react/utils.tsx +12 -1
  83. package/lib/runtime/components/web/mpx-scroll-view.vue +21 -4
  84. package/lib/runtime/components/web/mpx-sticky-header.vue +91 -0
  85. package/lib/runtime/components/web/mpx-sticky-section.vue +15 -0
  86. package/lib/script-setup-compiler/index.js +27 -5
  87. package/lib/template-compiler/compiler.js +3 -2
  88. package/package.json +1 -1
@@ -22,9 +22,9 @@ export interface RadioProps {
22
22
  'enable-offset'?: boolean
23
23
  'enable-var'?: boolean
24
24
  'external-var-context'?: Record<string, any>
25
- 'parent-font-size'?: number;
26
- 'parent-width'?: number;
27
- 'parent-height'?: number;
25
+ 'parent-font-size'?: number
26
+ 'parent-width'?: number
27
+ 'parent-height'?: number
28
28
  children: ReactNode
29
29
  bindtap?: (evt: NativeSyntheticEvent<TouchEvent> | unknown) => void
30
30
  }
@@ -84,7 +84,7 @@ const Radio = forwardRef<HandlerRef<View, RadioProps>, RadioProps>(
84
84
  const [isChecked, setIsChecked] = useState<boolean>(!!checked)
85
85
 
86
86
  const groupContext = useContext(RadioGroupContext)
87
- let groupValue: { [key: string]: { checked: boolean; setValue: Dispatch<SetStateAction<boolean>>; } } | undefined
87
+ let groupValue: { [key: string]: { checked: boolean; setValue: Dispatch<SetStateAction<boolean>> } } | undefined
88
88
  let notifyChange: (evt: NativeSyntheticEvent<TouchEvent>) => void | undefined
89
89
 
90
90
  const labelContext = useContext(LabelContext)
@@ -149,14 +149,13 @@ const Radio = forwardRef<HandlerRef<View, RadioProps>, RadioProps>(
149
149
  }
150
150
 
151
151
  const innerProps = useInnerProps(
152
- props,
153
152
  extendObject(
154
- {
155
- ref: nodeRef,
156
- style: extendObject({}, innerStyle, layoutStyle)
157
- },
153
+ {},
154
+ props,
158
155
  layoutProps,
159
156
  {
157
+ ref: nodeRef,
158
+ style: extendObject({}, innerStyle, layoutStyle),
160
159
  bindtap: !disabled && onTap
161
160
  }
162
161
  ),
@@ -91,12 +91,21 @@ const _RichText = forwardRef<HandlerRef<View, _RichTextProps>, _RichTextProps>((
91
91
  layoutRef
92
92
  })
93
93
 
94
- const innerProps = useInnerProps(props, extendObject({
95
- ref: nodeRef,
96
- style: extendObject(normalStyle, layoutStyle)
97
- }, layoutProps), [], {
98
- layoutRef
99
- })
94
+ const innerProps = useInnerProps(
95
+ extendObject(
96
+ {},
97
+ props,
98
+ layoutProps,
99
+ {
100
+ ref: nodeRef,
101
+ style: extendObject(normalStyle, layoutStyle)
102
+ }
103
+ ),
104
+ [],
105
+ {
106
+ layoutRef
107
+ }
108
+ )
100
109
 
101
110
  const html: string = typeof nodes === 'string' ? nodes : jsonToHtmlStr(nodes)
102
111
 
@@ -32,7 +32,7 @@
32
32
  * ✔ bindscroll
33
33
  */
34
34
  import { ScrollView, RefreshControl, Gesture, GestureDetector } from 'react-native-gesture-handler'
35
- import { View, NativeSyntheticEvent, NativeScrollEvent, LayoutChangeEvent, ViewStyle } from 'react-native'
35
+ import { View, NativeSyntheticEvent, NativeScrollEvent, LayoutChangeEvent, ViewStyle, Animated as RNAnimated } from 'react-native'
36
36
  import { isValidElement, Children, JSX, ReactNode, RefObject, useRef, useState, useEffect, forwardRef, useContext, useMemo, createElement } from 'react'
37
37
  import Animated, { useAnimatedRef, useSharedValue, withTiming, useAnimatedStyle, runOnJS } from 'react-native-reanimated'
38
38
  import { warn } from '@mpxjs/utils'
@@ -46,7 +46,6 @@ interface ScrollViewProps {
46
46
  enhanced?: boolean;
47
47
  bounces?: boolean;
48
48
  style?: ViewStyle;
49
- scrollEventThrottle?: number;
50
49
  'scroll-x'?: boolean;
51
50
  'scroll-y'?: boolean;
52
51
  'enable-back-to-top'?: boolean;
@@ -70,9 +69,11 @@ interface ScrollViewProps {
70
69
  'parent-font-size'?: number;
71
70
  'parent-width'?: number;
72
71
  'parent-height'?: number;
72
+ 'enable-sticky'?: boolean;
73
73
  'wait-for'?: Array<GestureHandler>;
74
74
  'simultaneous-handlers'?: Array<GestureHandler>;
75
75
  'scroll-event-throttle'?:number;
76
+ 'scroll-into-view-offset'?: number;
76
77
  bindscrolltoupper?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
77
78
  bindscrolltolower?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
78
79
  bindscroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
@@ -87,26 +88,28 @@ interface ScrollViewProps {
87
88
  __selectRef?: (selector: string, nodeType: 'node' | 'component', all?: boolean) => HandlerRef<any, any>
88
89
  }
89
90
  type ScrollAdditionalProps = {
90
- pinchGestureEnabled: boolean;
91
- horizontal: boolean;
92
- onScroll: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
93
- onContentSizeChange: (width: number, height: number) => void;
94
- onLayout?: (event: LayoutChangeEvent) => void;
95
- scrollsToTop: boolean;
96
- showsHorizontalScrollIndicator: boolean;
97
- showsVerticalScrollIndicator: boolean;
98
- scrollEnabled: boolean;
99
- ref: RefObject<ScrollView>;
100
- bounces?: boolean;
101
- pagingEnabled?: boolean;
102
- style?: ViewStyle;
103
- bindtouchstart?: (event: NativeSyntheticEvent<TouchEvent>) => void;
104
- bindtouchmove?: (event: NativeSyntheticEvent<TouchEvent>) => void;
105
- bindtouchend?: (event: NativeSyntheticEvent<TouchEvent>) => void;
106
- onScrollBeginDrag?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
107
- onScrollEndDrag?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
108
- onMomentumScrollEnd?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
109
- };
91
+ pinchGestureEnabled: boolean
92
+ horizontal: boolean
93
+ onScroll: (event: NativeSyntheticEvent<NativeScrollEvent>) => void
94
+ onContentSizeChange: (width: number, height: number) => void
95
+ onLayout?: (event: LayoutChangeEvent) => void
96
+ scrollsToTop: boolean
97
+ showsHorizontalScrollIndicator: boolean
98
+ showsVerticalScrollIndicator: boolean
99
+ scrollEnabled: boolean
100
+ ref: RefObject<ScrollView>
101
+ bounces?: boolean
102
+ pagingEnabled?: boolean
103
+ style?: ViewStyle
104
+ bindtouchstart?: (event: NativeSyntheticEvent<TouchEvent>) => void
105
+ bindtouchmove?: (event: NativeSyntheticEvent<TouchEvent>) => void
106
+ bindtouchend?: (event: NativeSyntheticEvent<TouchEvent>) => void
107
+ onScrollBeginDrag?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void
108
+ onScrollEndDrag?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void
109
+ onMomentumScrollEnd?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void
110
+ }
111
+
112
+ const AnimatedScrollView = RNAnimated.createAnimatedComponent(ScrollView) as React.ComponentType<any>
110
113
 
111
114
  const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, ScrollViewProps>((scrollViewProps: ScrollViewProps = {}, ref): JSX.Element => {
112
115
  const { textProps, innerProps: props = {} } = splitProps(scrollViewProps)
@@ -144,10 +147,14 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
144
147
  'parent-height': parentHeight,
145
148
  'simultaneous-handlers': originSimultaneousHandlers,
146
149
  'wait-for': waitFor,
150
+ 'enable-sticky': enableSticky,
147
151
  'scroll-event-throttle': scrollEventThrottle = 0,
152
+ 'scroll-into-view-offset': scrollIntoViewOffset = 0,
148
153
  __selectRef
149
154
  } = props
150
155
 
156
+ const scrollOffset = useRef(new RNAnimated.Value(0)).current
157
+
151
158
  const simultaneousHandlers = flatGesture(originSimultaneousHandlers)
152
159
  const waitForHandlers = flatGesture(waitFor)
153
160
 
@@ -179,7 +186,7 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
179
186
  const initialTimeout = useRef<ReturnType<typeof setTimeout> | null>(null)
180
187
  const intersectionObservers = useContext(IntersectionObserverContext)
181
188
 
182
- const firstScrollIntoViewChange = useRef<boolean>(false)
189
+ const firstScrollIntoViewChange = useRef<boolean>(true)
183
190
 
184
191
  const refreshColor = {
185
192
  black: ['#000'],
@@ -211,19 +218,21 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
211
218
  pagingEnabled,
212
219
  fastDeceleration: false,
213
220
  decelerationDisabled: false,
214
- scrollTo
221
+ scrollTo,
222
+ scrollIntoView: handleScrollIntoView
215
223
  },
216
224
  gestureRef: scrollViewRef
217
225
  })
218
226
 
227
+ const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: scrollViewRef, onLayout })
228
+
219
229
  const contextValue = useMemo(() => {
220
230
  return {
221
- gestureRef: scrollViewRef
231
+ gestureRef: scrollViewRef,
232
+ scrollOffset
222
233
  }
223
234
  }, [])
224
235
 
225
- const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: scrollViewRef, onLayout })
226
-
227
236
  const hasRefresherLayoutRef = useRef(false)
228
237
 
229
238
  // layout 完成前先隐藏,避免安卓闪烁问题
@@ -249,13 +258,15 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
249
258
 
250
259
  useEffect(() => {
251
260
  if (scrollIntoView && __selectRef) {
252
- if (!firstScrollIntoViewChange.current) {
253
- setTimeout(handleScrollIntoView)
261
+ if (firstScrollIntoViewChange.current) {
262
+ setTimeout(() => {
263
+ handleScrollIntoView(scrollIntoView, { offset: scrollIntoViewOffset, animated: scrollWithAnimation })
264
+ })
254
265
  } else {
255
- handleScrollIntoView()
266
+ handleScrollIntoView(scrollIntoView, { offset: scrollIntoViewOffset, animated: scrollWithAnimation })
256
267
  }
257
268
  }
258
- firstScrollIntoViewChange.current = true
269
+ firstScrollIntoViewChange.current = false
259
270
  }, [scrollIntoView])
260
271
 
261
272
  useEffect(() => {
@@ -274,18 +285,20 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
274
285
  }
275
286
  }, [refresherTriggered])
276
287
 
277
- function scrollTo ({ top = 0, left = 0, animated = false } : { top?: number; left?: number; animated?: boolean }) {
288
+ function scrollTo ({ top = 0, left = 0, animated = false }: { top?: number; left?: number; animated?: boolean }) {
278
289
  scrollToOffset(left, top, animated)
279
290
  }
280
291
 
281
- function handleScrollIntoView () {
282
- const refs = __selectRef!(`#${scrollIntoView}`, 'node')
292
+ function handleScrollIntoView (selector = '', { offset = 0, animated = true } = {}) {
293
+ const refs = __selectRef!(`#${selector}`, 'node')
283
294
  if (!refs) return
284
295
  const { nodeRef } = refs.getNodeInstance()
285
296
  nodeRef.current?.measureLayout(
286
297
  scrollViewRef.current,
287
298
  (left: number, top: number) => {
288
- scrollToOffset(left, top)
299
+ const adjustedLeft = scrollX ? left + offset : left
300
+ const adjustedTop = scrollY ? top + offset : top
301
+ scrollToOffset(adjustedLeft, adjustedTop, animated)
289
302
  }
290
303
  )
291
304
  }
@@ -485,6 +498,16 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
485
498
  updateIntersection()
486
499
  }
487
500
 
501
+ const scrollHandler = RNAnimated.event(
502
+ [{ nativeEvent: { contentOffset: { y: scrollOffset } } }],
503
+ {
504
+ useNativeDriver: true,
505
+ listener: (event: NativeSyntheticEvent<NativeScrollEvent>) => {
506
+ onScroll(event)
507
+ }
508
+ }
509
+ )
510
+
488
511
  function onScrollDragStart (e: NativeSyntheticEvent<NativeScrollEvent>) {
489
512
  hasCallScrollToLower.current = false
490
513
  hasCallScrollToUpper.current = false
@@ -655,7 +678,7 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
655
678
  scrollEnabled: !enableScroll ? false : !!(scrollX || scrollY),
656
679
  bounces: false,
657
680
  ref: scrollViewRef,
658
- onScroll: onScroll,
681
+ onScroll: enableSticky ? scrollHandler : onScroll,
659
682
  onContentSizeChange: onContentSizeChange,
660
683
  bindtouchstart: ((enhanced && binddragstart) || bindtouchstart) && onScrollTouchStart,
661
684
  bindtouchmove: ((enhanced && binddragging) || bindtouchmove) && onScrollTouchMove,
@@ -676,39 +699,47 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
676
699
  })
677
700
  }
678
701
 
679
- const innerProps = useInnerProps(props, scrollAdditionalProps, [
680
- 'id',
681
- 'scroll-x',
682
- 'scroll-y',
683
- 'enable-back-to-top',
684
- 'enable-trigger-intersection-observer',
685
- 'paging-enabled',
686
- 'show-scrollbar',
687
- 'upper-threshold',
688
- 'lower-threshold',
689
- 'scroll-top',
690
- 'scroll-left',
691
- 'scroll-with-animation',
692
- 'refresher-triggered',
693
- 'refresher-enabled',
694
- 'refresher-default-style',
695
- 'refresher-background',
696
- 'children',
697
- 'enhanced',
698
- 'binddragstart',
699
- 'binddragging',
700
- 'binddragend',
701
- 'bindscroll',
702
- 'bindscrolltoupper',
703
- 'bindscrolltolower',
704
- 'bindrefresherrefresh'
705
- ], { layoutRef })
702
+ const innerProps = useInnerProps(
703
+ extendObject(
704
+ {},
705
+ props,
706
+ scrollAdditionalProps
707
+ ),
708
+ [
709
+ 'id',
710
+ 'scroll-x',
711
+ 'scroll-y',
712
+ 'enable-back-to-top',
713
+ 'enable-trigger-intersection-observer',
714
+ 'paging-enabled',
715
+ 'show-scrollbar',
716
+ 'upper-threshold',
717
+ 'lower-threshold',
718
+ 'scroll-top',
719
+ 'scroll-left',
720
+ 'scroll-with-animation',
721
+ 'refresher-triggered',
722
+ 'refresher-enabled',
723
+ 'refresher-default-style',
724
+ 'refresher-background',
725
+ 'children',
726
+ 'enhanced',
727
+ 'binddragstart',
728
+ 'binddragging',
729
+ 'binddragend',
730
+ 'bindscroll',
731
+ 'bindscrolltoupper',
732
+ 'bindscrolltolower',
733
+ 'bindrefresherrefresh'
734
+ ], { layoutRef })
735
+
736
+ const ScrollViewComponent = enableSticky ? AnimatedScrollView : ScrollView
706
737
 
707
738
  const withRefresherScrollView = createElement(
708
739
  GestureDetector,
709
740
  { gesture: panGesture },
710
741
  createElement(
711
- ScrollView,
742
+ ScrollViewComponent,
712
743
  innerProps,
713
744
  createElement(
714
745
  Animated.View,
@@ -736,8 +767,8 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
736
767
  )
737
768
 
738
769
  const commonScrollView = createElement(
739
- ScrollView,
740
- extendObject(innerProps, {
770
+ ScrollViewComponent,
771
+ extendObject({}, innerProps, {
741
772
  refreshControl: refresherEnabled
742
773
  ? createElement(RefreshControl, extendObject({
743
774
  progressBackgroundColor: refresherBackground,
@@ -1,6 +1,7 @@
1
1
  import { Text, TextProps } from 'react-native'
2
2
  import { JSX, createElement } from 'react'
3
3
  import useInnerProps from './getInnerListeners'
4
+ import { extendObject } from './utils'
4
5
 
5
6
  const SimpleText = (props: TextProps): JSX.Element => {
6
7
  const {
@@ -8,9 +9,15 @@ const SimpleText = (props: TextProps): JSX.Element => {
8
9
  children
9
10
  } = props
10
11
 
11
- const innerProps = useInnerProps(props, {
12
- allowFontScaling
13
- }, [])
12
+ const innerProps = useInnerProps(
13
+ extendObject(
14
+ {},
15
+ props,
16
+ {
17
+ allowFontScaling
18
+ }
19
+ )
20
+ )
14
21
 
15
22
  return createElement(Text, innerProps, children)
16
23
  }
@@ -1,6 +1,6 @@
1
1
  import { View, ViewProps, TextStyle } from 'react-native'
2
2
  import { createElement } from 'react'
3
- import { splitProps, splitStyle, wrapChildren } from './utils'
3
+ import { splitProps, splitStyle, wrapChildren, extendObject } from './utils'
4
4
  import useInnerProps from './getInnerListeners'
5
5
 
6
6
  const SimpleView = (simpleViewProps: ViewProps): JSX.Element => {
@@ -8,9 +8,15 @@ const SimpleView = (simpleViewProps: ViewProps): JSX.Element => {
8
8
 
9
9
  const { textStyle, innerStyle = {} } = splitStyle(props.style || {})
10
10
 
11
- const innerProps = useInnerProps(props, {
12
- style: innerStyle
13
- }, [])
11
+ const innerProps = useInnerProps(
12
+ extendObject(
13
+ {},
14
+ props,
15
+ {
16
+ style: innerStyle
17
+ }
18
+ )
19
+ )
14
20
 
15
21
  return createElement(View, innerProps, wrapChildren(
16
22
  props,
@@ -0,0 +1,179 @@
1
+ import { useEffect, useRef, useContext, forwardRef, useMemo, createElement, ReactNode, useId } from 'react'
2
+ import { Animated, StyleSheet, View, NativeSyntheticEvent, ViewStyle, LayoutChangeEvent, useAnimatedValue } from 'react-native'
3
+ import { ScrollViewContext, StickyContext } from './context'
4
+ import useNodesRef, { HandlerRef } from './useNodesRef'
5
+ import { splitProps, splitStyle, useTransformStyle, wrapChildren, useLayout, extendObject } from './utils'
6
+ import { error } from '@mpxjs/utils'
7
+ import useInnerProps, { getCustomEvent } from './getInnerListeners'
8
+
9
+ interface StickyHeaderProps {
10
+ children?: ReactNode;
11
+ style?: ViewStyle;
12
+ padding?: [number, number, number, number];
13
+ 'offset-top'?: number;
14
+ 'enable-var'?: boolean;
15
+ 'external-var-context'?: Record<string, any>;
16
+ 'parent-font-size'?: number;
17
+ 'parent-width'?: number;
18
+ 'parent-height'?: number;
19
+ bindstickontopchange?: (e: NativeSyntheticEvent<unknown>) => void;
20
+ }
21
+
22
+ const _StickyHeader = forwardRef<HandlerRef<View, StickyHeaderProps>, StickyHeaderProps>((stickyHeaderProps: StickyHeaderProps = {}, ref): JSX.Element => {
23
+ const { textProps, innerProps: props = {} } = splitProps(stickyHeaderProps)
24
+ const {
25
+ style,
26
+ bindstickontopchange,
27
+ padding = [0, 0, 0, 0],
28
+ 'offset-top': offsetTop = 0,
29
+ 'enable-var': enableVar,
30
+ 'external-var-context': externalVarContext,
31
+ 'parent-font-size': parentFontSize,
32
+ 'parent-width': parentWidth,
33
+ 'parent-height': parentHeight
34
+ } = props
35
+
36
+ const scrollViewContext = useContext(ScrollViewContext)
37
+ const stickyContext = useContext(StickyContext)
38
+ const { scrollOffset } = scrollViewContext
39
+ const { registerStickyHeader, unregisterStickyHeader } = stickyContext
40
+ const headerRef = useRef<View>(null)
41
+ const isStickOnTopRef = useRef(false)
42
+ const id = useId()
43
+
44
+ const {
45
+ normalStyle,
46
+ hasVarDec,
47
+ varContextRef,
48
+ hasSelfPercent,
49
+ setWidth,
50
+ setHeight
51
+ } = useTransformStyle(style, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight })
52
+
53
+ const { layoutRef, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: headerRef, onLayout })
54
+
55
+ const { textStyle, innerStyle = {} } = splitStyle(normalStyle)
56
+
57
+ const headerTopAnimated = useAnimatedValue(0)
58
+ // harmony animatedValue 不支持通过 _value 访问
59
+ const headerTopRef = useRef(0)
60
+
61
+ useEffect(() => {
62
+ registerStickyHeader({ key: id, updatePosition })
63
+ return () => {
64
+ unregisterStickyHeader(id)
65
+ }
66
+ }, [])
67
+
68
+ function updatePosition () {
69
+ if (headerRef.current) {
70
+ const scrollViewRef = scrollViewContext.gestureRef
71
+ if (scrollViewRef && scrollViewRef.current) {
72
+ headerRef.current.measureLayout(
73
+ scrollViewRef.current,
74
+ (left: number, top: number) => {
75
+ Animated.timing(headerTopAnimated, {
76
+ toValue: top,
77
+ duration: 0,
78
+ useNativeDriver: true
79
+ }).start()
80
+ headerTopRef.current = top
81
+ }
82
+ )
83
+ } else {
84
+ error('StickyHeader measureLayout error: scrollViewRef is not a valid native component reference')
85
+ }
86
+ }
87
+ }
88
+
89
+ function onLayout (e: LayoutChangeEvent) {
90
+ updatePosition()
91
+ }
92
+
93
+ useNodesRef(props, ref, headerRef, {
94
+ style: normalStyle
95
+ })
96
+
97
+ useEffect(() => {
98
+ if (!bindstickontopchange) return
99
+
100
+ const listener = scrollOffset.addListener((state: { value: number }) => {
101
+ const currentScrollValue = state.value
102
+ const newIsStickOnTop = currentScrollValue > headerTopRef.current
103
+ if (newIsStickOnTop !== isStickOnTopRef.current) {
104
+ isStickOnTopRef.current = newIsStickOnTop
105
+ bindstickontopchange(
106
+ getCustomEvent('stickontopchange', {}, {
107
+ detail: {
108
+ isStickOnTop: newIsStickOnTop
109
+ },
110
+ layoutRef
111
+ }, props))
112
+ }
113
+ })
114
+
115
+ return () => {
116
+ scrollOffset.removeListener(listener)
117
+ }
118
+ }, [])
119
+
120
+ const animatedStyle = useMemo(() => {
121
+ const translateY = Animated.subtract(scrollOffset, headerTopAnimated).interpolate({
122
+ inputRange: [0, 1],
123
+ outputRange: [0, 1],
124
+ extrapolateLeft: 'clamp',
125
+ extrapolateRight: 'extend'
126
+ })
127
+
128
+ const finalTranslateY = offsetTop === 0
129
+ ? translateY
130
+ : Animated.add(
131
+ translateY,
132
+ Animated.subtract(scrollOffset, headerTopAnimated).interpolate({
133
+ inputRange: [0, 1],
134
+ outputRange: [0, offsetTop],
135
+ extrapolate: 'clamp'
136
+ })
137
+ )
138
+
139
+ return {
140
+ transform: [{ translateY: finalTranslateY }]
141
+ }
142
+ }, [scrollOffset, headerTopAnimated, offsetTop])
143
+
144
+ const innerProps = useInnerProps(extendObject({}, props, {
145
+ ref: headerRef,
146
+ style: extendObject({}, styles.content, innerStyle, animatedStyle, {
147
+ paddingTop: padding[0] || 0,
148
+ paddingRight: padding[1] || 0,
149
+ paddingBottom: padding[2] || 0,
150
+ paddingLeft: padding[3] || 0
151
+ })
152
+ }, layoutProps), [], { layoutRef })
153
+
154
+ return (
155
+ createElement(
156
+ Animated.View,
157
+ innerProps,
158
+ wrapChildren(
159
+ props,
160
+ {
161
+ hasVarDec,
162
+ varContext: varContextRef.current,
163
+ textStyle,
164
+ textProps
165
+ }
166
+ )
167
+ )
168
+ )
169
+ })
170
+
171
+ const styles = StyleSheet.create({
172
+ content: {
173
+ width: '100%',
174
+ zIndex: 10
175
+ }
176
+ })
177
+
178
+ _StickyHeader.displayName = 'MpxStickyHeader'
179
+ export default _StickyHeader
@@ -0,0 +1,96 @@
1
+
2
+ import { useRef, forwardRef, createElement, ReactNode, useCallback, useMemo } from 'react'
3
+ import { View, ViewStyle } from 'react-native'
4
+ import useNodesRef, { HandlerRef } from './useNodesRef'
5
+ import { splitProps, splitStyle, useTransformStyle, wrapChildren, useLayout, extendObject } from './utils'
6
+ import { StickyContext } from './context'
7
+ import useInnerProps from './getInnerListeners'
8
+
9
+ interface StickySectionProps {
10
+ children?: ReactNode;
11
+ style?: ViewStyle;
12
+ 'offset-top'?: number;
13
+ 'enable-var'?: boolean;
14
+ 'external-var-context'?: Record<string, any>;
15
+ 'parent-font-size'?: number;
16
+ 'parent-width'?: number;
17
+ 'parent-height'?: number;
18
+ }
19
+
20
+ const _StickySection = forwardRef<HandlerRef<View, StickySectionProps>, StickySectionProps>((stickySectionProps: StickySectionProps = {}, ref): JSX.Element => {
21
+ const { textProps, innerProps: props = {} } = splitProps(stickySectionProps)
22
+ const {
23
+ style,
24
+ 'enable-var': enableVar,
25
+ 'external-var-context': externalVarContext,
26
+ 'parent-font-size': parentFontSize,
27
+ 'parent-width': parentWidth,
28
+ 'parent-height': parentHeight
29
+ } = props
30
+ const sectionRef = useRef<View>(null)
31
+
32
+ const {
33
+ normalStyle,
34
+ hasVarDec,
35
+ varContextRef,
36
+ hasSelfPercent,
37
+ setWidth,
38
+ setHeight
39
+ } = useTransformStyle(style, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight })
40
+
41
+ const { layoutRef, layoutProps, layoutStyle } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: sectionRef, onLayout })
42
+
43
+ const { textStyle, innerStyle = {} } = splitStyle(normalStyle)
44
+
45
+ const stickyHeaders = useRef<Map<string, any>>(new Map())
46
+
47
+ const registerStickyHeader = useCallback((item: { id: string, updatePosition: Function }) => {
48
+ stickyHeaders.current.set(item.id, item)
49
+ }, [])
50
+
51
+ const unregisterStickyHeader = useCallback((id: string) => {
52
+ stickyHeaders.current.delete(id)
53
+ }, [])
54
+
55
+ const contextValue = useMemo(() => ({
56
+ registerStickyHeader,
57
+ unregisterStickyHeader
58
+ }), [])
59
+
60
+ useNodesRef(props, ref, sectionRef, {
61
+ style: normalStyle
62
+ })
63
+
64
+ function onLayout () {
65
+ stickyHeaders.current.forEach(item => {
66
+ item.updatePosition()
67
+ })
68
+ }
69
+
70
+ const innerProps = useInnerProps(extendObject({}, props, {
71
+ style: extendObject(innerStyle, layoutStyle),
72
+ ref: sectionRef
73
+ }, layoutProps), [], { layoutRef })
74
+
75
+ return (
76
+ createElement(
77
+ View,
78
+ innerProps,
79
+ createElement(
80
+ StickyContext.Provider,
81
+ { value: contextValue },
82
+ wrapChildren(
83
+ props,
84
+ {
85
+ hasVarDec,
86
+ varContext: varContextRef.current,
87
+ textStyle,
88
+ textProps
89
+ }
90
+ )
91
+ ))
92
+ )
93
+ })
94
+
95
+ _StickySection.displayName = 'MpxStickySection'
96
+ export default _StickySection