@thejaredwilcurt/csslop 0.0.48 → 0.0.50
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 +3 -4
- package/package.json +3 -3
- package/src/declarations/border.js +1 -1
- package/src/declarations/css-wide-keywords.js +37 -1
- package/src/declarations/fold.js +13 -3
- package/src/declarations/process.js +60 -7
- package/src/index.js +12 -7
- package/src/parser/source-search.js +6 -0
- package/src/rules/optimize/at-rules.js +113 -0
- package/src/rules/optimize/declaration-writes.js +70 -0
- package/src/rules/optimize/empty-rules.js +51 -0
- package/src/rules/optimize/expand-nesting.js +236 -0
- package/src/rules/optimize/factor-parents.js +343 -0
- package/src/rules/optimize/index.js +71 -0
- package/src/rules/optimize/merge-declarations.js +199 -0
- package/src/rules/optimize/merge-nested-rules.js +117 -0
- package/src/rules/optimize/merge-selectors.js +252 -0
- package/src/rules/optimize/nest-rules.js +202 -0
- package/src/rules/optimize/override-index.js +264 -0
- package/src/rules/optimize/prune-overridden.js +267 -0
- package/src/rules/optimize/selector-normalization.js +60 -0
- package/src/rules/optimize/specificity.js +280 -0
- package/src/{position-try.js → rules/position-try.js} +1 -1
- package/src/rules/selectors.js +9 -0
- package/src/rules/stringify.js +138 -76
- package/src/utilities.js +9 -8
- package/src/value/border.js +85 -0
- package/src/value/{colors.js → color/conversion.js} +3 -2
- package/src/value/color/functions.js +463 -0
- package/src/value/{light-dark.js → color/light-dark.js} +1 -1
- package/src/value/{color-mix.js → color/mix.js} +3 -3
- package/src/value/{relative-colors.js → color/relative.js} +3 -3
- package/src/value/color/shorten.js +93 -0
- package/src/value/gradients.js +1 -1
- package/src/value/hyphenate-limit-chars.js +72 -0
- package/src/value/initial-keywords.js +128 -0
- package/src/value/lengths.js +55 -0
- package/src/value/math/evaluate.js +36 -0
- package/src/value/math/fold.js +315 -0
- package/src/value/math/format.js +230 -0
- package/src/value/math/functions.js +302 -0
- package/src/value/math/index.js +219 -0
- package/src/value/math/parser.js +301 -0
- package/src/value/math/property-ranges.js +174 -0
- package/src/value/math/rewrite.js +222 -0
- package/src/value/math/tokenizer.js +160 -0
- package/src/value/math/unit-totals.js +194 -0
- package/src/value/minify.js +162 -1678
- package/src/value/numbers.js +28 -0
- package/src/value/positions.js +152 -0
- package/src/value/property-optimizations.js +485 -0
- package/src/value/segments.js +74 -0
- package/src/value/{svg-data-uri.js → svg/data-uri.js} +1 -1
- package/src/value/{svg-markup.js → svg/markup.js} +1 -1
- package/src/value/time.js +75 -0
- package/src/value/urls.js +242 -0
- package/src/value/whitespace.js +88 -0
- package/src/rules/optimize.js +0 -2031
- package/src/value/math-expression.js +0 -1156
- package/src/value/math.js +0 -886
- /package/src/value/{named-colors.js → color/named.js} +0 -0
package/src/rules/stringify.js
CHANGED
|
@@ -276,6 +276,143 @@ function stringifyAtRule (rule, context) {
|
|
|
276
276
|
const separator = minifiedPrelude ? ' ' : '';
|
|
277
277
|
return '@' + rule.name + separator + minifiedPrelude + '{' + body + '}';
|
|
278
278
|
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Rewrites `:nth-*()` pseudo-classes into their shortest equivalent forms.
|
|
282
|
+
*
|
|
283
|
+
* @param {string} selector A selector with its whitespace already collapsed.
|
|
284
|
+
* @return {string} The selector with simplified `:nth-*()` pseudo-classes.
|
|
285
|
+
*/
|
|
286
|
+
function simplifyNthPseudoClasses (selector) {
|
|
287
|
+
let minified = selector;
|
|
288
|
+
// Simplify :nth-child(2n+1) to :nth-child(odd)
|
|
289
|
+
minified = minified.replace(/:nth-child\(2n\s*\+\s*1\)/g, ':nth-child(odd)');
|
|
290
|
+
// Simplify :nth-child(2n+0) to :nth-child(2n)
|
|
291
|
+
minified = minified.replace(/:nth-child\(2n\s*\+\s*0\)/g, ':nth-child(2n)');
|
|
292
|
+
// Simplify :nth-child(1n) to :nth-child(n)
|
|
293
|
+
minified = minified.replace(/:nth-child\(1n\)/g, ':nth-child(n)');
|
|
294
|
+
// Remove unnecessary leading + sign from :nth-child()
|
|
295
|
+
minified = minified.replace(/:nth-child\(\+\s*(\d+)\)/g, ':nth-child($1)');
|
|
296
|
+
// Simplify :nth-child(0n+N) to :nth-child(N)
|
|
297
|
+
minified = minified.replace(/:nth-child\(0n\s*\+\s*(\d+)\)/g, ':nth-child($1)');
|
|
298
|
+
// Replace :nth-child(1) with :first-child
|
|
299
|
+
minified = minified.replace(/:nth-child\(1\)/g, ':first-child');
|
|
300
|
+
// Replace :nth-last-child(1) with :last-child
|
|
301
|
+
minified = minified.replace(/:nth-last-child\(1\)/g, ':last-child');
|
|
302
|
+
// Replace :nth-of-type(1) with :first-of-type
|
|
303
|
+
minified = minified.replace(/:nth-of-type\(1\)/g, ':first-of-type');
|
|
304
|
+
// Replace :nth-last-of-type(1) with :last-of-type
|
|
305
|
+
minified = minified.replace(/:nth-last-of-type\(1\)/g, ':last-of-type');
|
|
306
|
+
return minified;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Writes each attribute selector's value quoted or escaped, whichever is
|
|
311
|
+
* shorter, and removes the whitespace inside its brackets.
|
|
312
|
+
*
|
|
313
|
+
* @param {string} selector A selector with its whitespace already collapsed.
|
|
314
|
+
* @return {string} The selector with minified attribute selectors.
|
|
315
|
+
*/
|
|
316
|
+
function minifyAttributeSelectors (selector) {
|
|
317
|
+
let minified = selector;
|
|
318
|
+
// Minify double-quoted attribute selectors: remove inner whitespace and escape when shorter
|
|
319
|
+
minified = minified.replace(/\[\s*([^=]+)\s*=\s*"(.*?)"\s*\]/g, (match, attribute, value) => {
|
|
320
|
+
// Escape special characters that require quoting (spaces, #, ., :, /, ;), and compare lengths
|
|
321
|
+
let escaped = value.replace(/([ #.:/;])/g, '\\$1');
|
|
322
|
+
if (escaped.length < value.length + 2) {
|
|
323
|
+
return '[' + attribute + '=' + escaped + ']';
|
|
324
|
+
}
|
|
325
|
+
return '[' + attribute + '="' + value + '"]';
|
|
326
|
+
});
|
|
327
|
+
// Minify single-quoted attribute selectors: remove inner whitespace and escape when shorter
|
|
328
|
+
minified = minified.replace(/\[\s*([^=]+)\s*=\s*'(.*?)'\s*\]/g, (match, attribute, value) => {
|
|
329
|
+
// Escape special characters that require quoting (spaces, #, ., :, /, ;), and compare lengths
|
|
330
|
+
let escaped = value.replace(/([ #.:/;])/g, '\\$1');
|
|
331
|
+
if (escaped.length < value.length + 2) {
|
|
332
|
+
return '[' + attribute + '=' + escaped + ']';
|
|
333
|
+
}
|
|
334
|
+
return '[' + attribute + '="' + value + '"]';
|
|
335
|
+
});
|
|
336
|
+
// Minify unquoted attribute selectors: quote when unescaping produces a shorter result
|
|
337
|
+
minified = minified.replace(/\[\s*([^=]+)\s*=\s*([^"'].*?)\s*\]/g, (match, attribute, value) => {
|
|
338
|
+
// Unescape special characters (spaces, #, ., :, /, ;) and compare with quoted form
|
|
339
|
+
let unescaped = value.replace(/\\([ #.:/;])/g, '$1');
|
|
340
|
+
if (unescaped.length + 2 < value.length) {
|
|
341
|
+
return '[' + attribute + '="' + unescaped + '"]';
|
|
342
|
+
}
|
|
343
|
+
return '[' + attribute + '=' + value + ']';
|
|
344
|
+
});
|
|
345
|
+
return minified;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Rewrites `:not()` pseudo-classes that negate a pseudo-class with a direct
|
|
350
|
+
* opposite, such as `:not(:enabled)`, into that opposite.
|
|
351
|
+
*
|
|
352
|
+
* @param {string} selector A selector with its whitespace already collapsed.
|
|
353
|
+
* @return {string} The selector with simplified negations.
|
|
354
|
+
*/
|
|
355
|
+
function simplifyNegatedPseudoClasses (selector) {
|
|
356
|
+
let minified = selector;
|
|
357
|
+
// Minify logical combinations
|
|
358
|
+
// Replace :not(:invalid) with :valid, only directly after a form element type selector
|
|
359
|
+
minified = minified.replace(/(?<=\b(?:button|fieldset|form|input|select|textarea)):not\(:invalid\)/g, ':valid');
|
|
360
|
+
// Replace :not(:dir(ltr)) with :dir(rtl)
|
|
361
|
+
minified = minified.replace(/:not\(:dir\(ltr\)\)/g, ':dir(rtl)');
|
|
362
|
+
// Replace a double negation, :not(:not(X)), with the X it wraps
|
|
363
|
+
minified = minified.replace(/:not\(:not\((.*?)\)\)/g, '$1');
|
|
364
|
+
// Replace :not(:enabled) with :disabled
|
|
365
|
+
minified = minified.replace(/:not\(:enabled\)/g, ':disabled');
|
|
366
|
+
// Replace :not(:required) with :optional
|
|
367
|
+
minified = minified.replace(/:not\(:required\)/g, ':optional');
|
|
368
|
+
// Match a link element type selector at the start or after a combinator, with any attribute selectors and an optional :where( wrapper, followed by :not(:link)
|
|
369
|
+
minified = minified.replace(/(^|[\s,>+~])(a|area|link)(?:\[.*?\])*(?::where\()?:not\(:link\)\)?/g, (match) => {
|
|
370
|
+
return match.replace(':not(:link)', ':visited');
|
|
371
|
+
});
|
|
372
|
+
return minified;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Minifies a single selector's spacing, pseudo-classes, pseudo-elements, and
|
|
377
|
+
* attribute selectors. Most selectors hold none of the patterns a group of
|
|
378
|
+
* rewrites looks for, so each group only runs when its marker text is present.
|
|
379
|
+
*
|
|
380
|
+
* @param {string} selector A single selector from a rule's selector list.
|
|
381
|
+
* @return {string} The minified selector.
|
|
382
|
+
*/
|
|
383
|
+
function minifySelector (selector) {
|
|
384
|
+
let minified = unescapeSelector(selector);
|
|
385
|
+
// Collapse whitespace to single space
|
|
386
|
+
minified = minified.replace(/\s+/g, ' ');
|
|
387
|
+
// Strip whitespace around selector combinators and commas
|
|
388
|
+
minified = minified.replace(/\s*([,>+~])\s*/g, '$1');
|
|
389
|
+
// Strip whitespace inside parentheses for pseudo-class arguments
|
|
390
|
+
minified = minified.replace(/\(\s+/g, '(').replace(/\s+\)/g, ')');
|
|
391
|
+
if (minified.includes(':nth-')) {
|
|
392
|
+
minified = simplifyNthPseudoClasses(minified);
|
|
393
|
+
}
|
|
394
|
+
if (minified.includes('::')) {
|
|
395
|
+
// Convert double-colon pseudo-elements to single-colon legacy form
|
|
396
|
+
minified = minified.replace(/::before/g, ':before');
|
|
397
|
+
minified = minified.replace(/::after/g, ':after');
|
|
398
|
+
}
|
|
399
|
+
if (minified.includes('*')) {
|
|
400
|
+
// Strip redundant universal selector `*` when it precedes an ID, class, or attribute selector
|
|
401
|
+
minified = minified.replace(/\*([#.[])/g, '$1');
|
|
402
|
+
}
|
|
403
|
+
if (minified.includes('[') && minified.includes('=')) {
|
|
404
|
+
minified = minifyAttributeSelectors(minified);
|
|
405
|
+
}
|
|
406
|
+
if (minified.includes(':not(')) {
|
|
407
|
+
minified = simplifyNegatedPseudoClasses(minified);
|
|
408
|
+
}
|
|
409
|
+
// Remove redundant leading "& " nesting selector
|
|
410
|
+
minified = minified.replace(/^& /, '');
|
|
411
|
+
minified = mergeAdjacentWherePseudoClasses(minified);
|
|
412
|
+
minified = minifyLanguageSelector(minified);
|
|
413
|
+
return minified;
|
|
414
|
+
}
|
|
415
|
+
|
|
279
416
|
/**
|
|
280
417
|
* Converts a parsed CSS AST rule node into a minified CSS string, dispatching to specialized handlers for each rule type including selectors, `@media`, `@keyframes`, `@layer`, and other at-rules.
|
|
281
418
|
*
|
|
@@ -305,82 +442,7 @@ function stringifyRule (rule, context) {
|
|
|
305
442
|
if (rule.selectors?.length) {
|
|
306
443
|
let uniqueSelectors = [...new Set(rule.selectors)];
|
|
307
444
|
// Minify spacing within selectors (e.g. inside :is(), :where(), etc)
|
|
308
|
-
uniqueSelectors = uniqueSelectors.map(
|
|
309
|
-
let minified = unescapeSelector(selector);
|
|
310
|
-
// Collapse whitespace to single space
|
|
311
|
-
minified = minified.replace(/\s+/g, ' ');
|
|
312
|
-
// Strip whitespace around selector combinators and commas
|
|
313
|
-
minified = minified.replace(/\s*([,>+~])\s*/g, '$1');
|
|
314
|
-
// Strip whitespace inside parentheses for pseudo-class arguments
|
|
315
|
-
minified = minified.replace(/\(\s+/g, '(').replace(/\s+\)/g, ')');
|
|
316
|
-
// Simplify :nth-child(2n+1) to :nth-child(odd)
|
|
317
|
-
minified = minified.replace(/:nth-child\(2n\s*\+\s*1\)/g, ':nth-child(odd)');
|
|
318
|
-
// Simplify :nth-child(2n+0) to :nth-child(2n)
|
|
319
|
-
minified = minified.replace(/:nth-child\(2n\s*\+\s*0\)/g, ':nth-child(2n)');
|
|
320
|
-
// Simplify :nth-child(1n) to :nth-child(n)
|
|
321
|
-
minified = minified.replace(/:nth-child\(1n\)/g, ':nth-child(n)');
|
|
322
|
-
// Remove unnecessary leading + sign from :nth-child()
|
|
323
|
-
minified = minified.replace(/:nth-child\(\+\s*(\d+)\)/g, ':nth-child($1)');
|
|
324
|
-
// Simplify :nth-child(0n+N) to :nth-child(N)
|
|
325
|
-
minified = minified.replace(/:nth-child\(0n\s*\+\s*(\d+)\)/g, ':nth-child($1)');
|
|
326
|
-
// Replace :nth-child(1) with :first-child
|
|
327
|
-
minified = minified.replace(/:nth-child\(1\)/g, ':first-child');
|
|
328
|
-
// Replace :nth-last-child(1) with :last-child
|
|
329
|
-
minified = minified.replace(/:nth-last-child\(1\)/g, ':last-child');
|
|
330
|
-
// Replace :nth-of-type(1) with :first-of-type
|
|
331
|
-
minified = minified.replace(/:nth-of-type\(1\)/g, ':first-of-type');
|
|
332
|
-
// Replace :nth-last-of-type(1) with :last-of-type
|
|
333
|
-
minified = minified.replace(/:nth-last-of-type\(1\)/g, ':last-of-type');
|
|
334
|
-
// Convert double-colon pseudo-elements to single-colon legacy form
|
|
335
|
-
minified = minified.replace(/::before/g, ':before');
|
|
336
|
-
minified = minified.replace(/::after/g, ':after');
|
|
337
|
-
|
|
338
|
-
// Strip redundant universal selector `*` when it precedes an ID, class, or attribute selector
|
|
339
|
-
minified = minified.replace(/\*([#.[])/g, '$1');
|
|
340
|
-
|
|
341
|
-
// Minify double-quoted attribute selectors: remove inner whitespace and escape when shorter
|
|
342
|
-
minified = minified.replace(/\[\s*([^=]+)\s*=\s*"(.*?)"\s*\]/g, (match, attribute, value) => {
|
|
343
|
-
// Escape special characters that require quoting (spaces, #, ., :, /, ;), and compare lengths
|
|
344
|
-
let escaped = value.replace(/([ #.:/;])/g, '\\$1');
|
|
345
|
-
if (escaped.length < value.length + 2) {
|
|
346
|
-
return '[' + attribute + '=' + escaped + ']';
|
|
347
|
-
}
|
|
348
|
-
return '[' + attribute + '="' + value + '"]';
|
|
349
|
-
});
|
|
350
|
-
// Minify single-quoted attribute selectors: remove inner whitespace and escape when shorter
|
|
351
|
-
minified = minified.replace(/\[\s*([^=]+)\s*=\s*'(.*?)'\s*\]/g, (match, attribute, value) => {
|
|
352
|
-
// Escape special characters that require quoting (spaces, #, ., :, /, ;), and compare lengths
|
|
353
|
-
let escaped = value.replace(/([ #.:/;])/g, '\\$1');
|
|
354
|
-
if (escaped.length < value.length + 2) {
|
|
355
|
-
return '[' + attribute + '=' + escaped + ']';
|
|
356
|
-
}
|
|
357
|
-
return '[' + attribute + '="' + value + '"]';
|
|
358
|
-
});
|
|
359
|
-
// Minify unquoted attribute selectors: quote when unescaping produces a shorter result
|
|
360
|
-
minified = minified.replace(/\[\s*([^=]+)\s*=\s*([^"'].*?)\s*\]/g, (match, attribute, value) => {
|
|
361
|
-
// Unescape special characters (spaces, #, ., :, /, ;) and compare with quoted form
|
|
362
|
-
let unescaped = value.replace(/\\([ #.:/;])/g, '$1');
|
|
363
|
-
if (unescaped.length + 2 < value.length) {
|
|
364
|
-
return '[' + attribute + '="' + unescaped + '"]';
|
|
365
|
-
}
|
|
366
|
-
return '[' + attribute + '=' + value + ']';
|
|
367
|
-
});
|
|
368
|
-
|
|
369
|
-
// Minify logical combinations
|
|
370
|
-
minified = minified.replace(/(?<=\b(?:button|fieldset|form|input|select|textarea)):not\(:invalid\)/g, ':valid');
|
|
371
|
-
minified = minified.replace(/:not\(:dir\(ltr\)\)/g, ':dir(rtl)');
|
|
372
|
-
minified = minified.replace(/:not\(:not\((.*?)\)\)/g, '$1');
|
|
373
|
-
minified = minified.replace(/:not\(:enabled\)/g, ':disabled');
|
|
374
|
-
minified = minified.replace(/:not\(:required\)/g, ':optional');
|
|
375
|
-
minified = minified.replace(/(^|[\s,>+~])(a|area|link)(?:\[.*?\])*(?::where\()?:not\(:link\)\)?/g, (match) => {
|
|
376
|
-
return match.replace(':not(:link)', ':visited');
|
|
377
|
-
});
|
|
378
|
-
// Remove redundant leading "& " nesting selector
|
|
379
|
-
minified = minified.replace(/^& /, '');
|
|
380
|
-
minified = mergeAdjacentWherePseudoClasses(minified);
|
|
381
|
-
minified = minifyLanguageSelector(minified);
|
|
382
|
-
return minified;
|
|
383
|
-
});
|
|
445
|
+
uniqueSelectors = uniqueSelectors.map(minifySelector);
|
|
384
446
|
uniqueSelectors = combineLegacyAnySelectors(uniqueSelectors);
|
|
385
447
|
// When this rule is a nesting parent, its whole selector list is treated
|
|
386
448
|
// as :is() for the children's specificity, so a top-level :is() can be
|
package/src/utilities.js
CHANGED
|
@@ -20,18 +20,19 @@ function resolveUnicodeEscape (hex) {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
|
-
*
|
|
24
|
-
*
|
|
23
|
+
* Reports whether a property is a custom property. A custom property holds an
|
|
24
|
+
* arbitrary token stream rather than a typed value, so every one of its tokens,
|
|
25
|
+
* whitespace included, is part of what it stores, and neither shorthands nor
|
|
26
|
+
* `all` ever reset it.
|
|
25
27
|
*
|
|
26
|
-
* @param {string}
|
|
27
|
-
* @return {
|
|
28
|
+
* @param {string} property The CSS property name.
|
|
29
|
+
* @return {boolean} Whether the property is a custom property.
|
|
28
30
|
*/
|
|
29
|
-
function
|
|
30
|
-
|
|
31
|
-
return input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
31
|
+
function isCustomProperty (property) {
|
|
32
|
+
return Boolean(property) && property.startsWith('--');
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
export {
|
|
35
|
-
|
|
36
|
+
isCustomProperty,
|
|
36
37
|
resolveUnicodeEscape
|
|
37
38
|
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Rewrites `border` and `outline` values into their shortest canonical form, stating the width before the style and dropping the default width.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Matches the keywords that state a border line style.
|
|
7
|
+
*
|
|
8
|
+
* @type {string}
|
|
9
|
+
*/
|
|
10
|
+
const BORDER_STYLE_KEYWORD_SOURCE = 'solid|dashed|dotted|double|groove|ridge|inset|outset|hidden|none';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Matches the ways a border line width is stated: one of its three keywords, a
|
|
14
|
+
* length, or a math function that resolves to one.
|
|
15
|
+
*
|
|
16
|
+
* @type {string}
|
|
17
|
+
*/
|
|
18
|
+
const BORDER_WIDTH_SOURCE = 'thin|medium|thick|[+-]?(?:\\d+|\\d*\\.\\d+)(?:e[+-]?\\d+)?[a-z]*|(?:calc|min|max|clamp)\\([^()]*\\)';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Matches a `border` value that states its line style in front of its line
|
|
22
|
+
* width, with the two captured so they can be swapped.
|
|
23
|
+
*
|
|
24
|
+
* @type {RegExp}
|
|
25
|
+
*/
|
|
26
|
+
const BORDER_STYLE_BEFORE_WIDTH_PATTERN = new RegExp(
|
|
27
|
+
'^(' + BORDER_STYLE_KEYWORD_SOURCE + ')\\s+(' + BORDER_WIDTH_SOURCE + ')(?=\\s|$)',
|
|
28
|
+
'i'
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Rewrites a `border` value that leads with its line style into the canonical
|
|
33
|
+
* width-style-color order. The width has to be recognized before the two are
|
|
34
|
+
* swapped: `border` states its components in any order, so the component behind
|
|
35
|
+
* the style may be a color instead, as in `solid #8aadf4 1px`, and that one
|
|
36
|
+
* belongs behind the width rather than in front of it.
|
|
37
|
+
*
|
|
38
|
+
* @param {string} value The `border` value.
|
|
39
|
+
* @return {string} The value with its width stated before its style.
|
|
40
|
+
*/
|
|
41
|
+
function reorderBorderWidthBeforeStyle (value) {
|
|
42
|
+
return value.replace(BORDER_STYLE_BEFORE_WIDTH_PATTERN, '$2 $1');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Removes the default `medium` line width from a `border` value, since the
|
|
47
|
+
* shorthand resets an unstated width to it anyway.
|
|
48
|
+
*
|
|
49
|
+
* @param {string} value The `border` value.
|
|
50
|
+
* @return {string} The value without its default line width.
|
|
51
|
+
*/
|
|
52
|
+
function removeDefaultBorderWidth (value) {
|
|
53
|
+
// Match the medium keyword and the whitespace that separates it from the next component
|
|
54
|
+
return value.replace(/\bmedium\s+/g, '');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Matches a line style keyword written directly against one of the color
|
|
59
|
+
* keywords that can follow it, capturing both so a space can be put back
|
|
60
|
+
* between them.
|
|
61
|
+
*
|
|
62
|
+
* @type {RegExp}
|
|
63
|
+
*/
|
|
64
|
+
const STYLE_TOUCHING_COLOR_PATTERN = new RegExp(
|
|
65
|
+
'\\b(' + BORDER_STYLE_KEYWORD_SOURCE + ')(red|green|olive|tan|transparent)\\b',
|
|
66
|
+
'g'
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Restores the space between an `outline` value's line style and a color
|
|
71
|
+
* keyword when the two have been written against each other, since together
|
|
72
|
+
* they would read as one unknown keyword.
|
|
73
|
+
*
|
|
74
|
+
* @param {string} value The `outline` value.
|
|
75
|
+
* @return {string} The value with its style and color keywords separated.
|
|
76
|
+
*/
|
|
77
|
+
function separateOutlineStyleFromColor (value) {
|
|
78
|
+
return value.replace(STYLE_TOUCHING_COLOR_PATTERN, '$1 $2');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export {
|
|
82
|
+
removeDefaultBorderWidth,
|
|
83
|
+
reorderBorderWidthBeforeStyle,
|
|
84
|
+
separateOutlineStyleFromColor
|
|
85
|
+
};
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* @file Provides color parsing, color space conversion (sRGB, OKLab, OKLCH, HSL, HWB), and hex formatting for CSS value minification.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
|
|
5
|
+
import { parseAlphaString } from '../shared.js';
|
|
6
|
+
|
|
7
|
+
import { namedColors } from './named.js';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Reverse lookup from "r,g,b" to the shortest CSS named color keyword.
|