diff options
Diffstat (limited to 'src/_functions.scss')
-rw-r--r-- | src/_functions.scss | 328 |
1 files changed, 328 insertions, 0 deletions
diff --git a/src/_functions.scss b/src/_functions.scss new file mode 100644 index 0000000..2f34dc4 --- /dev/null +++ b/src/_functions.scss | |||
@@ -0,0 +1,328 @@ | |||
1 | //// | ||
2 | /// Various functions. | ||
3 | /// | ||
4 | /// This file contains various and mostly unrelated functions. Some of which | ||
5 | /// are used in this framework, while others are just there and may be used. | ||
6 | /// | ||
7 | /// @group Functions | ||
8 | /// | ||
9 | /// @access public | ||
10 | //// | ||
11 | |||
12 | /// | ||
13 | /// Replace a substring with a new string. | ||
14 | /// | ||
15 | /// @param {string} $string - String to search | ||
16 | /// @param {string} $search - Substring that gets replaced | ||
17 | /// @param {string} $replace - String that replaces $search | ||
18 | /// | ||
19 | /// @return {string} A string with all instances of $search replaced with $replace | ||
20 | /// | ||
21 | @function iro-str-replace($string, $search, $replace) { | ||
22 | $index: str-index($string, $search); | ||
23 | |||
24 | @if $index { | ||
25 | @return str-slice($string, 1, $index - 1) + $replace + iro-str-replace(str-slice($string, $index + str-length($search)), $search, $replace); | ||
26 | } | ||
27 | |||
28 | @return $string; | ||
29 | } | ||
30 | |||
31 | /// | ||
32 | /// Concatenate all items from $list. | ||
33 | /// | ||
34 | /// @param {list} $list | ||
35 | /// @param {number} $glue - Delimiter | ||
36 | /// | ||
37 | /// @return {string} | ||
38 | /// | ||
39 | @function iro-str-implode($list, $glue: '') { | ||
40 | $result: ''; | ||
41 | |||
42 | @each $item in $list { | ||
43 | $result: $result + if(length($item) > 1, iro-str-implode($item, $glue), $item); | ||
44 | |||
45 | @if $item != nth($list, length($list)) { | ||
46 | $result: $result + $glue; | ||
47 | } | ||
48 | } | ||
49 | |||
50 | @return $result; | ||
51 | } | ||
52 | |||
53 | /// | ||
54 | /// Extract a subset from the given list. | ||
55 | /// | ||
56 | /// @param {list} $list | ||
57 | /// @param {number} $start [1] - Indices before this value will be discarded | ||
58 | /// @param {number} $end [length($list)] - Indices starting after this value will be discarded | ||
59 | /// | ||
60 | /// @return {list} A slice of the list | ||
61 | /// | ||
62 | @function iro-list-slice($list, $start: 1, $end: length($list)) { | ||
63 | $result: (); | ||
64 | |||
65 | @for $i from $start through $end { | ||
66 | @if $i != 0 { | ||
67 | $result: append($result, nth($list, $i), list-separator($list)); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | @return $result; | ||
72 | } | ||
73 | |||
74 | /// | ||
75 | /// Add a new item to the beginning of a list. | ||
76 | /// | ||
77 | /// @param {list} $list | ||
78 | /// @param {number} $value | ||
79 | /// | ||
80 | /// @return {list} A list with $value at the beginning, followed by the other items | ||
81 | /// | ||
82 | @function iro-list-prepend($list, $value) { | ||
83 | $result: append((), $value, list-separator($list)); | ||
84 | |||
85 | @if length($list) > 0 { | ||
86 | @for $i from 1 through length($list) { | ||
87 | $result: append($result, nth($list, $i), list-separator($list)); | ||
88 | } | ||
89 | } | ||
90 | |||
91 | @return $result; | ||
92 | } | ||
93 | |||
94 | /// | ||
95 | /// Sort numeric items in a list. | ||
96 | /// | ||
97 | /// The implementation is based on the algorithm on the German Wikipedia article | ||
98 | /// about quicksort: https://de.wikipedia.org/wiki/Quicksort#Pseudocode | ||
99 | /// | ||
100 | /// @param {list} $l | ||
101 | /// | ||
102 | /// @return {list} Sorted list | ||
103 | /// | ||
104 | @function iro-quicksort($l, $left: 1, $right: length($l)) { | ||
105 | @if $left < $right { | ||
106 | $pvr: iro-quicksort-partition($l, $left, $right); | ||
107 | $pivot: nth($pvr, 1); | ||
108 | $l: nth($pvr, 2); | ||
109 | $l: iro-quicksort($l, $left, $pivot); | ||
110 | $l: iro-quicksort($l, $pivot + 1, $right); | ||
111 | } | ||
112 | |||
113 | @return $l; | ||
114 | } | ||
115 | |||
116 | /// | ||
117 | /// @access private | ||
118 | /// | ||
119 | @function iro-quicksort-partition($l, $left, $right) { | ||
120 | $start: true; | ||
121 | $i: $left; | ||
122 | $j: $right - 1; | ||
123 | $pivot: nth($l, $right); | ||
124 | |||
125 | @while ($i < $j) or $start { | ||
126 | @while (nth($l, $i) < $pivot) and ($i < $right - 1) { | ||
127 | $i: $i + 1; | ||
128 | } | ||
129 | |||
130 | @while (nth($l, $j)>= $pivot) and ($j > $left) { | ||
131 | $j: $j - 1; | ||
132 | } | ||
133 | |||
134 | @if $i < $j { | ||
135 | $i-val: nth($l, $i); | ||
136 | $l: set-nth($l, $i, nth($l, $j)); | ||
137 | $l: set-nth($l, $j, $i-val); | ||
138 | } | ||
139 | |||
140 | $start: false; | ||
141 | } | ||
142 | |||
143 | @if nth($l, $i) > $pivot { | ||
144 | $i-val: nth($l, $i); | ||
145 | $l: set-nth($l, $i, nth($l, $right)); | ||
146 | $l: set-nth($l, $right, $i-val); | ||
147 | } | ||
148 | |||
149 | @return $i $l; | ||
150 | } | ||
151 | |||
152 | /// | ||
153 | /// Try to get the value for the given key from the given map. If it doesn't contain that key, | ||
154 | /// return the provided default value instead. | ||
155 | /// | ||
156 | /// @param {map} $map | ||
157 | /// @param {string} $key | ||
158 | /// @param {any} $default | ||
159 | /// | ||
160 | /// @return {any} Either the value assigned to $key or $default | ||
161 | /// | ||
162 | @function iro-map-get-default($map, $key, $default) { | ||
163 | @return if(map-has-key($map, $key), map-get($map, $key), $default); | ||
164 | } | ||
165 | |||
166 | /// | ||
167 | /// Get the value for a map within a map (or deeper). | ||
168 | /// | ||
169 | /// @param {map} $map | ||
170 | /// @param {string | list} $key | ||
171 | /// @param {any} $default [null] | ||
172 | /// | ||
173 | /// @return {any} Either the value assigned to $key or $default | ||
174 | /// | ||
175 | @function iro-map-get-deep($map, $key, $default: null) { | ||
176 | $value: null; | ||
177 | |||
178 | @if type-of($key) == list { | ||
179 | $value: $map; | ||
180 | |||
181 | @each $k in $key { | ||
182 | $value: map-get($value, $k); | ||
183 | |||
184 | @if $value == null { | ||
185 | @return $default; | ||
186 | } | ||
187 | } | ||
188 | } @else { | ||
189 | $value: map-get($map, $key); | ||
190 | |||
191 | @if $value == null { | ||
192 | @return $default; | ||
193 | } | ||
194 | } | ||
195 | |||
196 | @return $value; | ||
197 | } | ||
198 | |||
199 | /// | ||
200 | /// Merge two maps recursively. | ||
201 | /// | ||
202 | /// @param {map} $map1 | ||
203 | /// @param {map} $map2 | ||
204 | /// | ||
205 | /// @return {map} The result of a recursive merge of $map1 and $map2 | ||
206 | /// | ||
207 | @function iro-map-merge-recursive($map1, $map2) { | ||
208 | @if type-of($map1) != map or type-of($map2) != map { | ||
209 | @error 'Two maps expected.'; | ||
210 | } | ||
211 | |||
212 | $result: $map1; | ||
213 | |||
214 | @each $key, $value in $map2 { | ||
215 | @if type-of(map-get($result, $key)) == map and type-of($value) == map { | ||
216 | $result: map-merge($result, ($key: iro-map-merge-recursive(map-get($result, $key), $value))); | ||
217 | } @else { | ||
218 | $result: map-merge($result, ($key: $value)); | ||
219 | } | ||
220 | } | ||
221 | |||
222 | @return $result; | ||
223 | } | ||
224 | |||
225 | /// | ||
226 | /// Get the contents of a map as a user-friendly string representation. | ||
227 | /// | ||
228 | /// @param {map} $map | ||
229 | /// | ||
230 | /// @return {string} | ||
231 | /// | ||
232 | @function iro-map-print($map) { | ||
233 | $output: ''; | ||
234 | |||
235 | @each $key, $value in $map { | ||
236 | $value-str: ''; | ||
237 | |||
238 | @if type-of($value) == map { | ||
239 | $value-str: '[ ' + iro-map-print($value) + ' ]'; | ||
240 | } @else if type-of($value) == list { | ||
241 | $value-str: '[ ' + iro-str-implode($value, ', ') + ' ]'; | ||
242 | } @else if type-of($value) == string { | ||
243 | $value-str: '\'' + $value + '\''; | ||
244 | } @else { | ||
245 | $value-str: $value; | ||
246 | } | ||
247 | |||
248 | @if $output == '' { | ||
249 | $output: $key + ': ' + $value-str; | ||
250 | } @else { | ||
251 | $output: $output + ', ' + $key + ': ' + $value-str; | ||
252 | } | ||
253 | } | ||
254 | |||
255 | @return $output; | ||
256 | } | ||
257 | |||
258 | /// | ||
259 | /// Check if the given selector ends with one of the provided suffixes. | ||
260 | /// | ||
261 | /// @param {selector} $selector | ||
262 | /// @param {selector} $suffixes | ||
263 | /// | ||
264 | /// @return {bool} `true` if the selector matches at least one suffix, otherwise `false`. | ||
265 | /// | ||
266 | @function iro-selector-suffix-match($selector, $suffixes) { | ||
267 | $match: true; | ||
268 | |||
269 | @each $sel in $selector { | ||
270 | @if $match { | ||
271 | $sel-match: false; | ||
272 | |||
273 | @each $suffix in $suffixes { | ||
274 | @if not $sel-match { | ||
275 | $suf-match: true; | ||
276 | |||
277 | @for $i from 1 through length($suffix) { | ||
278 | @if $suf-match and (nth($sel, -$i) != nth($suffix, -$i)) { | ||
279 | $suf-match: false; | ||
280 | } | ||
281 | } | ||
282 | |||
283 | @if $suf-match { | ||
284 | $sel-match: true; | ||
285 | } | ||
286 | } | ||
287 | } | ||
288 | |||
289 | @if not $sel-match { | ||
290 | $match: false; | ||
291 | } | ||
292 | } | ||
293 | } | ||
294 | |||
295 | @return $match; | ||
296 | } | ||
297 | |||
298 | /// | ||
299 | /// Remove the unit from any variable. | ||
300 | /// | ||
301 | /// @param {any} $n | ||
302 | /// | ||
303 | /// @return {number} Unit-less variable | ||
304 | /// | ||
305 | @function iro-strip-unit($n) { | ||
306 | @return $n / ($n * 0 + 1); | ||
307 | } | ||
308 | |||
309 | /// | ||
310 | /// Convert a pixel value to a rem value. | ||
311 | /// | ||
312 | /// @param {number} $size - Pixel value to convert | ||
313 | /// @param {number} $base [$iro-root-size] - Reference base font size used for conversion | ||
314 | /// | ||
315 | /// @return {number} Pixel value converted to rem | ||
316 | /// | ||
317 | @function iro-px-to-rem($size, $base: $iro-root-size) { | ||
318 | @return $size / $base * 1rem; | ||
319 | } | ||
320 | |||
321 | /// | ||
322 | /// A mixin with the sole purpose of letting you use temporary variables without polluting the global namespace. | ||
323 | /// | ||
324 | /// @content | ||
325 | /// | ||
326 | @mixin iro-execute { | ||
327 | @content; | ||
328 | } | ||