@mpxjs/webpack-plugin 2.10.24-test.1 → 2.11.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 (128) hide show
  1. package/LICENSE +433 -0
  2. package/lib/index.js +4 -1
  3. package/lib/platform/style/wx/index.js +44 -38
  4. package/lib/platform/template/wx/component-config/picker.js +0 -6
  5. package/lib/resolver/AddEnvPlugin.js +1 -1
  6. package/lib/resolver/AddModePlugin.js +1 -1
  7. package/lib/resolver/ExtendComponentsPlugin.js +68 -0
  8. package/lib/runtime/components/extends/section-list.mpx +14 -0
  9. package/lib/runtime/components/react/dist/mpx-button.d.ts +0 -1
  10. package/lib/runtime/components/react/dist/mpx-button.jsx +2 -2
  11. package/lib/runtime/components/react/dist/mpx-camera.d.ts +0 -1
  12. package/lib/runtime/components/react/dist/mpx-camera.jsx +36 -4
  13. package/lib/runtime/components/react/dist/mpx-canvas/index.d.ts +0 -1
  14. package/lib/runtime/components/react/dist/mpx-canvas/index.jsx +1 -2
  15. package/lib/runtime/components/react/dist/mpx-checkbox-group.d.ts +0 -1
  16. package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +2 -2
  17. package/lib/runtime/components/react/dist/mpx-checkbox.d.ts +0 -1
  18. package/lib/runtime/components/react/dist/mpx-checkbox.jsx +2 -2
  19. package/lib/runtime/components/react/dist/mpx-form.d.ts +0 -1
  20. package/lib/runtime/components/react/dist/mpx-form.jsx +2 -2
  21. package/lib/runtime/components/react/dist/mpx-icon/index.d.ts +0 -1
  22. package/lib/runtime/components/react/dist/mpx-icon/index.jsx +2 -2
  23. package/lib/runtime/components/react/dist/mpx-image.d.ts +0 -1
  24. package/lib/runtime/components/react/dist/mpx-image.jsx +2 -2
  25. package/lib/runtime/components/react/dist/mpx-inline-text.jsx +13 -4
  26. package/lib/runtime/components/react/dist/mpx-input.d.ts +0 -1
  27. package/lib/runtime/components/react/dist/mpx-input.jsx +16 -8
  28. package/lib/runtime/components/react/dist/mpx-label.d.ts +0 -1
  29. package/lib/runtime/components/react/dist/mpx-label.jsx +2 -2
  30. package/lib/runtime/components/react/dist/mpx-movable-area.d.ts +0 -1
  31. package/lib/runtime/components/react/dist/mpx-movable-area.jsx +2 -2
  32. package/lib/runtime/components/react/dist/mpx-movable-view.d.ts +0 -1
  33. package/lib/runtime/components/react/dist/mpx-movable-view.jsx +2 -2
  34. package/lib/runtime/components/react/dist/mpx-nav.jsx +1 -1
  35. package/lib/runtime/components/react/dist/mpx-picker/index.jsx +72 -23
  36. package/lib/runtime/components/react/dist/mpx-picker/multiSelector.jsx +2 -2
  37. package/lib/runtime/components/react/dist/mpx-picker/type.d.ts +4 -0
  38. package/lib/runtime/components/react/dist/mpx-picker-view/index.jsx +6 -8
  39. package/lib/runtime/components/react/dist/mpx-picker-view/pickerVIewContext.d.ts +0 -2
  40. package/lib/runtime/components/react/dist/mpx-picker-view/pickerVIewContext.js +0 -5
  41. package/lib/runtime/components/react/dist/mpx-picker-view-column/index.d.ts +1 -0
  42. package/lib/runtime/components/react/dist/mpx-picker-view-column/index.jsx +34 -14
  43. package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewColumnItem.d.ts +0 -2
  44. package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewColumnItem.jsx +4 -5
  45. package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewColumnItemLite.d.ts +0 -2
  46. package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewColumnItemLite.jsx +3 -5
  47. package/lib/runtime/components/react/dist/mpx-popup/index.d.ts +5 -4
  48. package/lib/runtime/components/react/dist/mpx-popup/index.jsx +2 -2
  49. package/lib/runtime/components/react/dist/mpx-popup/popupBase.jsx +3 -2
  50. package/lib/runtime/components/react/dist/mpx-progress.d.ts +0 -1
  51. package/lib/runtime/components/react/dist/mpx-progress.jsx +1 -2
  52. package/lib/runtime/components/react/dist/mpx-radio-group.d.ts +0 -1
  53. package/lib/runtime/components/react/dist/mpx-radio-group.jsx +2 -2
  54. package/lib/runtime/components/react/dist/mpx-radio.d.ts +0 -1
  55. package/lib/runtime/components/react/dist/mpx-radio.jsx +2 -2
  56. package/lib/runtime/components/react/dist/mpx-rich-text/index.d.ts +0 -1
  57. package/lib/runtime/components/react/dist/mpx-rich-text/index.jsx +1 -2
  58. package/lib/runtime/components/react/dist/mpx-scroll-view.d.ts +0 -1
  59. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +2 -2
  60. package/lib/runtime/components/react/dist/mpx-section-list.d.ts +51 -0
  61. package/lib/runtime/components/react/dist/mpx-section-list.jsx +376 -0
  62. package/lib/runtime/components/react/dist/mpx-simple-text.jsx +27 -14
  63. package/lib/runtime/components/react/dist/mpx-simple-view.d.ts +1 -0
  64. package/lib/runtime/components/react/dist/mpx-slider.d.ts +0 -1
  65. package/lib/runtime/components/react/dist/mpx-slider.jsx +1 -2
  66. package/lib/runtime/components/react/dist/mpx-sticky-header.d.ts +0 -1
  67. package/lib/runtime/components/react/dist/mpx-sticky-header.jsx +2 -2
  68. package/lib/runtime/components/react/dist/mpx-sticky-section.d.ts +0 -1
  69. package/lib/runtime/components/react/dist/mpx-sticky-section.jsx +2 -2
  70. package/lib/runtime/components/react/dist/mpx-swiper-item.d.ts +0 -1
  71. package/lib/runtime/components/react/dist/mpx-swiper.d.ts +0 -1
  72. package/lib/runtime/components/react/dist/mpx-swiper.jsx +1 -2
  73. package/lib/runtime/components/react/dist/mpx-switch.d.ts +0 -1
  74. package/lib/runtime/components/react/dist/mpx-switch.jsx +1 -2
  75. package/lib/runtime/components/react/dist/mpx-text.d.ts +0 -1
  76. package/lib/runtime/components/react/dist/mpx-text.jsx +22 -8
  77. package/lib/runtime/components/react/dist/mpx-video.d.ts +0 -1
  78. package/lib/runtime/components/react/dist/mpx-video.jsx +1 -2
  79. package/lib/runtime/components/react/dist/mpx-view.d.ts +0 -1
  80. package/lib/runtime/components/react/dist/mpx-view.jsx +1 -2
  81. package/lib/runtime/components/react/dist/mpx-web-view.d.ts +2 -1
  82. package/lib/runtime/components/react/dist/utils.d.ts +6 -9
  83. package/lib/runtime/components/react/dist/utils.jsx +70 -84
  84. package/lib/runtime/components/react/mpx-button.tsx +1 -3
  85. package/lib/runtime/components/react/mpx-camera.tsx +40 -5
  86. package/lib/runtime/components/react/mpx-canvas/index.tsx +5 -5
  87. package/lib/runtime/components/react/mpx-checkbox-group.tsx +1 -3
  88. package/lib/runtime/components/react/mpx-checkbox.tsx +1 -3
  89. package/lib/runtime/components/react/mpx-form.tsx +1 -3
  90. package/lib/runtime/components/react/mpx-icon/index.tsx +1 -3
  91. package/lib/runtime/components/react/mpx-image.tsx +2 -5
  92. package/lib/runtime/components/react/mpx-inline-text.tsx +13 -4
  93. package/lib/runtime/components/react/mpx-input.tsx +19 -10
  94. package/lib/runtime/components/react/mpx-label.tsx +1 -3
  95. package/lib/runtime/components/react/mpx-movable-area.tsx +2 -3
  96. package/lib/runtime/components/react/mpx-movable-view.tsx +1 -3
  97. package/lib/runtime/components/react/mpx-nav.tsx +1 -1
  98. package/lib/runtime/components/react/mpx-picker/index.tsx +100 -29
  99. package/lib/runtime/components/react/mpx-picker/multiSelector.tsx +3 -3
  100. package/lib/runtime/components/react/mpx-picker/selector.tsx +1 -1
  101. package/lib/runtime/components/react/mpx-picker/type.ts +4 -0
  102. package/lib/runtime/components/react/mpx-picker-view/index.tsx +12 -17
  103. package/lib/runtime/components/react/mpx-picker-view/pickerVIewContext.ts +0 -9
  104. package/lib/runtime/components/react/mpx-picker-view-column/index.tsx +44 -21
  105. package/lib/runtime/components/react/mpx-picker-view-column/pickerViewColumnItem.tsx +1 -9
  106. package/lib/runtime/components/react/mpx-picker-view-column/pickerViewColumnItemLite.tsx +0 -9
  107. package/lib/runtime/components/react/mpx-popup/index.tsx +7 -3
  108. package/lib/runtime/components/react/mpx-popup/popupBase.tsx +3 -2
  109. package/lib/runtime/components/react/mpx-progress.tsx +0 -3
  110. package/lib/runtime/components/react/mpx-radio-group.tsx +1 -3
  111. package/lib/runtime/components/react/mpx-radio.tsx +1 -3
  112. package/lib/runtime/components/react/mpx-rich-text/index.tsx +0 -3
  113. package/lib/runtime/components/react/mpx-scroll-view.tsx +1 -3
  114. package/lib/runtime/components/react/mpx-section-list.tsx +557 -0
  115. package/lib/runtime/components/react/mpx-simple-text.tsx +26 -13
  116. package/lib/runtime/components/react/mpx-slider.tsx +0 -3
  117. package/lib/runtime/components/react/mpx-sticky-header.tsx +1 -3
  118. package/lib/runtime/components/react/mpx-sticky-section.tsx +1 -3
  119. package/lib/runtime/components/react/mpx-swiper-item.tsx +0 -1
  120. package/lib/runtime/components/react/mpx-swiper.tsx +0 -3
  121. package/lib/runtime/components/react/mpx-switch.tsx +0 -3
  122. package/lib/runtime/components/react/mpx-text.tsx +21 -9
  123. package/lib/runtime/components/react/mpx-video.tsx +0 -3
  124. package/lib/runtime/components/react/mpx-view.tsx +0 -3
  125. package/lib/runtime/components/react/mpx-web-view.tsx +4 -3
  126. package/lib/runtime/components/react/utils.tsx +82 -88
  127. package/lib/template-compiler/compiler.js +6 -0
  128. package/package.json +5 -5
@@ -0,0 +1,557 @@
1
+ import { forwardRef, useRef, useMemo, createElement, useImperativeHandle } from 'react'
2
+ import type { ComponentType, ReactElement } from 'react'
3
+ import { SectionList, RefreshControl, NativeSyntheticEvent, NativeScrollEvent } from 'react-native'
4
+ import type { SectionListData, SectionListProps as RNSectionListProps } from 'react-native'
5
+ import { Gesture, GestureDetector } from 'react-native-gesture-handler'
6
+ import { hasOwn } from '@mpxjs/utils'
7
+ import useInnerProps, { getCustomEvent } from './getInnerListeners'
8
+ import { extendObject, useLayout, useTransformStyle, GestureHandler, flatGesture, wrapChildren, splitStyle, useTextPassThrough, splitProps } from './utils'
9
+ import Portal from './mpx-portal'
10
+ interface ListItem {
11
+ isSectionHeader?: boolean;
12
+ isSectionFooter?: boolean;
13
+ [key: string]: any;
14
+ }
15
+
16
+ interface SectionExtra {
17
+ headerData: ListItem | null;
18
+ footerData: ListItem | null;
19
+ hasSectionHeader?: boolean;
20
+ hasSectionFooter?: boolean;
21
+ }
22
+
23
+ interface Section extends SectionExtra {
24
+ data: ListItem[];
25
+ }
26
+
27
+ type RNSection = SectionListData<ListItem, SectionExtra>
28
+
29
+ const TypedSectionList = SectionList as unknown as ComponentType<RNSectionListProps<ListItem, SectionExtra>>
30
+
31
+ interface ItemHeightType {
32
+ value?: number;
33
+ getter?: (item: any, index: number) => number;
34
+ }
35
+
36
+ interface MpxSectionListProps {
37
+ enhanced?: boolean;
38
+ bounces?: boolean;
39
+ height?: number | string;
40
+ width?: number | string;
41
+ generichash?: string;
42
+ style?: Record<string, any>;
43
+ 'scroll-event-throttle'?: number;
44
+ 'list-data'?: ListItem[];
45
+ 'item-height'?: ItemHeightType;
46
+ 'section-header-height'?: ItemHeightType;
47
+ 'section-footer-height'?: ItemHeightType;
48
+ 'list-header-data'?: any;
49
+ 'list-header-height'?: number;
50
+ 'use-list-header'?: boolean;
51
+ 'list-footer-data'?: any;
52
+ 'use-list-footer'?: boolean;
53
+ 'genericrecycle-item'?: string;
54
+ 'genericsection-header'?: string;
55
+ 'genericsection-footer'?: string;
56
+ 'genericlist-header'?: string;
57
+ 'genericlist-footer'?: string;
58
+ 'enable-var'?: boolean;
59
+ 'parent-width'?: number;
60
+ 'parent-height'?: number;
61
+ 'enable-sticky'?: boolean;
62
+ 'enable-back-to-top'?: boolean;
63
+ 'end-reached-threshold'?: number;
64
+ 'refresher-enabled'?: boolean;
65
+ 'show-scrollbar'?: boolean;
66
+ 'refresher-triggered'?: boolean;
67
+ 'wait-for'?: Array<GestureHandler>;
68
+ 'simultaneous-handlers'?: Array<GestureHandler>;
69
+ bindrefresherrefresh?: (event: any) => void;
70
+ bindscrolltolower?: (event: any) => void;
71
+ bindscroll?: (event: any) => void;
72
+ [key: string]: any;
73
+ }
74
+
75
+ interface ScrollPositionParams {
76
+ index: number;
77
+ animated?: boolean;
78
+ viewOffset?: number;
79
+ viewPosition?: number;
80
+ }
81
+
82
+ const getGeneric = (generichash: string, generickey: string) => {
83
+ if (!generichash || !generickey) return null
84
+ return global.__mpxGenericsMap?.[generichash]?.[generickey]?.() || null
85
+ }
86
+
87
+ const _SectionList = forwardRef<any, MpxSectionListProps>((sectionListProps = {}, ref) => {
88
+ const { textProps, innerProps: props = {} } = splitProps(sectionListProps)
89
+ const {
90
+ enhanced = false,
91
+ bounces = true,
92
+ height,
93
+ width,
94
+ generichash,
95
+ style = {},
96
+ 'list-data': listData,
97
+ 'scroll-event-throttle': scrollEventThrottle = 0,
98
+ 'item-height': itemHeight = {},
99
+ 'section-header-height': sectionHeaderHeight = {},
100
+ 'section-footer-height': sectionFooterHeight = {},
101
+ 'list-header-height': listHeaderHeight = 0,
102
+ 'list-header-data': listHeaderData = null,
103
+ 'use-list-header': useListHeader = false,
104
+ 'list-footer-data': listFooterData = null,
105
+ 'use-list-footer': useListFooter = false,
106
+ 'genericrecycle-item': genericrecycleItem,
107
+ 'genericsection-header': genericsectionHeader,
108
+ 'genericsection-footer': genericsectionFooter,
109
+ 'genericlist-header': genericListHeader,
110
+ 'genericlist-footer': genericListFooter,
111
+ 'enable-var': enableVar,
112
+ 'enable-text-pass-through': enableTextPassThrough,
113
+ 'parent-width': parentWidth,
114
+ 'parent-height': parentHeight,
115
+ 'enable-sticky': enableSticky = false,
116
+ 'enable-back-to-top': enableBackToTop = false,
117
+ 'end-reached-threshold': onEndReachedThreshold = 0.1,
118
+ 'refresher-enabled': refresherEnabled,
119
+ 'show-scrollbar': showScrollbar = true,
120
+ 'refresher-triggered': refresherTriggered,
121
+ 'simultaneous-handlers': originSimultaneousHandlers,
122
+ 'wait-for': waitFor
123
+ } = props
124
+
125
+ const refreshing = !!refresherTriggered
126
+
127
+ const scrollViewRef = useRef<any>(null)
128
+ const sectionListGestureRef = useRef<any>()
129
+
130
+ const indexMap = useRef<{ [key: string]: string }>({})
131
+
132
+ const reverseIndexMap = useRef<{ [key: string]: number }>({})
133
+
134
+ const {
135
+ normalStyle,
136
+ hasVarDec,
137
+ varContextRef,
138
+ hasSelfPercent,
139
+ hasPositionFixed,
140
+ setWidth,
141
+ setHeight
142
+ } = useTransformStyle(style, { enableVar, parentWidth, parentHeight })
143
+
144
+ const { textStyle, innerStyle = {} } = splitStyle(normalStyle)
145
+ const textPassThrough = useTextPassThrough(textStyle, textProps, { enableTextPassThrough })
146
+
147
+ const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: scrollViewRef })
148
+
149
+ const onRefresh = () => {
150
+ const { bindrefresherrefresh } = props
151
+ bindrefresherrefresh &&
152
+ bindrefresherrefresh(
153
+ getCustomEvent('refresherrefresh', {}, { layoutRef }, props)
154
+ )
155
+ }
156
+
157
+ const onEndReached = () => {
158
+ const { bindscrolltolower } = props
159
+ bindscrolltolower &&
160
+ bindscrolltolower(
161
+ getCustomEvent('scrolltolower', {}, { layoutRef }, props)
162
+ )
163
+ }
164
+
165
+ const onScroll = (event: NativeSyntheticEvent<NativeScrollEvent>) => {
166
+ const { bindscroll } = props
167
+ if (bindscroll) {
168
+ const { nativeEvent } = event
169
+ bindscroll(
170
+ getCustomEvent('scroll', event, {
171
+ detail: {
172
+ scrollTop: nativeEvent.contentOffset.y
173
+ },
174
+ layoutRef
175
+ }, props)
176
+ )
177
+ }
178
+ }
179
+
180
+ // 通过sectionIndex和rowIndex获取原始索引
181
+ const getOriginalIndex = (sectionIndex: number, rowIndex: number | 'header' | 'footer'): number => {
182
+ const key = `${sectionIndex}_${rowIndex}`
183
+ return reverseIndexMap.current[key] ?? -1 // 如果找不到,返回-1
184
+ }
185
+
186
+ const scrollToIndex = ({ index, animated, viewOffset = 0, viewPosition = 0 }: ScrollPositionParams) => {
187
+ if (!scrollViewRef.current) return
188
+ // 通过索引映射表快速定位位置
189
+ const position = indexMap.current[index]
190
+ if (!position) return
191
+ const [sectionIndex, itemIndex] = position.split('_')
192
+ const targetSectionIndex = Number(sectionIndex) || 0
193
+ const targetItemIndex = itemIndex === 'header'
194
+ ? 0
195
+ : itemIndex === 'footer'
196
+ ? convertedListData[targetSectionIndex].data.length + 1
197
+ : Number(itemIndex) + 1
198
+ scrollViewRef.current.scrollToLocation?.({
199
+ itemIndex: targetItemIndex,
200
+ sectionIndex: targetSectionIndex,
201
+ animated,
202
+ viewOffset,
203
+ viewPosition
204
+ })
205
+ }
206
+
207
+ const getItemHeight = ({ sectionIndex, rowIndex }: { sectionIndex: number, rowIndex: number }) => {
208
+ if (!itemHeight) {
209
+ return 0
210
+ }
211
+ if ((itemHeight as ItemHeightType).getter) {
212
+ const item = convertedListData[sectionIndex].data[rowIndex]
213
+ // 使用getOriginalIndex获取原始索引
214
+ const originalIndex = getOriginalIndex(sectionIndex, rowIndex)
215
+ return (itemHeight as ItemHeightType).getter?.(item, originalIndex) || 0
216
+ } else {
217
+ return (itemHeight as ItemHeightType).value || 0
218
+ }
219
+ }
220
+
221
+ const getSectionExtraHeight = ({ sectionIndex, type }: { sectionIndex: number, type: 'header' | 'footer' }) => {
222
+ const item = convertedListData[sectionIndex]
223
+ const isHeader = type === 'header'
224
+ if (!(isHeader ? item.hasSectionHeader : item.hasSectionFooter)) return 0
225
+ const sectionExtraHeight = (isHeader ? sectionHeaderHeight : sectionFooterHeight) as ItemHeightType
226
+ if (sectionExtraHeight.getter) {
227
+ const sectionExtraData = isHeader ? item.headerData : item.footerData
228
+ return sectionExtraHeight.getter?.(sectionExtraData, getOriginalIndex(sectionIndex, type)) || 0
229
+ }
230
+ return sectionExtraHeight.value || 0
231
+ }
232
+
233
+ const convertedListData = useMemo(() => {
234
+ const sections: Section[] = []
235
+ let currentSection: Section | null = null
236
+ // 清空之前的索引映射
237
+ indexMap.current = {}
238
+ // 清空反向索引映射
239
+ reverseIndexMap.current = {}
240
+
241
+ // 处理 listData 为空的情况
242
+ if (!listData || !listData.length) {
243
+ return sections
244
+ }
245
+
246
+ listData.forEach((item: ListItem, index: number) => {
247
+ if (item.isSectionHeader) {
248
+ // 如果已经存在一个 section,先把它添加到 sections 中
249
+ if (currentSection) {
250
+ sections.push(currentSection)
251
+ }
252
+ // 创建新的 section
253
+ currentSection = {
254
+ headerData: item,
255
+ footerData: null,
256
+ data: [],
257
+ hasSectionHeader: true,
258
+ hasSectionFooter: false
259
+ }
260
+ // 为 section header 添加索引映射
261
+ const sectionIndex = sections.length
262
+ indexMap.current[index] = `${sectionIndex}_header`
263
+ // 添加反向索引映射
264
+ reverseIndexMap.current[`${sectionIndex}_header`] = index
265
+ } else if (item.isSectionFooter) {
266
+ // 如果没有当前 section,创建一个默认的
267
+ if (!currentSection) {
268
+ // 创建默认section (无header的section)
269
+ currentSection = {
270
+ headerData: null,
271
+ footerData: null,
272
+ data: [],
273
+ hasSectionHeader: false,
274
+ hasSectionFooter: false
275
+ }
276
+ }
277
+ const sectionIndex = sections.length
278
+ currentSection.footerData = item
279
+ currentSection.hasSectionFooter = true
280
+ indexMap.current[index] = `${sectionIndex}_footer`
281
+ // 添加反向索引映射
282
+ reverseIndexMap.current[`${sectionIndex}_footer`] = index
283
+ sections.push(currentSection)
284
+ currentSection = null
285
+ } else {
286
+ // 如果没有当前 section,创建一个默认的
287
+ if (!currentSection) {
288
+ // 创建默认section (无header的section)
289
+ currentSection = {
290
+ headerData: null,
291
+ footerData: null,
292
+ data: [],
293
+ hasSectionHeader: false,
294
+ hasSectionFooter: false
295
+ }
296
+ }
297
+ // 将 item 添加到当前 section 的 data 中
298
+ const itemIndex = currentSection.data.length
299
+ currentSection.data.push(item)
300
+ let sectionIndex
301
+ // 为 item 添加索引映射 - 存储格式为: "sectionIndex_itemIndex"
302
+ if (!currentSection.hasSectionHeader && sections.length === 0) {
303
+ // 在默认section中(第一个且无header)
304
+ sectionIndex = 0
305
+ indexMap.current[index] = `${sectionIndex}_${itemIndex}`
306
+ } else {
307
+ // 在普通section中
308
+ sectionIndex = sections.length
309
+ indexMap.current[index] = `${sectionIndex}_${itemIndex}`
310
+ }
311
+ // 添加反向索引映射
312
+ reverseIndexMap.current[`${sectionIndex}_${itemIndex}`] = index
313
+ }
314
+ })
315
+ // 添加最后一个 section
316
+ if (currentSection) {
317
+ sections.push(currentSection)
318
+ }
319
+ return sections
320
+ }, [listData, listData?.length])
321
+
322
+ const { getItemLayout } = useMemo(() => {
323
+ const layouts: Array<{ length: number, offset: number, index: number }> = []
324
+ let offset = 0
325
+
326
+ if (useListHeader) {
327
+ // 计算列表头部的高度
328
+ offset += listHeaderHeight
329
+ }
330
+
331
+ // 遍历所有 sections
332
+ convertedListData.forEach((section: Section, sectionIndex: number) => {
333
+ // 添加 section header 的位置信息
334
+ const headerHeight = getSectionExtraHeight({ sectionIndex, type: 'header' })
335
+ layouts.push({
336
+ length: headerHeight,
337
+ offset,
338
+ index: layouts.length
339
+ })
340
+ offset += headerHeight
341
+
342
+ // 添加该 section 中所有 items 的位置信息
343
+ section.data.forEach((item: ListItem, itemIndex: number) => {
344
+ const contentHeight = getItemHeight({ sectionIndex, rowIndex: itemIndex })
345
+ layouts.push({
346
+ length: contentHeight,
347
+ offset,
348
+ index: layouts.length
349
+ })
350
+ offset += contentHeight
351
+ })
352
+
353
+ // 添加该 section 尾部位置信息
354
+ // 因为即使 sectionList 没传 renderSectionFooter,getItemLayout 中的 index 的计算也会包含尾部节点
355
+ const footerHeight = getSectionExtraHeight({ sectionIndex, type: 'footer' })
356
+ layouts.push({
357
+ length: footerHeight,
358
+ offset,
359
+ index: layouts.length
360
+ })
361
+ offset += footerHeight
362
+ })
363
+ return {
364
+ itemLayouts: layouts,
365
+ getItemLayout: (data: any, index: number) => layouts[index]
366
+ }
367
+ }, [convertedListData, useListHeader, itemHeight.value, itemHeight.getter, sectionHeaderHeight.value, sectionHeaderHeight.getter, sectionFooterHeight.value, sectionFooterHeight.getter, listHeaderHeight])
368
+
369
+ const scrollAdditionalProps = extendObject(
370
+ {
371
+ style: [
372
+ hasOwn(innerStyle, 'flex') || hasOwn(innerStyle, 'flexGrow') ? null : { flexGrow: 0 },
373
+ { height, width },
374
+ innerStyle,
375
+ layoutStyle
376
+ ],
377
+ alwaysBounceVertical: false,
378
+ alwaysBounceHorizontal: false,
379
+ scrollEventThrottle: scrollEventThrottle,
380
+ scrollsToTop: enableBackToTop,
381
+ showsVerticalScrollIndicator: showScrollbar,
382
+ onEndReachedThreshold,
383
+ ref: scrollViewRef,
384
+ bounces: enhanced ? bounces : false,
385
+ stickySectionHeadersEnabled: enableSticky,
386
+ onScroll: onScroll,
387
+ onEndReached: onEndReached
388
+ },
389
+ refresherEnabled ? { refreshing } : null,
390
+ layoutProps
391
+ )
392
+
393
+ const nativeGesture = useMemo(() => {
394
+ const simultaneousHandlers = flatGesture(originSimultaneousHandlers)
395
+ const waitForHandlers = flatGesture(waitFor)
396
+ const gesture = Gesture.Native().withRef(sectionListGestureRef as any)
397
+ if (simultaneousHandlers && simultaneousHandlers.length) {
398
+ gesture.simultaneousWithExternalGesture(...simultaneousHandlers)
399
+ }
400
+ if (waitForHandlers && waitForHandlers.length) {
401
+ gesture.requireExternalGestureToFail(...waitForHandlers)
402
+ }
403
+ return gesture
404
+ }, [originSimultaneousHandlers, waitFor])
405
+
406
+ useImperativeHandle(ref, () => {
407
+ return {
408
+ gestureRef: sectionListGestureRef,
409
+ scrollToIndex
410
+ }
411
+ })
412
+
413
+ const innerProps = useInnerProps(extendObject({}, props, scrollAdditionalProps), [
414
+ 'id',
415
+ 'enhanced',
416
+ 'height',
417
+ 'width',
418
+ 'list-data',
419
+ 'item-height',
420
+ 'section-header-height',
421
+ 'section-footer-height',
422
+ 'list-header-height',
423
+ 'list-header-data',
424
+ 'use-list-header',
425
+ 'list-footer-data',
426
+ 'use-list-footer',
427
+ 'genericrecycle-item',
428
+ 'genericsection-header',
429
+ 'genericsection-footer',
430
+ 'genericlist-header',
431
+ 'genericlist-footer',
432
+ 'enable-text-pass-through',
433
+ 'show-scrollbar',
434
+ 'lower-threshold',
435
+ 'scroll-event-throttle',
436
+ 'enable-sticky',
437
+ 'enable-back-to-top',
438
+ 'end-reached-threshold',
439
+ 'refresher-triggered',
440
+ 'refresher-enabled',
441
+ 'bindrefresherrefresh',
442
+ 'bindscrolltolower',
443
+ 'bindscroll',
444
+ 'simultaneous-handlers',
445
+ 'wait-for'
446
+ ], { layoutRef })
447
+
448
+ // 使用 useMemo 获取 GenericComponent 并创建渲染函数,避免每次组件更新都重新创建函数引用导致不必要的重新渲染
449
+ const renderItem = useMemo(
450
+ () => {
451
+ const ItemComponent = getGeneric(generichash, genericrecycleItem)
452
+ if (!ItemComponent) return undefined
453
+ return ({ item }: { item: ListItem }) => createElement(ItemComponent, { itemData: item })
454
+ },
455
+ [generichash, genericrecycleItem]
456
+ )
457
+
458
+ const renderSectionHeader = useMemo(
459
+ () => {
460
+ const SectionHeaderComponent = getGeneric(generichash, genericsectionHeader)
461
+ if (!SectionHeaderComponent) return undefined
462
+ return (sectionData: { section: RNSection }) => {
463
+ if (!sectionData.section.hasSectionHeader) return null
464
+ return createElement(SectionHeaderComponent, { itemData: sectionData.section.headerData })
465
+ }
466
+ },
467
+ [generichash, genericsectionHeader]
468
+ )
469
+
470
+ const renderSectionFooter = useMemo(
471
+ () => {
472
+ const SectionFooterComponent = getGeneric(generichash, genericsectionFooter)
473
+ if (!SectionFooterComponent) return undefined
474
+ return (sectionData: { section: RNSection }) => {
475
+ if (!sectionData.section.hasSectionFooter) return null
476
+ return createElement(SectionFooterComponent, { itemData: sectionData.section.footerData })
477
+ }
478
+ },
479
+ [generichash, genericsectionFooter]
480
+ )
481
+
482
+ const ListHeaderGenericComponent = useMemo(
483
+ () => {
484
+ if (!useListHeader) return null
485
+ return getGeneric(generichash, genericListHeader)
486
+ },
487
+ [useListHeader, generichash, genericListHeader]
488
+ )
489
+
490
+ const ListFooterGenericComponent = useMemo(
491
+ () => {
492
+ if (!useListFooter) return null
493
+ return getGeneric(generichash, genericListFooter)
494
+ },
495
+ [useListFooter, generichash, genericListFooter]
496
+ )
497
+
498
+ const ListHeaderComponent = useMemo(
499
+ () => {
500
+ if (!ListHeaderGenericComponent) return null
501
+ return createElement(ListHeaderGenericComponent, { listHeaderData })
502
+ },
503
+ [ListHeaderGenericComponent, listHeaderData]
504
+ )
505
+
506
+ const ListFooterComponent = useMemo(
507
+ () => {
508
+ if (!ListFooterGenericComponent) return null
509
+ return createElement(ListFooterGenericComponent, { listFooterData })
510
+ },
511
+ [ListFooterGenericComponent, listFooterData]
512
+ )
513
+
514
+ const rnSectionListProps: RNSectionListProps<ListItem, SectionExtra> = extendObject(
515
+ {
516
+ sections: convertedListData,
517
+ renderItem: renderItem,
518
+ getItemLayout: getItemLayout,
519
+ ListHeaderComponent: useListHeader ? ListHeaderComponent : null,
520
+ ListFooterComponent: useListFooter ? ListFooterComponent : null,
521
+ renderSectionHeader: renderSectionHeader,
522
+ renderSectionFooter: renderSectionFooter,
523
+ refreshControl: refresherEnabled
524
+ ? createElement(RefreshControl, {
525
+ onRefresh: onRefresh,
526
+ refreshing: refreshing
527
+ })
528
+ : undefined
529
+ },
530
+ innerProps
531
+ )
532
+
533
+ let sectionListComponent = wrapChildren(
534
+ createElement(
535
+ GestureDetector,
536
+ { gesture: nativeGesture },
537
+ createElement(
538
+ TypedSectionList,
539
+ rnSectionListProps
540
+ )
541
+ ),
542
+ {
543
+ hasVarDec,
544
+ varContext: varContextRef.current,
545
+ textPassThrough
546
+ }
547
+ ) as ReactElement
548
+
549
+ if (hasPositionFixed) {
550
+ sectionListComponent = createElement(Portal, null, sectionListComponent)
551
+ }
552
+ return sectionListComponent
553
+ })
554
+
555
+ _SectionList.displayName = 'MpxSectionList'
556
+
557
+ export default _SectionList
@@ -1,8 +1,10 @@
1
1
  import { Text, TextStyle, TextProps } from 'react-native'
2
- import { JSX, createElement } from 'react'
2
+ import { JSX, createElement, useContext, useRef } from 'react'
3
3
  import useInnerProps from './getInnerListeners'
4
- import { extendObject, getDefaultAllowFontScaling, useTextPassThroughText, wrapChildren, isStringChildren, transformBoxSizing, splitStyle, isBoxSizingAffectingStyle } from './utils'
4
+ import { extendObject, getDefaultAllowFontScaling, wrapChildren, isStringChildren, transformBoxSizing, splitStyle, isBoxSizingAffectingStyle, resolveTextFontSizePercentStyle, resolveTextLineHeightPercentStyle } from './utils'
5
5
  import * as perf from '@mpxjs/perf'
6
+ import { diffAndCloneA } from '@mpxjs/utils'
7
+ import { TextPassThroughContext, TextPassThroughContextValue } from './context'
6
8
 
7
9
  const SimpleText = (props: TextProps): JSX.Element => {
8
10
  let idTotal = -1
@@ -12,27 +14,38 @@ const SimpleText = (props: TextProps): JSX.Element => {
12
14
  let idStyle = -1
13
15
  if (__mpx_perf_framework__) idStyle = perf.scopeStart('simple-text:render:style')
14
16
  let hasBoxSizingAffectingStyle = false
15
- const { textStyle } = splitStyle(props.style || {}, (key) => {
17
+ const { textStyle } = splitStyle(props.style as TextStyle | undefined, (key) => {
16
18
  if (!hasBoxSizingAffectingStyle && isBoxSizingAffectingStyle(key)) {
17
19
  hasBoxSizingAffectingStyle = true
18
20
  }
19
21
  })
22
+ const inheritedText = useContext(TextPassThroughContext)
23
+ const resolvedTextStyle = resolveTextFontSizePercentStyle(textStyle, inheritedText?.textStyle)
20
24
  // textStyle 仅在子节点非纯字符串时才需要透传给子级;按需计算 isStringChildren
21
- const childTextStyle: TextStyle | undefined = textStyle && !isStringChildren(props.children)
22
- ? textStyle as TextStyle
25
+ const childTextStyle = resolvedTextStyle && !isStringChildren(props.children)
26
+ ? resolvedTextStyle
23
27
  : undefined
24
- const { inheritedText, textPassThrough } = useTextPassThroughText(childTextStyle)
28
+ const textPassThroughRef = useRef<TextPassThroughContextValue | null>(null)
29
+ let textPassThrough: TextPassThroughContextValue | null = null
30
+ if (childTextStyle) {
31
+ const nextTextPassThrough = {
32
+ textStyle: extendObject({}, inheritedText?.textStyle, childTextStyle)
33
+ }
34
+ if (diffAndCloneA(textPassThroughRef.current, nextTextPassThrough).diff) {
35
+ textPassThroughRef.current = nextTextPassThrough
36
+ }
37
+ textPassThrough = textPassThroughRef.current
38
+ }
25
39
 
26
40
  const mergedProps = inheritedText?.pendingTextProps
27
41
  ? extendObject({}, inheritedText.pendingTextProps, props)
28
42
  : props
29
- let mergedStyle = inheritedText?.textStyle
30
- ? extendObject({}, inheritedText.textStyle, props.style)
31
- : props.style
32
- if (hasBoxSizingAffectingStyle) {
33
- // 仅在需要 mutate 时 clone,避免污染上游 props.style
34
- if (mergedStyle === props.style) mergedStyle = extendObject({}, props.style)
35
- transformBoxSizing(mergedStyle as Record<string, any>)
43
+ const mergedStyle = inheritedText?.textStyle || props.style
44
+ ? extendObject({}, inheritedText?.textStyle, props.style, resolvedTextStyle) as TextStyle
45
+ : undefined
46
+ if (mergedStyle) {
47
+ resolveTextLineHeightPercentStyle(mergedStyle, inheritedText?.textStyle)
48
+ if (hasBoxSizingAffectingStyle) transformBoxSizing(mergedStyle as Record<string, any>)
36
49
  }
37
50
  if (__mpx_perf_framework__) perf.scopeEnd(idStyle)
38
51
 
@@ -59,7 +59,6 @@ export interface SliderProps {
59
59
  style?: ViewStyle & Record<string, any>
60
60
  'enable-offset'?: boolean
61
61
  'enable-var'?: boolean
62
- 'parent-font-size'?: number
63
62
  'parent-width'?: number
64
63
  'parent-height'?: number
65
64
  }
@@ -83,7 +82,6 @@ const Slider = forwardRef<
83
82
  name,
84
83
  style = {},
85
84
  'enable-var': enableVar,
86
- 'parent-font-size': parentFontSize,
87
85
  'parent-width': parentWidth,
88
86
  'parent-height': parentHeight
89
87
  } = props
@@ -126,7 +124,6 @@ const Slider = forwardRef<
126
124
  hasPositionFixed
127
125
  } = useTransformStyle(style, {
128
126
  enableVar,
129
- parentFontSize,
130
127
  parentWidth,
131
128
  parentHeight
132
129
  })
@@ -13,7 +13,6 @@ interface StickyHeaderProps {
13
13
  'offset-top'?: number;
14
14
  'enable-var'?: boolean;
15
15
  'enable-text-pass-through'?: boolean;
16
- 'parent-font-size'?: number;
17
16
  'parent-width'?: number;
18
17
  'parent-height'?: number;
19
18
  bindstickontopchange?: (e: NativeSyntheticEvent<unknown>) => void;
@@ -28,7 +27,6 @@ const _StickyHeader = forwardRef<HandlerRef<View, StickyHeaderProps>, StickyHead
28
27
  'offset-top': offsetTop = 0,
29
28
  'enable-var': enableVar,
30
29
  'enable-text-pass-through': enableTextPassThrough,
31
- 'parent-font-size': parentFontSize,
32
30
  'parent-width': parentWidth,
33
31
  'parent-height': parentHeight
34
32
  } = props
@@ -47,7 +45,7 @@ const _StickyHeader = forwardRef<HandlerRef<View, StickyHeaderProps>, StickyHead
47
45
  hasSelfPercent,
48
46
  setWidth,
49
47
  setHeight
50
- } = useTransformStyle(style, { enableVar, parentFontSize, parentWidth, parentHeight })
48
+ } = useTransformStyle(style, { enableVar, parentWidth, parentHeight })
51
49
 
52
50
  const { layoutRef, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: headerRef, onLayout })
53
51
 
@@ -12,7 +12,6 @@ interface StickySectionProps {
12
12
  'offset-top'?: number;
13
13
  'enable-var'?: boolean;
14
14
  'enable-text-pass-through'?: boolean;
15
- 'parent-font-size'?: number;
16
15
  'parent-width'?: number;
17
16
  'parent-height'?: number;
18
17
  }
@@ -23,7 +22,6 @@ const _StickySection = forwardRef<HandlerRef<View, StickySectionProps>, StickySe
23
22
  style,
24
23
  'enable-var': enableVar,
25
24
  'enable-text-pass-through': enableTextPassThrough,
26
- 'parent-font-size': parentFontSize,
27
25
  'parent-width': parentWidth,
28
26
  'parent-height': parentHeight
29
27
  } = props
@@ -36,7 +34,7 @@ const _StickySection = forwardRef<HandlerRef<View, StickySectionProps>, StickySe
36
34
  hasSelfPercent,
37
35
  setWidth,
38
36
  setHeight
39
- } = useTransformStyle(style, { enableVar, parentFontSize, parentWidth, parentHeight })
37
+ } = useTransformStyle(style, { enableVar, parentWidth, parentHeight })
40
38
 
41
39
  const { layoutRef, layoutProps, layoutStyle } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: sectionRef, onLayout })
42
40