@mpxjs/webpack-plugin 2.10.24 → 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 (151) hide show
  1. package/lib/index.js +4 -1
  2. package/lib/platform/style/wx/index.js +417 -120
  3. package/lib/platform/template/wx/component-config/picker.js +0 -6
  4. package/lib/react/style-helper.js +6 -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/animationHooks/index.ts +7 -3
  10. package/lib/runtime/components/react/dist/animationHooks/index.d.ts +0 -2
  11. package/lib/runtime/components/react/dist/animationHooks/index.js +6 -1
  12. package/lib/runtime/components/react/dist/event.config.d.ts +2 -6
  13. package/lib/runtime/components/react/dist/event.config.js +28 -24
  14. package/lib/runtime/components/react/dist/getInnerListeners.d.ts +1 -1
  15. package/lib/runtime/components/react/dist/getInnerListeners.js +74 -56
  16. package/lib/runtime/components/react/dist/mpx-button.d.ts +1 -2
  17. package/lib/runtime/components/react/dist/mpx-button.jsx +16 -9
  18. package/lib/runtime/components/react/dist/mpx-camera.d.ts +0 -2
  19. package/lib/runtime/components/react/dist/mpx-camera.jsx +36 -5
  20. package/lib/runtime/components/react/dist/mpx-canvas/index.d.ts +0 -2
  21. package/lib/runtime/components/react/dist/mpx-canvas/index.jsx +1 -3
  22. package/lib/runtime/components/react/dist/mpx-canvas/utils.d.ts +1 -1
  23. package/lib/runtime/components/react/dist/mpx-checkbox-group.d.ts +0 -2
  24. package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +3 -4
  25. package/lib/runtime/components/react/dist/mpx-checkbox.d.ts +1 -2
  26. package/lib/runtime/components/react/dist/mpx-checkbox.jsx +8 -9
  27. package/lib/runtime/components/react/dist/mpx-form.d.ts +1 -2
  28. package/lib/runtime/components/react/dist/mpx-form.jsx +5 -5
  29. package/lib/runtime/components/react/dist/mpx-icon/index.d.ts +0 -2
  30. package/lib/runtime/components/react/dist/mpx-icon/index.jsx +2 -2
  31. package/lib/runtime/components/react/dist/mpx-image.d.ts +0 -2
  32. package/lib/runtime/components/react/dist/mpx-image.jsx +59 -43
  33. package/lib/runtime/components/react/dist/mpx-inline-text.jsx +13 -4
  34. package/lib/runtime/components/react/dist/mpx-input.d.ts +0 -2
  35. package/lib/runtime/components/react/dist/mpx-input.jsx +16 -8
  36. package/lib/runtime/components/react/dist/mpx-label.d.ts +1 -2
  37. package/lib/runtime/components/react/dist/mpx-label.jsx +5 -6
  38. package/lib/runtime/components/react/dist/mpx-movable-area.d.ts +0 -2
  39. package/lib/runtime/components/react/dist/mpx-movable-area.jsx +3 -3
  40. package/lib/runtime/components/react/dist/mpx-movable-view.d.ts +1 -2
  41. package/lib/runtime/components/react/dist/mpx-movable-view.jsx +6 -6
  42. package/lib/runtime/components/react/dist/mpx-nav.jsx +1 -1
  43. package/lib/runtime/components/react/dist/mpx-picker/index.jsx +72 -23
  44. package/lib/runtime/components/react/dist/mpx-picker/multiSelector.jsx +2 -2
  45. package/lib/runtime/components/react/dist/mpx-picker/type.d.ts +4 -0
  46. package/lib/runtime/components/react/dist/mpx-picker-view/index.d.ts +1 -1
  47. package/lib/runtime/components/react/dist/mpx-picker-view/index.jsx +10 -14
  48. package/lib/runtime/components/react/dist/mpx-picker-view/pickerVIewContext.d.ts +0 -2
  49. package/lib/runtime/components/react/dist/mpx-picker-view/pickerVIewContext.js +0 -5
  50. package/lib/runtime/components/react/dist/mpx-picker-view-column/index.d.ts +1 -1
  51. package/lib/runtime/components/react/dist/mpx-picker-view-column/index.jsx +34 -14
  52. package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewColumnItem.d.ts +0 -2
  53. package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewColumnItem.jsx +4 -5
  54. package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewColumnItemLite.d.ts +0 -2
  55. package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewColumnItemLite.jsx +3 -5
  56. package/lib/runtime/components/react/dist/mpx-popup/index.d.ts +5 -4
  57. package/lib/runtime/components/react/dist/mpx-popup/index.jsx +2 -2
  58. package/lib/runtime/components/react/dist/mpx-popup/popupBase.jsx +3 -2
  59. package/lib/runtime/components/react/dist/mpx-progress.d.ts +0 -2
  60. package/lib/runtime/components/react/dist/mpx-progress.jsx +1 -3
  61. package/lib/runtime/components/react/dist/mpx-radio-group.d.ts +0 -2
  62. package/lib/runtime/components/react/dist/mpx-radio-group.jsx +3 -4
  63. package/lib/runtime/components/react/dist/mpx-radio.d.ts +1 -2
  64. package/lib/runtime/components/react/dist/mpx-radio.jsx +8 -9
  65. package/lib/runtime/components/react/dist/mpx-rich-text/index.d.ts +0 -2
  66. package/lib/runtime/components/react/dist/mpx-rich-text/index.jsx +1 -3
  67. package/lib/runtime/components/react/dist/mpx-scroll-view.d.ts +1 -2
  68. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +6 -6
  69. package/lib/runtime/components/react/dist/mpx-section-list.d.ts +51 -0
  70. package/lib/runtime/components/react/dist/mpx-section-list.jsx +376 -0
  71. package/lib/runtime/components/react/dist/mpx-simple-text.jsx +37 -19
  72. package/lib/runtime/components/react/dist/mpx-simple-view.d.ts +4 -1
  73. package/lib/runtime/components/react/dist/mpx-simple-view.jsx +11 -4
  74. package/lib/runtime/components/react/dist/mpx-slider.d.ts +0 -2
  75. package/lib/runtime/components/react/dist/mpx-slider.jsx +6 -7
  76. package/lib/runtime/components/react/dist/mpx-sticky-header.d.ts +1 -2
  77. package/lib/runtime/components/react/dist/mpx-sticky-header.jsx +5 -5
  78. package/lib/runtime/components/react/dist/mpx-sticky-section.d.ts +1 -2
  79. package/lib/runtime/components/react/dist/mpx-sticky-section.jsx +6 -6
  80. package/lib/runtime/components/react/dist/mpx-swiper-item.d.ts +1 -2
  81. package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +5 -5
  82. package/lib/runtime/components/react/dist/mpx-swiper.d.ts +1 -2
  83. package/lib/runtime/components/react/dist/mpx-swiper.jsx +4 -8
  84. package/lib/runtime/components/react/dist/mpx-switch.d.ts +0 -2
  85. package/lib/runtime/components/react/dist/mpx-switch.jsx +1 -3
  86. package/lib/runtime/components/react/dist/mpx-text.d.ts +0 -2
  87. package/lib/runtime/components/react/dist/mpx-text.jsx +43 -25
  88. package/lib/runtime/components/react/dist/mpx-video.d.ts +0 -2
  89. package/lib/runtime/components/react/dist/mpx-video.jsx +4 -5
  90. package/lib/runtime/components/react/dist/mpx-view.d.ts +2 -2
  91. package/lib/runtime/components/react/dist/mpx-view.jsx +214 -114
  92. package/lib/runtime/components/react/dist/mpx-web-view.d.ts +2 -1
  93. package/lib/runtime/components/react/dist/mpx-web-view.jsx +5 -1
  94. package/lib/runtime/components/react/dist/namedColorSet.d.ts +2 -0
  95. package/lib/runtime/components/react/dist/namedColorSet.js +149 -0
  96. package/lib/runtime/components/react/dist/utils.d.ts +71 -70
  97. package/lib/runtime/components/react/dist/utils.jsx +1295 -456
  98. package/lib/runtime/components/react/event.config.ts +32 -25
  99. package/lib/runtime/components/react/getInnerListeners.ts +84 -60
  100. package/lib/runtime/components/react/mpx-button.tsx +18 -18
  101. package/lib/runtime/components/react/mpx-camera.tsx +40 -8
  102. package/lib/runtime/components/react/mpx-canvas/index.tsx +5 -7
  103. package/lib/runtime/components/react/mpx-canvas/utils.tsx +3 -1
  104. package/lib/runtime/components/react/mpx-checkbox-group.tsx +2 -8
  105. package/lib/runtime/components/react/mpx-checkbox.tsx +9 -13
  106. package/lib/runtime/components/react/mpx-form.tsx +6 -8
  107. package/lib/runtime/components/react/mpx-icon/index.tsx +1 -5
  108. package/lib/runtime/components/react/mpx-image.tsx +66 -58
  109. package/lib/runtime/components/react/mpx-inline-text.tsx +13 -4
  110. package/lib/runtime/components/react/mpx-input.tsx +19 -12
  111. package/lib/runtime/components/react/mpx-label.tsx +6 -10
  112. package/lib/runtime/components/react/mpx-movable-area.tsx +3 -5
  113. package/lib/runtime/components/react/mpx-movable-view.tsx +7 -9
  114. package/lib/runtime/components/react/mpx-nav.tsx +1 -1
  115. package/lib/runtime/components/react/mpx-picker/index.tsx +100 -29
  116. package/lib/runtime/components/react/mpx-picker/multiSelector.tsx +3 -3
  117. package/lib/runtime/components/react/mpx-picker/selector.tsx +1 -1
  118. package/lib/runtime/components/react/mpx-picker/type.ts +4 -0
  119. package/lib/runtime/components/react/mpx-picker-view/index.tsx +17 -24
  120. package/lib/runtime/components/react/mpx-picker-view/pickerVIewContext.ts +0 -9
  121. package/lib/runtime/components/react/mpx-picker-view-column/index.tsx +44 -23
  122. package/lib/runtime/components/react/mpx-picker-view-column/pickerViewColumnItem.tsx +1 -9
  123. package/lib/runtime/components/react/mpx-picker-view-column/pickerViewColumnItemLite.tsx +0 -9
  124. package/lib/runtime/components/react/mpx-popup/index.tsx +7 -3
  125. package/lib/runtime/components/react/mpx-popup/popupBase.tsx +3 -2
  126. package/lib/runtime/components/react/mpx-progress.tsx +0 -6
  127. package/lib/runtime/components/react/mpx-radio-group.tsx +2 -8
  128. package/lib/runtime/components/react/mpx-radio.tsx +9 -13
  129. package/lib/runtime/components/react/mpx-rich-text/index.tsx +0 -6
  130. package/lib/runtime/components/react/mpx-scroll-view.tsx +7 -9
  131. package/lib/runtime/components/react/mpx-section-list.tsx +557 -0
  132. package/lib/runtime/components/react/mpx-simple-text.tsx +36 -25
  133. package/lib/runtime/components/react/mpx-simple-view.tsx +17 -5
  134. package/lib/runtime/components/react/mpx-slider.tsx +15 -13
  135. package/lib/runtime/components/react/mpx-sticky-header.tsx +6 -8
  136. package/lib/runtime/components/react/mpx-sticky-section.tsx +7 -9
  137. package/lib/runtime/components/react/mpx-swiper-item.tsx +6 -7
  138. package/lib/runtime/components/react/mpx-swiper.tsx +5 -11
  139. package/lib/runtime/components/react/mpx-switch.tsx +0 -6
  140. package/lib/runtime/components/react/mpx-text.tsx +45 -36
  141. package/lib/runtime/components/react/mpx-video.tsx +3 -8
  142. package/lib/runtime/components/react/mpx-view.tsx +235 -129
  143. package/lib/runtime/components/react/mpx-web-view.tsx +12 -6
  144. package/lib/runtime/components/react/namedColorSet.ts +150 -0
  145. package/lib/runtime/components/react/types/getInnerListeners.d.ts +21 -1
  146. package/lib/runtime/components/react/types/global.d.ts +1 -0
  147. package/lib/runtime/components/react/utils.tsx +1352 -550
  148. package/lib/runtime/i18n.wxs +15 -9
  149. package/lib/style-compiler/strip-conditional.js +19 -4
  150. package/lib/template-compiler/compiler.js +6 -0
  151. package/package.json +6 -6
@@ -10,7 +10,7 @@ import useNodesRef from './useNodesRef';
10
10
  import { useLayout, useTransformStyle, wrapChildren, extendObject } from './utils';
11
11
  import Portal from './mpx-portal';
12
12
  const radioGroup = forwardRef((props, ref) => {
13
- const { style = {}, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight } = props;
13
+ const { style = {}, 'enable-var': enableVar, 'parent-width': parentWidth, 'parent-height': parentHeight } = props;
14
14
  const propsRef = useRef({});
15
15
  propsRef.current = props;
16
16
  const formContext = useContext(FormContext);
@@ -23,8 +23,7 @@ const radioGroup = forwardRef((props, ref) => {
23
23
  flexDirection: 'row',
24
24
  flexWrap: 'wrap'
25
25
  };
26
- const styleObj = extendObject({}, defaultStyle, style);
27
- const { hasPositionFixed, hasSelfPercent, normalStyle, hasVarDec, varContextRef, setWidth, setHeight } = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
26
+ const { hasPositionFixed, hasSelfPercent, normalStyle, hasVarDec, varContextRef, setWidth, setHeight } = useTransformStyle(style, { enableVar, parentWidth, parentHeight, defaultStyle });
28
27
  const nodeRef = useRef(null);
29
28
  useNodesRef(props, ref, nodeRef, { style: normalStyle });
30
29
  const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef });
@@ -83,7 +82,7 @@ const radioGroup = forwardRef((props, ref) => {
83
82
  });
84
83
  const finalComponent = createElement(View, innerProps, createElement(RadioGroupContext.Provider, {
85
84
  value: contextValue
86
- }, wrapChildren(props, {
85
+ }, wrapChildren(props.children, {
87
86
  hasVarDec,
88
87
  varContext: varContextRef.current
89
88
  })));
@@ -15,8 +15,7 @@ export interface RadioProps {
15
15
  style?: ViewStyle & Record<string, any>;
16
16
  'enable-offset'?: boolean;
17
17
  'enable-var'?: boolean;
18
- 'external-var-context'?: Record<string, any>;
19
- 'parent-font-size'?: number;
18
+ 'enable-text-pass-through'?: boolean;
20
19
  'parent-width'?: number;
21
20
  'parent-height'?: number;
22
21
  children: ReactNode;
@@ -10,7 +10,7 @@ import { warn } from '@mpxjs/utils';
10
10
  import { LabelContext, RadioGroupContext } from './context';
11
11
  import useInnerProps, { getCustomEvent } from './getInnerListeners';
12
12
  import useNodesRef from './useNodesRef';
13
- import { splitProps, splitStyle, useLayout, useTransformStyle, wrapChildren, extendObject, useTextPassThroughValue } from './utils';
13
+ import { splitProps, splitStyle, useLayout, useTransformStyle, wrapChildren, extendObject, useTextPassThrough } from './utils';
14
14
  import Icon from './mpx-icon';
15
15
  import Portal from './mpx-portal';
16
16
  const styles = StyleSheet.create({
@@ -48,14 +48,13 @@ const styles = StyleSheet.create({
48
48
  });
49
49
  const Radio = forwardRef((radioProps, ref) => {
50
50
  const { textProps, innerProps: props = {} } = splitProps(radioProps);
51
- const { value = '', disabled = false, checked = false, color = '#09BB07', style = [], 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, bindtap } = props;
51
+ const { value = '', disabled = false, checked = false, color = '#09BB07', style = [], 'enable-var': enableVar, 'enable-text-pass-through': enableTextPassThrough, 'parent-width': parentWidth, 'parent-height': parentHeight, bindtap } = props;
52
52
  const [isChecked, setIsChecked] = useState(!!checked);
53
53
  const groupContext = useContext(RadioGroupContext);
54
54
  let groupValue;
55
55
  let notifyChange;
56
56
  const labelContext = useContext(LabelContext);
57
- const defaultStyle = extendObject({}, styles.wrapper, isChecked ? styles.wrapperChecked : {}, disabled ? styles.wrapperDisabled : {});
58
- const styleObj = extendObject({}, styles.container, style);
57
+ const wrapperStyle = extendObject({}, styles.wrapper, isChecked ? styles.wrapperChecked : {}, disabled ? styles.wrapperDisabled : {});
59
58
  const onChange = (evt) => {
60
59
  if (disabled || isChecked)
61
60
  return;
@@ -74,15 +73,15 @@ const Radio = forwardRef((radioProps, ref) => {
74
73
  bindtap && bindtap(getCustomEvent('tap', evt, { layoutRef }, props));
75
74
  onChange(evt);
76
75
  };
77
- const { hasPositionFixed, hasSelfPercent, normalStyle, hasVarDec, varContextRef, setWidth, setHeight } = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
76
+ const { hasPositionFixed, hasSelfPercent, normalStyle, hasVarDec, varContextRef, setWidth, setHeight } = useTransformStyle(style, { enableVar, parentWidth, parentHeight, defaultStyle: styles.container });
78
77
  const { textStyle, backgroundStyle, innerStyle = {} } = splitStyle(normalStyle);
79
- const textPassThrough = useTextPassThroughValue(textStyle, textProps);
78
+ const textPassThrough = useTextPassThrough(textStyle, textProps, { enableTextPassThrough });
80
79
  if (backgroundStyle) {
81
80
  warn('Radio does not support background image-related styles!');
82
81
  }
83
82
  const nodeRef = useRef(null);
84
83
  useNodesRef(props, ref, nodeRef, {
85
- style: extendObject({}, defaultStyle, normalStyle),
84
+ style: normalStyle,
86
85
  change: onChange
87
86
  });
88
87
  const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef });
@@ -126,12 +125,12 @@ const Radio = forwardRef((radioProps, ref) => {
126
125
  }
127
126
  }
128
127
  }, [checked]);
129
- const finalComponent = createElement(View, innerProps, createElement(View, { style: defaultStyle }, createElement(Icon, {
128
+ const finalComponent = createElement(View, innerProps, createElement(View, { style: wrapperStyle }, createElement(Icon, {
130
129
  type: 'success',
131
130
  size: 24,
132
131
  color: disabled ? '#E1E1E1' : color,
133
132
  style: extendObject({}, styles.icon, isChecked && styles.iconChecked, disabled && styles.iconDisabled)
134
- })), wrapChildren(props, {
133
+ })), wrapChildren(props.children, {
135
134
  hasVarDec,
136
135
  varContext: varContextRef.current,
137
136
  textPassThrough
@@ -15,8 +15,6 @@ interface _RichTextProps extends ViewProps {
15
15
  style?: ViewStyle;
16
16
  nodes: string | Array<Node>;
17
17
  'enable-var'?: boolean;
18
- 'external-var-context'?: Record<string, any>;
19
- 'parent-font-size'?: number;
20
18
  'parent-width'?: number;
21
19
  'parent-height'?: number;
22
20
  }
@@ -28,7 +28,7 @@ function jsonToHtmlStr(elements) {
28
28
  return htmlStr;
29
29
  }
30
30
  const _RichText = forwardRef((props, ref) => {
31
- const { style = {}, nodes, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight } = props;
31
+ const { style = {}, nodes, 'enable-var': enableVar, 'parent-width': parentWidth, 'parent-height': parentHeight } = props;
32
32
  const nodeRef = useRef(null);
33
33
  const [webViewHeight, setWebViewHeight] = useState(0);
34
34
  const { normalStyle, hasSelfPercent, setWidth, setHeight, hasPositionFixed } = useTransformStyle(Object.assign({
@@ -36,8 +36,6 @@ const _RichText = forwardRef((props, ref) => {
36
36
  height: webViewHeight
37
37
  }, style), {
38
38
  enableVar,
39
- externalVarContext,
40
- parentFontSize,
41
39
  parentWidth,
42
40
  parentHeight
43
41
  });
@@ -26,8 +26,7 @@ interface ScrollViewProps {
26
26
  'scroll-into-view'?: string;
27
27
  'enable-trigger-intersection-observer'?: boolean;
28
28
  'enable-var'?: boolean;
29
- 'external-var-context'?: Record<string, any>;
30
- 'parent-font-size'?: number;
29
+ 'enable-text-pass-through'?: boolean;
31
30
  'parent-width'?: number;
32
31
  'parent-height'?: number;
33
32
  'enable-sticky'?: boolean;
@@ -38,7 +38,7 @@ import Animated, { useSharedValue, withTiming, useAnimatedStyle, runOnJS } from
38
38
  import { warn, hasOwn } from '@mpxjs/utils';
39
39
  import useInnerProps, { getCustomEvent } from './getInnerListeners';
40
40
  import useNodesRef from './useNodesRef';
41
- import { splitProps, splitStyle, useTransformStyle, useLayout, wrapChildren, extendObject, flatGesture, HIDDEN_STYLE, useRunOnJSCallback, useTextPassThroughValue } from './utils';
41
+ import { splitProps, splitStyle, useTransformStyle, useLayout, wrapChildren, extendObject, flatGesture, hiddenStyle, useRunOnJSCallback, useTextPassThrough } from './utils';
42
42
  import { IntersectionObserverContext, ScrollViewContext } from './context';
43
43
  import Portal from './mpx-portal';
44
44
  const AnimatedScrollView = RNAnimated.createAnimatedComponent(ScrollView);
@@ -48,7 +48,7 @@ const REFRESH_COLOR = {
48
48
  };
49
49
  const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
50
50
  const { textProps, innerProps: props = {} } = splitProps(scrollViewProps);
51
- const { enhanced = false, bounces = true, style = {}, binddragstart, binddragging, binddragend, bindtouchmove, 'scroll-x': scrollX = false, 'scroll-y': scrollY = false, 'enable-back-to-top': enableBackToTop = false, 'enable-trigger-intersection-observer': enableTriggerIntersectionObserver = false, 'paging-enabled': pagingEnabled = false, 'upper-threshold': upperThreshold = 50, 'lower-threshold': lowerThreshold = 50, 'scroll-with-animation': scrollWithAnimation = false, 'refresher-enabled': refresherEnabled, 'refresher-default-style': refresherDefaultStyle, 'refresher-background': refresherBackground, 'refresher-threshold': refresherThreshold = 45, 'show-scrollbar': showScrollbar = true, 'scroll-into-view': scrollIntoView = '', 'scroll-top': scrollTop = 0, 'scroll-left': scrollLeft = 0, 'refresher-triggered': refresherTriggered, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, 'simultaneous-handlers': originSimultaneousHandlers, 'wait-for': waitFor, 'enable-sticky': enableSticky, 'scroll-event-throttle': scrollEventThrottle = 0, 'scroll-into-view-offset': scrollIntoViewOffset = 0, __selectRef } = props;
51
+ const { enhanced = false, bounces = true, style = {}, binddragstart, binddragging, binddragend, bindtouchmove, 'scroll-x': scrollX = false, 'scroll-y': scrollY = false, 'enable-back-to-top': enableBackToTop = false, 'enable-trigger-intersection-observer': enableTriggerIntersectionObserver = false, 'paging-enabled': pagingEnabled = false, 'upper-threshold': upperThreshold = 50, 'lower-threshold': lowerThreshold = 50, 'scroll-with-animation': scrollWithAnimation = false, 'refresher-enabled': refresherEnabled, 'refresher-default-style': refresherDefaultStyle, 'refresher-background': refresherBackground, 'refresher-threshold': refresherThreshold = 45, 'show-scrollbar': showScrollbar = true, 'scroll-into-view': scrollIntoView = '', 'scroll-top': scrollTop = 0, 'scroll-left': scrollLeft = 0, 'refresher-triggered': refresherTriggered, 'enable-var': enableVar, 'enable-text-pass-through': enableTextPassThrough, 'parent-width': parentWidth, 'parent-height': parentHeight, 'simultaneous-handlers': originSimultaneousHandlers, 'wait-for': waitFor, 'enable-sticky': enableSticky, 'scroll-event-throttle': scrollEventThrottle = 0, 'scroll-into-view-offset': scrollIntoViewOffset = 0, __selectRef } = props;
52
52
  const scrollOffset = useRef(new RNAnimated.Value(0)).current;
53
53
  const simultaneousHandlers = flatGesture(originSimultaneousHandlers);
54
54
  const waitForHandlers = flatGesture(waitFor);
@@ -75,9 +75,9 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
75
75
  const intersectionObservers = useContext(IntersectionObserverContext);
76
76
  const firstScrollIntoViewChange = useRef(true);
77
77
  const isContentSizeChange = useRef(false);
78
- const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, hasPositionFixed, setWidth, setHeight } = useTransformStyle(style, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
78
+ const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, hasPositionFixed, setWidth, setHeight } = useTransformStyle(style, { enableVar, parentWidth, parentHeight });
79
79
  const { textStyle, innerStyle = {} } = splitStyle(normalStyle);
80
- const textPassThrough = useTextPassThroughValue(textStyle, textProps);
80
+ const textPassThrough = useTextPassThrough(textStyle, textProps, { enableTextPassThrough });
81
81
  const scrollViewRef = useRef(null);
82
82
  const propsRef = useRef(props);
83
83
  const refresherStateRef = useRef({
@@ -120,7 +120,7 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
120
120
  }, []);
121
121
  const hasRefresherLayoutRef = useRef(false);
122
122
  // layout 完成前先隐藏,避免安卓闪烁问题
123
- const refresherLayoutStyle = useMemo(() => { return !hasRefresherLayoutRef.current ? HIDDEN_STYLE : {}; }, [hasRefresherLayoutRef.current]);
123
+ const refresherLayoutStyle = useMemo(() => { return !hasRefresherLayoutRef.current ? hiddenStyle : {}; }, [hasRefresherLayoutRef.current]);
124
124
  const lastOffset = useRef(0);
125
125
  if (scrollX && scrollY) {
126
126
  warn('scroll-x and scroll-y cannot be set to true at the same time, Mpx will use the value of scroll-y as the criterion');
@@ -667,7 +667,7 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
667
667
  ], { layoutRef });
668
668
  const ScrollViewComponent = enableSticky ? AnimatedScrollView : ScrollView;
669
669
  const createScrollViewContent = () => {
670
- const wrappedChildren = wrapChildren(hasRefresher ? extendObject({}, props, { children: otherContent }) : props, {
670
+ const wrappedChildren = wrapChildren(hasRefresher ? otherContent : props.children, {
671
671
  hasVarDec,
672
672
  varContext: varContextRef.current,
673
673
  textPassThrough
@@ -0,0 +1,51 @@
1
+ /// <reference types="react" />
2
+ import { GestureHandler } from './utils';
3
+ interface ListItem {
4
+ isSectionHeader?: boolean;
5
+ isSectionFooter?: boolean;
6
+ [key: string]: any;
7
+ }
8
+ interface ItemHeightType {
9
+ value?: number;
10
+ getter?: (item: any, index: number) => number;
11
+ }
12
+ interface MpxSectionListProps {
13
+ enhanced?: boolean;
14
+ bounces?: boolean;
15
+ height?: number | string;
16
+ width?: number | string;
17
+ generichash?: string;
18
+ style?: Record<string, any>;
19
+ 'scroll-event-throttle'?: number;
20
+ 'list-data'?: ListItem[];
21
+ 'item-height'?: ItemHeightType;
22
+ 'section-header-height'?: ItemHeightType;
23
+ 'section-footer-height'?: ItemHeightType;
24
+ 'list-header-data'?: any;
25
+ 'list-header-height'?: number;
26
+ 'use-list-header'?: boolean;
27
+ 'list-footer-data'?: any;
28
+ 'use-list-footer'?: boolean;
29
+ 'genericrecycle-item'?: string;
30
+ 'genericsection-header'?: string;
31
+ 'genericsection-footer'?: string;
32
+ 'genericlist-header'?: string;
33
+ 'genericlist-footer'?: string;
34
+ 'enable-var'?: boolean;
35
+ 'parent-width'?: number;
36
+ 'parent-height'?: number;
37
+ 'enable-sticky'?: boolean;
38
+ 'enable-back-to-top'?: boolean;
39
+ 'end-reached-threshold'?: number;
40
+ 'refresher-enabled'?: boolean;
41
+ 'show-scrollbar'?: boolean;
42
+ 'refresher-triggered'?: boolean;
43
+ 'wait-for'?: Array<GestureHandler>;
44
+ 'simultaneous-handlers'?: Array<GestureHandler>;
45
+ bindrefresherrefresh?: (event: any) => void;
46
+ bindscrolltolower?: (event: any) => void;
47
+ bindscroll?: (event: any) => void;
48
+ [key: string]: any;
49
+ }
50
+ declare const _SectionList: import("react").ForwardRefExoticComponent<Omit<MpxSectionListProps, "ref"> & import("react").RefAttributes<any>>;
51
+ export default _SectionList;
@@ -0,0 +1,376 @@
1
+ import { forwardRef, useRef, useMemo, createElement, useImperativeHandle } from 'react';
2
+ import { SectionList, RefreshControl } from 'react-native';
3
+ import { Gesture, GestureDetector } from 'react-native-gesture-handler';
4
+ import { hasOwn } from '@mpxjs/utils';
5
+ import useInnerProps, { getCustomEvent } from './getInnerListeners';
6
+ import { extendObject, useLayout, useTransformStyle, flatGesture, wrapChildren, splitStyle, useTextPassThrough, splitProps } from './utils';
7
+ import Portal from './mpx-portal';
8
+ const TypedSectionList = SectionList;
9
+ const getGeneric = (generichash, generickey) => {
10
+ if (!generichash || !generickey)
11
+ return null;
12
+ return global.__mpxGenericsMap?.[generichash]?.[generickey]?.() || null;
13
+ };
14
+ const _SectionList = forwardRef((sectionListProps = {}, ref) => {
15
+ const { textProps, innerProps: props = {} } = splitProps(sectionListProps);
16
+ const { enhanced = false, bounces = true, height, width, generichash, style = {}, 'list-data': listData, 'scroll-event-throttle': scrollEventThrottle = 0, 'item-height': itemHeight = {}, 'section-header-height': sectionHeaderHeight = {}, 'section-footer-height': sectionFooterHeight = {}, 'list-header-height': listHeaderHeight = 0, 'list-header-data': listHeaderData = null, 'use-list-header': useListHeader = false, 'list-footer-data': listFooterData = null, 'use-list-footer': useListFooter = false, 'genericrecycle-item': genericrecycleItem, 'genericsection-header': genericsectionHeader, 'genericsection-footer': genericsectionFooter, 'genericlist-header': genericListHeader, 'genericlist-footer': genericListFooter, 'enable-var': enableVar, 'enable-text-pass-through': enableTextPassThrough, 'parent-width': parentWidth, 'parent-height': parentHeight, 'enable-sticky': enableSticky = false, 'enable-back-to-top': enableBackToTop = false, 'end-reached-threshold': onEndReachedThreshold = 0.1, 'refresher-enabled': refresherEnabled, 'show-scrollbar': showScrollbar = true, 'refresher-triggered': refresherTriggered, 'simultaneous-handlers': originSimultaneousHandlers, 'wait-for': waitFor } = props;
17
+ const refreshing = !!refresherTriggered;
18
+ const scrollViewRef = useRef(null);
19
+ const sectionListGestureRef = useRef();
20
+ const indexMap = useRef({});
21
+ const reverseIndexMap = useRef({});
22
+ const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, hasPositionFixed, setWidth, setHeight } = useTransformStyle(style, { enableVar, parentWidth, parentHeight });
23
+ const { textStyle, innerStyle = {} } = splitStyle(normalStyle);
24
+ const textPassThrough = useTextPassThrough(textStyle, textProps, { enableTextPassThrough });
25
+ const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: scrollViewRef });
26
+ const onRefresh = () => {
27
+ const { bindrefresherrefresh } = props;
28
+ bindrefresherrefresh &&
29
+ bindrefresherrefresh(getCustomEvent('refresherrefresh', {}, { layoutRef }, props));
30
+ };
31
+ const onEndReached = () => {
32
+ const { bindscrolltolower } = props;
33
+ bindscrolltolower &&
34
+ bindscrolltolower(getCustomEvent('scrolltolower', {}, { layoutRef }, props));
35
+ };
36
+ const onScroll = (event) => {
37
+ const { bindscroll } = props;
38
+ if (bindscroll) {
39
+ const { nativeEvent } = event;
40
+ bindscroll(getCustomEvent('scroll', event, {
41
+ detail: {
42
+ scrollTop: nativeEvent.contentOffset.y
43
+ },
44
+ layoutRef
45
+ }, props));
46
+ }
47
+ };
48
+ // 通过sectionIndex和rowIndex获取原始索引
49
+ const getOriginalIndex = (sectionIndex, rowIndex) => {
50
+ const key = `${sectionIndex}_${rowIndex}`;
51
+ return reverseIndexMap.current[key] ?? -1; // 如果找不到,返回-1
52
+ };
53
+ const scrollToIndex = ({ index, animated, viewOffset = 0, viewPosition = 0 }) => {
54
+ if (!scrollViewRef.current)
55
+ return;
56
+ // 通过索引映射表快速定位位置
57
+ const position = indexMap.current[index];
58
+ if (!position)
59
+ return;
60
+ const [sectionIndex, itemIndex] = position.split('_');
61
+ const targetSectionIndex = Number(sectionIndex) || 0;
62
+ const targetItemIndex = itemIndex === 'header'
63
+ ? 0
64
+ : itemIndex === 'footer'
65
+ ? convertedListData[targetSectionIndex].data.length + 1
66
+ : Number(itemIndex) + 1;
67
+ scrollViewRef.current.scrollToLocation?.({
68
+ itemIndex: targetItemIndex,
69
+ sectionIndex: targetSectionIndex,
70
+ animated,
71
+ viewOffset,
72
+ viewPosition
73
+ });
74
+ };
75
+ const getItemHeight = ({ sectionIndex, rowIndex }) => {
76
+ if (!itemHeight) {
77
+ return 0;
78
+ }
79
+ if (itemHeight.getter) {
80
+ const item = convertedListData[sectionIndex].data[rowIndex];
81
+ // 使用getOriginalIndex获取原始索引
82
+ const originalIndex = getOriginalIndex(sectionIndex, rowIndex);
83
+ return itemHeight.getter?.(item, originalIndex) || 0;
84
+ }
85
+ else {
86
+ return itemHeight.value || 0;
87
+ }
88
+ };
89
+ const getSectionExtraHeight = ({ sectionIndex, type }) => {
90
+ const item = convertedListData[sectionIndex];
91
+ const isHeader = type === 'header';
92
+ if (!(isHeader ? item.hasSectionHeader : item.hasSectionFooter))
93
+ return 0;
94
+ const sectionExtraHeight = (isHeader ? sectionHeaderHeight : sectionFooterHeight);
95
+ if (sectionExtraHeight.getter) {
96
+ const sectionExtraData = isHeader ? item.headerData : item.footerData;
97
+ return sectionExtraHeight.getter?.(sectionExtraData, getOriginalIndex(sectionIndex, type)) || 0;
98
+ }
99
+ return sectionExtraHeight.value || 0;
100
+ };
101
+ const convertedListData = useMemo(() => {
102
+ const sections = [];
103
+ let currentSection = null;
104
+ // 清空之前的索引映射
105
+ indexMap.current = {};
106
+ // 清空反向索引映射
107
+ reverseIndexMap.current = {};
108
+ // 处理 listData 为空的情况
109
+ if (!listData || !listData.length) {
110
+ return sections;
111
+ }
112
+ listData.forEach((item, index) => {
113
+ if (item.isSectionHeader) {
114
+ // 如果已经存在一个 section,先把它添加到 sections 中
115
+ if (currentSection) {
116
+ sections.push(currentSection);
117
+ }
118
+ // 创建新的 section
119
+ currentSection = {
120
+ headerData: item,
121
+ footerData: null,
122
+ data: [],
123
+ hasSectionHeader: true,
124
+ hasSectionFooter: false
125
+ };
126
+ // 为 section header 添加索引映射
127
+ const sectionIndex = sections.length;
128
+ indexMap.current[index] = `${sectionIndex}_header`;
129
+ // 添加反向索引映射
130
+ reverseIndexMap.current[`${sectionIndex}_header`] = index;
131
+ }
132
+ else if (item.isSectionFooter) {
133
+ // 如果没有当前 section,创建一个默认的
134
+ if (!currentSection) {
135
+ // 创建默认section (无header的section)
136
+ currentSection = {
137
+ headerData: null,
138
+ footerData: null,
139
+ data: [],
140
+ hasSectionHeader: false,
141
+ hasSectionFooter: false
142
+ };
143
+ }
144
+ const sectionIndex = sections.length;
145
+ currentSection.footerData = item;
146
+ currentSection.hasSectionFooter = true;
147
+ indexMap.current[index] = `${sectionIndex}_footer`;
148
+ // 添加反向索引映射
149
+ reverseIndexMap.current[`${sectionIndex}_footer`] = index;
150
+ sections.push(currentSection);
151
+ currentSection = null;
152
+ }
153
+ else {
154
+ // 如果没有当前 section,创建一个默认的
155
+ if (!currentSection) {
156
+ // 创建默认section (无header的section)
157
+ currentSection = {
158
+ headerData: null,
159
+ footerData: null,
160
+ data: [],
161
+ hasSectionHeader: false,
162
+ hasSectionFooter: false
163
+ };
164
+ }
165
+ // 将 item 添加到当前 section 的 data 中
166
+ const itemIndex = currentSection.data.length;
167
+ currentSection.data.push(item);
168
+ let sectionIndex;
169
+ // 为 item 添加索引映射 - 存储格式为: "sectionIndex_itemIndex"
170
+ if (!currentSection.hasSectionHeader && sections.length === 0) {
171
+ // 在默认section中(第一个且无header)
172
+ sectionIndex = 0;
173
+ indexMap.current[index] = `${sectionIndex}_${itemIndex}`;
174
+ }
175
+ else {
176
+ // 在普通section中
177
+ sectionIndex = sections.length;
178
+ indexMap.current[index] = `${sectionIndex}_${itemIndex}`;
179
+ }
180
+ // 添加反向索引映射
181
+ reverseIndexMap.current[`${sectionIndex}_${itemIndex}`] = index;
182
+ }
183
+ });
184
+ // 添加最后一个 section
185
+ if (currentSection) {
186
+ sections.push(currentSection);
187
+ }
188
+ return sections;
189
+ }, [listData, listData?.length]);
190
+ const { getItemLayout } = useMemo(() => {
191
+ const layouts = [];
192
+ let offset = 0;
193
+ if (useListHeader) {
194
+ // 计算列表头部的高度
195
+ offset += listHeaderHeight;
196
+ }
197
+ // 遍历所有 sections
198
+ convertedListData.forEach((section, sectionIndex) => {
199
+ // 添加 section header 的位置信息
200
+ const headerHeight = getSectionExtraHeight({ sectionIndex, type: 'header' });
201
+ layouts.push({
202
+ length: headerHeight,
203
+ offset,
204
+ index: layouts.length
205
+ });
206
+ offset += headerHeight;
207
+ // 添加该 section 中所有 items 的位置信息
208
+ section.data.forEach((item, itemIndex) => {
209
+ const contentHeight = getItemHeight({ sectionIndex, rowIndex: itemIndex });
210
+ layouts.push({
211
+ length: contentHeight,
212
+ offset,
213
+ index: layouts.length
214
+ });
215
+ offset += contentHeight;
216
+ });
217
+ // 添加该 section 尾部位置信息
218
+ // 因为即使 sectionList 没传 renderSectionFooter,getItemLayout 中的 index 的计算也会包含尾部节点
219
+ const footerHeight = getSectionExtraHeight({ sectionIndex, type: 'footer' });
220
+ layouts.push({
221
+ length: footerHeight,
222
+ offset,
223
+ index: layouts.length
224
+ });
225
+ offset += footerHeight;
226
+ });
227
+ return {
228
+ itemLayouts: layouts,
229
+ getItemLayout: (data, index) => layouts[index]
230
+ };
231
+ }, [convertedListData, useListHeader, itemHeight.value, itemHeight.getter, sectionHeaderHeight.value, sectionHeaderHeight.getter, sectionFooterHeight.value, sectionFooterHeight.getter, listHeaderHeight]);
232
+ const scrollAdditionalProps = extendObject({
233
+ style: [
234
+ hasOwn(innerStyle, 'flex') || hasOwn(innerStyle, 'flexGrow') ? null : { flexGrow: 0 },
235
+ { height, width },
236
+ innerStyle,
237
+ layoutStyle
238
+ ],
239
+ alwaysBounceVertical: false,
240
+ alwaysBounceHorizontal: false,
241
+ scrollEventThrottle: scrollEventThrottle,
242
+ scrollsToTop: enableBackToTop,
243
+ showsVerticalScrollIndicator: showScrollbar,
244
+ onEndReachedThreshold,
245
+ ref: scrollViewRef,
246
+ bounces: enhanced ? bounces : false,
247
+ stickySectionHeadersEnabled: enableSticky,
248
+ onScroll: onScroll,
249
+ onEndReached: onEndReached
250
+ }, refresherEnabled ? { refreshing } : null, layoutProps);
251
+ const nativeGesture = useMemo(() => {
252
+ const simultaneousHandlers = flatGesture(originSimultaneousHandlers);
253
+ const waitForHandlers = flatGesture(waitFor);
254
+ const gesture = Gesture.Native().withRef(sectionListGestureRef);
255
+ if (simultaneousHandlers && simultaneousHandlers.length) {
256
+ gesture.simultaneousWithExternalGesture(...simultaneousHandlers);
257
+ }
258
+ if (waitForHandlers && waitForHandlers.length) {
259
+ gesture.requireExternalGestureToFail(...waitForHandlers);
260
+ }
261
+ return gesture;
262
+ }, [originSimultaneousHandlers, waitFor]);
263
+ useImperativeHandle(ref, () => {
264
+ return {
265
+ gestureRef: sectionListGestureRef,
266
+ scrollToIndex
267
+ };
268
+ });
269
+ const innerProps = useInnerProps(extendObject({}, props, scrollAdditionalProps), [
270
+ 'id',
271
+ 'enhanced',
272
+ 'height',
273
+ 'width',
274
+ 'list-data',
275
+ 'item-height',
276
+ 'section-header-height',
277
+ 'section-footer-height',
278
+ 'list-header-height',
279
+ 'list-header-data',
280
+ 'use-list-header',
281
+ 'list-footer-data',
282
+ 'use-list-footer',
283
+ 'genericrecycle-item',
284
+ 'genericsection-header',
285
+ 'genericsection-footer',
286
+ 'genericlist-header',
287
+ 'genericlist-footer',
288
+ 'enable-text-pass-through',
289
+ 'show-scrollbar',
290
+ 'lower-threshold',
291
+ 'scroll-event-throttle',
292
+ 'enable-sticky',
293
+ 'enable-back-to-top',
294
+ 'end-reached-threshold',
295
+ 'refresher-triggered',
296
+ 'refresher-enabled',
297
+ 'bindrefresherrefresh',
298
+ 'bindscrolltolower',
299
+ 'bindscroll',
300
+ 'simultaneous-handlers',
301
+ 'wait-for'
302
+ ], { layoutRef });
303
+ // 使用 useMemo 获取 GenericComponent 并创建渲染函数,避免每次组件更新都重新创建函数引用导致不必要的重新渲染
304
+ const renderItem = useMemo(() => {
305
+ const ItemComponent = getGeneric(generichash, genericrecycleItem);
306
+ if (!ItemComponent)
307
+ return undefined;
308
+ return ({ item }) => createElement(ItemComponent, { itemData: item });
309
+ }, [generichash, genericrecycleItem]);
310
+ const renderSectionHeader = useMemo(() => {
311
+ const SectionHeaderComponent = getGeneric(generichash, genericsectionHeader);
312
+ if (!SectionHeaderComponent)
313
+ return undefined;
314
+ return (sectionData) => {
315
+ if (!sectionData.section.hasSectionHeader)
316
+ return null;
317
+ return createElement(SectionHeaderComponent, { itemData: sectionData.section.headerData });
318
+ };
319
+ }, [generichash, genericsectionHeader]);
320
+ const renderSectionFooter = useMemo(() => {
321
+ const SectionFooterComponent = getGeneric(generichash, genericsectionFooter);
322
+ if (!SectionFooterComponent)
323
+ return undefined;
324
+ return (sectionData) => {
325
+ if (!sectionData.section.hasSectionFooter)
326
+ return null;
327
+ return createElement(SectionFooterComponent, { itemData: sectionData.section.footerData });
328
+ };
329
+ }, [generichash, genericsectionFooter]);
330
+ const ListHeaderGenericComponent = useMemo(() => {
331
+ if (!useListHeader)
332
+ return null;
333
+ return getGeneric(generichash, genericListHeader);
334
+ }, [useListHeader, generichash, genericListHeader]);
335
+ const ListFooterGenericComponent = useMemo(() => {
336
+ if (!useListFooter)
337
+ return null;
338
+ return getGeneric(generichash, genericListFooter);
339
+ }, [useListFooter, generichash, genericListFooter]);
340
+ const ListHeaderComponent = useMemo(() => {
341
+ if (!ListHeaderGenericComponent)
342
+ return null;
343
+ return createElement(ListHeaderGenericComponent, { listHeaderData });
344
+ }, [ListHeaderGenericComponent, listHeaderData]);
345
+ const ListFooterComponent = useMemo(() => {
346
+ if (!ListFooterGenericComponent)
347
+ return null;
348
+ return createElement(ListFooterGenericComponent, { listFooterData });
349
+ }, [ListFooterGenericComponent, listFooterData]);
350
+ const rnSectionListProps = extendObject({
351
+ sections: convertedListData,
352
+ renderItem: renderItem,
353
+ getItemLayout: getItemLayout,
354
+ ListHeaderComponent: useListHeader ? ListHeaderComponent : null,
355
+ ListFooterComponent: useListFooter ? ListFooterComponent : null,
356
+ renderSectionHeader: renderSectionHeader,
357
+ renderSectionFooter: renderSectionFooter,
358
+ refreshControl: refresherEnabled
359
+ ? createElement(RefreshControl, {
360
+ onRefresh: onRefresh,
361
+ refreshing: refreshing
362
+ })
363
+ : undefined
364
+ }, innerProps);
365
+ let sectionListComponent = wrapChildren(createElement(GestureDetector, { gesture: nativeGesture }, createElement(TypedSectionList, rnSectionListProps)), {
366
+ hasVarDec,
367
+ varContext: varContextRef.current,
368
+ textPassThrough
369
+ });
370
+ if (hasPositionFixed) {
371
+ sectionListComponent = createElement(Portal, null, sectionListComponent);
372
+ }
373
+ return sectionListComponent;
374
+ });
375
+ _SectionList.displayName = 'MpxSectionList';
376
+ export default _SectionList;