Ao trabalhar em arquiteturas Sass complexas, não é incomum usar mapas Sass para manter a configuração e as opções. De vez em quando, você verá mapas dentro de mapas (possivelmente em vários níveis) como este do o-grid:
$o-grid-default-config: ( columns: 12, gutter: 10px, min-width: 240px, max-width: 1330px, layouts: ( S: 370px, // ≥20px columns M: 610px, // ≥40px columns L: 850px, // ≥60px columns XL: 1090px // ≥80px columns ), fluid: true, debug: false, fixed-layout: M, enhanced-experience: true );
O problema com esses mapas é que não é fácil obter e definir valores da árvore aninhada. Definitivamente, isso é algo que você deseja ocultar dentro das funções para evitar ter que fazer isso manualmente todas as vezes.
Deep get
Na verdade, construir uma função para buscar valores profundamente aninhados de um mapa é muito fácil.
/// Map deep get /// @author Hugo Giraudel /// @access public /// @param (Map) $map - Map /// @param (Arglist) $keys - Key chain /// @return (*) - Desired value @function map-deep-get($map, $keys… ) ( @each $key in $keys ( $map: map-get($map, $key); ) @return $map; )
Por exemplo, se quisermos obter o valor associado ao M
layout de nosso mapa de configuração, é tão fácil quanto:
$m-breakpoint: map-deep-get($o-grid-default-config, "layouts", "M"); // 610px
Observe que as aspas em torno das strings são opcionais. Nós apenas os adicionamos por questões de legibilidade.
Conjunto profundo
Por outro lado, construir uma função para definir uma chave profundamente aninhada pode ser muito tedioso.
/// Deep set function to set a value in nested maps /// @author Hugo Giraudel /// @access public /// @param (Map) $map - Map /// @param (List) $keys - Key chaine /// @param (*) $value - Value to assign /// @return (Map) @function map-deep-set($map, $keys, $value) ( $maps: ($map,); $result: null; // If the last key is a map already // Warn the user we will be overriding it with $value @if type-of(nth($keys, -1)) == "map" ( @warn "The last key you specified is a map; it will be overrided with `#($value)`."; ) // If $keys is a single key // Just merge and return @if length($keys) == 1 ( @return map-merge($map, ($keys: $value)); ) // Loop from the first to the second to last key from $keys // Store the associated map to this key in the $maps list // If the key doesn't exist, throw an error @for $i from 1 through length($keys) - 1 ( $current-key: nth($keys, $i); $current-map: nth($maps, -1); $current-get: map-get($current-map, $current-key); @if $current-get == null ( @error "Key `#($key)` doesn't exist at current level in map."; ) $maps: append($maps, $current-get); ) // Loop from the last map to the first one // Merge it with the previous one @for $i from length($maps) through 1 ( $current-map: nth($maps, $i); $current-key: nth($keys, $i); $current-val: if($i == length($maps), $value, $result); $result: map-merge($current-map, ($current-key: $current-val)); ) // Return result @return $result; )
Agora, se quisermos atualizar o valor associado ao M
layout de nosso mapa de configuração, podemos fazer:
$o-grid-default-config: map-deep-set($o-grid-default-config, "layouts" "M", 650px);
Recursos extras
A função acima não é a única solução para este problema.
A biblioteca Sassy-Maps também fornece map-deep-set
e map-deep-get
funções. Na mesma linha, Hugo Giraudel também escreveu uma extend
função no estilo jQuery para tornar o integrado map-merge
recursivo e capaz de mesclar mais de 2 mapas de uma vez.