You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

438 lines
15 KiB
JavaScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import { hyphenate, capitalize } from '@vue/shared';
function createDecl(prop, value, important, raws, source) {
const decl = {
type: 'decl',
prop,
value: value.toString(),
raws,
source,
};
if (important) {
decl.important = true;
}
return decl;
}
const backgroundColor = 'backgroundColor';
const backgroundImage = 'backgroundImage';
const handleTransformBackground = (decl) => {
const { value, important, raws, source } = decl;
if (/^#?\S+$/.test(value) || /^rgba?(.+)$/.test(value)) {
return [
createDecl(backgroundImage, 'none', important, raws, source),
createDecl(backgroundColor, value, important, raws, source),
];
}
else if (/^linear-gradient(.+)$/.test(value)) {
return [
createDecl(backgroundImage, value, important, raws, source),
createDecl(backgroundColor, 'transparent', important, raws, source),
];
}
else if (value == '') {
return [
createDecl(backgroundImage, 'none', important, raws, source),
createDecl(backgroundColor, 'transparent', important, raws, source),
];
}
return [decl];
};
const handleTransformBackgroundNvue = (decl) => {
const { value, important, raws, source } = decl;
if (/^#?\S+$/.test(value) || /^rgba?(.+)$/.test(value)) {
return [createDecl(backgroundColor, value, important, raws, source)];
}
else if (/^linear-gradient(.+)$/.test(value)) {
return [createDecl(backgroundImage, value, important, raws, source)];
}
else if (value == '') {
return [decl];
}
return [decl];
};
function createTransformBackground(options) {
return (decl) => {
// nvue 平台维持原有逻辑不变
const isUvuePlatform = options.type === 'uvue';
if (isUvuePlatform) {
return handleTransformBackground(decl);
}
else {
return handleTransformBackgroundNvue(decl);
}
};
}
function borderTop() {
return 'borderTop';
}
function borderRight() {
return 'borderRight';
}
function borderBottom() {
return 'borderBottom';
}
function borderLeft() {
return 'borderLeft';
}
const transformBorderColor = (decl) => {
const { prop, value, important, raws, source } = decl;
const _property_split = hyphenate(prop).split('-');
let property = _property_split[_property_split.length - 1];
{
property = capitalize(property);
}
const splitResult = value.replace(/\s*,\s*/g, ',').split(/\s+/); // 1pt
switch (splitResult.length) {
case 1:
if (_property_split.length === 3) {
// border-top-width
return [decl];
}
// border-width
splitResult.push(splitResult[0], splitResult[0], splitResult[0]);
break;
case 2:
splitResult.push(splitResult[0], splitResult[1]);
break;
case 3:
splitResult.push(splitResult[1]);
break;
}
return [
createDecl(borderTop() + property, splitResult[0], important, raws, source),
createDecl(borderRight() + property, splitResult[1], important, raws, source),
createDecl(borderBottom() + property, splitResult[2], important, raws, source),
createDecl(borderLeft() + property, splitResult[3], important, raws, source),
];
};
const transformBorderColorNvue = (decl) => {
const { prop, value, important, raws, source } = decl;
let property = hyphenate(prop).split('-')[1];
{
property = capitalize(property);
}
const splitResult = value.replace(/\s*,\s*/g, ',').split(/\s+/);
switch (splitResult.length) {
case 1:
return [decl];
case 2:
splitResult.push(splitResult[0], splitResult[1]);
break;
case 3:
splitResult.push(splitResult[1]);
break;
}
return [
createDecl(borderTop + property, splitResult[0], important, raws, source),
createDecl(borderRight + property, splitResult[1], important, raws, source),
createDecl(borderBottom + property, splitResult[2], important, raws, source),
createDecl(borderLeft + property, splitResult[3], important, raws, source),
];
};
const transformBorderStyle = transformBorderColor;
const transformBorderStyleNvue = transformBorderColorNvue;
const transformBorderWidth = transformBorderColor;
const transformBorderWidthNvue = transformBorderColorNvue;
function createTransformBorder(options) {
return (decl) => {
const borderWidth = () => {
return 'Width';
};
const borderStyle = () => {
return 'Style';
};
const borderColor = () => {
return 'Color';
};
const { prop, value, important, raws, source } = decl;
const splitResult = value.replace(/\s*,\s*/g, ',').split(/\s+/);
const result = [
/^[\d\.]+\S*|^(thin|medium|thick)$/,
/^(solid|dashed|dotted|none)$/,
/\S+/,
].map((item) => {
const index = splitResult.findIndex((str) => item.test(str));
return index < 0 ? null : splitResult.splice(index, 1)[0];
});
const isUvuePlatform = options.type == 'uvue';
if (isUvuePlatform) {
if (splitResult.length > 0 && value != '') {
return [decl];
}
}
else {
// nvue 维持不变
if (splitResult.length > 0) {
return [decl];
}
}
const defaultWidth = (str) => {
if (str != null) {
return str.trim();
}
if (options.type == 'uvue') {
return 'medium';
}
return '0';
};
const defaultStyle = (str) => {
if (str != null) {
return str.trim();
}
if (options.type == 'uvue') {
return 'none';
}
return 'solid';
};
const defaultColor = (str) => {
if (str != null) {
return str.trim();
}
return '#000000';
};
if (!isUvuePlatform) {
// nvue 维持不变
return [
createDecl(prop + borderWidth(), defaultWidth(result[0]), important, raws, source),
createDecl(prop + borderStyle(), defaultStyle(result[1]), important, raws, source),
createDecl(prop + borderColor(), defaultColor(result[2]), important, raws, source),
];
}
return [
...transformBorderWidth(createDecl(prop + borderWidth(), defaultWidth(result[0]), important, raws, source)),
...transformBorderStyle(createDecl(prop + borderStyle(), defaultStyle(result[1]), important, raws, source)),
...transformBorderColor(createDecl(prop + borderColor(), defaultColor(result[2]), important, raws, source)),
];
};
}
function createTransformBorderNvue(options) {
return (decl) => {
const borderWidth = 'Width';
const borderStyle = 'Style';
const borderColor = 'Color';
const { prop, value, important, raws, source } = decl;
const splitResult = value.replace(/\s*,\s*/g, ',').split(/\s+/);
const result = [
/^[\d\.]+\S*|^(thin|medium|thick)$/,
/^(solid|dashed|dotted|none)$/,
/\S+/,
].map((item) => {
const index = splitResult.findIndex((str) => item.test(str));
return index < 0 ? null : splitResult.splice(index, 1)[0];
});
if (splitResult.length) {
return [decl];
}
return [
createDecl(prop + borderWidth, (result[0] || '0').trim(), important, raws, source),
createDecl(prop + borderStyle, (result[1] || 'solid').trim(), important, raws, source),
createDecl(prop + borderColor, (result[2] || '#000000').trim(), important, raws, source),
];
};
}
const borderTopLeftRadius = 'borderTopLeftRadius';
const borderTopRightRadius = 'borderTopRightRadius';
const borderBottomRightRadius = 'borderBottomRightRadius';
const borderBottomLeftRadius = 'borderBottomLeftRadius';
const transformBorderRadius = (decl) => {
const { value, important, raws, source } = decl;
const splitResult = value.split(/\s+/);
if (value.includes('/')) {
return [decl];
}
switch (splitResult.length) {
case 1:
splitResult.push(splitResult[0], splitResult[0], splitResult[0]);
break;
case 2:
splitResult.push(splitResult[0], splitResult[1]);
break;
case 3:
splitResult.push(splitResult[1]);
break;
}
return [
createDecl(borderTopLeftRadius, splitResult[0], important, raws, source),
createDecl(borderTopRightRadius, splitResult[1], important, raws, source),
createDecl(borderBottomRightRadius, splitResult[2], important, raws, source),
createDecl(borderBottomLeftRadius, splitResult[3], important, raws, source),
];
};
const transformBorderRadiusNvue = (decl) => {
const { value, important, raws, source } = decl;
const splitResult = value.split(/\s+/);
if (value.includes('/')) {
return [decl];
}
// const isUvuePlatform = options.type == 'uvue'
switch (splitResult.length) {
case 1:
return [decl];
case 2:
splitResult.push(splitResult[0], splitResult[1]);
break;
case 3:
splitResult.push(splitResult[1]);
break;
}
return [
createDecl(borderTopLeftRadius, splitResult[0], important, raws, source),
createDecl(borderTopRightRadius, splitResult[1], important, raws, source),
createDecl(borderBottomRightRadius, splitResult[2], important, raws, source),
createDecl(borderBottomLeftRadius, splitResult[3], important, raws, source),
];
};
const flexDirection = 'flexDirection';
const flexWrap = 'flexWrap';
const transformFlexFlow = (decl) => {
const { value, important, raws, source } = decl;
const splitResult = value.split(/\s+/);
const result = [
/^(column|column-reverse|row|row-reverse)$/,
/^(nowrap|wrap|wrap-reverse)$/,
].map((item) => {
const index = splitResult.findIndex((str) => item.test(str));
return index < 0 ? null : splitResult.splice(index, 1)[0];
});
if (splitResult.length) {
return [decl];
}
return [
createDecl(flexDirection, result[0] || 'column', important, raws, source),
createDecl(flexWrap, result[1] || 'nowrap', important, raws, source),
];
};
const top = 'Top';
const right = 'Right';
const bottom = 'Bottom';
const left = 'Left';
const createTransformBox = (type) => {
return (decl) => {
const { value, important, raws, source } = decl;
const splitResult = value.split(/\s+/);
switch (splitResult.length) {
case 1:
splitResult.push(splitResult[0], splitResult[0], splitResult[0]);
break;
case 2:
splitResult.push(splitResult[0], splitResult[1]);
break;
case 3:
splitResult.push(splitResult[1]);
break;
}
return [
createDecl(type + top, splitResult[0], important, raws, source),
createDecl(type + right, splitResult[1], important, raws, source),
createDecl(type + bottom, splitResult[2], important, raws, source),
createDecl(type + left, splitResult[3], important, raws, source),
];
};
};
const transformMargin = createTransformBox('margin');
const transformPadding = createTransformBox('padding');
const transitionProperty = 'transitionProperty';
const transitionDuration = 'transitionDuration';
const transitionTimingFunction = 'transitionTimingFunction';
const transitionDelay = 'transitionDelay';
const transformTransition = (decl) => {
const { value, important, raws, source } = decl;
const result = [];
let match;
// 针对 cubic-bezier 特殊处理
// eg: cubic-bezier(0.42, 0, 1.0, 3) // (0.2,-2,0.8,2)
if (decl.value.includes('cubic-bezier')) {
const CHUNK_REGEXP = /^(\S*)?\s*(\d*\.?\d+(?:ms|s)?)?\s*((\S*)|cubic-bezier\(.*\))?\s*(\d*\.?\d+(?:ms|s)?)?$/;
match = value.match(CHUNK_REGEXP);
}
else {
const CHUNK_REGEXP = /^(\S*)?\s*(\d*\.?\d+(?:ms|s)?)?\s*(\S*)?\s*(\d*\.?\d+(?:ms|s)?)?$/;
match = value.match(CHUNK_REGEXP);
}
if (!match) {
return result;
}
match[1] &&
result.push(createDecl(transitionProperty, match[1], important, raws, source));
match[2] &&
result.push(createDecl(transitionDuration, match[2], important, raws, source));
match[3] &&
result.push(createDecl(transitionTimingFunction, match[3], important, raws, source));
match[4] &&
result.push(createDecl(transitionDelay, match[4], important, raws, source));
return result;
};
function getDeclTransforms(options) {
const transformBorder = options.type == 'uvue'
? createTransformBorder(options)
: createTransformBorderNvue();
const styleMap = {
transition: transformTransition,
border: transformBorder,
background: createTransformBackground(options),
borderTop: transformBorder,
borderRight: transformBorder,
borderBottom: transformBorder,
borderLeft: transformBorder,
borderStyle: options.type == 'uvue' ? transformBorderStyle : transformBorderStyleNvue,
borderWidth: options.type == 'uvue' ? transformBorderWidth : transformBorderWidthNvue,
borderColor: options.type == 'uvue' ? transformBorderColor : transformBorderColorNvue,
borderRadius: options.type == 'uvue'
? transformBorderRadius
: transformBorderRadiusNvue,
// uvue已经支持这些简写属性不需要展开
// margin,padding继续展开确保样式的优先级
margin: transformMargin,
padding: transformPadding,
/* eslint-disable no-restricted-syntax */
...(options.type !== 'uvue'
? {
flexFlow: transformFlexFlow,
}
: {}),
};
let result = {};
{
result = styleMap;
}
return result;
}
let DeclTransforms;
const expanded = Symbol('expanded');
function expand(options) {
const plugin = {
postcssPlugin: `${options.type || 'nvue'}:expand`,
Declaration(decl) {
if (decl[expanded]) {
return;
}
if (!DeclTransforms) {
DeclTransforms = getDeclTransforms(options);
}
const transform = DeclTransforms[decl.prop];
if (transform) {
const res = transform(decl);
const isSame = res.length === 1 && res[0] === decl;
if (!isSame) {
decl.replaceWith(res);
}
}
decl[expanded] = true;
},
};
return plugin;
}
export { expand };