diff --git a/packages/webpack-plugin/lib/runtime/components/react/getInnerListeners.ts b/packages/webpack-plugin/lib/runtime/components/react/getInnerListeners.ts index dfad78d65..8f2f148ee 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/getInnerListeners.ts +++ b/packages/webpack-plugin/lib/runtime/components/react/getInnerListeners.ts @@ -107,7 +107,7 @@ export const getCustomEvent = ( const useInnerProps = ( props: Props = {}, additionalProps: AdditionalProps = {}, - removeProps: RemoveProps = [], + userRemoveProps: RemoveProps = [], rawConfig?: UseInnerPropsConfig ) => { const ref = useRef({ @@ -130,6 +130,17 @@ const useInnerProps = ( const propsRef = useRef>({}) const eventConfig: { [key: string]: string[] } = {} const config = rawConfig || { layoutRef: { current: {} }, disableTouch: false, disableTap: false } + const removeProps = [ + 'children', + 'enable-background', + 'enable-offset', + 'enable-var', + 'external-var-context', + 'parent-font-size', + 'parent-width', + 'parent-height', + ...userRemoveProps + ] propsRef.current = { ...props, ...additionalProps } diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-form.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-form.tsx index 397dfd760..85b7ebb4f 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-form.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-form.tsx @@ -5,15 +5,21 @@ * ✔ bindreset */ -import { View, LayoutChangeEvent } from 'react-native' +import { View } from 'react-native' import { JSX, useRef, forwardRef, ReactNode } from 'react' import useNodesRef, { HandlerRef } from './useNodesRef' import useInnerProps, { getCustomEvent } from './getInnerListeners' import { FormContext } from './context' - +import { useTransformStyle, splitProps, splitStyle, useLayout, wrapChildren } from './utils' interface FormProps { style?: Record; children: ReactNode; + 'enable-offset'?: boolean; + 'enable-var'?: boolean + 'external-var-context'?: Record; + 'parent-font-size'?: number; + 'parent-width'?: number; + 'parent-height'?: number; bindsubmit?: (evt: { detail: { value: any; @@ -22,18 +28,32 @@ interface FormProps { bindreset?: () => void; } -const _Form = forwardRef, FormProps>((props: FormProps, ref): JSX.Element => { - const { children, style } = props - const layoutRef = useRef({}) +const _Form = forwardRef, FormProps>((fromProps: FormProps, ref): JSX.Element => { + const { textProps, innerProps: props = {} } = splitProps(fromProps) const formValuesMap = useRef(new Map()).current + const { + style, + 'enable-var': enableVar, + 'external-var-context': externalVarContext, + 'parent-font-size': parentFontSize, + 'parent-width': parentWidth, + 'parent-height': parentHeight + } = props + + const { + hasSelfPercent, + normalStyle, + hasVarDec, + varContextRef, + setWidth, + setHeight + } = useTransformStyle(style, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight }) + + const { textStyle, innerStyle } = splitStyle(normalStyle) const { nodeRef: formRef } = useNodesRef(props, ref) - const onLayout = (e: LayoutChangeEvent) => { - formRef.current?.measure((x: number, y: number, width: number, height: number, offsetLeft: number, offsetTop: number) => { - layoutRef.current = { x, y, width, height, offsetLeft, offsetTop } - }) - } + const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: formRef }) const submit = () => { const { bindsubmit } = props @@ -63,12 +83,10 @@ const _Form = forwardRef, FormProps>((props: FormPro } const innerProps = useInnerProps(props, { + style: { ...innerStyle, ...layoutStyle }, ref: formRef, - style, - onLayout + ...layoutProps }, [ - 'children', - 'style', 'bindsubmit', 'bindreset' ], { layoutRef }) @@ -78,7 +96,17 @@ const _Form = forwardRef, FormProps>((props: FormPro {...innerProps} > - {children} + { + wrapChildren( + props, + { + hasVarDec, + varContext: varContextRef.current, + textStyle, + textProps + } + ) + } ) diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-text.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-text.tsx index dba63dc21..6f4188fa5 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-text.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-text.tsx @@ -65,25 +65,17 @@ const _Text = forwardRef, _TextProps>((props, ref): const { nodeRef } = useNodesRef(props, ref) const innerProps = useInnerProps(props, { - ref: nodeRef + ref: nodeRef, + style: normalStyle, + selectable: !!selectable || !!userSelect }, [ - 'style', - 'children', - 'selectable', - 'user-select', - 'enable-var', - 'external-var-context', - 'parent-font-size', - 'parent-width', - 'parent-height' + 'user-select' ], { layoutRef }) return ( { diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-view.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-view.tsx index ef68ed291..9a53628cc 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-view.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-view.tsx @@ -539,25 +539,17 @@ const _View = forwardRef, _ViewProps>((props, ref): const innerProps = useInnerProps(props, { ref: nodeRef, + style: innerStyle, ...needLayout ? { onLayout } : null, ...(hoverStyle && { bindtouchstart: onTouchStart, bindtouchend: onTouchEnd }) }, [ - 'style', - 'children', 'hover-start-time', 'hover-stay-time', 'hover-style', - 'hover-class', - 'enable-offset', - 'enable-background-image', - 'enable-var', - 'external-var-context', - 'parent-font-size', - 'parent-width', - 'parent-height' + 'hover-class' ], { layoutRef }) @@ -565,7 +557,6 @@ const _View = forwardRef, _ViewProps>((props, ref): return ( { wrapChildren( diff --git a/packages/webpack-plugin/lib/runtime/components/react/utils.ts b/packages/webpack-plugin/lib/runtime/components/react/utils.tsx similarity index 85% rename from packages/webpack-plugin/lib/runtime/components/react/utils.ts rename to packages/webpack-plugin/lib/runtime/components/react/utils.tsx index 98b7fe5d1..5c056bf1e 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/utils.ts +++ b/packages/webpack-plugin/lib/runtime/components/react/utils.tsx @@ -1,5 +1,5 @@ -import { useEffect, useRef, ReactNode, ReactElement, FunctionComponent, isValidElement, useContext, useState } from 'react' -import { Dimensions, StyleSheet } from 'react-native' +import { useEffect, useRef, ReactNode, ReactElement, FunctionComponent, isValidElement, useContext, useState, Dispatch, SetStateAction, Children, cloneElement } from 'react' +import { Dimensions, StyleSheet, LayoutChangeEvent, TextStyle } from 'react-native' import { isObject, hasOwn, diffAndCloneA, error, warn } from '@mpxjs/utils' import { VarContext } from './context' import { ExpressionParser, parseFunc, ReplaceSource } from './parser' @@ -10,6 +10,9 @@ export const URL_REGEX = /^\s*url\(["']?(.*?)["']?\)\s*$/ export const BACKGROUND_REGEX = /^background(Image|Size|Repeat|Position)$/ export const TEXT_PROPS_REGEX = /ellipsizeMode|numberOfLines/ export const DEFAULT_FONT_SIZE = 16 +export const DEFAULT_UNLAY_STYLE = { + opacity: 0 +} export const throwReactWarning = (message: string) => { setTimeout(() => { @@ -426,3 +429,65 @@ export function splitProps> (props: T) { } }) } + +interface LayoutConfig { + props: Record + hasSelfPercent: boolean + setWidth: Dispatch> + setHeight: Dispatch> + onLayout?: (event?: LayoutChangeEvent) => void + nodeRef: React.RefObject +} +export const useLayout = ({ props, hasSelfPercent, setWidth, setHeight, onLayout, nodeRef }:LayoutConfig) => { + const layoutRef = useRef({}) + const hasLayoutRef = useRef(false) + const layoutStyle: Record = hasLayoutRef.current ? {} : DEFAULT_UNLAY_STYLE + const layoutProps: Record = {} + const enableOffset = props['enable-offset'] + if (hasSelfPercent || onLayout || enableOffset) { + layoutProps.onLayout = (e: LayoutChangeEvent) => { + hasLayoutRef.current = true + if (hasSelfPercent) { + const { width, height } = e?.nativeEvent?.layout || {} + setWidth(width || 0) + setHeight(height || 0) + } + if (enableOffset) { + nodeRef.current?.measure((x: number, y: number, width: number, height: number, offsetLeft: number, offsetTop: number) => { + layoutRef.current = { x, y, width, height, offsetLeft, offsetTop } + }) + } + onLayout && onLayout(e) + props.onLayout && props.onLayout(e) + } + } + return { + layoutRef, + layoutStyle, + layoutProps + } +} + +export interface WrapChildrenConfig { + hasVarDec: boolean + varContext?: Record + textStyle?: TextStyle + textProps?: Record +} + +export function wrapChildren (props: Record = {}, { hasVarDec, varContext, textStyle, textProps }: WrapChildrenConfig) { + let { children } = props + if (textStyle || textProps) { + children = Children.map(children, (child) => { + if (isText(child)) { + const style = { ...textStyle, ...child.props.style } + return cloneElement(child, { ...textProps, style }) + } + return child + }) + } + if (hasVarDec && varContext) { + children = {children} + } + return children +}