Skip to content

Commit

Permalink
t push
Browse files Browse the repository at this point in the history
Merge branch 'feat-rn-atomic-css' of github.com:didi/mpx into feat-rn-atomic-css
  • Loading branch information
mater1996 committed Jan 3, 2025
2 parents 43219d9 + a00c069 commit e3e4dac
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ export default function styleHelperMixin () {
Object.assign(result, appClassMap[className])
} else if (unoClassMap[className]) {
Object.assign(result, unoClassMap[className])
} else if (this.__props[className] && isObject(this.__props[className])) {
} else if (isObject(this.__props[className])) {
// externalClasses必定以对象形式传递下来
Object.assign(result, this.__props[className])
}
Expand Down
1 change: 0 additions & 1 deletion packages/core/src/platform/createApp.ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
15 changes: 7 additions & 8 deletions packages/core/src/platform/patch/getDefaultOptions.ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
148 changes: 89 additions & 59 deletions packages/webpack-plugin/lib/runtime/components/react/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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\(/

Expand All @@ -37,7 +39,7 @@ function getSafeAreaInset (name: string) {
}

export function omit<T, K extends string> (obj: T, fields: K[]): Omit<T, K> {
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]
Expand Down Expand Up @@ -77,7 +79,7 @@ export const parseInlineStyle = (inlineStyle = ''): Record<string, string> => {
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()) })
}, {})
}

Expand Down Expand Up @@ -286,11 +288,15 @@ interface TransformStyleConfig {

export function useTransformStyle (styleObj: Record<string, any> = {}, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight }: TransformStyleConfig) {
const varStyle: Record<string, any> = {}
const unoVarStyle: Record<string, any> = {}
const normalStyle: Record<string, any> = {}
const normalStyleRef = useRef<Record<string, any>>({})
const normalStyleChangedRef = useRef(false)
let hasVarDec = false
let hasVarUse = false
let hasSelfPercent = false
const varKeyPaths: Array<Array<string>> = []
const unoVarKeyPaths: Array<Array<string>> = []
const percentKeyPaths: Array<Array<string>> = []
const calcKeyPaths: Array<Array<string>> = []
const envKeyPaths: Array<Array<string>> = []
Expand All @@ -299,7 +305,9 @@ export function useTransformStyle (styleObj: Record<string, any> = {}, { 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 {
Expand All @@ -308,96 +316,118 @@ export function useTransformStyle (styleObj: Record<string, any> = {}, { 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
}
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 {
Expand Down Expand Up @@ -565,7 +595,7 @@ export const useStableCallback = <T extends AnyFunc | null | undefined> (
}

export const usePrevious = <T, > (value: T): T | undefined => {
const ref = useRef<T | undefined>(undefined)
const ref = useRef<T | undefined>()
const prev = ref.current
ref.current = value
return prev
Expand Down

0 comments on commit e3e4dac

Please sign in to comment.