Skip to content

Instantly share code, notes, and snippets.

@chriseppstein
Last active May 7, 2018 18:09
Show Gist options
  • Save chriseppstein/5818878 to your computer and use it in GitHub Desktop.
Save chriseppstein/5818878 to your computer and use it in GitHub Desktop.
I had this idea for how to expose general stylesheet structure data to SassScript, transform it, and then turn it back into styles.
// A named buffer. Will append to existing content captured there.
// The buffer can be accessed via get-capture("foo") or @emit "foo".
@capture "foo" {
@media screen {
.asdf {
.qwerty {
/* This is a comment */
color: red;
}
}
}
}
// Capture into a variable. If the variable is already is a map, the variable is
// set to a new map that is the merged result of the existing value and the captured styles.
// Defines the variable in the current scope if it isn't yet defined.
@capture into $some-capture-var {
@media screen {
.asdf {
.qwerty {
/* This is a comment */
color: red;
}
}
}
}
// Captures the following data structure:
$captured: (
("@media" : "screen") : (
(".asdf" ".qwerty") : (
"/*": " This is a comment ",
"color": red
)
)
)
// The captured content can be placed with a directive:
@emit "foo";
@emit from $some-capture-var;
@mixin render-capture($capture) {
@each $key, $value in $capture {
@if typeof($key) == "map" {
$directive: nth(map-keys($key), 1);
$directive-value: map-get($key, $directive)
// It seems bad that there's no way to generate an unknown directive from this data structure
// and that we have to enumerate all the possible directives with basically identical code.
// Perhaps we should have a @css-directive directive?
@if $directive == "@media" {
@media #{$directive-value} {
@include render-capture($value);
}
}
@else if $directive == "@supports" {
@supports #{$directive-value} {
@include render-capture($value);
}
}
@else {
@warn "I don't know how to render #{$directive}";
}
} @else if typeof($key) == "list" {
#{$key} {
@include render-capture($value);
}
} @else if typeof($key) == "string" {
@if $key == "/*" {
/*#{$value}*/
} @else {
#{$key}: $value;
}
}
}
}
@include render-capture(capture("foo"));
// So what's the point of all this?
@include transform-left-to-right {
.sidebar { float: left; }
// there's a really compelling use case to allow sass imports from this point in the code.
// Doing this would require dynamic importing: https://github.com/nex3/sass/issues/739
// and to allow mixins to be defined in places that are not at the top level.
}
// => .sidebar { float: right; }
@include darken-all-the-colors(15%) {
.dropdown { color: red; background: blue; }
}
// => .dropdown { color: #b30000, background: #0000b3; }
@mixin transform-left-to-right {
@if $rtl {
@capture into $content {
@content;
}
@each $thing in $content {
...
}
}
@else {
@content
}
}
@scottdavis
Copy link

Magically Delicious

@lunelson
Copy link

lunelson commented Apr 3, 2014

Implies the ability to dynamically call mixins

@chriseppstein
Copy link
Author

I think we probably want to capture into a slightly different data structure something more like how you'd model objects in JSON. Something like:

$captured: (
  directive: (
    name: "@media",
    value: "screen",
    contents: (
      ruleset: (
        selector: ".asdf" ".qwerty",
        properties: (
          "/*": " This is a comment ",
          "color": red
        )
      )
    )
  )
);

@MichaelArestad
Copy link

I would love the added utility '@capture' could provide. Use case I would love it for: lump like media queries together by storing the data in a map and outputting all the selectors with their data in a single media query (per breakpoint) at the end of the main styles.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment