Skip to content
Closed
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions scss/_functions.scss
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@
@return $result;
}

// Some functions are defined in separate files.
@import "functions/utilities-map";

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason to import it in the middle of a file ?


// Internal Bootstrap function to turn maps into its negative variant.
// It prefixes the keys with `n` and makes the value negative.
@function negativify-map($map) {
Expand Down
1 change: 1 addition & 0 deletions scss/_variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,7 @@ $enable-rfs: true !default;
$enable-validation-icons: true !default;
$enable-negative-margins: false !default;
$enable-deprecation-messages: true !default;
$enable-utility-classes: true !default;
$enable-important-utilities: true !default;

$enable-dark-mode: true !default;
Expand Down
89 changes: 89 additions & 0 deletions scss/functions/_utilities-map.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Builds a map of utility classes.
@function build-utilities-map($grid-breakpoints: $grid-breakpoints, $utilities: $utilities) {
// Build a breakpoint map that does not include the zero breakpoint.
$breakpoints-map: ();
@each $name, $min in $grid-breakpoints {
@if $min != 0 {
$breakpoints-map: map-merge(
$breakpoints-map,
(
"-#{$name}": $name,
)
);
}
}

$utilities-map: () !default;
Comment thread
mdo marked this conversation as resolved.

@each $key, $utility in $utilities {
@if type-of($utility) == "map" {
Comment thread
mdo marked this conversation as resolved.
$properties: map-get($utility, property);
// Some utilities set the value on more than one property.
@if type-of($properties) == "string" {
$properties: append((), $properties);
}

// Use custom class if present
$shortname: if(
map-has-key($utility, class),
map-get($utility, class),
nth($properties, 1)
);
$shortname: if($shortname == null, "", $shortname);

// Shortname with prepended dash, or empty string if empty.
$dashname: if($shortname == "", "", "-" + $shortname);

$values: map-get($utility, values);
// If the values are a list or string, convert it into a map
@if type-of($values) == "string" or type-of(nth($values, 1)) != "list" {
$values: zip($values, $values);
}

// $values could be a map or a list. @each covers both.
@each $k, $value in $values {
// Value key with prepended dash, or empty string if value key is null.
$dashkey: if($k, "-" + $k, "");
$property-value-map: ();
@each $property in $properties {
$property-value-map: map-merge(
$property-value-map,
(
$property: $value,
)
);
}
$dashclass: $dashname + $dashkey;
$class: str-slice($dashclass, 2);
$utilities-map: map-merge(
$utilities-map,
(
// Create a normalized version of the utility definition.
$class: (
breakpoint: null,
properties: $properties,
value: $value,
),
)
);
@if map-get($utility, responsive) {
@each $dashpoint, $breakpoint in $breakpoints-map {
$class: str-slice($dashname + $dashpoint + $dashkey, 2);
$utilities-map: map-merge(
$utilities-map,
(
$class: (
breakpoint: $breakpoint,
properties: $properties,
value: $value,
)
)
);
}
}
}
}
}

@return $utilities-map;
}
35 changes: 35 additions & 0 deletions scss/tests/utilities/_mixin.test.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
@import "../../functions";
@import "../../variables";
@import "../../variables-dark";
@import "../../maps";
@import "../../mixins";
@import "../../utilities";
@import "../../utilities/api";

@include describe("utility mixin") {
@include it("generate property-value pairs for given utility") {

@include assert() {
@include output() {
.test {
@include util(d-block);
@include util(p-3);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should maybe introduce some tests including a responsive classes as well ? Same for local-var/css-var ?

}
.test2 {
@include util(d-block, p-3);
}
}

@include expect() {
.test {
display: block;
padding: 1rem;
}
.test2 {
display: block;
padding: 1rem;
}
}
}
}
}
91 changes: 60 additions & 31 deletions scss/utilities/_api.scss
Original file line number Diff line number Diff line change
@@ -1,47 +1,76 @@
// Loop over each breakpoint
@each $breakpoint in map-keys($grid-breakpoints) {

// Generate media query if needed
@include media-breakpoint-up($breakpoint) {
$infix: breakpoint-infix($breakpoint, $grid-breakpoints);

// Loop over each utility property
@each $key, $utility in $utilities {
// The utility can be disabled with `false`, thus check if the utility is a map first
// Only proceed if responsive media queries are enabled or if it's the base media query
@if type-of($utility) == "map" and (map-get($utility, responsive) or $infix == "") {
@include generate-utility($utility, $infix);
}
}
}
}

// RFS rescaling
@media (min-width: $rfs-mq-value) {
@if $enable-utility-classes {
// Loop over each breakpoint
@each $breakpoint in map-keys($grid-breakpoints) {
$infix: breakpoint-infix($breakpoint, $grid-breakpoints);
// Generate media query if needed
@include media-breakpoint-up($breakpoint) {
$infix: breakpoint-infix($breakpoint, $grid-breakpoints);

@if (map-get($grid-breakpoints, $breakpoint) < $rfs-breakpoint) {
// Loop over each utility property
@each $key, $utility in $utilities {
// The utility can be disabled with `false`, thus check if the utility is a map first
// Only proceed if responsive media queries are enabled or if it's the base media query
@if type-of($utility) == "map" and map-get($utility, rfs) and (map-get($utility, responsive) or $infix == "") {
@include generate-utility($utility, $infix, true);
@if type-of($utility) == "map" and (map-get($utility, responsive) or $infix == "") {
@include generate-utility($utility, $infix);
}
}
}
}

// RFS rescaling
@media (min-width: $rfs-mq-value) {
@each $breakpoint in map-keys($grid-breakpoints) {
$infix: breakpoint-infix($breakpoint, $grid-breakpoints);

@if (map-get($grid-breakpoints, $breakpoint) < $rfs-breakpoint) {
// Loop over each utility property
@each $key, $utility in $utilities {
// The utility can be disabled with `false`, thus check if the utility is a map first
// Only proceed if responsive media queries are enabled or if it's the base media query
@if type-of($utility) == "map" and map-get($utility, rfs) and (map-get($utility, responsive) or $infix == "") {
@include generate-utility($utility, $infix, true);
}
}
}
}
}


// Print utilities
@media print {
@each $key, $utility in $utilities {
// The utility can be disabled with `false`, thus check if the utility is a map first
// Then check if the utility needs print styles
@if type-of($utility) == "map" and map-get($utility, print) == true {
@include generate-utility($utility, "-print");
}
}
}
}

// Generate utility placeholders

$utilities-map: build-utilities-map(); // stylelint-disable-line scss/dollar-variable-default

// Print utilities
@media print {
@each $key, $utility in $utilities {
// The utility can be disabled with `false`, thus check if the utility is a map first
// Then check if the utility needs print styles
@if type-of($utility) == "map" and map-get($utility, print) == true {
@include generate-utility($utility, "-print");
@mixin util($classes...) {
@each $class in $classes {
@if map-has-key($utilities-map, $class) {
$definition: map-get($utilities-map, $class);
$breakpoint: map-get($definition, breakpoint);
@if $breakpoint != null {
@include media-breakpoint-up($breakpoint) {
@each $property in map-get($definition, properties) {
#{$property}: map-get($definition, value);
}
}
}
@else {
@each $property in map-get($definition, properties) {
#{$property}: map-get($definition, value);
}
}
}
@else {
@debug "Unknown utility class " + $class;
}
}
}
1 change: 1 addition & 0 deletions site/content/docs/5.3/customize/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ You can find and customize these variables for key global options in Bootstrap's
| `$enable-validation-icons` | `true` (default) or `false` | Enables `background-image` icons within textual inputs and some custom forms for validation states. |
| `$enable-negative-margins` | `true` or `false` (default) | Enables the generation of [negative margin utilities]({{< docsref "/utilities/spacing#negative-margin" >}}). |
| `$enable-deprecation-messages` | `true` (default) or `false` | Set to `false` to hide warnings when using any of the deprecated mixins and functions that are planned to be removed in `v6`. |
| `$enable-utility-classes` | `true` (default) or `false` | Enables the generation of utility classes. |
| `$enable-important-utilities` | `true` (default) or `false` | Enables the `!important` suffix in utility classes. |
| `$enable-smooth-scroll` | `true` (default) or `false` | Applies `scroll-behavior: smooth` globally, except for users asking for reduced motion through [`prefers-reduced-motion` media query]({{< docsref "/getting-started/accessibility#reduced-motion" >}}) |
{{< /bs-table >}}
Loading