diff --git a/package.json b/package.json index 41d831e2c9..6b00312c2c 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "lint": "eslint --ext .js,.ts,.tsx packages/", "fix": "eslint --fix --ext .js,.ts,.tsx packages/", "lint:js": "eslint --ext .js packages/", - "test": "jest", + "test": "node ./test", "release": "npm run lint && npm run test && npx lerna version", "docs:dev": "vuepress dev docs-vuepress", "docs:build": "vuepress build docs-vuepress", diff --git a/packages/core/src/platform/patch/react/getDefaultOptions.ios.js b/packages/core/src/platform/patch/react/getDefaultOptions.ios.js index 12ad048939..8d4bc94a74 100644 --- a/packages/core/src/platform/patch/react/getDefaultOptions.ios.js +++ b/packages/core/src/platform/patch/react/getDefaultOptions.ios.js @@ -63,11 +63,14 @@ function getRootProps (props) { return rootProps } -function createInstance ({ propsRef, type, rawOptions, currentInject, validProps, components }) { +function createInstance ({ propsRef, type, rawOptions, currentInject, validProps, components, pageId }) { const instance = Object.create({ setData (data, callback) { return this.__mpxProxy.forceUpdate(data, { sync: true }, callback) }, + getPageId () { + return pageId + }, __getProps () { const props = propsRef.current const propsData = {} @@ -92,7 +95,6 @@ function createInstance ({ propsRef, type, rawOptions, currentInject, validProps }) return propsData }, - __resetInstance () { this.__refs = {} this.__dispatchedSlotSet = new WeakSet() @@ -258,7 +260,7 @@ function hasPageHook (mpxProxy, hookNames) { }) } -const routeContext = createContext(null) +const RouteContext = createContext(null) const triggerPageStatusHook = (mpxProxy, event) => { mpxProxy.callHook(event === 'show' ? ONSHOW : ONHIDE) @@ -282,13 +284,7 @@ const triggerResizeEvent = (mpxProxy) => { } } -function usePageContext (mpxProxy, instance) { - const pageId = useContext(routeContext) - - instance.getPageId = () => { - return pageId - } - +function usePageEffect (mpxProxy, pageId) { useEffect(() => { let unWatch const hasShowHook = hasPageHook(mpxProxy, [ONSHOW, 'show']) @@ -305,7 +301,6 @@ function usePageContext (mpxProxy, instance) { }) } } - return () => { unWatch && unWatch() } @@ -349,11 +344,12 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) { const defaultOptions = memo(forwardRef((props, ref) => { const instanceRef = useRef(null) const propsRef = useRef(null) + const pageId = useContext(RouteContext) propsRef.current = props let isFirst = false if (!instanceRef.current) { isFirst = true - instanceRef.current = createInstance({ propsRef, type, rawOptions, currentInject, validProps, components }) + instanceRef.current = createInstance({ propsRef, type, rawOptions, currentInject, validProps, components, pageId }) } const instance = instanceRef.current useImperativeHandle(ref, () => { @@ -384,7 +380,7 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) { } }) - usePageContext(proxy, instance) + usePageEffect(proxy, pageId) useEffect(() => { if (type === 'page') { @@ -445,14 +441,15 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) { // todo custom portal host for active route createElement(Provider, null, - createElement(routeContext.Provider, + createElement(RouteContext.Provider, { value: currentPageId }, createElement(defaultOptions, { navigation, - route + route, + id: currentPageId } ) ) diff --git a/packages/webpack-plugin/lib/runtime/components/react/utils.ts b/packages/webpack-plugin/lib/runtime/components/react/utils.ts index 14bdc0df5b..0458ff0f3b 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/utils.ts +++ b/packages/webpack-plugin/lib/runtime/components/react/utils.ts @@ -2,14 +2,13 @@ import { useEffect, useRef, ReactNode, ReactElement, FunctionComponent, isValidE import { Dimensions, StyleSheet } from 'react-native' import { isObject, hasOwn, diffAndCloneA, noop } from '@mpxjs/utils' import { VarContext } from './context' +import { ExpressionParser, parseFunc, ReplaceSource } from './parser' export const TEXT_STYLE_REGEX = /color|font.*|text.*|letterSpacing|lineHeight|includeFontPadding|writingDirection/ export const PERCENT_REGEX = /^\s*-?\d+(\.\d+)?%\s*$/ +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 VAR_DEC_REGEX = /^--.*/ -export const VAR_USE_REGEX = /^\s*var\(([^,]+)(?:,(.+))?\)\s*$/ -export const URL_REGEX = /^\s*url\(["']?(.*?)["']?\)\s*$/ export const DEFAULT_FONT_SIZE = 16 export const throwReactWarning = (message: string) => { @@ -167,21 +166,31 @@ function transformPercent (styleObj: Record, percentKeyPaths: Array }) } -function transformVar (styleObj: Record, varKeyPaths: Array>, varContext: Record) { +const VAR_DEC_REGEX = /^--.*/ +const VAR_USE_REGEX = /var\(/ + +function resolveVar (input: string, varContext: Record) { + const parsed = parseFunc(input, 'var') + const replaced = new ReplaceSource(input) + + parsed.forEach(({ start, end, args }) => { + const varName = args[0] + const fallback = args[1] || '' + let varValue = hasOwn(varContext, varName) ? varContext[varName] : fallback + if (VAR_USE_REGEX.test(varValue)) { + varValue = '' + resolveVar(varValue, varContext) + } else { + varValue = '' + formatValue(varValue) + } + replaced.replace(start, end - 1, varValue) + }) + return formatValue(replaced.source()) +} + +function transformVar (styleObj: Record, varKeyPaths: Array>, varContext: Record) { varKeyPaths.forEach((varKeyPath) => { setStyle(styleObj, varKeyPath, ({ target, key, value }) => { - const matched = VAR_USE_REGEX.exec(value) - if (matched) { - const varName = matched[1].trim() - const fallback = (matched[2] || '').trim() - if (hasOwn(varContext, varName)) { - target[key] = varContext[varName] - } else if (fallback) { - target[key] = formatValue(fallback) - } else { - delete target[key] - } - } + target[key] = resolveVar(value, varContext) }) }) } @@ -210,7 +219,7 @@ export function useTransformStyle (styleObj: Record = {}, { enableV const varStyle: Record = {} const normalStyle: Record = {} let hasVarDec = false - const hasVarUse = false + let hasVarUse = false let hasPercent = false const varKeyPaths: Array> = [] const percentKeyPaths: Array> = [] @@ -227,8 +236,9 @@ export function useTransformStyle (styleObj: Record = {}, { enableV normalStyle[key] = isObject(value) ? diffAndCloneA(value).clone : value } } - if (VAR_USE_REGEX.test(value)) { - hasVarDec = true + // 对于var定义中使用的var无需替换值,可以通过resolveVar递归解析出值 + if (!VAR_DEC_REGEX.test(key) && VAR_USE_REGEX.test(value)) { + hasVarUse = true varKeyPaths.push(keyPath.slice()) } }