@thejaredwilcurt/csslop 0.0.40 → 0.0.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/package.json +9 -12
- package/src/rules/stringify.js +2 -8
- package/src/value/math-expression.js +1103 -0
- package/src/value/math.js +110 -99
- package/src/value/minify.js +73 -13
- package/vite.config.js +0 -4
package/src/value/math.js
CHANGED
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
* @file Simplifies CSS math functions (calc, min, max) by folding constant expressions, flattening nested calcs, and converting absolute lengths to pixels.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { calc } from '@csstools/css-calc';
|
|
6
|
-
|
|
7
5
|
import { findMatchingParenthesis } from '../parser/source-search.js';
|
|
8
6
|
|
|
7
|
+
import {
|
|
8
|
+
formatUnitTotals,
|
|
9
|
+
MATH_FUNCTION_NAMES,
|
|
10
|
+
simplifyCalc
|
|
11
|
+
} from './math-expression.js';
|
|
9
12
|
import {
|
|
10
13
|
convertAbsoluteLengthToPx,
|
|
11
14
|
formatResolvedDimension,
|
|
@@ -86,25 +89,6 @@ function keepSeparatorAfterDissolvedFunction (replacer) {
|
|
|
86
89
|
};
|
|
87
90
|
}
|
|
88
91
|
|
|
89
|
-
/**
|
|
90
|
-
* The functions whose arguments are a math expression, where `*` and `/` are
|
|
91
|
-
* arithmetic operators rather than characters of some other syntax.
|
|
92
|
-
*
|
|
93
|
-
* @type {Set<string>}
|
|
94
|
-
*/
|
|
95
|
-
const MATH_FUNCTION_NAMES = new Set([
|
|
96
|
-
'abs',
|
|
97
|
-
'calc',
|
|
98
|
-
'clamp',
|
|
99
|
-
'hypot',
|
|
100
|
-
'max',
|
|
101
|
-
'min',
|
|
102
|
-
'mod',
|
|
103
|
-
'rem',
|
|
104
|
-
'round',
|
|
105
|
-
'sign'
|
|
106
|
-
]);
|
|
107
|
-
|
|
108
92
|
/**
|
|
109
93
|
* Matches a single character that may appear in a CSS function name.
|
|
110
94
|
*
|
|
@@ -270,6 +254,38 @@ function shorterOfResolutionAndCalculation (resolved, calculation) {
|
|
|
270
254
|
return calculation;
|
|
271
255
|
}
|
|
272
256
|
|
|
257
|
+
/**
|
|
258
|
+
* Writes a calculation as compactly as its syntax allows, squeezing out every
|
|
259
|
+
* space but the ones a `+` or a `-` needs to be read as an operator.
|
|
260
|
+
*
|
|
261
|
+
* @param {string} inner The contents of the `calc()`.
|
|
262
|
+
* @return {string} The whole `calc()`, written as compactly as it can be.
|
|
263
|
+
*/
|
|
264
|
+
function compactCalculation (inner) {
|
|
265
|
+
// Remove whitespace around multiplication and division operators
|
|
266
|
+
const compactInner = inner.replace(/\s+/g, ' ').trim().replace(/\s*([*/])\s*/g, '$1');
|
|
267
|
+
return 'calc(' + compactInner + ')';
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Picks between a calculation and what resolving its arithmetic came to. A
|
|
272
|
+
* resolved value states the same thing without any arithmetic, so it wins a
|
|
273
|
+
* tie, but a result that is itself a calculation only states the same terms
|
|
274
|
+
* another way, and writing them out again for no saving gains nothing.
|
|
275
|
+
*
|
|
276
|
+
* @param {string} resolved The value the calculation resolved to.
|
|
277
|
+
* @param {string} calculation The calculation, written as compactly as it can be.
|
|
278
|
+
* @return {string} Whichever of the two the value is written as.
|
|
279
|
+
*/
|
|
280
|
+
function chooseResolvedCalculation (resolved, calculation) {
|
|
281
|
+
// A resolution that kept its function form left terms behind that only
|
|
282
|
+
// resolve once the element they are measured against is laid out
|
|
283
|
+
if (resolved.startsWith('calc(') && resolved.length >= calculation.length) {
|
|
284
|
+
return calculation;
|
|
285
|
+
}
|
|
286
|
+
return shorterOfResolutionAndCalculation(resolved, calculation);
|
|
287
|
+
}
|
|
288
|
+
|
|
273
289
|
/**
|
|
274
290
|
* Resolves a percentage divided by a number into the single percentage it
|
|
275
291
|
* equals, which is how `calc(100%/16)` comes to be written as `6.25%`. The
|
|
@@ -398,21 +414,6 @@ function clampResolvedValueToPropertyRange (resolvedValue, property) {
|
|
|
398
414
|
return '0';
|
|
399
415
|
}
|
|
400
416
|
|
|
401
|
-
/**
|
|
402
|
-
* The units a folded calc() expression leads with, in the order they are
|
|
403
|
-
* written. Every other unit follows them alphabetically.
|
|
404
|
-
*
|
|
405
|
-
* @type {Array}
|
|
406
|
-
*/
|
|
407
|
-
const PREFERRED_UNIT_ORDER = ['%', '', 'px'];
|
|
408
|
-
|
|
409
|
-
/**
|
|
410
|
-
* The same leading units, for excluding them from the alphabetical remainder.
|
|
411
|
-
*
|
|
412
|
-
* @type {Set<string>}
|
|
413
|
-
*/
|
|
414
|
-
const PREFERRED_UNITS = new Set(PREFERRED_UNIT_ORDER);
|
|
415
|
-
|
|
416
417
|
/**
|
|
417
418
|
* Attempts to simplify a calc() expression by combining like-unit terms and evaluating pure arithmetic, returning the simplified string or null if folding is not possible.
|
|
418
419
|
*
|
|
@@ -492,38 +493,7 @@ function tryFoldCalcExpression (expression) {
|
|
|
492
493
|
totals.set(unit, (totals.get(unit) || 0) + number);
|
|
493
494
|
}
|
|
494
495
|
|
|
495
|
-
|
|
496
|
-
return !PREFERRED_UNITS.has(unit);
|
|
497
|
-
}).sort()];
|
|
498
|
-
const outputTerms = [];
|
|
499
|
-
|
|
500
|
-
for (const unit of orderedUnits) {
|
|
501
|
-
if (!totals.has(unit)) {
|
|
502
|
-
continue;
|
|
503
|
-
}
|
|
504
|
-
const value = totals.get(unit);
|
|
505
|
-
if (Math.abs(value) < 1e-12) {
|
|
506
|
-
continue;
|
|
507
|
-
}
|
|
508
|
-
outputTerms.push({ unit, value });
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
if (!outputTerms.length) {
|
|
512
|
-
return '0';
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
if (outputTerms.length === 1) {
|
|
516
|
-
const { unit, value } = outputTerms[0];
|
|
517
|
-
return formatResolvedDimension(value, unit);
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
const [first, ...rest] = outputTerms;
|
|
521
|
-
let result = formatResolvedDimension(first.value, first.unit);
|
|
522
|
-
for (const term of rest) {
|
|
523
|
-
const sign = term.value < 0 ? '-' : '+';
|
|
524
|
-
result += ' ' + sign + ' ' + formatResolvedDimension(Math.abs(term.value), term.unit);
|
|
525
|
-
}
|
|
526
|
-
return 'calc(' + result + ')';
|
|
496
|
+
return formatUnitTotals(totals);
|
|
527
497
|
}
|
|
528
498
|
|
|
529
499
|
/**
|
|
@@ -578,8 +548,7 @@ function chooseResolvedPercentage (simplified, compactInner, match) {
|
|
|
578
548
|
*/
|
|
579
549
|
function resolveCalcExpression (match, compactInner) {
|
|
580
550
|
if (PERCENTAGE_MULTIPLICATION.test(compactInner)) {
|
|
581
|
-
|
|
582
|
-
return 'calc(' + compactInner.replace(/\s*([*/])\s*/g, '$1') + ')';
|
|
551
|
+
return compactCalculation(compactInner);
|
|
583
552
|
}
|
|
584
553
|
|
|
585
554
|
const dividedPercentage = resolvePercentageDivision(compactInner);
|
|
@@ -592,26 +561,41 @@ function resolveCalcExpression (match, compactInner) {
|
|
|
592
561
|
return folded;
|
|
593
562
|
}
|
|
594
563
|
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
if (typeof simplified !== 'string') {
|
|
598
|
-
return match;
|
|
599
|
-
}
|
|
600
|
-
return chooseResolvedPercentage(simplified, compactInner, match);
|
|
601
|
-
} catch {
|
|
564
|
+
const simplified = simplifyCalc(match);
|
|
565
|
+
if (simplified === null) {
|
|
602
566
|
return match;
|
|
603
567
|
}
|
|
568
|
+
const resolved = chooseResolvedPercentage(simplified, compactInner, match);
|
|
569
|
+
return chooseResolvedCalculation(resolved, compactCalculation(compactInner));
|
|
604
570
|
}
|
|
605
571
|
|
|
606
572
|
/**
|
|
607
|
-
*
|
|
573
|
+
* Matches a math function other than `calc()` whose arguments hold no further
|
|
574
|
+
* parentheses, so that the whole of the function is matched. A `calc()` is
|
|
575
|
+
* left to its own pass, which weighs what the calculation resolves to against
|
|
576
|
+
* the calculation itself.
|
|
608
577
|
*
|
|
609
|
-
* @
|
|
610
|
-
* @param {string} property The CSS property name, whose range every resolved result is clamped into.
|
|
611
|
-
* @param {string} originalValue The original unmodified value to fall back to if simplification produces an invalid result.
|
|
612
|
-
* @return {string} The value with math functions simplified where possible.
|
|
578
|
+
* @type {RegExp}
|
|
613
579
|
*/
|
|
614
|
-
|
|
580
|
+
const RESOLVABLE_MATH_FUNCTION = new RegExp(
|
|
581
|
+
'\\b(?:' +
|
|
582
|
+
[...MATH_FUNCTION_NAMES].filter((name) => {
|
|
583
|
+
return name !== 'calc';
|
|
584
|
+
}).join('|') +
|
|
585
|
+
')\\([^()]+\\)',
|
|
586
|
+
'gi'
|
|
587
|
+
);
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Runs one pass of the math simplifications over a value: the rewrites that
|
|
591
|
+
* state a calculation more compactly, and the resolutions that replace a math
|
|
592
|
+
* function with the value it works out to.
|
|
593
|
+
*
|
|
594
|
+
* @param {string} value The CSS value string containing math functions to simplify.
|
|
595
|
+
* @param {string} property The CSS property name, whose range every resolved result is clamped into.
|
|
596
|
+
* @return {string} The value with its math functions simplified where possible.
|
|
597
|
+
*/
|
|
598
|
+
function simplifyMathFunctionsOnce (value, property) {
|
|
615
599
|
let result = rewriteMathFunctionContents(convertReciprocalMultiplicationToDivision, value);
|
|
616
600
|
|
|
617
601
|
// Unwrap calc(1 / (1 / x)) → x (double-reciprocal identity)
|
|
@@ -627,20 +611,16 @@ function normalizeMathFunctions (value, property, originalValue = '') {
|
|
|
627
611
|
return 'calc(' + inner + ')';
|
|
628
612
|
}));
|
|
629
613
|
|
|
630
|
-
//
|
|
631
|
-
result = result.replace(
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
if (typeof simplified !== 'string') {
|
|
635
|
-
return match;
|
|
636
|
-
}
|
|
637
|
-
return clampResolvedValueToPropertyRange(simplified, property);
|
|
638
|
-
} catch {
|
|
614
|
+
// Resolve every math function that compares or rounds its arguments
|
|
615
|
+
result = result.replace(RESOLVABLE_MATH_FUNCTION, keepSeparatorAfterDissolvedFunction((match) => {
|
|
616
|
+
const simplified = simplifyCalc(match);
|
|
617
|
+
if (simplified === null) {
|
|
639
618
|
return match;
|
|
640
619
|
}
|
|
620
|
+
return clampResolvedValueToPropertyRange(simplified, property);
|
|
641
621
|
}));
|
|
642
622
|
|
|
643
|
-
// Simplify calc() expressions using constant folding and
|
|
623
|
+
// Simplify calc() expressions using constant folding and expression resolution
|
|
644
624
|
result = result.replace(/calc\(([^()]+)\)/gi, keepSeparatorAfterDissolvedFunction((match, inner) => {
|
|
645
625
|
// Collapse whitespace inside calc expression
|
|
646
626
|
const compactInner = inner.replace(/\s+/g, ' ').trim();
|
|
@@ -648,6 +628,31 @@ function normalizeMathFunctions (value, property, originalValue = '') {
|
|
|
648
628
|
return clampResolvedValueToPropertyRange(resolved, property);
|
|
649
629
|
}));
|
|
650
630
|
|
|
631
|
+
return result;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* Simplifies every math function within a CSS value string, resolving the ones
|
|
636
|
+
* whose operands are all known and stating the rest as compactly as they can
|
|
637
|
+
* be written.
|
|
638
|
+
*
|
|
639
|
+
* @param {string} value The CSS value string containing math functions to simplify.
|
|
640
|
+
* @param {string} property The CSS property name, whose range every resolved result is clamped into.
|
|
641
|
+
* @param {string} originalValue The value as it was authored, which tells whether a result was ever part of a calculation.
|
|
642
|
+
* @return {string} The value with math functions simplified where possible.
|
|
643
|
+
*/
|
|
644
|
+
function normalizeMathFunctions (value, property, originalValue = '') {
|
|
645
|
+
let result = value;
|
|
646
|
+
let previous;
|
|
647
|
+
|
|
648
|
+
do {
|
|
649
|
+
previous = result;
|
|
650
|
+
// Resolving a math function leaves a plain value where it stood, which can
|
|
651
|
+
// bring the function it was nested in within reach of the next pass, so
|
|
652
|
+
// the value is simplified until it settles
|
|
653
|
+
result = simplifyMathFunctionsOnce(result, property);
|
|
654
|
+
} while (result !== previous);
|
|
655
|
+
|
|
651
656
|
// When calc() folded to an absolute-length unit (pt, pc, in, cm, mm, q), convert to pixels
|
|
652
657
|
if (originalValue.includes('calc(') && /^-?(?:\d+|\d*\.\d+)(pt|pc|in|cm|mm|q)$/i.test(result)) {
|
|
653
658
|
// Extract the absolute-length unit from the folded result
|
|
@@ -667,7 +672,7 @@ function normalizeMathFunctions (value, property, originalValue = '') {
|
|
|
667
672
|
}
|
|
668
673
|
|
|
669
674
|
/**
|
|
670
|
-
* Simplifies a standalone calc() value by flattening nested calc expressions, converting absolute length units to pixels, and folding constant terms.
|
|
675
|
+
* Simplifies a standalone calc() value by resolving its arithmetic, flattening nested calc expressions, converting absolute length units to pixels, and folding constant terms.
|
|
671
676
|
*
|
|
672
677
|
* @param {string} value The CSS value string, already known to be a single `calc()`.
|
|
673
678
|
* @return {string} The simplified value, or the original value if simplification is not applicable.
|
|
@@ -677,7 +682,15 @@ function foldStandaloneCalc (value) {
|
|
|
677
682
|
|
|
678
683
|
// Preserve percent-times-number expressions, only stripping whitespace around operators
|
|
679
684
|
if (PERCENTAGE_MULTIPLICATION.test(inner.replace(/\s+/g, ' ').trim())) {
|
|
680
|
-
return
|
|
685
|
+
return compactCalculation(inner);
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
// Resolve the calculation as it was written, which is the only reading of it
|
|
689
|
+
// that keeps the grouping its parentheses state. Everything below reads a
|
|
690
|
+
// flattened copy of the expression, where that grouping is already gone.
|
|
691
|
+
const resolved = simplifyCalc(value);
|
|
692
|
+
if (resolved !== null) {
|
|
693
|
+
return chooseResolvedCalculation(resolved, compactCalculation(inner));
|
|
681
694
|
}
|
|
682
695
|
|
|
683
696
|
// If no nested function calls and no multiplication/division involving parens, try flattening
|
|
@@ -714,14 +727,12 @@ function foldStandaloneCalc (value) {
|
|
|
714
727
|
}
|
|
715
728
|
|
|
716
729
|
// Collapse whitespace and check for percent-division expressions
|
|
717
|
-
const
|
|
718
|
-
const dividedPercentage = resolvePercentageDivision(compactInner);
|
|
730
|
+
const dividedPercentage = resolvePercentageDivision(inner.replace(/\s+/g, ' ').trim());
|
|
719
731
|
if (dividedPercentage) {
|
|
720
732
|
return dividedPercentage;
|
|
721
733
|
}
|
|
722
734
|
|
|
723
|
-
|
|
724
|
-
return 'calc(' + compactInner.replace(/\s*([*/])\s*/g, '$1') + ')';
|
|
735
|
+
return compactCalculation(inner);
|
|
725
736
|
}
|
|
726
737
|
|
|
727
738
|
/**
|
package/src/value/minify.js
CHANGED
|
@@ -451,6 +451,67 @@ function parseOklchHue (token) {
|
|
|
451
451
|
return parseAngleToDegrees(normalized);
|
|
452
452
|
}
|
|
453
453
|
|
|
454
|
+
/**
|
|
455
|
+
* Removes whitespace before a negative numeric channel in Lab-family colors.
|
|
456
|
+
* A preceding numeric token already separates the sign from the prior channel.
|
|
457
|
+
*
|
|
458
|
+
* @param {string} functionName The name of the color function.
|
|
459
|
+
* @param {string} value The minified function arguments.
|
|
460
|
+
* @return {string} The arguments with redundant channel spacing removed.
|
|
461
|
+
*/
|
|
462
|
+
function compactNegativeColorChannelSpacing (functionName, value) {
|
|
463
|
+
const normalizedFunctionName = functionName.toLowerCase();
|
|
464
|
+
if (!['lab', 'lch', 'oklab', 'oklch'].includes(normalizedFunctionName)) {
|
|
465
|
+
return value;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
let result = '';
|
|
469
|
+
let nestingDepth = 0;
|
|
470
|
+
for (let index = 0; index < value.length; index++) {
|
|
471
|
+
const character = value[index];
|
|
472
|
+
if (character === ' ' && nestingDepth === 0) {
|
|
473
|
+
const previousCharacter = result[result.length - 1];
|
|
474
|
+
const nextCharacter = value[index + 1];
|
|
475
|
+
const characterAfterSign = value[index + 2];
|
|
476
|
+
const characterAfterDecimal = value[index + 3];
|
|
477
|
+
const previousEndsNumber = (
|
|
478
|
+
isCssDigit(previousCharacter) ||
|
|
479
|
+
previousCharacter === '%'
|
|
480
|
+
);
|
|
481
|
+
const nextStartsNegativeNumber = (
|
|
482
|
+
nextCharacter === '-' &&
|
|
483
|
+
(
|
|
484
|
+
isCssDigit(characterAfterSign) ||
|
|
485
|
+
(
|
|
486
|
+
characterAfterSign === '.' &&
|
|
487
|
+
isCssDigit(characterAfterDecimal)
|
|
488
|
+
)
|
|
489
|
+
)
|
|
490
|
+
);
|
|
491
|
+
if (previousEndsNumber && nextStartsNegativeNumber) {
|
|
492
|
+
continue;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
result += character;
|
|
496
|
+
if (character === '(') {
|
|
497
|
+
nestingDepth++;
|
|
498
|
+
} else if (character === ')') {
|
|
499
|
+
nestingDepth--;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
return result;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* Checks whether a character is an ASCII decimal digit.
|
|
507
|
+
*
|
|
508
|
+
* @param {string} character The character to inspect.
|
|
509
|
+
* @return {boolean} Whether the character is a digit.
|
|
510
|
+
*/
|
|
511
|
+
function isCssDigit (character) {
|
|
512
|
+
return character >= '0' && character <= '9';
|
|
513
|
+
}
|
|
514
|
+
|
|
454
515
|
/**
|
|
455
516
|
* Converts `oklch()` colors that fall inside the sRGB gamut to their hex
|
|
456
517
|
* equivalent when that is shorter. Out-of-gamut colors have no sRGB
|
|
@@ -574,11 +635,13 @@ function convertColorsToHex (val) {
|
|
|
574
635
|
}
|
|
575
636
|
return integer;
|
|
576
637
|
});
|
|
638
|
+
minified = compactNegativeColorChannelSpacing(func, minified);
|
|
577
639
|
return func + '(' + minified.trim() + ')';
|
|
578
640
|
});
|
|
579
641
|
|
|
580
642
|
// Convert in-gamut oklab() to hex when it produces a shorter representation
|
|
581
|
-
|
|
643
|
+
// A negative channel may touch the preceding number because its sign separates the CSS number tokens.
|
|
644
|
+
val = val.replace(/\boklab\(\s*(-?(?:\d+|\d*\.\d+))(?:\s+|(?=-))(-?(?:\d+|\d*\.\d+))(?:\s+|(?=-))(-?(?:\d+|\d*\.\d+))(?:\s*\/\s*(-?(?:\d+|\d*\.\d+)%?))?\s*\)/gi, (match, lStr, aStr, bStr, alphaStr) => {
|
|
582
645
|
const alpha = parseAlphaString(alphaStr);
|
|
583
646
|
const hex = convertOklabToHex(parseFloat(lStr), parseFloat(aStr), parseFloat(bStr), alpha);
|
|
584
647
|
if (!hex) {
|
|
@@ -892,14 +955,13 @@ const POSITION_COMPONENT_SOURCE = '(' + POSITION_OFFSET_SOURCE + '(?:\\s+' + POS
|
|
|
892
955
|
const URL_TOKEN_BODY_SOURCE = 'url\\([^()]*';
|
|
893
956
|
|
|
894
957
|
/**
|
|
895
|
-
* Matches a close-paren that ends an image function,
|
|
896
|
-
* position that no slash follows
|
|
897
|
-
*
|
|
898
|
-
* that one closes a token rather than a function.
|
|
958
|
+
* Matches a close-paren that ends an image function, followed by a separated
|
|
959
|
+
* position that no slash follows. The parenthesis that ends a `url()` is
|
|
960
|
+
* skipped, since that one closes a token rather than a function.
|
|
899
961
|
*
|
|
900
962
|
* @type {RegExp}
|
|
901
963
|
*/
|
|
902
|
-
const
|
|
964
|
+
const SEPARATED_FUNCTION_POSITION_PATTERN = new RegExp('(?<!' + URL_TOKEN_BODY_SOURCE + ')\\)\\s+' + POSITION_COMPONENT_SOURCE + '(?!\\/)', 'gi');
|
|
903
965
|
|
|
904
966
|
/**
|
|
905
967
|
* Matches a `url()` separated from the position that follows it, which is the
|
|
@@ -920,18 +982,16 @@ const SEPARATED_IMAGE_SIZE_POSITION_PATTERN = new RegExp('\\)\\s+' + POSITION_CO
|
|
|
920
982
|
/**
|
|
921
983
|
* Normalizes the separator between the image of a layer and the position that
|
|
922
984
|
* follows it. Both `background` and `mask` take a `<position> [ / <size> ]`
|
|
923
|
-
* component after their image
|
|
924
|
-
*
|
|
925
|
-
*
|
|
926
|
-
* separator, since the slash delimits the pair and a url is consumed whole as a
|
|
927
|
-
* single token that ends at its own closing parenthesis.
|
|
985
|
+
* component after their image. The closing parenthesis already delimits a
|
|
986
|
+
* function token from the position, and neither a position that a `/` follows
|
|
987
|
+
* nor one that follows a `url()` needs a separator either.
|
|
928
988
|
*
|
|
929
989
|
* @param {string} value The layered image value, with the parenthesis padding removed.
|
|
930
990
|
* @return {string} The value with the position separator normalized.
|
|
931
991
|
*/
|
|
932
992
|
function normalizeImagePositionSeparator (value) {
|
|
933
|
-
const
|
|
934
|
-
const joinedToUrl =
|
|
993
|
+
const joinedToFunction = value.replace(SEPARATED_FUNCTION_POSITION_PATTERN, ')$1');
|
|
994
|
+
const joinedToUrl = joinedToFunction.replace(SEPARATED_URL_POSITION_PATTERN, '$1$2');
|
|
935
995
|
return joinedToUrl.replace(SEPARATED_IMAGE_SIZE_POSITION_PATTERN, ')$1');
|
|
936
996
|
}
|
|
937
997
|
|
package/vite.config.js
CHANGED
|
@@ -27,10 +27,6 @@ const config = defineConfig({
|
|
|
27
27
|
test: /node_modules\/@codemirror\/lang-css/,
|
|
28
28
|
name: 'codemirror-lang-css'
|
|
29
29
|
},
|
|
30
|
-
{
|
|
31
|
-
test: /node_modules\/@csstools\/css-calc/,
|
|
32
|
-
name: 'css-calc'
|
|
33
|
-
},
|
|
34
30
|
{
|
|
35
31
|
test: /node_modules\/@node-projects\/css-parser/,
|
|
36
32
|
name: 'css-parser'
|