Skip to content

Commit

Permalink
[css-mixins-1] Drop 'using', define dynamic scoping (#11642)
Browse files Browse the repository at this point in the history
Resolves #10954.

Co-authored-by: Anders Hartvoll Ruud <[email protected]>
  • Loading branch information
andruud and Anders Hartvoll Ruud authored Feb 4, 2025
1 parent 3959b73 commit 1867828
Showing 1 changed file with 61 additions and 40 deletions.
101 changes: 61 additions & 40 deletions css-mixins-1/Overview.bs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Default Highlight: css

<pre class=link-defaults>
spec:infra; type:dfn; text:list
spec:infra; type:dfn; for:list; text:append
spec:css-properties-values-api; type:dfn; text:supported syntax component name
spec:css-properties-values-api; type:dfn; text:syntax component
spec:css-syntax-3; type:dfn; text:declaration
Expand Down Expand Up @@ -83,20 +84,13 @@ Defining Custom Functions {#defining-custom-functions}

A <dfn>custom function</dfn> consists of a name (<<function-name>>),
a list of [=function parameter|parameters=],
a list of [=function dependency|dependencies=],
a function body,
and optionally a <dfn>return type</dfn> described by a [=syntax definition=].

A <dfn>function parameter</dfn> consists of a name (<<custom-property-name>>);
optionally a <dfn>parameter type</dfn>, described by a [=syntax definition=];
and optionally a <dfn>default value</dfn>.

A <dfn>function dependency</dfn>,
is a special [=function parameter=],
that represents
a [=local variable=], [=function parameter=], or [=custom property=]
being implicitly passed as an argument from the calling context.

The <dfn>@function</dfn> Rule {#function-rule}
----------------------------------------------

Expand All @@ -105,14 +99,12 @@ and its syntax is:

<pre class="prod def" nohighlight>
&lt;@function> = @function <<function-name>> <<function-parameter-list>>? )
[ using ( <<function-dependency-list>> ) ]?
[ returns <<css-type>> ]?
{
<<declaration-rule-list>>
}
<dfn><<function-parameter-list>></dfn> = <<function-parameter>>#
<dfn><<function-dependency-list>></dfn> = <<function-parameter>>#
<dfn><<function-parameter>></dfn> = <<custom-property-name>> <<css-type>>? [ : <<declaration-value>> ]?
<dfn><<css-type>></dfn> = <<syntax-component>> | <<type()>>
<dfn function lt="type()" for="@function">&lt;type()></dfn> = type( <<syntax>> )
Expand All @@ -125,12 +117,10 @@ with the additional restriction that it must start with two dashes

The name of the resulting [=custom function=] is given by the <<function-name>>,
the [=function parameters=] are optionally given by <<function-parameter-list>>,
the [=function dependencies=] are optionally given by <<function-dependency-list>>,
and the [=return type=] is optionally given by the <<css-type>> following the "returns" keyword.

<div class='example'>
If the <<css-type>> of a [=function parameter=],
[=function dependency=],
If the <<css-type>> of a [=function parameter=]
or [=custom function=] return value
can be described by a single <<syntax-component>>,
then the ''type()'' function may be omitted:
Expand All @@ -150,8 +140,6 @@ and the [=return type=] is optionally given by the <<css-type>> following the "r
</pre>
</div>

Issue: Should duplicates be disallowed <em>across</em> parameters/dependencies
as well?

If more than one ''@function'' exists for a given name,
then the rule in the stronger cascade layer wins,
Expand All @@ -161,8 +149,6 @@ The <<function-name>> of a ''@function'' rule is a [=tree-scoped name=].

If the <<function-parameter-list>>
contains the same <<custom-property-name>> more than once,
or if the <<function-dependency-list>>
contains the same <<custom-property-name>> more than once,
then the ''@function'' rule is invalid.

The body of a ''@function'' rule accepts [=conditional group rules=],
Expand Down Expand Up @@ -191,7 +177,7 @@ The '@function/result' descriptor
determines the result of [=evaluate a custom function|evaluating=]
the [=custom function=] that is defined by a ''@function'' rule.
Using [=locally substitute a var()|locally substituted=] ''var()'' functions,
it can reference [=function parameters=], [=function dependencies=], [=local variables=],
it can reference [=function parameters=], [=local variables=],
as well as other [=custom functions=] via <<dashed-function>>s.

The '@function/result' descriptor itself does not have a type,
Expand Down Expand Up @@ -246,23 +232,24 @@ described in [[!css-variables]].
1. Let |function| be the result of dereferencing
the |dashed function|'s name as a [=tree-scoped reference=].
If no such name exists, return failure.
2. Let |dependency values| be an initially empty [=list=].
3. For each |dependency| in |function|'s [=function dependency|dependencies=]:
* Let |dependency value| be the value that would be substituted
if a ''var()'' function had been specified explicitly
at the end of |dashed function|'s argument list,
with |dependency| as its only argument.
* If that substitution would have made a containing declaration
[=invalid at computed-value time=],
set |dependency value| to the [=guaranteed-invalid value=].
* Append the result of [=resolving an argument=] to |dependency values|,
using |dependency value| as value,
and |dependency| as parameter.
2. Let |dependencies| be an initially empty [=list=].
3. For every possible argument to ''var()'' (with no fallback)
that would lead to a valid [=locally substitute a var()|local substitution=]
in place of |dashed function|:
[=append=] a [=declaration=] to |dependencies|
with that argument as the name,
and the substitution value as the value.

Note: This exposes any [=custom properties=], [=local variables=],
and [=function parameters=] that are visible
in any given context
to [=custom functions=] invoked by that context.

4. [=substitute arbitrary substitution functions|Substitute=]
any [=arbitrary substitution functions=]
within |dashed function|'s arguments.
5. [=Evaluate a custom function=],
using |function|, |dashed function| and |dependency values|.
using |function|, |dashed function| and |dependencies|.
6. If failure was returned, return failure.
7. Otherwise,
replace the <<dashed-function>> with the [=equivalent token sequence=]
Expand All @@ -281,7 +268,7 @@ Evaluating Custom Functions {#evaluating-custom-functions}
To <dfn>evaluate a custom function</dfn>,
with |function| being a [=custom function=],
|dashed function| being the <<dashed-function>> invoking that |function|,
and |dependency values| being a [=list=] of values.
and |dependencies| being a [=list=] of [=declarations=].

1. If the number of values in |dashed function|'s argument list
is greater than the number of values in |function|'s [=function parameter|parameters=],
Expand All @@ -297,7 +284,7 @@ Evaluating Custom Functions {#evaluating-custom-functions}
and |parameter| as parameter.
3. Let |result| be the [=resolved local value=]
of the '@function/result' descriptor,
using |function|, |dashed function|, and |dependency values|.
using |function|, |dashed function|, and |dependencies|.
4. If |function| has a [=return type=],
set |result| to the result of [=resolve a typed value|resolving a typed value=],
using |result| as the value,
Expand Down Expand Up @@ -367,25 +354,26 @@ Evaluating Custom Functions {#evaluating-custom-functions}
Parameters and Locals {#parameters}
-----------------------------------

The [=function parameters=] and [=function dependencies=] of a [=custom function=]
The [=function parameters=] of a [=custom function=]
are available for [=locally substitute a var()|local substitution=]
as if they were declared as [=local variables=]
at the start of the ''@function'' rule body.

Note: A [=local variable=] with the same name
as a [=function parameter=]/[=function dependency=] is allowed,
but will make the parameter/dependency unreachable
as a [=function parameter=] is allowed,
but will make the parameter unreachable
for [=locally substitute a var()|substitution=]

A <dfn>local variable</dfn>
is a custom property defined with the body of a [=custom function=].
It is only visible within the function where it is defined.
It is visible within the function where it is defined,
and within other [=custom functions=] invoked by that function.

<div algorithm>
To <dfn>locally substitute a var()</dfn> within a value,
with |function| being a [=custom function=],
|dashed function| being the <<dashed-function>> invoking that |function|,
and |dependency values| being a [=list=] of values:
and |dependencies| being a [=list=] of [=declarations=]:

1. Let |substitution value| be one of the following options,
depending on the [=custom property=] named in the first argument of the ''var()'' function:
Expand All @@ -397,9 +385,9 @@ Parameters and Locals {#parameters}
: Otherwise, if the [=custom property=] name matches a [=function parameter|parameter=] within |function|
:: The corresponding argument value within the |dashed function|.

: Otherwise, if the [=custom property=] name matches a [=function dependency|dependency=] within |function|
:: The corresponding value of that [=function dependency|dependency=]
within |dependency values|.
: Otherwise, if the [=custom property=] name matches the name
of a [=declaration=] within |dependencies|
:: The corresponding value of that [=declaration=].

: Otherwise
:: The [=guaranteed-invalid value=].
Expand All @@ -426,6 +414,39 @@ If any substitution algorithm returns failure,
then the [=resolved local value=] of a [=local variable=]
is the [=guaranteed-invalid value=].

<div class='example'>
A [=custom function=] can access [=local variables=]
and [=function parameters=]
from functions higher up in the call stack:

<pre class='lang-css'>
@function --foo(--x) {
--y: 2;
result: --bar();
}
@function --bar() returns &lt;number&gt; {
result: calc(var(--x) + var(--y));
}
div {
z-index: --foo(1); /* 3 */
}
</pre>

Similarly, [=custom properties=] are implicitly available:

<pre class='lang-css'>
@function --double-z() returns &lt;number&gt; {
result: calc(var(--z) * 2);
}
div {
--z: 3;
z-index: --double-z(); /* 6 */
}
</pre>

</div>


Cycles {#cycles}
----------------

Expand Down

0 comments on commit 1867828

Please sign in to comment.