gerillass 2.3.1 → 3.0.0

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.
@@ -0,0 +1,425 @@
1
+ @charset "UTF-8";
2
+
3
+ @use "sass:list";
4
+ @use "sass:map";
5
+ @use "sass:math";
6
+ @use "sass:meta";
7
+ @use "sass:string";
8
+ @use "../maps/map-for-directions" as *;
9
+ @use "../maps/map-for-positions" as *;
10
+ @use "color-stops-problem" as *;
11
+ @use "is-condition-value" as *;
12
+ @use "is-css-function" as *;
13
+ @use "words" as *;
14
+
15
+ // Shared by the mixins and not public API; see _is-css-function.scss.
16
+ //
17
+ // Builds a linear, radial or conic gradient, plain or repeating, with an
18
+ // optional colour interpolation space, and checks every part of it. The
19
+ // gradient mixin, the gradientValue function, text-gradient, background-image,
20
+ // background-dots and background-stripes all write their gradients through it.
21
+ //
22
+ // What Chrome 152 kept and dropped, checked with CSS.supports in
23
+ // background-image:
24
+ //
25
+ // - a linear direction: an angle in deg, grad, rad or turn, a unitless 0, calc(),
26
+ // and `to` with one side or a side and a corner in either order (`to left
27
+ // top`); `to center`, `to top bottom` and a length were dropped;
28
+ // - a conic start: `from` an angle or 0, dropped with a length; a conic position
29
+ // takes `at` and a position like radial, and a size or shape dropped it;
30
+ // - a conic stop: an angle, a percentage, 0 or calc(), dropped with a length;
31
+ // - `in` a space: srgb, srgb-linear, display-p3, display-p3-linear, a98-rgb,
32
+ // prophoto-rgb, rec2020, lab, oklab, xyz, xyz-d50 and xyz-d65, or a polar
33
+ // hsl, hwb, lch or oklch with an optional `shorter`, `longer`, `increasing` or
34
+ // `decreasing hue`; a hue method on a rectangular space, `hue` without a
35
+ // method, a method without `hue`, and `rgb` or `hsv` were dropped. `in
36
+ // var(--s)` with `--s: oklab` computed to `in oklab`.
37
+ //
38
+ // The shape, size and position checks came from radial-gradient, removed in
39
+ // 3.0.0, with the measurements behind them.
40
+
41
+ $-types: "linear" "radial" "conic";
42
+ $-rectangular-spaces: "srgb" "srgb-linear" "display-p3" "display-p3-linear" "a98-rgb" "prophoto-rgb" "rec2020" "lab" "oklab" "xyz" "xyz-d50" "xyz-d65";
43
+ $-polar-spaces: "hsl" "hwb" "lch" "oklch";
44
+ $-hue-methods: "shorter" "longer" "increasing" "decreasing";
45
+ $-sides: "top" "bottom" "left" "right";
46
+
47
+ $-extents: "closest-side" "closest-corner" "farthest-side" "farthest-corner";
48
+ $-places: "left" "center" "right" "top" "bottom";
49
+
50
+ // "extent", "length" or "percentage" for a word that can size the gradient,
51
+ // or null.
52
+ @function -size-kind($word) {
53
+ $lower: string.to-lower-case("#{$word}");
54
+ @if list.index($-extents, $lower) {
55
+ @return "extent";
56
+ }
57
+ @if string.index($lower, "-") == 1 {
58
+ @return null;
59
+ }
60
+ @if isConditionValue($word, "length") {
61
+ @return "length";
62
+ }
63
+ @if isConditionValue($word, "length-percentage") {
64
+ @return "percentage";
65
+ }
66
+ @return null;
67
+ }
68
+
69
+ // Checks the size words before `at`. $shape is the shape named, or null.
70
+ @function -size-problem($words, $shape) {
71
+ $extents: 0;
72
+ $lengths: 0;
73
+ $percentages: 0;
74
+ @each $word in $words {
75
+ $kind: -size-kind($word);
76
+ @if $kind == null {
77
+ @return "`#{$word}` is not a shape, an extent keyword such as `closest-side`, or a length";
78
+ } @else if $kind == "extent" {
79
+ $extents: $extents + 1;
80
+ } @else if $kind == "length" {
81
+ $lengths: $lengths + 1;
82
+ } @else {
83
+ $percentages: $percentages + 1;
84
+ }
85
+ }
86
+ $sizes: $lengths + $percentages;
87
+ @if $extents > 1 or ($extents == 1 and $sizes > 0) {
88
+ @return "it gives the size twice";
89
+ }
90
+ @if $sizes > 2 {
91
+ @return "a size is one length or two";
92
+ }
93
+ @if $sizes == 1 and ($percentages == 1 or $shape == "ellipse") {
94
+ @return "one size is a circle's radius, which is a length and not a percentage";
95
+ }
96
+ @if $sizes == 2 and $shape == "circle" {
97
+ @return "a circle takes one length, not two";
98
+ }
99
+ @return null;
100
+ }
101
+
102
+ @function -shape-problem($shape) {
103
+ @if string.index($shape, "(") {
104
+ @return null;
105
+ }
106
+ $named: null;
107
+ $sizes: ();
108
+ @each $word in wordsOf($shape) {
109
+ $lower: string.to-lower-case($word);
110
+ @if list.index("circle" "ellipse", $lower) {
111
+ @if $named {
112
+ @return "it names the shape twice";
113
+ }
114
+ $named: $lower;
115
+ } @else {
116
+ $sizes: list.append($sizes, $word);
117
+ }
118
+ }
119
+ @return -size-problem($sizes, $named);
120
+ }
121
+
122
+ @function -position-problem($position) {
123
+ @if map.has-key($map-for-positions, $position) or string.index($position, "(") {
124
+ @return null;
125
+ }
126
+ $sizes: ();
127
+ $places: ();
128
+ $after-at: false;
129
+ @each $word in wordsOf($position) {
130
+ $lower: string.to-lower-case($word);
131
+ @if $lower == "at" {
132
+ @if $after-at {
133
+ @return "it has `at` twice";
134
+ }
135
+ $after-at: true;
136
+ } @else if $after-at {
137
+ $places: list.append($places, $word);
138
+ } @else if list.index("circle" "ellipse", $lower) {
139
+ @return "the shape goes in $shape, not $position";
140
+ } @else {
141
+ $sizes: list.append($sizes, $word);
142
+ }
143
+ }
144
+ $problem: -size-problem($sizes, null);
145
+ @if $problem {
146
+ @return "#{$problem}. Pass a position name such as `center` or `top-left`, an extent keyword such as `closest-side`, or `at` followed by a position, such as `at 30% 40%`";
147
+ }
148
+ @if $after-at and list.length($places) == 0 {
149
+ @return "`at` needs a position after it, such as `at center`";
150
+ }
151
+ @if list.length($places) > 4 {
152
+ @return "a position takes at most four values";
153
+ }
154
+ $keywords: 0;
155
+ @each $word in $places {
156
+ @if list.index($-places, string.to-lower-case($word)) {
157
+ $keywords: $keywords + 1;
158
+ } @else if not isConditionValue($word, "length-percentage") {
159
+ @return "`#{$word}` is not a position; after `at` pass left, center, right, top, bottom or a length";
160
+ }
161
+ }
162
+ @if $keywords > 2 and $keywords == list.length($places) {
163
+ @return "a position of keywords alone takes at most two, such as `at top left`";
164
+ }
165
+ @return null;
166
+ }
167
+
168
+ // True for var(), env() or attr(), which may stand for anything, so it is
169
+ // written as it is.
170
+ @function -is-substitution($value) {
171
+ @return isCssFunction($value, "var" "env" "attr");
172
+ }
173
+
174
+ // True for an angle, a unitless 0, a calculation or var().
175
+ @function -is-angle($value) {
176
+ @return $value == 0 or isConditionValue($value, "angle") or -is-substitution($value);
177
+ }
178
+
179
+ // The CSS for a linear gradient's $direction, or null when a browser would
180
+ // drop it. background-image checks its $filter-direction with this.
181
+ @function gradientDirection($direction) {
182
+ @if map.has-key($map-for-directions, $direction) {
183
+ @return map.get($map-for-directions, $direction);
184
+ }
185
+ @if -is-angle($direction) {
186
+ @return $direction;
187
+ }
188
+ $words: wordsOf($direction);
189
+ @if meta.type-of($direction) == "string" and string.to-lower-case("#{list.nth($words, 1)}") == "to" and list.length($words) >= 2 and list.length($words) <= 3 {
190
+ $vertical: 0;
191
+ $horizontal: 0;
192
+ @for $i from 2 through list.length($words) {
193
+ $word: string.to-lower-case("#{list.nth($words, $i)}");
194
+ @if $word == "top" or $word == "bottom" {
195
+ $vertical: $vertical + 1;
196
+ } @else if $word == "left" or $word == "right" {
197
+ $horizontal: $horizontal + 1;
198
+ } @else {
199
+ @return null;
200
+ }
201
+ }
202
+ @if $vertical <= 1 and $horizontal <= 1 {
203
+ @return string.unquote($direction);
204
+ }
205
+ }
206
+ @return null;
207
+ }
208
+
209
+ // What is wrong with $in, or null.
210
+ @function -in-problem($in) {
211
+ // Measured in Chrome 152: `in var(--s)` with `--s: oklab` computed to
212
+ // `in oklab`, so var() is written as it is.
213
+ @if -is-substitution($in) {
214
+ @return null;
215
+ }
216
+ @if not list.index("string" "list", meta.type-of($in)) {
217
+ @return "it is not a colour space";
218
+ }
219
+ $words: ();
220
+ @each $word in wordsOf($in) {
221
+ $words: list.append($words, string.to-lower-case("#{$word}"));
222
+ }
223
+ $space: list.nth($words, 1);
224
+ $count: list.length($words);
225
+ @if list.index($-rectangular-spaces, $space) {
226
+ @if $count > 1 {
227
+ @return "a hue method such as `longer hue` needs a polar space: hsl, hwb, lch or oklch";
228
+ }
229
+ @return null;
230
+ }
231
+ @if list.index($-polar-spaces, $space) {
232
+ @if $count == 1 {
233
+ @return null;
234
+ }
235
+ @if $count == 3 and list.index($-hue-methods, list.nth($words, 2)) and list.nth($words, 3) == "hue" {
236
+ @return null;
237
+ }
238
+ @return "after a polar space comes a hue method and the word hue, such as `oklch longer hue`";
239
+ }
240
+ @return "`#{$space}` is not a colour space; pass one such as oklab or oklch";
241
+ }
242
+
243
+ // What is wrong with a conic gradient's stops, or null. A position there is an
244
+ // angle or a percentage, so each is checked for that and then replaced with 0,
245
+ // and the list goes through colorStopsProblem for everything else.
246
+ @function -conic-stops-problem($colors) {
247
+ $checked: ();
248
+ @each $item in $colors {
249
+ @if meta.type-of($item) == "list" and list.length($item) > 1 {
250
+ $stop: (list.nth($item, 1),);
251
+ @for $i from 2 through list.length($item) {
252
+ $position: list.nth($item, $i);
253
+ @if not -is-conic-position($position) {
254
+ @return "in `#{meta.inspect($item)}`, `#{meta.inspect($position)}` is not an angle or a percentage, and a conic stop is placed by one";
255
+ }
256
+ @if -is-substitution($position) {
257
+ $stop: list.append($stop, $position, space);
258
+ } @else {
259
+ $stop: list.append($stop, 0, space);
260
+ }
261
+ }
262
+ $checked: list.append($checked, $stop, comma);
263
+ } @else if meta.type-of($item) == "number" or isConditionValue($item, "length-percentage") or isConditionValue($item, "angle") {
264
+ @if not -is-conic-position($item) {
265
+ @return "`#{meta.inspect($item)}` is not an angle or a percentage, and a conic hint is placed by one";
266
+ }
267
+ $checked: list.append($checked, 0, comma);
268
+ } @else {
269
+ $checked: list.append($checked, $item, comma);
270
+ }
271
+ }
272
+ @return colorStopsProblem($checked);
273
+ }
274
+
275
+ @function -is-conic-position($value) {
276
+ @if -is-angle($value) or meta.type-of($value) == "calculation" {
277
+ @return true;
278
+ }
279
+ @if meta.type-of($value) == "number" {
280
+ @return math.unit($value) == "%";
281
+ }
282
+ $text: string.unquote("#{$value}");
283
+ @return string.slice($text, -1) == "%" and isConditionValue($value, "length-percentage");
284
+ }
285
+
286
+
287
+ // A gradient, as a value. $member, $colors-name and $direction-name are the
288
+ // names an error gives, so a mixin that passes its own arguments through names
289
+ // them as its user wrote them. $warn is false for the fallback a mixin writes
290
+ // before a gradient with $in, so a single colour warns once.
291
+ @function gradientOf(
292
+ $colors,
293
+ $type: linear,
294
+ $direction: null,
295
+ $shape: null,
296
+ $position: null,
297
+ $from: null,
298
+ $in: null,
299
+ $repeating: false,
300
+ $member: "gradient",
301
+ $colors-name: "$colors",
302
+ $direction-name: "$direction",
303
+ $warn: true
304
+ ) {
305
+ $kind: string.to-lower-case("#{$type}");
306
+ @if meta.type-of($type) != "string" or not list.index($-types, $kind) {
307
+ @error "`#{meta.inspect($type)}` is not a valid $type for `#{$member}`. Pass linear, radial or conic.";
308
+ }
309
+ @if meta.type-of($repeating) != "bool" {
310
+ @error "`#{meta.inspect($repeating)}` is not a valid $repeating for `#{$member}`. Pass true or false.";
311
+ }
312
+
313
+ // An argument the type does not read would be dropped without a word.
314
+ @if $direction != null and $kind != "linear" {
315
+ $hint: "Use $position for where a radial gradient sits.";
316
+ @if $kind == "conic" {
317
+ $hint: "Use $from for where a conic gradient starts.";
318
+ }
319
+ @error "#{$direction-name} is for a linear gradient, and this one is #{$kind}. #{$hint}";
320
+ }
321
+ @if $shape != null and $kind != "radial" {
322
+ @error "$shape is for a radial gradient, and this one is #{$kind}.";
323
+ }
324
+ @if $position != null and $kind == "linear" {
325
+ @error "$position is for a radial or conic gradient, and this one is linear. Use #{$direction-name}.";
326
+ }
327
+ @if $from != null and $kind != "conic" {
328
+ @error "$from is for a conic gradient, and this one is #{$kind}.";
329
+ }
330
+
331
+ $prelude: ();
332
+
333
+ @if $kind == "linear" and $direction != null {
334
+ $value: gradientDirection($direction);
335
+ @if $value == null {
336
+ @error "`#{meta.inspect($direction)}` is not a valid #{$direction-name} for `#{$member}`. Pass an angle such as `45deg` or `0.25turn`, `\"to top right\"`, or one of: #{map.keys($map-for-directions)}.";
337
+ }
338
+ $prelude: list.append($prelude, $value, space);
339
+ }
340
+
341
+ // A shape or position written without quotes, such as `ellipse 70% 60%` or
342
+ // `at 50% 0%`, reaches here as a space-separated list; it is the same words.
343
+ @if meta.type-of($shape) == "list" and list.separator($shape) == "space" {
344
+ $shape: "#{$shape}";
345
+ }
346
+ @if meta.type-of($position) == "list" and list.separator($position) == "space" {
347
+ $position: "#{$position}";
348
+ }
349
+
350
+ @if $kind == "radial" and $shape != null {
351
+ @if meta.type-of($shape) != "string" {
352
+ @error "`#{meta.inspect($shape)}` is not a valid $shape for `#{$member}`. Pass circle or ellipse, optionally with a size.";
353
+ }
354
+ $shape: string.unquote($shape);
355
+ $problem: -shape-problem($shape);
356
+ @if $problem {
357
+ @error "`#{$shape}` is not a valid $shape for `#{$member}`: #{$problem}. A browser drops the whole gradient.";
358
+ }
359
+ $prelude: list.append($prelude, $shape, space);
360
+ }
361
+
362
+ @if $kind == "conic" and $from != null {
363
+ @if not -is-angle($from) {
364
+ @error "`#{meta.inspect($from)}` is not a valid $from for `#{$member}`. Pass an angle, such as `45deg` or `0.25turn`.";
365
+ }
366
+ $prelude: list.append($prelude, string.unquote("from #{$from}"), space);
367
+ }
368
+
369
+ @if $position != null {
370
+ @if meta.type-of($position) != "string" {
371
+ @error "`#{meta.inspect($position)}` is not a valid $position for `#{$member}`. Pass a position name such as `center` or `top-left`, or a CSS position as a string, such as `\"at 30% 40%\"`.";
372
+ }
373
+ $position: string.unquote($position);
374
+ @if map.has-key($map-for-positions, $position) {
375
+ $prelude: list.append($prelude, map.get($map-for-positions, $position), space);
376
+ } @else {
377
+ $problem: -position-problem($position);
378
+ @if not $problem and $kind == "conic" and not string.index($position, "(") and string.to-lower-case(list.nth(wordsOf($position), 1)) != "at" {
379
+ $problem: "a conic gradient has no size, so its position starts with `at`";
380
+ }
381
+ @if $problem {
382
+ @error "`#{$position}` is not a valid $position for `#{$member}`: #{$problem}. A browser drops the whole gradient.";
383
+ }
384
+ $prelude: list.append($prelude, $position, space);
385
+ }
386
+ }
387
+
388
+ $problem: null;
389
+ @if $kind == "conic" {
390
+ $problem: -conic-stops-problem($colors);
391
+ } @else {
392
+ $problem: colorStopsProblem($colors);
393
+ }
394
+ @if $problem {
395
+ @error "`#{meta.inspect($colors)}` is not a valid #{$colors-name} for `#{$member}`: #{$problem}. A browser drops the whole gradient.";
396
+ }
397
+ // From the compat data, not measured in an old browser: a gradient with one
398
+ // colour is kept only from Chrome 135, Firefox 136 and Safari 18.4.
399
+ @if $warn and list.length($colors) == 1 and not -is-substitution(list.nth($colors, 1)) {
400
+ @warn "`#{$member}` was given one colour, `#{meta.inspect($colors)}`. Browsers before Chrome 135, Firefox 136 and Safari 18.4 drop a gradient with a single colour stop; pass two colours, or use background-color.";
401
+ }
402
+
403
+ @if $in != null {
404
+ $problem: -in-problem($in);
405
+ @if $problem {
406
+ @error "`#{meta.inspect($in)}` is not a valid $in for `#{$member}`: #{$problem}. A browser drops the whole gradient.";
407
+ }
408
+ $prelude: list.append($prelude, string.unquote("in #{$in}"), space);
409
+ }
410
+
411
+ $stops: ();
412
+ @each $item in $colors {
413
+ $stops: list.append($stops, $item, comma);
414
+ }
415
+
416
+ $name: "#{$kind}-gradient";
417
+ @if $repeating {
418
+ $name: "repeating-#{$name}";
419
+ }
420
+ $function: meta.get-function($name, $css: true);
421
+ @if list.length($prelude) > 0 {
422
+ @return meta.call($function, $prelude, $stops...);
423
+ }
424
+ @return meta.call($function, $stops...);
425
+ }
@@ -7,6 +7,7 @@
7
7
  @use "../internal/image-value" as *;
8
8
  @use "../internal/color-problem" as *;
9
9
  @use "../internal/length-problem" as *;
10
+ @use "../internal/gradient" as *;
10
11
 
11
12
  @mixin background-dots(
12
13
  $color: null,
@@ -59,22 +60,22 @@
59
60
  @if not $color {
60
61
  $color: rgba(0, 0, 0, 0.1);
61
62
  @if $diagonal == true {
62
- background-image: radial-gradient($color $size, transparent 0),
63
- radial-gradient($color $size, transparent 0);
63
+ background-image: gradientOf(($color $size, transparent 0), radial, $member: "background-dots"),
64
+ gradientOf(($color $size, transparent 0), radial, $member: "background-dots");
64
65
  background-position: calc($gutter / 2) calc($gutter / 2),
65
66
  calc($gutter * 2) calc($gutter * 2);
66
67
  } @else if $diagonal == false {
67
- background-image: radial-gradient($color $size, transparent 0);
68
+ background-image: gradientOf(($color $size, transparent 0), radial, $member: "background-dots");
68
69
  background-position: calc($gutter / 2) calc($gutter / 2);
69
70
  }
70
71
  } @else if $color {
71
72
  @if $diagonal == true {
72
- background-image: radial-gradient(list.nth($color, 1) $size, transparent 0),
73
- radial-gradient(list.nth($color, list.length($color)) $size, transparent 0);
73
+ background-image: gradientOf((list.nth($color, 1) $size, transparent 0), radial, $member: "background-dots"),
74
+ gradientOf((list.nth($color, list.length($color)) $size, transparent 0), radial, $member: "background-dots");
74
75
  background-position: calc($gutter / 2) calc($gutter / 2),
75
76
  calc($gutter * 2) calc($gutter * 2);
76
77
  } @else if $diagonal == false {
77
- background-image: radial-gradient(list.nth($color, 1) $size, transparent 0);
78
+ background-image: gradientOf((list.nth($color, 1) $size, transparent 0), radial, $member: "background-dots");
78
79
  background-position: calc($gutter / 2) calc($gutter / 2);
79
80
  @if list.length($color) > 1 {
80
81
  @error "Please do not pass more than one argument when you disable 'diagonal' property! Simply remove the argument(s) after '#{list.nth($color, 1)}' to resolve the problem.";
@@ -4,11 +4,11 @@
4
4
  @use "sass:map";
5
5
  @use "sass:math";
6
6
  @use "sass:meta";
7
- @use "../library/linear-gradient" as *;
8
7
  @use "../maps/map-for-directions" as *;
9
8
  @use "../internal/image-value" as *;
10
9
  @use "../internal/color-problem" as *;
11
10
  @use "../internal/color-stops-problem" as *;
11
+ @use "../internal/gradient" as *;
12
12
  @use "../internal/is-css-function" as *;
13
13
 
14
14
  @mixin background-image(
@@ -19,8 +19,8 @@
19
19
  // The direction used to be read only when there were two or more colours,
20
20
  // so with one colour any value was dropped without a word, a typo included.
21
21
  // Check it first, against what the gradient branches accept.
22
- @if $filter-direction and not map.has-key($map-for-directions, $filter-direction) and not (meta.type-of($filter-direction) == "number" and math.unit($filter-direction) == "deg") {
23
- @error "`#{$filter-direction}` is not a valid $filter-direction. Pass an angle such as `45deg`, or one of: #{map.keys($map-for-directions)}.";
22
+ @if $filter-direction and gradientDirection($filter-direction) == null {
23
+ @error "`#{meta.inspect($filter-direction)}` is not a valid $filter-direction for `background-image`. Pass an angle such as `45deg` or `0.25turn`, `\"to top right\"`, or one of: #{map.keys($map-for-directions)}.";
24
24
  }
25
25
  // One filter colour is written into `linear-gradient(to top, $c, $c)` over an
26
26
  // image, or into `background` when there is none; several are the stops of a
@@ -56,29 +56,8 @@
56
56
  background-image: linear-gradient(to top, $filter-color, $filter-color),
57
57
  imageValue($image-url, "background-image", "$image-url");
58
58
  } @else if list.length($filter-color) > 1 {
59
- $color-list: ();
60
- @for $i from 1 through list.length($filter-color) {
61
- $color-list: list.append($color-list, list.nth($filter-color, $i), comma);
62
- }
63
- @if $filter-direction {
64
- @if map.has-key($map-for-directions, $filter-direction) {
65
- background-image: linear-gradient(
66
- map.get($map-for-directions, $filter-direction),
67
- $color-list
68
- ),
69
- imageValue($image-url, "background-image", "$image-url");
70
- } @else {
71
- @if meta.type-of($filter-direction) == "number" and list.index("deg", math.unit($filter-direction)) {
72
- background-image: linear-gradient($filter-direction, $color-list),
73
- imageValue($image-url, "background-image", "$image-url");
74
- } @else {
75
- @error "`#{$filter-direction}` is not a valid $filter-direction. Pass an angle such as `45deg`, or one of: #{map.keys($map-for-directions)}.";
76
- }
77
- }
78
- } @else {
79
- background-image: linear-gradient(to top, $color-list),
80
- imageValue($image-url, "background-image", "$image-url");
81
- }
59
+ background-image: gradientOf($filter-color, linear, $filter-direction or "top", $member: "background-image", $colors-name: "$filter-color", $direction-name: "$filter-direction"),
60
+ imageValue($image-url, "background-image", "$image-url");
82
61
  }
83
62
  } @else {
84
63
  background-image: imageValue($image-url, "background-image", "$image-url");
@@ -96,10 +75,7 @@
96
75
  @if list.length($filter-color) == 1 {
97
76
  background: $filter-color;
98
77
  } @else if list.length($filter-color) > 1 {
99
- @include linear-gradient(
100
- if(not $filter-direction, "top", $filter-direction),
101
- $filter-color
102
- );
78
+ background: gradientOf($filter-color, linear, $filter-direction or "top", $member: "background-image", $colors-name: "$filter-color", $direction-name: "$filter-direction");
103
79
  }
104
80
  }
105
81
  & > * {
@@ -8,6 +8,7 @@
8
8
  @use "../internal/image-value" as *;
9
9
  @use "../internal/color-problem" as *;
10
10
  @use "../internal/length-problem" as *;
11
+ @use "../internal/gradient" as *;
11
12
 
12
13
  @mixin background-stripes(
13
14
  $color: null,
@@ -57,26 +58,14 @@
57
58
  $get-image: if($image, string.unquote(", ") + imageValue($image, "background-stripes", "$image", $unquote: true), string.unquote(""));
58
59
  @if not $color {
59
60
  $color: rgba(0, 0, 0, 0.1);
60
- background-image: repeating-linear-gradient(
61
- $validate-unit,
62
- $color 0,
63
- $color $thickness,
64
- transparent $thickness,
65
- transparent calc($thickness * 2)
66
- ) + $get-image;
61
+ background-image: gradientOf(($color 0, $color $thickness, transparent $thickness, transparent calc($thickness * 2)), linear, $validate-unit, $repeating: true, $member: "background-stripes") + $get-image;
67
62
  @if $image {
68
63
  background-position: center;
69
64
  background-repeat: no-repeat;
70
65
  background-size: cover;
71
66
  }
72
67
  } @else if list.length($color) == 1 {
73
- background-image: repeating-linear-gradient(
74
- $validate-unit,
75
- $color 0,
76
- $color $thickness,
77
- transparent $thickness,
78
- transparent calc($thickness * 2)
79
- ) + $get-image;
68
+ background-image: gradientOf(($color 0, $color $thickness, transparent $thickness, transparent calc($thickness * 2)), linear, $validate-unit, $repeating: true, $member: "background-stripes") + $get-image;
80
69
  @if $image {
81
70
  background-position: center;
82
71
  background-repeat: no-repeat;
@@ -86,10 +75,10 @@
86
75
  $list: ();
87
76
  @for $i from 1 through list.length($color) {
88
77
  $index-color: list.nth($color, $i);
89
- $style-rule: $index-color calc($thickness * $i - $thickness), $index-color calc($thickness * $i);
90
- $list: list.append($list, $style-rule, comma);
78
+ $list: list.append($list, $index-color calc($thickness * $i - $thickness), comma);
79
+ $list: list.append($list, $index-color calc($thickness * $i), comma);
91
80
  }
92
- background-image: repeating-linear-gradient($validate-unit, $list) + $get-image;
81
+ background-image: gradientOf($list, linear, $validate-unit, $repeating: true, $member: "background-stripes") + $get-image;
93
82
  @if $image {
94
83
  background-position: center;
95
84
  background-repeat: no-repeat;
@@ -23,9 +23,9 @@
23
23
  // refused rather than described as a single pixel.
24
24
  $width: conditionWidth($value, "breakpoint");
25
25
  // One argument matches a single pixel, which two agent trials took for
26
- // "from this width up". Still emitted, so no stylesheet changes, but said
27
- // out loud until 3.0.0 refuses it.
28
- @warn "`breakpoint(#{$value})` matches only a viewport exactly #{$width} wide, `(width: #{$width})`. Write `breakpoint(only, #{$value})` for that width, or `breakpoint(min, #{$value})` from it upwards. The one-argument form will be refused in 3.0.0.";
26
+ // "from this width up". Still emitted, and said out loud,
27
+ // but not refused: the CSS is valid and matches that one width.
28
+ @warn "`breakpoint(#{$value})` matches only a viewport exactly #{$width} wide, `(width: #{$width})`. Write `breakpoint(only, #{$value})` for that width, or `breakpoint(min, #{$value})` from it upwards.";
29
29
  @if map.has-key($map-for-breakpoints, $value) {
30
30
  @media (width: map.get($map-for-breakpoints, $value)) {
31
31
  @content;
@@ -82,8 +82,8 @@ $-forbidden-in-name: "." "," "/" "#" ":" ";" "(" ")" "[" "]" "{" "}" "!" "@" "$"
82
82
  // what validateBreakpoint did, so a working call writes the same condition.
83
83
  $width: conditionWidth($value, "container-query", "@container");
84
84
  $condition: "(width: #{$width})";
85
- // A single pixel, as in `breakpoint`; still emitted until 3.0.0 refuses it.
86
- @warn "`container-query(#{$value})` matches only a container exactly #{$width} wide, `(width: #{$width})`. Write `container-query(only, #{$value})` for that width, or `container-query(min, #{$value})` from it upwards. The one-argument form will be refused in 3.0.0.";
85
+ // A single pixel, as in `breakpoint`; still emitted, with a warning.
86
+ @warn "`container-query(#{$value})` matches only a container exactly #{$width} wide, `(width: #{$width})`. Write `container-query(only, #{$value})` for that width, or `container-query(min, #{$value})` from it upwards.";
87
87
  } @else if $count == 2 {
88
88
  $mode: list.nth($params, 1);
89
89
  @if not list.index("only" "min" "max" "between", $mode) {
@@ -0,0 +1,31 @@
1
+ @charset "UTF-8";
2
+
3
+ @use "../internal/gradient" as *;
4
+
5
+ // One mixin for linear, radial and conic gradients, plain or repeating, with an
6
+ // optional colour interpolation space. It replaced linear-gradient and
7
+ // radial-gradient in 3.0.0; MIGRATION.md has each old call's new form.
8
+ //
9
+ // It writes background-image, not the background shorthand: measured in Chrome
10
+ // 152, the shorthand reset a background-color set before it to transparent.
11
+ // What each argument takes, and what was measured, is in
12
+ // scss/internal/_gradient.scss.
13
+ @mixin gradient(
14
+ $colors,
15
+ $type: linear,
16
+ $direction: null,
17
+ $shape: null,
18
+ $position: null,
19
+ $from: null,
20
+ $in: null,
21
+ $repeating: false
22
+ ) {
23
+ $value: gradientOf($colors, $type, $direction, $shape, $position, $from, $in, $repeating);
24
+ // Written without the space first. A browser that does not know `in` drops
25
+ // the second declaration and keeps this one; measured in Chrome by giving it
26
+ // a space name it does not know.
27
+ @if $in != null {
28
+ background-image: gradientOf($colors, $type, $direction, $shape, $position, $from, null, $repeating, $warn: false);
29
+ }
30
+ background-image: $value;
31
+ }
@@ -27,16 +27,15 @@
27
27
  @forward "except";
28
28
  @forward "focus-ring";
29
29
  @forward "font-face";
30
+ @forward "gradient";
30
31
  @forward "hide";
31
32
  @forward "line-clamp";
32
- @forward "linear-gradient";
33
33
  @forward "loadify";
34
34
  @forward "motion-safe";
35
35
  @forward "only";
36
36
  @forward "placeholder";
37
37
  @forward "placeholder-shown";
38
38
  @forward "position";
39
- @forward "radial-gradient";
40
39
  @forward "remove";
41
40
  @forward "reset-css";
42
41
  @forward "reset-figure";
@@ -13,7 +13,7 @@
13
13
  @include breakpoint(only, $value) {
14
14
  display: none;
15
15
  }
16
- @warn "`remove(#{$value})` hides the element only at a viewport exactly that wide, a single pixel. Write `remove(only, #{$value})` for that width, or `remove(min, #{$value})` from it upwards. The one-argument form will be refused in 3.0.0.";
16
+ @warn "`remove(#{$value})` hides the element only at a viewport exactly that wide, a single pixel. Write `remove(only, #{$value})` for that width, or `remove(min, #{$value})` from it upwards.";
17
17
  } @else if list.length($params) == 2 {
18
18
  @if list.index("min" "max", list.nth($params, 1)) {
19
19
  $mode: list.nth($params, 1);