From 1482211fc02ac95142ba10630db4501801b294b6 Mon Sep 17 00:00:00 2001 From: lareinayanyu Date: Thu, 17 Oct 2024 18:33:47 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=8A=BD=E7=A6=BBlayout?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/runtime/components/react/common.tsx | 31 +++++++++++ .../components/react/getInnerListeners.ts | 10 +++- .../lib/runtime/components/react/mpx-form.tsx | 51 ++++++++++++++----- .../lib/runtime/components/react/utils.ts | 42 ++++++++++++++- 4 files changed, 120 insertions(+), 14 deletions(-) create mode 100644 packages/webpack-plugin/lib/runtime/components/react/common.tsx diff --git a/packages/webpack-plugin/lib/runtime/components/react/common.tsx b/packages/webpack-plugin/lib/runtime/components/react/common.tsx new file mode 100644 index 0000000000..6d3cd0fce7 --- /dev/null +++ b/packages/webpack-plugin/lib/runtime/components/react/common.tsx @@ -0,0 +1,31 @@ +import { TextStyle } from 'react-native' +import { Children, cloneElement } from 'react' +import { VarContext } from './context' +import { isText } from './utils' + +export interface WrapChildrenConfig { + hasVarDec: boolean + varContext?: Record +} + +interface TextConfig { + textStyle?: TextStyle + textProps?: Record +} + +export function wrapChildren (props: Record = {}, { hasVarDec, varContext }: WrapChildrenConfig, { textStyle, textProps } : TextConfig = {}) { + 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 +} \ No newline at end of file diff --git a/packages/webpack-plugin/lib/runtime/components/react/getInnerListeners.ts b/packages/webpack-plugin/lib/runtime/components/react/getInnerListeners.ts index dfad78d653..afe302dc25 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 = [], + useRemoveProps: RemoveProps = [], rawConfig?: UseInnerPropsConfig ) => { const ref = useRef({ @@ -130,6 +130,14 @@ const useInnerProps = ( const propsRef = useRef>({}) const eventConfig: { [key: string]: string[] } = {} const config = rawConfig || { layoutRef: { current: {} }, disableTouch: false, disableTap: false } + const removeProps = [ + 'enable-var', + 'external-var-context', + 'parent-font-size', + 'parent-width', + 'parent-height', + ...useRemoveProps + ] 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 397dfd7606..fb239d5ce5 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-form.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-form.tsx @@ -10,10 +10,14 @@ 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 } from './utils' +import { wrapChildren } from './common' interface FormProps { style?: Record; children: ReactNode; + 'enable-offset'?: boolean; + 'enable-var'?: boolean + 'external-var-context'?: Record bindsubmit?: (evt: { detail: { value: any; @@ -22,18 +26,29 @@ 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 + } = props + + const { + hasSelfPercent, + normalStyle, + hasVarDec, + varContextRef, + setWidth, + setHeight + } = useTransformStyle(style, { enableVar, externalVarContext }) + + 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,9 +78,9 @@ const _Form = forwardRef, FormProps>((props: FormPro } const innerProps = useInnerProps(props, { + style: { ...innerStyle, ...layoutStyle }, ref: formRef, - style, - onLayout + ...layoutProps }, [ 'children', 'style', @@ -78,7 +93,19 @@ 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/utils.ts b/packages/webpack-plugin/lib/runtime/components/react/utils.ts index b7e49845df..e686c5f2b7 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/utils.ts +++ b/packages/webpack-plugin/lib/runtime/components/react/utils.ts @@ -1,5 +1,5 @@ import { useEffect, useRef, ReactNode, ReactElement, FunctionComponent, isValidElement, useContext, useState } from 'react' -import { Dimensions, StyleSheet } from 'react-native' +import { Dimensions, StyleSheet, LayoutChangeEvent } 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(() => { @@ -439,3 +442,40 @@ export function splitProps> (props: T) { } }) } + +interface layoutConfig { + props: Record; + hasSelfPercent: boolean; + setWidth:any + setHeight: any + onLayout?: any + nodeRef: any +} +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 = {} + if (hasSelfPercent || onLayout) { + layoutProps.onLayout = (e: LayoutChangeEvent) => { + hasLayoutRef.current = true + if (hasSelfPercent) { + const { width, height } = e?.nativeEvent?.layout || {} + setWidth(width || 0) + setHeight(height || 0) + } + if (props['enable-offset']) { + 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 + } +}