Skip to content

Should the extract function be enhanced to allow padding extraction? #1127

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

Closed
scottrippey opened this issue Jan 12, 2013 · 8 comments
Closed

Comments

@scottrippey
Copy link

I'd like to propose a feature, but I'd like to get feedback first.

In #1112, we added a function, extract(@pad, 2) that can be used to extract a top/right/bottom/left dimension from a padding shorthand (or ANY shorthand, since it's index based).
We originally wanted to specify a keyword, such as extract(@pad, right), but that requires Less to have intrinsic knowledge of CSS, and have special keywords, which was just not a good idea.

The only problem with the index-based approach is that it would be nice to also allow short-shorthand, such @pad: 1px; or @pad: 1px 2px 3px; but there's no reliable way to extract the right, bottom, or left values.

Here's my proposed solution: Allow "backup indexes" as follows:
@left: extract(@pad, 4 2 1), @bottom: extract(@pad, 3 1), @right: extract(@pad, 2 1).
The @left example tries to extract the 4th parameter, but if there aren't 4 parameters, it tries the 2nd, and if there aren't 2, it tries the 1st.

This puts the Less user in charge, and makes them responsible for the intrinsic CSS knowledge. But maybe I'm just off my rocker.

@extemporalgenome
Copy link
Contributor

I firmly believe that both number based and name based extraction would be both useful and reasonable. top, bottom, left, and right extraction have simple rules for typical usages:

If the value has:

  • 4 space separated values, assume the association: top right bottom left
  • 3 values: top right/left bottom
  • 2 values: top/bottom right/left
  • 1 value: top/right/bottom/left
  • otherwise, produce an error (or alternatively return the first value).

If @lukeapage's concept of a 'selector' builtin, as mentioned in #1357 were accepted, the value returned could be augmented with source information when it resolved to an attribute, and this additional information would persist in any subsequent variable assignments referencing that value too, in all cases allowing unambiguous extraction of other sub-attributes, for example:

border: 1px solid black;
@val:   selector(& @border);
@width: extract(@val, width);
@style: extract(@val, style);
@color: extract(@val, color);

Augmenting the 'unit' builtin (or creating a new builtin) to accept attribute names (the set of attribute names and unit names do not overlap) could be a way of manually adding this information to a value. The @Val line above could thus be replaced by @val: unit("1px solid black", border).

@seven-phases-max
Copy link
Member

I would propose a subtle modification: instead of "backup index" argument, extract may have (optional) "fallback value" argument - i.e. just like they do in http://dev.w3.org/csswg/css-variables/#using-variables...
But I'm not sure if there's still much need of this feature (right now at least).
In fact, soon (in 1.5) it will be possible to get this functionality right with LESS mixins (emulating functions) w/o any javascript:

usage {
    @pad: 1px 2px 3px;
    @border: 8px dotted red;
    extract-with-fallback: @extract-with-fallback;
        .extract-with-fallback(@pad, 1, "oops");
    extract-with-backup: @extract-with-backup;
        .extract-with-backup(@pad, 7 4 2 1);
    extract-by-name: @extract-by-name;
        .extract-by-name(@border, style);
}

// ............................................................................
// implementation (a bit simplified - not handling all possible invalid args):

.extract-with-fallback(@value, @index, @fallback...) {
    .-();
    .-() {@extract-with-fallback: extract(@value, @index)}
    .-() when (@index > length(@value)) {
        @extract-with-fallback: @fallback;
    }
}

.extract-with-backup(@value, @index) {
    .-(1);
    .-(@j) {@extract-with-backup: extract(@value, extract(@index, @j))}
    .-(@j) when (extract(@index, @j) > length(@value)) {
        .-((@j + 1));
    }
}

// yet more simplified .extract-by-name implementation
// not handling "short-hand" cases etc. (but it's all possible)

@extract-by-name-spec: 
    top right bottom left,
    width style color,
    etc;

.extract-by-name(@value, @name, @fallback...) {
    .-(1, 1, extract(extract(@extract-by-name-spec, 1), 1));

    .-(@i, @j, @key) when (@key = @name) {
        .extract-with-fallback(@value, @j, @fallback);
        @extract-by-name: @extract-with-fallback;
    }

    .-(@i, @j, @key) when not(@key = @name) and 
        (@i <= length(@extract-by-name-spec)) and
        (@j < length(extract(@extract-by-name-spec, @i))) {
            .-(@i, (@j + 1), extract(extract(@extract-by-name-spec, @i), (@j + 1)));
    }

    .-(@i, @j, @key) when not(@key = @name) and 
        (@i <= length(@extract-by-name-spec)) and 
        (@j = length(extract(@extract-by-name-spec, @i))) {
            .-((@i + 1), 1, extract(extract(@extract-by-name-spec, (@i + 1)), 1));
    }

    .-(@i, @j, @key) when not(@key = @name)
        and (@i > length(@extract-by-name-spec)) {
            @extract-by-name: @fallback;
    }
}

It looks a bit verbose because I used these long descriptive names for mixins and variables, but you can shorten everything down to .-/@-.
Something like that... (Curiously to mention this all is already possible in 1.4.2 but just more tricky'n'buggy due to lack of length())

@lukeapage
Copy link
Member

close due to inacitivity? any big desire for this?

@matthew-dean
Copy link
Member

Funnily enough, I had some desire to do something like this today, but I don't remember the context. I just remember wanting to pass in a list of... OH, I KNOW WHAT IT WAS.

I wanted to set up a kind of "configuration" mixin where someone could pass in an arbitrary list of elements, and then use each one to "pull in" elements referenced in a Less version of Normalize.css. However, there's a huge pile of so many things Less does not do (and no doubt my description is confusing), like allow you to mixin elements instead of classes, that I quickly abandoned it. So, my particular use case relied on other features that ALSO don't exist, so I personally wouldn't have a need for it unless the rest were addressed.

@lukeapage
Copy link
Member

@matthew-dean sounds like a different usecase too - we can already get at items in a list, we just can't interpret shorthand properties

@matthew-dean
Copy link
Member

Oh that, lol, yes, we don't need that. I misread this issue, sorry.

@seven-phases-max
Copy link
Member

I'm thinking of closing this (due to inactivity), but hmm, since after all it's quite easy to implement and it will be backward compatible (even supporting both "backup" and "fallback" parameters simultaneously, i.e. extract(@list, 4 2 1, @fallback-value))... Hmm...

@scottrippey
Copy link
Author

My suggestion is that we close this. My original use-case was to build a mixin that accepts padding as a single parameter and extracts the different properties. The current extract works fine, as long as my padding always has all 4 values. I think extract should remain this simple, and we should go down a different route if we want to "parse" CSS shorthands.

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

No branches or pull requests

5 participants