From 24c779976aa290b28345b291a4c9558b19cba4d5 Mon Sep 17 00:00:00 2001 From: April Arcus Date: Wed, 2 Mar 2022 09:59:44 -0800 Subject: [PATCH 1/2] division: use twbs/rfs for forward compatibility with dart-sass 1.33+ --- package.json | 7 ++-- tasks/converter/less_conversion.rb | 62 +++++++++++++++++++++++------- 2 files changed, 52 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index 88f432110..705181e34 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bootstrap-sass", - "version": "3.4.3", + "version": "3.4.4", "description": "bootstrap-sass is a Sass-powered version of Bootstrap 3, ready to drop right into your Sass powered applications.", "main": "assets/javascripts/bootstrap.js", "style": "assets/stylesheets/_bootstrap.scss", @@ -33,9 +33,10 @@ "url": "https://github.com/twbs/bootstrap-sass/issues" }, "devDependencies": { - "sass": "^1.33", + "node-sass": "^4.9.3", "mincer": "~1.4.0", - "ejs": "~2.6.1" + "ejs": "~2.6.1", + "rfs": "^8.1.0 || ^9.0.4" }, "eyeglass": { "exports": "eyeglass-exports.js", diff --git a/tasks/converter/less_conversion.rb b/tasks/converter/less_conversion.rb index f28f4ee76..4b08148e4 100644 --- a/tasks/converter/less_conversion.rb +++ b/tasks/converter/less_conversion.rb @@ -43,8 +43,8 @@ module LessConversion ) # Convert a snippet of bootstrap LESS to Scss - def convert_less(less) - less = convert_to_scss(less) + def convert_less(less, filename) + less = convert_to_scss(less, filename) less = yield(less) if block_given? less end @@ -58,15 +58,22 @@ def shared_mixins end def process_stylesheet_assets + save_to = @save_to[:scss] + + log_status 'Copying vendor stylesheets...' + rfs_path = File.expand_path('../../node_modules/rfs/scss.scss', __dir__) + rfs_dest = File.expand_path("../vendor/_rfs.scss", save_to) + raise "Couldn't find `node_modules/rfs/`. Forgot to `npm install`?" unless File.exist? rfs_path + save_file rfs_dest, File.read(rfs_path) + log_status 'Processing stylesheets...' files = read_files('less', bootstrap_less_files) - save_to = @save_to[:scss] log_status ' Converting LESS files to Scss:' files.each do |name, file| log_processing name # apply common conversions - file = convert_less(file) + file = convert_less(file, name) file = replace_all file, %r{// stylelint-disable.*?\n+}, '', optional: true if name.start_with?('mixins/') file = varargify_mixin_definitions(file, *VARARG_MIXINS) @@ -157,7 +164,7 @@ def bootstrap_less_files end # apply general less to scss conversion - def convert_to_scss(file) + def convert_to_scss(file, name) # get local mixin names before converting the definitions mixins = shared_mixins + read_mixins(file) file = replace_vars(file) @@ -173,7 +180,7 @@ def convert_to_scss(file) file = replace_calculation_semantics(file) file = replace_file_imports(file) file = wrap_at_groups_with_at_root(file) - file = replace_division(file) + file = replace_division(file, name) file end @@ -183,16 +190,33 @@ def wrap_at_groups_with_at_root(file) } end - def replace_division(less) + def replace_division(less, filename) re = %r{ (? - (?[[:alpha:]\.]+)? - \( + # optional - might be a function call, + # or might be parenthesized expression. + (? + (?:[[:alpha:]_\-]+\.)? # namespace + [[:alpha:]_\-]+ # function + )? + \( # opening paren + # within the bounding parens (?: (?> + # an argument to divide can be (? - [^()/]+ + # an expression containing no nested parens + [^()]+ + | + # a color function + (rgba?|hsla?hwb|lab|lch|oklab|oklch|color)\(.*\) | + # or else, a function call or parenthesized expression, + ( + (?:[[:alpha:]_\-]+\.)? + [[:alpha:]_\-]+ + )? + # containing no nested legacy division operators \([^/]+\) ) \s+ @@ -201,22 +225,32 @@ def replace_division(less) (? [^()/]+ | + ( + (?:[[:alpha:]_\-]+\.)? + [[:alpha:]_\-]+ + )? \([^/]+\) ) ) | - \g + # if match fails, + \g # attempt recursively within the parens ) - \) + \) # closing paren ) }x return less if less !~ re - "@use \"sass:math\";\n" + less.gsub(re) do + path_to_rfs = [ + *Array.new(filename.split('/').length, '..'), + 'vendor', + 'rfs' + ].join('/') + "@import \"#{path_to_rfs}\";\n" + less.gsub(re) do named_captures = $~.named_captures callee = named_captures['callee'] dividend = named_captures['dividend'] divisor = named_captures['divisor'] - expression = "math.div(#{dividend}, #{divisor})" + expression = "divide(#{dividend}, #{divisor})" callee.nil? ? expression : "#{callee}(#{expression})" end end From 24caa6b38850be770a76b50e2ef115dfd7d0cf71 Mon Sep 17 00:00:00 2001 From: April Arcus Date: Wed, 2 Mar 2022 10:02:02 -0800 Subject: [PATCH 2/2] rake convert[v3.4.1] --- assets/stylesheets/bootstrap/_carousel.scss | 8 +- assets/stylesheets/bootstrap/_code.scss | 6 +- assets/stylesheets/bootstrap/_forms.scss | 4 +- assets/stylesheets/bootstrap/_jumbotron.scss | 8 +- assets/stylesheets/bootstrap/_navbar.scss | 4 +- assets/stylesheets/bootstrap/_type.scss | 20 +- assets/stylesheets/bootstrap/_variables.scss | 6 +- .../bootstrap/mixins/_grid-framework.scss | 14 +- .../stylesheets/bootstrap/mixins/_grid.scss | 58 +-- .../bootstrap/mixins/_nav-divider.scss | 4 +- .../bootstrap/mixins/_nav-vertical-align.scss | 6 +- assets/stylesheets/vendor/_rfs.scss | 354 ++++++++++++++++++ templates/project/_bootstrap-variables.sass | 6 +- 13 files changed, 426 insertions(+), 72 deletions(-) create mode 100644 assets/stylesheets/vendor/_rfs.scss diff --git a/assets/stylesheets/bootstrap/_carousel.scss b/assets/stylesheets/bootstrap/_carousel.scss index 684360ff8..8148438e6 100644 --- a/assets/stylesheets/bootstrap/_carousel.scss +++ b/assets/stylesheets/bootstrap/_carousel.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@import "../vendor/rfs"; // // Carousel // -------------------------------------------------- @@ -245,16 +245,16 @@ .icon-next { width: ($carousel-control-font-size * 1.5); height: ($carousel-control-font-size * 1.5); - margin-top: math.div($carousel-control-font-size, -2); + margin-top: divide($carousel-control-font-size, -2); font-size: ($carousel-control-font-size * 1.5); } .glyphicon-chevron-left, .icon-prev { - margin-left: math.div($carousel-control-font-size, -2); + margin-left: divide($carousel-control-font-size, -2); } .glyphicon-chevron-right, .icon-next { - margin-right: math.div($carousel-control-font-size, -2); + margin-right: divide($carousel-control-font-size, -2); } } diff --git a/assets/stylesheets/bootstrap/_code.scss b/assets/stylesheets/bootstrap/_code.scss index 6299ddbf3..37009e6c3 100644 --- a/assets/stylesheets/bootstrap/_code.scss +++ b/assets/stylesheets/bootstrap/_code.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@import "../vendor/rfs"; // // Code (inline and block) // -------------------------------------------------- @@ -41,8 +41,8 @@ kbd { // Blocks of code pre { display: block; - padding: math.div(($line-height-computed - 1), 2); - margin: 0 0 math.div($line-height-computed, 2); + padding: divide(($line-height-computed - 1), 2); + margin: 0 0 divide($line-height-computed, 2); font-size: ($font-size-base - 1); // 14px to 13px line-height: $line-height-base; color: $pre-color; diff --git a/assets/stylesheets/bootstrap/_forms.scss b/assets/stylesheets/bootstrap/_forms.scss index 00951b3f2..329104517 100644 --- a/assets/stylesheets/bootstrap/_forms.scss +++ b/assets/stylesheets/bootstrap/_forms.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@import "../vendor/rfs"; // // Forms // -------------------------------------------------- @@ -582,7 +582,7 @@ textarea.form-control { // Reposition the icon because it's now within a grid column and columns have // `position: relative;` on them. Also accounts for the grid gutter padding. .has-feedback .form-control-feedback { - right: floor(math.div($grid-gutter-width, 2)); + right: floor(divide($grid-gutter-width, 2)); } // Form group sizes diff --git a/assets/stylesheets/bootstrap/_jumbotron.scss b/assets/stylesheets/bootstrap/_jumbotron.scss index 07a0f98ff..c1426ddf8 100644 --- a/assets/stylesheets/bootstrap/_jumbotron.scss +++ b/assets/stylesheets/bootstrap/_jumbotron.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@import "../vendor/rfs"; // // Jumbotron // -------------------------------------------------- @@ -17,7 +17,7 @@ } p { - margin-bottom: math.div($jumbotron-padding, 2); + margin-bottom: divide($jumbotron-padding, 2); font-size: $jumbotron-font-size; font-weight: 200; } @@ -28,8 +28,8 @@ .container &, .container-fluid & { - padding-right: math.div($grid-gutter-width, 2); - padding-left: math.div($grid-gutter-width, 2); + padding-right: divide($grid-gutter-width, 2); + padding-left: divide($grid-gutter-width, 2); border-radius: $border-radius-large; // Only round corners at higher resolutions if contained in a container } diff --git a/assets/stylesheets/bootstrap/_navbar.scss b/assets/stylesheets/bootstrap/_navbar.scss index 135aba0ae..21381d159 100644 --- a/assets/stylesheets/bootstrap/_navbar.scss +++ b/assets/stylesheets/bootstrap/_navbar.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@import "../vendor/rfs"; // // Navbars // -------------------------------------------------- @@ -229,7 +229,7 @@ // the nav the full height of the horizontal nav (above 768px). .navbar-nav { - margin: math.div($navbar-padding-vertical, 2) (-$navbar-padding-horizontal); + margin: divide($navbar-padding-vertical, 2) (-$navbar-padding-horizontal); > li > a { padding-top: 10px; diff --git a/assets/stylesheets/bootstrap/_type.scss b/assets/stylesheets/bootstrap/_type.scss index ac2eccdc9..5b7bc5cb0 100644 --- a/assets/stylesheets/bootstrap/_type.scss +++ b/assets/stylesheets/bootstrap/_type.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@import "../vendor/rfs"; // // Typography // -------------------------------------------------- @@ -26,7 +26,7 @@ h1, .h1, h2, .h2, h3, .h3 { margin-top: $line-height-computed; - margin-bottom: math.div($line-height-computed, 2); + margin-bottom: divide($line-height-computed, 2); small, .small { @@ -36,8 +36,8 @@ h3, .h3 { h4, .h4, h5, .h5, h6, .h6 { - margin-top: math.div($line-height-computed, 2); - margin-bottom: math.div($line-height-computed, 2); + margin-top: divide($line-height-computed, 2); + margin-bottom: divide($line-height-computed, 2); small, .small { @@ -57,7 +57,7 @@ h6, .h6 { font-size: $font-size-h6; } // ------------------------- p { - margin: 0 0 math.div($line-height-computed, 2); + margin: 0 0 divide($line-height-computed, 2); } .lead { @@ -75,10 +75,10 @@ p { // Emphasis & misc // ------------------------- -// Ex: math.div(12px small font, 14px base font) * 100% = about 85% +// Ex: divide(12px small font, 14px base font) * 100% = about 85% small, .small { - font-size: floor(math.div(100% * $font-size-small, $font-size-base)); + font-size: floor(divide(100% * $font-size-small, $font-size-base)); } mark, @@ -137,7 +137,7 @@ mark, // ------------------------- .page-header { - padding-bottom: (math.div($line-height-computed, 2) - 1); + padding-bottom: (divide($line-height-computed, 2) - 1); margin: ($line-height-computed * 2) 0 $line-height-computed; border-bottom: 1px solid $page-header-border-color; } @@ -150,7 +150,7 @@ mark, ul, ol { margin-top: 0; - margin-bottom: math.div($line-height-computed, 2); + margin-bottom: divide($line-height-computed, 2); ul, ol { margin-bottom: 0; @@ -240,7 +240,7 @@ abbr[data-original-title] { // Blockquotes blockquote { - padding: math.div($line-height-computed, 2) $line-height-computed; + padding: divide($line-height-computed, 2) $line-height-computed; margin: 0 0 $line-height-computed; font-size: $blockquote-font-size; border-left: 5px solid $blockquote-border-color; diff --git a/assets/stylesheets/bootstrap/_variables.scss b/assets/stylesheets/bootstrap/_variables.scss index 02fe1f43b..6c0503dd0 100644 --- a/assets/stylesheets/bootstrap/_variables.scss +++ b/assets/stylesheets/bootstrap/_variables.scss @@ -1,5 +1,5 @@ $bootstrap-sass-asset-helper: false !default; -@use "sass:math"; +@import "../vendor/rfs"; // // Variables // -------------------------------------------------- @@ -366,8 +366,8 @@ $container-lg: $container-large-desktop !default; $navbar-height: 50px !default; $navbar-margin-bottom: $line-height-computed !default; $navbar-border-radius: $border-radius-base !default; -$navbar-padding-horizontal: floor(math.div($grid-gutter-width, 2)) !default; -$navbar-padding-vertical: math.div(($navbar-height - $line-height-computed), 2) !default; +$navbar-padding-horizontal: floor(divide($grid-gutter-width, 2)) !default; +$navbar-padding-vertical: divide(($navbar-height - $line-height-computed), 2) !default; $navbar-collapse-max-height: 340px !default; $navbar-default-color: #777 !default; diff --git a/assets/stylesheets/bootstrap/mixins/_grid-framework.scss b/assets/stylesheets/bootstrap/mixins/_grid-framework.scss index 6160a048e..7fa620eb4 100644 --- a/assets/stylesheets/bootstrap/mixins/_grid-framework.scss +++ b/assets/stylesheets/bootstrap/mixins/_grid-framework.scss @@ -1,4 +1,4 @@ -@use "sass:math"; +@import "../../vendor/rfs"; // Framework grid generation // // Used only by Bootstrap to generate the correct number of grid classes given @@ -14,8 +14,8 @@ // Prevent columns from collapsing when empty min-height: 1px; // Inner gutter via padding - padding-right: floor(math.div($grid-gutter-width, 2)); - padding-left: ceil(math.div($grid-gutter-width, 2)); + padding-right: floor(divide($grid-gutter-width, 2)); + padding-left: ceil(divide($grid-gutter-width, 2)); } } @@ -34,12 +34,12 @@ @mixin calc-grid-column($index, $class, $type) { @if ($type == width) and ($index > 0) { .col-#{$class}-#{$index} { - width: percentage(math.div($index, $grid-columns)); + width: percentage(divide($index, $grid-columns)); } } @if ($type == push) and ($index > 0) { .col-#{$class}-push-#{$index} { - left: percentage(math.div($index, $grid-columns)); + left: percentage(divide($index, $grid-columns)); } } @if ($type == push) and ($index == 0) { @@ -49,7 +49,7 @@ } @if ($type == pull) and ($index > 0) { .col-#{$class}-pull-#{$index} { - right: percentage(math.div($index, $grid-columns)); + right: percentage(divide($index, $grid-columns)); } } @if ($type == pull) and ($index == 0) { @@ -59,7 +59,7 @@ } @if ($type == offset) { .col-#{$class}-offset-#{$index} { - margin-left: percentage(math.div($index, $grid-columns)); + margin-left: percentage(divide($index, $grid-columns)); } } } diff --git a/assets/stylesheets/bootstrap/mixins/_grid.scss b/assets/stylesheets/bootstrap/mixins/_grid.scss index 0cee189a9..2b7edd059 100644 --- a/assets/stylesheets/bootstrap/mixins/_grid.scss +++ b/assets/stylesheets/bootstrap/mixins/_grid.scss @@ -1,12 +1,12 @@ -@use "sass:math"; +@import "../../vendor/rfs"; // Grid system // // Generate semantic grid columns with these mixins. // Centered container element @mixin container-fixed($gutter: $grid-gutter-width) { - padding-right: ceil(math.div($gutter, 2)); - padding-left: floor(math.div($gutter, 2)); + padding-right: ceil(divide($gutter, 2)); + padding-left: floor(divide($gutter, 2)); margin-right: auto; margin-left: auto; @include clearfix; @@ -14,8 +14,8 @@ // Creates a wrapper for a series of columns @mixin make-row($gutter: $grid-gutter-width) { - margin-right: floor(math.div($gutter, -2)); - margin-left: ceil(math.div($gutter, -2)); + margin-right: floor(divide($gutter, -2)); + margin-left: ceil(divide($gutter, -2)); @include clearfix; } @@ -23,46 +23,46 @@ @mixin make-xs-column($columns, $gutter: $grid-gutter-width) { position: relative; float: left; - width: percentage(math.div($columns, $grid-columns)); + width: percentage(divide($columns, $grid-columns)); min-height: 1px; - padding-right: math.div($gutter, 2); - padding-left: math.div($gutter, 2); + padding-right: divide($gutter, 2); + padding-left: divide($gutter, 2); } @mixin make-xs-column-offset($columns) { - margin-left: percentage(math.div($columns, $grid-columns)); + margin-left: percentage(divide($columns, $grid-columns)); } @mixin make-xs-column-push($columns) { - left: percentage(math.div($columns, $grid-columns)); + left: percentage(divide($columns, $grid-columns)); } @mixin make-xs-column-pull($columns) { - right: percentage(math.div($columns, $grid-columns)); + right: percentage(divide($columns, $grid-columns)); } // Generate the small columns @mixin make-sm-column($columns, $gutter: $grid-gutter-width) { position: relative; min-height: 1px; - padding-right: math.div($gutter, 2); - padding-left: math.div($gutter, 2); + padding-right: divide($gutter, 2); + padding-left: divide($gutter, 2); @media (min-width: $screen-sm-min) { float: left; - width: percentage(math.div($columns, $grid-columns)); + width: percentage(divide($columns, $grid-columns)); } } @mixin make-sm-column-offset($columns) { @media (min-width: $screen-sm-min) { - margin-left: percentage(math.div($columns, $grid-columns)); + margin-left: percentage(divide($columns, $grid-columns)); } } @mixin make-sm-column-push($columns) { @media (min-width: $screen-sm-min) { - left: percentage(math.div($columns, $grid-columns)); + left: percentage(divide($columns, $grid-columns)); } } @mixin make-sm-column-pull($columns) { @media (min-width: $screen-sm-min) { - right: percentage(math.div($columns, $grid-columns)); + right: percentage(divide($columns, $grid-columns)); } } @@ -70,27 +70,27 @@ @mixin make-md-column($columns, $gutter: $grid-gutter-width) { position: relative; min-height: 1px; - padding-right: math.div($gutter, 2); - padding-left: math.div($gutter, 2); + padding-right: divide($gutter, 2); + padding-left: divide($gutter, 2); @media (min-width: $screen-md-min) { float: left; - width: percentage(math.div($columns, $grid-columns)); + width: percentage(divide($columns, $grid-columns)); } } @mixin make-md-column-offset($columns) { @media (min-width: $screen-md-min) { - margin-left: percentage(math.div($columns, $grid-columns)); + margin-left: percentage(divide($columns, $grid-columns)); } } @mixin make-md-column-push($columns) { @media (min-width: $screen-md-min) { - left: percentage(math.div($columns, $grid-columns)); + left: percentage(divide($columns, $grid-columns)); } } @mixin make-md-column-pull($columns) { @media (min-width: $screen-md-min) { - right: percentage(math.div($columns, $grid-columns)); + right: percentage(divide($columns, $grid-columns)); } } @@ -98,26 +98,26 @@ @mixin make-lg-column($columns, $gutter: $grid-gutter-width) { position: relative; min-height: 1px; - padding-right: math.div($gutter, 2); - padding-left: math.div($gutter, 2); + padding-right: divide($gutter, 2); + padding-left: divide($gutter, 2); @media (min-width: $screen-lg-min) { float: left; - width: percentage(math.div($columns, $grid-columns)); + width: percentage(divide($columns, $grid-columns)); } } @mixin make-lg-column-offset($columns) { @media (min-width: $screen-lg-min) { - margin-left: percentage(math.div($columns, $grid-columns)); + margin-left: percentage(divide($columns, $grid-columns)); } } @mixin make-lg-column-push($columns) { @media (min-width: $screen-lg-min) { - left: percentage(math.div($columns, $grid-columns)); + left: percentage(divide($columns, $grid-columns)); } } @mixin make-lg-column-pull($columns) { @media (min-width: $screen-lg-min) { - right: percentage(math.div($columns, $grid-columns)); + right: percentage(divide($columns, $grid-columns)); } } diff --git a/assets/stylesheets/bootstrap/mixins/_nav-divider.scss b/assets/stylesheets/bootstrap/mixins/_nav-divider.scss index 80a39d43a..b57590975 100644 --- a/assets/stylesheets/bootstrap/mixins/_nav-divider.scss +++ b/assets/stylesheets/bootstrap/mixins/_nav-divider.scss @@ -1,11 +1,11 @@ -@use "sass:math"; +@import "../../vendor/rfs"; // Horizontal dividers // // Dividers (basically an hr) within dropdowns and nav lists @mixin nav-divider($color: #e5e5e5) { height: 1px; - margin: (math.div($line-height-computed, 2) - 1) 0; + margin: (divide($line-height-computed, 2) - 1) 0; overflow: hidden; background-color: $color; } diff --git a/assets/stylesheets/bootstrap/mixins/_nav-vertical-align.scss b/assets/stylesheets/bootstrap/mixins/_nav-vertical-align.scss index 146d9961c..dee111a49 100644 --- a/assets/stylesheets/bootstrap/mixins/_nav-vertical-align.scss +++ b/assets/stylesheets/bootstrap/mixins/_nav-vertical-align.scss @@ -1,10 +1,10 @@ -@use "sass:math"; +@import "../../vendor/rfs"; // Navbar vertical align // // Vertically center elements in the navbar. // Example: an element has a height of 30px, so write out `.navbar-vertical-align(30px);` to calculate the appropriate top margin. @mixin navbar-vertical-align($element-height) { - margin-top: math.div(($navbar-height - $element-height), 2); - margin-bottom: math.div(($navbar-height - $element-height), 2); + margin-top: divide(($navbar-height - $element-height), 2); + margin-bottom: divide(($navbar-height - $element-height), 2); } diff --git a/assets/stylesheets/vendor/_rfs.scss b/assets/stylesheets/vendor/_rfs.scss new file mode 100644 index 000000000..7e9a6c7a8 --- /dev/null +++ b/assets/stylesheets/vendor/_rfs.scss @@ -0,0 +1,354 @@ +// stylelint-disable property-blacklist, scss/dollar-variable-default + +// SCSS RFS mixin +// +// Automated responsive values for font sizes, paddings, margins and much more +// +// Licensed under MIT (https://github.com/twbs/rfs/blob/main/LICENSE) + +// Configuration + +// Base value +$rfs-base-value: 1.25rem !default; +$rfs-unit: rem !default; + +@if $rfs-unit != rem and $rfs-unit != px { + @error "`#{$rfs-unit}` is not a valid unit for $rfs-unit. Use `px` or `rem`."; +} + +// Breakpoint at where values start decreasing if screen width is smaller +$rfs-breakpoint: 1200px !default; +$rfs-breakpoint-unit: px !default; + +@if $rfs-breakpoint-unit != px and $rfs-breakpoint-unit != em and $rfs-breakpoint-unit != rem { + @error "`#{$rfs-breakpoint-unit}` is not a valid unit for $rfs-breakpoint-unit. Use `px`, `em` or `rem`."; +} + +// Resize values based on screen height and width +$rfs-two-dimensional: false !default; + +// Factor of decrease +$rfs-factor: 10 !default; + +@if type-of($rfs-factor) != number or $rfs-factor <= 1 { + @error "`#{$rfs-factor}` is not a valid $rfs-factor, it must be greater than 1."; +} + +// Mode. Possibilities: "min-media-query", "max-media-query" +$rfs-mode: min-media-query !default; + +// Generate enable or disable classes. Possibilities: false, "enable" or "disable" +$rfs-class: false !default; + +// 1 rem = $rfs-rem-value px +$rfs-rem-value: 16 !default; + +// Safari iframe resize bug: https://github.com/twbs/rfs/issues/14 +$rfs-safari-iframe-resize-bug-fix: false !default; + +// Disable RFS by setting $enable-rfs to false +$enable-rfs: true !default; + +// Cache $rfs-base-value unit +$rfs-base-value-unit: unit($rfs-base-value); + +@function divide($dividend, $divisor, $precision: 10) { + $sign: if($dividend > 0 and $divisor > 0 or $dividend < 0 and $divisor < 0, 1, -1); + $dividend: abs($dividend); + $divisor: abs($divisor); + @if $dividend == 0 { + @return 0; + } + @if $divisor == 0 { + @error "Cannot divide by 0"; + } + $remainder: $dividend; + $result: 0; + $factor: 10; + @while ($remainder > 0 and $precision >= 0) { + $quotient: 0; + @while ($remainder >= $divisor) { + $remainder: $remainder - $divisor; + $quotient: $quotient + 1; + } + $result: $result * 10 + $quotient; + $factor: $factor * .1; + $remainder: $remainder * 10; + $precision: $precision - 1; + @if ($precision < 0 and $remainder >= $divisor * 5) { + $result: $result + 1; + } + } + $result: $result * $factor * $sign; + $dividend-unit: unit($dividend); + $divisor-unit: unit($divisor); + $unit-map: ( + "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); + } + @return $result; +} + +// 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 { + $rfs-base-value: divide($rfs-base-value, divide($rfs-base-value * 0 + 1, $rfs-rem-value)); +} + +// Cache $rfs-breakpoint unit to prevent multiple calls +$rfs-breakpoint-unit-cache: 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" { + $rfs-breakpoint: divide($rfs-breakpoint, divide($rfs-breakpoint * 0 + 1, $rfs-rem-value)); +} + +// Calculate the media query value +$rfs-mq-value: if($rfs-breakpoint-unit == px, #{$rfs-breakpoint}px, #{divide($rfs-breakpoint, $rfs-rem-value)}#{$rfs-breakpoint-unit}); +$rfs-mq-property-width: if($rfs-mode == max-media-query, max-width, min-width); +$rfs-mq-property-height: if($rfs-mode == max-media-query, max-height, min-height); + +// Internal mixin used to determine which media query needs to be used +@mixin _rfs-media-query { + @if $rfs-two-dimensional { + @if $rfs-mode == max-media-query { + @media (#{$rfs-mq-property-width}: #{$rfs-mq-value}), (#{$rfs-mq-property-height}: #{$rfs-mq-value}) { + @content; + } + } + @else { + @media (#{$rfs-mq-property-width}: #{$rfs-mq-value}) and (#{$rfs-mq-property-height}: #{$rfs-mq-value}) { + @content; + } + } + } + @else { + @media (#{$rfs-mq-property-width}: #{$rfs-mq-value}) { + @content; + } + } +} + +// Internal mixin that adds disable classes to the selector if needed. +@mixin _rfs-rule { + @if $rfs-class == disable and $rfs-mode == max-media-query { + // Adding an extra class increases specificity, which prevents the media query to override the property + &, + .disable-rfs &, + &.disable-rfs { + @content; + } + } + @else if $rfs-class == enable and $rfs-mode == min-media-query { + .enable-rfs &, + &.enable-rfs { + @content; + } + } + @else { + @content; + } +} + +// 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 { + .enable-rfs &, + &.enable-rfs { + @content; + } + } + } + @else { + @if $rfs-class == disable and $rfs-mode == min-media-query { + .disable-rfs &, + &.disable-rfs { + @content; + } + } + @include _rfs-media-query { + @content; + } + } +} + +// Helper function to get the formatted non-responsive value +@function rfs-value($values) { + // Convert to list + $values: if(type-of($values) != list, ($values,), $values); + + $val: ''; + + // Loop over each value and calculate value + @each $value in $values { + @if $value == 0 { + $val: $val + ' 0'; + } + @else { + // Cache $value unit + $unit: if(type-of($value) == "number", unit($value), false); + + @if $unit == px { + // Convert to rem if needed + $val: $val + ' ' + if($rfs-unit == rem, #{divide($value, $value * 0 + $rfs-rem-value)}rem, $value); + } + @else if $unit == rem { + // Convert to px if needed + $val: $val + ' ' + if($rfs-unit == px, #{divide($value, $value * 0 + 1) * $rfs-rem-value}px, $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; + } + } + } + + // Remove first space + @return unquote(str-slice($val, 2)); +} + +// Helper function to get the responsive value calculated by RFS +@function rfs-fluid-value($values) { + // Convert to list + $values: if(type-of($values) != list, ($values,), $values); + + $val: ''; + + // Loop over each value and calculate value + @each $value in $values { + @if $value == 0 { + $val: $val + ' 0'; + } + + @else { + // Cache $value unit + $unit: if(type-of($value) == "number", unit($value), 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; + } + + @else { + // Remove unit from $value for calculations + $value: divide($value, $value * 0 + if($unit == px, 1, divide(1, $rfs-rem-value))); + + // Only add the media query if the value is greater than the minimum value + @if abs($value) <= $rfs-base-value or not $enable-rfs { + $val: $val + ' ' + if($rfs-unit == rem, #{divide($value, $rfs-rem-value)}rem, #{$value}px); + } + @else { + // Calculate the minimum value + $value-min: $rfs-base-value + divide(abs($value) - $rfs-base-value, $rfs-factor); + + // Calculate difference between $value and the minimum value + $value-diff: abs($value) - $value-min; + + // Base value formatting + $min-width: if($rfs-unit == rem, #{divide($value-min, $rfs-rem-value)}rem, #{$value-min}px); + + // Use negative value if needed + $min-width: if($value < 0, -$min-width, $min-width); + + // Use `vmin` if two-dimensional is enabled + $variable-unit: if($rfs-two-dimensional, vmin, vw); + + // Calculate the variable width between 0 and $rfs-breakpoint + $variable-width: #{divide($value-diff * 100, $rfs-breakpoint)}#{$variable-unit}; + + // Return the calculated value + $val: $val + ' calc(' + $min-width + if($value < 0, ' - ', ' + ') + $variable-width + ')'; + } + } + } + } + + // Remove first space + @return unquote(str-slice($val, 2)); +} + +// RFS mixin +@mixin rfs($values, $property: font-size) { + @if $values != null { + $val: rfs-value($values); + $fluidVal: rfs-fluid-value($values); + + // Do not print the media query if responsive & non-responsive values are the same + @if $val == $fluidVal { + #{$property}: $val; + } + @else { + @include _rfs-rule { + #{$property}: if($rfs-mode == max-media-query, $val, $fluidVal); + + // Include safari iframe resize fix if needed + min-width: if($rfs-safari-iframe-resize-bug-fix, (0 * 1vw), null); + } + + @include _rfs-media-query-rule { + #{$property}: if($rfs-mode == max-media-query, $fluidVal, $val); + } + } + } +} + +// Shorthand helper mixins +@mixin font-size($value) { + @include rfs($value); +} + +@mixin padding($value) { + @include rfs($value, padding); +} + +@mixin padding-top($value) { + @include rfs($value, padding-top); +} + +@mixin padding-right($value) { + @include rfs($value, padding-right); +} + +@mixin padding-bottom($value) { + @include rfs($value, padding-bottom); +} + +@mixin padding-left($value) { + @include rfs($value, padding-left); +} + +@mixin margin($value) { + @include rfs($value, margin); +} + +@mixin margin-top($value) { + @include rfs($value, margin-top); +} + +@mixin margin-right($value) { + @include rfs($value, margin-right); +} + +@mixin margin-bottom($value) { + @include rfs($value, margin-bottom); +} + +@mixin margin-left($value) { + @include rfs($value, margin-left); +} diff --git a/templates/project/_bootstrap-variables.sass b/templates/project/_bootstrap-variables.sass index d5bc1a14f..59b1bc18e 100644 --- a/templates/project/_bootstrap-variables.sass +++ b/templates/project/_bootstrap-variables.sass @@ -1,6 +1,6 @@ // Override Bootstrap variables here (defaults from bootstrap-sass v3.4.1): -@use "sass:math"; +@import "../vendor/rfs"; // // Variables // -------------------------------------------------- @@ -367,8 +367,8 @@ // $navbar-height: 50px // $navbar-margin-bottom: $line-height-computed // $navbar-border-radius: $border-radius-base -// $navbar-padding-horizontal: floor(math.div($grid-gutter-width, 2)) -// $navbar-padding-vertical: math.div(($navbar-height - $line-height-computed), 2) +// $navbar-padding-horizontal: floor(divide($grid-gutter-width, 2)) +// $navbar-padding-vertical: divide(($navbar-height - $line-height-computed), 2) // $navbar-collapse-max-height: 340px // $navbar-default-color: #777