-
Notifications
You must be signed in to change notification settings - Fork 3.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
3 layers of mixin invocations with variables across scopes produces duplicated broken output #2350
Comments
This looks like more curvy variant of #1291 (examples there were fixed at some point near v1.7 but since that was unintentional fix it may appear still in more complex cases).
So, yes, currently it's important to avoid using outer mixin parameters within inner mixins (at least when it comes to complex scope hierarchies).
See also related discussion started at #1648 (comment) (as well as the initial #965). Most likely that the another variant ("passing mixins by reference") would suit parametric callbacks better (so that instead of defining quite heavy on syntax (at least like it looks in #2270) "parametric detached rulesets" we would be allowed use ordinal mixins as explicit callbacks at will). |
Your "more curious behavior" isn't all that much more curious; it's the same thing that happens if you swap the order without |
Change |
See https://github.com/SLaks/SLaks.Blog/blob/gh-pages/css/_colors.less for my actual use case; I'm replicating lambdas by passing 5 "parameters" as variables from the callsite for the ruleset callback. |
its not so unexpected Lets do the first call
Now the 2nd call - Note that we have included InvokerCallback in the scope already, so it is called again
Now if multiple mixins match within a scope, they are all called e.g.
becomes
So my expected would be
and there is definitely something weird going on because we don't get that, but I wouldn't expect what you got. |
Curiouse. Actually if we assume the code after the first call to be equal to:
(which indeed seems to be logical) then the original result becomes expected because in this case the So this becomes closely related to #1316 stuff (just not for parametric/non-parametric difference but for expecting different non-local scope precedences for different use-cases). |
So I'm actually closing this as "currently expected behaviour". As I mentioned above it's just: Inside For a detailed explanation of how scope precedences work for mixin expansions see #2435 (comment). For an overall discussion around Workarounds for this particular example: a {
.Invoker(@color) {
.InvokerCallback(@color, lighten(@color, 40%));
}
.Define(@name, @color) {
.InvokerCallback(@baseColor, @foreColor) {
output: @name @baseColor @foreColor;
}
.Invoker(@color);
}
& {.Define(First, red)}
& {.Define(Second, green)}
& {.Define(Third, blue)}
& {.Define(Fourth, black)}
} [2] Use DRs instead of caller callbacks. a {
.Invoker(@color, @apply) {
@baseColor: @color;
@foreColor: lighten(@color, 40%);
@apply();
}
.Define(@name, @color) {
.Invoker(@color, {
output: @name @baseColor @foreColor;
});
}
.Define(First, red);
.Define(Second, green);
.Define(Third, blue);
.Define(Fourth, black);
} |
Closing as "expected behaviour". |
Source:
Actual result:
Expected result:
Workarounds:
This seems to be caused by mixing variables from different scopes.
Removing the
@name
from theoutput:
property, or inlining theInvokerCallback()
mixin intoInvoker()
fixes it.Moving
.Invoker()
outside the ruleset also fixes it.Motivation:
In my actual (messier) code,
.Invoker()
is a generic loop mixin which iterates over a list parameter comes and callsInvokerCallback()
separately for each item in the list, and the entire thing is a mixin with a further callback that lets me apply theming to different elements.This lets me define a number of names for each color in a single call to
Define()
.This whole thing would become much saner if you add support for lambdas (#2270)
The text was updated successfully, but these errors were encountered: