You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
225 lines
7.5 KiB
225 lines
7.5 KiB
import { hyphenate, capitalize, extend } 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'; |
|
const transformBorder = (decl) => { |
|
const { prop, value, important, raws, source } = decl; |
|
const splitResult = value.replace(/\s*,\s*/g, ',').split(/\s+/); |
|
const result = [/^[\d\.]+\S*$/, /^(solid|dashed|dotted)$/, /\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 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; |
|
}; |
|
|
|
const DeclTransforms = { |
|
transition: transformTransition, |
|
margin: transformMargin, |
|
padding: transformPadding, |
|
border: transformBorder, |
|
background: transformBackground, |
|
}; |
|
{ |
|
extend(DeclTransforms, { |
|
borderTop: transformBorder, |
|
borderRight: transformBorder, |
|
borderBottom: transformBorder, |
|
borderLeft: transformBorder, |
|
borderStyle: transformBorderStyle, |
|
borderWidth: transformBorderWidth, |
|
borderColor: transformBorderColor, |
|
borderRadius: transformBorderRadius, |
|
flexFlow: transformFlexFlow, |
|
}); |
|
} |
|
const expanded = Symbol('expanded'); |
|
const expand = { |
|
postcssPlugin: 'nvue:expand', |
|
Declaration(decl) { |
|
if (decl[expanded]) { |
|
return; |
|
} |
|
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; |
|
}, |
|
}; |
|
|
|
export { expand };
|
|
|