Last active
August 29, 2015 14:11
-
-
Save sgregson/aca4fe6b2adff9b0fcdc to your computer and use it in GitHub Desktop.
LibSass Configuable Objects (syntax 1)
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.1.0-beta) | |
// ---- | |
// LibSass Configurable Objects Syntax 1 | |
// uses selector() to include content | |
// | |
// @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) { | |
@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}; | |
} | |
} | |
} | |
} | |
} | |
//////////////////////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); | |
@include selector('.button', $conf) { | |
@extend %full_width; // every instance of .button will extend %full_width | |
// @include box_sizing($type:border-box); | |
} | |
@include selector('.button:hover', $conf); | |
} | |
// 2) INSTANTIATE the element | |
// keys set in the instance will either: | |
// * override the default value | |
// * append new property | |
/*Page Instance 1 (default values) */ | |
@include buttons(); | |
/*Page Instance 2 (override+append) */ | |
.parent { | |
@include buttons(( | |
'.button': ( | |
color: blue, | |
background: white, | |
'@extend': '%full_height' | |
), | |
'.button:hover': ( | |
text-decoration: null, | |
color: yellow | |
) | |
)); | |
} | |
/*//////////////////////// | |
//// COMPLETE EXAMPLE //// | |
////////////////////////*/ | |
//////////////////////PARTIALS FILE///////////////////////////////////////////// | |
@mixin topnav-mainsearch($conf:()) { | |
$conf: init(( | |
'input.search': ( | |
padding: 30px 0 10px, | |
width: null, | |
margin-top: 2px, | |
outline: none, | |
), | |
'.search .btn_search': ( | |
position: absolute, | |
top: 0, | |
right: 0 | |
)), $conf); | |
@include selector('input.search', $conf) { | |
// THIS IS WHERE YOU PLACE CONTENT THAT MUST NOT VARY FOR THIS SELECTOR | |
@include box_sizing($type: 'border-box'); | |
@content; // to allow the instance to have content | |
} | |
@include selector('.search .btn_search', $conf); | |
} | |
//////////////////////PAGE FILE VARIATIONS////////////////////////////////////// | |
/********************************** | |
VARIATION 1: PARAMETERLESS | |
*/ | |
@include topnav-mainsearch(); | |
/********************************** | |
VARIATION 2: KILLING A SELECTOR | |
'null' removes .search .btn_search {...} | |
*/ | |
@include topnav-mainsearch(( | |
'.search .btn_search': null | |
)); | |
/********************************** | |
VARIATION 3: PARTIAL OVERWRITE with parent selector | |
.search .btn_search { | |
margin: 20px 6px 0 0, | |
right: null | |
} | |
*/ | |
a.parent { | |
@include topnav-mainsearch(( | |
'.search .btn_search': ( | |
margin: 20px 6px 0 0, | |
right: null | |
) | |
)); | |
} | |
/********************************** | |
VARIATION 4: DEEP EXTENSION | |
* both are extended | |
* duplicate selector enabled with underscore prefix | |
* star-hack possible with quoted value | |
*/ | |
@include topnav-mainsearch(( | |
'input.search': ( | |
padding: 6px 0 6px 10px, | |
width: 1px, | |
_width: '3px\9 /*ie-hack*/', | |
'*width': 2px, | |
border-color: $primary | |
), | |
'.search .btn_search': ( | |
margin: 8px 6px 0 0 | |
) | |
)); |
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 (default values) */ | |
.button { | |
color: red; | |
} | |
.button:hover { | |
text-decoration: underline; | |
} | |
/*Page Instance 2 (override+append) */ | |
.parent .button { | |
color: blue; | |
background: white; | |
} | |
.parent .button:hover { | |
color: yellow; | |
} | |
/*//////////////////////// | |
//// COMPLETE EXAMPLE //// | |
////////////////////////*/ | |
/********************************** | |
VARIATION 1: PARAMETERLESS | |
*/ | |
input.search { | |
-webkit-box-sizing: "border-box"; | |
-moz-box-sizing: "border-box"; | |
box-sizing: "border-box"; | |
padding: 30px 0 10px; | |
margin-top: 2px; | |
outline: none; | |
} | |
.search .btn_search { | |
position: absolute; | |
top: 0; | |
right: 0; | |
} | |
/********************************** | |
VARIATION 2: KILLING A SELECTOR | |
'null' removes .search .btn_search {...} | |
*/ | |
input.search { | |
-webkit-box-sizing: "border-box"; | |
-moz-box-sizing: "border-box"; | |
box-sizing: "border-box"; | |
padding: 30px 0 10px; | |
margin-top: 2px; | |
outline: none; | |
} | |
/********************************** | |
VARIATION 3: PARTIAL OVERWRITE with parent selector | |
.search .btn_search { | |
margin: 20px 6px 0 0, | |
right: null | |
} | |
*/ | |
a.parent input.search { | |
-webkit-box-sizing: "border-box"; | |
-moz-box-sizing: "border-box"; | |
box-sizing: "border-box"; | |
padding: 30px 0 10px; | |
margin-top: 2px; | |
outline: none; | |
} | |
a.parent .search .btn_search { | |
position: absolute; | |
top: 0; | |
margin: 20px 6px 0 0; | |
} | |
/********************************** | |
VARIATION 4: DEEP EXTENSION | |
* both are extended | |
* duplicate selector enabled with underscore prefix | |
* star-hack possible with quoted value | |
*/ | |
input.search { | |
-webkit-box-sizing: "border-box"; | |
-moz-box-sizing: "border-box"; | |
box-sizing: "border-box"; | |
padding: 6px 0 6px 10px; | |
width: 1px; | |
margin-top: 2px; | |
outline: none; | |
width: 3px /*ie-hack*/; | |
*width: 2px; | |
border-color: #0072BC; | |
} | |
.search .btn_search { | |
position: absolute; | |
top: 0; | |
right: 0; | |
margin: 8px 6px 0 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment