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.
126 lines
3.3 KiB
126 lines
3.3 KiB
let valueParser = require('postcss-value-parser') |
|
|
|
function parseValue (value) { |
|
let parsed = value.match(/([\d.-]+)(.*)/) |
|
if (!parsed || !parsed[1] || !parsed[2] || isNaN(parsed[1])) { |
|
return undefined |
|
} |
|
return [parseFloat(parsed[1]), parsed[2]] |
|
} |
|
|
|
function compose (first, second, third) { |
|
if (first && second && third) { |
|
return `max(${first}, min(${second}, ${third}))` |
|
} |
|
if (first && second) { |
|
return `max(${first}, ${second})` |
|
} |
|
|
|
return first |
|
} |
|
|
|
function updateValue (declaration, value, preserve) { |
|
let newValue = value |
|
let newValueAst = valueParser(value) |
|
let valueAST = valueParser(declaration.value) |
|
// Walk can't be interrupted, so we only care about first |
|
let foundClamp = false |
|
|
|
valueAST.walk((node, index, nodes) => { |
|
let isClamp = node.type === 'function' && node.value === 'clamp' |
|
|
|
if (!isClamp || foundClamp) { |
|
return |
|
} |
|
|
|
foundClamp = true |
|
nodes[index] = newValueAst |
|
}) |
|
|
|
if (foundClamp) { |
|
newValue = valueAST.toString() |
|
} |
|
|
|
if (preserve) { |
|
declaration.cloneBefore({ value: newValue }) |
|
} else { |
|
declaration.value = newValue |
|
} |
|
} |
|
|
|
module.exports = opts => { |
|
opts = opts || {} |
|
let precalculate = opts.precalculate ? Boolean(opts.precalculate) : false |
|
let preserve = opts.preserve ? Boolean(opts.preserve) : false |
|
|
|
return { |
|
postcssPlugin: 'postcss-clamp', |
|
Declaration (decl) { |
|
if (!decl || !decl.value.includes('clamp')) { |
|
return |
|
} |
|
valueParser(decl.value).walk(node => { |
|
let nodes = node.nodes |
|
if ( |
|
node.type !== 'function' || |
|
node.value !== 'clamp' || |
|
nodes.length !== 5 |
|
) { |
|
return |
|
} |
|
let first = nodes[0] |
|
let second = nodes[2] |
|
let third = nodes[4] |
|
let naive = compose( |
|
valueParser.stringify(first), |
|
valueParser.stringify(second), |
|
valueParser.stringify(third) |
|
) |
|
if (!precalculate || second.type !== 'word' || third.type !== 'word') { |
|
updateValue(decl, naive, preserve) |
|
return |
|
} |
|
let parsedSecond = parseValue(second.value) |
|
let parsedThird = parseValue(third.value) |
|
if (parsedSecond === undefined || parsedThird === undefined) { |
|
updateValue(decl, naive, preserve) |
|
return |
|
} |
|
let [secondValue, secondUnit] = parsedSecond |
|
let [thirdValue, thirdUnit] = parsedThird |
|
if (secondUnit !== thirdUnit) { |
|
updateValue(decl, naive, preserve) |
|
return |
|
} |
|
let parsedFirst = parseValue(first.value) |
|
if (parsedFirst === undefined) { |
|
let secondThirdValue = `${secondValue + thirdValue}${secondUnit}` |
|
updateValue( |
|
decl, |
|
compose(valueParser.stringify(first), secondThirdValue), |
|
preserve |
|
) |
|
return |
|
} |
|
let [firstValue, firstUnit] = parsedFirst |
|
if (firstUnit !== secondUnit) { |
|
let secondThirdValue = `${secondValue + thirdValue}${secondUnit}` |
|
updateValue( |
|
decl, |
|
compose(valueParser.stringify(first), secondThirdValue), |
|
preserve |
|
) |
|
return |
|
} |
|
|
|
updateValue( |
|
decl, |
|
compose(`${firstValue + secondValue + thirdValue}${secondUnit}`), |
|
preserve |
|
) |
|
}) |
|
} |
|
} |
|
} |
|
|
|
module.exports.postcss = true
|
|
|