gerillass 0.0.6 → 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.
- checksums.yaml +4 -4
- data/LICENSE.md +13 -0
- data/README.md +328 -0
- data/SKILL.md +282 -0
- data/gerillass.json +2713 -0
- data/lib/gerillass/engine.rb +55 -0
- data/lib/gerillass/jekyll.rb +13 -0
- data/lib/gerillass.rb +26 -0
- data/scss/_gerillass.scss +15 -0
- data/scss/internal/_color-problem.scss +99 -0
- data/scss/internal/_color-stops-problem.scss +94 -0
- data/scss/internal/_condition-width.scss +22 -0
- data/scss/internal/_custom-property-in.scss +25 -0
- data/scss/internal/_gradient.scss +425 -0
- data/scss/internal/_image-value.scss +68 -0
- data/scss/internal/_is-condition-value.scss +94 -0
- data/scss/internal/_is-css-function.scss +21 -0
- data/scss/internal/_is-size.scss +22 -0
- data/scss/internal/_keyword-value.scss +76 -0
- data/scss/internal/_length-problem.scss +127 -0
- data/scss/internal/_sibling-index.scss +51 -0
- data/scss/internal/_words.scss +35 -0
- data/scss/library/_adaptive.scss +31 -0
- data/scss/library/_after.scss +28 -0
- data/scss/library/_all-buttons.scss +21 -0
- data/scss/library/_all-text-inputs.scss +21 -0
- data/{core → scss}/library/_antialias.scss +5 -1
- data/scss/library/_aspect-ratio.scss +27 -0
- data/scss/library/_background-dots.scss +104 -0
- data/scss/library/_background-image.scss +89 -0
- data/scss/library/_background-stripes.scss +88 -0
- data/scss/library/_before.scss +28 -0
- data/scss/library/_border-box.scss +30 -0
- data/scss/library/_border-radius.scss +164 -0
- data/scss/library/_brand-logo.scss +33 -0
- data/scss/library/_breakpoint.scss +96 -0
- data/scss/library/_breakpointer.scss +40 -0
- data/scss/library/_center.scss +19 -0
- data/scss/library/_circle.scss +15 -0
- data/{core → scss}/library/_clearfix.scss +1 -1
- data/scss/library/_columnizer.scss +125 -0
- data/scss/library/_container-query.scss +119 -0
- data/scss/library/_container.scss +72 -0
- data/scss/library/_counter.scss +59 -0
- data/scss/library/_ellipsis.scss +87 -0
- data/scss/library/_escape-to-parent.scss +12 -0
- data/scss/library/_except.scss +71 -0
- data/scss/library/_focus-ring.scss +63 -0
- data/scss/library/_font-face.scss +240 -0
- data/scss/library/_gradient.scss +31 -0
- data/scss/library/_hide.scss +25 -0
- data/scss/library/_index.scss +57 -0
- data/scss/library/_line-clamp.scss +38 -0
- data/scss/library/_loadify.scss +62 -0
- data/scss/library/_motion-safe.scss +28 -0
- data/scss/library/_only.scss +73 -0
- data/scss/library/_placeholder-shown.scss +7 -0
- data/scss/library/_placeholder.scss +19 -0
- data/scss/library/_position.scss +72 -0
- data/scss/library/_remove.scss +40 -0
- data/scss/library/_reset-css.scss +57 -0
- data/scss/library/_reset-figure.scss +10 -0
- data/scss/library/_resizable.scss +34 -0
- data/scss/library/_responsive-image.scss +6 -0
- data/scss/library/_scissors.scss +34 -0
- data/scss/library/_screen-agent.scss +34 -0
- data/scss/library/_sizer.scss +15 -0
- data/scss/library/_smartphone.scss +29 -0
- data/scss/library/_sprite.scss +100 -0
- data/scss/library/_stretched-link.scss +21 -0
- data/scss/library/_tablet.scss +29 -0
- data/scss/library/_text-gradient.scss +48 -0
- data/scss/library/_text-image.scss +15 -0
- data/scss/library/_text-selection.scss +22 -0
- data/scss/library/_text-shadow.scss +145 -0
- data/scss/library/_text-stroke.scss +43 -0
- data/scss/library/_tokens.scss +111 -0
- data/scss/library/_triangle.scss +115 -0
- data/scss/lists/_index.scss +8 -0
- data/scss/lists/_list-of-anchor-pseudo-classes.scss +9 -0
- data/scss/lists/_list-of-buttons.scss +8 -0
- data/scss/lists/_list-of-counter-styles.scss +59 -0
- data/scss/lists/_list-of-directions.scss +12 -0
- data/scss/lists/_list-of-length-units.scss +23 -0
- data/scss/lists/_list-of-text-inputs.scss +20 -0
- data/scss/maps/_index.scss +8 -0
- data/scss/maps/_map-for-breakpoints.scss +9 -0
- data/scss/maps/_map-for-directions.scss +12 -0
- data/scss/maps/_map-for-font-formats.scss +9 -0
- data/scss/maps/_map-for-positions.scss +13 -0
- data/scss/maps/_map-for-smartphones.scss +72 -0
- data/scss/maps/_map-for-tablets.scss +32 -0
- data/scss/utilities/_clear-unit.scss +11 -0
- data/scss/utilities/_clear-whitespace.scss +15 -0
- data/scss/utilities/_convert-to-em.scss +16 -0
- data/scss/utilities/_convert-to-number.scss +45 -0
- data/scss/utilities/_fill-nulls.scss +18 -0
- data/scss/utilities/_fluid.scss +76 -0
- data/scss/utilities/_font-sizer.scss +19 -0
- data/scss/utilities/_font-source.scss +23 -0
- data/scss/utilities/_gradient-value.scss +24 -0
- data/scss/utilities/_index.scss +26 -0
- data/scss/utilities/_is-color.scss +16 -0
- data/scss/utilities/_is-gutter.scss +24 -0
- data/scss/utilities/_is-number.scss +11 -0
- data/scss/utilities/_is-time.scss +14 -0
- data/scss/utilities/_map-deep-get.scss +10 -0
- data/scss/utilities/_pixelify.scss +20 -0
- data/scss/utilities/_pseudo-selector.scss +12 -0
- data/scss/utilities/_remify.scss +16 -0
- data/scss/utilities/_shade.scss +10 -0
- data/scss/utilities/_shorthand-property.scss +17 -0
- data/scss/utilities/_tint.scss +10 -0
- data/scss/utilities/_validate-breakpoint.scss +41 -0
- data/scss/utilities/_validate-length.scss +37 -0
- data/scss/utilities/_validate-ratio.scss +77 -0
- data/scss/utilities/_validate-scissors.scss +34 -0
- metadata +131 -46
- data/core/_gerillass.scss +0 -4
- data/core/library/_before.scss +0 -18
- data/core/library/_border-box.scss +0 -26
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
@charset "UTF-8";
|
|
2
|
+
|
|
3
|
+
@use "sass:meta";
|
|
4
|
+
@use "sass:string";
|
|
5
|
+
@use "is-css-function" as *;
|
|
6
|
+
|
|
7
|
+
// Shared by the mixins and not public API; see _is-css-function.scss.
|
|
8
|
+
|
|
9
|
+
// An image path goes into url(). A var(), url(), image-set() or gradient is
|
|
10
|
+
// already an image, and wrapping it produced url(var(--x)), which loads nothing.
|
|
11
|
+
//
|
|
12
|
+
// $unquote is there because the copies this replaced differed:
|
|
13
|
+
// background-dots and background-stripes wrote `url(a.png)`, the other three
|
|
14
|
+
// `url("a.png")`. Both load the same file, and keeping each as it was means no
|
|
15
|
+
// stylesheet changes.
|
|
16
|
+
//
|
|
17
|
+
// What it refuses, measured in Chrome 152:
|
|
18
|
+
//
|
|
19
|
+
// - a list where one image is meant: `url(16 9)` was dropped;
|
|
20
|
+
// - a number, a colour or a boolean: `url(42)`, `url(#ff0000)` and `url(true)`
|
|
21
|
+
// are kept, but ask for a file named 42, a fragment of the page, or a file
|
|
22
|
+
// named true, which is never the image meant. background-dots and
|
|
23
|
+
// background-stripes refused these already.
|
|
24
|
+
//
|
|
25
|
+
// And an unquoted path is quoted when it has to be: `url(a b)`, `url(a(1).png)`
|
|
26
|
+
// and `url(a'b.png)` were dropped, while the same paths in quotes were kept and
|
|
27
|
+
// `url("a b")` resolved to `a%20b`. Every other path is written as before.
|
|
28
|
+
@function imageValue($value, $mixin, $argument, $unquote: false) {
|
|
29
|
+
// paint(), image() and -webkit-cross-fade() were kept as images in Chrome
|
|
30
|
+
// 152 and used to be wrapped into url(paint(...)), which loads nothing;
|
|
31
|
+
// cross-fade(), element() and -moz-element() are in the specification or
|
|
32
|
+
// other engines.
|
|
33
|
+
@if isCssFunction($value, "var" "url" "image-set" "linear-gradient" "radial-gradient" "conic-gradient" "repeating-linear-gradient" "repeating-radial-gradient" "repeating-conic-gradient" "paint" "image" "cross-fade" "-webkit-cross-fade" "element" "-moz-element") {
|
|
34
|
+
@return $value;
|
|
35
|
+
}
|
|
36
|
+
@if meta.type-of($value) == "list" or meta.type-of($value) == "arglist" or meta.type-of($value) == "map" {
|
|
37
|
+
@error "`#{meta.inspect($value)}` is not a valid #{$argument} for `#{$mixin}`: it is a list where one image is meant, and a browser drops `url()` with a list in it. Pass one path as a string, such as `\"/img/hero.png\"`.";
|
|
38
|
+
}
|
|
39
|
+
@if meta.type-of($value) != "string" {
|
|
40
|
+
@error "`#{meta.inspect($value)}` is not a valid #{$argument} for `#{$mixin}`: an image path is a string, and `url(#{meta.inspect($value)})` asks for a file of that name, which is never the image. Pass a path as a string, such as `\"/img/hero.png\"`, or var() or a gradient.";
|
|
41
|
+
}
|
|
42
|
+
@if not $unquote {
|
|
43
|
+
@return url($value);
|
|
44
|
+
}
|
|
45
|
+
$text: string.unquote($value);
|
|
46
|
+
@if not (string.index($text, " ") or string.index($text, "(") or string.index($text, ")") or string.index($text, "'") or string.index($text, "\"")) {
|
|
47
|
+
@return url(string.unquote($value));
|
|
48
|
+
}
|
|
49
|
+
@if string.index($text, "\"") {
|
|
50
|
+
@return string.unquote("url('#{-escaped-single-quotes($text)}')");
|
|
51
|
+
}
|
|
52
|
+
@return string.unquote("url(\"#{$text}\")");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// A path holding a double quote goes into single quotes, so any single quote in
|
|
56
|
+
// it is escaped.
|
|
57
|
+
@function -escaped-single-quotes($text) {
|
|
58
|
+
$result: "";
|
|
59
|
+
@for $i from 1 through string.length($text) {
|
|
60
|
+
$character: string.slice($text, $i, $i);
|
|
61
|
+
@if $character == "'" {
|
|
62
|
+
$result: $result + "\\'";
|
|
63
|
+
} @else {
|
|
64
|
+
$result: $result + $character;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
@return $result;
|
|
68
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
@charset "UTF-8";
|
|
2
|
+
|
|
3
|
+
@use "sass:list";
|
|
4
|
+
@use "sass:math";
|
|
5
|
+
@use "sass:meta";
|
|
6
|
+
@use "sass:string";
|
|
7
|
+
|
|
8
|
+
// Shared by the mixins and not public API; see _is-css-function.scss.
|
|
9
|
+
|
|
10
|
+
// Every length unit a width condition kept in Chrome 152, in @media and
|
|
11
|
+
// @container alike and in any case: `(min-width: 10PX)` matched. `x`, `dppx`,
|
|
12
|
+
// `fr`, `s`, `%` and a made-up unit never matched, and neither did a unitless
|
|
13
|
+
// number other than 0.
|
|
14
|
+
$-length-units: "px" "cm" "mm" "q" "in" "pt" "pc" "em" "rem" "ex" "rex" "ch" "rch" "cap" "rcap" "ic" "ric" "lh" "rlh" "vw" "vh" "vi" "vb" "vmin" "vmax" "svw" "svh" "svi" "svb" "svmin" "svmax" "lvw" "lvh" "lvi" "lvb" "lvmin" "lvmax" "dvw" "dvh" "dvi" "dvb" "dvmin" "dvmax" "cqw" "cqh" "cqi" "cqb" "cqmin" "cqmax";
|
|
15
|
+
|
|
16
|
+
// The units a resolution condition kept, also in any case. A unitless number, a
|
|
17
|
+
// length and a negative resolution never matched; `0dppx` was kept.
|
|
18
|
+
$-resolution-units: "dpi" "dpcm" "dppx" "x";
|
|
19
|
+
|
|
20
|
+
// Angles, for an oblique `font-style`: `oblique 0.2rad` was kept in a @font-face
|
|
21
|
+
// rule and `oblique 10`, unitless, was dropped.
|
|
22
|
+
$-angle-units: "deg" "grad" "rad" "turn";
|
|
23
|
+
|
|
24
|
+
// True for a value a @media or @container condition can match: a number in one
|
|
25
|
+
// of the units above, a calculation, or either written as a quoted string, which
|
|
26
|
+
// Sass writes into a condition without its quotes, so `breakpoint(min, "600px")`
|
|
27
|
+
// has always worked. A calculation is taken on trust: `calc(30em + 1px)`,
|
|
28
|
+
// `clamp()`, `min()` and `max()` were all kept, and Sass reduces `calc(10deg)`
|
|
29
|
+
// to a number before it gets here, so that one is checked like any other.
|
|
30
|
+
//
|
|
31
|
+
// $kind is "length" or "resolution" for a condition. A negative length was
|
|
32
|
+
// kept, since it is valid and simply matches every width or none; a negative
|
|
33
|
+
// resolution was not. Two more kinds serve values outside a condition, where a
|
|
34
|
+
// caller rules out a negative itself if the property does: "length-percentage",
|
|
35
|
+
// a length or a percentage, and "angle".
|
|
36
|
+
@function isConditionValue($value, $kind: "length") {
|
|
37
|
+
$units: $-length-units;
|
|
38
|
+
@if $kind == "resolution" {
|
|
39
|
+
$units: $-resolution-units;
|
|
40
|
+
} @else if $kind == "length-percentage" {
|
|
41
|
+
$units: list.append($-length-units, "%");
|
|
42
|
+
} @else if $kind == "angle" {
|
|
43
|
+
$units: $-angle-units;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@if meta.type-of($value) == "calculation" {
|
|
47
|
+
@return true;
|
|
48
|
+
}
|
|
49
|
+
@if meta.type-of($value) == "number" {
|
|
50
|
+
@if math.is-unitless($value) {
|
|
51
|
+
@return ($kind == "length" or $kind == "length-percentage") and $value == 0;
|
|
52
|
+
}
|
|
53
|
+
@if $kind == "resolution" and $value < 0 {
|
|
54
|
+
@return false;
|
|
55
|
+
}
|
|
56
|
+
@return list.index($units, string.to-lower-case(math.unit($value))) != null;
|
|
57
|
+
}
|
|
58
|
+
@if meta.type-of($value) != "string" {
|
|
59
|
+
@return false;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
$text: string.to-lower-case(string.unquote($value));
|
|
63
|
+
@each $function in "calc(" "clamp(" "min(" "max(" {
|
|
64
|
+
@if string.index($text, $function) == 1 {
|
|
65
|
+
@return true;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// A quoted length, such as "600px": the number runs up to the first
|
|
70
|
+
// character that cannot be part of one, and the rest is the unit.
|
|
71
|
+
$unit-start: null;
|
|
72
|
+
$digits: 0;
|
|
73
|
+
@for $i from 1 through string.length($text) {
|
|
74
|
+
$character: string.slice($text, $i, $i);
|
|
75
|
+
@if $unit-start == null {
|
|
76
|
+
@if string.index("0123456789", $character) {
|
|
77
|
+
$digits: $digits + 1;
|
|
78
|
+
} @else if not string.index(".+-", $character) {
|
|
79
|
+
$unit-start: $i;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
@if $digits == 0 {
|
|
84
|
+
@return false;
|
|
85
|
+
}
|
|
86
|
+
@if $unit-start == null {
|
|
87
|
+
// A quoted unitless number: only zero, and only for a length.
|
|
88
|
+
@return ($kind == "length" or $kind == "length-percentage") and not string.index($text, "1") and not string.index($text, "2") and not string.index($text, "3") and not string.index($text, "4") and not string.index($text, "5") and not string.index($text, "6") and not string.index($text, "7") and not string.index($text, "8") and not string.index($text, "9");
|
|
89
|
+
}
|
|
90
|
+
@if $kind == "resolution" and string.index(string.slice($text, 1, $unit-start - 1), "-") {
|
|
91
|
+
@return false;
|
|
92
|
+
}
|
|
93
|
+
@return list.index($units, string.slice($text, $unit-start)) != null;
|
|
94
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
@charset "UTF-8";
|
|
2
|
+
|
|
3
|
+
@use "sass:list";
|
|
4
|
+
@use "sass:meta";
|
|
5
|
+
@use "sass:string";
|
|
6
|
+
|
|
7
|
+
// scss/internal/ holds checks the mixins share. No _index.scss forwards it, so
|
|
8
|
+
// a user cannot reach these functions and they are not public API: through
|
|
9
|
+
// `@use "gerillass" as *` or `@import` a call to one renders as literal CSS,
|
|
10
|
+
// and through a namespace it is an undefined function. Their names must not
|
|
11
|
+
// start with `-` or `_`, which would make them private to their own file.
|
|
12
|
+
|
|
13
|
+
// True for an unquoted call to one of $names, such as var(--x). A quoted string
|
|
14
|
+
// stays text, so `"var(--x)"` is not a call.
|
|
15
|
+
@function isCssFunction($value, $names) {
|
|
16
|
+
@if meta.type-of($value) != "string" or string.slice(meta.inspect($value), 1, 1) == "\"" {
|
|
17
|
+
@return false;
|
|
18
|
+
}
|
|
19
|
+
$open: string.index($value, "(");
|
|
20
|
+
@return $open != null and list.index($names, string.to-lower-case(string.slice($value, 1, $open - 1))) != null;
|
|
21
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
@charset "UTF-8";
|
|
2
|
+
|
|
3
|
+
@use "sass:list";
|
|
4
|
+
@use "sass:meta";
|
|
5
|
+
@use "sass:string";
|
|
6
|
+
|
|
7
|
+
// Shared by the mixins and not public API; see _is-css-function.scss.
|
|
8
|
+
|
|
9
|
+
// A size Sass can use inside calc(): a number, a calculation such as calc(),
|
|
10
|
+
// min() or clamp(), or var() and env(), which only the browser can resolve.
|
|
11
|
+
// Anything else would pass silently through calc(): `calc(nonsense * 5)`
|
|
12
|
+
// compiles.
|
|
13
|
+
@function isSize($value) {
|
|
14
|
+
@if meta.type-of($value) == "number" or meta.type-of($value) == "calculation" {
|
|
15
|
+
@return true;
|
|
16
|
+
}
|
|
17
|
+
@if meta.type-of($value) == "string" and string.slice(meta.inspect($value), 1, 1) != "\"" {
|
|
18
|
+
$open: string.index($value, "(");
|
|
19
|
+
@return $open != null and list.index("var" "env", string.to-lower-case(string.slice($value, 1, $open - 1))) != null;
|
|
20
|
+
}
|
|
21
|
+
@return false;
|
|
22
|
+
}
|