//// /// Various functions. /// /// This file contains various and mostly unrelated functions. Some of which /// are used in this framework, while others are just there and may be used. /// /// @group Functions /// /// @access public //// /// /// Replace a substring with a new string. /// /// @param {string} $string - String to search /// @param {string} $search - Substring that gets replaced /// @param {string} $replace - String that replaces $search /// /// @return {string} A string with all instances of $search replaced with $replace /// @function iro-str-replace($string, $search, $replace) { $index: str-index($string, $search); @if $index { @return str-slice($string, 1, $index - 1) + $replace + iro-str-replace(str-slice($string, $index + str-length($search)), $search, $replace); } @return $string; } /// /// Concatenate all items from $list. /// /// @param {list} $list /// @param {number} $glue - Delimiter /// /// @return {string} /// @function iro-str-implode($list, $glue: '') { $result: ''; @each $item in $list { $result: $result + if(length($item) > 1, iro-str-implode($item, $glue), $item); @if $item != nth($list, length($list)) { $result: $result + $glue; } } @return $result; } /// /// Extract a subset from the given list. /// /// @param {list} $list /// @param {number} $start [1] - Indices before this value will be discarded /// @param {number} $end [length($list)] - Indices starting after this value will be discarded /// /// @return {list} A slice of the list /// @function iro-list-slice($list, $start: 1, $end: length($list)) { $result: (); @for $i from $start through $end { @if $i != 0 { $result: append($result, nth($list, $i), list-separator($list)); } } @return $result; } /// /// Add a new item to the beginning of a list. /// /// @param {list} $list /// @param {number} $value /// /// @return {list} A list with $value at the beginning, followed by the other items /// @function iro-list-prepend($list, $value) { $result: append((), $value, list-separator($list)); @if length($list) > 0 { @for $i from 1 through length($list) { $result: append($result, nth($list, $i), list-separator($list)); } } @return $result; } /// /// Sort numeric items in a list. /// /// The implementation is based on the algorithm on the German Wikipedia article /// about quicksort: https://de.wikipedia.org/wiki/Quicksort#Pseudocode /// /// @param {list} $l /// /// @return {list} Sorted list /// @function iro-quicksort($l, $left: 1, $right: length($l)) { @if $left < $right { $pvr: iro-quicksort-partition($l, $left, $right); $pivot: nth($pvr, 1); $l: nth($pvr, 2); $l: iro-quicksort($l, $left, $pivot); $l: iro-quicksort($l, $pivot + 1, $right); } @return $l; } /// /// @access private /// @function iro-quicksort-partition($l, $left, $right) { $start: true; $i: $left; $j: $right - 1; $pivot: nth($l, $right); @while ($i < $j) or $start { @while (nth($l, $i) < $pivot) and ($i < $right - 1) { $i: $i + 1; } @while (nth($l, $j)>= $pivot) and ($j > $left) { $j: $j - 1; } @if $i < $j { $i-val: nth($l, $i); $l: set-nth($l, $i, nth($l, $j)); $l: set-nth($l, $j, $i-val); } $start: false; } @if nth($l, $i) > $pivot { $i-val: nth($l, $i); $l: set-nth($l, $i, nth($l, $right)); $l: set-nth($l, $right, $i-val); } @return $i $l; } /// /// Try to get the value for the given key from the given map. If it doesn't contain that key, /// return the provided default value instead. /// /// @param {map} $map /// @param {string} $key /// @param {any} $default /// /// @return {any} Either the value assigned to $key or $default /// @function iro-map-get-default($map, $key, $default) { @return if(map-has-key($map, $key), map-get($map, $key), $default); } /// /// Get the value for a map within a map (or deeper). /// /// @param {map} $map /// @param {string | list} $key /// @param {any} $default [null] /// /// @return {any} Either the value assigned to $key or $default /// @function iro-map-get-deep($map, $key, $default: null) { $value: null; @if type-of($key) == list { $value: $map; @each $k in $key { $value: map-get($value, $k); @if $value == null { @return $default; } } } @else { $value: map-get($map, $key); @if $value == null { @return $default; } } @return $value; } /// /// Merge two maps recursively. /// /// @param {map} $map1 /// @param {map} $map2 /// /// @return {map} The result of a recursive merge of $map1 and $map2 /// @function iro-map-merge-recursive($map1, $map2) { @if type-of($map1) != map or type-of($map2) != map { @error 'Two maps expected.'; } $result: $map1; @each $key, $value in $map2 { @if type-of(map-get($result, $key)) == map and type-of($value) == map { $result: map-merge($result, ($key: iro-map-merge-recursive(map-get($result, $key), $value))); } @else { $result: map-merge($result, ($key: $value)); } } @return $result; } /// /// Get the contents of a map as a user-friendly string representation. /// /// @param {map} $map /// /// @return {string} /// @function iro-map-print($map) { $output: ''; @each $key, $value in $map { $value-str: ''; @if type-of($value) == map { $value-str: '[ ' + iro-map-print($value) + ' ]'; } @else if type-of($value) == list { $value-str: '[ ' + iro-str-implode($value, ', ') + ' ]'; } @else if type-of($value) == string { $value-str: '\'' + $value + '\''; } @else { $value-str: $value; } @if $output == '' { $output: $key + ': ' + $value-str; } @else { $output: $output + ', ' + $key + ': ' + $value-str; } } @return $output; } /// /// Check if the given selector ends with one of the provided suffixes. /// /// @param {selector} $selector /// @param {selector} $suffixes /// /// @return {bool} `true` if the selector matches at least one suffix, otherwise `false`. /// @function iro-selector-suffix-match($selector, $suffixes) { $match: true; @each $sel in $selector { @if $match { $sel-match: false; @each $suffix in $suffixes { @if not $sel-match { $suf-match: true; @for $i from 1 through length($suffix) { @if $suf-match and (nth($sel, -$i) != nth($suffix, -$i)) { $suf-match: false; } } @if $suf-match { $sel-match: true; } } } @if not $sel-match { $match: false; } } } @return $match; } /// /// Remove the unit from any variable. /// /// @param {any} $n /// /// @return {number} Unit-less variable /// @function iro-strip-unit($n) { @return $n / ($n * 0 + 1); } /// /// Convert a pixel value to a rem value. /// /// @param {number} $size - Pixel value to convert /// @param {number} $base [$iro-root-size] - Reference base font size used for conversion /// /// @return {number} Pixel value converted to rem /// @function iro-px-to-rem($size, $base: $iro-root-size) { @return $size / $base * 1rem; } /// /// A mixin with the sole purpose of letting you use temporary variables without polluting the global namespace. /// /// @content /// @mixin iro-execute { @content; }