From c98c741cb96dab54edf1db1e58daaa1fa386e446 Mon Sep 17 00:00:00 2001 From: WX-DongXing Date: Fri, 27 Dec 2024 17:19:01 +0800 Subject: [PATCH 1/2] fix: use default gesture config --- packages/core/src/platform/createApp.ios.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/core/src/platform/createApp.ios.js b/packages/core/src/platform/createApp.ios.js index 226894d9fc..b3ef722394 100644 --- a/packages/core/src/platform/createApp.ios.js +++ b/packages/core/src/platform/createApp.ios.js @@ -183,7 +183,6 @@ export default function createApp (option, config = {}) { const { initialRouteName, initialParams } = initialRouteRef.current const headerBackImageProps = Mpx.config.rnConfig.headerBackImageProps || null const navScreenOpts = { - gestureEnabled: true, // 7.x替换headerBackTitleVisible // headerBackButtonDisplayMode: 'minimal', headerBackTitleVisible: false, From efb3a643f577810909c79cd58bbc44bf5fd4f35c Mon Sep 17 00:00:00 2001 From: hiyuki <674883329@qq.com> Date: Tue, 31 Dec 2024 18:18:08 +0800 Subject: [PATCH 2/2] optimize useTransformStyle with memo & adjust host props inherit & support unocss var --- .../builtInMixins/styleHelperMixin.ios.js | 2 +- .../platform/patch/getDefaultOptions.ios.js | 15 +- .../lib/runtime/components/react/utils.tsx | 148 +++++++++++------- 3 files changed, 97 insertions(+), 68 deletions(-) diff --git a/packages/core/src/platform/builtInMixins/styleHelperMixin.ios.js b/packages/core/src/platform/builtInMixins/styleHelperMixin.ios.js index 28fbe08a4a..3566007f75 100644 --- a/packages/core/src/platform/builtInMixins/styleHelperMixin.ios.js +++ b/packages/core/src/platform/builtInMixins/styleHelperMixin.ios.js @@ -181,7 +181,7 @@ export default function styleHelperMixin () { } else if (appClassMap[className]) { // todo 全局样式在每个页面和组件中生效,以支持全局原子类,后续支持样式模块复用后可考虑移除 Object.assign(result, appClassMap[className]) - } else if (this.__props[className] && isObject(this.__props[className])) { + } else if (isObject(this.__props[className])) { // externalClasses必定以对象形式传递下来 Object.assign(result, this.__props[className]) } diff --git a/packages/core/src/platform/patch/getDefaultOptions.ios.js b/packages/core/src/platform/patch/getDefaultOptions.ios.js index 1f44e346f6..ac4c5c7561 100644 --- a/packages/core/src/platform/patch/getDefaultOptions.ios.js +++ b/packages/core/src/platform/patch/getDefaultOptions.ios.js @@ -3,7 +3,7 @@ import * as ReactNative from 'react-native' import { ReactiveEffect } from '../../observer/effect' import { watch } from '../../observer/watch' import { reactive, set, del } from '../../observer/reactive' -import { hasOwn, isFunction, noop, isObject, isArray, getByPath, collectDataset, hump2dash, callWithErrorHandling, wrapMethodsWithErrorHandling } from '@mpxjs/utils' +import { hasOwn, isFunction, noop, isObject, isArray, getByPath, collectDataset, hump2dash, dash2hump, callWithErrorHandling, wrapMethodsWithErrorHandling } from '@mpxjs/utils' import MpxProxy from '../../core/proxy' import { BEFOREUPDATE, ONLOAD, UPDATED, ONSHOW, ONHIDE, ONRESIZE, REACTHOOKSEXEC } from '../../core/innerLifecycle' import mergeOptions from '../../core/mergeOptions' @@ -58,14 +58,12 @@ function createEffect (proxy, components) { proxy.toggleRecurse(true) } -function getRootProps (props) { +function getRootProps (props, validProps) { const rootProps = {} for (const key in props) { - if (hasOwn(props, key)) { - const match = /^(bind|catch|capture-bind|capture-catch|style|enable-var):?(.*?)(?:\.(.*))?$/.exec(key) - if (match) { - rootProps[key] = props[key] - } + const altKey = dash2hump(key) + if (!hasOwn(validProps, key) && !hasOwn(validProps, altKey) && key !== 'children') { + rootProps[key] = props[key] } } return rootProps @@ -474,7 +472,8 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) { const root = useMemo(() => proxy.effect.run(), [finalMemoVersion]) if (root && root.props.ishost) { - const rootProps = getRootProps(props) + // 对于组件未注册的属性继承到host节点上,如事件、样式和其他属性等 + const rootProps = getRootProps(props, validProps) rootProps.style = Object.assign({}, root.props.style, rootProps.style) // update root props return cloneElement(root, rootProps) diff --git a/packages/webpack-plugin/lib/runtime/components/react/utils.tsx b/packages/webpack-plugin/lib/runtime/components/react/utils.tsx index a00bb771ea..99a171d7ec 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/utils.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/utils.tsx @@ -18,8 +18,10 @@ export const HIDDEN_STYLE = { opacity: 0 } -const varDecRegExp = /^--.*/ +const varDecRegExp = /^--/ const varUseRegExp = /var\(/ +const unoVarDecRegExp = /^--un-/ +const unoVarUseRegExp = /var\(--un-/ const calcUseRegExp = /calc\(/ const envUseRegExp = /env\(/ @@ -37,7 +39,7 @@ function getSafeAreaInset (name: string) { } export function omit (obj: T, fields: K[]): Omit { - const shallowCopy: any = Object.assign({}, obj) + const shallowCopy: any = extendObject({}, obj) for (let i = 0; i < fields.length; i += 1) { const key = fields[i] delete shallowCopy[key] @@ -77,7 +79,7 @@ export const parseInlineStyle = (inlineStyle = ''): Record => { const [k, v, ...rest] = style.split(':') if (rest.length || !v || !k) return styleObj const key = k.trim().replace(/-./g, c => c.substring(1).toUpperCase()) - return Object.assign(styleObj, { [key]: global.__formatValue(v.trim()) }) + return extendObject(styleObj, { [key]: global.__formatValue(v.trim()) }) }, {}) } @@ -286,11 +288,15 @@ interface TransformStyleConfig { export function useTransformStyle (styleObj: Record = {}, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight }: TransformStyleConfig) { const varStyle: Record = {} + const unoVarStyle: Record = {} const normalStyle: Record = {} + const normalStyleRef = useRef>({}) + const normalStyleChangedRef = useRef(false) let hasVarDec = false let hasVarUse = false let hasSelfPercent = false const varKeyPaths: Array> = [] + const unoVarKeyPaths: Array> = [] const percentKeyPaths: Array> = [] const calcKeyPaths: Array> = [] const envKeyPaths: Array> = [] @@ -299,7 +305,9 @@ export function useTransformStyle (styleObj: Record = {}, { enableV function varVisitor ({ key, value, keyPath }: VisitorArg) { if (keyPath.length === 1) { - if (varDecRegExp.test(key)) { + if (unoVarDecRegExp.test(key)) { + unoVarStyle[key] = value + } else if (varDecRegExp.test(key)) { hasVarDec = true varStyle[key] = value } else { @@ -308,25 +316,31 @@ export function useTransformStyle (styleObj: Record = {}, { enableV } } // 对于var定义中使用的var无需替换值,可以通过resolveVar递归解析出值 - if (!varDecRegExp.test(key) && varUseRegExp.test(value)) { - hasVarUse = true - varKeyPaths.push(keyPath.slice()) + if (!varDecRegExp.test(key)) { + // 一般情况下一个样式属性中不会混用unocss var和普通css var,可分开进行互斥处理 + if (unoVarUseRegExp.test(value)) { + unoVarKeyPaths.push(keyPath.slice()) + } else if (varUseRegExp.test(value)) { + hasVarUse = true + varKeyPaths.push(keyPath.slice()) + } } } - // traverse var + // traverse var & generate normalStyle traverseStyle(styleObj, [varVisitor]) + hasVarDec = hasVarDec || !!externalVarContext enableVar = enableVar || hasVarDec || hasVarUse const enableVarRef = useRef(enableVar) if (enableVarRef.current !== enableVar) { error('css variable use/declare should be stable in the component lifecycle, or you can set [enable-var] with true.') } - // apply var + // apply css var const varContextRef = useRef({}) if (enableVarRef.current) { const varContext = useContext(VarContext) - const newVarContext = Object.assign({}, varContext, externalVarContext, varStyle) + const newVarContext = extendObject({}, varContext, externalVarContext, varStyle) // 缓存比较newVarContext是否发生变化 if (diffAndCloneA(varContextRef.current, newVarContext).diff) { varContextRef.current = newVarContext @@ -334,70 +348,86 @@ export function useTransformStyle (styleObj: Record = {}, { enableV transformVar(normalStyle, varKeyPaths, varContextRef.current) } - function envVisitor ({ value, keyPath }: VisitorArg) { - if (envUseRegExp.test(value)) { - envKeyPaths.push(keyPath.slice()) - } + // apply unocss var + if (unoVarKeyPaths.length) { + transformVar(normalStyle, unoVarKeyPaths, unoVarStyle) } - function calcVisitor ({ value, keyPath }: VisitorArg) { - if (calcUseRegExp.test(value)) { - calcKeyPaths.push(keyPath.slice()) - } + const { clone, diff } = diffAndCloneA(normalStyle, normalStyleRef.current) + if (diff) { + normalStyleRef.current = clone + normalStyleChangedRef.current = !normalStyleChangedRef.current } - function percentVisitor ({ key, value, keyPath }: VisitorArg) { - if (hasOwn(selfPercentRule, key) && PERCENT_REGEX.test(value)) { - hasSelfPercent = true - percentKeyPaths.push(keyPath.slice()) - } else if ((key === 'fontSize' || key === 'lineHeight') && PERCENT_REGEX.test(value)) { - percentKeyPaths.push(keyPath.slice()) + const memoResult = useMemo(() => { + // transform can be memoized + function envVisitor ({ value, keyPath }: VisitorArg) { + if (envUseRegExp.test(value)) { + envKeyPaths.push(keyPath.slice()) + } } - } - // traverse env & calc & percent - traverseStyle(normalStyle, [envVisitor, percentVisitor, calcVisitor]) + function calcVisitor ({ value, keyPath }: VisitorArg) { + if (calcUseRegExp.test(value)) { + calcKeyPaths.push(keyPath.slice()) + } + } - const percentConfig = { - width, - height, - fontSize: normalStyle.fontSize, - parentWidth, - parentHeight, - parentFontSize - } + function percentVisitor ({ key, value, keyPath }: VisitorArg) { + if (hasOwn(selfPercentRule, key) && PERCENT_REGEX.test(value)) { + hasSelfPercent = true + percentKeyPaths.push(keyPath.slice()) + } else if ((key === 'fontSize' || key === 'lineHeight') && PERCENT_REGEX.test(value)) { + percentKeyPaths.push(keyPath.slice()) + } + } - // apply env - transformEnv(normalStyle, envKeyPaths) - // apply percent - transformPercent(normalStyle, percentKeyPaths, percentConfig) - // apply calc - transformCalc(normalStyle, calcKeyPaths, (value: string, key: string) => { - if (PERCENT_REGEX.test(value)) { - const resolved = resolvePercent(value, key, percentConfig) - return typeof resolved === 'number' ? resolved : 0 - } else { - const formatted = global.__formatValue(value) - if (typeof formatted === 'number') { - return formatted + // traverse env & calc & percent + traverseStyle(normalStyle, [envVisitor, percentVisitor, calcVisitor]) + + const percentConfig = { + width, + height, + fontSize: normalStyle.fontSize, + parentWidth, + parentHeight, + parentFontSize + } + + // apply env + transformEnv(normalStyle, envKeyPaths) + // apply percent + transformPercent(normalStyle, percentKeyPaths, percentConfig) + // apply calc + transformCalc(normalStyle, calcKeyPaths, (value: string, key: string) => { + if (PERCENT_REGEX.test(value)) { + const resolved = resolvePercent(value, key, percentConfig) + return typeof resolved === 'number' ? resolved : 0 } else { - warn('calc() only support number, px, rpx, % temporarily.') - return 0 + const formatted = global.__formatValue(value) + if (typeof formatted === 'number') { + return formatted + } else { + warn('calc() only support number, px, rpx, % temporarily.') + return 0 + } } + }) + // transform number enum stringify + transformStringify(normalStyle) + + return { + normalStyle, + hasSelfPercent } - }) - // transform number enum stringify - transformStringify(normalStyle) + }, [normalStyleChangedRef.current, width, height, parentWidth, parentHeight, parentFontSize]) - return { - normalStyle, - hasSelfPercent, + return extendObject({ hasVarDec, - enableVarRef, varContextRef, setWidth, setHeight - } + }, memoResult) } export interface VisitorArg { @@ -565,7 +595,7 @@ export const useStableCallback = ( } export const usePrevious = (value: T): T | undefined => { - const ref = useRef(undefined) + const ref = useRef() const prev = ref.current ref.current = value return prev