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/gerillass.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gerillass",
3
- "version": "2.0.1",
3
+ "version": "2.1.1",
4
4
  "description": "Gerillass is an open-source toolkit that contains a set of Sass mixins to help designers and developers to create better, faster and consistent user interfaces.",
5
5
  "homepage": "https://gerillass.com",
6
6
  "documentation": "https://docs.gerillass.com",
@@ -42,17 +42,23 @@
42
42
  "accepts": [
43
43
  "a string used as the content value",
44
44
  "a data- attribute name, rendered as attr()",
45
- "null to write content yourself"
45
+ "null to write content yourself",
46
+ "var(), attr(), counter() or counters(), written as they are"
46
47
  ]
47
48
  }
48
49
  ],
49
50
  "file": "scss/library/_after.scss",
50
51
  "signature": "after($content: null)",
51
52
  "summary": "Styles the ::after pseudo-element. A `data-` argument becomes an attr() content value.",
53
+ "caveats": [
54
+ "With no argument no `content` is emitted, so the pseudo-element does not render unless the block sets `content`. Pass `\"\"` for an empty one."
55
+ ],
52
56
  "examples": [
53
57
  ".a { @include after(\"→\") { color: red; } }",
54
58
  ".a { @include after(\"data-label\") { color: red; } }",
55
- ".a { @include after { content: \"x\"; } }"
59
+ ".a { @include after { content: \"x\"; } }",
60
+ ".a { @include after(var(--label)) { color: red; } }",
61
+ ".a { @include after(attr(data-label)) { color: red; } }"
56
62
  ],
57
63
  "rejects": [
58
64
  ".a { @include after(42) { color: red; } }",
@@ -151,7 +157,8 @@
151
157
  "a slash separated string, such as \"16/9\"",
152
158
  "a colon separated string, such as \"16:9\"",
153
159
  "a number, where 1.5 means 1.5 / 1",
154
- "null for the 16/9 default"
160
+ "null for the 16/9 default",
161
+ "var(), written as it is"
155
162
  ]
156
163
  },
157
164
  {
@@ -170,17 +177,22 @@
170
177
  "file": "scss/library/_aspect-ratio.scss",
171
178
  "signature": "aspect-ratio($ratio: null, $fit: cover)",
172
179
  "summary": "Holds an element to a ratio and adds what CSS aspect-ratio alone leaves out: object-fit so an image is cropped rather than stretched, and border: 0 so an iframe does not overflow its container by 4px. Apply it to the element itself, not to a wrapper.",
180
+ "caveats": [
181
+ "On an element with a `height` attribute, such as `<img width=\"1600\" height=\"900\">` or an embed code's `<iframe>`, the attribute height wins and the ratio is ignored. Write `height: auto` after the include."
182
+ ],
173
183
  "examples": [
174
184
  ".thumb { @include aspect-ratio(\"16:9\"); }",
175
185
  ".video { @include aspect-ratio(\"16/9\"); }",
176
186
  ".tile { @include aspect-ratio(\"1:1\", contain); }",
177
187
  ".plain { @include aspect-ratio(1.5, null); }",
178
- ".default { @include aspect-ratio; }"
188
+ ".default { @include aspect-ratio; }",
189
+ ".a { @include aspect-ratio(var(--ratio)); }"
179
190
  ],
180
191
  "rejects": [
181
192
  ".thumb { @include aspect-ratio(\"16:9\", nonsense); }",
182
193
  ".thumb { @include aspect-ratio(16 9); }",
183
- ".thumb { @include aspect-ratio(\"sixteen/nine\"); }"
194
+ ".thumb { @include aspect-ratio(\"sixteen/nine\"); }",
195
+ ".a { @include aspect-ratio(url(a.png)); }"
184
196
  ]
185
197
  },
186
198
  {
@@ -199,14 +211,15 @@
199
211
  "name": "$size",
200
212
  "default": "1em",
201
213
  "accepts": [
202
- "dot radius"
214
+ "dot radius: a length, or var(), env() or a calculation such as calc() or clamp()"
203
215
  ]
204
216
  },
205
217
  {
206
218
  "name": "$gutter",
207
- "default": "$size * 5",
219
+ "default": "null",
208
220
  "accepts": [
209
- "spacing between dots"
221
+ "spacing between dots, in the same forms as $size",
222
+ "null, the default, for five times $size"
210
223
  ]
211
224
  },
212
225
  {
@@ -221,21 +234,27 @@
221
234
  "name": "$image",
222
235
  "default": "null",
223
236
  "accepts": [
224
- "an image path to sit behind the dots"
237
+ "an image path to sit behind the dots",
238
+ "var(), url(), image-set() or a gradient, written as they are rather than wrapped in url()"
225
239
  ]
226
240
  }
227
241
  ],
228
242
  "file": "scss/library/_background-dots.scss",
229
- "signature": "background-dots($color: null, $size: 1em, $gutter: $size * 5, $diagonal: true, $image: null)",
243
+ "signature": "background-dots($color: null, $size: 1em, $gutter: null, $diagonal: true, $image: null)",
230
244
  "summary": "Repeating dot pattern as a background, optionally over an image.",
231
245
  "examples": [
232
246
  ".a { @include background-dots; }",
233
247
  ".a { @include background-dots(red); }",
234
- ".a { @include background-dots(red, 1em, 5em, false); }"
248
+ ".a { @include background-dots(red, 1em, 5em, false); }",
249
+ ".a { @include background-dots(red, var(--dot), calc(var(--dot) * 6)); }",
250
+ ".a { @include background-dots(red, clamp(2px, 0.5vw, 6px)); }",
251
+ ".a { @include background-dots(red, $image: var(--photo)); }"
235
252
  ],
236
253
  "rejects": [
237
254
  ".a { @include background-dots(red, 1em, 5em, maybe); }",
238
- ".a { @include background-dots(red, 1em, 5em, true, 42); }"
255
+ ".a { @include background-dots(red, 1em, 5em, true, 42); }",
256
+ ".a { @include background-dots(red, nonsense); }",
257
+ ".a { @include background-dots(red, 1em, nonsense); }"
239
258
  ]
240
259
  },
241
260
  {
@@ -247,7 +266,8 @@
247
266
  "default": "null",
248
267
  "accepts": [
249
268
  "an image path",
250
- "null to filter the element itself instead"
269
+ "null to filter the element itself instead",
270
+ "var(), url(), image-set() or a gradient, written as they are rather than wrapped in url()"
251
271
  ]
252
272
  },
253
273
  {
@@ -272,10 +292,14 @@
272
292
  "examples": [
273
293
  ".a { @include background-image(\"/img/a.png\"); }",
274
294
  ".a { @include background-image(\"/img/a.png\", rgba(0,0,0,0.5)); }",
275
- ".a { @include background-image(\"/img/a.png\", (red, blue), \"top\"); }"
295
+ ".a { @include background-image(\"/img/a.png\", (red, blue), \"top\"); }",
296
+ ".a { @include background-image(var(--hero), rgba(0,0,0,0.5)); }",
297
+ ".a { @include background-image(image-set(\"/img/a.png\" 1x, \"/img/a@2x.png\" 2x)); }"
276
298
  ],
277
299
  "rejects": [
278
- ".a { @include background-image(\"/img/a.png\", (red, blue), sideways); }"
300
+ ".a { @include background-image(\"/img/a.png\", (red, blue), sideways); }",
301
+ ".a { @include background-image(\"/img/a.png\", rgba(0,0,0,0.5), sideways); }",
302
+ ".a { @include background-image(null, rgba(0,0,0,0.5), sideways); }"
279
303
  ]
280
304
  },
281
305
  {
@@ -294,7 +318,7 @@
294
318
  "name": "$thickness",
295
319
  "default": "1em",
296
320
  "accepts": [
297
- "stripe thickness"
321
+ "stripe thickness: a length, or var(), env() or a calculation such as calc() or clamp()"
298
322
  ]
299
323
  },
300
324
  {
@@ -308,7 +332,8 @@
308
332
  "name": "$image",
309
333
  "default": "null",
310
334
  "accepts": [
311
- "an image path to sit behind the stripes"
335
+ "an image path to sit behind the stripes",
336
+ "var(), url(), image-set() or a gradient, written as they are rather than wrapped in url()"
312
337
  ]
313
338
  }
314
339
  ],
@@ -317,11 +342,14 @@
317
342
  "summary": "Repeating stripe pattern as a background, optionally over an image.",
318
343
  "examples": [
319
344
  ".a { @include background-stripes; }",
320
- ".a { @include background-stripes(red, 2em, -30deg); }"
345
+ ".a { @include background-stripes(red, 2em, -30deg); }",
346
+ ".a { @include background-stripes(red blue, var(--stripe)); }",
347
+ ".a { @include background-stripes(red, 2em, -30deg, var(--photo)); }"
321
348
  ],
322
349
  "rejects": [
323
350
  ".a { @include background-stripes(red, 2em, nonsense); }",
324
- ".a { @include background-stripes(red, 2em, -45deg, 42); }"
351
+ ".a { @include background-stripes(red, 2em, -45deg, 42); }",
352
+ ".a { @include background-stripes(red, nonsense); }"
325
353
  ]
326
354
  },
327
355
  {
@@ -334,16 +362,21 @@
334
362
  "accepts": [
335
363
  "a string used as the content value",
336
364
  "a data- attribute name, rendered as attr()",
337
- "null to write content yourself"
365
+ "null to write content yourself",
366
+ "var(), attr(), counter() or counters(), written as they are"
338
367
  ]
339
368
  }
340
369
  ],
341
370
  "file": "scss/library/_before.scss",
342
371
  "signature": "before($content: null)",
343
372
  "summary": "Styles the ::before pseudo-element. A `data-` argument becomes an attr() content value.",
373
+ "caveats": [
374
+ "With no argument no `content` is emitted, so the pseudo-element does not render unless the block sets `content`. Pass `\"\"` for an empty one."
375
+ ],
344
376
  "examples": [
345
377
  ".a { @include before(\"→\") { color: red; } }",
346
- ".a { @include before(\"data-label\") { color: red; } }"
378
+ ".a { @include before(\"data-label\") { color: red; } }",
379
+ ".a { @include before(var(--label)) { color: red; } }"
347
380
  ],
348
381
  "rejects": [
349
382
  ".a { @include before(42) { color: red; } }"
@@ -423,7 +456,8 @@
423
456
  "name": "$image-url",
424
457
  "default": "null",
425
458
  "accepts": [
426
- "an image path"
459
+ "an image path",
460
+ "var(), url(), image-set() or a gradient, written as they are rather than wrapped in url()"
427
461
  ]
428
462
  }
429
463
  ],
@@ -431,7 +465,8 @@
431
465
  "signature": "brand-logo($width, $height, $image-url: null)",
432
466
  "summary": "Logo box with an image and an accessible stretched link over it.",
433
467
  "examples": [
434
- ".logo { @include brand-logo(120px, 40px, \"/img/logo.svg\"); }"
468
+ ".logo { @include brand-logo(120px, 40px, \"/img/logo.svg\"); }",
469
+ ".logo { @include brand-logo(120px, 40px, var(--logo)); }"
435
470
  ],
436
471
  "rejects": []
437
472
  },
@@ -453,12 +488,21 @@
453
488
  "file": "scss/library/_breakpoint.scss",
454
489
  "signature": "breakpoint($params...)",
455
490
  "summary": "Media query built from the breakpoint map, or from raw lengths.",
491
+ "caveats": [
492
+ "With one argument the query matches exactly that width, `(width: 768px)`, which is a single pixel. Use `min`, `max` or a range for anything wider.",
493
+ "Declarations written after the include, in the same rule, are emitted after the `@media` block and win over it. Write them before the include."
494
+ ],
456
495
  "examples": [
457
496
  ".a { @include breakpoint(\"medium\") { color: red; } }",
458
497
  ".a { @include breakpoint(\"min\", \"medium\") { color: red; } }",
459
498
  ".a { @include breakpoint(\"between\", \"medium\" \"large\") { color: red; } }"
460
499
  ],
461
- "rejects": []
500
+ "rejects": [
501
+ ".a { @include breakpoint(\"between\", \"medium\", \"large\") { color: red; } }",
502
+ ".a { @include breakpoint() { color: red; } }",
503
+ ".a { @include breakpoint(\"min\", var(--wide)) { color: red; } }",
504
+ ".a { @include breakpoint(\"between\", var(--start) \"large\") { color: red; } }"
505
+ ]
462
506
  },
463
507
  {
464
508
  "name": "breakpointer",
@@ -571,6 +615,76 @@
571
615
  ".grid { @include columnizer(3, nonsense); }"
572
616
  ]
573
617
  },
618
+ {
619
+ "name": "container-query",
620
+ "kind": "mixin",
621
+ "arguments": [
622
+ {
623
+ "name": "$params",
624
+ "variadic": true,
625
+ "accepts": [
626
+ "a size",
627
+ "two sizes for a range",
628
+ "one of min, max, only or between followed by a size",
629
+ "$name as a keyword, to query one named container"
630
+ ]
631
+ }
632
+ ],
633
+ "file": "scss/library/_container-query.scss",
634
+ "signature": "container-query($params...)",
635
+ "summary": "A @container rule, taking the same argument shapes as breakpoint so the two read alike. Sizes may be a key from $map-for-breakpoints or a raw length, and a length is the common case because a container is usually narrower than the viewport. Nothing matches at all unless an ancestor was declared with the container mixin.",
636
+ "examples": [
637
+ ".title { @include container-query(\"min\", 400px) { font-size: 2rem; } }",
638
+ ".title { @include container-query(\"max\", 399px) { font-size: 1rem; } }",
639
+ ".title { @include container-query(\"between\", 300px 500px) { color: red; } }",
640
+ ".title { @include container-query(300px, 500px) { color: red; } }",
641
+ ".title { @include container-query(\"min\", \"medium\") { color: red; } }",
642
+ ".title { @include container-query(\"min\", 400px, $name: \"card\") { color: red; } }"
643
+ ],
644
+ "rejects": [
645
+ ".title { @include container-query(\"min\", 400px, 800px) { color: red; } }",
646
+ ".title { @include container-query(\"min\", 400px, $name: 42) { color: red; } }",
647
+ ".title { @include container-query(\"min\", var(--wide)) { color: red; } }"
648
+ ]
649
+ },
650
+ {
651
+ "name": "container",
652
+ "kind": "mixin",
653
+ "arguments": [
654
+ {
655
+ "name": "$name",
656
+ "default": "null",
657
+ "accepts": [
658
+ "a container name as a string, such as \"card\"",
659
+ "null for an unnamed container"
660
+ ]
661
+ },
662
+ {
663
+ "name": "$type",
664
+ "default": "inline-size",
665
+ "accepts": [
666
+ "inline-size",
667
+ "size",
668
+ "normal"
669
+ ]
670
+ }
671
+ ],
672
+ "file": "scss/library/_container.scss",
673
+ "signature": "container($name: null, $type: inline-size)",
674
+ "summary": "Marks an element as a query container, so container-query can ask about its width instead of the viewport's. The rule that asks has to sit on a descendant: an element is never matched by a @container rule reading its own container, and nothing warns you when it is not.",
675
+ "caveats": [
676
+ "An element does not match a `@container` query that reads its own container, and nothing warns. Put the `container-query` on a descendant."
677
+ ],
678
+ "examples": [
679
+ ".card { @include container(\"card\"); }",
680
+ ".panel { @include container; }",
681
+ ".panel { @include container(null, size); }"
682
+ ],
683
+ "rejects": [
684
+ ".card { @include container(\"card\", sideways); }",
685
+ ".card { @include container(42); }"
686
+ ]
687
+ },
574
688
  {
575
689
  "name": "counter",
576
690
  "kind": "mixin",
@@ -581,17 +695,22 @@
581
695
  "accepts": [
582
696
  "a counter style name",
583
697
  "a prefix and/or suffix string",
584
- "a prefix, a counter style and a suffix"
698
+ "a prefix, a counter style and a suffix",
699
+ "var(), attr(), counter() or counters() in place of a prefix or suffix, written as they are"
585
700
  ]
586
701
  }
587
702
  ],
588
703
  "file": "scss/library/_counter.scss",
589
704
  "signature": "counter($params...)",
590
705
  "summary": "CSS counter for a list, with optional text before and after the number.",
706
+ "caveats": [
707
+ "Numbering restarts on every item, each showing the first number, when the items are size containers (`container-type: inline-size`): containment scopes counters to each item."
708
+ ],
591
709
  "examples": [
592
710
  ".list { @include counter(\"decimal\"); }",
593
711
  ".list { @include counter(\".\"); }",
594
- ".list { @include counter(\"(\", \"decimal\", \")\"); }"
712
+ ".list { @include counter(\"(\", \"decimal\", \")\"); }",
713
+ ".list { @include counter(var(--prefix), \"decimal\"); }"
595
714
  ],
596
715
  "rejects": []
597
716
  },
@@ -722,7 +841,11 @@
722
841
  "rejects": [
723
842
  ".a { @include font-face(\"Inter\", \"/fonts/inter\"); }",
724
843
  "@include font-face(42, \"/fonts/x\");",
725
- "@include font-face(\"Inter\", 42);"
844
+ "@include font-face(\"Inter\", 42);",
845
+ "@include font-face(\"Inter\", \"/fonts/inter\", $file-formats: otf);",
846
+ "@include font-face(\"Inter\", \"/fonts/inter\", $file-formats: woff2 wof);",
847
+ "@include font-face(\"Inter\", \"/fonts/inter\", $file-formats: null);",
848
+ "@include font-face(\"Inter\", var(--font-path));"
726
849
  ]
727
850
  },
728
851
  {
@@ -749,6 +872,38 @@
749
872
  ".a { @include hide(nonsense); }"
750
873
  ]
751
874
  },
875
+ {
876
+ "name": "line-clamp",
877
+ "kind": "mixin",
878
+ "arguments": [
879
+ {
880
+ "name": "$lines",
881
+ "default": "3",
882
+ "accepts": [
883
+ "a whole number of lines, at least 1",
884
+ "none, to undo a clamp",
885
+ "var(), written as it is"
886
+ ]
887
+ }
888
+ ],
889
+ "file": "scss/library/_line-clamp.scss",
890
+ "signature": "line-clamp($lines: 3)",
891
+ "summary": "Truncates text after a number of lines, where ellipsis truncates one. It emits five declarations rather than one because -webkit-line-clamp does nothing on its own: without display: -webkit-box or without -webkit-box-orient: vertical the text is not clamped at all and nothing warns you, and without overflow: hidden the clamped text spills out below the box. The unprefixed line-clamp is emitted too, for when it becomes Baseline.",
892
+ "examples": [
893
+ ".excerpt { @include line-clamp(3); }",
894
+ ".title { @include line-clamp(2); }",
895
+ ".full { @include line-clamp(none); }",
896
+ ".default { @include line-clamp; }",
897
+ ".a { @include line-clamp(var(--lines)); }"
898
+ ],
899
+ "rejects": [
900
+ ".a { @include line-clamp(0); }",
901
+ ".a { @include line-clamp(2.5); }",
902
+ ".a { @include line-clamp(3px); }",
903
+ ".a { @include line-clamp(\"three\"); }",
904
+ ".a { @include line-clamp(url(a.png)); }"
905
+ ]
906
+ },
752
907
  {
753
908
  "name": "linear-gradient",
754
909
  "kind": "mixin",
@@ -796,7 +951,10 @@
796
951
  ],
797
952
  "file": "scss/library/_loadify.scss",
798
953
  "signature": "loadify($params...)",
799
- "summary": "Fades elements in on page load. Call once at the root to set up, then on each element.",
954
+ "summary": "Fades elements in on page load. Call once at the root to set up, then on each element. Under prefers-reduced-motion: reduce the end state is applied directly and no animation runs. Switching the animation off alone would not do, because the element starts invisible and the animation is what reveals it, so the content would stay hidden for good.",
955
+ "caveats": [
956
+ "`init` and every call must be in the same module, or the module with the call must `@use` the one that calls `init`. Otherwise Sass fails with \"The target selector was not found\"."
957
+ ],
800
958
  "examples": [
801
959
  "@include loadify(init);\n.a { @include loadify; }",
802
960
  "@include loadify;\n.a { @include loadify(0.4s, 1s); }"
@@ -871,7 +1029,8 @@
871
1029
  "name": "$offsets",
872
1030
  "default": "0",
873
1031
  "accepts": [
874
- "one to four lengths in shorthand order, or auto/inherit/initial/0"
1032
+ "one to four lengths in shorthand order, or auto/inherit/initial/0",
1033
+ "null in any position to leave that edge out"
875
1034
  ]
876
1035
  }
877
1036
  ],
@@ -880,7 +1039,9 @@
880
1039
  "summary": "Sets position and offsets in one call, using shorthand order.",
881
1040
  "examples": [
882
1041
  ".a { @include position(absolute, 0); }",
883
- ".a { @include position(fixed, 0 10px); }"
1042
+ ".a { @include position(fixed, 0 10px); }",
1043
+ ".a { @include position(absolute, null 16px 16px 16px); }",
1044
+ ".a { @include position(absolute, 0 null null 0); }"
884
1045
  ],
885
1046
  "rejects": []
886
1047
  },
@@ -931,7 +1092,7 @@
931
1092
  "variadic": true,
932
1093
  "accepts": [
933
1094
  "nothing, to hide it always",
934
- "one breakpoint",
1095
+ "one breakpoint, for exactly that width and no other",
935
1096
  "min or max plus a breakpoint",
936
1097
  "a start and an end breakpoint"
937
1098
  ]
@@ -939,14 +1100,20 @@
939
1100
  ],
940
1101
  "file": "scss/library/_remove.scss",
941
1102
  "signature": "remove($params...)",
942
- "summary": "Hides an element outright, or only within a breakpoint range.",
1103
+ "summary": "Hides an element outright, or within a media query: from a breakpoint up with min, up to it with max, or between two breakpoints. One breakpoint on its own hides the element at exactly that width, a single pixel.",
1104
+ "caveats": [
1105
+ "With one argument the element is hidden at exactly that width, `(width: 768px)`, which is a single pixel. Use `min`, `max` or a range for anything wider.",
1106
+ "A `display` written after the include, in the same rule, is emitted after the `@media` block and wins over it. Write it before the include."
1107
+ ],
943
1108
  "examples": [
944
1109
  ".a { @include remove; }",
945
- ".a { @include remove(\"medium\"); }",
946
- ".a { @include remove(\"min\", \"medium\"); }"
1110
+ ".a { @include remove(\"min\", \"medium\"); }",
1111
+ ".a { @include remove(\"max\", \"medium\"); }",
1112
+ ".a { @include remove(\"small\", \"large\"); }"
947
1113
  ],
948
1114
  "rejects": [
949
- ".a { @include remove(a, b, c); }"
1115
+ ".a { @include remove(a, b, c); }",
1116
+ ".a { @include remove(\"max\", var(--narrow)); }"
950
1117
  ]
951
1118
  },
952
1119
  {
@@ -1059,7 +1226,9 @@
1059
1226
  "examples": [
1060
1227
  ".a { @include screen-agent(\"2x\") { background-image: url(\"/img/a@2x.png\"); } }"
1061
1228
  ],
1062
- "rejects": []
1229
+ "rejects": [
1230
+ ".a { @include screen-agent(var(--density)) { color: red; } }"
1231
+ ]
1063
1232
  },
1064
1233
  {
1065
1234
  "name": "sizer",
@@ -1242,7 +1411,8 @@
1242
1411
  "name": "$image",
1243
1412
  "default": "null",
1244
1413
  "accepts": [
1245
- "an image path"
1414
+ "an image path",
1415
+ "var(), url(), image-set() or a gradient, written as they are rather than wrapped in url()"
1246
1416
  ]
1247
1417
  }
1248
1418
  ],
@@ -1250,7 +1420,8 @@
1250
1420
  "signature": "text-image($image: null)",
1251
1421
  "summary": "Fills the text with an image via background-clip.",
1252
1422
  "examples": [
1253
- ".a { @include text-image(\"/img/t.png\"); }"
1423
+ ".a { @include text-image(\"/img/t.png\"); }",
1424
+ ".a { @include text-image(var(--texture)); }"
1254
1425
  ],
1255
1426
  "rejects": []
1256
1427
  },
@@ -1365,14 +1536,17 @@
1365
1536
  "name": "$color",
1366
1537
  "default": "black",
1367
1538
  "accepts": [
1368
- "any colour value"
1539
+ "a Sass colour, such as red, #333 or oklch(70% 0.1 200)",
1540
+ "currentColor",
1541
+ "var(), color-mix() or light-dark(), which CSS resolves"
1369
1542
  ]
1370
1543
  },
1371
1544
  {
1372
1545
  "name": "$size",
1373
1546
  "default": "10px 8px",
1374
1547
  "accepts": [
1375
- "one length, or two lengths as width then height"
1548
+ "one length, or two lengths as width then height",
1549
+ "var(), env() or a calculation in place of any length"
1376
1550
  ]
1377
1551
  }
1378
1552
  ],
@@ -1381,11 +1555,17 @@
1381
1555
  "summary": "Draws a CSS triangle out of borders, pointing in a given direction.",
1382
1556
  "examples": [
1383
1557
  ".caret { @include triangle(\"bottom\", black, 10px 8px); }",
1384
- ".arrow { @include triangle(\"left\", red); }"
1558
+ ".arrow { @include triangle(\"left\", red); }",
1559
+ ".arrow { @include triangle(\"right\", var(--accent), 6px 8px); }",
1560
+ ".arrow { @include triangle(\"right\", currentColor); }",
1561
+ ".arrow { @include triangle(\"top\", color-mix(in srgb, red 50%, blue)); }",
1562
+ ".arrow { @include triangle(\"bottom\", currentColor, var(--caret-w) var(--caret-h)); }"
1385
1563
  ],
1386
1564
  "rejects": [
1387
1565
  ".caret { @include triangle(sideways); }",
1388
- ".caret { @include triangle(\"top\", notacolor); }"
1566
+ ".caret { @include triangle(\"top\", notacolor); }",
1567
+ ".caret { @include triangle(\"top\", url(a.png)); }",
1568
+ ".caret { @include triangle(\"top\", red, nonsense); }"
1389
1569
  ]
1390
1570
  },
1391
1571
  {
@@ -1406,7 +1586,9 @@
1406
1586
  "examples": [
1407
1587
  ".a { line-height: clearUnit(24px); }"
1408
1588
  ],
1409
- "rejects": []
1589
+ "rejects": [
1590
+ ".a { line-height: clearUnit(nonsense); }"
1591
+ ]
1410
1592
  },
1411
1593
  {
1412
1594
  "name": "clearWhitespace",
@@ -1448,7 +1630,10 @@
1448
1630
  "examples": [
1449
1631
  ".a { margin: convertToEm(24px); }"
1450
1632
  ],
1451
- "rejects": []
1633
+ "rejects": [
1634
+ ".a { margin: convertToEm(nonsense); }",
1635
+ ".a { margin: convertToEm(24); }"
1636
+ ]
1452
1637
  },
1453
1638
  {
1454
1639
  "name": "convertToNumber",
@@ -1469,7 +1654,9 @@
1469
1654
  ".a { z-index: convertToNumber(\"42\"); }"
1470
1655
  ],
1471
1656
  "rejects": [
1472
- ".a { --x: #{convertToNumber(42)}; }"
1657
+ ".a { --x: #{convertToNumber(42)}; }",
1658
+ ".a { z-index: convertToNumber(\"4a\"); }",
1659
+ ".a { z-index: convertToNumber(\"\"); }"
1473
1660
  ]
1474
1661
  },
1475
1662
  {
@@ -1509,6 +1696,55 @@
1509
1696
  ".a { --x: #{fillNulls(1px null, nonsense)}; }"
1510
1697
  ]
1511
1698
  },
1699
+ {
1700
+ "name": "fluid",
1701
+ "kind": "function",
1702
+ "arguments": [
1703
+ {
1704
+ "name": "$min",
1705
+ "required": true,
1706
+ "accepts": [
1707
+ "a length in px or rem, the value at $min-viewport"
1708
+ ]
1709
+ },
1710
+ {
1711
+ "name": "$max",
1712
+ "required": true,
1713
+ "accepts": [
1714
+ "a length in px or rem, the value at $max-viewport, no smaller than $min"
1715
+ ]
1716
+ },
1717
+ {
1718
+ "name": "$min-viewport",
1719
+ "default": "320px",
1720
+ "accepts": [
1721
+ "a length in px or rem, the width below which the value stops shrinking"
1722
+ ]
1723
+ },
1724
+ {
1725
+ "name": "$max-viewport",
1726
+ "default": "1280px",
1727
+ "accepts": [
1728
+ "a length in px or rem, larger than $min-viewport"
1729
+ ]
1730
+ }
1731
+ ],
1732
+ "file": "scss/utilities/_fluid.scss",
1733
+ "signature": "fluid($min, $max, $min-viewport: 320px, $max-viewport: 1280px)",
1734
+ "summary": "A clamp() value that grows with the viewport between two widths, then stops. The preferred value keeps a rem term rather than being pure vw, because a vw-only value ignores browser text zoom and fails WCAG 1.4.4. It is a function rather than a mixin because the value is the hard part and belongs to any property, not only font-size.",
1735
+ "examples": [
1736
+ ".title { font-size: fluid(24px, 48px); }",
1737
+ ".title { font-size: fluid(1rem, 3rem, 320px, 1200px); }",
1738
+ ".section { padding: fluid(16px, 64px) fluid(8px, 40px); }",
1739
+ ".stack { gap: fluid(0.5rem, 2rem); }"
1740
+ ],
1741
+ "rejects": [
1742
+ ".title { font-size: fluid(16px, 24px, 1280px, 320px); }",
1743
+ ".title { font-size: fluid(40px, 20px); }",
1744
+ ".title { font-size: fluid(16, 24); }",
1745
+ ".title { font-size: fluid(1em, 2em); }"
1746
+ ]
1747
+ },
1512
1748
  {
1513
1749
  "name": "fontSizer",
1514
1750
  "kind": "function",
@@ -1534,7 +1770,10 @@
1534
1770
  "examples": [
1535
1771
  ".a { font-size: fontSizer(16px, 1.5); }"
1536
1772
  ],
1537
- "rejects": []
1773
+ "rejects": [
1774
+ ".a { font-size: fontSizer(nonsense, 1.5); }",
1775
+ ".a { font-size: fontSizer(16px, 1px); }"
1776
+ ]
1538
1777
  },
1539
1778
  {
1540
1779
  "name": "fontSource",
@@ -1749,7 +1988,11 @@
1749
1988
  "examples": [
1750
1989
  ".a { font-size: remify(24px); }"
1751
1990
  ],
1752
- "rejects": []
1991
+ "rejects": [
1992
+ ".a { font-size: remify(nonsense); }",
1993
+ ".a { font-size: remify(1.5rem); }",
1994
+ ".a { font-size: remify(24); }"
1995
+ ]
1753
1996
  },
1754
1997
  {
1755
1998
  "name": "shade",
@@ -1777,7 +2020,8 @@
1777
2020
  ".a { color: shade(red, 20%); }"
1778
2021
  ],
1779
2022
  "rejects": [
1780
- ".a { color: shade(notacolor, 20%); }"
2023
+ ".a { color: shade(notacolor, 20%); }",
2024
+ ".a { color: shade(var(--x), 20%); }"
1781
2025
  ]
1782
2026
  },
1783
2027
  {
@@ -1828,7 +2072,8 @@
1828
2072
  ".a { color: tint(red, 20%); }"
1829
2073
  ],
1830
2074
  "rejects": [
1831
- ".a { color: tint(notacolor, 20%); }"
2075
+ ".a { color: tint(notacolor, 20%); }",
2076
+ ".a { color: tint(var(--x), 20%); }"
1832
2077
  ]
1833
2078
  },
1834
2079
  {
@@ -1859,13 +2104,14 @@
1859
2104
  "name": "$value",
1860
2105
  "required": true,
1861
2106
  "accepts": [
1862
- "a length with a unit, or auto, inherit, initial, 0"
2107
+ "a length with a unit, or auto, inherit, initial, 0",
2108
+ "null, returned as null without a warning"
1863
2109
  ]
1864
2110
  }
1865
2111
  ],
1866
2112
  "file": "scss/utilities/_validate-length.scss",
1867
2113
  "signature": "validateLength($value)",
1868
- "summary": "Returns the value if it is a length or one of auto, inherit, initial, 0.",
2114
+ "summary": "Returns the value if it is a length or one of auto, inherit, initial, 0. Returns null quietly for null, so a caller can skip a value.",
1869
2115
  "examples": [
1870
2116
  ".a { width: validateLength(20px); }"
1871
2117
  ],
@@ -1881,7 +2127,8 @@
1881
2127
  "accepts": [
1882
2128
  "a string such as \"16/9\" or \"16:9\"",
1883
2129
  "a unitless number",
1884
- "null for the 16/9 default"
2130
+ "null for the 16/9 default",
2131
+ "var(), returned as it is"
1885
2132
  ]
1886
2133
  }
1887
2134
  ],
@@ -1890,10 +2137,12 @@
1890
2137
  "summary": "Turns an aspect ratio into a value for the CSS aspect-ratio property.",
1891
2138
  "examples": [
1892
2139
  ".a { aspect-ratio: validateRatio(\"16/9\"); }",
1893
- ".a { aspect-ratio: validateRatio(1.5); }"
2140
+ ".a { aspect-ratio: validateRatio(1.5); }",
2141
+ ".a { aspect-ratio: validateRatio(var(--ratio)); }"
1894
2142
  ],
1895
2143
  "rejects": [
1896
- ".a { aspect-ratio: validateRatio(16 9); }"
2144
+ ".a { aspect-ratio: validateRatio(16 9); }",
2145
+ ".a { aspect-ratio: validateRatio(\"16 / 9\"); }"
1897
2146
  ]
1898
2147
  },
1899
2148
  {