@mpxjs/webpack-plugin 2.9.69-beta.4 → 2.9.69-beta.5

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.
@@ -12,10 +12,10 @@ import useAnimationHooks from './useAnimationHooks'
12
12
  import type { AnimationProp } from './useAnimationHooks'
13
13
  import { ExtendedViewStyle } from './types/common'
14
14
  import useNodesRef, { HandlerRef } from './useNodesRef'
15
- import { parseUrl, PERCENT_REGEX, splitStyle, splitProps, useTransformStyle, wrapChildren, useLayout, renderImage, pickStyle, extendObject, useHoverStyle } from './utils'
15
+ import { parseUrl, PERCENT_REGEX, splitStyle, splitProps, useTransformStyle, wrapChildren, useLayout, renderImage, pickStyle, extendObject, useHover } from './utils'
16
16
  import { error } from '@mpxjs/utils'
17
17
  import LinearGradient from 'react-native-linear-gradient'
18
- import { GestureDetector } from 'react-native-gesture-handler'
18
+ import { GestureDetector, PanGesture } from 'react-native-gesture-handler'
19
19
 
20
20
  export interface _ViewProps extends ViewProps {
21
21
  style?: ExtendedViewStyle
@@ -552,7 +552,7 @@ function inheritStyle (innerStyle: ExtendedViewStyle = {}) {
552
552
  : undefined)
553
553
  }
554
554
 
555
- function wrapImage (imageStyle?: ExtendedViewStyle, innerStyle?: Record<string, any>, enableFastImage?: boolean) {
555
+ function useWrapImage (imageStyle?: ExtendedViewStyle, innerStyle?: Record<string, any>, enableFastImage?: boolean) {
556
556
  // 预处理数据
557
557
  const preImageInfo: PreImageInfo = preParseImage(imageStyle)
558
558
  // 预解析
@@ -653,11 +653,6 @@ interface WrapChildrenConfig {
653
653
  }
654
654
 
655
655
  function wrapWithChildren (props: _ViewProps, { hasVarDec, enableBackground, textStyle, backgroundStyle, varContext, textProps, innerStyle, enableFastImage }: WrapChildrenConfig) {
656
- enableBackground = enableBackground || !!backgroundStyle
657
- const enableBackgroundRef = useRef(enableBackground)
658
- if (enableBackgroundRef.current !== enableBackground) {
659
- error('[Mpx runtime error]: background use should be stable in the component lifecycle, or you can set [enable-background] with true.')
660
- }
661
656
  const children = wrapChildren(props, {
662
657
  hasVarDec,
663
658
  varContext,
@@ -666,14 +661,15 @@ function wrapWithChildren (props: _ViewProps, { hasVarDec, enableBackground, tex
666
661
  })
667
662
 
668
663
  return [
669
- enableBackground ? wrapImage(backgroundStyle, innerStyle, enableFastImage) : null,
664
+ // eslint-disable-next-line react-hooks/rules-of-hooks
665
+ enableBackground ? useWrapImage(backgroundStyle, innerStyle, enableFastImage) : null,
670
666
  children
671
667
  ]
672
668
  }
673
669
 
674
670
  const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((viewProps, ref): JSX.Element => {
675
671
  const { textProps, innerProps: props = {} } = splitProps(viewProps)
676
- const {
672
+ let {
677
673
  style = {},
678
674
  'hover-style': hoverStyle,
679
675
  'hover-start-time': hoverStartTime = 50,
@@ -699,7 +695,8 @@ const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((viewProps, r
699
695
  }
700
696
  : {}
701
697
 
702
- const { isHover, enableHoverStyle, gesture } = useHoverStyle({ hoverStyle, hoverStartTime, hoverStayTime })
698
+ const enableHover = !!hoverStyle
699
+ const { isHover, gesture } = useHover({ enableHover, hoverStartTime, hoverStayTime })
703
700
 
704
701
  const styleObj: ExtendedViewStyle = extendObject({}, defaultStyle, style, isHover ? hoverStyle as ExtendedViewStyle : {})
705
702
 
@@ -720,6 +717,12 @@ const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((viewProps, r
720
717
 
721
718
  const { textStyle, backgroundStyle, innerStyle = {} } = splitStyle(normalStyle)
722
719
 
720
+ enableBackground = enableBackground || !!backgroundStyle
721
+ const enableBackgroundRef = useRef(enableBackground)
722
+ if (enableBackgroundRef.current !== enableBackground) {
723
+ error('[Mpx runtime error]: background use should be stable in the component lifecycle, or you can set [enable-background] with true.')
724
+ }
725
+
723
726
  const nodeRef = useRef(null)
724
727
  useNodesRef<View, _ViewProps>(props, ref, nodeRef, {
725
728
  style: normalStyle
@@ -757,7 +760,7 @@ const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((viewProps, r
757
760
 
758
761
  const childNode = wrapWithChildren(props, {
759
762
  hasVarDec,
760
- enableBackground,
763
+ enableBackground: enableBackgroundRef.current,
761
764
  textStyle,
762
765
  backgroundStyle,
763
766
  varContext: varContextRef.current,
@@ -770,8 +773,8 @@ const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((viewProps, r
770
773
  ? createElement(Animated.View, innerProps, childNode)
771
774
  : createElement(View, innerProps, childNode)
772
775
 
773
- return enableHoverStyle
774
- ? createElement(GestureDetector, { gesture }, BaseComponent)
776
+ return enableHover
777
+ ? createElement(GestureDetector, { gesture: gesture as PanGesture }, BaseComponent)
775
778
  : BaseComponent
776
779
  })
777
780
 
@@ -1,5 +1,5 @@
1
- import { forwardRef, useRef, useContext, useMemo, useState, createElement, useCallback, useEffect } from 'react'
2
- import { warn, getFocusedNavigation, isFunction } from '@mpxjs/utils'
1
+ import { forwardRef, useRef, useContext, useMemo, useState, useCallback, useEffect } from 'react'
2
+ import { warn, isFunction } from '@mpxjs/utils'
3
3
  import Portal from './mpx-portal'
4
4
  import { getCustomEvent } from './getInnerListeners'
5
5
  import { promisify, redirectTo, navigateTo, navigateBack, reLaunch, switchTab } from '@mpxjs/api-proxy'
@@ -7,6 +7,7 @@ import { WebView } from 'react-native-webview'
7
7
  import useNodesRef, { HandlerRef } from './useNodesRef'
8
8
  import { getCurrentPage, extendObject } from './utils'
9
9
  import { WebViewNavigationEvent, WebViewErrorEvent, WebViewMessageEvent, WebViewNavigation, WebViewProgressEvent, WebViewSource } from 'react-native-webview/lib/WebViewTypes'
10
+ import { useNavigation } from '@react-navigation/native'
10
11
  import { RouteContext } from './context'
11
12
  import { BackHandler, StyleSheet, View, Text, Platform } from 'react-native'
12
13
 
@@ -29,6 +30,7 @@ interface WebViewProps {
29
30
  binderror?: (event: CommonCallbackEvent) => void
30
31
  [x: string]: any
31
32
  }
33
+ type Listener = (type: string, callback: (e: Event) => void) => () => void
32
34
 
33
35
  interface PayloadData {
34
36
  [x: string]: any
@@ -105,6 +107,7 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
105
107
  bottom: 0 as number
106
108
  }
107
109
  const canGoBack = useRef<boolean>(false)
110
+ const isNavigateBack = useRef<boolean>(false)
108
111
 
109
112
  const onAndroidBackPress = useCallback(() => {
110
113
  if (canGoBack.current) {
@@ -115,44 +118,27 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
115
118
  }, [canGoBack])
116
119
 
117
120
  const beforeRemoveHandle = useCallback((e: Event) => {
118
- if (canGoBack.current) {
121
+ if (canGoBack.current && !isNavigateBack.current) {
119
122
  webViewRef.current?.goBack()
120
123
  e.preventDefault()
121
124
  }
125
+ isNavigateBack.current = false
122
126
  }, [canGoBack])
123
127
 
124
- const navigation = getFocusedNavigation()
125
-
126
- // ios 16以下版本 的hash会被转义,因此对于iOS环境下在页面load之后再注入hash部分的逻辑
127
- let [baseUrl, hashParams = ''] = src.split('#')
128
- if (hashParams) hashParams = '#' + hashParams
129
- const source = useMemo<WebViewSource>(() => {
130
- if (Platform.OS === 'ios') {
131
- return { uri: baseUrl };
132
- }
133
- return { uri: baseUrl + hashParams };
134
- }, [baseUrl, hashParams])
135
-
136
- const hashInjectedJavascript = useMemo(() => {
137
- if (Platform.OS === 'ios' && hashParams) {
138
- return `(function() {
139
- try {
140
- location.hash = '${hashParams}';
141
- } catch(e) {
142
- }
143
- })()`;
144
- }
145
- return '';
146
- }, [hashParams]);
147
-
148
- navigation?.addListener('beforeRemove', beforeRemoveHandle)
128
+ const navigation = useNavigation()
149
129
 
150
130
  useEffect(() => {
151
131
  if (__mpx_mode__ === 'android') {
152
132
  BackHandler.addEventListener('hardwareBackPress', onAndroidBackPress)
153
- return () => {
133
+ }
134
+ const addListener: Listener = navigation?.addListener.bind(navigation)
135
+ const beforeRemoveSubscription = addListener?.('beforeRemove', beforeRemoveHandle)
136
+ return () => {
137
+ if (__mpx_mode__ === 'android') {
154
138
  BackHandler.removeEventListener('hardwareBackPress', onAndroidBackPress)
155
- navigation?.removeListener('beforeRemove', beforeRemoveHandle)
139
+ }
140
+ if (isFunction(beforeRemoveSubscription)) {
141
+ beforeRemoveSubscription()
156
142
  }
157
143
  }
158
144
  }, [])
@@ -215,10 +201,10 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
215
201
  return _documentTitle
216
202
  }
217
203
  });
218
- ${hashInjectedJavascript}
219
204
  }
220
205
  true;
221
206
  `
207
+
222
208
  const sendMessage = function (params: string) {
223
209
  return `
224
210
  window.mpxWebviewMessageCallback(${params})
@@ -274,6 +260,7 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
274
260
  asyncCallback = navObj.navigateTo(...params)
275
261
  break
276
262
  case 'navigateBack':
263
+ isNavigateBack.current = true
277
264
  asyncCallback = navObj.navigateBack(...params)
278
265
  break
279
266
  case 'redirectTo':
@@ -343,7 +330,7 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
343
330
  )
344
331
  : (<WebView
345
332
  style={defaultWebViewStyle}
346
- source={source}
333
+ source={{ uri: src }}
347
334
  ref={webViewRef}
348
335
  javaScriptEnabled={true}
349
336
  onNavigationStateChange={_changeUrl}
@@ -55,9 +55,6 @@ export const createFaces = (
55
55
  for (let i = 0; i < index; i++) {
56
56
  offset += freeSpaces[i]
57
57
  }
58
- if (index === 0) {
59
- offset *= 0.6
60
- }
61
58
  return offset
62
59
  }) as unknown as T
63
60
  return [screenHeights, offsets]
@@ -67,9 +64,7 @@ export const createFaces = (
67
64
  const map: Record<number, number> = {
68
65
  0: 0,
69
66
  1: 0.8,
70
- 2: 0.9 // 0.35
71
- // 3: 0.45, // 0.45
72
- // 4: 0.5 // 0.5
67
+ 2: 0.9
73
68
  }
74
69
  return map[index] ?? Math.min(1, map[2] + index * 0.05)
75
70
  }
@@ -32,3 +32,7 @@ declare module '@mpxjs/utils' {
32
32
  declare let global: {
33
33
  __formatValue (value: string): string | number
34
34
  } & Record<string, any>
35
+
36
+ declare module '@react-navigation/native' {
37
+ export function useNavigation (): Record<string, any>
38
+ }
@@ -176,20 +176,23 @@ export default function useAnimationHooks<T, P> (props: _ViewProps & { enableAni
176
176
  error('[Mpx runtime error]: animation use should be stable in the component lifecycle, or you can set [enable-animation] with true.')
177
177
  }
178
178
 
179
- if (!enableStyleAnimation) return { enableStyleAnimation }
179
+ if (!enableAnimationRef.current) return { enableStyleAnimation: false }
180
180
 
181
181
  const originalStyle = formatStyle(style)
182
182
  // id 标识
183
183
  const id = animation?.id || -1
184
184
  // 有动画样式的 style key
185
+ // eslint-disable-next-line react-hooks/rules-of-hooks
185
186
  const animatedStyleKeys = useSharedValue([] as (string|string[])[])
186
187
  // 记录动画key的style样式值 没有的话设置为false
188
+ // eslint-disable-next-line react-hooks/rules-of-hooks
187
189
  const animatedKeys = useRef({} as {[propName: keyof ExtendedViewStyle]: boolean})
188
190
  // const animatedKeys = useRef({} as {[propName: keyof ExtendedViewStyle]: boolean|number|string})
189
191
  // ** 全量 style prop sharedValue
190
192
  // 不能做增量的原因:
191
193
  // 1 尝试用 useRef,但 useAnimatedStyle 访问后的 ref 不能在增加新的值,被冻结
192
194
  // 2 尝试用 useSharedValue,因为实际触发的 style prop 需要是 sharedValue 才能驱动动画,若外层 shareValMap 也是 sharedValue,动画无法驱动。
195
+ // eslint-disable-next-line react-hooks/rules-of-hooks
193
196
  const shareValMap = useMemo(() => {
194
197
  return Object.keys(InitialValue).reduce((valMap, key) => {
195
198
  const defaultVal = getInitialVal(key, isTransform(key))
@@ -198,6 +201,7 @@ export default function useAnimationHooks<T, P> (props: _ViewProps & { enableAni
198
201
  }, {} as { [propName: keyof ExtendedViewStyle]: SharedValue<string|number> })
199
202
  }, [])
200
203
  // ** 获取动画样式prop & 驱动动画
204
+ // eslint-disable-next-line react-hooks/rules-of-hooks
201
205
  useEffect(() => {
202
206
  if (id === -1) return
203
207
  // 更新动画样式 key map
@@ -218,6 +222,7 @@ export default function useAnimationHooks<T, P> (props: _ViewProps & { enableAni
218
222
  // })
219
223
  // }, [style])
220
224
  // ** 清空动画
225
+ // eslint-disable-next-line react-hooks/rules-of-hooks
221
226
  useEffect(() => {
222
227
  return () => {
223
228
  Object.values(shareValMap).forEach((value) => {
@@ -250,14 +255,13 @@ export default function useAnimationHooks<T, P> (props: _ViewProps & { enableAni
250
255
  }
251
256
  // 添加每个key的多次step动画
252
257
  animatedKeys.forEach(key => {
258
+ const ruleV = isTransform(key) ? transform.get(key) : rules.get(key)
253
259
  // key不存在,第一轮取shareValMap[key]value,非第一轮取上一轮的
254
- const toVal = rules.get(key) !== undefined
255
- ? rules.get(key)
256
- : transform.get(key) !== undefined
257
- ? transform.get(key)
258
- : index > 0
259
- ? lastValueMap[key]
260
- : shareValMap[key].value
260
+ const toVal = ruleV !== undefined
261
+ ? ruleV
262
+ : index > 0
263
+ ? lastValueMap[key]
264
+ : shareValMap[key].value
261
265
  const animation = getAnimation({ key, value: toVal! }, { delay, duration, easing }, needSetCallback ? setTransformOrigin : undefined)
262
266
  needSetCallback = false
263
267
  if (!sequence[key]) {
@@ -346,7 +350,7 @@ export default function useAnimationHooks<T, P> (props: _ViewProps & { enableAni
346
350
  }, {} as { [propName: string]: string | number })
347
351
  }
348
352
  // ** 生成动画样式
349
-
353
+ // eslint-disable-next-line react-hooks/rules-of-hooks
350
354
  const animationStyle = useAnimatedStyle(() => {
351
355
  // console.info(`useAnimatedStyle styles=`, originalStyle)
352
356
  return animatedStyleKeys.value.reduce((styles, key) => {
@@ -367,7 +371,7 @@ export default function useAnimationHooks<T, P> (props: _ViewProps & { enableAni
367
371
  })
368
372
 
369
373
  return {
370
- enableStyleAnimation,
374
+ enableStyleAnimation: enableAnimationRef.current,
371
375
  animationStyle
372
376
  }
373
377
  }
@@ -680,3 +680,67 @@ export function useHoverStyle ({ hoverStyle, hoverStartTime, hoverStayTime, disa
680
680
  enableHoverStyle
681
681
  }
682
682
  }
683
+
684
+ export function useHover ({ enableHover, hoverStartTime, hoverStayTime, disabled } : { enableHover: boolean, hoverStartTime: number, hoverStayTime: number, disabled?: boolean }) {
685
+ const enableHoverRef = useRef(enableHover)
686
+ if (enableHoverRef.current !== enableHover) {
687
+ error('[Mpx runtime error]: hover-class use should be stable in the component lifecycle.')
688
+ }
689
+
690
+ if (!enableHoverRef.current) return { isHover: false }
691
+ // eslint-disable-next-line react-hooks/rules-of-hooks
692
+ const gestureRef = useContext(ScrollViewContext).gestureRef
693
+ // eslint-disable-next-line react-hooks/rules-of-hooks
694
+ const [isHover, setIsHover] = useState(false)
695
+ // eslint-disable-next-line react-hooks/rules-of-hooks
696
+ const dataRef = useRef<{
697
+ startTimer?: ReturnType<typeof setTimeout>
698
+ stayTimer?: ReturnType<typeof setTimeout>
699
+ }>({})
700
+
701
+ // eslint-disable-next-line react-hooks/rules-of-hooks
702
+ useEffect(() => {
703
+ return () => {
704
+ dataRef.current.startTimer && clearTimeout(dataRef.current.startTimer)
705
+ dataRef.current.stayTimer && clearTimeout(dataRef.current.stayTimer)
706
+ }
707
+ }, [])
708
+
709
+ const setStartTimer = () => {
710
+ if (disabled) return
711
+ dataRef.current.startTimer && clearTimeout(dataRef.current.startTimer)
712
+ dataRef.current.startTimer = setTimeout(() => {
713
+ setIsHover(true)
714
+ }, +hoverStartTime)
715
+ }
716
+
717
+ const setStayTimer = () => {
718
+ if (disabled) return
719
+ dataRef.current.stayTimer && clearTimeout(dataRef.current.stayTimer)
720
+ dataRef.current.startTimer && clearTimeout(dataRef.current.startTimer)
721
+ dataRef.current.stayTimer = setTimeout(() => {
722
+ setIsHover(false)
723
+ }, +hoverStayTime)
724
+ }
725
+ // eslint-disable-next-line react-hooks/rules-of-hooks
726
+ const gesture = useMemo(() => {
727
+ return Gesture.Pan()
728
+ .onTouchesDown(() => {
729
+ 'worklet'
730
+ runOnJS(setStartTimer)()
731
+ })
732
+ .onTouchesUp(() => {
733
+ 'worklet'
734
+ runOnJS(setStayTimer)()
735
+ })
736
+ }, [])
737
+
738
+ if (gestureRef) {
739
+ gesture.simultaneousWithExternalGesture(gestureRef)
740
+ }
741
+
742
+ return {
743
+ isHover,
744
+ gesture
745
+ }
746
+ }
@@ -32,6 +32,13 @@ const {
32
32
  } = require('./utils')
33
33
  const createHelpers = require('../helpers')
34
34
 
35
+ const RN_PRESET_OPTIMISATION = {
36
+ reduceInitial: false,
37
+ normalizeWhitespace: false,
38
+ minifyFontValues: false,
39
+ convertValues: false
40
+ }
41
+
35
42
  module.exports = async function loader (content, map, meta) {
36
43
  const rawOptions = this.getOptions(schema)
37
44
  const plugins = []
@@ -41,6 +48,7 @@ module.exports = async function loader (content, map, meta) {
41
48
  const externals = mpx.externals
42
49
  const root = mpx.projectRoot
43
50
  const sourceMap = mpx.cssSourceMap || false
51
+ const isRN = ['ios', 'android', 'harmony'].includes(mpx.mode)
44
52
 
45
53
  let options
46
54
 
@@ -152,12 +160,17 @@ module.exports = async function loader (content, map, meta) {
152
160
  if (this.minimize) {
153
161
  const cssnano = require('cssnano')
154
162
  const minimizeOptions = rawOptions.minimize || {}
163
+ const presetOptimisation = Object.assign(
164
+ {},
165
+ isRN ? RN_PRESET_OPTIMISATION : {},
166
+ minimizeOptions.optimisation
167
+ )
155
168
  let cssnanoConfig = {
156
- preset: ['cssnano-preset-default', minimizeOptions.optimisation || {}]
169
+ preset: ['cssnano-preset-default', presetOptimisation]
157
170
  }
158
171
  if (minimizeOptions.advanced) {
159
172
  cssnanoConfig = {
160
- preset: ['cssnano-preset-advanced', minimizeOptions.optimisation || {}]
173
+ preset: ['cssnano-preset-advanced', presetOptimisation]
161
174
  }
162
175
  }
163
176
  plugins.push(cssnano(cssnanoConfig))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mpxjs/webpack-plugin",
3
- "version": "2.9.69-beta.4",
3
+ "version": "2.9.69-beta.5",
4
4
  "description": "mpx compile core",
5
5
  "keywords": [
6
6
  "mpx"