From 80a5b531f671428daa871587b0fc26ec058950ea Mon Sep 17 00:00:00 2001 From: Zev Zhu <45655660+aibayanyu20@users.noreply.github.com> Date: Fri, 18 Aug 2023 09:48:10 +0800 Subject: [PATCH] feat: add px2rem in cssinjs (#6817) * fix: fix table column data is passed into chlidren is undefined or null errorr * feat: add px2rem in cssinjs --- components/_util/cssinjs/index.ts | 8 +- components/_util/cssinjs/linters/index.ts | 1 + .../cssinjs/linters/parentSelectorLinter.ts | 15 ++++ .../_util/cssinjs/transformers/px2rem.ts | 76 +++++++++++++++++++ 4 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 components/_util/cssinjs/linters/parentSelectorLinter.ts create mode 100644 components/_util/cssinjs/transformers/px2rem.ts diff --git a/components/_util/cssinjs/index.ts b/components/_util/cssinjs/index.ts index 49d0443b53..a229437877 100644 --- a/components/_util/cssinjs/index.ts +++ b/components/_util/cssinjs/index.ts @@ -3,14 +3,14 @@ import type { CSSInterpolation, CSSObject } from './hooks/useStyleRegister'; import useStyleRegister, { extractStyle } from './hooks/useStyleRegister'; import Keyframes from './Keyframes'; import type { Linter } from './linters'; -import { legacyNotSelectorLinter, logicalPropertiesLinter } from './linters'; +import { legacyNotSelectorLinter, logicalPropertiesLinter, parentSelectorLinter } from './linters'; import type { StyleContextProps, StyleProviderProps } from './StyleContext'; import { createCache, useStyleInject, useStyleProvider, StyleProvider } from './StyleContext'; import type { DerivativeFunc, TokenType } from './theme'; import { createTheme, Theme } from './theme'; import type { Transformer } from './transformers/interface'; import legacyLogicalPropertiesTransformer from './transformers/legacyLogicalProperties'; - +import px2remTransformer from './transformers/px2rem'; const cssinjs = { Theme, createTheme, @@ -24,10 +24,12 @@ const cssinjs = { // Transformer legacyLogicalPropertiesTransformer, + px2remTransformer, // Linters logicalPropertiesLinter, legacyNotSelectorLinter, + parentSelectorLinter, // cssinjs StyleProvider, @@ -45,10 +47,12 @@ export { // Transformer legacyLogicalPropertiesTransformer, + px2remTransformer, // Linters logicalPropertiesLinter, legacyNotSelectorLinter, + parentSelectorLinter, // cssinjs StyleProvider, diff --git a/components/_util/cssinjs/linters/index.ts b/components/_util/cssinjs/linters/index.ts index a7a3ee1009..ae7d8cc9a7 100644 --- a/components/_util/cssinjs/linters/index.ts +++ b/components/_util/cssinjs/linters/index.ts @@ -3,3 +3,4 @@ export { default as hashedAnimationLinter } from './hashedAnimationLinter'; export type { Linter } from './interface'; export { default as legacyNotSelectorLinter } from './legacyNotSelectorLinter'; export { default as logicalPropertiesLinter } from './logicalPropertiesLinter'; +export { default as parentSelectorLinter } from './parentSelectorLinter'; diff --git a/components/_util/cssinjs/linters/parentSelectorLinter.ts b/components/_util/cssinjs/linters/parentSelectorLinter.ts new file mode 100644 index 0000000000..7a061ce8a5 --- /dev/null +++ b/components/_util/cssinjs/linters/parentSelectorLinter.ts @@ -0,0 +1,15 @@ +import type { Linter } from '..'; +import { lintWarning } from './utils'; + +const linter: Linter = (_key, _value, info) => { + if ( + info.parentSelectors.some(selector => { + const selectors = selector.split(','); + return selectors.some(item => item.split('&').length > 2); + }) + ) { + lintWarning('Should not use more than one `&` in a selector.', info); + } +}; + +export default linter; diff --git a/components/_util/cssinjs/transformers/px2rem.ts b/components/_util/cssinjs/transformers/px2rem.ts new file mode 100644 index 0000000000..328cfbc42d --- /dev/null +++ b/components/_util/cssinjs/transformers/px2rem.ts @@ -0,0 +1,76 @@ +/** + * respect https://github.com/cuth/postcss-pxtorem + */ +import unitless from '@emotion/unitless'; +import type { CSSObject } from '..'; +import type { Transformer } from './interface'; + +interface Options { + /** + * The root font size. + * @default 16 + */ + rootValue?: number; + /** + * The decimal numbers to allow the REM units to grow to. + * @default 5 + */ + precision?: number; + /** + * Whether to allow px to be converted in media queries. + * @default false + */ + mediaQuery?: boolean; +} + +const pxRegex = /url\([^)]+\)|var\([^)]+\)|(\d*\.?\d+)px/g; + +function toFixed(number: number, precision: number) { + const multiplier = Math.pow(10, precision + 1), + wholeNumber = Math.floor(number * multiplier); + return (Math.round(wholeNumber / 10) * 10) / multiplier; +} + +const transform = (options: Options = {}): Transformer => { + const { rootValue = 16, precision = 5, mediaQuery = false } = options; + + const pxReplace = (m: string, $1: any) => { + if (!$1) return m; + const pixels = parseFloat($1); + // covenant: pixels <= 1, not transform to rem @zombieJ + if (pixels <= 1) return m; + const fixedVal = toFixed(pixels / rootValue, precision); + return `${fixedVal}rem`; + }; + + const visit = (cssObj: CSSObject): CSSObject => { + const clone: CSSObject = { ...cssObj }; + + Object.entries(cssObj).forEach(([key, value]) => { + if (typeof value === 'string' && value.includes('px')) { + const newValue = value.replace(pxRegex, pxReplace); + clone[key] = newValue; + } + + // no unit + if (!unitless[key] && typeof value === 'number' && value !== 0) { + clone[key] = `${value}px`.replace(pxRegex, pxReplace); + } + + // Media queries + const mergedKey = key.trim(); + if (mergedKey.startsWith('@') && mergedKey.includes('px') && mediaQuery) { + const newKey = key.replace(pxRegex, pxReplace); + + clone[newKey] = clone[key]; + delete clone[key]; + } + }); + + return clone; + }; + + return { visit }; +}; + +export default transform;