@thejaredwilcurt/csslop 0.0.30 → 0.0.32
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/package.json
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { minifyValue } from '../value/minify.js';
|
|
6
6
|
|
|
7
7
|
import { shorthandMap } from './config.js';
|
|
8
|
+
import { buildLayerPositionAndSize } from './image-layers.js';
|
|
8
9
|
|
|
9
10
|
const BACKGROUND_POSITION_KEYWORDS = new Set(['left', 'center', 'right', 'top', 'bottom']);
|
|
10
11
|
const BACKGROUND_REPEAT_KEYWORDS = new Set(['repeat', 'no-repeat', 'repeat-x', 'repeat-y', 'space', 'round']);
|
|
@@ -246,16 +247,7 @@ function buildBackgroundShorthandValue (valueMap, importantSuffix) {
|
|
|
246
247
|
if (image && image !== 'none') {
|
|
247
248
|
result.push(image);
|
|
248
249
|
}
|
|
249
|
-
|
|
250
|
-
result.push(position);
|
|
251
|
-
}
|
|
252
|
-
if (size && size !== 'auto') {
|
|
253
|
-
if (position && position !== '0 0' && position !== '0% 0%') {
|
|
254
|
-
result.push('/' + size);
|
|
255
|
-
} else {
|
|
256
|
-
result.push('0 0/' + size);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
250
|
+
result.push(...buildLayerPositionAndSize(position, size));
|
|
259
251
|
if (repeat && repeat !== 'repeat') {
|
|
260
252
|
result.push(repeat);
|
|
261
253
|
}
|
|
@@ -80,7 +80,7 @@ const shorthandMap = {
|
|
|
80
80
|
'border-block-width': ['border-block-start-width', 'border-block-end-width'],
|
|
81
81
|
transition: ['transition-property', 'transition-duration', 'transition-timing-function', 'transition-delay'],
|
|
82
82
|
animation: ['animation-name', 'animation-duration', 'animation-timing-function', 'animation-delay', 'animation-iteration-count', 'animation-direction', 'animation-fill-mode', 'animation-play-state'],
|
|
83
|
-
mask: ['mask-image', 'mask-
|
|
83
|
+
mask: ['mask-image', 'mask-position', 'mask-size', 'mask-repeat'],
|
|
84
84
|
'position-try': ['position-try-order', 'position-try-fallbacks'],
|
|
85
85
|
font: ['font-style', 'font-weight', 'font-size', 'line-height', 'font-family'],
|
|
86
86
|
marker: ['marker-start', 'marker-mid', 'marker-end'],
|
|
@@ -92,7 +92,7 @@ const shorthandOverrideMap = {
|
|
|
92
92
|
columns: ['column-wrap'],
|
|
93
93
|
border: ['border-image', 'border-image-source', 'border-image-slice', 'border-image-width', 'border-image-outset', 'border-image-repeat'],
|
|
94
94
|
font: ['font-variant', 'font-variant-alternates', 'font-variant-caps', 'font-variant-east-asian', 'font-variant-ligatures', 'font-variant-numeric', 'font-variant-position', 'font-feature-settings', 'font-kerning', 'font-language-override', 'font-optical-sizing', 'font-size-adjust', 'font-variation-settings'],
|
|
95
|
-
mask: ['mask-border', 'mask-border-source', 'mask-border-slice', 'mask-border-width', 'mask-border-outset', 'mask-border-repeat', 'mask-border-mode', 'mask-
|
|
95
|
+
mask: ['mask-border', 'mask-border-source', 'mask-border-slice', 'mask-border-width', 'mask-border-outset', 'mask-border-repeat', 'mask-border-mode', 'mask-origin', 'mask-clip', 'mask-composite', 'mask-mode']
|
|
96
96
|
};
|
|
97
97
|
|
|
98
98
|
/**
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Shared grammar helpers for the layered image shorthands, `background` and `mask`, whose layers only accept a size behind a slash that follows a position.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The layer positions a shorthand may leave unstated, since they already match
|
|
7
|
+
* the initial position that the shorthand resets the layer to.
|
|
8
|
+
*
|
|
9
|
+
* @type {Set<string>}
|
|
10
|
+
*/
|
|
11
|
+
const INITIAL_LAYER_POSITIONS = new Set(['0 0', '0% 0%']);
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The shortest spelling of the initial layer position, used whenever a stated
|
|
15
|
+
* size needs a position in front of it.
|
|
16
|
+
*
|
|
17
|
+
* @type {string}
|
|
18
|
+
*/
|
|
19
|
+
const SHORTEST_INITIAL_LAYER_POSITION = '0 0';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The layer size a shorthand may leave unstated, since it already matches the
|
|
23
|
+
* initial size that the shorthand resets the layer to.
|
|
24
|
+
*
|
|
25
|
+
* @type {string}
|
|
26
|
+
*/
|
|
27
|
+
const INITIAL_LAYER_SIZE = 'auto';
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Reduces a layer position to what the shorthand has to spell out, which is
|
|
31
|
+
* nothing at all while the position holds its initial value.
|
|
32
|
+
*
|
|
33
|
+
* @param {string} position The layer position, or a falsy value when the layer states none.
|
|
34
|
+
* @return {string} The position to write, or an empty string when it can be left out.
|
|
35
|
+
*/
|
|
36
|
+
function resolveStatedLayerPosition (position) {
|
|
37
|
+
if (!position || INITIAL_LAYER_POSITIONS.has(position)) {
|
|
38
|
+
return '';
|
|
39
|
+
}
|
|
40
|
+
return position;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Reduces a layer size to what the shorthand has to spell out, which is nothing
|
|
45
|
+
* at all while the size holds its initial value.
|
|
46
|
+
*
|
|
47
|
+
* @param {string} size The layer size, or a falsy value when the layer states none.
|
|
48
|
+
* @return {string} The size to write, or an empty string when it can be left out.
|
|
49
|
+
*/
|
|
50
|
+
function resolveStatedLayerSize (size) {
|
|
51
|
+
if (!size || size === INITIAL_LAYER_SIZE) {
|
|
52
|
+
return '';
|
|
53
|
+
}
|
|
54
|
+
return size;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Builds the position and size components of a layered image shorthand value.
|
|
59
|
+
* The layer grammar only reads a size directly behind a `/` that follows a
|
|
60
|
+
* position, so a stated size pulls the initial position back into the output
|
|
61
|
+
* whenever the layer states no position of its own.
|
|
62
|
+
*
|
|
63
|
+
* @param {string} position The layer position, or a falsy value when the layer states none.
|
|
64
|
+
* @param {string} size The layer size, or a falsy value when the layer states none.
|
|
65
|
+
* @return {Array} The shorthand components covering the position and the size.
|
|
66
|
+
*/
|
|
67
|
+
function buildLayerPositionAndSize (position, size) {
|
|
68
|
+
const statedPosition = resolveStatedLayerPosition(position);
|
|
69
|
+
const statedSize = resolveStatedLayerSize(size);
|
|
70
|
+
if (statedSize) {
|
|
71
|
+
return [(statedPosition || SHORTEST_INITIAL_LAYER_POSITION) + '/' + statedSize];
|
|
72
|
+
}
|
|
73
|
+
if (statedPosition) {
|
|
74
|
+
return [statedPosition];
|
|
75
|
+
}
|
|
76
|
+
return [];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export { buildLayerPositionAndSize };
|
|
@@ -7,6 +7,7 @@ import { splitTopLevelComponents } from '../value/syntax.js';
|
|
|
7
7
|
|
|
8
8
|
import { buildBackgroundShorthandValue } from './background.js';
|
|
9
9
|
import { UNIFORM_VALUE_SHORTHANDS } from './config.js';
|
|
10
|
+
import { buildLayerPositionAndSize } from './image-layers.js';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* @typedef {object} ShorthandComponents
|
|
@@ -124,26 +125,33 @@ function buildBackgroundValue ({ valueMap, importantSuffix }) {
|
|
|
124
125
|
}
|
|
125
126
|
|
|
126
127
|
/**
|
|
127
|
-
* Builds a `mask` value
|
|
128
|
+
* Builds a `mask` value. A mask layer follows the same grammar as a background
|
|
129
|
+
* layer, so the image leads, the size only reads as a size while it sits behind
|
|
130
|
+
* a `/` that follows the position, and the repeat comes after both of them. A
|
|
131
|
+
* component holding its initial value is left out, since the shorthand already
|
|
132
|
+
* resets every longhand it covers back to that value.
|
|
128
133
|
*
|
|
129
134
|
* @param {ShorthandComponents} components The collected longhand values.
|
|
130
135
|
* @return {string|null} The shorthand value, or null when it cannot be built.
|
|
131
136
|
*/
|
|
132
137
|
function buildMaskValue ({ valueMap, importantSuffix }) {
|
|
133
138
|
const image = valueMap.get('mask-image');
|
|
134
|
-
const repeat = valueMap.get('mask-repeat');
|
|
135
|
-
const size = valueMap.get('mask-size');
|
|
136
139
|
if (!image) {
|
|
137
140
|
return null;
|
|
138
141
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
+
const repeat = valueMap.get('mask-repeat');
|
|
143
|
+
const result = [];
|
|
144
|
+
if (image !== 'none') {
|
|
145
|
+
result.push(image);
|
|
146
|
+
}
|
|
147
|
+
result.push(...buildLayerPositionAndSize(valueMap.get('mask-position'), valueMap.get('mask-size')));
|
|
148
|
+
if (repeat && repeat !== 'repeat') {
|
|
149
|
+
result.push(repeat);
|
|
142
150
|
}
|
|
143
|
-
if (
|
|
144
|
-
|
|
151
|
+
if (!result.length) {
|
|
152
|
+
return 'none' + importantSuffix;
|
|
145
153
|
}
|
|
146
|
-
return result + importantSuffix;
|
|
154
|
+
return result.join(' ') + importantSuffix;
|
|
147
155
|
}
|
|
148
156
|
|
|
149
157
|
/**
|
package/src/value/minify.js
CHANGED
|
@@ -980,12 +980,31 @@ const POSITION_OFFSET_SOURCE = '(?:left|center|right|top|bottom|[+-]?(?:\\d+|\\d
|
|
|
980
980
|
const POSITION_COMPONENT_SOURCE = '(' + POSITION_OFFSET_SOURCE + '(?:\\s+' + POSITION_OFFSET_SOURCE + ')?)';
|
|
981
981
|
|
|
982
982
|
/**
|
|
983
|
-
* Matches a
|
|
984
|
-
*
|
|
983
|
+
* Matches everything a `url()` holds up to but not including its own closing
|
|
984
|
+
* parenthesis. A url is written without nested parentheses, so the first one
|
|
985
|
+
* that closes it is the end of the token.
|
|
986
|
+
*
|
|
987
|
+
* @type {string}
|
|
988
|
+
*/
|
|
989
|
+
const URL_TOKEN_BODY_SOURCE = 'url\\([^()]*';
|
|
990
|
+
|
|
991
|
+
/**
|
|
992
|
+
* Matches a close-paren that ends an image function, directly followed by a
|
|
993
|
+
* position that no slash follows, which is the position that needs its
|
|
994
|
+
* separator put back. The parenthesis that ends a `url()` is skipped, since
|
|
995
|
+
* that one closes a token rather than a function.
|
|
996
|
+
*
|
|
997
|
+
* @type {RegExp}
|
|
998
|
+
*/
|
|
999
|
+
const UNSEPARATED_FUNCTION_POSITION_PATTERN = new RegExp('(?<!' + URL_TOKEN_BODY_SOURCE + ')\\)' + POSITION_COMPONENT_SOURCE + '(?!\\/)', 'gi');
|
|
1000
|
+
|
|
1001
|
+
/**
|
|
1002
|
+
* Matches a `url()` separated from the position that follows it, which is the
|
|
1003
|
+
* separator a url does not need.
|
|
985
1004
|
*
|
|
986
1005
|
* @type {RegExp}
|
|
987
1006
|
*/
|
|
988
|
-
const
|
|
1007
|
+
const SEPARATED_URL_POSITION_PATTERN = new RegExp('(' + URL_TOKEN_BODY_SOURCE + '\\))\\s+' + POSITION_COMPONENT_SOURCE, 'gi');
|
|
989
1008
|
|
|
990
1009
|
/**
|
|
991
1010
|
* Matches a close-paren separated from a position that a slash follows, where
|
|
@@ -996,18 +1015,21 @@ const UNSEPARATED_IMAGE_POSITION_PATTERN = new RegExp('\\)' + POSITION_COMPONENT
|
|
|
996
1015
|
const SEPARATED_IMAGE_SIZE_POSITION_PATTERN = new RegExp('\\)\\s+' + POSITION_COMPONENT_SOURCE + '(?=\\/)', 'gi');
|
|
997
1016
|
|
|
998
1017
|
/**
|
|
999
|
-
*
|
|
1018
|
+
* Normalizes the separator between the image of a layer and the position that
|
|
1000
1019
|
* follows it. Both `background` and `mask` take a `<position> [ / <size> ]`
|
|
1001
1020
|
* component after their image, and a bare position only reads as its own
|
|
1002
|
-
* component while whitespace separates it from
|
|
1003
|
-
* that a `/` follows
|
|
1021
|
+
* component while whitespace separates it from an image function. Neither a
|
|
1022
|
+
* position that a `/` follows nor one that follows a `url()` needs the
|
|
1023
|
+
* separator, since the slash delimits the pair and a url is consumed whole as a
|
|
1024
|
+
* single token that ends at its own closing parenthesis.
|
|
1004
1025
|
*
|
|
1005
1026
|
* @param {string} value The layered image value, with the parenthesis padding removed.
|
|
1006
|
-
* @return {string} The value with the position separator
|
|
1027
|
+
* @return {string} The value with the position separator normalized.
|
|
1007
1028
|
*/
|
|
1008
|
-
function
|
|
1009
|
-
const
|
|
1010
|
-
|
|
1029
|
+
function normalizeImagePositionSeparator (value) {
|
|
1030
|
+
const separatedFromFunction = value.replace(UNSEPARATED_FUNCTION_POSITION_PATTERN, ') $1');
|
|
1031
|
+
const joinedToUrl = separatedFromFunction.replace(SEPARATED_URL_POSITION_PATTERN, '$1$2');
|
|
1032
|
+
return joinedToUrl.replace(SEPARATED_IMAGE_SIZE_POSITION_PATTERN, ')$1');
|
|
1011
1033
|
}
|
|
1012
1034
|
|
|
1013
1035
|
/**
|
|
@@ -1227,11 +1249,11 @@ function applyPropertyOptimizations (val, property, allowsSeparatorElision) {
|
|
|
1227
1249
|
if (normalized) {
|
|
1228
1250
|
val = normalized;
|
|
1229
1251
|
}
|
|
1230
|
-
val =
|
|
1252
|
+
val = normalizeImagePositionSeparator(val);
|
|
1231
1253
|
}
|
|
1232
1254
|
|
|
1233
1255
|
if (property === 'mask') {
|
|
1234
|
-
val =
|
|
1256
|
+
val = normalizeImagePositionSeparator(val);
|
|
1235
1257
|
}
|
|
1236
1258
|
|
|
1237
1259
|
if (property === 'border') {
|