| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249 |
- 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 transformBackground = (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)];
- }
- return [decl];
- };
- const borderWidth = 'Width';
- const borderStyle = 'Style';
- const borderColor = 'Color';
- function createTransformBorder(options) {
- return (decl) => {
- 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] || (options.type === 'uvue' ? 'medium' : '0')).trim(), important, raws, source),
- createDecl(prop + borderStyle, (result[1] || (options.type === 'uvue' ? 'none' : 'solid')).trim(), important, raws, source),
- createDecl(prop + borderColor, (result[2] || '#000000').trim(), important, raws, source),
- ];
- };
- }
- const borderTop = 'borderTop';
- const borderRight = 'borderRight';
- const borderBottom = 'borderBottom';
- const borderLeft = 'borderLeft';
- const transformBorderColor = (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 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:
- 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 transformBorderStyle = transformBorderColor;
- const transformBorderWidth = transformBorderColor;
- 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 CHUNK_REGEXP = /^(\S*)?\s*(\d*\.?\d+(?:ms|s)?)?\s*(\S*)?\s*(\d*\.?\d+(?:ms|s)?)?$/;
- const { value, important, raws, source } = decl;
- const result = [];
- const 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 = createTransformBorder(options);
- const styleMap = {
- transition: transformTransition,
- border: transformBorder,
- background: transformBackground,
- borderTop: transformBorder,
- borderRight: transformBorder,
- borderBottom: transformBorder,
- borderLeft: transformBorder,
- borderStyle: transformBorderStyle,
- borderWidth: transformBorderWidth,
- borderColor: transformBorderColor,
- borderRadius: transformBorderRadius,
- // 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: '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 };
|