ant-design-vue/components/_util/cssinjs/transformers/legacyLogicalProperties.ts

163 lines
4.8 KiB
TypeScript

import type { CSSObject } from '..';
import type { Transformer } from './interface';
function splitValues(value: string | number) {
if (typeof value === 'number') {
return [value];
}
const splitStyle = String(value).split(/\s+/);
// Combine styles split in brackets, like `calc(1px + 2px)`
let temp = '';
let brackets = 0;
return splitStyle.reduce<string[]>((list, item) => {
if (item.includes('(')) {
temp += item;
brackets += item.split('(').length - 1;
} else if (item.includes(')')) {
temp += ` ${item}`;
brackets -= item.split(')').length - 1;
if (brackets === 0) {
list.push(temp);
temp = '';
}
} else if (brackets > 0) {
temp += ` ${item}`;
} else {
list.push(item);
}
return list;
}, []);
}
type MatchValue = string[] & {
notSplit?: boolean;
};
function noSplit(list: MatchValue): MatchValue {
list.notSplit = true;
return list;
}
const keyMap: Record<string, MatchValue> = {
// Inset
inset: ['top', 'right', 'bottom', 'left'],
insetBlock: ['top', 'bottom'],
insetBlockStart: ['top'],
insetBlockEnd: ['bottom'],
insetInline: ['left', 'right'],
insetInlineStart: ['left'],
insetInlineEnd: ['right'],
// Margin
marginBlock: ['marginTop', 'marginBottom'],
marginBlockStart: ['marginTop'],
marginBlockEnd: ['marginBottom'],
marginInline: ['marginLeft', 'marginRight'],
marginInlineStart: ['marginLeft'],
marginInlineEnd: ['marginRight'],
// Padding
paddingBlock: ['paddingTop', 'paddingBottom'],
paddingBlockStart: ['paddingTop'],
paddingBlockEnd: ['paddingBottom'],
paddingInline: ['paddingLeft', 'paddingRight'],
paddingInlineStart: ['paddingLeft'],
paddingInlineEnd: ['paddingRight'],
// Border
borderBlock: noSplit(['borderTop', 'borderBottom']),
borderBlockStart: noSplit(['borderTop']),
borderBlockEnd: noSplit(['borderBottom']),
borderInline: noSplit(['borderLeft', 'borderRight']),
borderInlineStart: noSplit(['borderLeft']),
borderInlineEnd: noSplit(['borderRight']),
// Border width
borderBlockWidth: ['borderTopWidth', 'borderBottomWidth'],
borderBlockStartWidth: ['borderTopWidth'],
borderBlockEndWidth: ['borderBottomWidth'],
borderInlineWidth: ['borderLeftWidth', 'borderRightWidth'],
borderInlineStartWidth: ['borderLeftWidth'],
borderInlineEndWidth: ['borderRightWidth'],
// Border style
borderBlockStyle: ['borderTopStyle', 'borderBottomStyle'],
borderBlockStartStyle: ['borderTopStyle'],
borderBlockEndStyle: ['borderBottomStyle'],
borderInlineStyle: ['borderLeftStyle', 'borderRightStyle'],
borderInlineStartStyle: ['borderLeftStyle'],
borderInlineEndStyle: ['borderRightStyle'],
// Border color
borderBlockColor: ['borderTopColor', 'borderBottomColor'],
borderBlockStartColor: ['borderTopColor'],
borderBlockEndColor: ['borderBottomColor'],
borderInlineColor: ['borderLeftColor', 'borderRightColor'],
borderInlineStartColor: ['borderLeftColor'],
borderInlineEndColor: ['borderRightColor'],
// Border radius
borderStartStartRadius: ['borderTopLeftRadius'],
borderStartEndRadius: ['borderTopRightRadius'],
borderEndStartRadius: ['borderBottomLeftRadius'],
borderEndEndRadius: ['borderBottomRightRadius'],
};
function skipCheck(value: string | number) {
return { _skip_check_: true, value };
}
/**
* Convert css logical properties to legacy properties.
* Such as: `margin-block-start` to `margin-top`.
* Transform list:
* - inset
* - margin
* - padding
* - border
*/
const transform: Transformer = {
visit: cssObj => {
const clone: CSSObject = {};
Object.keys(cssObj).forEach(key => {
const value = cssObj[key];
const matchValue = keyMap[key];
if (matchValue && (typeof value === 'number' || typeof value === 'string')) {
const values = splitValues(value);
if (matchValue.length && matchValue.notSplit) {
// not split means always give same value like border
matchValue.forEach(matchKey => {
clone[matchKey] = skipCheck(value);
});
} else if (matchValue.length === 1) {
// Handle like `marginBlockStart` => `marginTop`
clone[matchValue[0]] = skipCheck(value);
} else if (matchValue.length === 2) {
// Handle like `marginBlock` => `marginTop` & `marginBottom`
matchValue.forEach((matchKey, index) => {
clone[matchKey] = skipCheck(values[index] ?? values[0]);
});
} else if (matchValue.length === 4) {
// Handle like `inset` => `top` & `right` & `bottom` & `left`
matchValue.forEach((matchKey, index) => {
clone[matchKey] = skipCheck(values[index] ?? values[index - 2] ?? values[0]);
});
} else {
clone[key] = value;
}
} else {
clone[key] = value;
}
});
return clone;
},
};
export default transform;