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.
- package/README.md +46 -7
- package/SKILL.md +20 -11
- package/gerillass.json +275 -112
- package/package.json +1 -1
- package/scss/internal/_gradient.scss +425 -0
- package/scss/library/_background-dots.scss +7 -6
- package/scss/library/_background-image.scss +6 -30
- package/scss/library/_background-stripes.scss +6 -17
- package/scss/library/_breakpoint.scss +3 -3
- package/scss/library/_container-query.scss +2 -2
- package/scss/library/_gradient.scss +31 -0
- package/scss/library/_index.scss +1 -2
- package/scss/library/_remove.scss +1 -1
- package/scss/library/_text-gradient.scss +36 -26
- package/scss/utilities/_gradient-value.scss +24 -0
- package/scss/utilities/_index.scss +1 -0
- package/scss/library/_linear-gradient.scss +0 -33
- package/scss/library/_radial-gradient.scss +0 -184
|
@@ -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:
|
|
63
|
-
|
|
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:
|
|
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:
|
|
73
|
-
|
|
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:
|
|
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
|
|
23
|
-
@error "`#{$filter-direction}` is not a valid $filter-direction
|
|
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-
|
|
60
|
-
|
|
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
|
-
|
|
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-
|
|
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-
|
|
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
|
-
$
|
|
90
|
-
$list: list.append($list, $
|
|
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:
|
|
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,
|
|
27
|
-
//
|
|
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.
|
|
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
|
|
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.
|
|
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
|
+
}
|
package/scss/library/_index.scss
CHANGED
|
@@ -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.
|
|
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);
|