gradient-utils
Version:
css and svg gradient utils
204 lines (200 loc) • 6.67 kB
JavaScript
;
var utils = require('../utils-HrBEEUzj.js');
const linearPrefix = 'linear-gradient(';
const repeatingPrefix = 'repeating-linear-gradient(';
const parseLinearGradient = (gradient) => linearGradientParser(gradient, linearPrefix);
const parseRepeatingLinearGradient = (gradient) => linearGradientParser(gradient, repeatingPrefix, true);
const linearGradientParser = (gradient, prefix, repeatable = false) => {
if (!gradient) {
return null;
}
gradient = utils.removeCSSComments(gradient).toLowerCase();
//fix the casting toLowerCase. Otherwise, we can lose currentColor or should do insensitivity search every time
gradient = gradient.replaceAll('currentcolor', 'currentColor');
gradient = gradient.trim();
if (!gradient.startsWith(prefix) || !gradient.endsWith(')')) {
return null;
}
gradient = gradient.substring(prefix.length, gradient.length - 1).trim();
const extractAngleResult = extractAngle(gradient);
if (!extractAngleResult) {
return null;
}
let linearGradient;
if ('angle' in extractAngleResult) {
linearGradient = {
angle: extractAngleResult.angle,
colorStops: [],
};
}
else if ('sideOrCorner' in extractAngleResult) {
linearGradient = {
sideOrCorner: extractAngleResult.sideOrCorner,
colorStops: [],
};
}
else {
linearGradient = {
interpolation: extractAngleResult.interpolation,
colorStops: [],
};
}
gradient = extractAngleResult.gradientWithoutAngle;
const colorStops = parseColorStops(gradient);
if (!colorStops) {
return null;
}
linearGradient.colorStops = colorStops;
if (repeatable) {
linearGradient.repeatable = true;
}
return linearGradient;
};
const extractAngle = (gradient) => {
const unit = 'deg';
let degAngle = 180;
let sourceValue = '';
const angleUnit = utils.extractStartValueWithUnit(gradient, unit);
if (angleUnit && utils.isAngleUnit(angleUnit.unit)) {
degAngle = utils.angleToDeg(angleUnit.value, angleUnit.unit);
sourceValue = angleUnit.sourceValue;
const gradientWithoutAngle = utils.extractStartComma(angleUnit.source);
if (gradientWithoutAngle == null) {
return null;
}
return {
angle: {
unit: angleUnit.unit,
degAngle,
sourceValue,
},
gradientWithoutAngle,
};
}
const sideOrCorner = extractSideOrCorner(gradient);
if (sideOrCorner) {
return {
sideOrCorner: {
top: sideOrCorner.top,
bottom: sideOrCorner.bottom,
left: sideOrCorner.left,
right: sideOrCorner.right,
sourceValue: sideOrCorner.sourceValue,
},
gradientWithoutAngle: sideOrCorner.gradientWithoutAngle,
};
}
const interpolation = extractInterpolation(gradient);
if (interpolation) {
return interpolation;
}
return {
angle: {
unit,
degAngle,
sourceValue,
},
gradientWithoutAngle: gradient,
};
};
const extractSideOrCorner = (source) => {
const match = source.match(utils.START_WITH_SIDE_OR_CORNER_REGEX);
if (match) {
const sourceValue = match[0];
const top = sourceValue.includes('top');
const bottom = sourceValue.includes('bottom');
const left = sourceValue.includes('left');
const right = sourceValue.includes('right');
const gradientWithoutAngle = utils.extractStartComma(source.substring(sourceValue.length));
if (gradientWithoutAngle == null) {
return null;
}
return {
top,
bottom,
left,
right,
sourceValue,
gradientWithoutAngle,
};
}
return null;
};
const extractInterpolation = (source) => {
const match = source.match(utils.START_WITH_INTERPOLATION);
if (match && match.groups) {
return {
interpolation: match.groups.interpolation,
gradientWithoutAngle: source.substring(match[0].length).trim(),
};
}
return null;
};
const parseColorStop = (source) => {
let colorStop = null;
const colorResult = utils.extractColor(source);
if (colorResult) {
source = colorResult.source;
colorStop = {
color: colorResult.color,
alpha: colorResult.alpha,
};
}
let valueWithUnit = utils.extractStartValueWithUnit(source);
if (valueWithUnit) {
source = valueWithUnit.source;
if (!colorStop && valueWithUnit.unit === '%') {
colorStop = {
value: valueWithUnit.value,
unit: '%',
sourceValue: valueWithUnit.sourceValue,
};
}
else if (colorStop) {
colorStop.start = {
value: valueWithUnit.value,
unit: valueWithUnit.unit,
sourceValue: valueWithUnit.sourceValue,
};
}
}
valueWithUnit = utils.extractStartValueWithUnit(source);
if (valueWithUnit && colorStop && 'color' in colorStop) {
colorStop.end = {
value: valueWithUnit.value,
unit: valueWithUnit.unit,
sourceValue: valueWithUnit.sourceValue,
};
}
return colorStop;
};
const parseColorStops = (source) => {
const result = [];
let i = 0;
let bracesCount = 0;
while (i < source.length) {
if (source.charAt(i) === '(') {
bracesCount++;
}
if (source.charAt(i) === ')') {
bracesCount--;
}
const comma = source.charAt(i) === ',';
if ((comma || i === source.length - 1) && bracesCount === 0) {
const colorStop = parseColorStop(source.substring(0, comma ? i : i + 1).trim());
if (colorStop === null) {
return null;
}
result.push(colorStop);
source = source.substring(i + 1, source.length).trim();
i = 0;
}
i++;
}
return result;
};
exports.isLinearGradientWithAngle = utils.isLinearGradientWithAngle;
exports.isLinearGradientWithInterpolation = utils.isLinearGradientWithInterpolation;
exports.isLinearGradientWithSideOrCorner = utils.isLinearGradientWithSideOrCorner;
exports.parseLinearGradient = parseLinearGradient;
exports.parseRepeatingLinearGradient = parseRepeatingLinearGradient;