sass/accepted/content-args.md

121 lines
3.6 KiB
Markdown
Raw Permalink Normal View History

# `@content` Arguments: Draft 1
*([Issue](https://github.com/sass/sass/issues/871))*
## Table of Contents
* [Summary](#summary)
* [Design Decisions](#design-decisions)
* [Syntax](#syntax)
* [Semantics](#semantics)
## 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`:
```scss
@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:
```scss
// 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
2024-06-18 00:49:23 +00:00
[module system proposal] uses to declare an argument *invocation* rather than
an argument *declaration*.
[module system proposal]: module-system.md
## Syntax
This proposal updates the syntax for `@content` and `@include` as follows:
<x><pre>
**ContentRule** ::= '@content' ArgumentInvocation?
**IncludeRule** ::= '@include' Identifier ArgumentInvocation? ContentBlock?
**ContentBlock** ::= UsingDeclaration? '{' Statements '}'
**UsingDeclaration** ::= 'using' ArgumentDeclaration
</pre></x>
## 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`.