Last active
October 20, 2015 14:30
-
-
Save sgregson/72d7983445b912fe640f to your computer and use it in GitHub Desktop.
LibSASS Configurable Objects (Syntax 2)
This file contains 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
// ---- | |
// libsass (v3.2.5) | |
// ---- | |
// LibSass Configurable Objects Syntax 2 | |
// uses actual selector to include configuration | |
// NOTE: currently unworkable without passing in selector reference due to https://github.com/sass/libsass/issues/548 | |
// | |
// @author Spencer Gregson | |
// @credit http://hugogiraudel.com/2014/05/05/bringing-configuration-objects-to-sass/ - a modular way to build partials with signatures | |
// @credit map-merge-deep() - Pedr Browne (https://gist.github.com/Undistraction/681818d751b6dd06c0cc), edited for compatibility with libsass 3.0.2, no dependencies | |
//////////////////////REQUIRED UTILITIES//////////////////////////////////////// | |
// map-merge-deep() | |
// | |
// Merges the contents of two maps, depth-first | |
// ```map-merge-deep($base, $ext)``` | |
// | |
// Styleguide functions.map-merge-deep | |
@function map-merge-deep($map-old, $map-new, $overwrite: true) { | |
// Iterate through each value of the new map | |
@each $key, $new-value in $map-new { | |
@if map-has-key($map-old, $key) { | |
// There is an existing key | |
$old-value: map-get($map-old, $key); | |
@if type-of($new-value) == map and type-of($old-value) == map { | |
// If both are maps, recurse regardless of $overwrite | |
$merged-value: map-merge-deep($old-value, $new-value); | |
$map-old: map-merge($map-old, ($key: $merged-value)); | |
} @else { | |
// Otherwise check $overwrite | |
@if $overwrite{ | |
$map-old: map-merge($map-old, ($key: $new-value)); | |
} | |
} | |
} @else { | |
// There is no existing key so add | |
$map-old: map-merge($map-old, ($key: $new-value)); | |
} | |
} | |
@return $map-old; | |
} | |
// init() | |
// | |
// Alias to initialize a mixin configuration | |
// deeply merges two maps - where the keys exist in both, the second takes priority | |
// ``` | |
// $conf: init(( | |
// '.button': ( color: red ), | |
// '.button:hover': ( text-decoration: underline ) | |
// ), $conf); | |
// ``` | |
// | |
// Styleguide functions.init | |
@function init($base, $ext) { | |
// $ext: map-merge-deep($ext, ('scope': #{&})); | |
@return map-merge-deep($base, $ext); | |
} | |
// selector() | |
// | |
// Renders a selector using the given configuration object | |
// Each key-value pair in $conf will output as a CSS property-value | |
// + When the value is 'null', the property won't render | |
// + When the selector is 'null', the selector won't render | |
// | |
// Styleguide mixins.selector | |
@mixin selector($sel, $conf) { | |
// remove everything if the selector instance is nulled-out | |
@if map-get($conf, $sel) != null { | |
#{$sel} { | |
// debug: map-values(map-get($conf, $sel)); | |
// content from the selector initialization | |
@content; | |
// CSS property-value pairs from the selector instance | |
@each $key, $value in map-get($conf, $sel) { | |
// Permit duplicate keys using an underscore prefix (use case: rgba() degradation) | |
@if str-index($key, '_') == 1 { | |
$key: str-slice($key, 2); | |
} | |
@if str-index($key, '@extend') != 1 { | |
#{$key}: #{$value}; | |
} @else { | |
@extend #{$value}; | |
} | |
} | |
} | |
} | |
} | |
@mixin config($sel, $conf) { | |
// $scope: if(map-get($conf, 'scope') != '', str-length(map-get($conf, 'scope')), 0 ); | |
// $sel: if($scope > 0, str-slice(#{&}, $scope+2), #{&}); | |
@if map-get($conf, $sel) != null { | |
// content from the selector initialization | |
@content; | |
// CSS property-value pairs from the selector instance | |
@each $key, $value in map-get($conf, $sel) { | |
// Permit duplicate keys using an underscore prefix (use case: rgba() degradation) | |
@if str-index($key, '_') == 1 { | |
$key: str-slice($key, 2); | |
} | |
@if str-index($key, '@extend') != 1 { | |
#{$key}: #{$value}; | |
} @else { | |
@extend #{$value}; | |
} | |
} | |
} | |
} | |
//////////////////////GLOBALS/////////////////////////////////////////////////// | |
/*////////////////////// | |
//// SIMPLE EXAMPLE //// | |
//////////////////////*/ | |
/*SHARED*/ | |
$primary: #0072BC; | |
@mixin box_sizing($type) { | |
-webkit-box-sizing: $type; | |
-moz-box-sizing: $type; | |
box-sizing: $type; | |
} | |
%full_width { width: 100%; } | |
%full_height { height: 100%; } | |
// 1) INITIALIZE the component: | |
// required properties/settings go into the content of the @include selector() directive | |
// any properties which you expect to vary live in the init() call | |
@mixin buttons($conf: ()) { | |
$conf: init(( | |
'.button': ( | |
color: red | |
), | |
'.button:hover': ( | |
text-decoration: underline | |
) | |
), $conf); | |
.button { | |
// REQUIRED PARAMETERS | |
@extend %full_width; | |
//Configurable parameters | |
@include config('.button', $conf); | |
&:hover { | |
@include config('.button:hover', $conf); | |
} | |
} | |
} | |
// 2) INSTANTIATE the element | |
// keys set in the instance will either: | |
// * override the default value | |
// * append new property | |
/*Page Instance 1 (defaults) */ | |
@include buttons(); | |
/*Page Instance 2 (override+append) */ | |
.parent { | |
@include buttons(( | |
'.button': ( | |
color: blue, | |
background: white, | |
'@extend': '%full_height' | |
), | |
'.button:hover': ( | |
text-decoration: null | |
) | |
)); | |
} |
This file contains 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
/*////////////////////// | |
//// SIMPLE EXAMPLE //// | |
//////////////////////*/ | |
/*SHARED*/ | |
.button, .parent .button { | |
width: 100%; | |
} | |
.parent .button { | |
height: 100%; | |
} | |
/*Page Instance 1 (defaults) */ | |
.button { | |
color: red; | |
} | |
.button:hover { | |
text-decoration: underline; | |
} | |
/*Page Instance 2 (override+append) */ | |
.parent .button { | |
color: blue; | |
background: white; | |
} | |
.parent .button:hover { | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment