Unify workspace lint, format, and type-check quality gates (#2732)

This commit is contained in:
Paweł Kuna
2026-07-30 19:36:41 +02:00
committed by GitHub
parent c527135aae
commit 6db32ea2c2
114 changed files with 2021 additions and 2696 deletions
+14 -6
View File
@@ -984,21 +984,29 @@ $aspect-ratios: (
// Shadows
$box-shadow-xs: 0 1px 2px 0 rgba(18, 18, 23, 0.05) !default;
$box-shadow-sm: 0 1px 3px 0 rgba(18, 18, 23, 0.1), 0 1px 2px 0 rgba(18, 18, 23, 0.06) !default;
$box-shadow-md: 0px 2px 4px -1px rgba(18, 18, 23, 0.06), 0px 4px 6px -1px rgba(18, 18, 23, 0.08) !default;
$box-shadow-lg: 0px 4px 6px -2px rgba(18, 18, 23, 0.05), 0px 10px 15px -3px rgba(18, 18, 23, 0.08) !default;
$box-shadow-xl: 0px 10px 10px -5px rgba(18, 18, 23, 0.04), 0px 20px 25px -5px rgba(18, 18, 23, 0.10) !default;
$box-shadow-sm:
0 1px 3px 0 rgba(18, 18, 23, 0.1),
0 1px 2px 0 rgba(18, 18, 23, 0.06) !default;
$box-shadow-md:
0px 2px 4px -1px rgba(18, 18, 23, 0.06),
0px 4px 6px -1px rgba(18, 18, 23, 0.08) !default;
$box-shadow-lg:
0px 4px 6px -2px rgba(18, 18, 23, 0.05),
0px 10px 15px -3px rgba(18, 18, 23, 0.08) !default;
$box-shadow-xl:
0px 10px 10px -5px rgba(18, 18, 23, 0.04),
0px 20px 25px -5px rgba(18, 18, 23, 0.1) !default;
$box-shadow-2xl: 0px 25px 50px -12px rgba(18, 18, 23, 0.25) !default;
$box-shadow-overlay:
0px 2px 4px 0px rgba(18, 18, 23, 0.04),
0px 5px 8px 0px rgba(18, 18, 23, 0.04),
0px 10px 18px 0px rgba(18, 18, 23, 0.03),
0px 24px 48px 0px rgba(18, 18, 23, 0.03),
0px 0px 0px 1px rgba(18, 18, 23, 0.10) !default;
0px 0px 0px 1px rgba(18, 18, 23, 0.1) !default;
$box-shadow: $box-shadow-md !default;
$box-shadow-transparent: 0 0 0 0 transparent !default;
$box-shadow-border: 0px 0px 0px 1px rgba(18, 18, 23, 0.10) !default;
$box-shadow-border: 0px 0px 0px 1px rgba(18, 18, 23, 0.1) !default;
$box-shadow-input: $box-shadow-xs !default;
$box-shadow-card: $box-shadow-xs !default;
$box-shadow-card-hover: $box-shadow-lg !default;
+7 -7
View File
@@ -1,9 +1,9 @@
@use "sass:meta";
@use "../settings" as *;
@use "../variables" as *;
@use "functions" as *;
@use "bootstrap/transition" as *;
@use "bootstrap/border-radius" as *;
@use 'sass:meta';
@use '../settings' as *;
@use '../variables' as *;
@use 'functions' as *;
@use 'bootstrap/transition' as *;
@use 'bootstrap/border-radius' as *;
@mixin subheader($include-color: true, $include-line-height: true) {
font-size: $h5-font-size;
@@ -21,7 +21,7 @@
}
@mixin scrollbar {
$selector: if(sass(meta.type-of(&) != "null"): "&"; else: "*");
$selector: if(sass(meta.type-of(&) != 'null'): '&'; else: '*');
#{$selector} {
scrollbar-color: color-transparent(var(--#{$prefix}scrollbar-color, var(--#{$prefix}body-color)), 0.2) transparent;
}
+4 -4
View File
@@ -1,7 +1,7 @@
@use "../../settings" as *;
@use "../../variables" as *;
@use "../functions" as *;
@use "breakpoints" as *;
@use '../../settings' as *;
@use '../../variables' as *;
@use '../functions' as *;
@use 'breakpoints' as *;
// Alert variants
//
// Tabler overrides Bootstrap's alert-variant with an empty mixin
+10 -6
View File
@@ -1,7 +1,7 @@
@use "../../settings" as *;
@use "../../variables" as *;
@use "../functions" as *;
@use "breakpoints" as *;
@use '../../settings' as *;
@use '../../variables' as *;
@use '../functions' as *;
@use 'breakpoints' as *;
// Shared between modals and offcanvases
@mixin overlay-backdrop($zindex, $backdrop-bg, $backdrop-opacity) {
position: fixed;
@@ -13,6 +13,10 @@
background-color: $backdrop-bg;
// Fade for backdrop
&.fade { opacity: 0; }
&.show { opacity: $backdrop-opacity; }
&.fade {
opacity: 0;
}
&.show {
opacity: $backdrop-opacity;
}
}
@@ -1,11 +1,11 @@
@use "../../settings" as *;
@use "../../variables" as *;
@use "../functions" as *;
@use "breakpoints" as *;
@use '../../settings' as *;
@use '../../variables' as *;
@use '../functions' as *;
@use 'breakpoints' as *;
// stylelint-disable property-disallowed-list
@use "sass:list";
@use "sass:math";
@use "sass:meta";
@use 'sass:list';
@use 'sass:math';
@use 'sass:meta';
// Single side border-radius
+5 -5
View File
@@ -1,8 +1,8 @@
@use "../../settings" as *;
@use "../../variables" as *;
@use "../functions" as *;
@use "breakpoints" as *;
@use "sass:list";
@use '../../settings' as *;
@use '../../variables' as *;
@use '../functions' as *;
@use 'breakpoints' as *;
@use 'sass:list';
@mixin box-shadow($shadow...) {
@if $enable-shadows {
+6 -6
View File
@@ -1,6 +1,6 @@
@use "sass:list";
@use "sass:map";
@use "../../settings" as *;
@use 'sass:list';
@use 'sass:map';
@use '../../settings' as *;
// Breakpoint viewport sizes and media queries.
//
@@ -35,7 +35,7 @@
// Returns a blank string if smallest breakpoint, otherwise returns the name with a dash in front.
@function breakpoint-infix($name, $breakpoints: $grid-breakpoints) {
@return if(sass(breakpoint-min($name, $breakpoints) == null): ""; else: "-#{$name}");
@return if(sass(breakpoint-min($name, $breakpoints) == null): ''; else: '-#{$name}');
}
// Media of at least the minimum breakpoint width. No query for the smallest breakpoint.
@@ -84,9 +84,9 @@
// Media between the breakpoint's minimum and maximum widths.
@mixin media-breakpoint-only($name, $breakpoints: $grid-breakpoints) {
$min: breakpoint-min($name, $breakpoints);
$min: breakpoint-min($name, $breakpoints);
$next: breakpoint-next($name, $breakpoints);
$max: breakpoint-max($next, $breakpoints);
$max: breakpoint-max($next, $breakpoints);
@if $min != null and $max != null {
@media (min-width: $min) and (max-width: $max) {
+5 -5
View File
@@ -1,8 +1,8 @@
@use "rfs" as *;
@use "../../settings" as *;
@use "../../variables" as *;
@use "../functions" as *;
@use "breakpoints" as *;
@use 'rfs' as *;
@use '../../settings' as *;
@use '../../variables' as *;
@use '../functions' as *;
@use 'breakpoints' as *;
// Button variants
//
// Tabler overrides Bootstrap's button-variant and button-outline-variant with empty mixins
+5 -10
View File
@@ -1,7 +1,7 @@
@use "../../settings" as *;
@use "../../variables" as *;
@use "../functions" as *;
@use "breakpoints" as *;
@use '../../settings' as *;
@use '../../variables' as *;
@use '../functions' as *;
@use 'breakpoints' as *;
@mixin caret-down($width: $caret-width) {
border-top: $width solid;
border-right: $width solid transparent;
@@ -29,12 +29,7 @@
border-bottom: $width solid transparent;
}
@mixin caret(
$direction: down,
$width: $caret-width,
$spacing: $caret-spacing,
$vertical-align: $caret-vertical-align
) {
@mixin caret($direction: down, $width: $caret-width, $spacing: $caret-spacing, $vertical-align: $caret-vertical-align) {
$selector: 'after';
@if $direction == 'left' {
+5 -5
View File
@@ -1,11 +1,11 @@
@use "../../settings" as *;
@use "../../variables" as *;
@use "../functions" as *;
@use "breakpoints" as *;
@use '../../settings' as *;
@use '../../variables' as *;
@use '../functions' as *;
@use 'breakpoints' as *;
@mixin clearfix() {
&::after {
display: block;
clear: both;
content: "";
content: '';
}
}
+7 -7
View File
@@ -1,9 +1,9 @@
@use "../../settings" as *;
@use "../../variables" as *;
@use "../functions" as *;
@use "breakpoints" as *;
@use '../../settings' as *;
@use '../../variables' as *;
@use '../functions' as *;
@use 'breakpoints' as *;
@mixin color-mode($mode: light, $root: false) {
@if $color-mode-type == "media-query" {
@if $color-mode-type == 'media-query' {
@if $root == true {
@media (prefers-color-scheme: $mode) {
:root {
@@ -16,8 +16,8 @@
}
}
} @else {
[data-bs-theme="#{$mode}"],
[data-theme="#{$mode}"] {
[data-bs-theme='#{$mode}'],
[data-theme='#{$mode}'] {
@content;
}
}
@@ -1,7 +1,7 @@
@use "../../settings" as *;
@use "../../variables" as *;
@use "../functions" as *;
@use "breakpoints" as *;
@use '../../settings' as *;
@use '../../variables' as *;
@use '../functions' as *;
@use 'breakpoints' as *;
@mixin color-scheme($name) {
@media (prefers-color-scheme: #{$name}) {
@content;
+6 -6
View File
@@ -1,15 +1,15 @@
@use "../../settings" as *;
@use "../../variables" as *;
@use "../functions" as *;
@use "breakpoints" as *;
@use '../../settings' as *;
@use '../../variables' as *;
@use '../functions' as *;
@use 'breakpoints' as *;
// Container mixins
@mixin make-container($gutter: $container-padding-x) {
--#{$prefix}gutter-x: #{$gutter};
--#{$prefix}gutter-y: 0;
width: 100%;
padding-right: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list
padding-left: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list
padding-right: calc(var(--#{$prefix}gutter-x) * 0.5); // stylelint-disable-line function-disallowed-list
padding-left: calc(var(--#{$prefix}gutter-x) * 0.5); // stylelint-disable-line function-disallowed-list
margin-right: auto;
margin-left: auto;
}
+4 -4
View File
@@ -1,7 +1,7 @@
@use "../../settings" as *;
@use "../../variables" as *;
@use "../functions" as *;
@use "breakpoints" as *;
@use '../../settings' as *;
@use '../../variables' as *;
@use '../functions' as *;
@use 'breakpoints' as *;
// Deprecate mixin
//
// This mixin can be used to deprecate mixins or functions.
+14 -22
View File
@@ -1,15 +1,15 @@
@use "border-radius" as *;
@use "box-shadow" as *;
@use "rfs" as *;
@use "../../settings" as *;
@use "../../variables" as *;
@use "../functions" as *;
@use "breakpoints" as *;
@use 'border-radius' as *;
@use 'box-shadow' as *;
@use 'rfs' as *;
@use '../../settings' as *;
@use '../../variables' as *;
@use '../functions' as *;
@use 'breakpoints' as *;
// This mixin uses an `if()` technique to be compatible with Dart Sass
// See https://github.com/sass/sass/issues/1873#issuecomment-152293725 for more details
@mixin form-validation-state-selector($state) {
@if ($state == "valid" or $state == "invalid") {
@if ($state == 'valid' or $state == 'invalid') {
.was-validated #{if(sass(&): "&"; else: "")}:#{$state},
#{if(sass(&): "&"; else: "")}.is-#{$state} {
@content;
@@ -21,15 +21,7 @@
}
}
@mixin form-validation-state(
$state,
$color,
$icon,
$tooltip-color: color-contrast($color),
$tooltip-bg-color: rgba($color, $form-feedback-tooltip-opacity),
$focus-box-shadow: 0 0 $input-btn-focus-blur $input-focus-width rgba($color, $input-btn-focus-color-opacity),
$border-color: $color
) {
@mixin form-validation-state($state, $color, $icon, $tooltip-color: color-contrast($color), $tooltip-bg-color: rgba($color, $form-feedback-tooltip-opacity), $focus-box-shadow: 0 0 $input-btn-focus-blur $input-focus-width rgba($color, $input-btn-focus-color-opacity), $border-color: $color) {
.#{$state}-feedback {
display: none;
width: 100%;
@@ -46,7 +38,7 @@
display: none;
max-width: 100%;
padding: $form-feedback-tooltip-padding-y $form-feedback-tooltip-padding-x;
margin-top: .1rem;
margin-top: 0.1rem;
@include font-size($form-feedback-tooltip-font-size);
line-height: $form-feedback-tooltip-line-height;
color: $tooltip-color;
@@ -100,7 +92,7 @@
@if $enable-validation-icons {
&:not([multiple]):not([size]),
&:not([multiple])[size="1"] {
&:not([multiple])[size='1'] {
--#{$prefix}form-select-bg-icon: #{escape-svg($icon)};
padding-right: $form-select-feedback-icon-padding-end;
background-position: $form-select-bg-position, $form-select-feedback-icon-position;
@@ -146,7 +138,7 @@
}
.form-check-inline .form-check-input {
~ .#{$state}-feedback {
margin-left: .5em;
margin-left: 0.5em;
}
}
@@ -155,9 +147,9 @@
> .form-select:not(:focus),
> .form-floating:not(:focus-within) {
@include form-validation-state-selector($state) {
@if $state == "valid" {
@if $state == 'valid' {
z-index: 3;
} @else if $state == "invalid" {
} @else if $state == 'invalid' {
z-index: 4;
}
}
+5 -5
View File
@@ -1,7 +1,7 @@
@use "../../settings" as *;
@use "../../variables" as *;
@use "../functions" as *;
@use "breakpoints" as *;
@use '../../settings' as *;
@use '../../variables' as *;
@use '../functions' as *;
@use 'breakpoints' as *;
// Gradients
@mixin gradient-bg($color: null) {
@@ -38,6 +38,6 @@
background-image: radial-gradient(circle, $inner-color, $outer-color);
}
@mixin gradient-striped($color: rgba($white, .15), $angle: 45deg) {
@mixin gradient-striped($color: rgba($white, 0.15), $angle: 45deg) {
background-image: linear-gradient($angle, $color 25%, transparent 25%, transparent 50%, $color 50%, $color 75%, transparent 75%, transparent);
}
+14 -14
View File
@@ -1,11 +1,11 @@
@use "../../settings" as *;
@use "../../variables" as *;
@use "../functions" as *;
@use "../../maps" as *;
@use "breakpoints" as *;
@use "sass:math";
@use "sass:map";
@use "sass:meta";
@use '../../settings' as *;
@use '../../variables' as *;
@use '../functions' as *;
@use '../../maps' as *;
@use 'breakpoints' as *;
@use 'sass:math';
@use 'sass:map';
@use 'sass:meta';
// Grid system
//
@@ -17,17 +17,17 @@
display: flex;
flex-wrap: wrap;
margin-top: calc(-1 * var(--#{$prefix}gutter-y)); // stylelint-disable-line function-disallowed-list
margin-right: calc(-.5 * var(--#{$prefix}gutter-x)); // stylelint-disable-line function-disallowed-list
margin-left: calc(-.5 * var(--#{$prefix}gutter-x)); // stylelint-disable-line function-disallowed-list
margin-right: calc(-0.5 * var(--#{$prefix}gutter-x)); // stylelint-disable-line function-disallowed-list
margin-left: calc(-0.5 * var(--#{$prefix}gutter-x)); // stylelint-disable-line function-disallowed-list
}
@mixin make-col-ready() {
box-sizing: if(sass(meta.global-variable-exists("include-column-box-sizing") and $include-column-box-sizing): border-box; else: null);
box-sizing: if(sass(meta.global-variable-exists('include-column-box-sizing') and $include-column-box-sizing): border-box; else: null);
flex-shrink: 0;
width: 100%;
max-width: 100%;
padding-right: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list
padding-left: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list
padding-right: calc(var(--#{$prefix}gutter-x) * 0.5); // stylelint-disable-line function-disallowed-list
padding-left: calc(var(--#{$prefix}gutter-x) * 0.5); // stylelint-disable-line function-disallowed-list
margin-top: var(--#{$prefix}gutter-y);
}
@@ -91,7 +91,7 @@
}
@for $i from 0 through ($columns - 1) {
@if not ($infix == "" and $i == 0) {
@if not($infix == '' and $i == 0) {
.offset#{$infix}-#{$i} {
@include make-col-offset($i, $columns);
}
+4 -4
View File
@@ -1,7 +1,7 @@
@use "../../settings" as *;
@use "../../variables" as *;
@use "../functions" as *;
@use "breakpoints" as *;
@use '../../settings' as *;
@use '../../variables' as *;
@use '../functions' as *;
@use 'breakpoints' as *;
// Image Mixins
// - Responsive image
// - Retina image
+4 -4
View File
@@ -1,7 +1,7 @@
@use "../../settings" as *;
@use "../../variables" as *;
@use "../functions" as *;
@use "breakpoints" as *;
@use '../../settings' as *;
@use '../../variables' as *;
@use '../functions' as *;
@use 'breakpoints' as *;
// Lists
// Unstyled keeps list items block level, just removes default browser padding and list-style
+5 -5
View File
@@ -1,8 +1,8 @@
@use "rfs" as *;
@use "../../settings" as *;
@use "../../variables" as *;
@use "../functions" as *;
@use "breakpoints" as *;
@use 'rfs' as *;
@use '../../settings' as *;
@use '../../variables' as *;
@use '../functions' as *;
@use 'breakpoints' as *;
// Pagination
@mixin pagination-size($padding-y, $padding-x, $font-size, $border-radius) {
+4 -4
View File
@@ -1,7 +1,7 @@
@use "../../settings" as *;
@use "../../variables" as *;
@use "../functions" as *;
@use "breakpoints" as *;
@use '../../settings' as *;
@use '../../variables' as *;
@use '../functions' as *;
@use 'breakpoints' as *;
@mixin reset-text {
font-family: $font-family-base;
// We deliberately do NOT reset font-size or overflow-wrap / word-wrap.
+4 -4
View File
@@ -1,7 +1,7 @@
@use "../../settings" as *;
@use "../../variables" as *;
@use "../functions" as *;
@use "breakpoints" as *;
@use '../../settings' as *;
@use '../../variables' as *;
@use '../functions' as *;
@use 'breakpoints' as *;
// Resize anything
@mixin resizable($direction) {
+43 -49
View File
@@ -1,9 +1,9 @@
// stylelint-disable scss/dimension-no-non-numeric-values
@use "sass:map";
@use "sass:math";
@use "sass:meta";
@use "sass:string";
@use 'sass:map';
@use 'sass:math';
@use 'sass:meta';
@use 'sass:string';
// SCSS RFS mixin
//
@@ -77,7 +77,7 @@ $rfs-base-value-unit: math.unit($rfs-base-value);
$quotient: $quotient + 1;
}
$result: $result * 10 + $quotient;
$factor: $factor * .1;
$factor: $factor * 0.1;
$remainder: $remainder * 10;
$precision: $precision - 1;
@if ($precision < 0 and $remainder >= $divisor * 5) {
@@ -88,10 +88,10 @@ $rfs-base-value-unit: math.unit($rfs-base-value);
$dividend-unit: math.unit($dividend);
$divisor-unit: math.unit($divisor);
$unit-map: (
"px": 1px,
"rem": 1rem,
"em": 1em,
"%": 1%
'px': 1px,
'rem': 1rem,
'em': 1em,
'%': 1%,
);
@if ($dividend-unit != $divisor-unit and map.has-key($unit-map, $dividend-unit)) {
$result: $result * map.get($unit-map, $dividend-unit);
@@ -102,8 +102,7 @@ $rfs-base-value-unit: math.unit($rfs-base-value);
// Remove px-unit from $rfs-base-value for calculations
@if $rfs-base-value-unit == px {
$rfs-base-value: divide($rfs-base-value, $rfs-base-value * 0 + 1);
}
@else if $rfs-base-value-unit == rem {
} @else if $rfs-base-value-unit == rem {
$rfs-base-value: divide($rfs-base-value, divide($rfs-base-value * 0 + 1, $rfs-rem-value));
}
@@ -113,8 +112,7 @@ $rfs-breakpoint-unit-cache: math.unit($rfs-breakpoint);
// Remove unit from $rfs-breakpoint for calculations
@if $rfs-breakpoint-unit-cache == px {
$rfs-breakpoint: divide($rfs-breakpoint, $rfs-breakpoint * 0 + 1);
}
@else if $rfs-breakpoint-unit-cache == rem or $rfs-breakpoint-unit-cache == "em" {
} @else if $rfs-breakpoint-unit-cache == rem or $rfs-breakpoint-unit-cache == 'em' {
$rfs-breakpoint: divide($rfs-breakpoint, divide($rfs-breakpoint * 0 + 1, $rfs-rem-value));
}
@@ -130,14 +128,12 @@ $rfs-mq-property-height: if(sass($rfs-mode == max-media-query): max-height; else
@media (#{$rfs-mq-property-width}: #{$rfs-mq-value}), (#{$rfs-mq-property-height}: #{$rfs-mq-value}) {
@content;
}
}
@else {
} @else {
@media (#{$rfs-mq-property-width}: #{$rfs-mq-value}) and (#{$rfs-mq-property-height}: #{$rfs-mq-value}) {
@content;
}
}
}
@else {
} @else {
@media (#{$rfs-mq-property-width}: #{$rfs-mq-value}) {
@content;
}
@@ -153,8 +149,7 @@ $rfs-mq-property-height: if(sass($rfs-mode == max-media-query): max-height; else
&.disable-rfs {
@content;
}
}
@else if $rfs-class == enable and $rfs-mode == min-media-query {
} @else if $rfs-class == enable and $rfs-mode == min-media-query {
.enable-rfs &,
&.enable-rfs {
@content;
@@ -166,27 +161,25 @@ $rfs-mq-property-height: if(sass($rfs-mode == max-media-query): max-height; else
// Internal mixin that adds enable classes to the selector if needed.
@mixin _rfs-media-query-rule {
@if $rfs-class == enable {
@if $rfs-mode == min-media-query {
@content;
}
@include _rfs-media-query () {
@include _rfs-media-query() {
.enable-rfs &,
&.enable-rfs {
@content;
}
}
}
@else {
} @else {
@if $rfs-class == disable and $rfs-mode == min-media-query {
.disable-rfs &,
&.disable-rfs {
@content;
}
}
@include _rfs-media-query () {
@include _rfs-media-query() {
@content;
}
}
@@ -195,29 +188,27 @@ $rfs-mq-property-height: if(sass($rfs-mode == max-media-query): max-height; else
// Helper function to get the formatted non-responsive value
@function rfs-value($values) {
// Convert to list
$values: if(sass(meta.type-of($values) != list): ($values,); else: $values);
$values: if(sass(meta.type-of($values) != list): ($values); else: $values);
$val: "";
$val: '';
// Loop over each value and calculate value
@each $value in $values {
@if $value == 0 {
$val: $val + " 0";
}
@else {
$val: $val + ' 0';
} @else {
// Cache $value unit
$unit: if(sass(meta.type-of($value) == "number"): math.unit($value); else: false);
$unit: if(sass(meta.type-of($value) == 'number'): math.unit($value); else: false);
@if $unit == px {
// Convert to rem if needed
$val: $val + " " + if(sass($rfs-unit == rem): #{divide($value, $value * 0 + $rfs-rem-value)}rem; else: $value);
}
@else if $unit == rem {
$val: $val + ' ' + if(sass($rfs-unit == rem): #{divide($value, $value * 0 + $rfs-rem-value)}rem; else: $value);
} @else if $unit == rem {
// Convert to px if needed
$val: $val + " " + if(sass($rfs-unit == px): #{divide($value, $value * 0 + 1) * $rfs-rem-value}px; else: $value);
$val: $val + ' ' + if(sass($rfs-unit == px): #{divide($value, $value * 0 + 1) * $rfs-rem-value}px; else: $value);
} @else {
// If $value isn't a number (like inherit) or $value has a unit (not px or rem, like 1.5em) or $ is 0, just print the value
$val: $val + " " + $value;
$val: $val + ' ' + $value;
}
}
}
@@ -229,30 +220,29 @@ $rfs-mq-property-height: if(sass($rfs-mode == max-media-query): max-height; else
// Helper function to get the responsive value calculated by RFS
@function rfs-fluid-value($values) {
// Convert to list
$values: if(sass(meta.type-of($values) != list): ($values,); else: $values);
$values: if(sass(meta.type-of($values) != list): ($values); else: $values);
$val: "";
$val: '';
// Loop over each value and calculate value
@each $value in $values {
@if $value == 0 {
$val: $val + " 0";
$val: $val + ' 0';
} @else {
// Cache $value unit
$unit: if(sass(meta.type-of($value) == "number"): math.unit($value); else: false);
$unit: if(sass(meta.type-of($value) == 'number'): math.unit($value); else: false);
// If $value isn't a number (like inherit) or $value has a unit (not px or rem, like 1.5em) or $ is 0, just print the value
@if not $unit or $unit != px and $unit != rem {
$val: $val + " " + $value;
$val: $val + ' ' + $value;
} @else {
// Remove unit from $value for calculations
$value: divide($value, $value * 0 + if(sass($unit == px): 1; else: divide(1, $rfs-rem-value)));
// Only add the media query if the value is greater than the minimum value
@if math.abs($value) <= $rfs-base-value or not $enable-rfs {
$val: $val + " " + if(sass($rfs-unit == rem): #{divide($value, $rfs-rem-value)}rem; else: #{$value}px);
}
@else {
$val: $val + ' ' + if(sass($rfs-unit == rem): #{divide($value, $rfs-rem-value)}rem; else: #{$value}px);
} @else {
// Calculate the minimum value
$value-min: $rfs-base-value + divide(math.abs($value) - $rfs-base-value, $rfs-factor);
@@ -272,7 +262,7 @@ $rfs-mq-property-height: if(sass($rfs-mode == max-media-query): max-height; else
$variable-width: #{divide($value-diff * 100, $rfs-breakpoint)}#{$variable-unit};
// Return the calculated value
$val: $val + " calc(" + $min-width + if(sass($value < 0): " - "; else: " + ") + $variable-width + ")";
$val: $val + ' calc(' + $min-width + if(sass($value < 0): ' - '; else: ' + ') + $variable-width + ')';
}
}
}
@@ -291,16 +281,20 @@ $rfs-mq-property-height: if(sass($rfs-mode == max-media-query): max-height; else
// Do not print the media query if responsive & non-responsive values are the same
@if $val == $fluid-val {
#{$property}: $val;
}
@else {
@include _rfs-rule () {
} @else {
@include _rfs-rule() {
#{$property}: if(sass($rfs-mode == max-media-query): $val; else: $fluid-val);
// Include safari iframe resize fix if needed
min-width: if(sass($rfs-safari-iframe-resize-bug-fix): (0 * 1vw); else: null);
min-width: if(
sass($rfs-safari-iframe-resize-bug-fix): (
0 * 1vw,
);
else: null
);
}
@include _rfs-media-query-rule () {
@include _rfs-media-query-rule() {
#{$property}: if(sass($rfs-mode == max-media-query): $fluid-val; else: $val);
}
}
@@ -1,9 +1,9 @@
@use "../../settings" as *;
@use "../../variables" as *;
@use "../functions" as *;
@use "breakpoints" as *;
@use "sass:color";
@use "sass:math";
@use '../../settings' as *;
@use '../../variables' as *;
@use '../functions' as *;
@use 'breakpoints' as *;
@use 'sass:color';
@use 'sass:math';
@mixin table-variant($state, $background) {
.table-#{$state} {
@@ -1,7 +1,7 @@
@use "../../settings" as *;
@use "../../variables" as *;
@use "../functions" as *;
@use "breakpoints" as *;
@use '../../settings' as *;
@use '../../variables' as *;
@use '../functions' as *;
@use 'breakpoints' as *;
// Text truncate
// Requires inline-block or block for proper styling
+5 -5
View File
@@ -1,9 +1,9 @@
@use "../../settings" as *;
@use "../../variables" as *;
@use "../functions" as *;
@use "breakpoints" as *;
@use '../../settings' as *;
@use '../../variables' as *;
@use '../functions' as *;
@use 'breakpoints' as *;
// stylelint-disable property-disallowed-list
@use "sass:list";
@use 'sass:list';
@mixin transition($transition...) {
@if list.length($transition) == 0 {
+16 -17
View File
@@ -1,20 +1,20 @@
@use "rfs" as *;
@use "../../settings" as *;
@use "../../variables" as *;
@use "../functions" as *;
@use "breakpoints" as *;
@use "sass:list";
@use "sass:map";
@use "sass:meta";
@use "sass:string";
@use 'rfs' as *;
@use '../../settings' as *;
@use '../../variables' as *;
@use '../functions' as *;
@use 'breakpoints' as *;
@use 'sass:list';
@use 'sass:map';
@use 'sass:meta';
@use 'sass:string';
// Utility generator
// Used to generate utilities & print utilities
@mixin generate-utility($utility, $infix: "", $is-rfs-media-query: false) {
@mixin generate-utility($utility, $infix: '', $is-rfs-media-query: false) {
$values: map.get($utility, values);
// If the values are a list or string, convert it into a map
@if meta.type-of($values) == "string" or meta.type-of(list.nth($values, 1)) != "list" {
@if meta.type-of($values) == 'string' or meta.type-of(list.nth($values, 1)) != 'list' {
$values: list.zip($values, $values);
}
@@ -22,13 +22,13 @@
$properties: map.get($utility, property);
// Multiple properties are possible, for example with vertical or horizontal margins or paddings
@if meta.type-of($properties) == "string" {
@if meta.type-of($properties) == 'string' {
$properties: list.append((), $properties);
}
// Use custom class if present
$property-class: if(sass(map.has-key($utility, class)): map.get($utility, class); else: list.nth($properties, 1));
$property-class: if(sass($property-class == null): ""; else: $property-class);
$property-class: if(sass($property-class == null): ''; else: $property-class);
// Use custom CSS variable name if present, otherwise default to `class`
$css-variable-name: if(sass(map.has-key($utility, css-variable-name)): map.get($utility, css-variable-name); else: map.get($utility, class));
@@ -36,10 +36,10 @@
// State params to generate pseudo-classes
$state: if(sass(map.has-key($utility, state)): map.get($utility, state); else: ());
$infix: if(sass($property-class == "" and string.slice($infix, 1, 1) == "-"): string.slice($infix, 2); else: $infix);
$infix: if(sass($property-class == '' and string.slice($infix, 1, 1) == '-'): string.slice($infix, 2); else: $infix);
// Don't prefix if value key is null (e.g. with shadow class)
$property-class-modifier: if(sass($key): if(sass($property-class == "" and $infix == ""): ""; else: "-") + $key; else: "");
$property-class-modifier: if(sass($key): if(sass($property-class == '' and $infix == ''): ''; else: '-') + $key; else: '');
@if map.get($utility, rfs) {
// Inside the media query
@@ -48,8 +48,7 @@
// Do not render anything if fluid and non fluid values are the same
$value: if(sass($val == rfs-fluid-value($value)): null; else: $val);
}
@else {
} @else {
$value: rfs-fluid-value($value);
}
}
@@ -1,7 +1,7 @@
@use "../../settings" as *;
@use "../../variables" as *;
@use "../functions" as *;
@use "breakpoints" as *;
@use '../../settings' as *;
@use '../../variables' as *;
@use '../functions' as *;
@use 'breakpoints' as *;
// stylelint-disable declaration-no-important
// Hide content visually while keeping it accessible to assistive technologies
+16 -16
View File
@@ -3,46 +3,46 @@
// to a `calc()` expression when the operands are unit-incompatible, so the
// branches around null-handling and the numeric-vs-calc path are what matter.
@use "sass:meta";
@use "sass:string";
@use "../mixins/functions" as *;
@use 'sass:meta';
@use 'sass:string';
@use '../mixins/functions' as *;
@include describe("add") {
@include it("treats a null operand as the identity") {
@include describe('add') {
@include it('treats a null operand as the identity') {
@include assert-equal(add(null, 5px), 5px);
@include assert-equal(add(5px, null), 5px);
}
@include it("adds two compatible numbers directly") {
@include it('adds two compatible numbers directly') {
@include assert-equal(add(2px, 3px), 5px);
}
// add() returns a real `calculation` here; two structurally-identical
// calculations aren't `==` in Sass, so compare the rendered output instead.
@include it("falls back to calc() for incompatible units") {
@include assert-equal(meta.inspect(add(2px, 3%)), "calc(2px + 3%)");
@include it('falls back to calc() for incompatible units') {
@include assert-equal(meta.inspect(add(2px, 3%)), 'calc(2px + 3%)');
}
@include it("builds a plain expression when calc is disabled") {
@include assert-equal(add(2px, 3%, false), string.unquote("2px + 3%"));
@include it('builds a plain expression when calc is disabled') {
@include assert-equal(add(2px, 3%, false), string.unquote('2px + 3%'));
}
}
@include describe("subtract") {
@include it("returns null when both operands are null") {
@include describe('subtract') {
@include it('returns null when both operands are null') {
@include assert-equal(subtract(null, null), null);
}
@include it("handles a single null operand") {
@include it('handles a single null operand') {
@include assert-equal(subtract(5px, null), 5px);
@include assert-equal(subtract(null, 5px), -5px);
}
@include it("subtracts two compatible numbers directly") {
@include it('subtracts two compatible numbers directly') {
@include assert-equal(subtract(5px, 2px), 3px);
}
@include it("falls back to calc() for incompatible units") {
@include assert-equal(meta.inspect(subtract(5px, 2%)), "calc(5px - 2%)");
@include it('falls back to calc() for incompatible units') {
@include assert-equal(meta.inspect(subtract(5px, 2%)), 'calc(5px - 2%)');
}
}
+14 -14
View File
@@ -5,29 +5,29 @@
// They return Sass lists, so the results are compared through `meta.inspect(...)`
// (a single-item list is not `==` to the bare number it contains).
@use "sass:meta";
@use "../mixins/bootstrap/border-radius" as *;
@use 'sass:meta';
@use '../mixins/bootstrap/border-radius' as *;
@include describe("valid-radius") {
@include it("clamps a negative value to 0") {
@include assert-equal(meta.inspect(valid-radius(-5px)), "0");
@include describe('valid-radius') {
@include it('clamps a negative value to 0') {
@include assert-equal(meta.inspect(valid-radius(-5px)), '0');
}
@include it("leaves a non-negative value untouched") {
@include assert-equal(meta.inspect(valid-radius(8px)), "8px");
@include it('leaves a non-negative value untouched') {
@include assert-equal(meta.inspect(valid-radius(8px)), '8px');
}
@include it("clamps only the negative members of a list") {
@include assert-equal(meta.inspect(valid-radius(4px -2px 6px)), "4px 0 6px");
@include it('clamps only the negative members of a list') {
@include assert-equal(meta.inspect(valid-radius(4px -2px 6px)), '4px 0 6px');
}
}
@include describe("squircle-radius") {
@include it("keeps 0 as 0") {
@include assert-equal(meta.inspect(squircle-radius(0)), "0");
@include describe('squircle-radius') {
@include it('keeps 0 as 0') {
@include assert-equal(meta.inspect(squircle-radius(0)), '0');
}
@include it("scales a non-zero radius by 2.5 via calc()") {
@include assert-equal(meta.inspect(squircle-radius(4px)), "calc(4px * 2.5)");
@include it('scales a non-zero radius by 2.5 via calc()') {
@include assert-equal(meta.inspect(squircle-radius(4px)), 'calc(4px * 2.5)');
}
}
+48 -14
View File
@@ -4,34 +4,68 @@
// comma list. The `$enable-shadows: false` gate depends on overriding that global
// and is not covered here.
@use "../mixins/bootstrap/box-shadow" as *;
@use '../mixins/bootstrap/box-shadow' as *;
@include describe("box-shadow") {
@include it("emits a single shadow value") {
@include describe('box-shadow') {
@include it('emits a single shadow value') {
@include assert() {
@include output() { .t { @include box-shadow(0 1px 2px #000); } }
@include expect() { .t { box-shadow: 0 1px 2px #000; } }
@include output() {
.t {
@include box-shadow(0 1px 2px #000);
}
}
@include expect() {
.t {
box-shadow: 0 1px 2px #000;
}
}
}
}
@include it("passes a keyword through untouched") {
@include it('passes a keyword through untouched') {
@include assert() {
@include output() { .t { @include box-shadow(none); } }
@include expect() { .t { box-shadow: none; } }
@include output() {
.t {
@include box-shadow(none);
}
}
@include expect() {
.t {
box-shadow: none;
}
}
}
}
@include it("joins multiple shadows into a comma list") {
@include it('joins multiple shadows into a comma list') {
@include assert() {
@include output() { .t { @include box-shadow(0 1px 2px #000, 0 2px 4px #111); } }
@include expect() { .t { box-shadow: 0 1px 2px #000, 0 2px 4px #111; } }
@include output() {
.t {
@include box-shadow(0 1px 2px #000, 0 2px 4px #111);
}
}
@include expect() {
.t {
box-shadow:
0 1px 2px #000,
0 2px 4px #111;
}
}
}
}
@include it("filters out null values") {
@include it('filters out null values') {
@include assert() {
@include output() { .t { @include box-shadow(null, 0 1px 2px #000); } }
@include expect() { .t { box-shadow: 0 1px 2px #000; } }
@include output() {
.t {
@include box-shadow(null, 0 1px 2px #000);
}
}
@include expect() {
.t {
box-shadow: 0 1px 2px #000;
}
}
}
}
}
+20 -14
View File
@@ -6,39 +6,45 @@
// `breakpoint-prev` lives in mixins/_functions.scss; the rest live in
// mixins/bootstrap/_breakpoints.scss.
@use "../mixins/functions" as fn;
@use "../mixins/bootstrap/breakpoints" as *;
@use '../mixins/functions' as fn;
@use '../mixins/bootstrap/breakpoints' as *;
$grid: (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px);
$grid: (
xs: 0,
sm: 576px,
md: 768px,
lg: 992px,
xl: 1200px,
);
@include describe("breakpoint-next / breakpoint-prev") {
@include it("returns the neighbouring breakpoint name") {
@include describe('breakpoint-next / breakpoint-prev') {
@include it('returns the neighbouring breakpoint name') {
@include assert-equal(breakpoint-next(md, $grid), lg);
@include assert-equal(fn.breakpoint-prev(md, $grid), sm);
}
@include it("returns null past the last / before the first breakpoint") {
@include it('returns null past the last / before the first breakpoint') {
@include assert-equal(breakpoint-next(xl, $grid), null);
@include assert-equal(fn.breakpoint-prev(xs, $grid), null);
}
}
@include describe("breakpoint-min") {
@include it("returns the min width, or null for the zero breakpoint") {
@include describe('breakpoint-min') {
@include it('returns the min width, or null for the zero breakpoint') {
@include assert-equal(breakpoint-min(md, $grid), 768px);
@include assert-equal(breakpoint-min(xs, $grid), null);
}
}
@include describe("breakpoint-max") {
@include it("subtracts 0.02px to avoid min/max overlap") {
@include describe('breakpoint-max') {
@include it('subtracts 0.02px to avoid min/max overlap') {
@include assert-equal(breakpoint-max(md, $grid), 767.98px);
}
}
@include describe("breakpoint-infix") {
@include it("is blank for the smallest breakpoint and dash-prefixed otherwise") {
@include assert-equal(breakpoint-infix(xs, $grid), "");
@include assert-equal(breakpoint-infix(md, $grid), "-md");
@include describe('breakpoint-infix') {
@include it('is blank for the smallest breakpoint and dash-prefixed otherwise') {
@include assert-equal(breakpoint-infix(xs, $grid), '');
@include assert-equal(breakpoint-infix(md, $grid), '-md');
}
}
+35 -15
View File
@@ -3,12 +3,16 @@
// main `caret()` builds a pseudo-element and branches on `$direction` for the
// rotation and (for `left`) the ::before/::after structure.
@use "../mixins/bootstrap/caret" as *;
@use '../mixins/bootstrap/caret' as *;
@include describe("caret-* border helpers") {
@include it("caret-down points the border triangle downward") {
@include describe('caret-* border helpers') {
@include it('caret-down points the border triangle downward') {
@include assert() {
@include output() { .t { @include caret-down(0.3em); } }
@include output() {
.t {
@include caret-down(0.3em);
}
}
@include expect() {
.t {
border-top: 0.3em solid;
@@ -20,9 +24,13 @@
}
}
@include it("caret-up points the border triangle upward") {
@include it('caret-up points the border triangle upward') {
@include assert() {
@include output() { .t { @include caret-up(0.3em); } }
@include output() {
.t {
@include caret-up(0.3em);
}
}
@include expect() {
.t {
border-top: 0;
@@ -34,9 +42,13 @@
}
}
@include it("caret-start omits the left border") {
@include it('caret-start omits the left border') {
@include assert() {
@include output() { .t { @include caret-start(0.3em); } }
@include output() {
.t {
@include caret-start(0.3em);
}
}
@include expect() {
.t {
border-top: 0.3em solid transparent;
@@ -48,13 +60,17 @@
}
}
@include describe("caret mixin") {
@include it("renders an ::after caret rotated for the down direction") {
@include describe('caret mixin') {
@include it('renders an ::after caret rotated for the down direction') {
@include assert() {
@include output() { .t { @include caret(down); } }
@include output() {
.t {
@include caret(down);
}
}
@include expect() {
.t:after {
content: "";
content: '';
display: inline-block;
vertical-align: 0.255em;
width: 0.3em;
@@ -69,12 +85,16 @@
}
}
@include it("uses ::before and clears ::after for the left direction") {
@include it('uses ::before and clears ::after for the left direction') {
@include assert() {
@include output() { .t { @include caret(left); } }
@include output() {
.t {
@include caret(left);
}
}
@include expect() {
.t:before {
content: "";
content: '';
display: inline-block;
vertical-align: 0.255em;
width: 0.3em;
+5 -5
View File
@@ -4,21 +4,21 @@
// live in scss/_settings.scss, which functions.scss already `@use`s, so no
// fixtures are needed a plain `@use` of the functions module is enough.
@use "../mixins/functions" as *;
@use '../mixins/functions' as *;
@include describe("color-contrast") {
@include it("picks black text on a light background") {
@include describe('color-contrast') {
@include it('picks black text on a light background') {
@include assert-equal(color-contrast(#ffffff), #000000);
}
@include it("picks white text on a dark background") {
@include it('picks white text on a dark background') {
@include assert-equal(color-contrast(#000000), #ffffff);
}
// When no candidate reaches the required ratio the function falls back to the
// highest-contrast option (and emits a @warn, which sass-true ignores). An
// impossible ratio of 21 against mid-grey forces that branch; black wins.
@include it("falls back to the highest-contrast colour when none qualifies") {
@include it('falls back to the highest-contrast colour when none qualifies') {
@include assert-equal(color-contrast(#808080, #000, #fff, 21), #000);
}
}
+8 -6
View File
@@ -5,19 +5,21 @@
// Tabler uses for dark mode). The `media-query` branch depends on overriding
// that global through the variables module, so it is not covered here.
@use "../mixins/bootstrap/color-mode" as *;
@use '../mixins/bootstrap/color-mode' as *;
@include describe("color-mode") {
@include it("scopes content under the theme attribute selectors") {
@include describe('color-mode') {
@include it('scopes content under the theme attribute selectors') {
@include assert() {
@include output() {
@include color-mode(dark) {
.x { color: red; }
.x {
color: red;
}
}
}
@include expect() {
[data-bs-theme=dark] .x,
[data-theme=dark] .x {
[data-bs-theme='dark'] .x,
[data-theme='dark'] .x {
color: red;
}
}
+12 -12
View File
@@ -4,41 +4,41 @@
// isolation. A regression here silently degrades accessibility, which is why
// they rank high.
@use "../mixins/functions" as *;
@use '../mixins/functions' as *;
@include describe("luminance") {
@include it("is 0 for black and 1 for white") {
@include describe('luminance') {
@include it('is 0 for black and 1 for white') {
@include assert-equal(luminance(#000), 0);
@include assert-equal(luminance(#fff), 1);
}
}
@include describe("contrast-ratio") {
@include it("is 21 for the black/white extreme") {
@include describe('contrast-ratio') {
@include it('is 21 for the black/white extreme') {
@include assert-equal(contrast-ratio(#000, #fff), 21);
}
@include it("is 1 for a colour against itself") {
@include it('is 1 for a colour against itself') {
@include assert-equal(contrast-ratio(#fff, #fff), 1);
}
}
@include describe("shade-color / tint-color") {
@include it("shade mixes the colour toward black") {
@include describe('shade-color / tint-color') {
@include it('shade mixes the colour toward black') {
@include assert-equal(shade-color(#ffffff, 10%), rgb(229.5, 229.5, 229.5));
}
@include it("tint mixes the colour toward white") {
@include it('tint mixes the colour toward white') {
@include assert-equal(tint-color(#000000, 10%), rgb(25.5, 25.5, 25.5));
}
}
@include describe("shift-color") {
@include it("shades when the weight is positive") {
@include describe('shift-color') {
@include it('shades when the weight is positive') {
@include assert-equal(shift-color(#808080, 20%), shade-color(#808080, 20%));
}
@include it("tints when the weight is negative") {
@include it('tints when the weight is negative') {
@include assert-equal(shift-color(#808080, -20%), tint-color(#808080, 20%));
}
}
+32 -31
View File
@@ -7,73 +7,74 @@
// a `url(...)` token; those are asserted through `meta.inspect(...)` so the
// comparison is against the exact rendered output.
@use "sass:meta";
@use "../mixins/functions" as *;
@use 'sass:meta';
@use '../mixins/functions' as *;
@include describe("to-rgb") {
@include it("returns the comma-separated rgb channels") {
@include describe('to-rgb') {
@include it('returns the comma-separated rgb channels') {
@include assert-equal(to-rgb(#ff0000), (255, 0, 0));
@include assert-equal(to-rgb(#123456), (18, 52, 86));
}
}
@include describe("opaque") {
@include it("flattens a translucent foreground over the background") {
@include describe('opaque') {
@include it('flattens a translucent foreground over the background') {
@include assert-equal(opaque(#fff, rgba(#000, 0.5)), rgb(127.5, 127.5, 127.5));
}
@include it("returns the foreground unchanged when it is fully opaque") {
@include it('returns the foreground unchanged when it is fully opaque') {
@include assert-equal(opaque(#fff, #000), black);
}
}
@include describe("to-percentage") {
@include it("converts a unitless number to a percentage") {
@include describe('to-percentage') {
@include it('converts a unitless number to a percentage') {
@include assert-equal(to-percentage(0.5), 50%);
}
@include it("passes a value that already has a unit straight through") {
@include it('passes a value that already has a unit straight through') {
@include assert-equal(to-percentage(10px), 10px);
}
}
@include describe("color-transparent") {
@include it("returns the colour untouched when alpha is 1") {
@include describe('color-transparent') {
@include it('returns the colour untouched when alpha is 1') {
@include assert-equal(color-transparent(#f00, 1), #f00);
}
@include it("builds a color-mix() with the alpha as a percentage otherwise") {
@include assert-equal(
meta.inspect(color-transparent(#f00, 0.5)),
"color-mix(in srgb, #f00 50%, transparent)"
);
@include it('builds a color-mix() with the alpha as a percentage otherwise') {
@include assert-equal(meta.inspect(color-transparent(#f00, 0.5)), 'color-mix(in srgb, #f00 50%, transparent)');
}
}
@include describe("url-svg") {
@include describe('url-svg') {
@include it("percent-encodes '#' so the data URI stays valid") {
@include assert-equal(
meta.inspect(url-svg("#")),
'url("data:image/svg+xml;charset=UTF-8,%23")'
);
@include assert-equal(meta.inspect(url-svg('#')), 'url("data:image/svg+xml;charset=UTF-8,%23")');
}
@include it("injects the SVG xmlns attribute") {
@include assert-equal(
meta.inspect(url-svg("<svg></svg>")),
"url('data:image/svg+xml;charset=UTF-8,<svg xmlns=\"http://www.w3.org/2000/svg\"></svg>')"
);
@include it('injects the SVG xmlns attribute') {
@include assert-equal(meta.inspect(url-svg('<svg></svg>')), 'url(\'data:image/svg+xml;charset=UTF-8,<svg xmlns="http://www.w3.org/2000/svg"></svg>\')');
}
}
@include describe("map-loop") {
@include describe('map-loop') {
// Applies a module-level function (resolved by name via meta.get-function) to
// every value in the map. `to-percentage` lives in the same module, so it
// resolves correctly.
@include it("maps every value through the named function") {
@include it('maps every value through the named function') {
@include assert-equal(
map-loop((a: 0.5, b: 0.25), "to-percentage", "$value"),
(a: 50%, b: 25%)
map-loop(
(
a: 0.5,
b: 0.25,
),
'to-percentage',
'$value'
),
(
a: 50%,
b: 25%,
)
);
}
}
+10 -16
View File
@@ -3,18 +3,18 @@
// in scss/_settings.scss (already `@use`d by functions.scss), so a plain `@use`
// of the functions module is enough no fixtures.
@use "sass:meta";
@use "../mixins/functions" as *;
@use 'sass:meta';
@use '../mixins/functions' as *;
@include describe("varify") {
@include describe('varify') {
// `varify` seeds its accumulator with `null`, so the raw list inspects as
// `null var(...) ...`; Sass drops the null when serialising to CSS, so the
// behaviour is asserted through the rendered output rather than the value.
@include it("prefixes each entry as a space-separated var() list") {
@include it('prefixes each entry as a space-separated var() list') {
@include assert() {
@include output() {
.t {
padding: varify(("gutter-x" "gutter-y"));
padding: varify(('gutter-x' 'gutter-y'));
}
}
@include expect() {
@@ -26,18 +26,12 @@
}
}
@include describe("rgba-css-var") {
@include it("builds a color-mix() from the identifier and target opacity") {
@include assert-equal(
meta.inspect(rgba-css-var("primary", "bg")),
"color-mix(in srgb, var(--tblr-primary) calc(var(--tblr-bg-opacity) * 100%), transparent)"
);
@include describe('rgba-css-var') {
@include it('builds a color-mix() from the identifier and target opacity') {
@include assert-equal(meta.inspect(rgba-css-var('primary', 'bg')), 'color-mix(in srgb, var(--tblr-primary) calc(var(--tblr-bg-opacity) * 100%), transparent)');
}
@include it("special-cases the body background") {
@include assert-equal(
meta.inspect(rgba-css-var("body", "bg")),
"color-mix(in srgb, var(--tblr-body-bg) calc(var(--tblr-bg-opacity) * 100%), transparent)"
);
@include it('special-cases the body background') {
@include assert-equal(meta.inspect(rgba-css-var('body', 'bg')), 'color-mix(in srgb, var(--tblr-body-bg) calc(var(--tblr-bg-opacity) * 100%), transparent)');
}
}
+9 -9
View File
@@ -7,38 +7,38 @@
// and cannot be caught by sass-true (there is no assert-throws), so it is not
// covered here.
@use "../mixins/functions" as *;
@use '../mixins/functions' as *;
@include describe("divide") {
@include it("divides two unitless numbers") {
@include describe('divide') {
@include it('divides two unitless numbers') {
@include assert-equal(divide(4, 2), 2);
}
@include it("returns a fractional result") {
@include it('returns a fractional result') {
@include assert-equal(divide(10, 4), 2.5);
@include assert-equal(divide(1, 2), 0.5);
}
@include it("returns 0 when the dividend is 0") {
@include it('returns 0 when the dividend is 0') {
@include assert-equal(divide(0, 5), 0);
}
@include it("keeps the correct sign for mixed-sign operands") {
@include it('keeps the correct sign for mixed-sign operands') {
@include assert-equal(divide(-6, 2), -3);
@include assert-equal(divide(6, -2), -3);
@include assert-equal(divide(-6, -2), 3);
}
@include it("propagates the dividend unit when the divisor is unitless") {
@include it('propagates the dividend unit when the divisor is unitless') {
@include assert-equal(divide(10px, 2), 5px);
@include assert-equal(divide(5%, 2), 2.5%);
}
@include it("cancels matching units to a unitless result") {
@include it('cancels matching units to a unitless result') {
@include assert-equal(divide(10px, 2px), 5);
}
@include it("rounds to the requested precision") {
@include it('rounds to the requested precision') {
@include assert-equal(divide(2, 3, 0), 1);
@include assert-equal(divide(2, 3, 2), 0.67);
}
+6 -9
View File
@@ -5,17 +5,14 @@
// the functions module is enough no fixtures. Escaping only happens when the
// string looks like an SVG data URI; anything else is returned untouched.
@use "../mixins/functions" as *;
@use '../mixins/functions' as *;
@include describe("escape-svg") {
@include it("returns a non data-URI string unchanged") {
@include assert-equal(escape-svg("no data uri <here>"), "no data uri <here>");
@include describe('escape-svg') {
@include it('returns a non data-URI string unchanged') {
@include assert-equal(escape-svg('no data uri <here>'), 'no data uri <here>');
}
@include it("percent-encodes reserved characters inside an SVG data URI") {
@include assert-equal(
escape-svg("data:image/svg+xml,<svg><path/></svg>"),
"data:image/svg+xml,%3csvg%3e%3cpath/%3e%3c/svg%3e"
);
@include it('percent-encodes reserved characters inside an SVG data URI') {
@include assert-equal(escape-svg('data:image/svg+xml,<svg><path/></svg>'), 'data:image/svg+xml,%3csvg%3e%3cpath/%3e%3c/svg%3e');
}
}
+135 -37
View File
@@ -9,39 +9,73 @@
// single vs multiple properties, custom class, css-var mode, pseudo-class
// states and the responsive infix.
@use "sass:map";
@use "../mixins/bootstrap/utilities" as *;
@use "../mixins/bootstrap/breakpoints" as *;
@use 'sass:map';
@use '../mixins/bootstrap/utilities' as *;
@use '../mixins/bootstrap/breakpoints' as *;
@include describe("generate-utility") {
@include it("generates a class per key from a values map") {
@include describe('generate-utility') {
@include it('generates a class per key from a values map') {
@include assert() {
@include output() {
@include generate-utility((property: opacity, values: (0: 0, 50: 0.5)));
@include generate-utility(
(
property: opacity,
values: (
0: 0,
50: 0.5,
),
)
);
}
@include expect() {
.opacity-0 { opacity: 0 !important; }
.opacity-50 { opacity: 0.5 !important; }
.opacity-0 {
opacity: 0 !important;
}
.opacity-50 {
opacity: 0.5 !important;
}
}
}
}
@include it("zips a plain list of values into key/value pairs") {
@include it('zips a plain list of values into key/value pairs') {
@include assert() {
@include output() {
@include generate-utility((property: float, class: float, values: (left, right)));
@include generate-utility(
(
property: float,
class: float,
values: (
left,
right,
),
)
);
}
@include expect() {
.float-left { float: left !important; }
.float-right { float: right !important; }
.float-left {
float: left !important;
}
.float-right {
float: right !important;
}
}
}
}
@include it("emits every property when several are given") {
@include it('emits every property when several are given') {
@include assert() {
@include output() {
@include generate-utility((property: (margin-right margin-left), class: mx, values: (0: 0, auto: auto)));
@include generate-utility(
(
property: margin-right margin-left,
class: mx,
values: (
0: 0,
auto: auto,
),
)
);
}
@include expect() {
.mx-0 {
@@ -56,10 +90,19 @@
}
}
@include it("sets a custom property instead of a declaration in css-var mode") {
@include it('sets a custom property instead of a declaration in css-var mode') {
@include assert() {
@include output() {
@include generate-utility((property: opacity, class: opacity, css-var: true, values: (50: 0.5)));
@include generate-utility(
(
property: opacity,
class: opacity,
css-var: true,
values: (
50: 0.5,
),
)
);
}
@include expect() {
.opacity-50 {
@@ -69,25 +112,45 @@
}
}
@include it("adds a pseudo-class variant for each declared state") {
@include it('adds a pseudo-class variant for each declared state') {
@include assert() {
@include output() {
@include generate-utility((property: text-decoration, class: text-decoration, state: hover, values: (underline)));
@include generate-utility(
(
property: text-decoration,
class: text-decoration,
state: hover,
values: (underline),
)
);
}
@include expect() {
.text-decoration-underline { text-decoration: underline !important; }
.text-decoration-underline-hover:hover { text-decoration: underline !important; }
.text-decoration-underline {
text-decoration: underline !important;
}
.text-decoration-underline-hover:hover {
text-decoration: underline !important;
}
}
}
}
@include it("injects the responsive infix into the class name") {
@include it('injects the responsive infix into the class name') {
@include assert() {
@include output() {
@include generate-utility((property: display, class: d, values: (none)), "-md");
@include generate-utility(
(
property: display,
class: d,
values: (none),
),
'-md'
);
}
@include expect() {
.d-md-none { display: none !important; }
.d-md-none {
display: none !important;
}
}
}
}
@@ -98,21 +161,40 @@
// the mixin for a given infix when `map.get($utility, responsive)` is truthy (or
// it's the base, infix-less breakpoint). This reproduces that gate against a local
// breakpoint map with two utilities: one `responsive: true`, one without.
@include describe("generate-utility (responsive property)") {
$g: (xs: 0, sm: 576px, md: 768px);
@include describe('generate-utility (responsive property)') {
$g: (
xs: 0,
sm: 576px,
md: 768px,
);
$utils: (
"display": (property: display, class: d, responsive: true, values: (none, flex)),
"float": (property: float, class: float, values: (left, right)),
'display': (
property: display,
class: d,
responsive: true,
values: (
none,
flex,
),
),
'float': (
property: float,
class: float,
values: (
left,
right,
),
),
);
@include it("only a `responsive: true` utility gets breakpoint-infixed variants") {
@include it('only a `responsive: true` utility gets breakpoint-infixed variants') {
@include assert() {
@include output() {
@each $bp in map.keys($g) {
@include media-breakpoint-up($bp, $g) {
$infix: breakpoint-infix($bp, $g);
@each $key, $utility in $utils {
@if map.get($utility, responsive) or $infix == "" {
@if map.get($utility, responsive) or $infix == '' {
@include generate-utility($utility, $infix);
}
}
@@ -121,20 +203,36 @@
}
@include expect() {
// base breakpoint: both utilities emit bare classes
.d-none { display: none !important; }
.d-flex { display: flex !important; }
.float-left { float: left !important; }
.float-right { float: right !important; }
.d-none {
display: none !important;
}
.d-flex {
display: flex !important;
}
.float-left {
float: left !important;
}
.float-right {
float: right !important;
}
// responsive breakpoints: only `d` (responsive: true) is repeated; `float` is not
@media (min-width: 576px) {
.d-sm-none { display: none !important; }
.d-sm-flex { display: flex !important; }
.d-sm-none {
display: none !important;
}
.d-sm-flex {
display: flex !important;
}
}
@media (min-width: 768px) {
.d-md-none { display: none !important; }
.d-md-flex { display: flex !important; }
.d-md-none {
display: none !important;
}
.d-md-flex {
display: flex !important;
}
}
}
}
+89 -29
View File
@@ -3,62 +3,118 @@
// + math.percentage); `$columns` is passed explicitly so the tests don't depend
// on the global `$grid-columns`.
@use "../mixins/bootstrap/grid" as *;
@use '../mixins/bootstrap/grid' as *;
@include describe("make-col") {
@include it("sets a fixed width as a percentage of the column count") {
@include describe('make-col') {
@include it('sets a fixed width as a percentage of the column count') {
@include assert() {
@include output() { .t { @include make-col(6, 12); } }
@include expect() { .t { flex: 0 0 auto; width: 50%; } }
@include output() {
.t {
@include make-col(6, 12);
}
}
@include expect() {
.t {
flex: 0 0 auto;
width: 50%;
}
}
}
}
@include it("grows to fill the row when no size is given") {
@include it('grows to fill the row when no size is given') {
@include assert() {
@include output() { .t { @include make-col(); } }
@include expect() { .t { flex: 1 1 0; max-width: 100%; } }
@include output() {
.t {
@include make-col();
}
}
@include expect() {
.t {
flex: 1 1 0;
max-width: 100%;
}
}
}
}
}
@include describe("make-col-auto") {
@include it("sizes to the content") {
@include describe('make-col-auto') {
@include it('sizes to the content') {
@include assert() {
@include output() { .t { @include make-col-auto(); } }
@include expect() { .t { flex: 0 0 auto; width: auto; } }
@include output() {
.t {
@include make-col-auto();
}
}
@include expect() {
.t {
flex: 0 0 auto;
width: auto;
}
}
}
}
}
@include describe("make-col-offset") {
@include it("offsets by a percentage of the column count") {
@include describe('make-col-offset') {
@include it('offsets by a percentage of the column count') {
@include assert() {
@include output() { .t { @include make-col-offset(3, 12); } }
@include expect() { .t { margin-left: 25%; } }
@include output() {
.t {
@include make-col-offset(3, 12);
}
}
@include expect() {
.t {
margin-left: 25%;
}
}
}
}
@include it("collapses a zero offset to 0 (not 0%)") {
@include it('collapses a zero offset to 0 (not 0%)') {
@include assert() {
@include output() { .t { @include make-col-offset(0, 12); } }
@include expect() { .t { margin-left: 0; } }
@include output() {
.t {
@include make-col-offset(0, 12);
}
}
@include expect() {
.t {
margin-left: 0;
}
}
}
}
}
@include describe("row-cols") {
@include it("splits children into equal fractions of the row") {
@include describe('row-cols') {
@include it('splits children into equal fractions of the row') {
@include assert() {
@include output() { .t { @include row-cols(3); } }
@include expect() { .t > * { flex: 0 0 auto; width: 33.33333333%; } }
@include output() {
.t {
@include row-cols(3);
}
}
@include expect() {
.t > * {
flex: 0 0 auto;
width: 33.33333333%;
}
}
}
}
}
@include describe("make-row") {
@include it("sets the gutter custom properties and negative margins") {
@include describe('make-row') {
@include it('sets the gutter custom properties and negative margins') {
@include assert() {
@include output() { .t { @include make-row(1rem); } }
@include output() {
.t {
@include make-row(1rem);
}
}
@include expect() {
.t {
--tblr-gutter-x: 1rem;
@@ -74,10 +130,14 @@
}
}
@include describe("make-col-ready") {
@include it("primes a column with full width and gutter padding") {
@include describe('make-col-ready') {
@include it('primes a column with full width and gutter padding') {
@include assert() {
@include output() { .t { @include make-col-ready(); } }
@include output() {
.t {
@include make-col-ready();
}
}
@include expect() {
.t {
flex-shrink: 0;
+54 -16
View File
@@ -1,38 +1,76 @@
// Priority 3 unit tests for the map utilities in scss/mixins/_functions.scss.
// The test maps are built inline, so no project config is required.
@use "../mixins/functions" as *;
@use '../mixins/functions' as *;
@include describe("negativify-map") {
@include it("prefixes keys with `n` and negates the values") {
@include describe('negativify-map') {
@include it('prefixes keys with `n` and negates the values') {
@include assert-equal(
negativify-map((1: 10px, 2: 20px)),
("n1": -10px, "n2": -20px)
negativify-map(
(
1: 10px,
2: 20px,
)
),
(
'n1': -10px,
'n2': -20px,
)
);
}
@include it("leaves a 0 key untouched") {
@include it('leaves a 0 key untouched') {
@include assert-equal(
negativify-map((0: 0, 1: 5px)),
("n1": -5px)
negativify-map(
(
0: 0,
1: 5px,
)
),
(
'n1': -5px,
)
);
}
}
@include describe("map-get-multiple") {
@include it("keeps only the requested keys, preserving map order") {
@include describe('map-get-multiple') {
@include it('keeps only the requested keys, preserving map order') {
@include assert-equal(
map-get-multiple((a: 1, b: 2, c: 3), (a c)),
(a: 1, c: 3)
map-get-multiple(
(
a: 1,
b: 2,
c: 3,
),
(a c)
),
(
a: 1,
c: 3,
)
);
}
}
@include describe("map-merge-multiple") {
@include it("merges maps left-to-right, later keys winning") {
@include describe('map-merge-multiple') {
@include it('merges maps left-to-right, later keys winning') {
@include assert-equal(
map-merge-multiple((a: 1), (b: 2), (a: 3)),
(a: 3, b: 2)
map-merge-multiple(
(
a: 1,
),
(
b: 2,
),
(
a: 3,
)
),
(
a: 3,
b: 2,
)
);
}
}
+70 -32
View File
@@ -9,130 +9,168 @@
// Max-widths are the breakpoint value minus 0.02px (the min-/max- overlap fix);
// the smallest/edge cases emit the content with no media query at all.
@use "../mixins/bootstrap/breakpoints" as *;
@use "../mixins/functions" as *;
@use '../mixins/bootstrap/breakpoints' as *;
@use '../mixins/functions' as *;
$g: (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px);
$g: (
xs: 0,
sm: 576px,
md: 768px,
lg: 992px,
xl: 1200px,
);
@include describe("media-breakpoint-up") {
@include it("wraps content in a min-width query") {
@include describe('media-breakpoint-up') {
@include it('wraps content in a min-width query') {
@include assert() {
@include output() {
@include media-breakpoint-up(md, $g) {
.t { color: red; }
.t {
color: red;
}
}
}
@include expect() {
@media (min-width: 768px) {
.t { color: red; }
.t {
color: red;
}
}
}
}
}
@include it("emits content directly for the zero breakpoint") {
@include it('emits content directly for the zero breakpoint') {
@include assert() {
@include output() {
@include media-breakpoint-up(xs, $g) {
.t { color: red; }
.t {
color: red;
}
}
}
@include expect() {
.t { color: red; }
.t {
color: red;
}
}
}
}
}
@include describe("media-breakpoint-down") {
@include it("wraps content in a max-width query (value - 0.02px)") {
@include describe('media-breakpoint-down') {
@include it('wraps content in a max-width query (value - 0.02px)') {
@include assert() {
@include output() {
@include media-breakpoint-down(md, $g) {
.t { color: red; }
.t {
color: red;
}
}
}
@include expect() {
@media (max-width: 767.98px) {
.t { color: red; }
.t {
color: red;
}
}
}
}
}
@include it("emits content directly for the zero breakpoint") {
@include it('emits content directly for the zero breakpoint') {
@include assert() {
@include output() {
@include media-breakpoint-down(xs, $g) {
.t { color: red; }
.t {
color: red;
}
}
}
@include expect() {
.t { color: red; }
.t {
color: red;
}
}
}
}
}
@include describe("media-breakpoint-between") {
@include it("combines a min-width and a max-width query") {
@include describe('media-breakpoint-between') {
@include it('combines a min-width and a max-width query') {
@include assert() {
@include output() {
@include media-breakpoint-between(sm, md, $g) {
.t { color: red; }
.t {
color: red;
}
}
}
@include expect() {
@media (min-width: 576px) and (max-width: 767.98px) {
.t { color: red; }
.t {
color: red;
}
}
}
}
}
}
@include describe("media-breakpoint-only") {
@include it("spans from the breakpoint min to the next breakpoint max") {
@include describe('media-breakpoint-only') {
@include it('spans from the breakpoint min to the next breakpoint max') {
@include assert() {
@include output() {
@include media-breakpoint-only(md, $g) {
.t { color: red; }
.t {
color: red;
}
}
}
@include expect() {
@media (min-width: 768px) and (max-width: 991.98px) {
.t { color: red; }
.t {
color: red;
}
}
}
}
}
}
@include describe("media-breakpoint-down-than") {
@include it("targets everything below the previous breakpoint") {
@include describe('media-breakpoint-down-than') {
@include it('targets everything below the previous breakpoint') {
@include assert() {
@include output() {
@include media-breakpoint-down-than(md, $g) {
.t { color: red; }
.t {
color: red;
}
}
}
@include expect() {
@media (max-width: 575.98px) {
.t { color: red; }
.t {
color: red;
}
}
}
}
}
@include it("emits content directly when there is no previous breakpoint") {
@include it('emits content directly when there is no previous breakpoint') {
@include assert() {
@include output() {
@include media-breakpoint-down-than(xs, $g) {
.t { color: red; }
.t {
color: red;
}
}
}
@include expect() {
.t { color: red; }
.t {
color: red;
}
}
}
}
+7 -7
View File
@@ -2,11 +2,11 @@
// dependency on project variables, so they are pulled in directly by path.
// `output()` / `expect()` come from the `true` module (injected by the runner).
@use "../mixins/bootstrap/clearfix" as *;
@use "../mixins/bootstrap/visually-hidden" as *;
@use '../mixins/bootstrap/clearfix' as *;
@use '../mixins/bootstrap/visually-hidden' as *;
@include describe("clearfix mixin") {
@include it("emits a clearing ::after pseudo-element") {
@include describe('clearfix mixin') {
@include it('emits a clearing ::after pseudo-element') {
@include assert() {
@include output() {
.t {
@@ -17,15 +17,15 @@
.t::after {
display: block;
clear: both;
content: "";
content: '';
}
}
}
}
}
@include describe("visually-hidden mixin") {
@include it("hides the element while keeping it accessible") {
@include describe('visually-hidden mixin') {
@include it('hides the element while keeping it accessible') {
@include assert() {
@include output() {
.t {
+16 -16
View File
@@ -5,10 +5,10 @@
// means the assertions run against real values `$prefix` = "tblr-", the real
// `$h5-font-size`, etc. instead of fixtures.
@use "../mixins/mixins" as *;
@use '../mixins/mixins' as *;
@include describe("subheader mixin") {
@include it("outputs the full subheader with colour and line-height") {
@include describe('subheader mixin') {
@include it('outputs the full subheader with colour and line-height') {
@include assert() {
@include output() {
.t {
@@ -28,7 +28,7 @@
}
}
@include it("drops colour and line-height when the flags are false") {
@include it('drops colour and line-height when the flags are false') {
@include assert() {
@include output() {
.t {
@@ -47,8 +47,8 @@
}
}
@include describe("autodark-image mixin") {
@include it("inverts the image via filter") {
@include describe('autodark-image mixin') {
@include it('inverts the image via filter') {
@include assert() {
@include output() {
.t {
@@ -64,8 +64,8 @@
}
}
@include describe("elements-list mixin") {
@include it("sets up a wrapping flex list with the default gap") {
@include describe('elements-list mixin') {
@include it('sets up a wrapping flex list with the default gap') {
@include assert() {
@include output() {
.t {
@@ -83,7 +83,7 @@
}
}
@include it("honours a custom gap argument") {
@include it('honours a custom gap argument') {
@include assert() {
@include output() {
.t {
@@ -102,8 +102,8 @@
}
}
@include describe("focus-ring mixin") {
@include it("outputs the ring without a border by default") {
@include describe('focus-ring mixin') {
@include it('outputs the ring without a border by default') {
@include assert() {
@include output() {
.t {
@@ -119,7 +119,7 @@
}
}
@include it("adds a border colour when requested") {
@include it('adds a border colour when requested') {
@include assert() {
@include output() {
.t {
@@ -137,8 +137,8 @@
}
}
@include describe("media-print mixin") {
@include it("wraps content in a print media query") {
@include describe('media-print mixin') {
@include it('wraps content in a print media query') {
@include assert() {
@include output() {
@include media-print {
@@ -158,11 +158,11 @@
}
}
@include describe("scrollbar mixin") {
@include describe('scrollbar mixin') {
// The mixin resolves `&` to the current selector (or `*` at root); nested here,
// every rule is prefixed with `.scroll`. Also covers the reduced-motion query
// injected by the transition mixin.
@include it("emits the webkit scrollbar rule set") {
@include it('emits the webkit scrollbar rule set') {
@include assert() {
@include output() {
.scroll {
+12 -12
View File
@@ -6,25 +6,25 @@
// gives the fluid value unchanged below the base size, a responsive `calc()`
// above it.
@use "../mixins/bootstrap/rfs" as *;
@use '../mixins/bootstrap/rfs' as *;
@include describe("rfs-value") {
@include it("passes rem values through and keeps 0") {
@include assert-equal(rfs-value(2rem), "2rem");
@include assert-equal(rfs-value(0), "0");
@include describe('rfs-value') {
@include it('passes rem values through and keeps 0') {
@include assert-equal(rfs-value(2rem), '2rem');
@include assert-equal(rfs-value(0), '0');
}
@include it("normalises px to rem") {
@include assert-equal(rfs-value(20px), "1.25rem");
@include it('normalises px to rem') {
@include assert-equal(rfs-value(20px), '1.25rem');
}
}
@include describe("rfs-fluid-value") {
@include it("leaves values at or below the base size unchanged") {
@include assert-equal(rfs-fluid-value(1rem), "1rem");
@include describe('rfs-fluid-value') {
@include it('leaves values at or below the base size unchanged') {
@include assert-equal(rfs-fluid-value(1rem), '1rem');
}
@include it("produces a responsive calc() above the base size") {
@include assert-equal(rfs-fluid-value(3rem), "calc(1.425rem + 2.1vw)");
@include it('produces a responsive calc() above the base size') {
@include assert-equal(rfs-fluid-value(3rem), 'calc(1.425rem + 2.1vw)');
}
}
+14 -14
View File
@@ -5,30 +5,30 @@
// `describe`, `it` and `assert-equal` come from the `true` module, which the
// runner injects for us.
@use "../mixins/functions" as *;
@use '../mixins/functions' as *;
@include describe("str-replace") {
@include it("replaces a single occurrence") {
@include assert-equal(str-replace("a-b-c", "-", "_"), "a_b_c");
@include describe('str-replace') {
@include it('replaces a single occurrence') {
@include assert-equal(str-replace('a-b-c', '-', '_'), 'a_b_c');
}
@include it("replaces every occurrence, not just the first") {
@include assert-equal(str-replace("a.b.c.d", ".", "/"), "a/b/c/d");
@include it('replaces every occurrence, not just the first') {
@include assert-equal(str-replace('a.b.c.d', '.', '/'), 'a/b/c/d');
}
@include it("returns the string unchanged when the search is not found") {
@include assert-equal(str-replace("hello world", "x", "y"), "hello world");
@include it('returns the string unchanged when the search is not found') {
@include assert-equal(str-replace('hello world', 'x', 'y'), 'hello world');
}
@include it("removes the search string when no replacement is given") {
@include assert-equal(str-replace("1,000,000", ","), "1000000");
@include it('removes the search string when no replacement is given') {
@include assert-equal(str-replace('1,000,000', ','), '1000000');
}
@include it("handles a replacement longer than the search string") {
@include assert-equal(str-replace("aaa", "a", "bb"), "bbbbbb");
@include it('handles a replacement longer than the search string') {
@include assert-equal(str-replace('aaa', 'a', 'bb'), 'bbbbbb');
}
@include it("returns an empty string unchanged") {
@include assert-equal(str-replace("", "-", "_"), "");
@include it('returns an empty string unchanged') {
@include assert-equal(str-replace('', '-', '_'), '');
}
}
+19 -7
View File
@@ -3,12 +3,16 @@
// defaults), a real transition also emits a `prefers-reduced-motion` reset
// except when the value itself is `none`.
@use "../mixins/bootstrap/transition" as *;
@use '../mixins/bootstrap/transition' as *;
@include describe("transition") {
@include it("emits the transition plus a reduced-motion reset") {
@include describe('transition') {
@include it('emits the transition plus a reduced-motion reset') {
@include assert() {
@include output() { .t { @include transition(color 0.3s); } }
@include output() {
.t {
@include transition(color 0.3s);
}
}
@include expect() {
.t {
transition: color 0.3s;
@@ -22,10 +26,18 @@
}
}
@include it("skips the reduced-motion reset when the value is none") {
@include it('skips the reduced-motion reset when the value is none') {
@include assert() {
@include output() { .t { @include transition(none); } }
@include expect() { .t { transition: none; } }
@include output() {
.t {
@include transition(none);
}
}
@include expect() {
.t {
transition: none;
}
}
}
}
}