@mpxjs/webpack-plugin 2.10.7 → 2.10.8-beta.3

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 (138) hide show
  1. package/lib/dependencies/RecordPageConfigsMapDependency.js +1 -1
  2. package/lib/dependencies/RequireExternalDependency.js +61 -0
  3. package/lib/file-loader.js +3 -2
  4. package/lib/index.js +55 -9
  5. package/lib/json-compiler/index.js +1 -0
  6. package/lib/parser.js +1 -1
  7. package/lib/platform/json/wx/index.js +43 -25
  8. package/lib/platform/style/wx/index.js +7 -0
  9. package/lib/platform/template/wx/component-config/fix-component-name.js +2 -2
  10. package/lib/platform/template/wx/component-config/index.js +9 -1
  11. package/lib/platform/template/wx/component-config/nav-container.js +27 -0
  12. package/lib/platform/template/wx/component-config/page-container.js +19 -0
  13. package/lib/platform/template/wx/component-config/sticky-header.js +23 -0
  14. package/lib/platform/template/wx/component-config/sticky-section.js +23 -0
  15. package/lib/platform/template/wx/component-config/unsupported.js +1 -1
  16. package/lib/react/LoadAsyncChunkModule.js +74 -0
  17. package/lib/react/index.js +3 -1
  18. package/lib/react/processJSON.js +74 -13
  19. package/lib/react/processScript.js +6 -6
  20. package/lib/react/script-helper.js +100 -41
  21. package/lib/runtime/components/ali/mpx-nav-container.mpx +3 -0
  22. package/lib/runtime/components/react/context.ts +27 -7
  23. package/lib/runtime/components/react/dist/context.d.ts +78 -0
  24. package/lib/runtime/components/react/dist/context.js +5 -1
  25. package/lib/runtime/components/react/dist/event.config.d.ts +7 -0
  26. package/lib/runtime/components/react/dist/getInnerListeners.d.ts +7 -0
  27. package/lib/runtime/components/react/dist/mpx-async-suspense.d.ts +12 -0
  28. package/lib/runtime/components/react/dist/mpx-async-suspense.jsx +135 -0
  29. package/lib/runtime/components/react/dist/mpx-button.d.ts +68 -0
  30. package/lib/runtime/components/react/dist/mpx-button.jsx +2 -2
  31. package/lib/runtime/components/react/dist/mpx-canvas/Bus.d.ts +23 -0
  32. package/lib/runtime/components/react/dist/mpx-canvas/CanvasGradient.d.ts +7 -0
  33. package/lib/runtime/components/react/dist/mpx-canvas/CanvasRenderingContext2D.d.ts +6 -0
  34. package/lib/runtime/components/react/dist/mpx-canvas/Image.d.ts +20 -0
  35. package/lib/runtime/components/react/dist/mpx-canvas/ImageData.d.ts +8 -0
  36. package/lib/runtime/components/react/dist/mpx-canvas/constructorsRegistry.d.ts +10 -0
  37. package/lib/runtime/components/react/dist/mpx-canvas/html.d.ts +2 -0
  38. package/lib/runtime/components/react/dist/mpx-canvas/index.d.ts +32 -0
  39. package/lib/runtime/components/react/dist/mpx-canvas/utils.d.ts +52 -0
  40. package/lib/runtime/components/react/dist/mpx-checkbox-group.d.ts +20 -0
  41. package/lib/runtime/components/react/dist/mpx-checkbox.d.ts +32 -0
  42. package/lib/runtime/components/react/dist/mpx-form.d.ts +27 -0
  43. package/lib/runtime/components/react/dist/mpx-icon/index.d.ts +18 -0
  44. package/lib/runtime/components/react/dist/mpx-image.d.ts +21 -0
  45. package/lib/runtime/components/react/dist/mpx-inline-text.d.ts +7 -0
  46. package/lib/runtime/components/react/dist/mpx-input.d.ts +49 -0
  47. package/lib/runtime/components/react/dist/mpx-input.jsx +28 -9
  48. package/lib/runtime/components/react/dist/mpx-keyboard-avoiding-view.d.ts +12 -0
  49. package/lib/runtime/components/react/dist/mpx-keyboard-avoiding-view.jsx +42 -46
  50. package/lib/runtime/components/react/dist/mpx-label.d.ts +20 -0
  51. package/lib/runtime/components/react/dist/mpx-movable-area.d.ts +20 -0
  52. package/lib/runtime/components/react/dist/mpx-movable-view.d.ts +63 -0
  53. package/lib/runtime/components/react/dist/mpx-movable-view.jsx +8 -6
  54. package/lib/runtime/components/react/dist/mpx-nav-container.d.ts +9 -0
  55. package/lib/runtime/components/react/dist/mpx-nav-container.jsx +23 -0
  56. package/lib/runtime/components/react/dist/mpx-navigator.d.ts +9 -0
  57. package/lib/runtime/components/react/dist/mpx-page-container.d.ts +27 -0
  58. package/lib/runtime/components/react/dist/mpx-page-container.jsx +255 -0
  59. package/lib/runtime/components/react/dist/mpx-picker/date.d.ts +6 -0
  60. package/lib/runtime/components/react/dist/mpx-picker/dateData.d.ts +7 -0
  61. package/lib/runtime/components/react/dist/mpx-picker/index.d.ts +6 -0
  62. package/lib/runtime/components/react/dist/mpx-picker/multiSelector.d.ts +6 -0
  63. package/lib/runtime/components/react/dist/mpx-picker/region.d.ts +6 -0
  64. package/lib/runtime/components/react/dist/mpx-picker/regionData.d.ts +2 -0
  65. package/lib/runtime/components/react/dist/mpx-picker/selector.d.ts +6 -0
  66. package/lib/runtime/components/react/dist/mpx-picker/time.d.ts +6 -0
  67. package/lib/runtime/components/react/dist/mpx-picker/type.d.ts +106 -0
  68. package/lib/runtime/components/react/dist/mpx-picker-view/index.d.ts +31 -0
  69. package/lib/runtime/components/react/dist/mpx-picker-view/pickerVIewContext.d.ts +8 -0
  70. package/lib/runtime/components/react/dist/mpx-picker-view-column/index.d.ts +22 -0
  71. package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewColumnItem.d.ts +14 -0
  72. package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewFaces.d.ts +16 -0
  73. package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewIndicator.d.ts +12 -0
  74. package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewMask.d.ts +11 -0
  75. package/lib/runtime/components/react/dist/mpx-popup/index.d.ts +22 -0
  76. package/lib/runtime/components/react/dist/mpx-popup/popupBase.d.ts +16 -0
  77. package/lib/runtime/components/react/dist/mpx-portal/index.d.ts +15 -0
  78. package/lib/runtime/components/react/dist/mpx-portal/portal-host.d.ts +29 -0
  79. package/lib/runtime/components/react/dist/mpx-portal/portal-manager.d.ts +9 -0
  80. package/lib/runtime/components/react/dist/mpx-radio-group.d.ts +20 -0
  81. package/lib/runtime/components/react/dist/mpx-radio.d.ts +26 -0
  82. package/lib/runtime/components/react/dist/mpx-rich-text/html.d.ts +1 -0
  83. package/lib/runtime/components/react/dist/mpx-rich-text/index.d.ts +24 -0
  84. package/lib/runtime/components/react/dist/mpx-root-portal.d.ts +14 -0
  85. package/lib/runtime/components/react/dist/mpx-scroll-view.d.ts +54 -0
  86. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +31 -15
  87. package/lib/runtime/components/react/dist/mpx-simple-text.d.ts +7 -0
  88. package/lib/runtime/components/react/dist/mpx-simple-view.d.ts +7 -0
  89. package/lib/runtime/components/react/dist/mpx-sticky-header.d.ts +17 -0
  90. package/lib/runtime/components/react/dist/mpx-sticky-header.jsx +117 -0
  91. package/lib/runtime/components/react/dist/mpx-sticky-section.d.ts +15 -0
  92. package/lib/runtime/components/react/dist/mpx-sticky-section.jsx +45 -0
  93. package/lib/runtime/components/react/dist/mpx-swiper-item.d.ts +18 -0
  94. package/lib/runtime/components/react/dist/mpx-swiper.d.ts +52 -0
  95. package/lib/runtime/components/react/dist/mpx-swiper.jsx +3 -2
  96. package/lib/runtime/components/react/dist/mpx-switch.d.ts +26 -0
  97. package/lib/runtime/components/react/dist/mpx-text.d.ts +21 -0
  98. package/lib/runtime/components/react/dist/mpx-textarea.d.ts +7 -0
  99. package/lib/runtime/components/react/dist/mpx-video.d.ts +101 -0
  100. package/lib/runtime/components/react/dist/mpx-view.d.ts +34 -0
  101. package/lib/runtime/components/react/dist/mpx-web-view.d.ts +22 -0
  102. package/lib/runtime/components/react/dist/nav.d.ts +11 -0
  103. package/lib/runtime/components/react/dist/nav.jsx +141 -0
  104. package/lib/runtime/components/react/dist/parser.d.ts +39 -0
  105. package/lib/runtime/components/react/dist/useAnimationHooks.d.ts +32 -0
  106. package/lib/runtime/components/react/dist/useNavShared.d.ts +2 -0
  107. package/lib/runtime/components/react/dist/useNavShared.js +6 -0
  108. package/lib/runtime/components/react/dist/useNodesRef.d.ts +11 -0
  109. package/lib/runtime/components/react/dist/utils.d.ts +121 -0
  110. package/lib/runtime/components/react/mpx-async-suspense.tsx +180 -0
  111. package/lib/runtime/components/react/mpx-button.tsx +3 -2
  112. package/lib/runtime/components/react/mpx-input.tsx +35 -16
  113. package/lib/runtime/components/react/mpx-keyboard-avoiding-view.tsx +46 -45
  114. package/lib/runtime/components/react/mpx-movable-view.tsx +8 -4
  115. package/lib/runtime/components/react/mpx-nav-container.tsx +33 -0
  116. package/lib/runtime/components/react/mpx-page-container.tsx +394 -0
  117. package/lib/runtime/components/react/mpx-scroll-view.tsx +84 -59
  118. package/lib/runtime/components/react/mpx-sticky-header.tsx +181 -0
  119. package/lib/runtime/components/react/mpx-sticky-section.tsx +96 -0
  120. package/lib/runtime/components/react/mpx-swiper.tsx +4 -2
  121. package/lib/runtime/components/react/nav.tsx +172 -0
  122. package/lib/runtime/components/react/types/common.d.ts +19 -0
  123. package/lib/runtime/components/react/useNavShared.ts +8 -0
  124. package/lib/runtime/components/web/mpx-nav-container.vue +13 -0
  125. package/lib/runtime/components/web/mpx-scroll-view.vue +18 -4
  126. package/lib/runtime/components/web/mpx-sticky-header.vue +99 -0
  127. package/lib/runtime/components/web/mpx-sticky-section.vue +15 -0
  128. package/lib/runtime/components/wx/mpx-nav-container.mpx +9 -0
  129. package/lib/runtime/optionProcessorReact.d.ts +18 -0
  130. package/lib/runtime/optionProcessorReact.js +30 -0
  131. package/lib/script-setup-compiler/index.js +27 -5
  132. package/lib/template-compiler/bind-this.js +2 -1
  133. package/lib/template-compiler/compiler.js +27 -6
  134. package/lib/utils/dom-tag-config.js +18 -4
  135. package/lib/utils/trans-async-sub-rules.js +19 -0
  136. package/lib/web/script-helper.js +1 -1
  137. package/package.json +4 -4
  138. package/LICENSE +0 -433
@@ -0,0 +1,181 @@
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
+ // harmony 需要手动设置 relative, zIndex 才生效
176
+ position: 'relative'
177
+ }
178
+ })
179
+
180
+ _StickyHeader.displayName = 'MpxStickyHeader'
181
+ 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
@@ -143,7 +143,8 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
143
143
  style = {},
144
144
  autoplay = false,
145
145
  circular = false,
146
- disableGesture = false
146
+ disableGesture = false,
147
+ bindchange
147
148
  } = props
148
149
  const easeingFunc = props['easing-function'] || 'default'
149
150
  const easeDuration = props.duration || 500
@@ -428,6 +429,7 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
428
429
  if (props.current !== currentIndex.value) {
429
430
  const eventData = getCustomEvent('change', {}, { detail: { current, source: 'touch' }, layoutRef: layoutRef })
430
431
  props.bindchange && props.bindchange(eventData)
432
+ bindchange && bindchange(eventData)
431
433
  }
432
434
  }
433
435
 
@@ -469,7 +471,7 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
469
471
  // 1. 用户在当前页切换选中项,动画;用户携带选中index打开到swiper页直接选中不走动画
470
472
  useAnimatedReaction(() => currentIndex.value, (newIndex: number, preIndex: number) => {
471
473
  // 这里必须传递函数名, 直接写()=> {}形式会报 访问了未sharedValue信息
472
- if (newIndex !== preIndex && props.bindchange) {
474
+ if (newIndex !== preIndex && bindchange) {
473
475
  runOnJS(handleSwiperChange)(newIndex)
474
476
  }
475
477
  })
@@ -0,0 +1,172 @@
1
+ /* eslint-disable space-before-function-paren */
2
+ import { createElement, useState, useMemo, memo, useContext, useLayoutEffect } from 'react'
3
+ import { useSafeAreaInsets } from 'react-native-safe-area-context'
4
+ import { StatusBar, processColor, TouchableWithoutFeedback, Image, View, StyleSheet, Text } from 'react-native'
5
+ import { useNavShared } from './useNavShared'
6
+
7
+ function convertToHex(color?: string) {
8
+ try {
9
+ const intColor = processColor(color) as number | null | undefined
10
+ if (intColor === null || intColor === undefined) {
11
+ return null
12
+ }
13
+ // 将32位整数颜色值转换为RGBA
14
+ const r = (intColor >> 16) & 255
15
+ const g = (intColor >> 8) & 255
16
+ const b = intColor & 255
17
+ // 转换为十六进制
18
+ const hexR = r.toString(16).padStart(2, '0')
19
+ const hexG = g.toString(16).padStart(2, '0')
20
+ const hexB = b.toString(16).padStart(2, '0')
21
+ return `#${hexR}${hexG}${hexB}`
22
+ } catch (error) {
23
+ return null
24
+ }
25
+ }
26
+
27
+ const titleHeight = 44
28
+ export function useInnerHeaderHeight(pageConfig: PageConfig) {
29
+ const safeArea = useSafeAreaInsets()
30
+ if (pageConfig.navigationStyle === 'custom') {
31
+ return 0
32
+ } else {
33
+ const safeAreaTop = safeArea?.top || 0
34
+ const headerHeight = safeAreaTop + titleHeight
35
+ return headerHeight
36
+ }
37
+ }
38
+
39
+ const styles = StyleSheet.create({
40
+ header: {
41
+ elevation: 3
42
+ },
43
+ headerContent: {
44
+ flexDirection: 'row',
45
+ alignItems: 'center',
46
+ justifyContent: 'center'
47
+ },
48
+ backButton: {
49
+ position: 'absolute',
50
+ height: '100%',
51
+ width: 40,
52
+ left: 0,
53
+ top: 0,
54
+ alignItems: 'center',
55
+ justifyContent: 'center'
56
+ },
57
+ backButtonImage: {
58
+ width: 22,
59
+ height: 22
60
+ },
61
+ title: {
62
+ fontSize: 17,
63
+ fontWeight: 600,
64
+ width: '60%',
65
+ textAlign: 'center'
66
+ }
67
+ })
68
+ const NavColor = {
69
+ White: '#ffffff',
70
+ Black: '#000000'
71
+ }
72
+ // navigationBarTextStyle 只支持黑白 'white'/'black
73
+ const validBarTextStyle = (textStyle?: string) => {
74
+ const textStyleColor = convertToHex(textStyle)
75
+ if (textStyle && textStyleColor && [NavColor.White, NavColor.Black].includes(textStyleColor)) {
76
+ return textStyleColor
77
+ } else {
78
+ return NavColor.White
79
+ }
80
+ }
81
+
82
+ export interface MpxNavProps {
83
+ pageConfig: PageConfig
84
+ navigation: any
85
+ }
86
+
87
+ export interface MpxNavFactorOptions {
88
+ Mpx: any
89
+ }
90
+
91
+ const BACK_ICON =
92
+ 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAABICAYAAACqT5alAAAA2UlEQVR4nO3bMQrCUBRE0Yla6AYEN2nnBrTL+izcitW3MRDkEUWSvPzJvfCqgMwhZbAppWhNbbIHzB1g9wATERFRVyvpkj1irlpJ5X326D7WHh1hbdFD2CLpLmmftm7kfsEe09aNHFiBrT+wAlt/YAW2/sAKbP2BFdj6Ayuwy+ufz6XPL893krZ//O6iu2n4LT8kndLWTRTo4EC7BDo40C6BDg60S6CDA+0S6OBAuwQ6uNWiD2nrJmoIfU7cNWkR2hbb1UfbY7uuWhGWiIg+a/iHuHmA3QPs3gu4JW9Gan+OJAAAAABJRU5ErkJggg=='
93
+
94
+ function createMpxNav(options: MpxNavFactorOptions) {
95
+ const { Mpx } = options
96
+ const innerNav = memo(({ pageConfig, navigation }: MpxNavProps) => {
97
+ const [innerPageConfig, setPageConfig] = useState<PageConfig>(pageConfig || {})
98
+ const [customNav] = useNavShared()
99
+ const safeAreaTop = useSafeAreaInsets()?.top || 0
100
+
101
+ navigation.setPageConfig = (config: PageConfig) => {
102
+ setPageConfig(Object.assign({}, innerPageConfig, config))
103
+ }
104
+ const isCustom = innerPageConfig.navigationStyle === 'custom'
105
+ const navigationBarTextStyle = useMemo(() => validBarTextStyle(innerPageConfig.navigationBarTextStyle), [innerPageConfig.navigationBarTextStyle])
106
+ // 状态栏的颜色
107
+ const statusBarElement = (
108
+ <StatusBar
109
+ translucent
110
+ backgroundColor='transparent'
111
+ barStyle={navigationBarTextStyle === NavColor.White ? 'light-content' : 'dark-content'}></StatusBar>
112
+ )
113
+
114
+ if (isCustom)
115
+ return (
116
+ <>
117
+ {statusBarElement}
118
+ {customNav}
119
+ </>
120
+ )
121
+ // 假设是栈导航,获取栈的长度
122
+ const stackLength = navigation.getState()?.routes?.length
123
+ const onStackTopBack = Mpx.config?.rnConfig?.onStackTopBack
124
+ const isHandleStackTopBack = typeof onStackTopBack === 'function'
125
+
126
+ // 回退按钮与图标
127
+ // prettier-ignore
128
+ const backElement = stackLength > 1 || isHandleStackTopBack
129
+ ? (
130
+ <TouchableWithoutFeedback
131
+ onPress={() => {
132
+ if (stackLength <= 1 && isHandleStackTopBack) {
133
+ onStackTopBack()
134
+ return
135
+ }
136
+ navigation.goBack()
137
+ }}>
138
+ <View style={[styles.backButton]}>
139
+ <Image style={[styles.backButtonImage, { tintColor: navigationBarTextStyle }]} source={{ uri: BACK_ICON }}></Image>
140
+ </View>
141
+ </TouchableWithoutFeedback>
142
+ )
143
+ : null
144
+
145
+ return (
146
+ <View
147
+ style={[
148
+ styles.header,
149
+ {
150
+ paddingTop: safeAreaTop,
151
+ backgroundColor: innerPageConfig.navigationBarBackgroundColor || '#000000'
152
+ }
153
+ ]}>
154
+ {statusBarElement}
155
+ {/* TODO: 确定 height 的有效性 */}
156
+ {/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */}
157
+ {/* @ts-expect-error */}
158
+ <View style={styles.headerContent} height={titleHeight}>
159
+ {backElement}
160
+ <Text style={[styles.title, { color: navigationBarTextStyle }]} numberOfLines={1}>
161
+ {innerPageConfig.navigationBarTitleText?.trim() || ''}
162
+ </Text>
163
+ </View>
164
+ </View>
165
+ )
166
+ })
167
+
168
+ innerNav.displayName = 'MpxNav'
169
+ return innerNav
170
+ }
171
+
172
+ export default createMpxNav
@@ -18,3 +18,22 @@ export type ExtendedFunctionComponent = FunctionComponent & {
18
18
  }
19
19
 
20
20
  export type AnyFunc = (...args: ReadonlyArray<any>) => any
21
+
22
+ declare global {
23
+ interface PageConfig {
24
+ /**
25
+ * 是否自定义导航栏
26
+ */
27
+ navigationStyle?: 'custom'
28
+ /**
29
+ * 标题栏样式
30
+ */
31
+ navigationBarTextStyle?: 'white' | 'black' | '#ffffff' | '#000000'
32
+ /**
33
+ * 页面标题
34
+ */
35
+ navigationBarTitleText?: string
36
+
37
+ [key: string]: any
38
+ }
39
+ }
@@ -0,0 +1,8 @@
1
+ import { useContext } from 'react'
2
+ import { NavSharedContext } from './context'
3
+
4
+ export function useNavShared () {
5
+ const navSharedValue = useContext(NavSharedContext)
6
+
7
+ return [navSharedValue.customNav, navSharedValue.setCustomNav] as const
8
+ }
@@ -0,0 +1,13 @@
1
+ <script>
2
+ export default {
3
+ name: 'mpx-view',
4
+ data() {
5
+ return {}
6
+ },
7
+ props: {},
8
+ render() {
9
+ return this.$slots.default
10
+ },
11
+ methods: {}
12
+ }
13
+ </script>
@@ -1,4 +1,5 @@
1
1
  <script>
2
+ import { computed } from 'vue'
2
3
  import getInnerListeners, { getCustomEvent } from './getInnerListeners'
3
4
  import { processSize } from '../../utils'
4
5
  import BScroll from '@better-scroll/core'
@@ -44,6 +45,7 @@
44
45
  enhanced: Boolean,
45
46
  refresherEnabled: Boolean,
46
47
  refresherTriggered: Boolean,
48
+ enableSticky: Boolean,
47
49
  refresherThreshold: {
48
50
  type: Number,
49
51
  default: 45
@@ -57,6 +59,12 @@
57
59
  default: ''
58
60
  }
59
61
  },
62
+ provide () {
63
+ return {
64
+ scrollOffset: computed(() => -this.lastY || 0),
65
+ refreshVersion: computed(() => this.refreshVersion || 0)
66
+ }
67
+ },
60
68
  data () {
61
69
  return {
62
70
  isLoading: false,
@@ -68,7 +76,8 @@
68
76
  lastContentWidth: 0,
69
77
  lastContentHeight: 0,
70
78
  lastWrapperWidth: 0,
71
- lastWrapperHeight: 0
79
+ lastWrapperHeight: 0,
80
+ refreshVersion: 0
72
81
  }
73
82
  },
74
83
  computed: {
@@ -222,6 +231,9 @@
222
231
  stop: 56
223
232
  }
224
233
  }
234
+ if(this.enableSticky) {
235
+ originBsOptions.useTransition = false
236
+ }
225
237
  const bsOptions = Object.assign({}, originBsOptions, this.scrollOptions, { observeDOM: false })
226
238
  this.bs = new BScroll(this.$refs.wrapper, bsOptions)
227
239
  this.lastX = -this.currentX
@@ -251,7 +263,7 @@
251
263
  }
252
264
  this.lastX = x
253
265
  this.lastY = y
254
- }, 30, {
266
+ }, this.enableSticky ? 0 : 30, {
255
267
  leading: true,
256
268
  trailing: true
257
269
  }))
@@ -392,6 +404,7 @@
392
404
  this.lastContentHeight = scrollContentHeight
393
405
  this.lastWrapperWidth = scrollWrapperWidth
394
406
  this.lastWrapperHeight = scrollWrapperHeight
407
+ this.refreshVersion++
395
408
  if (this.bs) this.bs.refresh()
396
409
  }
397
410
  },
@@ -458,7 +471,8 @@
458
471
  }
459
472
 
460
473
  const innerWrapper = createElement('div', {
461
- ref: 'innerWrapper'
474
+ ref: 'innerWrapper',
475
+ class: 'mpx-inner-wrapper'
462
476
  }, this.$slots.default)
463
477
 
464
478
  const pullDownContent = this.refresherDefaultStyle !== 'none' ? createElement('div', {
@@ -568,4 +582,4 @@
568
582
  background: rgba(255, 255, 255, .7)
569
583
  100%
570
584
  background: rgba(255, 255, 255, .3)
571
- </style>
585
+ </style>
@@ -0,0 +1,99 @@
1
+ <script>
2
+ import { warn } from '@mpxjs/utils'
3
+ import { getCustomEvent } from './getInnerListeners'
4
+
5
+ export default {
6
+ name: 'mpx-sticky-header',
7
+ inject: ['scrollOffset', 'refreshVersion'],
8
+ props: {
9
+ offsetTop: {
10
+ type: Number,
11
+ default: 0
12
+ },
13
+ padding: Array
14
+ },
15
+ data() {
16
+ return {
17
+ headerTop: 0,
18
+ isStickOnTop: false
19
+ }
20
+ },
21
+ watch: {
22
+ scrollOffset: {
23
+ handler(newScrollOffset) {
24
+ const newIsStickOnTop = newScrollOffset > this.headerTop
25
+ if (newIsStickOnTop !== this.isStickOnTop) {
26
+ this.isStickOnTop = newIsStickOnTop
27
+ this.$emit('stickontopchange', getCustomEvent('stickontopchange', {
28
+ isStickOnTop: newIsStickOnTop
29
+ }, this))
30
+ }
31
+
32
+ this.setTransformStyle()
33
+ },
34
+ immediate: true
35
+ },
36
+ refreshVersion: {
37
+ handler() {
38
+ this.setHeaderTop()
39
+ this.setTransformStyle()
40
+ },
41
+ }
42
+ },
43
+ mounted() {
44
+ this.setPaddingStyle()
45
+ this.setHeaderTop()
46
+ },
47
+ methods: {
48
+ setHeaderTop () {
49
+ const parentElement = this.$el.parentElement
50
+ if (!parentElement) return
51
+
52
+ const parentClass = parentElement.className || ''
53
+ const isStickySection = /mpx-sticky-section/.test(parentClass)
54
+ const isScrollViewWrapper = /mpx-inner-wrapper/.test(parentClass)
55
+
56
+ if (!isStickySection && !isScrollViewWrapper) {
57
+ warn('sticky-header only supports being a direct child of a scroll-view or sticky-section component.')
58
+ return
59
+ }
60
+ this.headerTop = isStickySection
61
+ ? this.$el.offsetTop + parentElement.offsetTop
62
+ : this.$el.offsetTop
63
+ },
64
+ setPaddingStyle() {
65
+ const stickyHeader = this.$refs.stickyHeader
66
+ if (!stickyHeader) return
67
+
68
+ if (this.padding && Array.isArray(this.padding)) {
69
+ const [top = 0, right = 0, bottom = 0, left = 0] = this.padding
70
+ stickyHeader.style.padding = `${top}px ${right}px ${bottom}px ${left}px`
71
+ }
72
+ },
73
+ setTransformStyle () {
74
+ const stickyHeader = this.$refs.stickyHeader
75
+ if (!stickyHeader) return
76
+
77
+ // 设置 transform
78
+ if (this.scrollOffset > this.headerTop) {
79
+ stickyHeader.style.transform = `translateY(${this.scrollOffset - this.headerTop + this.offsetTop}px)`
80
+ } else {
81
+ stickyHeader.style.transform = 'none'
82
+ }
83
+ }
84
+ },
85
+ render(h) {
86
+ const style = {
87
+ width: '100%',
88
+ boxSizing: 'border-box',
89
+ position: 'relative',
90
+ zIndex: 10
91
+ }
92
+
93
+ return h('div', {
94
+ style,
95
+ ref: 'stickyHeader'
96
+ }, this.$slots.default)
97
+ }
98
+ }
99
+ </script>