Closed dbanksdesign closed 5 years ago
This would be great!
I would love a map output using variables so they can have the !default flag...
$shadow: ( xs: $shadow-xs, sm: $shadow-sm );
We also ran into some issues with syntax when using theo. We like to use functions and retrieve with t-shirt sizes so a developer doesn't have to know any unique values per map. Theo looks for a unique name for the key.
Ideally all of our maps can have a similar simple key without overwriting like so:
$shadow: ( xs: $shadow-xs, sm: $shadow-sm );
$space: ( xs: $space-xs, sm: $space-sm );
Awesome! So trying to come up with some psuedo-requirements:
!default
flagxs: 10px
v. xs: $space-xs
For the key naming, my first thought would be for the keys and map nesting to match the object structure of the JSON of the design tokens. So having JSON like this:
{
"size": {
"font": {
"small": { "value": "13px" },
"medium": { "value": "15px" },
"large": { "value": "17px" },
"base": { "value": "{size.font.medium.value}" }
}
}
}
The output might look like
$size: (
'font': (
small: $size-font-small,
medium: $size-font-medium,
large: $size-font-large,
base: $size-font-base
)
);
Thoughts?
That would be perfect!
@jeaster12 a few questions to clarify:
!default
option for them)? In the second case, these are two different "features".
button.json:
{
"button": {
"border": {
"radius": {
"value": "3px"
},
"width": {
"value": "1px"
}
}
}
}
icon.json { "icon": { "size": { "xsm": { "value": "10px", }, "sm": { "value": "16px" }, "md": { "value": "22px" }, "lg": { "value": "30px" }, "xlg": { "value": "36px" }, "xxlg": { "value": "46px" } } } }
consider that in this case, the Sass variables file is generated in this way:
$button-border-radius: 10px; $button-border-width: 1px; $icon-size-xsm: 10px; $icon-size-sm: 16px; $icon-size-md: 22px; $icon-size-lg: 30px; $icon-size-xlg: 36px; $icon-size-xxlg: 46px;
would you expect a single map? multiple maps? an in that case, how a map "group" is declared or inferred from the declarations?
I was literally about to post about this on slack channel earlier after a week of playing around with creating one after seeing @dbanksdesign Big Design Talk.
I have been playing around with building a template, but my JS is rusty so I fear im not seeing the easier path to create it. Ive played around with reformatting a JSON output all the way to rebuilding the structure with allProperties with mixed success.
Ultimately I was able to create the 'mega' map i wanted, but my lack of JS skills here resulted in maps that worked in some areas are but then I hit a wall of values being strings so messed up in scss -> css or the keys not being strings so that key names in color values or numbers (ex Colors>Core>Red>50) caused issues. which sass seems to not like in maps, which I thought was a issue in Sass maps already fixed but im seeing it in my environment.
So if the experts could aid in providing this, it would be awesome. We had to give up on our map system just today to go back to straight variables to meet deadlines.
Having the maps in SCSS saves a huge amount of time on the CSS toolkit side when looping through them or using through deep get functions, so its a huge win to have them.
@didoo 'would you expect a single map? multiple maps? ' We may be wanting unique in our needs, but we are looking for a single map, basically mirroring the JSON output minor the other attributes and value declarations. Example below:
$bp-tokens: (
color: (
core: (
blue: (
10: #a3dcff,
20: #6bbef2,
30: #49aae6
),
orange: (
10: #ffe0d2,
20: #ffbc9d,
30: #ff9564
)
),
border: (
dark: #ffffff,
lighter: #dfdddd,
light: #c6c3c3
),
background: (
dark: #ffffff,
lighter: #dfdddd,
light: #c6c3c3
)
),
space: (
spacing: (
'default': 16px,
'xs':4px,
'sm':8px,
'md':16px,
'lg':24px,
),
inset: (
'default': 16px 16px 16px 16px,
'sm': 8px 8px 8px 8px,
'md': 16px 16px 16px 16px,
)
)
)
@didoo I would use 2 formatters if needed - currently thats how we use Theo - we push out basically a huge variables file that has the !default flag. The additional map format then just uses the variables.
I think the most flexible would be if you get out what you put in. You could write one huge map, a nested map for the definitions of an entire element, or multiple simple maps.
In your first example above - this is the output I'd expect:
$button: (
border: (
radius: (
sm: $border-radius-sm,
md: $border-radius-md,
lg: $border-radius-lg
),
width: (
sm: $border-width-sm,
md: $border-width-md,
lg: $border-width-lg
)
)
);
Deep maps like this would be super valuable for themes, color palettes, or - if preferred - writing all the attributes for a single component.
We actually break it into more globally usable attributes. We would use a radius.json and define all the border radius values there.
$radius: (
sm: $radius-sm,
md: $radius-md,
lg: $radius-lg,
pill: $radius-pill
);
Then we write a simpler function to retrieve radius values and loop over it for helpers as well.
Here is an example SassMeister
@dbanksdesign some thoughts about this issue:
example
folder, with an example of how to do it with custom formats/templates (and maybe some other examples of how to do things in a Sass-oriented way)?--
Continuing on this: probably we can follow an approach similar to Theo, so people will be familiar with the formats and will expect a similar behavior: https://github.com/salesforce-ux/theo/blob/master/lib/formats/map.scss.hbs https://github.com/salesforce-ux/theo/blob/master/lib/formats/map.variables.scss.hbs
@bolora I think you want this functionality as well?
@didoo here is the way I did it(crudely) with Theo...
https://github.com/Cupcake-Design-System/Cupcake-Sprinkles/blob/master/gulp/_default.js
Maybe its better to only doing it if you explicitly tell it to for example:
{
"size": {
"font": {
"small": { "value": "13px" },
"medium": { "value": "15px" },
"large": { "value": "17px" },
"base": { "value": "{size.font.medium.value}" }
}
}
}
would still yield:
$size-font-small: 13px; $size-font-medium: 15px; $size-font-large: 17px; $size-font-base: 15px;
But something like this:
{
"size": {
"font": {
"map: {
"small": { "value": "13px" },
"medium": { "value": "15px" },
"large": { "value": "17px" },
"base": { "value": "{size.font.medium.value}" }
}
}
}
}
Might yield:
$size-font-small: 13px;
$size-font-medium: 15px;
$size-font-large: 17px;
$size-font-base: 15px;
$size-font (
"small": $size-font-small;
"medium": $size-font-medium;
"large": $size-font-large;
"base": $size-font-base;
);
BTW I use this because I create functions to call up the values
@function font-size($key: "base", $isMobile: null) {
@if $isMobile == null {
@return map-get($font-sizes, $key);
} @else {
@return map-get($font-sizes-mobile, $key);
}
}
Then use it like this:
font-size: font-size(medium);
but a better example is using a map in a mixin:
@include make-color-backgrounds();
@mixin make-color-backgrounds ($color-list: $all-colors) {
@each $color, $value in $color-list {
.#{$prefix}bg-#{$color} {
@include color-background($value);
@if isDarkColor(#{$color}) {
color: $color-white;
}
}
}
}
Without a doubt, a !default
flag option would be HUGE, although this has no impact on platforms other than Sass.
In regards to the mapped output, the example at the top of this thread is not Sass compatible?
$size: (
'font': (
small: $size-font-small,
medium: $size-font-medium,
large: $size-font-large,
base: $size-font-base
)
);
Allowing Sass to consume nested maps has been a HUGE ask for years and as far as I know, Ruby Sass, libSass and DartSass do not support this?
@blackfalcon what do you mean by compatible? as in map-get for nested maps isn't core functionality?
We write a function for retrieving values with map-deep-get - like this - Example of above
But if you didn't wish to use a separate function you could still do this I think -
h1 { font-size: map-get(map-get($size, font), small); }
@jeaster12 I am familiar with things like map-deep functions and things like sass-maps-plus like I mentioned in my comment.
My point was that by itself Sass does not support this nesting model yet as the issue #1739 I referred to has not been completed and holy crap ... that's 3 years ago now I made that comment.
And sure there is the syntax that you eluded to of nesting map-get calls, but damn ... that just sucks.
$thing: (
thing: (
thing: (
thing: (
thing: (
thing: 10px
)
)
)
)
);
.thing {
size: map-get(map-get(map-get(map-get(map-get($thing, thing), thing), thing), thing), thing);
}
@jeaster12 @blackfalcon @bolora I have submitted a PR #193 to add the Sass maps in two formats, flat and nested.
If this is the input:
// --- file1.json ---
{
"size": {
"font": {
"small" : { "value": "12px" },
"large" : {
"value": "18px",
"comment": "this is a comment"
}
}
}
}
// --- file2.json ---
{
"color": {
"base": {
"red": {
"value": "#FF0000"
}
},
"white": { "value": "#ffffff" }
}
}
this is the generated output:
tokens_map-flat.scss
$tokens: (
'size-font-small': 12rem,
// this is a comment
'size-font-large': 18rem,
'color-base-red': #ff0000,
'color-white': #ffffff
);
tokens_map-deep.scss
$size-font-small: 12rem !default;
$size-font-large: 18rem !default; // this is a comment
$color-base-red: #ff0000 !default;
$color-white: #ffffff !default;
$tokens: (
'size': (
'font': (
'small': $size-font-small,
'large': $size-font-large
)
),
'color': (
'base': (
'red': $color-base-red
),
'white': $color-white
)
);
Let me know your thoughts.
While we have had some discussion on Sass vs Scss, the original intent of this issue was to add scss maps. As such, this is complete as of v2.7.0.
I actually needed something more in line to what w find on frameworks like bootstrap, so I wrote a format and you can find it here. https://gist.github.com/griiettner/3a400039f97a400d0ffc9b6dfafa5f2d
On the current project I'm working on, was decided that Bootstrap 5 would be the base for the project, so I need, somehow, replicate the entire Bootstrap 5 variables and preserve the maps, because there is bunch of dependencies on it.
Instead of just sass variables, it would be good to have a sass map format. If someone could comment with what they expect the output of the format to look like, that would help in writing the formatter code 😊