Created
November 4, 2013 08:52
-
-
Save jakob-e/7299875 to your computer and use it in GitHub Desktop.
SassyLists by Hugo Giraudel - http://hugogiraudel.com/2013/08/08/advanced-sass-list-functions/
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Chunks $list into $size large lists | |
// ------------------------------------------------------------------------------- | |
// @documentation http://sassylists.com/documentation/#chunk | |
// ------------------------------------------------------------------------------- | |
// @example chunk(a b c d e, 2) => a b, c d, e | |
// @example chunk(a b c d e, 3) => a b c, d e | |
// ------------------------------------------------------------------------------- | |
// @param $list [List] : list | |
// @param $size [Number] : length of lists | |
// ------------------------------------------------------------------------------- | |
// @return [List] | |
@function chunk($list, $size) { | |
$n-lists: ceil(length($list) / $size); | |
$tmp-index: 0; | |
$result: (); | |
@for $i from 1 through $n-lists { | |
$tmp-list: (); | |
@for $j from 1 + $tmp-index through $size + $tmp-index { | |
@if $j <= length($list) { | |
$tmp-list: append($tmp-list, nth($list, $j)); | |
} | |
} | |
$result: append($result, $tmp-list); | |
$tmp-index: $tmp-index + $size; | |
} | |
@return $result; | |
} | |
// Counts the number of occurrences of each value of $list | |
// ------------------------------------------------------------------------------- | |
// @documentation http://sassylists.com/documentation/#count-values | |
// ------------------------------------------------------------------------------- | |
// @dependence `replace-nth()` | |
// ------------------------------------------------------------------------------- | |
// @example count-values(a b c d e) => a 1, b 1, c 1, d 1, e 1 | |
// @example count-values(a b c a d b a e) => a 3, b 2, c 1, d 1, e 1 | |
// ------------------------------------------------------------------------------- | |
// @param $list [List] : list | |
// ------------------------------------------------------------------------------- | |
// @return [List] | |
@function count-values($list) { | |
$keys : (); | |
$counts : (); | |
@each $item in $list { | |
$index: index($keys, $item); | |
@if not $index { | |
$keys : append($keys, $item); | |
$counts : append($counts, 1); | |
} | |
@else { | |
$count : nth($counts, $index) + 1; | |
$counts : replace-nth($counts, $index, $count); | |
} | |
} | |
@return zip($keys, $counts); | |
} | |
// Returns first element of $list | |
// ------------------------------------------------------------------------------- | |
// @documentation http://sassylists.com/documentation/#first | |
// ------------------------------------------------------------------------------- | |
// @example first(a b c) => a | |
// ------------------------------------------------------------------------------- | |
// @param $list [List] : list | |
// ------------------------------------------------------------------------------- | |
// @return [Literal] | |
@function first($list) { | |
@return nth($list, 1); | |
} | |
// Adds $value at $index in $list | |
// ------------------------------------------------------------------------------- | |
// @documentation http://sassylists.com/documentation/#insert-nth | |
// ------------------------------------------------------------------------------- | |
// @dependence `purge()` | |
// ------------------------------------------------------------------------------- | |
// @example insert-nth(a b c, 2, z) => a, z, b, c | |
// @example insert-nth(a b c, 0, z) => error | |
// @example insert-nth(a b c, -1, z) => error | |
// @example insert-nth(a b c, 10, z) => error | |
// ------------------------------------------------------------------------------- | |
// @param $list [List] : list | |
// @param $index [Number] : index to add | |
// @param $value [Literal] : value to add | |
// ------------------------------------------------------------------------------- | |
// @raise [Error] if $index isn't an integer | |
// @raise [Error] if $index is strictly lesser than 1 | |
// @raise [Error] if $index is strictly greater than length of $list | |
// ------------------------------------------------------------------------------- | |
// @return [List] | false | |
@function insert-nth($list, $index, $value) { | |
$result: false; | |
@if type-of($index) != number { | |
@warn "List index #{quote($index)} is not a number for `insert-nth`."; | |
@return $result; | |
} | |
@else if $index < 1 { | |
@warn "List index #{quote($index)} must be a non-zero integer for `insert-nth`"; | |
@return $result; | |
} | |
@else if $index > length($list) { | |
@warn "List index is #{quote($index)} but list is only #{length($list)} items long for `insert-nth'."; | |
@return $result; | |
} | |
@else { | |
$result: (); | |
@for $i from 1 through length($list) { | |
@if $i == $index { | |
$result: append($result, $value); | |
} | |
$result: append($result, nth($list, $i)); | |
} | |
} | |
@return purge($result); | |
} | |
// Checks whether $list is symmetrical (one-level deep) | |
// ------------------------------------------------------------------------------- | |
// @documentation http://sassylists.com/documentation/#is-symmetrical | |
// ------------------------------------------------------------------------------- | |
// @dependence `reverse()` | |
// ------------------------------------------------------------------------------- | |
// @example is-symmetrical(a b c d e) => false | |
// @example is-symmetrical(a b c b a) => true | |
// @example is-symmetrical(a (b c d) a) => true | |
// ------------------------------------------------------------------------------- | |
// @param $list [List] : list | |
// ------------------------------------------------------------------------------- | |
// @return [Boolean] | |
@function is-symmetrical($list) { | |
@return reverse($list) == reverse(reverse($list)); | |
} | |
// Returns last index of $value in $list | |
// ------------------------------------------------------------------------------- | |
// @documentation http://sassylists.com/documentation/#last-index | |
// ------------------------------------------------------------------------------- | |
// @example last-index(a b c a, a) => 4 | |
// @example last-index(a b c, z) => null | |
// ------------------------------------------------------------------------------- | |
// @param $list [List] : list | |
// @param $value [Literal] : value to be searched for | |
// ------------------------------------------------------------------------------- | |
// @return [Number] | null | |
@function last-index($list, $value) { | |
@for $i from length($list) * -1 through -1 { | |
$i: abs($i); | |
@if nth($list, $i) == $value { | |
@return $i; | |
} | |
} | |
@return null; | |
} | |
// Returns last element of $list | |
// ------------------------------------------------------------------------------- | |
// @documentation http://sassylists.com/documentation/#last | |
// ------------------------------------------------------------------------------- | |
// @example last(a b c) => c | |
// ------------------------------------------------------------------------------- | |
// @param $list [List] : list | |
// ------------------------------------------------------------------------------- | |
// @return [Literal] | |
@function last($list) { | |
@return nth($list, length($list)); | |
} | |
// Shift indexes from $list of $value | |
// ------------------------------------------------------------------------------- | |
// @documentation http://sassylists.com/documentation/#loop | |
// ------------------------------------------------------------------------------- | |
// @example loop(a b c d e) => e, a, b, c, d | |
// @example loop(a b c d e, 2) => d, e, a, b, c | |
// @example loop(a b c d e, -2) => c, d, e, a, b | |
// ------------------------------------------------------------------------------- | |
// @param $list [List] : list | |
// @param $value [Number] : number of position between old and new indexes | |
// ------------------------------------------------------------------------------- | |
// @return [List] | |
@function loop($list, $value: 1) { | |
$result: (); | |
@for $i from 0 to length($list) { | |
$result: append($result, nth($list, ($i - $value) % length($list) + 1)); | |
} | |
@return $result; | |
} | |
// Adds $value as first index of $list | |
// ------------------------------------------------------------------------------- | |
// @documentation http://sassylists.com/documentation/#prepend | |
// ------------------------------------------------------------------------------- | |
// @dependence `purge()` | |
// ------------------------------------------------------------------------------- | |
// @example prepend(a b c, z) => z, a, b, c | |
// @example prepend(a b c, y z) => y z, a, b, c | |
// ------------------------------------------------------------------------------- | |
// @param $list [List] : list | |
// @param $value [Literal] : value to prepend to the list | |
// ------------------------------------------------------------------------------- | |
// @return [List] | |
@function prepend($list, $value) { | |
@return purge(join($value, $list)); | |
} | |
// Removes all false and null values from $list | |
// ------------------------------------------------------------------------------- | |
// @documentation http://sassylists.com/documentation.html#purge | |
// ------------------------------------------------------------------------------- | |
// @example purge(a null b false c) => a, b, c | |
// @example purge(a b c) => a, b, c | |
// ------------------------------------------------------------------------------- | |
// @param $list [List] : list | |
// ------------------------------------------------------------------------------- | |
// @return [List] | |
@function purge($list) { | |
$result: (); | |
@each $item in $list { | |
@if $item != null and $item != false and $item != "" { | |
$result: append($result, $item); | |
} | |
} | |
@return $result; | |
} | |
// Returns a random value of $list | |
// ------------------------------------------------------------------------------- | |
// @documentation http://sassylists.com/documentation.html#random-value | |
// ------------------------------------------------------------------------------- | |
// @dependence `rand` (Ruby) | |
// ------------------------------------------------------------------------------- | |
// @example random-value(a b c d e) => c | |
// ------------------------------------------------------------------------------- | |
// @param $list [List] : List | |
// ------------------------------------------------------------------------------- | |
// @return [Literal] | |
@function random-value($list) { | |
@return nth($list, random(length($list)) + 1); | |
} | |
// Removes duplicate values from $list | |
// ------------------------------------------------------------------------------- | |
// @documentation http://sassylists.com/documentation/#remove-duplicates | |
// ------------------------------------------------------------------------------- | |
// @example remove-duplicates(a b a c b d c e) => a, b, c, d, e | |
// @example remove-duplicates(a b (c c c), true) => a, b, c | |
// ------------------------------------------------------------------------------- | |
// @param $list [List] : list | |
// @param $recursive [Boolean] : enable / disable recursivity | |
// ------------------------------------------------------------------------------- | |
// @return [List] | |
@function remove-duplicates($list, $recursive: false) { | |
$result: (); | |
@each $item in $list { | |
@if not index($result, $item) { | |
@if length($item) > 1 and $recursive { | |
$result: append($result, remove-duplicates($item, $recursive)); | |
} | |
@else { | |
$result: append($result, $item); | |
} | |
} | |
} | |
@return $result; | |
} | |
// Removes value from $list at index $index | |
// ------------------------------------------------------------------------------- | |
// @documentation http://sassylists.com/documentation/#remove-nth | |
// ------------------------------------------------------------------------------- | |
// @dependence `replace-nth()` | |
// ------------------------------------------------------------------------------- | |
// @example remove-nth(a b c, 2) => a, c | |
// @example remove-nth(a b c, 0) => error | |
// @example remove-nth(a b c, -1) => a, b | |
// @example remove-nth(a b c, 10) => error | |
// @example remove-nth(a b c, -10) => error | |
// ------------------------------------------------------------------------------- | |
// @param $list [List] : list | |
// @param $index [Number] : index to remove | |
// ------------------------------------------------------------------------------- | |
// @raise [Error] if $index isn't an integer | |
// @raise [Error] if $index is 0 | |
// @raise [Error] if abs value of $index is strictly greater then length of $list | |
// ------------------------------------------------------------------------------- | |
// @return [List] | false | |
@function remove-nth($list, $index) { | |
@return replace-nth($list, $index, ""); | |
} | |
// Removes value(s) $value from $list | |
// ------------------------------------------------------------------------------- | |
// @documentation http://sassylists.com/documentation/#remove | |
// ------------------------------------------------------------------------------- | |
// @dependence `replace()` | |
// ------------------------------------------------------------------------------- | |
// @example remove(a b c, b) => a, c | |
// @example remove(a b c, z) => a, b, c | |
// @example remove(a b c b, b) => a, c b | |
// @example remove(a b c b, b, true) => a, c | |
// ------------------------------------------------------------------------------- | |
// @param $list [List] : list | |
// @param $value [Literal] : value to remove | |
// @param $recursive [Boolean] : enable / disable recursivity | |
// ------------------------------------------------------------------------------- | |
// @return [List] | |
@function remove($list, $value, $recursive: false) { | |
@return replace($list, $value, "", $recursive); | |
} | |
// Replaces $old-value by $new-value in $list | |
// ------------------------------------------------------------------------------- | |
// @documentation http://sassylists.com/documentation.html#replace | |
// ------------------------------------------------------------------------------- | |
// @dependence `purge()` | |
// ------------------------------------------------------------------------------- | |
// @example replace( (a, b, c), b, z ) => a, z, c | |
// @example replace( (a, b, c), y, z ) => a, b, c | |
// @example replace( (a, b, c a), a, z ) => z, b, c z | |
// @example replace( (a, b, c a), a, z, true ) => z, b, c z | |
// ------------------------------------------------------------------------------- | |
// @param $list [List] : list | |
// @param $old-value [Literal] : value to replace | |
// @param $new-value [Literal] : new value for $old-value | |
// @param $recursive [Boolean] : enable / disable recursivity | |
// ------------------------------------------------------------------------------- | |
// @return [List] | |
@function replace($list, $old-value, $new-value, $recursive: false) { | |
$result: (); | |
@each $item in $list { | |
@if length($item) > 1 and $recursive { | |
$result: append($result, replace($item, $old-value, $new-value, $recursive)); | |
} | |
@else { | |
$result: append($result, if($item == $old-value, $new-value, $item)); | |
} | |
} | |
@return purge($result); | |
} | |
// Reverses the order of $list | |
// ------------------------------------------------------------------------------- | |
// @documentation http://sassylists.com/documentation/#reverse | |
// ------------------------------------------------------------------------------- | |
// @example reverse(a b c) => c, b, a | |
// @example reverse(a b (c a)) => c a, b, a | |
// @example reverse(a b (c a), true) => a c, b, a | |
// ------------------------------------------------------------------------------- | |
// @param $list [List] : list | |
// @param $recursive [Boolean] : enable / disable recursivity | |
// ------------------------------------------------------------------------------- | |
// @return [List] | |
@function reverse($list, $recursive: false) { | |
$result: (); | |
@for $i from length($list) * -1 through -1 { | |
$item: nth($list, abs($i)); | |
@if length($item) > 1 and $recursive { | |
$result: append($result, reverse($item, $recursive)); | |
} | |
@else { | |
$result: append($result, $item); | |
} | |
} | |
@return $result; | |
} | |
// Slices $list between $start and $end | |
// ------------------------------------------------------------------------------- | |
// @documentation http://sassylists.com/documentation/#slice | |
// ------------------------------------------------------------------------------- | |
// @example slice(a b c d, 2, 3) => b, c | |
// @example slice(a b c d, 3, 2) => error | |
// @example slice(a b c d, 3, 5) => error | |
// @example slice(a b c d, -1, 3) => error | |
// @example slice(a b c d, 0, 3) => error | |
// @example slice(a b c d, 3, 3) => c | |
// ------------------------------------------------------------------------------- | |
// @param $list [List] : list | |
// @param $start [Number] : start index | |
// @param $end [Number] : end index | |
// ------------------------------------------------------------------------------- | |
// @raise [Error] if $start or $end aren't integers | |
// @raise [Error] if $start is greater than $end | |
// @raise [Error] if $start or $end is strictly lesser than 1 | |
// @raise [Error] if $start is strictly greater than length of $list | |
// @raise [Error] if $end is strictly greater than length of $list | |
// ------------------------------------------------------------------------------- | |
// @return [List] | false | |
@function slice($list, $start: 1, $end: length($list)) { | |
$result: false; | |
@if type-of($start) != number or type-of($end) != number { | |
@warn "List indexes #{quote($start)} and #{quote($end)} must be numbers for `slice`."; | |
@return $result; | |
} | |
@else if $start > $end { | |
@warn "Start index is #{quote($start)} but has to be lesser than or equals to the end index (#{quote($end)}) for `slice`."; | |
@return $result; | |
} | |
@else if $start < 1 or $end < 1 { | |
@warn "List indexes must be non-zero integers for `slice`."; | |
@return $result; | |
} | |
@else if $start > length($list) { | |
@warn "Start index is #{quote($start)} but list is only #{length($list)} items long for `slice`."; | |
@return $result; | |
} | |
@else if $end > length($list) { | |
@warn "End index is #{quote($end)} but list is only #{length($list)} items long for `slice`."; | |
@return $result; | |
} | |
@else { | |
$result: (); | |
@for $i from $start through $end { | |
$result: append($result, nth($list, $i)); | |
} | |
} | |
@return $result; | |
} | |
// Sorts numeric values of $list | |
// ------------------------------------------------------------------------------- | |
// @documentation http://sassylists.com/documentation/#sort | |
// ------------------------------------------------------------------------------- | |
// @dependence `last()` | |
// @dependence `insert-nth()` | |
// ------------------------------------------------------------------------------- | |
// @example sort(5 12 4.7 6 69 6) => 4.7, 5, 6, 6, 12, 69 | |
// @example sort(5 12 4.7 "8" 6 14px 69 6) => 4.7, 5, 6, 6, 12, 69 | |
// ------------------------------------------------------------------------------- | |
// @param $list [List] : list | |
// ------------------------------------------------------------------------------- | |
// @raise [Warning] if not unitless number found | |
// ------------------------------------------------------------------------------- | |
// @return [List] | |
@function sort($list, $force: false) { | |
$result : nth($list, 1); | |
@if length($list) > 1 { | |
@for $i from 2 through length($list) { | |
$item: nth($list, $i); | |
@if type-of($item) == number { | |
@if unitless($item) and $force { | |
@if $item > last($result) { | |
$result: append($result, $item); | |
} | |
@else { | |
$index: 0; | |
@for $i from length($result) * -1 through -1 { | |
$i: abs($i); | |
@if $item <= nth($result, $i) { | |
$index: $i; | |
} | |
} | |
$result: insert-nth($result, $index, $item); | |
} | |
} | |
@else { | |
@warn "Not unitless number found. Omitted."; | |
} | |
} | |
@else { | |
@warn "Not integer value found. Omitted."; | |
} | |
} | |
} | |
@return $result; | |
} | |
// Sums up all unitless values in $list | |
// ------------------------------------------------------------------------------- | |
// @documentation http://sassylists.com/documentation/#sum | |
// ------------------------------------------------------------------------------- | |
// @example sum(1 2 3 4 5) => 15 | |
// @example sum(1 a 2 b 3) => 6 | |
// @example sum(10px 3em 5%) => 0 | |
// @example sum(10px 3em 5%, true) => 18 | |
// ------------------------------------------------------------------------------- | |
// @param $list [List] : list | |
// @param $force [Boolean] : enable / disable parseInt | |
// ------------------------------------------------------------------------------- | |
// @return [Number] | |
@function sum($list, $force: false) { | |
$result: 0; | |
@each $item in $list { | |
@if type-of($item) == number { | |
@if $force and unit($item) { | |
$item: $item / ($item * 0 + 1); | |
} | |
@if unitless($item) { | |
$result: $result + $item; | |
} | |
} | |
} | |
@return $result; | |
} | |
// Joins all elements of $list with $glue | |
// ------------------------------------------------------------------------------- | |
// @documentation http://sassylists.com/documentation/#to-string | |
// ------------------------------------------------------------------------------- | |
// @example to-string(a b c) => abc | |
// @example to-string(a (b c) d) => abcd | |
// @example to-string(a b c, '-') => a-b-c | |
// ------------------------------------------------------------------------------- | |
// @param $list [List] : list | |
// @param $glue [String] : value to use as a join string | |
// @param $root [Boolean] : strictly internal boolean for recursivity | |
// ------------------------------------------------------------------------------- | |
// @return [String] | |
@function to-string($list, $glue: '', $root: true) { | |
$result: null; | |
@each $item in $list { | |
@if length($item) > 1 { | |
$result: $result#{to-string($item, $glue, false)}; | |
} | |
@else { | |
$condition: index($list, $item) != length($list) or not $root; | |
$result: if($condition, $result#{$item}#{$glue}, $result#{$item}); | |
} | |
} | |
@return quote($result); | |
} | |
// Returns $list as a string | |
// ------------------------------------------------------------------------------- | |
// @documentation http://sassylists.com/documentation/#debug | |
// ------------------------------------------------------------------------------- | |
// @example debug(a b c d e) => [ a, b, c, d, e ] | |
// @example debug(a b (c d e)) => [ a, b, [ c, d, e ] ] | |
// ------------------------------------------------------------------------------- | |
// @param $list [List] : list | |
// @param $pre [Boolean] : enable/disable variables type and proper indentation | |
// @param $level [Number] : internal variable for recursivity | |
// ------------------------------------------------------------------------------- | |
// @return [String] | |
@function debug($list, $pre: false, $level: 1) { | |
@debug $level; | |
$tab : " "; | |
$indent : ""; | |
$break : if($pre, "\A ", ""); | |
@for $i from 1 to $level { | |
$indent : $indent + $tab; | |
} | |
$result: "[" + $break; | |
@each $item in $list { | |
$result: $result + if($pre, $indent + $tab, " "); | |
@if length($item) > 1 { | |
$result: $result | |
+ if($pre, "(list: " + length($item) + ") ", "") | |
+ debug($item, $pre, $level + 1); | |
} | |
@else { | |
$result: $result | |
+ if($pre, "(" + type-of($item) + ") ", "") | |
+ $item; | |
} | |
@if index($list, $item) != length($list) { | |
$result: $result + "," + $break; | |
} | |
} | |
$result: $result + $break + if($pre, if($level > 1, $indent, ""), " ") + "]"; | |
@return quote($result); | |
} | |
// Mixin displaying clean debug | |
// ------------------------------------------------------------------------------- | |
// @param $list [List] : list | |
@mixin debug($list) { | |
body:before { | |
content: debug($list, true) !important; | |
display: block !important; | |
margin: 1em !important; | |
padding: .5em !important; | |
background: #EFEFEF !important; | |
border: 1px solid #DDD !important; | |
border-radius: .2em !important; | |
color: #333 !important; | |
font: .75em/1.5 "Courier New", monospace !important; | |
text-shadow: 0 1px white !important; | |
white-space: pre-wrap !important; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment