gerillass 2.3.0 → 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.
Files changed (55) hide show
  1. package/README.md +46 -7
  2. package/SKILL.md +37 -12
  3. package/gerillass.json +527 -145
  4. package/package.json +1 -1
  5. package/scss/internal/_color-problem.scss +99 -0
  6. package/scss/internal/_color-stops-problem.scss +94 -0
  7. package/scss/internal/_condition-width.scss +22 -0
  8. package/scss/internal/_custom-property-in.scss +25 -0
  9. package/scss/internal/_gradient.scss +425 -0
  10. package/scss/internal/_image-value.scss +68 -0
  11. package/scss/internal/_is-condition-value.scss +94 -0
  12. package/scss/internal/_is-css-function.scss +21 -0
  13. package/scss/internal/_is-size.scss +22 -0
  14. package/scss/internal/_keyword-value.scss +76 -0
  15. package/scss/internal/_length-problem.scss +127 -0
  16. package/scss/internal/_sibling-index.scss +51 -0
  17. package/scss/internal/_words.scss +35 -0
  18. package/scss/library/_adaptive.scss +17 -0
  19. package/scss/library/_after.scss +2 -12
  20. package/scss/library/_background-dots.scss +36 -43
  21. package/scss/library/_background-image.scss +40 -52
  22. package/scss/library/_background-stripes.scss +40 -54
  23. package/scss/library/_before.scss +2 -12
  24. package/scss/library/_border-radius.scss +83 -0
  25. package/scss/library/_brand-logo.scss +10 -24
  26. package/scss/library/_breakpoint.scss +19 -26
  27. package/scss/library/_circle.scss +7 -0
  28. package/scss/library/_columnizer.scss +62 -2
  29. package/scss/library/_container-query.scss +13 -29
  30. package/scss/library/_container.scss +2 -19
  31. package/scss/library/_counter.scss +3 -14
  32. package/scss/library/_ellipsis.scss +78 -1
  33. package/scss/library/_except.scss +15 -0
  34. package/scss/library/_focus-ring.scss +29 -0
  35. package/scss/library/_font-face.scss +117 -1
  36. package/scss/library/_gradient.scss +31 -0
  37. package/scss/library/_index.scss +1 -2
  38. package/scss/library/_line-clamp.scss +2 -13
  39. package/scss/library/_only.scss +16 -0
  40. package/scss/library/_position.scss +34 -3
  41. package/scss/library/_remove.scss +1 -1
  42. package/scss/library/_resizable.scss +29 -2
  43. package/scss/library/_screen-agent.scss +8 -22
  44. package/scss/library/_sizer.scss +9 -0
  45. package/scss/library/_sprite.scss +65 -0
  46. package/scss/library/_text-gradient.scss +36 -18
  47. package/scss/library/_text-image.scss +2 -23
  48. package/scss/library/_text-stroke.scss +30 -0
  49. package/scss/library/_triangle.scss +25 -56
  50. package/scss/utilities/_gradient-value.scss +24 -0
  51. package/scss/utilities/_index.scss +1 -0
  52. package/scss/utilities/_validate-breakpoint.scss +32 -6
  53. package/scss/utilities/_validate-scissors.scss +7 -0
  54. package/scss/library/_linear-gradient.scss +0 -26
  55. package/scss/library/_radial-gradient.scss +0 -30
@@ -3,40 +3,11 @@
3
3
  @use "sass:list";
4
4
  @use "sass:meta";
5
5
  @use "sass:string";
6
-
7
- // An image path goes into url(). A var(), url(), image-set() or gradient is
8
- // already an image, and wrapping it produced url(var(--x)), which loads nothing.
9
- @function -image($value) {
10
- @if -is-css-function($value, "var" "url" "image-set" "linear-gradient" "radial-gradient" "conic-gradient" "repeating-linear-gradient" "repeating-radial-gradient" "repeating-conic-gradient") {
11
- @return $value;
12
- }
13
- @return url(string.unquote($value));
14
- }
15
-
16
- // True for an unquoted call to one of $names, such as var(--x). A quoted string
17
- // stays text, so `"var(--x)"` is not a call.
18
- @function -is-css-function($value, $names) {
19
- @if meta.type-of($value) != "string" or string.slice(meta.inspect($value), 1, 1) == "\"" {
20
- @return false;
21
- }
22
- $open: string.index($value, "(");
23
- @return $open != null and list.index($names, string.to-lower-case(string.slice($value, 1, $open - 1))) != null;
24
- }
25
-
26
- // A size Sass can use inside calc(): a number, a calculation such as calc(),
27
- // min() or clamp(), or var() and env(), which only the browser can resolve.
28
- // Anything else would pass silently through calc(): `calc(nonsense * 5)`
29
- // compiles.
30
- @function -is-size($value) {
31
- @if meta.type-of($value) == "number" or meta.type-of($value) == "calculation" {
32
- @return true;
33
- }
34
- @if meta.type-of($value) == "string" and string.slice(meta.inspect($value), 1, 1) != "\"" {
35
- $open: string.index($value, "(");
36
- @return $open != null and list.index("var" "env", string.to-lower-case(string.slice($value, 1, $open - 1))) != null;
37
- }
38
- @return false;
39
- }
6
+ @use "../internal/is-size" as *;
7
+ @use "../internal/image-value" as *;
8
+ @use "../internal/color-problem" as *;
9
+ @use "../internal/length-problem" as *;
10
+ @use "../internal/gradient" as *;
40
11
 
41
12
  @mixin background-dots(
42
13
  $color: null,
@@ -49,40 +20,62 @@
49
20
  // the signature lets $size be checked first, and doing the arithmetic in
50
21
  // calc() lets var() and clamp() through: Sass simplifies calc() on plain
51
22
  // numbers back to a number, so a call with lengths emits the same CSS.
52
- @if not -is-size($size) {
23
+ @if not isSize($size) {
53
24
  @error "`#{meta.inspect($size)}` is not a valid $size for `background-dots`. Pass a length, or var(), env() or a calculation such as `clamp()`.";
54
25
  }
55
26
  @if $gutter == null {
56
27
  $gutter: calc($size * 5);
57
28
  }
58
- @if not -is-size($gutter) {
29
+ @if not isSize($gutter) {
59
30
  @error "`#{meta.inspect($gutter)}` is not a valid $gutter for `background-dots`. Pass a length, or var(), env() or a calculation such as `calc()`.";
60
31
  }
32
+ // isSize takes any number, since it only guards the arithmetic. The size is a
33
+ // colour stop's position and the gutter a background-size, which in Chrome
34
+ // 152 kept a percentage and dropped a negative length, a unitless number
35
+ // other than 0 and a unit that is not a length, so no dots were drawn.
36
+ @each $name, $value in ("$size": $size, "$gutter": $gutter) {
37
+ $problem: lengthProblem($value, $negative: false);
38
+ @if $problem {
39
+ @error "`#{meta.inspect($value)}` is not a valid #{$name} for `background-dots`: #{$problem}. A browser drops the pattern.";
40
+ }
41
+ }
61
42
  @if $image != null and meta.type-of($image) != "string" {
62
43
  @error "`#{$image}` is not a valid $image for `background-dots`. Pass an image path as a string.";
63
44
  }
64
45
  @if $diagonal != true and $diagonal != false {
65
46
  @error "`#{$diagonal}` is not a valid $diagonal for `background-dots`. Pass `true` or `false`.";
66
47
  }
48
+ // Each colour goes into a radial gradient as `radial-gradient($color $size,
49
+ // ...)`. Measured in Chrome 152, a word or a quoted colour there drops the
50
+ // gradient, and a length is read as the gradient's size instead, so neither
51
+ // draws the dots meant; see scss/internal/_color-problem.scss.
52
+ @if $color != null {
53
+ @each $item in $color {
54
+ $problem: colorProblem($item);
55
+ @if $problem {
56
+ @error "`#{meta.inspect($item)}` is not a valid colour in $color for `background-dots`: #{$problem}. Pass one colour, or two for the diagonal variant, such as `red` or `var(--dot)`.";
57
+ }
58
+ }
59
+ }
67
60
  @if not $color {
68
61
  $color: rgba(0, 0, 0, 0.1);
69
62
  @if $diagonal == true {
70
- background-image: radial-gradient($color $size, transparent 0),
71
- 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");
72
65
  background-position: calc($gutter / 2) calc($gutter / 2),
73
66
  calc($gutter * 2) calc($gutter * 2);
74
67
  } @else if $diagonal == false {
75
- background-image: radial-gradient($color $size, transparent 0);
68
+ background-image: gradientOf(($color $size, transparent 0), radial, $member: "background-dots");
76
69
  background-position: calc($gutter / 2) calc($gutter / 2);
77
70
  }
78
71
  } @else if $color {
79
72
  @if $diagonal == true {
80
- background-image: radial-gradient(list.nth($color, 1) $size, transparent 0),
81
- 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");
82
75
  background-position: calc($gutter / 2) calc($gutter / 2),
83
76
  calc($gutter * 2) calc($gutter * 2);
84
77
  } @else if $diagonal == false {
85
- 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");
86
79
  background-position: calc($gutter / 2) calc($gutter / 2);
87
80
  @if list.length($color) > 1 {
88
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.";
@@ -101,7 +94,7 @@
101
94
  height: 100%;
102
95
  top: 0;
103
96
  left: 0;
104
- background-image: -image($image);
97
+ background-image: imageValue($image, "background-dots", "$image", $unquote: true);
105
98
  background-repeat: no-repeat;
106
99
  background-position: center;
107
100
  background-size: cover;
@@ -4,28 +4,12 @@
4
4
  @use "sass:map";
5
5
  @use "sass:math";
6
6
  @use "sass:meta";
7
- @use "sass:string";
8
- @use "../library/linear-gradient" as *;
9
7
  @use "../maps/map-for-directions" as *;
10
-
11
- // An image path goes into url(). A var(), url(), image-set() or gradient is
12
- // already an image, and wrapping it produced url(var(--x)), which loads nothing.
13
- @function -image($value) {
14
- @if -is-css-function($value, "var" "url" "image-set" "linear-gradient" "radial-gradient" "conic-gradient" "repeating-linear-gradient" "repeating-radial-gradient" "repeating-conic-gradient") {
15
- @return $value;
16
- }
17
- @return url($value);
18
- }
19
-
20
- // True for an unquoted call to one of $names, such as var(--x). A quoted string
21
- // stays text, so `"var(--x)"` is not a call.
22
- @function -is-css-function($value, $names) {
23
- @if meta.type-of($value) != "string" or string.slice(meta.inspect($value), 1, 1) == "\"" {
24
- @return false;
25
- }
26
- $open: string.index($value, "(");
27
- @return $open != null and list.index($names, string.to-lower-case(string.slice($value, 1, $open - 1))) != null;
28
- }
8
+ @use "../internal/image-value" as *;
9
+ @use "../internal/color-problem" as *;
10
+ @use "../internal/color-stops-problem" as *;
11
+ @use "../internal/gradient" as *;
12
+ @use "../internal/is-css-function" as *;
29
13
 
30
14
  @mixin background-image(
31
15
  $image-url: null,
@@ -35,41 +19,48 @@
35
19
  // The direction used to be read only when there were two or more colours,
36
20
  // so with one colour any value was dropped without a word, a typo included.
37
21
  // Check it first, against what the gradient branches accept.
38
- @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") {
39
- @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
+ }
25
+ // One filter colour is written into `linear-gradient(to top, $c, $c)` over an
26
+ // image, or into `background` when there is none; several are the stops of a
27
+ // gradient. Measured in Chrome 152, a word or a quoted colour drops either, and
28
+ // a length in `background` is read as a position, so none of them is a filter.
29
+ // CSS-wide keywords are refused, since they drop the gradient.
30
+ // With no $image-url the image sits in the markup and the filter is written
31
+ // as an ::after layer's `background`, where an image is as valid as a colour.
32
+ // Measured in Chrome 152 over an image in a style attribute, a
33
+ // linear-gradient drew a scrim, a radial-gradient a vignette and url() a
34
+ // pattern, so those are accepted there. `inherit` drew the same image over
35
+ // itself and `10px` an empty layer, so they stay refused. With an image the
36
+ // filter goes inside linear-gradient(), where a gradient dropped the whole
37
+ // declaration, image included.
38
+ // paint(), image() and -webkit-cross-fade() were kept as images in Chrome 152;
39
+ // cross-fade(), element() and -moz-element() are in the specification or other
40
+ // engines and are let through on the same grounds.
41
+ $overlay-image: not $image-url and isCssFunction($filter-color, "url" "image-set" "var" "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");
42
+ @if $filter-color != null and not $overlay-image {
43
+ $problem: null;
44
+ @if list.length($filter-color) == 1 {
45
+ $problem: colorProblem($filter-color);
46
+ } @else {
47
+ $problem: colorStopsProblem($filter-color);
48
+ }
49
+ @if $problem {
50
+ @error "`#{meta.inspect($filter-color)}` is not a valid $filter-color for `background-image`: #{$problem}. Pass a colour, such as `rgba(0, 0, 0, 0.5)`, or several for a gradient.";
51
+ }
40
52
  }
41
53
  @if $image-url {
42
54
  @if $filter-color {
43
55
  @if list.length($filter-color) == 1 {
44
56
  background-image: linear-gradient(to top, $filter-color, $filter-color),
45
- -image($image-url);
57
+ imageValue($image-url, "background-image", "$image-url");
46
58
  } @else if list.length($filter-color) > 1 {
47
- $color-list: ();
48
- @for $i from 1 through list.length($filter-color) {
49
- $color-list: list.append($color-list, list.nth($filter-color, $i), comma);
50
- }
51
- @if $filter-direction {
52
- @if map.has-key($map-for-directions, $filter-direction) {
53
- background-image: linear-gradient(
54
- map.get($map-for-directions, $filter-direction),
55
- $color-list
56
- ),
57
- -image($image-url);
58
- } @else {
59
- @if meta.type-of($filter-direction) == "number" and list.index("deg", math.unit($filter-direction)) {
60
- background-image: linear-gradient($filter-direction, $color-list),
61
- -image($image-url);
62
- } @else {
63
- @error "`#{$filter-direction}` is not a valid $filter-direction. Pass an angle such as `45deg`, or one of: #{map.keys($map-for-directions)}.";
64
- }
65
- }
66
- } @else {
67
- background-image: linear-gradient(to top, $color-list),
68
- -image($image-url);
69
- }
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");
70
61
  }
71
62
  } @else {
72
- background-image: -image($image-url);
63
+ background-image: imageValue($image-url, "background-image", "$image-url");
73
64
  }
74
65
  } @else {
75
66
  position: relative;
@@ -84,10 +75,7 @@
84
75
  @if list.length($filter-color) == 1 {
85
76
  background: $filter-color;
86
77
  } @else if list.length($filter-color) > 1 {
87
- @include linear-gradient(
88
- if(not $filter-direction, "top", $filter-direction),
89
- $filter-color
90
- );
78
+ background: gradientOf($filter-color, linear, $filter-direction or "top", $member: "background-image", $colors-name: "$filter-color", $direction-name: "$filter-direction");
91
79
  }
92
80
  }
93
81
  & > * {
@@ -4,40 +4,11 @@
4
4
  @use "sass:math";
5
5
  @use "sass:meta";
6
6
  @use "sass:string";
7
-
8
- // An image path goes into url(). A var(), url(), image-set() or gradient is
9
- // already an image, and wrapping it produced url(var(--x)), which loads nothing.
10
- @function -image($value) {
11
- @if -is-css-function($value, "var" "url" "image-set" "linear-gradient" "radial-gradient" "conic-gradient" "repeating-linear-gradient" "repeating-radial-gradient" "repeating-conic-gradient") {
12
- @return $value;
13
- }
14
- @return url(string.unquote($value));
15
- }
16
-
17
- // True for an unquoted call to one of $names, such as var(--x). A quoted string
18
- // stays text, so `"var(--x)"` is not a call.
19
- @function -is-css-function($value, $names) {
20
- @if meta.type-of($value) != "string" or string.slice(meta.inspect($value), 1, 1) == "\"" {
21
- @return false;
22
- }
23
- $open: string.index($value, "(");
24
- @return $open != null and list.index($names, string.to-lower-case(string.slice($value, 1, $open - 1))) != null;
25
- }
26
-
27
- // A size Sass can use inside calc(): a number, a calculation such as calc(),
28
- // min() or clamp(), or var() and env(), which only the browser can resolve.
29
- // Anything else would pass silently through calc(): `calc(nonsense * 5)`
30
- // compiles.
31
- @function -is-size($value) {
32
- @if meta.type-of($value) == "number" or meta.type-of($value) == "calculation" {
33
- @return true;
34
- }
35
- @if meta.type-of($value) == "string" and string.slice(meta.inspect($value), 1, 1) != "\"" {
36
- $open: string.index($value, "(");
37
- @return $open != null and list.index("var" "env", string.to-lower-case(string.slice($value, 1, $open - 1))) != null;
38
- }
39
- @return false;
40
- }
7
+ @use "../internal/is-size" as *;
8
+ @use "../internal/image-value" as *;
9
+ @use "../internal/color-problem" as *;
10
+ @use "../internal/length-problem" as *;
11
+ @use "../internal/gradient" as *;
41
12
 
42
13
  @mixin background-stripes(
43
14
  $color: null,
@@ -47,39 +18,54 @@
47
18
  ) {
48
19
  // The arithmetic below runs in calc() so var() and clamp() work; on plain
49
20
  // lengths Sass simplifies it back to the same number.
50
- @if not -is-size($thickness) {
21
+ @if not isSize($thickness) {
51
22
  @error "`#{meta.inspect($thickness)}` is not a valid $thickness for `background-stripes`. Pass a length, or var(), env() or a calculation such as `clamp()`.";
52
23
  }
24
+ // isSize takes any number. The thickness is a colour stop's position, which
25
+ // in Chrome 152 kept a percentage and a negative length and dropped a unitless
26
+ // number other than 0 and a unit that is not a length.
27
+ $thickness-problem: lengthProblem($thickness);
28
+ @if $thickness-problem {
29
+ @error "`#{meta.inspect($thickness)}` is not a valid $thickness for `background-stripes`: #{$thickness-problem}. A browser drops the gradient.";
30
+ }
53
31
  @if meta.type-of($rotation) != "number" {
54
32
  @error "`#{$rotation}` is not a valid $rotation for `background-stripes`. Pass an angle such as `-45deg`, or a unitless number which is treated as degrees.";
55
33
  }
56
34
  @if $image != null and meta.type-of($image) != "string" {
57
35
  @error "`#{$image}` is not a valid $image for `background-stripes`. Pass an image path as a string.";
58
36
  }
59
- $validate-unit: if(not list.index("deg", math.unit($rotation)), $rotation + deg, $rotation);
60
- $get-image: if($image, string.unquote(", ") + -image($image), string.unquote(""));
37
+ // A unitless rotation is read as degrees. `deg` used to be added to any unit
38
+ // that was not deg, so a valid `0.25turn` became `0.25turndeg` and `-10px`
39
+ // became `-10pxdeg`, both dropped. Measured in Chrome 152, a gradient kept
40
+ // deg, grad, rad and turn in any case (`10DEG`, `0.25TURN`) and a unitless 0,
41
+ // and dropped a unitless 45, `-10px` and `10%`.
42
+ // Each colour becomes a stripe in a repeating gradient, where a word or a
43
+ // quoted colour drops the whole pattern; see scss/internal/_color-problem.scss.
44
+ @if $color != null {
45
+ @each $item in $color {
46
+ $problem: colorProblem($item);
47
+ @if $problem {
48
+ @error "`#{meta.inspect($item)}` is not a valid colour in $color for `background-stripes`: #{$problem}. Pass one colour or several, such as `red` or `red var(--stripe)`.";
49
+ }
50
+ }
51
+ }
52
+ $validate-unit: $rotation;
53
+ @if math.is-unitless($rotation) {
54
+ $validate-unit: $rotation + deg;
55
+ } @else if not list.index("deg" "grad" "rad" "turn", string.to-lower-case(math.unit($rotation))) {
56
+ @error "`#{meta.inspect($rotation)}` is not a valid $rotation for `background-stripes`: `#{math.unit($rotation)}` is not an angle unit, and a browser drops the gradient. Pass an angle in deg, grad, rad or turn, such as `-45deg`, or a unitless number, which is read as degrees.";
57
+ }
58
+ $get-image: if($image, string.unquote(", ") + imageValue($image, "background-stripes", "$image", $unquote: true), string.unquote(""));
61
59
  @if not $color {
62
60
  $color: rgba(0, 0, 0, 0.1);
63
- background-image: repeating-linear-gradient(
64
- $validate-unit,
65
- $color 0,
66
- $color $thickness,
67
- transparent $thickness,
68
- transparent calc($thickness * 2)
69
- ) + $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;
70
62
  @if $image {
71
63
  background-position: center;
72
64
  background-repeat: no-repeat;
73
65
  background-size: cover;
74
66
  }
75
67
  } @else if list.length($color) == 1 {
76
- background-image: repeating-linear-gradient(
77
- $validate-unit,
78
- $color 0,
79
- $color $thickness,
80
- transparent $thickness,
81
- transparent calc($thickness * 2)
82
- ) + $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;
83
69
  @if $image {
84
70
  background-position: center;
85
71
  background-repeat: no-repeat;
@@ -89,10 +75,10 @@
89
75
  $list: ();
90
76
  @for $i from 1 through list.length($color) {
91
77
  $index-color: list.nth($color, $i);
92
- $style-rule: $index-color calc($thickness * $i - $thickness), $index-color calc($thickness * $i);
93
- $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);
94
80
  }
95
- 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;
96
82
  @if $image {
97
83
  background-position: center;
98
84
  background-repeat: no-repeat;
@@ -1,18 +1,8 @@
1
1
  @charset "UTF-8";
2
2
 
3
- @use "sass:list";
4
3
  @use "sass:meta";
5
4
  @use "sass:string";
6
-
7
- // True for an unquoted call to one of $names, such as var(--x). A quoted string
8
- // stays text, so `"var(--x)"` is not a call.
9
- @function -is-css-function($value, $names) {
10
- @if meta.type-of($value) != "string" or string.slice(meta.inspect($value), 1, 1) == "\"" {
11
- @return false;
12
- }
13
- $open: string.index($value, "(");
14
- @return $open != null and list.index($names, string.to-lower-case(string.slice($value, 1, $open - 1))) != null;
15
- }
5
+ @use "../internal/is-css-function" as *;
16
6
 
17
7
  @mixin before($content: null) {
18
8
  &::before {
@@ -20,7 +10,7 @@
20
10
  @content;
21
11
  } @else if meta.type-of($content) != "string" {
22
12
  @error "`#{$content}` is not a valid $content for `before`. Pass a string to use as the content value, a data- attribute name such as `\"data-label\"` to render it with attr(), or no argument at all and write the content yourself.";
23
- } @else if -is-css-function($content, "var" "attr" "counter" "counters") {
13
+ } @else if isCssFunction($content, "var" "attr" "counter" "counters") {
24
14
  // Quoting would turn the call into text: content: "var(--label)".
25
15
  content: $content;
26
16
  @content;
@@ -1,8 +1,77 @@
1
1
  @charset "UTF-8";
2
2
 
3
3
  @use "sass:list";
4
+ @use "sass:meta";
5
+ @use "sass:string";
4
6
  @use "../lists/list-of-directions" as *;
5
7
  @use "../utilities/fill-nulls" as *;
8
+ @use "../internal/length-problem" as *;
9
+
10
+ // The parts of $text between the separator, empty parts left out.
11
+ @function -split($text, $separator) {
12
+ $parts: ();
13
+ $at: string.index($text, $separator);
14
+ @while $at {
15
+ @if $at > 1 {
16
+ $parts: list.append($parts, string.unquote(string.slice($text, 1, $at - 1)));
17
+ }
18
+ $text: string.slice($text, $at + 1);
19
+ $at: string.index($text, $separator);
20
+ }
21
+ @if string.length($text) > 0 {
22
+ $parts: list.append($parts, string.unquote($text));
23
+ }
24
+ @return $parts;
25
+ }
26
+
27
+ // What is wrong with $value as the radii of one declaration, or null. Measured
28
+ // in Chrome 152: border-radius kept one to four radii, and a slash between two
29
+ // such sets; a corner's own property kept one or two radii and no slash. Both
30
+ // kept a length, 0, a percentage and a CSS-wide keyword alone, and dropped a
31
+ // negative radius, a keyword such as auto, and more radii than that.
32
+ // Interpolation, as in `#{$a}/#{$b}`, gives the same value as a string, so a
33
+ // string is read by its parts. null is a corner left out, as fillNulls has it.
34
+ @function -radii-problem($value, $max, $slash: false) {
35
+ @if $value == null {
36
+ @return null;
37
+ }
38
+ $is-text: meta.type-of($value) == "string" and string.slice(meta.inspect($value), 1, 1) != "\"" and not string.index($value, "(");
39
+ @if ($is-text and string.index($value, "/")) or (meta.type-of($value) == "list" and list.separator($value) == "slash") {
40
+ $sets: $value;
41
+ @if $is-text {
42
+ $sets: -split($value, "/");
43
+ }
44
+ @if not $slash {
45
+ @return "a slash only works in the one-argument form, between two sets of radii";
46
+ }
47
+ @if list.length($sets) != 2 {
48
+ @return "a slash goes between exactly two sets of radii";
49
+ }
50
+ @each $set in $sets {
51
+ $problem: -radii-problem($set, $max);
52
+ @if $problem {
53
+ @return $problem;
54
+ }
55
+ }
56
+ @return null;
57
+ }
58
+ $radii: $value;
59
+ @if $is-text and string.index($value, " ") {
60
+ $radii: -split($value, " ");
61
+ }
62
+ @if list.length($radii) > $max {
63
+ @return "it is #{list.length($radii)} radii where at most #{$max} are meant";
64
+ }
65
+ @each $radius in $radii {
66
+ @if $radius != null {
67
+ $problem: lengthProblem($radius, $negative: false, $css-wide: list.length($radii) == 1);
68
+ @if $problem {
69
+ @return $problem;
70
+ }
71
+ }
72
+ }
73
+ @return null;
74
+ }
6
75
 
7
76
  @mixin border-radius($args...) {
8
77
  // Logical corners are named block side first, inline side second, like the
@@ -12,11 +81,19 @@
12
81
  $list: list.join(list.join($list-of-directions, ("cross-left", "cross-right", "all")), $logical);
13
82
  @if list.length($args) == 1 {
14
83
  $value: list.nth($args, 1);
84
+ $problem: -radii-problem($value, 4, $slash: true);
85
+ @if $problem {
86
+ @error "`#{meta.inspect($value)}` is not a valid radius for `border-radius`: #{$problem}. A browser drops the declaration.";
87
+ }
15
88
  border-radius: fillNulls($value, space);
16
89
  } @else if list.length($args) == 2 {
17
90
  $corner: list.nth($args, 1);
18
91
  $value: list.nth($args, 2);
19
92
  @if list.index($list, $corner) {
93
+ $problem: -radii-problem($value, 2);
94
+ @if $problem {
95
+ @error "`#{meta.inspect($value)}` is not a valid radius for `border-radius`: #{$problem}. A browser drops the declaration.";
96
+ }
20
97
  @if $corner == "top" {
21
98
  border-top-left-radius: $value;
22
99
  border-top-right-radius: $value;
@@ -70,6 +147,12 @@
70
147
  @error "Corner value must be one of the followings: #{$list}.";
71
148
  }
72
149
  } @else if list.length($args) == 4 {
150
+ @each $value in $args {
151
+ $problem: -radii-problem($value, 2);
152
+ @if $problem {
153
+ @error "`#{meta.inspect($value)}` is not a valid radius for `border-radius`: #{$problem}. A browser drops the declaration.";
154
+ }
155
+ }
73
156
  $args: fillNulls($args, space, true);
74
157
  border-top-left-radius: list.nth($args, 1);
75
158
  border-top-right-radius: list.nth($args, 2);
@@ -1,37 +1,23 @@
1
1
  @charset "UTF-8";
2
2
 
3
- @use "sass:list";
4
- @use "sass:meta";
5
- @use "sass:string";
6
-
7
3
  @use "../library/stretched-link" as *;
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
- @function -image($value) {
12
- @if -is-css-function($value, "var" "url" "image-set" "linear-gradient" "radial-gradient" "conic-gradient" "repeating-linear-gradient" "repeating-radial-gradient" "repeating-conic-gradient") {
13
- @return $value;
14
- }
15
- @return url($value);
16
- }
17
-
18
- // True for an unquoted call to one of $names, such as var(--x). A quoted string
19
- // stays text, so `"var(--x)"` is not a call.
20
- @function -is-css-function($value, $names) {
21
- @if meta.type-of($value) != "string" or string.slice(meta.inspect($value), 1, 1) == "\"" {
22
- @return false;
23
- }
24
- $open: string.index($value, "(");
25
- @return $open != null and list.index($names, string.to-lower-case(string.slice($value, 1, $open - 1))) != null;
26
- }
4
+ @use "sass:meta";
5
+ @use "../internal/image-value" as *;
6
+ @use "../internal/length-problem" as *;
27
7
 
28
8
  @mixin brand-logo($width, $height, $image-url: null) {
9
+ @each $name, $value in ("$width": $width, "$height": $height) {
10
+ $problem: sizeProblem($value);
11
+ @if $problem {
12
+ @error "`#{meta.inspect($value)}` is not a valid #{$name} for `brand-logo`: #{$problem}. A browser drops the declaration.";
13
+ }
14
+ }
29
15
  display: inline-block;
30
16
  position: relative;
31
17
  width: $width;
32
18
  height: $height;
33
19
  @if $image-url {
34
- background-image: -image($image-url);
20
+ background-image: imageValue($image-url, "brand-logo", "$image-url");
35
21
  }
36
22
  background-position: center;
37
23
  background-repeat: no-repeat;
@@ -2,42 +2,30 @@
2
2
 
3
3
  @use "sass:list";
4
4
  @use "sass:map";
5
- @use "sass:meta";
6
- @use "sass:string";
7
5
  @use "../maps/map-for-breakpoints" as *;
8
6
  @use "../utilities/validate-breakpoint" as *;
7
+ @use "../internal/custom-property-in" as *;
8
+ @use "../internal/condition-width" as *;
9
9
 
10
- // Returns the first value in $value that holds var(), looking inside lists and
11
- // calculations, or null. Custom properties are not evaluated in a @media or
12
- // @container condition, so a rule built from one never applies, and nothing
13
- // warns. Measured in Chrome 152: `(min-width: var(--wide))` did not match with
14
- // `--wide: 200px`, while `(min-width: 200px)` did.
15
- @function -custom-property-in($value) {
16
- @each $item in $value {
17
- @if meta.type-of($item) == "list" or meta.type-of($item) == "arglist" {
18
- $found: -custom-property-in($item);
19
- @if $found {
20
- @return $found;
21
- }
22
- } @else if string.index(meta.inspect($item), "var(") {
23
- @return $item;
24
- }
25
- }
26
- @return null;
27
- }
28
-
10
+ // Every size goes through conditionWidth before a query is written, so a size no
11
+ // width condition can match raises instead of compiling into one. The queries
12
+ // themselves are written as they always were, and the checks in the branches
13
+ // below are called only for the error they raise, so a call that worked writes
14
+ // the same CSS.
29
15
  @mixin breakpoint($params...) {
30
- $custom-property: -custom-property-in($params);
16
+ $custom-property: customPropertyIn($params);
31
17
  @if $custom-property {
32
18
  @error "`#{$custom-property}` cannot be used in a breakpoint: custom properties are not evaluated in a @media condition, so the rule would never apply. Pass a length or a key from $map-for-breakpoints.";
33
19
  }
34
20
  @if list.length($params) == 1 {
35
21
  $value: list.nth($params, 1);
36
- $width: if(map.has-key($map-for-breakpoints, $value), map.get($map-for-breakpoints, $value), $value);
22
+ // Checked before the warning below, so a size that is wrong outright is
23
+ // refused rather than described as a single pixel.
24
+ $width: conditionWidth($value, "breakpoint");
37
25
  // One argument matches a single pixel, which two agent trials took for
38
- // "from this width up". Still emitted, so no stylesheet changes, but said
39
- // out loud until 3.0.0 refuses it.
40
- @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.";
41
29
  @if map.has-key($map-for-breakpoints, $value) {
42
30
  @media (width: map.get($map-for-breakpoints, $value)) {
43
31
  @content;
@@ -51,12 +39,16 @@
51
39
  @if not list.index("only" "min" "max" "between", list.nth($params, 1)) {
52
40
  $start: list.nth($params, 1);
53
41
  $end: list.nth($params, 2);
42
+ $checked: conditionWidth($start, "breakpoint") conditionWidth($end, "breakpoint");
54
43
  @media (min-width: #{validateBreakpoint($start)}) and (max-width: #{if(map.has-key($map-for-breakpoints, $end), validateBreakpoint($end) - 1, $end)}) {
55
44
  @content;
56
45
  }
57
46
  } @else {
58
47
  $mode: list.nth($params, 1);
59
48
  $value: list.nth($params, 2);
49
+ @if $mode != "between" {
50
+ $checked: conditionWidth($value, "breakpoint");
51
+ }
60
52
  @if $mode == "only" {
61
53
  @if map.has-key($map-for-breakpoints, $value) {
62
54
  @media (width: map.get($map-for-breakpoints, $value)) {
@@ -90,6 +82,7 @@
90
82
  } @else if $mode == "between" {
91
83
  $start: list.nth($value, 1);
92
84
  $end: list.nth($value, 2);
85
+ $checked: conditionWidth($start, "breakpoint") conditionWidth($end, "breakpoint");
93
86
  @media (min-width: #{validateBreakpoint($start)}) and (max-width: #{if(map.has-key($map-for-breakpoints, $end), validateBreakpoint($end) - 1, $end)}) {
94
87
  @content;
95
88
  }