Skip to content
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

Mixin guard default function (#1584) #1606

Merged
merged 2 commits into from
Dec 19, 2013
Merged

Mixin guard default function (#1584) #1606

merged 2 commits into from
Dec 19, 2013

Conversation

seven-phases-max
Copy link
Member

Function default

Available inside guard conditions and returns true only if no other mixin matches. (see #1584)

Usage:

mixin(1)                   {x: 11}
mixin(2)                   {y: 22}
mixin(@x) when (default()) {z: @x}

div {
    mixin(3);
}

div.special {
    mixin(1);
}

Expressions

It is possible to use the value returned by default with guard operators.
For example .mixin() when not(default()) {} will match only if there's at least one more mixin definition that matches .mixin() call:

.mixin(@value) when (ispixel(@value)) {width: @value}
.mixin(@value) when not(default())    {padding: (@value / 5)}

div-1 {
    .mixin(100px);
}

div-2 {
    /* ... */
    .mixin(100%);
}

result:

div-1 {
  width: 100px;
  padding: 20px;
}
div-2 {
  /* ... */
}

Another example:

.expr-example {
    .m(@x) when (@x = true)      {v1: @x}
    .m(@x) when (@x = false)     {v2: @x}
    .m(@x) when (@x = default()) {v3: @x}

    &-true  {.m(true)}
    &-false {.m(false)}
}

result:

.expr-example-true {
  v1: true;
}
.expr-example-false {
  v2: false;
  v3: false;
}

Outside of guards

default is available as built-in function only inside guard expressions. If used outside of a mixin guard condition it is interpreted as a regular CSS value:

div {
    property1: default();
    property2: default(42);
}

result:

div {
  property1: default();
  property2: default(42);
}

Advanced usage and multiple default() calls

It is allowed to make multiple default() calls in the same guard condition or in a different conditions of a mixins with the same name:

div {
    .m(@x) when (default()), not(default())    {always: @x}
    .m(@x) when (default()) and not(default()) {never:  @x}

    .m(1); // OK
}

However LESS will throw a error if it detects a potential conflict between multiple mixin definitions using default():

div {
    .m(@x) when (default())    {}
    .m(@x) when not(default()) {}

    .m(1); // Error
}

In above example it is impossible to determine what value each default() call should return since they recursively depend on each other.

This "multiple default() calls" analysis is not too deep and very simple as its main intention is mostly to notify a user of possible default misuse, hence

detects a potential conflict

The following also causes a error:

div {
    .m(@x) when (default())    {default:     @x} // (1)
    .m(@x) when not(default()) {not-default: @x} // (2)
    .m(3)                      {case-3:       3} // (3)

    .m(3); // Error
}

Although there's no direct conflict with .m(3); since (1) and (2) do not interfere because of (3), the whole mixin family is interpreted as erroneous (basically, it is the same error as in previous example).

And finally, here's advanced correct "multiple default() calls" usage (not too practical perhaps, but to illustrate why this is allowed at all):

.x {
    .m(red)                                    {case-1: darkred}
    .m(blue)                                   {case-2: darkblue}
    .m(@x) when (iscolor(@x)) and (default())  {default-color: @x}
    .m('foo')                                  {case-1: I am 'foo'}
    .m('bar')                                  {case-2: I am 'bar'}
    .m(@x) when (isstring(@x)) and (default()) {default-string: and I am the default}

    &-blue  {.m(blue)}
    &-green {.m(green)}
    &-foo   {.m('foo')}
    &-baz   {.m('baz')}
}

result:

.x-blue {
  case-2: #00008b;
}
.x-green {
  default-color: #008000;
}
.x-foo {
  case-1: I am 'foo';
}
.x-baz {
  default-string: and I am the default;
}

And more examples in included tests...

@lukeapage
Copy link
Member

Wow, am impressed. Am unwell at the moment but will give it a better look
soon. I will release 1.5 then put this in the next release (which btw will
be released quicker - I think our releases are too far apart at the moment)

@jonschlinkert
Copy link
Contributor

nice! I'm deep in the middle of doing docs updates @seven-phases-max mind if I grab your content and use it once this is released?

@lukeapage hope you feel better

@seven-phases-max
Copy link
Member Author

@lukeapage Get well!

@jonschlinkert Sure (just in case - a markdown copy of it is here)

@jonschlinkert
Copy link
Contributor

awesome! thanks

@lukeapage
Copy link
Member

Jon are you updating lesscss.org or a new repository? I was planning on
updating docs next so I can collaborate either way if your not done by then.

@Soviut
Copy link

Soviut commented Oct 20, 2013

I'd like to get involved in that documentation as well. I'd gladly proofread what you guys come up with.

@jonschlinkert
Copy link
Contributor

Nice, I'll be pushing stuff up tonight!

Sent from my iPhone

On Oct 20, 2013, at 5:07 PM, Soviut notifications@github.com wrote:

I'd like to get involved in that documentation as well. I'd gladly proofread what you guys come up with.


Reply to this email directly or view it on GitHub.

@jonschlinkert
Copy link
Contributor

The less-docs repo just at first, then when it's ready we can switch it to the other if that makes sense. It's not ideal, but the existing site is a different beast

Sent from my iPhone

On Oct 20, 2013, at 4:44 PM, Luke Page notifications@github.com wrote:

Jon are you updating lesscss.org or a new repository? I was planning on
updating docs next so I can collaborate either way if your not done by then.

Reply to this email directly or view it on GitHub.

@matthew-dean
Copy link
Member

Radness!

@lukeapage lukeapage merged commit f168d18 into less:master Dec 19, 2013
@lukeapage
Copy link
Member

merged

@jonschlinkert
Copy link
Contributor

👍

@seven-phases-max seven-phases-max deleted the mutually-exclusive-guards branch December 19, 2013 08:51
@matthew-dean
Copy link
Member

By the way, this is pretty late, but the parentheses in default() seems unnecessary. It's not a JS function, really, it's just a keyword guard. Wouldn't just default be sufficient?

mixin(1)                   {x: 11}
mixin(2)                   {y: 22}
mixin(@x) when (default) {z: @x}

@seven-phases-max
Copy link
Member Author

@matthew-dean Well, it's made as a built-in function (not a directive/keyword) so parens are required. See #1584 for the history of this syntax.

@lukeapage
Copy link
Member

and its not too late to change it, it hasn't been released.

I'm guessing (an obscure case) but you could do

.a when (b = true) {
}
.a when (default() = false) {
   // runs when one or more of the other overloads runs
}

I would much rather introduce new functions than introduce new syntax

@seven-phases-max
Copy link
Member Author

I guess we can also turn it into a keyword anytime later (if necessary), but keyword would also need some extra code in the parser (while function needs no parser changes). I.e. a keyword might be a bit overkilling for this relatively minor feature, at the moment at least :)

@matthew-dean
Copy link
Member

Ok, I see. It seemed like a keyword, but I can see the interpretation as a kind of "is" function. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants