Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(view): view hover style #1769

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ const TAG_NAME = 'movable-view'

module.exports = function ({ print }) {
const aliEventLog = print({ platform: 'ali', tag: TAG_NAME, isError: false, type: 'event' })
const androidEventLog = print({ platform: 'android', tag: TAG_NAME, isError: false, type: 'event' })
const iosEventLog = print({ platform: 'ios', tag: TAG_NAME, isError: false, type: 'event' })
const qaPropLog = print({ platform: 'qa', tag: TAG_NAME, isError: false })
const androidPropLog = print({ platform: 'android', tag: TAG_NAME, isError: false })
const iosPropLog = print({ platform: 'ios', tag: TAG_NAME, isError: false })
Expand All @@ -27,7 +29,7 @@ module.exports = function ({ print }) {
android: androidPropLog
},
{
test: /^(inertia|damping|animation)$/,
test: /^(damping|friction|scale|scale-min|scale-max|scale-value)$/,
ios: iosPropLog,
android: androidPropLog
}
Expand All @@ -36,6 +38,11 @@ module.exports = function ({ print }) {
{
test: /^(htouchmove|vtouchmove)$/,
ali: aliEventLog
},
{
test: /^(bindscale)$/,
ios: iosEventLog,
android: androidEventLog
}
]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ module.exports = function ({ print }) {
qa: qaPropLog
},
{
test: /^(scroll-into-view|refresher-threshold|enable-passive|scroll-anchoring|using-sticky|fast-deceleration|enable-flex)$/,
test: /^(refresher-threshold|enable-passive|scroll-anchoring|using-sticky|fast-deceleration|enable-flex)$/,
android: androidPropLog,
ios: iosPropLog
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ export interface IntersectionObserver {
}
}

export interface ScrollViewContextValue {
gestureRef: React.RefObject<any> | null
}

export const MovableAreaContext = createContext({ width: 0, height: 0 })

export const FormContext = createContext<FormContextValue | null>(null)
Expand All @@ -52,3 +56,5 @@ export const IntersectionObserverContext = createContext<IntersectionObserver |
export const RouteContext = createContext<number | null>(null)

export const KeyboardAvoidContext = createContext<KeyboardAvoidContextValue | null>(null)

export const ScrollViewContext = createContext<ScrollViewContextValue>({ gestureRef: null })
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
* ✘ scale-min
* ✘ scale-max
* ✘ scale-value
* animation
* animation
* ✔ bindchange
* ✘ bindscale
* ✔ htouchmove
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
* ✔ nodes
*/
import { View, ViewProps, ViewStyle } from 'react-native'
import { useRef, forwardRef, JSX, useState } from 'react'
import { useRef, forwardRef, JSX, useState, createElement } from 'react'
import useInnerProps from '../getInnerListeners'
import useNodesRef, { HandlerRef } from '../useNodesRef' // 引入辅助函数
import { useTransformStyle, useLayout } from '../utils'
import { useTransformStyle, useLayout, extendObject } from '../utils'
import { WebView, WebViewMessageEvent } from 'react-native-webview'
import { generateHTML } from './html'

Expand Down Expand Up @@ -91,28 +91,22 @@ const _RichText = forwardRef<HandlerRef<View, _RichTextProps>, _RichTextProps>((
layoutRef
})

const innerProps = useInnerProps(props, {
const innerProps = useInnerProps(props, extendObject({
ref: nodeRef,
style: { ...normalStyle, ...layoutStyle },
...layoutProps
}, [], {
style: extendObject(normalStyle, layoutStyle)
}, layoutProps), [], {
layoutRef
})

const html: string = typeof nodes === 'string' ? nodes : jsonToHtmlStr(nodes)

return (
<View
{...innerProps}
>
<WebView
source={{ html: generateHTML(html) }}
onMessage={(event: WebViewMessageEvent) => {
setWebViewHeight(+event.nativeEvent.data)
}}
>
</WebView>
</View>
return createElement(View, innerProps,
createElement(WebView, {
source: { html: generateHTML(html) },
onMessage: (event: WebViewMessageEvent) => {
setWebViewHeight(+event.nativeEvent.data)
}
})
)
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@
*/
import { ScrollView } from 'react-native-gesture-handler'
import { View, RefreshControl, NativeSyntheticEvent, NativeScrollEvent, LayoutChangeEvent, ViewStyle } from 'react-native'
import { JSX, ReactNode, RefObject, useRef, useState, useEffect, forwardRef, useContext, createElement } from 'react'
import { JSX, ReactNode, RefObject, useRef, useState, useEffect, forwardRef, useContext, createElement, useMemo } from 'react'
import { useAnimatedRef } from 'react-native-reanimated'
import { warn } from '@mpxjs/utils'
import useInnerProps, { getCustomEvent } from './getInnerListeners'
import useNodesRef, { HandlerRef } from './useNodesRef'
import { splitProps, splitStyle, useTransformStyle, useLayout, wrapChildren, extendObject, flatGesture, GestureHandler } from './utils'
import { IntersectionObserverContext } from './context'
import { IntersectionObserverContext, ScrollViewContext } from './context'

interface ScrollViewProps {
children?: ReactNode;
Expand Down Expand Up @@ -194,6 +194,12 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
gestureRef: scrollViewRef
})

const contextValue = useMemo(() => {
return {
gestureRef: scrollViewRef
}
}, [])

const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: scrollViewRef, onLayout })

if (scrollX && scrollY) {
Expand Down Expand Up @@ -507,14 +513,17 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
}, (refresherDefaultStyle && refresherDefaultStyle !== 'none' ? { colors: refreshColor[refresherDefaultStyle] } : null)))
: undefined
}),
wrapChildren(
props,
{
hasVarDec,
varContext: varContextRef.current,
textStyle,
textProps
}
createElement(ScrollViewContext.Provider,
{ value: contextValue },
wrapChildren(
props,
{
hasVarDec,
varContext: varContextRef.current,
textStyle,
textProps
}
)
)
)
})
Expand Down
96 changes: 25 additions & 71 deletions packages/webpack-plugin/lib/runtime/components/react/mpx-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ import useAnimationHooks from './useAnimationHooks'
import type { AnimationProp } from './useAnimationHooks'
import { ExtendedViewStyle } from './types/common'
import useNodesRef, { HandlerRef } from './useNodesRef'
import { parseUrl, PERCENT_REGEX, splitStyle, splitProps, useTransformStyle, wrapChildren, useLayout, renderImage, pickStyle, extendObject } from './utils'
import { parseUrl, PERCENT_REGEX, splitStyle, splitProps, useTransformStyle, wrapChildren, useLayout, renderImage, pickStyle, extendObject, useHoverStyle } from './utils'
import { error } from '@mpxjs/utils'
import LinearGradient from 'react-native-linear-gradient'
import { GestureDetector } from 'react-native-gesture-handler'

export interface _ViewProps extends ViewProps {
style?: ExtendedViewStyle
Expand Down Expand Up @@ -642,7 +643,7 @@ function wrapImage (imageStyle?: ExtendedViewStyle, innerStyle?: Record<string,

interface WrapChildrenConfig {
hasVarDec: boolean
enableBackground: boolean
enableBackground?: boolean
textStyle?: TextStyle
backgroundStyle?: ExtendedViewStyle
varContext?: Record<string, any>
Expand All @@ -652,6 +653,11 @@ interface WrapChildrenConfig {
}

function wrapWithChildren (props: _ViewProps, { hasVarDec, enableBackground, textStyle, backgroundStyle, varContext, textProps, innerStyle, enableFastImage }: WrapChildrenConfig) {
enableBackground = enableBackground || !!backgroundStyle
const enableBackgroundRef = useRef(enableBackground)
if (enableBackgroundRef.current !== enableBackground) {
error('[Mpx runtime error]: background use should be stable in the component lifecycle, or you can set [enable-background] with true.')
}
const children = wrapChildren(props, {
hasVarDec,
varContext,
Expand All @@ -667,7 +673,7 @@ function wrapWithChildren (props: _ViewProps, { hasVarDec, enableBackground, tex

const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((viewProps, ref): JSX.Element => {
const { textProps, innerProps: props = {} } = splitProps(viewProps)
let {
const {
style = {},
'hover-style': hoverStyle,
'hover-start-time': hoverStartTime = 50,
Expand All @@ -683,8 +689,6 @@ const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((viewProps, r
animation
} = props

const [isHover, setIsHover] = useState(false)

// 默认样式
const defaultStyle: ExtendedViewStyle = style.display === 'flex'
? {
Expand All @@ -695,6 +699,8 @@ const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((viewProps, r
}
: {}

const { isHover, enableHoverStyle, gesture } = useHoverStyle({ hoverStyle, hoverStartTime, hoverStayTime })

const styleObj: ExtendedViewStyle = extendObject({}, defaultStyle, style, isHover ? hoverStyle as ExtendedViewStyle : {})

const {
Expand All @@ -714,56 +720,11 @@ const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((viewProps, r

const { textStyle, backgroundStyle, innerStyle = {} } = splitStyle(normalStyle)

enableBackground = enableBackground || !!backgroundStyle
const enableBackgroundRef = useRef(enableBackground)
if (enableBackgroundRef.current !== enableBackground) {
error('[Mpx runtime error]: background use should be stable in the component lifecycle, or you can set [enable-background] with true.')
}

const nodeRef = useRef(null)
useNodesRef<View, _ViewProps>(props, ref, nodeRef, {
style: normalStyle
})

const dataRef = useRef<{
startTimer?: ReturnType<typeof setTimeout>
stayTimer?: ReturnType<typeof setTimeout>
}>({})

useEffect(() => {
return () => {
dataRef.current.startTimer && clearTimeout(dataRef.current.startTimer)
dataRef.current.stayTimer && clearTimeout(dataRef.current.stayTimer)
}
}, [])

const setStartTimer = () => {
dataRef.current.startTimer && clearTimeout(dataRef.current.startTimer)
dataRef.current.startTimer = setTimeout(() => {
setIsHover(true)
}, +hoverStartTime)
}

const setStayTimer = () => {
dataRef.current.stayTimer && clearTimeout(dataRef.current.stayTimer)
dataRef.current.startTimer && clearTimeout(dataRef.current.startTimer)
dataRef.current.stayTimer = setTimeout(() => {
setIsHover(false)
}, +hoverStayTime)
}

function onTouchStart (e: NativeSyntheticEvent<TouchEvent>) {
const { bindtouchstart } = props
bindtouchstart && bindtouchstart(e)
setStartTimer()
}

function onTouchEnd (e: NativeSyntheticEvent<TouchEvent>) {
const { bindtouchend } = props
bindtouchend && bindtouchend(e)
setStayTimer()
}

const {
layoutRef,
layoutStyle,
Expand All @@ -772,30 +733,19 @@ const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((viewProps, r

const viewStyle = extendObject({}, innerStyle, layoutStyle)

enableAnimation = enableAnimation || !!animation
const enableAnimationRef = useRef(enableAnimation)
if (enableAnimationRef.current !== enableAnimation) {
error('[Mpx runtime error]: animation use should be stable in the component lifecycle, or you can set [enable-animation] with true.')
}
const finalStyle = enableAnimationRef.current
? [viewStyle, useAnimationHooks({
animation,
style: viewStyle
})]
: viewStyle
const { enableStyleAnimation, animationStyle } = useAnimationHooks({
enableAnimation,
animation,
style: viewStyle
})

const innerProps = useInnerProps(
props,
extendObject({
ref: nodeRef,
style: finalStyle
style: enableStyleAnimation ? [viewStyle, animationStyle] : viewStyle
},
layoutProps,
hoverStyle
? {
bindtouchstart: onTouchStart,
bindtouchend: onTouchEnd
}
: {}
layoutProps
), [
'hover-start-time',
'hover-stay-time',
Expand All @@ -807,7 +757,7 @@ const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((viewProps, r

const childNode = wrapWithChildren(props, {
hasVarDec,
enableBackground: enableBackgroundRef.current,
enableBackground,
textStyle,
backgroundStyle,
varContext: varContextRef.current,
Expand All @@ -816,9 +766,13 @@ const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((viewProps, r
enableFastImage
})

return enableAnimation
const BaseComponent = enableAnimation
? createElement(Animated.View, innerProps, childNode)
: createElement(View, innerProps, childNode)

return enableHoverStyle
? createElement(GestureDetector, { gesture }, BaseComponent)
: BaseComponent
})

_View.displayName = 'MpxView'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
WithTimingConfig,
AnimationCallback
} from 'react-native-reanimated'
import { error } from '@mpxjs/utils'
import { ExtendedViewStyle } from './types/common'
import type { _ViewProps } from './mpx-view'

Expand Down Expand Up @@ -166,8 +167,17 @@ const formatStyle = (style: ExtendedViewStyle): ExtendedViewStyle => {
})
}

export default function useAnimationHooks<T, P> (props: _ViewProps) {
const { style = {}, animation } = props
export default function useAnimationHooks<T, P> (props: _ViewProps & { enableAnimation?: boolean }) {
const { style = {}, animation, enableAnimation } = props

const enableStyleAnimation = enableAnimation || !!animation
const enableAnimationRef = useRef(enableStyleAnimation)
if (enableAnimationRef.current !== enableStyleAnimation) {
error('[Mpx runtime error]: animation use should be stable in the component lifecycle, or you can set [enable-animation] with true.')
}

if (!enableStyleAnimation) return { enableStyleAnimation }

const originalStyle = formatStyle(style)
// id 标识
const id = animation?.id || -1
Expand Down
Loading
Loading