Permalink
bcb86c6 Nov 1, 2018
1 contributor

Users who have contributed to this file

121 lines (86 sloc) 3.69 KB

@content Arguments: Draft 1

(Issue)

Table of Contents

Summary

This section is non-normative.

This proposal adds the ability for mixins to pass arguments to their @content blocks. These arguments are passed using the normal argument syntax, and accepted using a new using syntax for @include:

@mixin accepts-content {
  @for $i from 1 to 5 {
    @content($i, 360deg * $i / 5);
  }
}

@include accepts-content using ($number, $hue) {
  .color-#{$number} {
    background-color: hsl($hue, 75%, 90%);
  }
}

The argument list for using supports all the features of a normal argument list declaration.

Design Decisions

While the syntax for passing arguments to @content was pretty obvious, a number of different syntaxes were considered for declaring which arguments are accepted by an @include, including:

// Adding a new at-rule:
@include accepts-content {
  @receive ($number, $hue);
  // ...
}

// Adopting Ruby's block syntax:
@include accepts-content { |$number, $hue|
  // ...
}

// A Haskell-like punctuation syntax:
@include accepts-content -> ($number, $hue) {
  // ...
}

We decided on using over @receive because it reads clearer to have the arguments be part of the @include syntax rather than in the mixin body. We chose it over Ruby- or Haskell-style because we generally prefer the use of words over punctuation in Sass.

We decided to use using as opposed to another word because it's relatively terse while still being clear. We considered as instead, but decided the meaning of the word didn't match the semantics; and we considered with, but decided that it was both semantically ambiguous and confusing because the module system proposal uses to declare an argument invocation rather than an argument declaration.

Syntax

This proposal updates the syntax for @content and @include as follows:

ContentRule      ::= '@content' ArgumentInvocation?
IncludeRule      ::= '@include' Identifier ArgumentInvocation? ContentBlock?
ContentBlock     ::= UsingDeclaration? '{' Statements '}'
UsingDeclaration ::= 'using' ArgumentDeclaration

Semantics

This proposal defines a new algorithm for evaluating a @content rule. Given a @content rule content within a mixin that's invoked with an @include rule include:

  • Let invocation be content's ArgumentInvocation, or an invocation with no arguments if content has no ArgumentInvocation.

    This means that @content and @content() are interpreted identically.

  • Let declaration be include's UsingDeclaration's ArgumentDeclaration, or a declaration with no arguments if include has no UsingDeclaration.

    This means that @include foo { ... } and @include foo using () { ... } are interpreted identically.

  • Let arguments be the result of applying invocation to declaration.

    This means arguments is a mapping from variable names to values. If invocation isn't a valid invocation of declaration, this will throw an error that should be surfaced to the user.

  • If include has no ContentBlock, do nothing.

    Exiting here rather than earlier means that @content(value) is an error if include has no content block.

  • Otherwise, let scope be a new scope that's a child of include's scope.

  • For each pair variable and value in arguments:

    • Set variable to value in scope.
  • Evaluate include's ContentBlock statements in scope.