Skip to content

Instantly share code, notes, and snippets.

@low-ghost
Last active August 29, 2015 14:14
Show Gist options
  • Save low-ghost/72ce62d066ee47e1d9d0 to your computer and use it in GitHub Desktop.
Save low-ghost/72ce62d066ee47e1d9d0 to your computer and use it in GitHub Desktop.
Organizing Sass Transitions by Class with Transitioner
// Organizing Sass Transitions with Transitioner
//
// transitioner creates
//
// .root .selector { ...transition rules... }
// .selector.classNameToBeAnimated { ...properties to be transitioned... }
//
// great for organizing multiple transitions when adding a single class via js
// feed it classes in quotes, anything else can go either way
// write "extend #id-name" as 2nd arg to extend previous transition rules
// provide parent element(s) (multiple selectors written as usual), or don't
// can even organize pseudo class transitions if it's DRY / helpful. see :hover below
//
// example:
//
// $root: "#parentelement";
// .full-height {
// @include transitioner(#results, height 0.6s ease-in-out, $root){
// height:100%;
// }
// @include transitioner(".title", extend #results){
// height:40px;
// }
// }
// :hover{
// @include transitioner("#main .fa", all 0.3s ease-in-out, $root, $root){
// color: blue;
// }
// }
//
// output:
//
// #parentelement #results, .title {
// transition: height 0.6s ease-in-out;
// }
// #results.full-height { height: 100%; }
// .title.full-height { height: 40px; }
// #parentelement #main .fa {
// transition: all 0.3s ease-in-out;
// }
// #parentelement #main .fa:hover { color: blue; }
//
// EXTREME (BAD) EXAMPLE OF NAMESPACING WITH ROOTS
//
// dot or hash delimited selectors can be the main element,
// but space descendants must be in $root or $properties-root variables
//
// $root: "body > .block.left #main";
// $properties-root: "left";
//
// .full-height {
// @include transitioner("#inner.results", height 0.6s ease-in-out, $root, $properties-root){
// @include from($root){
// height:0px;
// }
// @include to(){
// height:100%;
// }
// }
// }
//
// OUTPUT
//
// body > .block.left #main #inner.results {
// transition: height 0.6s ease-in-out;
// }
//
// body > .block.left #main #inner.results {
// height: 0px;
// }
//
// .left #inner.results.full-height {
// height: 100%;
// }
@function to-string($value) {
@return inspect(#{$value});
}
// general string replace functionality! what's next, regex?
// also providing a fourth argument will prefix it to returned string
@function str-replace($string, $remove, $replace, $accumulator: "") {
$pos: str-index($string, $remove);
@if $remove == "" {
@warn "no argument provided for $remove";
} @else if $replace == $remove {
@return $string;
} @else if $pos {
$accumulator: $accumulator + str-slice($string, 1, $pos - 1) + $replace;
$part2: str-slice($string, $pos + str-length($remove));
@return str-replace($part2, $remove, $replace, $accumulator);
}
@return $accumulator + $string;
}
@function str-remove($string, $list...) {
@for $i from 1 through length($list) {
$string: str-replace($string, to-string(nth($list, $i)), "");
}
@return $string;
}
@function rm-sp($string, $replace: ""){
@return str-replace($string, " ", $replace);
}
@function rm-last($list){
@return set-nth($list, length($list), "");
}
//creates a string by removing commas and spaces from a list
@function flatten-list($list){
@return rm-sp(str-replace(to-string($list), ",", ""));
};
//this one is borrowed from hugo giraudel
@function remove($list, $value, $recursive: false) {
$result: ();
@for $i from 1 through length($list) {
@if type-of(nth($list, $i)) == list and $recursive {
$result: append($result, remove(nth($list, $i), $value, $recursive));
}
@else if nth($list, $i) != $value {
$result: append($result, nth($list, $i));
}
}
@return $result;
}
// START TRANSITIONER
// changes "#main .fa" to "main-subclass-fa-transition", for instance
// b/c sass can't extend nested selectors
@function to-placeholder-name($value){
@return str-replace(
str-replace(
rm-sp($value, '-'), '.', 'subclass-'), '#', 'subid-')
+ "-transition";
}
// drops a placeholder for given element and transition
@mixin placeholder-transition($name, $transition) {
%#{$name} { transition: #{$transition}; }
}
@mixin transitioner($selector, $transition, $root: false, $properties-root: false) {
$transition: to-string($transition);
$selector: to-string($selector);
@at-root {
$placeholder: to-placeholder-name($selector);
$s-for-transition: $selector;
$s-for-properties: $selector + &;
@if str-index($transition, extend) {
$placeholder: to-placeholder-name(str-slice($transition, 8));
} @else {
@include placeholder-transition($placeholder, $transition);
}
@if $root {
$s-for-transition: $root $selector;
}
@if $properties-root {
$s-for-properties: $properties-root $selector + &;
}
#{$s-for-transition} { @extend %#{$placeholder}; }
#{$s-for-properties} { @content; }
}
}
//adds initial properties. Must use to() mixin, otherwise the "from"
//propetries will be included after the properties with the added class,
//which may overwrite them and cause unexpected results
@mixin from($root: ""){
@at-root{
$list: simple-selectors(rm-sp(to-string(&)));
//guarantees $root and $list formatting are maintained while added
//class is dropped
$root-remove: rm-sp(to-string($root));
$prop-root-remove: rm-sp(to-string($properties-root));
$list: str-remove(flatten-list(rm-last($list)), $root-remove, $prop-root-remove);
#{($root $list)}{
@content;
}
}
}
@mixin to(){
@at-root{
#{&}{ @content; }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment