gerillass 2.0.1 → 2.1.1
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 +23 -0
- package/SKILL.md +50 -5
- package/gerillass.json +304 -55
- package/package.json +1 -1
- package/scss/library/_after.scss +15 -0
- package/scss/library/_background-dots.scss +55 -9
- package/scss/library/_background-image.scss +31 -5
- package/scss/library/_background-stripes.scss +43 -4
- package/scss/library/_before.scss +15 -0
- package/scss/library/_brand-logo.scss +24 -1
- package/scss/library/_breakpoint.scss +29 -0
- package/scss/library/_container-query.scss +86 -0
- package/scss/library/_container.scss +26 -0
- package/scss/library/_counter.scss +24 -2
- package/scss/library/_font-face.scss +14 -0
- package/scss/library/_index.scss +3 -0
- package/scss/library/_line-clamp.scss +49 -0
- package/scss/library/_loadify.scss +18 -0
- package/scss/library/_reset-css.scss +7 -5
- package/scss/library/_screen-agent.scss +27 -0
- package/scss/library/_text-image.scss +24 -1
- package/scss/library/_triangle.scss +69 -7
- package/scss/utilities/_clear-unit.scss +4 -0
- package/scss/utilities/_convert-to-em.scss +6 -0
- package/scss/utilities/_convert-to-number.scss +15 -0
- package/scss/utilities/_fluid.scss +76 -0
- package/scss/utilities/_font-sizer.scss +14 -0
- package/scss/utilities/_index.scss +1 -0
- package/scss/utilities/_remify.scss +7 -0
- package/scss/utilities/_validate-length.scss +7 -0
- package/scss/utilities/_validate-ratio.scss +25 -2
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
@charset "UTF-8";
|
|
2
|
+
|
|
3
|
+
@use "sass:list";
|
|
4
|
+
@use "sass:math";
|
|
5
|
+
@use "sass:meta";
|
|
6
|
+
@use "sass:string";
|
|
7
|
+
|
|
8
|
+
// True for an unquoted call to one of $names, such as var(--x). A quoted string
|
|
9
|
+
// stays text, so `"var(--x)"` is not a call.
|
|
10
|
+
@function -is-css-function($value, $names) {
|
|
11
|
+
@if meta.type-of($value) != "string" or string.slice(meta.inspect($value), 1, 1) == "\"" {
|
|
12
|
+
@return false;
|
|
13
|
+
}
|
|
14
|
+
$open: string.index($value, "(");
|
|
15
|
+
@return $open != null and list.index($names, string.to-lower-case(string.slice($value, 1, $open - 1))) != null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Truncates text after a number of lines. `ellipsis` does one line; this does
|
|
19
|
+
// several, and needs five declarations rather than one because -webkit-line-clamp
|
|
20
|
+
// only works alongside two other properties.
|
|
21
|
+
//
|
|
22
|
+
// All five were measured in a browser, on a paragraph that runs to five lines
|
|
23
|
+
// with a clamp of three:
|
|
24
|
+
//
|
|
25
|
+
// the three together 3 lines, with an ellipsis
|
|
26
|
+
// without -webkit-box-orient 5 lines, no clamping and no warning
|
|
27
|
+
// without display: -webkit-box 5 lines, likewise
|
|
28
|
+
// the standard line-clamp alone 5 lines; it is not Baseline yet
|
|
29
|
+
// without overflow: hidden the box is 3 lines, but the rest of the text
|
|
30
|
+
// spills out below it
|
|
31
|
+
//
|
|
32
|
+
// So the standard property is emitted for the future and the prefixed trio is
|
|
33
|
+
// what actually does the work today.
|
|
34
|
+
@mixin line-clamp($lines: 3) {
|
|
35
|
+
// var() is resolved by the browser, so only a literal count is checked.
|
|
36
|
+
@if $lines != none and not -is-css-function($lines, "var" "env") {
|
|
37
|
+
@if meta.type-of($lines) != "number" or not math.is-unitless($lines) {
|
|
38
|
+
@error "`#{$lines}` is not a valid $lines for `line-clamp`. Pass a whole number of lines, or `none` to undo a clamp.";
|
|
39
|
+
}
|
|
40
|
+
@if $lines < 1 or $lines != math.round($lines) {
|
|
41
|
+
@error "`#{$lines}` is not a valid $lines for `line-clamp`. Pass a whole number of lines that is at least 1, or `none` to undo a clamp.";
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
display: -webkit-box;
|
|
45
|
+
-webkit-box-orient: vertical;
|
|
46
|
+
-webkit-line-clamp: $lines;
|
|
47
|
+
line-clamp: $lines;
|
|
48
|
+
overflow: hidden;
|
|
49
|
+
}
|
|
@@ -4,6 +4,13 @@
|
|
|
4
4
|
@use "sass:meta";
|
|
5
5
|
@use "../utilities/is-time" as *;
|
|
6
6
|
|
|
7
|
+
// `init` defines the %loadify placeholder, and every call extends it. Under the
|
|
8
|
+
// module system a selector can only extend a placeholder from a module it
|
|
9
|
+
// loads, so the file with the call must be the file that calls `init`, or must
|
|
10
|
+
// `@use` it. Anything else fails with "The target selector was not found".
|
|
11
|
+
// An entry file calling `init` does not help a partial it loads, since the
|
|
12
|
+
// partial does not load the entry file. Stylesheets using @import share one
|
|
13
|
+
// scope and are unaffected.
|
|
7
14
|
@mixin loadify($params...) {
|
|
8
15
|
@if not & {
|
|
9
16
|
@if list.length($params) == 0 or (list.length($params) == 1 and list.nth($params, 1) == "init") {
|
|
@@ -20,6 +27,17 @@
|
|
|
20
27
|
backface-visibility: hidden;
|
|
21
28
|
animation-name: loadify;
|
|
22
29
|
animation-fill-mode: forwards;
|
|
30
|
+
|
|
31
|
+
// The element starts invisible and the animation is what reveals it,
|
|
32
|
+
// so switching the animation off is not enough on its own: it would
|
|
33
|
+
// leave the content hidden for good. Under reduced motion the end
|
|
34
|
+
// state is applied directly instead, and nothing moves.
|
|
35
|
+
@media (prefers-reduced-motion: reduce) {
|
|
36
|
+
opacity: 1;
|
|
37
|
+
visibility: visible;
|
|
38
|
+
backface-visibility: visible;
|
|
39
|
+
animation: none;
|
|
40
|
+
}
|
|
23
41
|
}
|
|
24
42
|
} @else if (list.length($params) == 1 and list.nth($params, 1) != "init") or (list.length($params) == 1 and meta.type-of(list.nth($params, 1)) != "string") {
|
|
25
43
|
@error "#{list.nth($params, 1)} is not a valid argument. Please pass `init` as an argument to initialize the effect or do not pass any argument at all.";
|
|
@@ -4,10 +4,12 @@
|
|
|
4
4
|
@if & {
|
|
5
5
|
@error "Please call the mixin at the root of your style sheet.";
|
|
6
6
|
} @else {
|
|
7
|
-
|
|
8
|
-
v2.0 | 20110126
|
|
9
|
-
License: none (public domain)
|
|
10
|
-
|
|
7
|
+
// http://meyerweb.com/eric/tools/css/reset/
|
|
8
|
+
// v2.0 | 20110126
|
|
9
|
+
// License: none (public domain)
|
|
10
|
+
//
|
|
11
|
+
// Comments in this file are `//`: a /* */ comment inside a mixin is emitted
|
|
12
|
+
// into the stylesheet of everyone who includes it.
|
|
11
13
|
html, body, div, span, applet, object, iframe,
|
|
12
14
|
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
|
13
15
|
a, abbr, acronym, address, big, cite, code,
|
|
@@ -28,7 +30,7 @@
|
|
|
28
30
|
font: inherit;
|
|
29
31
|
vertical-align: baseline;
|
|
30
32
|
}
|
|
31
|
-
|
|
33
|
+
// HTML5 display-role reset for older browsers
|
|
32
34
|
article, aside, details, figcaption, figure,
|
|
33
35
|
footer, header, hgroup, menu, main, nav, section {
|
|
34
36
|
display: block;
|
|
@@ -1,6 +1,33 @@
|
|
|
1
1
|
@charset "UTF-8";
|
|
2
2
|
|
|
3
|
+
@use "sass:list";
|
|
4
|
+
@use "sass:meta";
|
|
5
|
+
@use "sass:string";
|
|
6
|
+
|
|
7
|
+
// Returns the first value in $value that holds var(), looking inside lists and
|
|
8
|
+
// calculations, or null. Custom properties are not evaluated in a @media or
|
|
9
|
+
// @container condition, so a rule built from one never applies, and nothing
|
|
10
|
+
// warns. Measured in Chrome 152: `(min-width: var(--wide))` did not match with
|
|
11
|
+
// `--wide: 200px`, while `(min-width: 200px)` did.
|
|
12
|
+
@function -custom-property-in($value) {
|
|
13
|
+
@each $item in $value {
|
|
14
|
+
@if meta.type-of($item) == "list" or meta.type-of($item) == "arglist" {
|
|
15
|
+
$found: -custom-property-in($item);
|
|
16
|
+
@if $found {
|
|
17
|
+
@return $found;
|
|
18
|
+
}
|
|
19
|
+
} @else if string.index(meta.inspect($item), "var(") {
|
|
20
|
+
@return $item;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
@return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
3
26
|
@mixin screen-agent($resolution) {
|
|
27
|
+
$custom-property: -custom-property-in($resolution);
|
|
28
|
+
@if $custom-property {
|
|
29
|
+
@error "`#{$custom-property}` cannot be used as a resolution: custom properties are not evaluated in a @media condition, so the rule would never apply. Pass `1x`, `2x`, `3x` or a resolution such as `2dppx`.";
|
|
30
|
+
}
|
|
4
31
|
@if $resolution == "1x" {
|
|
5
32
|
@media (min-resolution: 96dpi) {
|
|
6
33
|
@content;
|
|
@@ -1,8 +1,31 @@
|
|
|
1
1
|
@charset "UTF-8";
|
|
2
2
|
|
|
3
|
+
@use "sass:list";
|
|
4
|
+
@use "sass:meta";
|
|
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($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
|
+
|
|
3
26
|
@mixin text-image($image: null) {
|
|
4
27
|
@if $image {
|
|
5
|
-
background-image:
|
|
28
|
+
background-image: -image($image);
|
|
6
29
|
}
|
|
7
30
|
background-size: cover;
|
|
8
31
|
background-position: center;
|
|
@@ -1,13 +1,75 @@
|
|
|
1
1
|
@charset "UTF-8";
|
|
2
2
|
|
|
3
3
|
@use "sass:list";
|
|
4
|
-
@use "sass:
|
|
4
|
+
@use "sass:meta";
|
|
5
|
+
@use "sass:string";
|
|
5
6
|
@use "../lists/list-of-directions" as *;
|
|
6
|
-
|
|
7
|
+
|
|
8
|
+
// A size Sass can use inside calc(): a number, a calculation such as calc(),
|
|
9
|
+
// min() or clamp(), or var() and env(), which only the browser can resolve.
|
|
10
|
+
// Anything else would pass silently through calc(): `calc(nonsense * 5)`
|
|
11
|
+
// compiles.
|
|
12
|
+
@function -is-size($value) {
|
|
13
|
+
@if meta.type-of($value) == "number" or meta.type-of($value) == "calculation" {
|
|
14
|
+
@return true;
|
|
15
|
+
}
|
|
16
|
+
@if meta.type-of($value) == "string" and string.slice(meta.inspect($value), 1, 1) != "\"" {
|
|
17
|
+
$open: string.index($value, "(");
|
|
18
|
+
@return $open != null and list.index("var" "env", string.to-lower-case(string.slice($value, 1, $open - 1))) != null;
|
|
19
|
+
}
|
|
20
|
+
@return false;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// A value CSS will take as a colour: a Sass colour, currentColor, or a function
|
|
24
|
+
// that returns a colour when the browser resolves it. A list passes when every
|
|
25
|
+
// item does, as it did through isColor.
|
|
26
|
+
//
|
|
27
|
+
// inherit, initial, unset and revert are left out on purpose. The mixin writes
|
|
28
|
+
// the colour into a border-color shorthand beside `transparent`, and a CSS-wide
|
|
29
|
+
// keyword is only valid as the whole value: `transparent transparent inherit`
|
|
30
|
+
// is rejected by the browser. Checked with CSS.supports in Chrome 152.
|
|
31
|
+
//
|
|
32
|
+
// Deliberately looser than isColor, which stays strict because tint and shade
|
|
33
|
+
// pass its result to color.mix, and that needs a real Sass colour. A border
|
|
34
|
+
// colour does not. The functions are named rather than "anything with a
|
|
35
|
+
// parenthesis", which would let url() through as a colour.
|
|
36
|
+
@function -is-css-color($value) {
|
|
37
|
+
@if list.length($value) > 1 {
|
|
38
|
+
@each $item in $value {
|
|
39
|
+
@if not -is-css-color($item) {
|
|
40
|
+
@return false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
@return true;
|
|
44
|
+
}
|
|
45
|
+
@if meta.type-of($value) == "color" {
|
|
46
|
+
@return true;
|
|
47
|
+
}
|
|
48
|
+
@if meta.type-of($value) == "string" and string.slice(meta.inspect($value), 1, 1) != "\"" {
|
|
49
|
+
$text: string.to-lower-case($value);
|
|
50
|
+
@if $text == "currentcolor" {
|
|
51
|
+
@return true;
|
|
52
|
+
}
|
|
53
|
+
$open: string.index($text, "(");
|
|
54
|
+
@if $open and list.index("var" "color-mix" "light-dark" "env", string.slice($text, 1, $open - 1)) {
|
|
55
|
+
@return true;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
@return false;
|
|
59
|
+
}
|
|
7
60
|
|
|
8
61
|
@mixin triangle($direction: "bottom", $color: black, $size: 10px 8px) {
|
|
9
62
|
@if list.index($list-of-directions, $direction) {
|
|
10
|
-
|
|
63
|
+
// Halving a size in calc() rather than math.div() keeps var() and clamp()
|
|
64
|
+
// working instead of emitting `var(--w)/2`, which is not valid CSS.
|
|
65
|
+
@each $item in $size {
|
|
66
|
+
@if not -is-size($item) {
|
|
67
|
+
@error "`#{meta.inspect($size)}` is not a valid $size for `triangle`. Pass one or two lengths, or var(), env() or a calculation in place of either.";
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
@if not -is-css-color($color) {
|
|
71
|
+
@error "`#{meta.inspect($color)}` is not a valid $color for `triangle`. Pass a colour, `currentColor`, or a CSS function such as `var(--accent)`, `color-mix(...)` or `light-dark(...)`.";
|
|
72
|
+
} @else {
|
|
11
73
|
content: "";
|
|
12
74
|
height: 0;
|
|
13
75
|
width: 0;
|
|
@@ -15,25 +77,25 @@
|
|
|
15
77
|
border-style: solid;
|
|
16
78
|
@if $direction == "top"{
|
|
17
79
|
border-color: transparent transparent $color;
|
|
18
|
-
border-width: 0
|
|
80
|
+
border-width: 0 calc(list.nth($size, 1) / 2) if(list.length($size) == 2, list.nth($size, 2), list.nth($size, 1));
|
|
19
81
|
} @else if $direction == "top-right" {
|
|
20
82
|
border-color: transparent $color transparent transparent;
|
|
21
83
|
border-width: 0 list.nth($size, 1) list.nth($size, 1) 0;
|
|
22
84
|
} @else if $direction == "right" {
|
|
23
85
|
border-color: transparent transparent transparent $color;
|
|
24
|
-
border-width:
|
|
86
|
+
border-width: calc(if(list.length($size) == 2, list.nth($size, 2), list.nth($size, 1)) / 2) 0 calc(if(list.length($size) == 2, list.nth($size, 2), list.nth($size, 1)) / 2) list.nth($size, 1);
|
|
25
87
|
} @else if $direction == "bottom-right" {
|
|
26
88
|
border-color: transparent transparent $color;
|
|
27
89
|
border-width: 0 0 list.nth($size, 1) list.nth($size, 1);
|
|
28
90
|
} @else if $direction == "bottom" {
|
|
29
91
|
border-color: $color transparent transparent;
|
|
30
|
-
border-width: if(list.length($size) == 2, list.nth($size, 2), list.nth($size, 1))
|
|
92
|
+
border-width: if(list.length($size) == 2, list.nth($size, 2), list.nth($size, 1)) calc(list.nth($size, 1) / 2) 0;
|
|
31
93
|
} @else if $direction == "bottom-left" {
|
|
32
94
|
border-color: transparent transparent transparent $color;
|
|
33
95
|
border-width: list.nth($size, 1) 0 0 list.nth($size, 1);
|
|
34
96
|
} @else if $direction == "left" {
|
|
35
97
|
border-color: transparent $color transparent transparent;
|
|
36
|
-
border-width:
|
|
98
|
+
border-width: calc(if(list.length($size) == 2, list.nth($size, 2), list.nth($size, 1)) / 2) list.nth($size, 1) calc(if(list.length($size) == 2, list.nth($size, 2), list.nth($size, 1)) / 2) 0;
|
|
37
99
|
} @else if $direction == "top-left" {
|
|
38
100
|
border-color: $color transparent transparent;
|
|
39
101
|
border-width: list.nth($size, 1) list.nth($size, 1) 0 0;
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
@charset "UTF-8";
|
|
2
2
|
|
|
3
3
|
@use "sass:math";
|
|
4
|
+
@use "sass:meta";
|
|
4
5
|
|
|
5
6
|
@function clearUnit($value) {
|
|
7
|
+
@if meta.type-of($value) != "number" {
|
|
8
|
+
@error "`#{meta.inspect($value)}` is not a valid $value for `clearUnit`. Pass a number, such as `24px`.";
|
|
9
|
+
}
|
|
6
10
|
@return math.div($value, ($value * 0 + 1));
|
|
7
11
|
}
|
|
@@ -2,8 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
@use "sass:string";
|
|
4
4
|
@use "sass:math";
|
|
5
|
+
@use "sass:meta";
|
|
5
6
|
|
|
6
7
|
@function convertToEm($value) {
|
|
8
|
+
// Only a pixel length converts cleanly. A unitless number or another unit
|
|
9
|
+
// compiled to `calc(1.5 / 1px)em`, and a word or var() to `var(--x)/16pxem`.
|
|
10
|
+
@if meta.type-of($value) != "number" or math.unit($value) != "px" {
|
|
11
|
+
@error "`#{meta.inspect($value)}` is not a valid $value for `convertToEm`. Pass a pixel length, such as `24px`.";
|
|
12
|
+
}
|
|
7
13
|
$base-value: 16px;
|
|
8
14
|
$rem-value: math.div($value, $base-value);
|
|
9
15
|
@return $rem-value + string.unquote("em");
|
|
@@ -11,6 +11,21 @@
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
$string-numerals: "0" "1" "2" "3" "4" "5" "6" "7" "8" "9";
|
|
14
|
+
|
|
15
|
+
// Every character has to be a digit before the parse runs. Otherwise an
|
|
16
|
+
// empty string or a sign failed with Sass's own "Undefined operation", and a
|
|
17
|
+
// letter or a space was folded into nonsense such as `40-1`. The empty case
|
|
18
|
+
// is checked first because `@for $i from 1 through 0` counts down, not zero
|
|
19
|
+
// times.
|
|
20
|
+
@if string.length($value) == 0 {
|
|
21
|
+
@error "`\"\"` is not a valid $value for `convertToNumber`. Pass a string made only of digits, such as `\"42\"`.";
|
|
22
|
+
}
|
|
23
|
+
@for $i from 1 through string.length($value) {
|
|
24
|
+
@if not list.index($string-numerals, string.slice($value, $i, $i)) {
|
|
25
|
+
@error "`#{meta.inspect($value)}` is not a valid $value for `convertToNumber`. Pass a string made only of digits, such as `\"42\"`.";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
14
29
|
$calc: 0;
|
|
15
30
|
|
|
16
31
|
@for $i from 1 through string.length($value) {
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
@charset "UTF-8";
|
|
2
|
+
|
|
3
|
+
@use "sass:list";
|
|
4
|
+
@use "sass:math";
|
|
5
|
+
@use "sass:meta";
|
|
6
|
+
@use "sass:string";
|
|
7
|
+
@use "../utilities/clear-unit" as *;
|
|
8
|
+
@use "../utilities/remify" as *;
|
|
9
|
+
|
|
10
|
+
// A value that grows with the viewport between two widths, then stops.
|
|
11
|
+
//
|
|
12
|
+
// clamp() takes a floor, a preferred value and a ceiling. The preferred value
|
|
13
|
+
// is the straight line through (min-viewport, min) and (max-viewport, max):
|
|
14
|
+
//
|
|
15
|
+
// slope = (max - min) / (max-viewport - min-viewport)
|
|
16
|
+
// intercept = min - slope * min-viewport
|
|
17
|
+
// preferred = intercept + slope * 100vw
|
|
18
|
+
//
|
|
19
|
+
// The intercept is emitted in rem rather than px deliberately. A preferred
|
|
20
|
+
// value made only of vw ignores browser zoom, which fails WCAG 1.4.4, and
|
|
21
|
+
// keeping a rem term in the sum is what restores it. This is the part that is
|
|
22
|
+
// easy to get wrong by hand, and the reason this is a function rather than a
|
|
23
|
+
// mixin: the value is the hard part, and it belongs to any property, not just
|
|
24
|
+
// font-size.
|
|
25
|
+
//
|
|
26
|
+
// Sass cannot add rem to vw, so the sum is assembled as a string. CSS evaluates
|
|
27
|
+
// it; Sass only writes it.
|
|
28
|
+
|
|
29
|
+
$_fluid-root-size: 16px;
|
|
30
|
+
|
|
31
|
+
@function fluid($min, $max, $min-viewport: 320px, $max-viewport: 1280px) {
|
|
32
|
+
// Pairs rather than a map: two arguments can legitimately hold the same
|
|
33
|
+
// length, and a map would reject that as a duplicate key.
|
|
34
|
+
$given: (($min, "$min"), ($max, "$max"), ($min-viewport, "$min-viewport"), ($max-viewport, "$max-viewport"));
|
|
35
|
+
@each $pair in $given {
|
|
36
|
+
$value: list.nth($pair, 1);
|
|
37
|
+
$label: list.nth($pair, 2);
|
|
38
|
+
@if meta.type-of($value) != "number" or math.is-unitless($value) {
|
|
39
|
+
@error "`#{$value}` is not a valid #{$label} for `fluid`. Pass a length in px or rem.";
|
|
40
|
+
}
|
|
41
|
+
@if math.unit($value) != "px" and math.unit($value) != "rem" {
|
|
42
|
+
@error "`#{$value}` is not a valid #{$label} for `fluid`. Pass a length in px or rem, not #{math.unit($value)}.";
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Everything is compared in px, because Sass cannot convert rem to px on its
|
|
47
|
+
// own: it has no way to know the root font size, so the assumption is stated
|
|
48
|
+
// here rather than hidden.
|
|
49
|
+
$min-px: $min;
|
|
50
|
+
$max-px: $max;
|
|
51
|
+
$from-px: $min-viewport;
|
|
52
|
+
$to-px: $max-viewport;
|
|
53
|
+
@if math.unit($min) == "rem" { $min-px: clearUnit($min) * $_fluid-root-size; }
|
|
54
|
+
@if math.unit($max) == "rem" { $max-px: clearUnit($max) * $_fluid-root-size; }
|
|
55
|
+
@if math.unit($min-viewport) == "rem" { $from-px: clearUnit($min-viewport) * $_fluid-root-size; }
|
|
56
|
+
@if math.unit($max-viewport) == "rem" { $to-px: clearUnit($max-viewport) * $_fluid-root-size; }
|
|
57
|
+
|
|
58
|
+
@if $from-px >= $to-px {
|
|
59
|
+
@error "`fluid` needs $min-viewport to be smaller than $max-viewport, and was given #{$min-viewport} and #{$max-viewport}.";
|
|
60
|
+
}
|
|
61
|
+
@if $min-px > $max-px {
|
|
62
|
+
@error "`fluid` needs $min to be no larger than $max, and was given #{$min} and #{$max}. clamp() would return the floor at every width, so the value would never grow.";
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
$slope: math.div($max-px - $min-px, $to-px - $from-px);
|
|
66
|
+
$intercept: $min-px - $slope * $from-px;
|
|
67
|
+
|
|
68
|
+
// Four decimals is past the point any browser renders differently, and keeps
|
|
69
|
+
// the output readable.
|
|
70
|
+
$vw: math.div(math.round($slope * 100 * 10000), 10000);
|
|
71
|
+
$floor: math.div(math.round(clearUnit(remify($min-px)) * 10000), 10000);
|
|
72
|
+
$base: math.div(math.round(clearUnit(remify($intercept)) * 10000), 10000);
|
|
73
|
+
$ceiling: math.div(math.round(clearUnit(remify($max-px)) * 10000), 10000);
|
|
74
|
+
|
|
75
|
+
@return string.unquote("clamp(#{$floor}rem, #{$base}rem + #{$vw}vw, #{$ceiling}rem)");
|
|
76
|
+
}
|
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
@charset "UTF-8";
|
|
2
2
|
|
|
3
|
+
@use "sass:math";
|
|
4
|
+
@use "sass:meta";
|
|
5
|
+
|
|
3
6
|
@function fontSizer($size, $time) {
|
|
7
|
+
@if meta.type-of($size) != "number" {
|
|
8
|
+
@error "`#{meta.inspect($size)}` is not a valid $size for `fontSizer`. Pass a length, such as `16px`.";
|
|
9
|
+
}
|
|
10
|
+
@if meta.type-of($time) != "number" {
|
|
11
|
+
@error "`#{meta.inspect($time)}` is not a valid $time for `fontSizer`. Pass a multiplier, such as `1.5`.";
|
|
12
|
+
}
|
|
13
|
+
// Two units multiply into a unit squared, which Sass writes as
|
|
14
|
+
// `calc(16px * 1px)`: not a length anywhere in CSS.
|
|
15
|
+
@if not math.is-unitless($size) and not math.is-unitless($time) {
|
|
16
|
+
@error "`fontSizer(#{$size}, #{$time})` multiplies two units, which is not a length. Pass the multiplier without a unit, such as `1.5`.";
|
|
17
|
+
}
|
|
4
18
|
@return $size * $time;
|
|
5
19
|
}
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
@charset "UTF-8";
|
|
2
2
|
|
|
3
3
|
@use "sass:math";
|
|
4
|
+
@use "sass:meta";
|
|
4
5
|
|
|
5
6
|
@function remify($value) {
|
|
7
|
+
// Only a pixel length converts cleanly. Anything else used to reach the
|
|
8
|
+
// arithmetic unchecked: a word failed with Sass's own "Undefined operation",
|
|
9
|
+
// and a unitless number or another unit compiled to `calc(1.5rem / 1px)`.
|
|
10
|
+
@if meta.type-of($value) != "number" or math.unit($value) != "px" {
|
|
11
|
+
@error "`#{meta.inspect($value)}` is not a valid $value for `remify`. Pass a pixel length, such as `24px`.";
|
|
12
|
+
}
|
|
6
13
|
$base-value: 16px;
|
|
7
14
|
$rem-value: math.div($value, $base-value);
|
|
8
15
|
@return $rem-value * 1rem;
|
|
@@ -6,6 +6,13 @@
|
|
|
6
6
|
@use "sass:string";
|
|
7
7
|
|
|
8
8
|
@function validateLength($value) {
|
|
9
|
+
// null means "leave this out": `position` skips an edge given null, as its
|
|
10
|
+
// documentation shows. It is not a mistake to warn about, and the warning
|
|
11
|
+
// printed empty backticks, because null interpolates to nothing.
|
|
12
|
+
@if $value == null {
|
|
13
|
+
@return null;
|
|
14
|
+
}
|
|
15
|
+
|
|
9
16
|
$keywords: ("auto", "inherit", "initial", "unset", "revert", 0);
|
|
10
17
|
|
|
11
18
|
@if list.index($keywords, $value) {
|
|
@@ -28,6 +28,13 @@
|
|
|
28
28
|
@return $ratio;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
// var() is resolved by the browser. Checked inline rather than through a
|
|
32
|
+
// helper function, which tools/build-manifest.js would take for this file's
|
|
33
|
+
// member in place of validateRatio.
|
|
34
|
+
@if meta.type-of($ratio) == "string" and string.slice(meta.inspect($ratio), 1, 1) != "\"" and string.index(string.to-lower-case($ratio), "var(") == 1 {
|
|
35
|
+
@return $ratio;
|
|
36
|
+
}
|
|
37
|
+
|
|
31
38
|
@if meta.type-of($ratio) == "string" {
|
|
32
39
|
$separator: null;
|
|
33
40
|
@if string.index($ratio, "/") {
|
|
@@ -38,8 +45,24 @@
|
|
|
38
45
|
@error "`#{$ratio}` is not a valid ratio. A string ratio must separate width and height with `/` or `:`, like `\"16/9\"` or `\"16:9\"`.";
|
|
39
46
|
}
|
|
40
47
|
|
|
41
|
-
$width:
|
|
42
|
-
$height:
|
|
48
|
+
$width-text: string.slice($ratio, 1, $separator - 1);
|
|
49
|
+
$height-text: string.slice($ratio, $separator + 1);
|
|
50
|
+
|
|
51
|
+
// Checked here so a malformed ratio is reported as a ratio, rather than as
|
|
52
|
+
// a bad argument to convertToNumber, which the caller never called.
|
|
53
|
+
@each $part in ($width-text, $height-text) {
|
|
54
|
+
@if string.length($part) == 0 {
|
|
55
|
+
@error "`#{$ratio}` is not a valid ratio. Width and height must both be whole numbers, like `\"16/9\"` or `\"16:9\"`.";
|
|
56
|
+
}
|
|
57
|
+
@for $i from 1 through string.length($part) {
|
|
58
|
+
@if not list.index("0" "1" "2" "3" "4" "5" "6" "7" "8" "9", string.slice($part, $i, $i)) {
|
|
59
|
+
@error "`#{$ratio}` is not a valid ratio. Width and height must both be whole numbers, like `\"16/9\"` or `\"16:9\"`.";
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
$width: convertToNumber($width-text);
|
|
65
|
+
$height: convertToNumber($height-text);
|
|
43
66
|
|
|
44
67
|
@if $width == 0 {
|
|
45
68
|
@error "`#{$ratio}` is not a valid ratio. The width must be greater than zero.";
|