@mpxjs/webpack-plugin 2.10.18-beta.11 → 2.10.18-beta.12

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.
@@ -135,27 +135,18 @@ function getClassMap ({ content, filename, mode, srcMode, ctorType, formatValueN
135
135
  if (classMapKeys.length) {
136
136
  classMapKeys.forEach((key) => {
137
137
  if (Object.keys(classMapValue).length) {
138
- let _default = classMap[key]?._default
139
- let _media = classMap[key]?._media
138
+ // set css defalut value
139
+ const val = classMap[key] || {}
140
+ classMap[key] = Object.assign(val, classMapValue)
141
+
142
+ // set css media
140
143
  if (isMedia) {
141
- // 当前是媒体查询
142
- _default = _default || {}
143
- _media = _media || []
144
+ const _media = classMap[key]?._media || []
144
145
  _media.push({
145
146
  options,
146
147
  value: classMapValue
147
148
  })
148
- classMap[key] = {
149
- _media,
150
- _default
151
- }
152
- } else if (_default) {
153
- // 已有媒体查询数据,此次非媒体查询
154
- Object.assign(_default, classMapValue)
155
- } else {
156
- // 无媒体查询
157
- const val = classMap[key] || {}
158
- classMap[key] = Object.assign(val, classMapValue)
149
+ classMap[key]._media = _media
159
150
  }
160
151
  }
161
152
  })
@@ -144,7 +144,7 @@ function parseTransitionStyle (originalStyle: ExtendedViewStyle) {
144
144
  const transitionMap = transitionData.reduce((acc, cur) => {
145
145
  // hasOwn(transitionSupportedProperty, dash2hump(val)) || val === Transform
146
146
  const { property = '', duration = 0, delay = 0, easing = Easing.inOut(Easing.ease) } = cur
147
- if ((hasOwn(transitionSupportedProperty, dash2hump(property)) || property === 'transform') && duration > 0) {
147
+ if ((hasOwn(transitionSupportedProperty, dash2hump(property)) || property === 'transform') && duration >= 0) {
148
148
  acc[property] = {
149
149
  duration,
150
150
  delay,
@@ -157,17 +157,59 @@ function parseTransitionStyle (originalStyle: ExtendedViewStyle) {
157
157
  return transitionMap
158
158
  }
159
159
 
160
+ const transitionKeys = ['transition', 'transitionDuration', 'transitionTimingFunction', 'transitionDelay', 'transitionProperty'] as const
161
+
162
+ function getTransitionPropertyKeys (map: TransitionMap): string {
163
+ return Object.keys(map).sort().join(',')
164
+ }
165
+
160
166
  export default function useTransitionHooks<T, P> (props: AnimationHooksPropsType) {
161
167
  // console.log(`useTransitionHooks, props=`, props)
162
168
  const { style: originalStyle = {}, transitionend } = props
163
169
  // style变更标识(首次render不执行),初始值为0,首次渲染后为1
164
170
  const animationDeps = useRef(0)
165
- // 记录上次style map
166
- // const lastStyleRef = useRef({} as {[propName: keyof ExtendedViewStyle]: number|string})
167
- // ** style 中获取动画数据
171
+ // transition 时序属性动态更新追踪
172
+ const transitionMapVersionRef = useRef(0)
173
+ const lastTransitionStyleRef = useRef<Record<string, any>>(
174
+ transitionKeys.reduce((acc, key) => { acc[key] = originalStyle[key]; return acc }, {} as Record<string, any>)
175
+ )
176
+ const initialPropertyKeysRef = useRef('')
177
+ const prevTransitionMapRef = useRef<TransitionMap>({})
178
+ // 检测 transition 时序属性变化,返回版本号驱动 transitionMap 重新计算
179
+ const transitionMapVersion = useMemo(() => {
180
+ const prevStyle = lastTransitionStyleRef.current
181
+ const hasChanged = transitionKeys.some(key => prevStyle[key] !== originalStyle[key])
182
+ if (hasChanged) {
183
+ transitionKeys.forEach(key => { lastTransitionStyleRef.current[key] = originalStyle[key] })
184
+ transitionMapVersionRef.current++
185
+ }
186
+ return transitionMapVersionRef.current
187
+ }, [originalStyle])
188
+ // ** 从 style 中获取动画数据(支持动态更新 transitionDuration/transitionDelay/transitionTimingFunction)
168
189
  const transitionMap = useMemo(() => {
169
- return parseTransitionStyle(originalStyle)
170
- }, [])
190
+ const newTransitionMap = parseTransitionStyle(originalStyle)
191
+ const newPropertyKeys = getTransitionPropertyKeys(newTransitionMap)
192
+ if (!initialPropertyKeysRef.current) {
193
+ // 首次计算,记录初始属性集合
194
+ initialPropertyKeysRef.current = newPropertyKeys
195
+ prevTransitionMapRef.current = newTransitionMap
196
+ return newTransitionMap
197
+ }
198
+ // 检测 transitionProperty 是否变化
199
+ if (newPropertyKeys !== initialPropertyKeysRef.current) {
200
+ error('[Mpx runtime error]: dynamic setting transitionProperty is not supported')
201
+ // 保留初始属性集合,仅更新已有属性的时序
202
+ const prevMap = prevTransitionMapRef.current
203
+ const result = Object.keys(prevMap).reduce((map, property) => {
204
+ map[property] = newTransitionMap[property] || prevMap[property]
205
+ return map
206
+ }, {} as TransitionMap)
207
+ prevTransitionMapRef.current = result
208
+ return result
209
+ }
210
+ prevTransitionMapRef.current = newTransitionMap
211
+ return newTransitionMap
212
+ }, [transitionMapVersion])
171
213
  // ** style prop sharedValue interpolateOutput: SharedValue<InterpolateOutput>
172
214
  const { shareValMap, animatedKeys, animatedStyleKeys } = useMemo(() => {
173
215
  // 记录需要执行动画的 propName
@@ -117,7 +117,7 @@ function parseTransitionStyle(originalStyle) {
117
117
  const transitionMap = transitionData.reduce((acc, cur) => {
118
118
  // hasOwn(transitionSupportedProperty, dash2hump(val)) || val === Transform
119
119
  const { property = '', duration = 0, delay = 0, easing = Easing.inOut(Easing.ease) } = cur;
120
- if ((hasOwn(transitionSupportedProperty, dash2hump(property)) || property === 'transform') && duration > 0) {
120
+ if ((hasOwn(transitionSupportedProperty, dash2hump(property)) || property === 'transform') && duration >= 0) {
121
121
  acc[property] = {
122
122
  duration,
123
123
  delay,
@@ -129,17 +129,55 @@ function parseTransitionStyle(originalStyle) {
129
129
  // console.log(`parseTransitionStyle transitionMap=`, transitionMap)
130
130
  return transitionMap;
131
131
  }
132
+ const transitionKeys = ['transition', 'transitionDuration', 'transitionTimingFunction', 'transitionDelay', 'transitionProperty'];
133
+ function getTransitionPropertyKeys(map) {
134
+ return Object.keys(map).sort().join(',');
135
+ }
132
136
  export default function useTransitionHooks(props) {
133
137
  // console.log(`useTransitionHooks, props=`, props)
134
138
  const { style: originalStyle = {}, transitionend } = props;
135
139
  // style变更标识(首次render不执行),初始值为0,首次渲染后为1
136
140
  const animationDeps = useRef(0);
137
- // 记录上次style map
138
- // const lastStyleRef = useRef({} as {[propName: keyof ExtendedViewStyle]: number|string})
139
- // ** style 中获取动画数据
141
+ // transition 时序属性动态更新追踪
142
+ const transitionMapVersionRef = useRef(0);
143
+ const lastTransitionStyleRef = useRef(transitionKeys.reduce((acc, key) => { acc[key] = originalStyle[key]; return acc; }, {}));
144
+ const initialPropertyKeysRef = useRef('');
145
+ const prevTransitionMapRef = useRef({});
146
+ // 检测 transition 时序属性变化,返回版本号驱动 transitionMap 重新计算
147
+ const transitionMapVersion = useMemo(() => {
148
+ const prevStyle = lastTransitionStyleRef.current;
149
+ const hasChanged = transitionKeys.some(key => prevStyle[key] !== originalStyle[key]);
150
+ if (hasChanged) {
151
+ transitionKeys.forEach(key => { lastTransitionStyleRef.current[key] = originalStyle[key]; });
152
+ transitionMapVersionRef.current++;
153
+ }
154
+ return transitionMapVersionRef.current;
155
+ }, [originalStyle]);
156
+ // ** 从 style 中获取动画数据(支持动态更新 transitionDuration/transitionDelay/transitionTimingFunction)
140
157
  const transitionMap = useMemo(() => {
141
- return parseTransitionStyle(originalStyle);
142
- }, []);
158
+ const newTransitionMap = parseTransitionStyle(originalStyle);
159
+ const newPropertyKeys = getTransitionPropertyKeys(newTransitionMap);
160
+ if (!initialPropertyKeysRef.current) {
161
+ // 首次计算,记录初始属性集合
162
+ initialPropertyKeysRef.current = newPropertyKeys;
163
+ prevTransitionMapRef.current = newTransitionMap;
164
+ return newTransitionMap;
165
+ }
166
+ // 检测 transitionProperty 是否变化
167
+ if (newPropertyKeys !== initialPropertyKeysRef.current) {
168
+ error('[Mpx runtime error]: dynamic setting transitionProperty is not supported');
169
+ // 保留初始属性集合,仅更新已有属性的时序
170
+ const prevMap = prevTransitionMapRef.current;
171
+ const result = Object.keys(prevMap).reduce((map, property) => {
172
+ map[property] = newTransitionMap[property] || prevMap[property];
173
+ return map;
174
+ }, {});
175
+ prevTransitionMapRef.current = result;
176
+ return result;
177
+ }
178
+ prevTransitionMapRef.current = newTransitionMap;
179
+ return newTransitionMap;
180
+ }, [transitionMapVersion]);
143
181
  // ** style prop sharedValue interpolateOutput: SharedValue<InterpolateOutput>
144
182
  const { shareValMap, animatedKeys, animatedStyleKeys } = useMemo(() => {
145
183
  // 记录需要执行动画的 propName
@@ -40,7 +40,7 @@
40
40
  import { forwardRef, useRef, useState, useContext, useEffect, createElement } from 'react';
41
41
  import { TextInput } from 'react-native';
42
42
  import { warn } from '@mpxjs/utils';
43
- import { useUpdateEffect, useTransformStyle, useLayout, extendObject, isAndroid } from './utils';
43
+ import { useUpdateEffect, useTransformStyle, useLayout, extendObject } from './utils';
44
44
  import useInnerProps, { getCustomEvent } from './getInnerListeners';
45
45
  import useNodesRef from './useNodesRef';
46
46
  import { FormContext, KeyboardAvoidContext } from './context';
@@ -285,11 +285,6 @@ const Input = forwardRef((props, ref) => {
285
285
  ? nodeRef.current?.focus()
286
286
  : nodeRef.current?.blur();
287
287
  }, [isAutoFocus]);
288
- // 使用 multiline 来修复光标位置问题
289
- // React Native 的 TextInput 在 textAlign center + placeholder 时光标会跑到右边
290
- // 这个问题只在 Android 上出现
291
- // 参考:https://github.com/facebook/react-native/issues/28794 (Android only)
292
- const needMultilineFix = isAndroid && !multiline;
293
288
  const innerProps = useInnerProps(extendObject({}, props, layoutProps, {
294
289
  ref: nodeRef,
295
290
  style: extendObject({}, normalStyle, layoutStyle),
@@ -308,7 +303,7 @@ const Input = forwardRef((props, ref) => {
308
303
  underlineColorAndroid: 'rgba(0,0,0,0)',
309
304
  textAlignVertical: textAlignVertical,
310
305
  placeholderTextColor: placeholderStyle?.color,
311
- multiline: multiline || needMultilineFix,
306
+ multiline: !!multiline,
312
307
  onTouchStart,
313
308
  onTouchEnd,
314
309
  onFocus,
@@ -317,7 +312,7 @@ const Input = forwardRef((props, ref) => {
317
312
  onSelectionChange,
318
313
  onContentSizeChange,
319
314
  onSubmitEditing: bindconfirm && onSubmitEditing
320
- }, needMultilineFix ? { numberOfLines: 1 } : {}, !!multiline && confirmType === 'return' ? {} : { enterKeyHint: confirmType }), [
315
+ }, !!multiline && confirmType === 'return' ? {} : { enterKeyHint: confirmType }), [
321
316
  'type',
322
317
  'password',
323
318
  'placeholder-style',
@@ -73,6 +73,15 @@ const _PickerViewColumn = forwardRef((props, ref) => {
73
73
  clearTimerScrollTo();
74
74
  };
75
75
  }, []);
76
+ // `contentOffset` prop sets visual position but does not fire scroll events,
77
+ // so `offsetYShared` (from `useScrollViewOffset`) stays at 0 until the user scrolls.
78
+ // Directly sync it whenever `itemRawH` is established so wheel animation renders correctly.
79
+ useEffect(() => {
80
+ if (!itemRawH || dragging.current || scrolling.current) {
81
+ return;
82
+ }
83
+ offsetYShared.value = activeIndex.current * itemRawH;
84
+ }, [itemRawH]);
76
85
  useEffect(() => {
77
86
  if (!scrollViewRef.current ||
78
87
  !itemRawH ||
@@ -58,6 +58,7 @@ interface SwiperProps {
58
58
  disableGesture?: boolean;
59
59
  'display-multiple-items'?: number;
60
60
  bindchange?: (event: NativeSyntheticEvent<TouchEvent> | unknown) => void;
61
+ bindchangestart?: (event: NativeSyntheticEvent<TouchEvent> | unknown) => void;
61
62
  }
62
63
  declare const SwiperWrapper: React.ForwardRefExoticComponent<SwiperProps & React.RefAttributes<HandlerRef<View, SwiperProps>>>;
63
64
  export default SwiperWrapper;
@@ -61,7 +61,7 @@ const easeMap = {
61
61
  easeInOutCubic: Easing.inOut(Easing.cubic)
62
62
  };
63
63
  const SwiperWrapper = forwardRef((props, ref) => {
64
- const { 'indicator-dots': showPagination, 'indicator-color': dotColor = 'rgba(0, 0, 0, .3)', 'indicator-width': dotWidth = 8, 'indicator-height': dotHeight = 8, 'indicator-radius': dotRadius = 4, 'indicator-spacing': dotSpacing = 4, 'indicator-margin': paginationMargin = 10, 'indicator-active-color': activeDotColor = '#000000', 'enable-var': enableVar = false, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, 'external-var-context': externalVarContext, 'simultaneous-handlers': originSimultaneousHandlers = [], 'wait-for': waitFor = [], style = {}, autoplay = false, circular = false, disableGesture = false, current: propCurrent = 0, bindchange } = props;
64
+ const { 'indicator-dots': showPagination, 'indicator-color': dotColor = 'rgba(0, 0, 0, .3)', 'indicator-width': dotWidth = 8, 'indicator-height': dotHeight = 8, 'indicator-radius': dotRadius = 4, 'indicator-spacing': dotSpacing = 4, 'indicator-margin': paginationMargin = 10, 'indicator-active-color': activeDotColor = '#000000', 'enable-var': enableVar = false, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, 'external-var-context': externalVarContext, 'simultaneous-handlers': originSimultaneousHandlers = [], 'wait-for': waitFor = [], style = {}, autoplay = false, circular = false, disableGesture = false, current: propCurrent = 0, bindchange, bindchangestart } = props;
65
65
  const dotCommonStyle = {
66
66
  width: dotWidth,
67
67
  height: dotHeight,
@@ -300,6 +300,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
300
300
  nextIndex += 1;
301
301
  // targetOffset = -nextIndex * step.value - preMarginShared.value
302
302
  targetOffset = -nextIndex * step.value;
303
+ runOnJSCallback('handleSwiperChangeStart', nextIndex);
303
304
  offset.value = withTiming(targetOffset, {
304
305
  duration: easeDuration,
305
306
  easing: easeMap[easeingFunc]
@@ -314,6 +315,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
314
315
  nextIndex = 0;
315
316
  targetOffset = -(childrenLength.value + patchElmNumShared.value) * step.value + preMarginShared.value;
316
317
  // 执行动画到下一帧
318
+ runOnJSCallback('handleSwiperChangeStart', nextIndex);
317
319
  offset.value = withTiming(targetOffset, {
318
320
  duration: easeDuration
319
321
  }, () => {
@@ -328,6 +330,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
328
330
  nextIndex = currentIndex.value + 1;
329
331
  targetOffset = -(nextIndex + patchElmNumShared.value) * step.value + preMarginShared.value;
330
332
  // 执行动画到下一帧
333
+ runOnJSCallback('handleSwiperChangeStart', nextIndex);
331
334
  offset.value = withTiming(targetOffset, {
332
335
  duration: easeDuration,
333
336
  easing: easeMap[easeingFunc]
@@ -362,11 +365,16 @@ const SwiperWrapper = forwardRef((props, ref) => {
362
365
  const eventData = getCustomEvent('change', {}, { detail: { current, source: 'touch' }, layoutRef: layoutRef });
363
366
  bindchange && bindchange(eventData);
364
367
  }
368
+ function handleSwiperChangeStart(current) {
369
+ const eventData = getCustomEvent('changestart', {}, { detail: { current }, layoutRef: layoutRef });
370
+ bindchangestart && bindchangestart(eventData);
371
+ }
365
372
  const runOnJSCallbackRef = useRef({
366
373
  loop,
367
374
  pauseLoop,
368
375
  resumeLoop,
369
- handleSwiperChange
376
+ handleSwiperChange,
377
+ handleSwiperChangeStart
370
378
  });
371
379
  const runOnJSCallback = useRunOnJSCallback(runOnJSCallbackRef);
372
380
  function getOffset(index, stepValue) {
@@ -387,6 +395,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
387
395
  if (targetOffset !== offset.value) {
388
396
  // 内部基于props.current!==currentIndex.value决定是否使用动画及更新currentIndex.value
389
397
  if (propCurrent !== undefined && propCurrent !== currentIndex.value) {
398
+ runOnJSCallback('handleSwiperChangeStart', propCurrent);
390
399
  offset.value = withTiming(targetOffset, {
391
400
  duration: easeDuration,
392
401
  easing: easeMap[easeingFunc]
@@ -686,7 +695,10 @@ const SwiperWrapper = forwardRef((props, ref) => {
686
695
  const offsetHalf = computeHalf();
687
696
  if (childrenLength.value > 1 && offsetHalf) {
688
697
  const { selectedIndex } = getTargetPosition({ transdir: moveDistance });
689
- currentIndex.value = selectedIndex;
698
+ if (selectedIndex !== currentIndex.value) {
699
+ currentIndex.value = selectedIndex;
700
+ runOnJS(runOnJSCallback)('handleSwiperChangeStart', selectedIndex);
701
+ }
690
702
  }
691
703
  // 2. 非循环: 处理用户一直拖拽到临界点的场景,如果放到onFinalize无法阻止offset.value更新为越界的值
692
704
  if (!circularShared.value) {
@@ -285,7 +285,7 @@ export function parseValues(str, char = ' ') {
285
285
  function parseTransform(transformStr) {
286
286
  const values = parseValues(transformStr);
287
287
  // Todo transform 排序不一致时,transform动画会闪烁,故这里同样的排序输出 transform
288
- values.sort();
288
+ // values.sort()
289
289
  const transform = [];
290
290
  values.forEach(item => {
291
291
  const match = item.match(/([/\w]+)\((.+)\)/);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mpxjs/webpack-plugin",
3
- "version": "2.10.18-beta.11",
3
+ "version": "2.10.18-beta.12",
4
4
  "description": "mpx compile core",
5
5
  "keywords": [
6
6
  "mpx"