index.es.mjs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. import { lab2rgb, lch2rgb } from '@csstools/convert-colors';
  2. import postcss from 'postcss';
  3. import parser from 'postcss-values-parser';
  4. var index = postcss.plugin('postcss-lab-function', opts => {
  5. const preserve = 'preserve' in Object(opts) ? Boolean(opts.preserve) : false;
  6. return root => {
  7. root.walkDecls(decl => {
  8. const value = decl.value;
  9. if (colorAnyRegExp.test(value)) {
  10. const ast = parser(value).parse();
  11. ast.walkType('func', node => {
  12. if (colorRegExp.test(node.value)) {
  13. const children = node.nodes.slice(1, -1);
  14. const isLab = labRegExp.test(node.value);
  15. const isGray = grayRegExp.test(node.value);
  16. const isFunctionalLAB = !isGray && matchFunctionalLAB(children);
  17. const isFunctionalLCH = !isGray && matchFunctionalLCH(children);
  18. const isFunctionalGray = isGray && matchFunctionalGray(children);
  19. if (isFunctionalLAB || isFunctionalLCH) {
  20. node.value = 'rgb';
  21. const slashNode = children[3];
  22. const alphaNode = children[4];
  23. if (alphaNode) {
  24. if (isPercentage(alphaNode) && !isCalc(alphaNode)) {
  25. alphaNode.unit = '';
  26. alphaNode.value = String(alphaNode.value / 100);
  27. }
  28. if (alphaNode.value === '1') {
  29. slashNode.remove();
  30. alphaNode.remove();
  31. } else {
  32. node.value += 'a';
  33. }
  34. }
  35. if (slashNode && isSlash(slashNode)) {
  36. slashNode.replaceWith(newComma());
  37. }
  38. const converter = isLab ? lab2rgb : lch2rgb;
  39. const rgbValues = converter(...[children[0].value, children[1].value, children[2].value].map(number => parseFloat(number))).map(sourceValue => Math.max(Math.min(parseInt(sourceValue * 2.55), 255), 0));
  40. children[0].value = String(rgbValues[0]);
  41. children[1].value = String(rgbValues[1]);
  42. children[2].value = String(rgbValues[2]);
  43. node.nodes.splice(3, 0, [newComma()]);
  44. node.nodes.splice(2, 0, [newComma()]);
  45. } else if (isFunctionalGray) {
  46. node.value = 'rgb';
  47. const alphaNode = children[2];
  48. const rgbValues = lab2rgb(...[children[0].value, 0, 0].map(number => parseFloat(number))).map(sourceValue => Math.max(Math.min(parseInt(sourceValue * 2.55), 255), 0));
  49. node.removeAll().append(newParen('(')).append(newNumber(rgbValues[0])).append(newComma()).append(newNumber(rgbValues[1])).append(newComma()).append(newNumber(rgbValues[2])).append(newParen(')'));
  50. if (alphaNode) {
  51. if (isPercentage(alphaNode) && !isCalc(alphaNode)) {
  52. alphaNode.unit = '';
  53. alphaNode.value = String(alphaNode.value / 100);
  54. }
  55. if (alphaNode.value !== '1') {
  56. node.value += 'a';
  57. node.insertBefore(node.last, newComma()).insertBefore(node.last, alphaNode);
  58. }
  59. }
  60. }
  61. }
  62. });
  63. const newValue = String(ast);
  64. if (preserve) {
  65. decl.cloneBefore({
  66. value: newValue
  67. });
  68. } else {
  69. decl.value = newValue;
  70. }
  71. }
  72. });
  73. };
  74. });
  75. const colorAnyRegExp = /(^|[^\w-])(lab|lch|gray)\(/i;
  76. const colorRegExp = /^(lab|lch|gray)$/i;
  77. const labRegExp = /^lab$/i;
  78. const grayRegExp = /^gray$/i;
  79. const alphaUnitMatch = /^%?$/i;
  80. const calcFuncMatch = /^calc$/i;
  81. const hueUnitMatch = /^(deg|grad|rad|turn)?$/i;
  82. const isAlphaValue = node => isCalc(node) || node.type === 'number' && alphaUnitMatch.test(node.unit);
  83. const isCalc = node => node.type === 'func' && calcFuncMatch.test(node.value);
  84. const isHue = node => isCalc(node) || node.type === 'number' && hueUnitMatch.test(node.unit);
  85. const isNumber = node => isCalc(node) || node.type === 'number' && node.unit === '';
  86. const isPercentage = node => isCalc(node) || node.type === 'number' && node.unit === '%';
  87. const isSlash = node => node.type === 'operator' && node.value === '/';
  88. const functionalLABMatch = [isNumber, isNumber, isNumber, isSlash, isAlphaValue];
  89. const functionalLCHMatch = [isNumber, isNumber, isHue, isSlash, isAlphaValue];
  90. const functionalGrayMatch = [isNumber, isSlash, isAlphaValue];
  91. const matchFunctionalLAB = children => children.every((child, index) => typeof functionalLABMatch[index] === 'function' && functionalLABMatch[index](child));
  92. const matchFunctionalLCH = children => children.every((child, index) => typeof functionalLCHMatch[index] === 'function' && functionalLCHMatch[index](child));
  93. const matchFunctionalGray = children => children.every((child, index) => typeof functionalGrayMatch[index] === 'function' && functionalGrayMatch[index](child));
  94. const newComma = () => parser.comma({
  95. value: ','
  96. });
  97. const newNumber = value => parser.number({
  98. value
  99. });
  100. const newParen = value => parser.paren({
  101. value
  102. });
  103. export default index;
  104. //# sourceMappingURL=index.es.mjs.map