@mpxjs/webpack-plugin 2.9.65 → 2.9.66

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.
package/lib/index.js CHANGED
@@ -139,6 +139,7 @@ class MpxWebpackPlugin {
139
139
  options.writeMode = options.writeMode || 'changed'
140
140
  options.autoScopeRules = options.autoScopeRules || {}
141
141
  options.autoVirtualHostRules = options.autoVirtualHostRules || {}
142
+ options.customTextRules = options.customTextRules || {}
142
143
  options.forceDisableProxyCtor = options.forceDisableProxyCtor || false
143
144
  options.transMpxRules = options.transMpxRules || {
144
145
  include: () => true
@@ -173,6 +174,7 @@ class MpxWebpackPlugin {
173
174
  options.subpackageModulesRules = options.subpackageModulesRules || {}
174
175
  options.forceMainPackageRules = options.forceMainPackageRules || {}
175
176
  options.forceProxyEventRules = options.forceProxyEventRules || {}
177
+ options.disableRequireAsync = options.disableRequireAsync || false
176
178
  options.miniNpmPackages = options.miniNpmPackages || []
177
179
  options.fileConditionRules = options.fileConditionRules || {
178
180
  include: () => true
@@ -687,6 +689,7 @@ class MpxWebpackPlugin {
687
689
  projectName: this.options.projectName,
688
690
  autoScopeRules: this.options.autoScopeRules,
689
691
  autoVirtualHostRules: this.options.autoVirtualHostRules,
692
+ customTextRules: this.options.customTextRules,
690
693
  transRpxRules: this.options.transRpxRules,
691
694
  postcssInlineConfig: this.options.postcssInlineConfig,
692
695
  decodeHTMLText: this.options.decodeHTMLText,
@@ -708,7 +711,8 @@ class MpxWebpackPlugin {
708
711
  useRelativePath: this.options.useRelativePath,
709
712
  removedChunks: [],
710
713
  forceProxyEventRules: this.options.forceProxyEventRules,
711
- supportRequireAsync: this.options.mode === 'wx' || this.options.mode === 'ali' || this.options.mode === 'tt' || isWeb(this.options.mode),
714
+ // 若配置disableRequireAsync=true, 则全平台构建不支持异步分包
715
+ supportRequireAsync: !this.options.disableRequireAsync && (this.options.mode === 'wx' || this.options.mode === 'ali' || this.options.mode === 'tt' || isWeb(this.options.mode)),
712
716
  partialCompileRules: this.options.partialCompileRules,
713
717
  collectDynamicEntryInfo: ({ resource, packageName, filename, entryType, hasAsync }) => {
714
718
  const curInfo = mpx.dynamicEntryInfo[packageName] = mpx.dynamicEntryInfo[packageName] || {
@@ -190,12 +190,16 @@ module.exports = function getSpec ({ warn, error }) {
190
190
  flex: ['flexGrow', 'flexShrink', 'flexBasis'],
191
191
  // flex-flow: <'flex-direction'> or flex-flow: <'flex-direction'> and <'flex-wrap'>
192
192
  'flex-flow': ['flexDirection', 'flexWrap'],
193
- 'border-radius': ['borderTopLeftRadius', 'borderTopRightRadius', 'borderBottomRightRadius', 'borderBottomLeftRadius']
193
+ 'border-radius': ['borderTopLeftRadius', 'borderTopRightRadius', 'borderBottomRightRadius', 'borderBottomLeftRadius'],
194
+ 'border-width': ['borderTopWidth', 'borderRightWidth', 'borderBottomWidth', 'borderLeftWidth'],
195
+ 'border-color': ['borderTopColor', 'borderRightColor', 'borderBottomColor', 'borderLeftColor'],
196
+ margin: ['marginTop', 'marginRight', 'marginBottom', 'marginLeft'],
197
+ padding: ['paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft']
194
198
  }
195
199
  const formatAbbreviation = ({ prop, value, selector }, { mode }) => {
196
200
  const original = `${prop}:${value}`
197
201
  const props = AbbreviationMap[prop]
198
- const values = parseValues(value)
202
+ const values = Array.isArray(value) ? value : parseValues(value)
199
203
  const cssMap = []
200
204
  let idx = 0
201
205
  let propsIdx = 0
@@ -255,32 +259,20 @@ module.exports = function getSpec ({ warn, error }) {
255
259
  return cssMap
256
260
  }
257
261
 
258
- // margin padding
259
- const formatMargins = ({ prop, value, selector }) => {
260
- const values = parseValues(value)
261
- // format
262
- let suffix = []
262
+ const formatCompositeVal = ({ prop, value, selector }, { mode }) => {
263
+ const values = parseValues(value).splice(0, 4)
263
264
  switch (values.length) {
264
- // case 1:
265
+ case 1:
266
+ verifyValues({ prop, value, selector }, false)
267
+ return { prop, value }
265
268
  case 2:
266
- suffix = ['Vertical', 'Horizontal']
269
+ values.push(...values)
267
270
  break
268
271
  case 3:
269
- suffix = ['Top', 'Horizontal', 'Bottom']
270
- break
271
- case 4:
272
- suffix = ['Top', 'Right', 'Bottom', 'Left']
272
+ values.push(values[1])
273
273
  break
274
274
  }
275
- return values.map((value, index) => {
276
- const newProp = `${prop}${suffix[index] || ''}`
277
- // validate
278
- verifyValues({ prop: hump2dash(newProp), value, selector }, false)
279
- return {
280
- prop: newProp,
281
- value: value
282
- }
283
- })
275
+ return formatAbbreviation({ prop, value: values, selector }, { mode })
284
276
  }
285
277
 
286
278
  // line-height
@@ -374,22 +366,6 @@ module.exports = function getSpec ({ warn, error }) {
374
366
  return false
375
367
  }
376
368
 
377
- // border-radius 缩写转换
378
- const getBorderRadius = ({ prop, value, selector }, { mode }) => {
379
- const values = parseValues(value)
380
- if (values.length === 1) {
381
- verifyValues({ prop, value, selector }, false)
382
- return { prop, value }
383
- } else {
384
- if (values.length === 2) {
385
- values.push(...values)
386
- } else if (values.length === 3) {
387
- values.push(values[1])
388
- }
389
- return formatAbbreviation({ prop, value: values.join(' ') }, { mode })
390
- }
391
- }
392
-
393
369
  // transform 转换
394
370
  const formatTransform = ({ prop, value, selector }, { mode }) => {
395
371
  if (Array.isArray(value)) return { prop, value }
@@ -566,15 +542,10 @@ module.exports = function getSpec ({ warn, error }) {
566
542
  ios: checkBackgroundImage,
567
543
  android: checkBackgroundImage
568
544
  },
569
- {
570
- test: 'border-radius',
571
- ios: getBorderRadius,
572
- android: getBorderRadius
573
- },
574
545
  { // margin padding 内外边距的处理
575
- test: /^(margin|padding)$/,
576
- ios: formatMargins,
577
- android: formatMargins
546
+ test: /^(margin|padding|border-radius|border-width|border-color)$/,
547
+ ios: formatCompositeVal,
548
+ android: formatCompositeVal
578
549
  },
579
550
  { // line-height 换算
580
551
  test: 'line-height',
@@ -27,7 +27,8 @@ module.exports = function (template, {
27
27
  decodeHTMLText,
28
28
  externalClasses,
29
29
  checkUsingComponents,
30
- autoVirtualHostRules
30
+ autoVirtualHostRules,
31
+ customTextRules
31
32
  } = mpx
32
33
  const { resourcePath } = parseRequest(loaderContext.resource)
33
34
  const builtInComponentsMap = {}
@@ -84,7 +85,8 @@ module.exports = function (template, {
84
85
  globalComponents: [],
85
86
  // web模式下实现抽象组件
86
87
  componentGenerics,
87
- hasVirtualHost: matchCondition(resourcePath, autoVirtualHostRules)
88
+ hasVirtualHost: matchCondition(resourcePath, autoVirtualHostRules),
89
+ isCustomText: matchCondition(resourcePath, customTextRules)
88
90
  })
89
91
 
90
92
  if (meta.wxsContentMap) {
@@ -25,6 +25,12 @@ export interface FormContextValue {
25
25
  reset: () => void
26
26
  }
27
27
 
28
+ export interface IntersectionObserver {
29
+ [key: number]: {
30
+ throttleMeasure: () => void
31
+ }
32
+ }
33
+
28
34
  export const MovableAreaContext = createContext({ width: 0, height: 0 })
29
35
 
30
36
  export const FormContext = createContext<FormContextValue | null>(null)
@@ -38,3 +44,5 @@ export const LabelContext = createContext<LabelContextValue | null>(null)
38
44
  export const PickerContext = createContext(null)
39
45
 
40
46
  export const VarContext = createContext({})
47
+
48
+ export const IntersectionObserverContext = createContext<IntersectionObserver | null>(null)
@@ -6,3 +6,4 @@ export const RadioGroupContext = createContext(null);
6
6
  export const LabelContext = createContext(null);
7
7
  export const PickerContext = createContext(null);
8
8
  export const VarContext = createContext({});
9
+ export const IntersectionObserverContext = createContext(null);
@@ -33,15 +33,16 @@
33
33
  */
34
34
  import { ScrollView } from 'react-native-gesture-handler';
35
35
  import { RefreshControl } from 'react-native';
36
- import { useRef, useState, useEffect, forwardRef } from 'react';
36
+ import { useRef, useState, useEffect, forwardRef, useContext } from 'react';
37
37
  import { useAnimatedRef } from 'react-native-reanimated';
38
38
  import { warn } from '@mpxjs/utils';
39
39
  import useInnerProps, { getCustomEvent } from './getInnerListeners';
40
40
  import useNodesRef from './useNodesRef';
41
41
  import { splitProps, splitStyle, useTransformStyle, useLayout, wrapChildren } from './utils';
42
+ import { IntersectionObserverContext } from './context';
42
43
  const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
43
44
  const { textProps, innerProps: props = {} } = splitProps(scrollViewProps);
44
- const { enhanced = false, bounces = true, style = {}, 'scroll-x': scrollX = false, 'scroll-y': scrollY = false, 'enable-back-to-top': enableBackToTop = false, 'paging-enabled': pagingEnabled = false, 'upper-threshold': upperThreshold = 50, 'lower-threshold': lowerThreshold = 50, 'scroll-with-animation': scrollWithAnimation, 'refresher-enabled': refresherEnabled, 'refresher-default-style': refresherDefaultStyle, 'refresher-background': refresherBackground, 'show-scrollbar': showScrollbar = true, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight } = props;
45
+ const { enhanced = false, bounces = true, style = {}, '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, 'refresher-enabled': refresherEnabled, 'refresher-default-style': refresherDefaultStyle, 'refresher-background': refresherBackground, 'show-scrollbar': showScrollbar = true, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight } = props;
45
46
  const [refreshing, setRefreshing] = useState(true);
46
47
  const snapScrollTop = useRef(0);
47
48
  const snapScrollLeft = useRef(0);
@@ -56,6 +57,7 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
56
57
  const hasCallScrollToUpper = useRef(true);
57
58
  const hasCallScrollToLower = useRef(false);
58
59
  const initialTimeout = useRef(null);
60
+ const intersectionObservers = useContext(IntersectionObserverContext);
59
61
  const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, setWidth, setHeight } = useTransformStyle(style, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
60
62
  const { textStyle, innerStyle } = splitStyle(normalStyle);
61
63
  const scrollViewRef = useAnimatedRef();
@@ -173,6 +175,11 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
173
175
  layoutRef
174
176
  }, props));
175
177
  updateScrollOptions(e, { scrollLeft, scrollTop });
178
+ if (enableTriggerIntersectionObserver && intersectionObservers) {
179
+ for (const key in intersectionObservers) {
180
+ intersectionObservers[key].throttleMeasure();
181
+ }
182
+ }
176
183
  }
177
184
  function onScrollEnd(e) {
178
185
  const { bindscrollend } = props;
@@ -279,6 +286,7 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
279
286
  'scroll-x',
280
287
  'scroll-y',
281
288
  'enable-back-to-top',
289
+ 'enable-trigger-intersection-observer',
282
290
  'paging-enabled',
283
291
  'show-scrollbar',
284
292
  'upper-threshold',
@@ -67,6 +67,8 @@ const _Carouse = forwardRef((props, ref) => {
67
67
  const initOffsetIndex = initIndex + (props.circular && totalElements > 1 ? 1 : 0);
68
68
  const defaultX = (defaultWidth * initOffsetIndex) || 0;
69
69
  const defaultY = (defaultHeight * initOffsetIndex) || 0;
70
+ // 主动scorllTo时是否要出发onScrollEnd
71
+ const needTriggerScrollEnd = useRef(true);
70
72
  // 内部存储上一次的offset值
71
73
  const autoplayTimerRef = useRef(null);
72
74
  const scrollViewRef = useRef(null);
@@ -77,22 +79,21 @@ const _Carouse = forwardRef((props, ref) => {
77
79
  // 内部存储上一次的偏移量
78
80
  const internalsRef = useRef({
79
81
  offset: {
80
- x: defaultX || 0,
81
- y: defaultY || 0
82
+ x: 0,
83
+ y: 0
82
84
  },
83
85
  isScrolling: false
84
86
  });
85
87
  const isDragRef = useRef(false);
86
88
  const [state, setState] = useState({
87
- children: newChild,
88
89
  width: dir === 'x' && typeof defaultWidth === 'number' ? defaultWidth - previousMargin - nextMargin : defaultWidth,
89
90
  height: dir === 'y' && typeof defaultHeight === 'number' ? defaultHeight - previousMargin - nextMargin : defaultHeight,
90
91
  // 真正的游标索引, 从0开始
91
92
  index: initIndex,
92
93
  total: totalElements,
93
94
  offset: {
94
- x: dir === 'x' ? defaultX : 0,
95
- y: dir === 'y' ? defaultY : 0
95
+ x: 0,
96
+ y: 0
96
97
  },
97
98
  dir
98
99
  });
@@ -113,25 +114,38 @@ const _Carouse = forwardRef((props, ref) => {
113
114
  }, [props.autoplay, props.current, state.index, state.width, state.height]);
114
115
  useEffect(() => {
115
116
  // 确认这个是变化的props变化的时候才执行,还是初始化的时候就执行
116
- if (!props.autoplay && props.current !== state.index) {
117
+ if (!props.autoplay && props.current !== undefined && props.current !== state.index) {
117
118
  const initIndex = props.current || 0;
118
119
  // 这里要排除超过元素个数的设置
119
- const initOffsetIndex = initIndex + (props.circular && totalElements > 1 ? 1 : 0);
120
- const defaultX = (defaultWidth * initOffsetIndex) || 0;
121
- const offset = {
122
- x: dir === 'x' ? defaultX : 0,
123
- y: dir === 'y' ? defaultY : 0
124
- };
125
- state.offset = offset;
126
- internalsRef.current.offset = offset;
127
- setState((preState) => {
128
- return {
129
- ...preState,
130
- offset
131
- };
132
- });
120
+ const { nextIndex, nextOffset } = getMultiNextConfig(props.current);
121
+ // 1. 安卓需要主动更新下内部状态, 2. IOS不能触发完wcrollTo之后立即updateState, 会造成滑动两次
122
+ // 2. setTimeout 是fix 当再渲染过程中触发scrollTo失败的问题
123
+ if (Platform.OS === 'ios') {
124
+ needTriggerScrollEnd.current = false;
125
+ setTimeout(() => {
126
+ scrollViewRef.current?.scrollTo({
127
+ ...nextOffset,
128
+ animated: true
129
+ });
130
+ }, 50);
131
+ }
132
+ else {
133
+ updateState(nextIndex, nextOffset);
134
+ }
133
135
  }
134
- }, [props.current]);
136
+ }, [props.current, state.width, state.height]);
137
+ function getMultiNextConfig(target) {
138
+ const step = state.dir === 'x' ? state.width : state.height;
139
+ const targetPos = step * props.current;
140
+ const targetOffset = {
141
+ x: dir === 'x' ? targetPos : 0,
142
+ y: dir === 'y' ? targetPos : 0
143
+ };
144
+ return {
145
+ nextIndex: target,
146
+ nextOffset: targetOffset
147
+ };
148
+ }
135
149
  /**
136
150
  * @desc: 更新状态: index和offset, 并响应索引变化的事件
137
151
  * scrollViewOffset: 移动到的目标位置
@@ -181,7 +195,6 @@ const _Carouse = forwardRef((props, ref) => {
181
195
  nextIndex = isBack ? nextIndex - 2 : nextIndex;
182
196
  }
183
197
  if (!props.circular) {
184
- // nextIndex = isBack ? nextIndex - 2 : nextIndex
185
198
  nextOffset = Object.assign({}, currentOffset, { [state.dir]: step * nextIndex });
186
199
  }
187
200
  else {
@@ -230,13 +243,12 @@ const _Carouse = forwardRef((props, ref) => {
230
243
  createAutoPlay();
231
244
  return;
232
245
  }
233
- if (!Array.isArray(state.children)) {
246
+ if (!Array.isArray(props.children)) {
234
247
  return;
235
248
  }
236
249
  const step = state.dir === 'x' ? state.width : state.height;
237
250
  const { nextOffset, autoMoveOffset, isAutoEnd } = getNextConfig(state.offset);
238
251
  // 这里可以scroll到下一个元素, 但是把scrollView的偏移量在设置为content,视觉效果就没了吧
239
- // scrollViewRef.current?.scrollTo({ x: nextOffset['x'], y: nextOffset['y'], animated: true })
240
252
  if (Platform.OS === 'ios') {
241
253
  if (!isAutoEnd) {
242
254
  scrollViewRef.current?.scrollTo({ x: nextOffset.x, y: nextOffset.y, animated: true });
@@ -266,7 +278,6 @@ const _Carouse = forwardRef((props, ref) => {
266
278
  // 安卓无法实现视觉的无缝连接, 只能回到真正的位置, 且安卓调用scrollTo不能触发onMomentumScrollEnd,还未找到为啥
267
279
  if (state.dir === 'x') {
268
280
  scrollViewRef.current?.scrollTo({ x: step, y: step, animated: true });
269
- // scrollViewRef.current?.scrollTo({ x: autoMoveOffset.x, y: autoMoveOffset.y, animated: true })
270
281
  }
271
282
  else {
272
283
  scrollViewRef.current?.scrollTo({ x: autoMoveOffset.x, y: step, animated: true });
@@ -283,9 +294,15 @@ const _Carouse = forwardRef((props, ref) => {
283
294
  }
284
295
  /**
285
296
  * 当用户开始拖动结束
297
+ * 注意: 当手动调用scrollTo的时候, 安卓不会触发onMomentumScrollEnd, IOS会触发onMomentumScrollEnd
286
298
  */
287
299
  function onScrollEnd(event) {
288
- // 这里安卓好像没有触发onScrollEnd, 调用scrollTo的时候
300
+ if (Platform.OS === 'ios' && !needTriggerScrollEnd.current) {
301
+ const { nextIndex, nextOffset } = getMultiNextConfig(props.current);
302
+ updateState(nextIndex, nextOffset);
303
+ needTriggerScrollEnd.current = true;
304
+ return;
305
+ }
289
306
  if (totalElements === 1) {
290
307
  return;
291
308
  }
@@ -311,58 +328,41 @@ const _Carouse = forwardRef((props, ref) => {
311
328
  * @desc: 水平方向时,获取元素的布局,更新, 其中如果传递100%时需要依赖measure计算元算的宽高
312
329
  */
313
330
  function onWrapperLayout(e) {
314
- if (hasSelfPercent) {
315
- const { width, height } = e?.nativeEvent?.layout || {};
316
- setWidth(width || 0);
317
- setHeight(height || 0);
318
- }
319
- if (props.enableOffset) {
320
- scrollViewRef.current?.measure((x, y, width, height, offsetLeft, offsetTop) => {
321
- layoutRef.current = { x, y, width, height, offsetLeft, offsetTop };
322
- const isWDiff = state.width !== width;
323
- const isHDiff = state.height !== height;
324
- if (isWDiff || isHDiff) {
325
- const changeState = {
326
- width: isWDiff ? width : state.width,
327
- height: isHDiff ? height : state.height
331
+ scrollViewRef.current?.measure((x, y, width, height, offsetLeft, offsetTop) => {
332
+ layoutRef.current = { x, y, width, height, offsetLeft, offsetTop };
333
+ const isWDiff = state.width !== width;
334
+ const isHDiff = state.height !== height;
335
+ if (isWDiff || isHDiff) {
336
+ const changeState = {
337
+ width: isWDiff ? width : state.width,
338
+ height: isHDiff ? height : state.height
339
+ };
340
+ const attr = state.dir === 'x' ? 'width' : 'height';
341
+ changeState[attr] = changeState[attr] - previousMargin - nextMargin;
342
+ const correctOffset = Object.assign({}, state.offset, {
343
+ [state.dir]: initOffsetIndex * (state.dir === 'x' ? changeState.width : changeState.height)
344
+ });
345
+ state.width = changeState.width;
346
+ state.height = changeState.height;
347
+ // 这里setState之后,会再触发重新渲染, renderScrollView会再次触发onScrollEnd,
348
+ setState((preState) => {
349
+ return {
350
+ ...preState,
351
+ width: changeState.width,
352
+ height: changeState.height
328
353
  };
329
- const attr = state.dir === 'x' ? 'width' : 'height';
330
- changeState[attr] = changeState[attr] - previousMargin - nextMargin;
331
- const correctOffset = Object.assign({}, state.offset, {
332
- [state.dir]: initOffsetIndex * (state.dir === 'x' ? changeState.width : changeState.height)
333
- });
334
- state.offset = correctOffset;
335
- state.width = changeState.width;
336
- state.height = changeState.height;
337
- setState((preState) => {
338
- return {
339
- ...preState,
340
- offset: correctOffset,
341
- width: changeState.width,
342
- height: changeState.height
343
- };
344
- });
345
- scrollViewRef.current?.scrollTo({ x: correctOffset.x, y: correctOffset.y, animated: false });
346
- }
347
- props.getInnerLayout && props.getInnerLayout(layoutRef);
348
- });
349
- }
354
+ });
355
+ }
356
+ props.getInnerLayout && props.getInnerLayout(layoutRef);
357
+ });
350
358
  }
351
359
  function getOffset() {
352
360
  const step = state.dir === 'x' ? state.width : state.height;
353
361
  if (!step || Number.isNaN(+step))
354
362
  return [];
355
363
  const offsetArray = [];
356
- if (previousMargin) {
357
- offsetArray.push(0);
358
- for (let i = 1; i < totalElements; i++) {
359
- offsetArray.push(i * step - previousMargin);
360
- }
361
- }
362
- else {
363
- for (let i = 0; i < totalElements; i++) {
364
- offsetArray.push(i * step);
365
- }
364
+ for (let i = 0; i < totalElements; i++) {
365
+ offsetArray.push(i * step);
366
366
  }
367
367
  return offsetArray;
368
368
  }
@@ -371,7 +371,7 @@ const _Carouse = forwardRef((props, ref) => {
371
371
  const scrollElementProps = {
372
372
  ref: scrollViewRef,
373
373
  horizontal: props.horizontal,
374
- pagingEnabled: false,
374
+ pagingEnabled: true,
375
375
  snapToOffsets: offsetsArray,
376
376
  decelerationRate: 0.99,
377
377
  showsHorizontalScrollIndicator: false,
@@ -423,20 +423,21 @@ const _Carouse = forwardRef((props, ref) => {
423
423
  </View>);
424
424
  }
425
425
  function renderPages() {
426
- const { width, height, total, children } = state;
426
+ const { width, height } = state;
427
+ const { children } = props;
427
428
  const { circular } = props;
428
429
  const pageStyle = { width: width, height: height };
429
430
  // 设置了previousMargin或者nextMargin,
430
431
  // 1. 元素的宽度是减去这两个数目之和
431
432
  // 2. previousMargin设置marginLeft正值, nextmargin设置marginRight负值
432
433
  // 3. 第一个元素设置previousMargin 和 nextMargin, 最后一个元素
433
- if (total > 1 && Array.isArray(children)) {
434
+ if (totalElements > 1 && Array.isArray(children)) {
434
435
  let arrElements = [];
435
436
  // pages = ["2", "0", "1", "2", "0"]
436
437
  const pages = Array.isArray(children) ? Object.keys(children) : [];
437
438
  /* 无限循环的时候 */
438
439
  if (circular) {
439
- pages.unshift(total - 1 + '');
440
+ pages.unshift(totalElements - 1 + '');
440
441
  pages.push('0');
441
442
  }
442
443
  arrElements = pages.map((page, i) => {
@@ -447,7 +448,6 @@ const _Carouse = forwardRef((props, ref) => {
447
448
  else if (i === pages.length - 1 && typeof width === 'number') {
448
449
  nextMargin && (extraStyle.marginRight = nextMargin);
449
450
  }
450
- // return (<View style={[pageStyle, styles.slide, extraStyle]} key={ 'page' + i}>{children[+page]}</View>)
451
451
  return (<View style={[pageStyle, styles.slide, extraStyle]} key={'page' + i}>
452
452
  {wrapChildren({
453
453
  children: children[+page]
@@ -7,6 +7,8 @@
7
7
  import { View, StyleSheet, Image } from 'react-native';
8
8
  import { useRef, useState, useEffect, forwardRef } from 'react';
9
9
  import useInnerProps from './getInnerListeners';
10
+ import Animated from 'react-native-reanimated';
11
+ import useAnimationHooks from './useAnimationHooks';
10
12
  import useNodesRef from './useNodesRef';
11
13
  import { parseUrl, PERCENT_REGEX, splitStyle, splitProps, useTransformStyle, wrapChildren, useLayout } from './utils';
12
14
  import LinearGradient from 'react-native-linear-gradient';
@@ -527,7 +529,7 @@ function wrapWithChildren(props, { hasVarDec, enableBackground, textStyle, backg
527
529
  }
528
530
  const _View = forwardRef((viewProps, ref) => {
529
531
  const { textProps, innerProps: props = {} } = splitProps(viewProps);
530
- let { style = {}, 'hover-style': hoverStyle, 'hover-start-time': hoverStartTime = 50, 'hover-stay-time': hoverStayTime = 400, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'enable-background': enableBackground, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight } = props;
532
+ let { style = {}, 'hover-style': hoverStyle, 'hover-start-time': hoverStartTime = 50, 'hover-stay-time': hoverStayTime = 400, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'enable-background': enableBackground, 'enable-animation': enableAnimation, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, animation } = props;
531
533
  const [isHover, setIsHover] = useState(false);
532
534
  // 默认样式
533
535
  const defaultStyle = {
@@ -592,9 +594,10 @@ const _View = forwardRef((viewProps, ref) => {
592
594
  setStayTimer();
593
595
  }
594
596
  const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef });
597
+ const viewStyle = Object.assign({}, innerStyle, layoutStyle);
595
598
  const innerProps = useInnerProps(props, {
596
599
  ref: nodeRef,
597
- style: { ...innerStyle, ...layoutStyle },
600
+ style: viewStyle,
598
601
  ...layoutProps,
599
602
  ...(hoverStyle && {
600
603
  bindtouchstart: onTouchStart,
@@ -608,15 +611,31 @@ const _View = forwardRef((viewProps, ref) => {
608
611
  ], {
609
612
  layoutRef
610
613
  });
611
- return (<View {...innerProps}>
612
- {wrapWithChildren(props, {
613
- hasVarDec,
614
- enableBackground: enableBackgroundRef.current,
615
- textStyle,
616
- backgroundStyle,
617
- varContext: varContextRef.current,
618
- textProps
619
- })}
614
+ enableAnimation = enableAnimation || !!animation;
615
+ const enableAnimationRef = useRef(enableAnimation);
616
+ if (enableAnimationRef.current !== enableAnimation) {
617
+ throw new Error('[Mpx runtime error]: animation use should be stable in the component lifecycle, or you can set [enable-animation] with true.');
618
+ }
619
+ const finalStyle = enableAnimation
620
+ ? useAnimationHooks({
621
+ animation,
622
+ style: viewStyle
623
+ })
624
+ : viewStyle;
625
+ const childNode = wrapWithChildren(props, {
626
+ hasVarDec,
627
+ enableBackground: enableBackgroundRef.current,
628
+ textStyle,
629
+ backgroundStyle,
630
+ varContext: varContextRef.current,
631
+ textProps
632
+ });
633
+ return animation?.actions?.length
634
+ ? (<Animated.View {...innerProps} style={finalStyle}>
635
+ {childNode}
636
+ </Animated.View>)
637
+ : (<View {...innerProps}>
638
+ {childNode}
620
639
  </View>);
621
640
  });
622
641
  _View.displayName = 'mpx-view';
@@ -6,7 +6,7 @@ import { promisify, redirectTo, navigateTo, navigateBack, reLaunch, switchTab }
6
6
  import { WebView } from 'react-native-webview';
7
7
  import useNodesRef from './useNodesRef';
8
8
  const _WebView = forwardRef((props, ref) => {
9
- const { src, bindmessage = noop, bindload = noop, binderror = noop } = props;
9
+ const { src = '', bindmessage = noop, bindload = noop, binderror = noop } = props;
10
10
  if (props.style) {
11
11
  warn('The web-view component does not support the style prop.');
12
12
  }