mayank99 / open-props-scss

open-props as sass variables
MIT License
22 stars 2 forks source link

Oklch props #8

Closed woodcox closed 1 year ago

woodcox commented 1 year ago

@mayank99 Now that oklch has landed across the main browsers and color-mix and color functions are gaining browser support. Could we add the following:

import ColorsHd from 'open-props/src/props.colors-oklch.js';
import OklchHues from 'open-props/src/props.colors-oklch-hues.js';
import GrayOklch from 'open-props/src/props.gray-oklch.js';

Here is a starting point:

  // colors-hd.scss
  } else if (moduleName.toLowerCase() === 'colors-hd') {
    generatedScss = '$color-hue: 0 !default;\n';

    Object.entries(importObj).forEach(([key, value]) => {
      key = key.replace('--', '$');
      value = value.replace(/var\(--(.*?)(?:,\s*(.*?))?\)/g, '#{$$$1}');

      generatedScss += `${key}: ${value};\n`;
    });

  // gray-oklch.scss
  } else if (moduleName.toLowerCase() === 'gray-oklch') {
    generatedScss = '$gray-hue: none !default;\n$gray-chroma: none !default;\n';

    Object.entries(importObj).forEach(([key, value]) => {
      key = key.replace('--', '$hd-'); // prevent naming conflict with the grays in colors module
      value = value.replace(/var\(--(.*?)(?:,\s*(.*?))?\)/g, '#{$$$1}');

      generatedScss += `${key}: ${value};\n`;
    });

Which outputs:

//colors-hd.scss
$color-hue: 0 !default;
$color-0: oklch(99% .03 #{$color-hue});
$color-1: oklch(95% .06 #{$color-hue});
$color-2: oklch(88% .12 #{$color-hue});
// ...

// gray-oklch.scss
$gray-hue: none !default;
$gray-chroma: none !default;
$hd-gray-0: oklch(99% #{$gray-chroma} #{$gray-hue});
$hd-gray-1: oklch(95% #{$gray-chroma} #{$gray-hue});
// ...

// oklch-hues.scss
$hue-red: 25;
$hue-pink: 350;
$hue-purple: 310;
// ...
mayank99 commented 1 year ago

I haven't looked at the new colors that open-props has added and I also have to think a bit more about the api we want to expose. But yes, definitely something we should add.

woodcox commented 1 year ago

Regarding the api, what if the sass compiled to valid css color function? Such as:

.my-thing {
  color: color-mix(in oklch, oklch(74% 0.16 25), transparent 50%);
  background-color: lch(from oklch(74% 0.16 25) l c 100);
}

By using two sass functions:

/// MIX FUNCTION
@function mix($color-space, $color1, $color2, $weight: 0.5) {
    @return color-mix(in $color-space, $color1, $color2 $weight);
}

/// ADJUST FUNCTION
@function adjust($color-space, $color, $p1: 0, $p2: 0, $p3: 0, $alpha: 1) {
$colorspace-map: (
  rgb: (
    r: $p1,
    g: $p2,
    b: $p3,
  ),
  hsl: (
    h: $p1,
    s: $p2,
    l: $p3,
  ),
  lch: (
    l: $p1,
    c: $p2,
    h: $p3,
  ),
  oklch: (
    l: $p1,
    c: $p2,
    h: $p3,
  ),
);
  $color-space-config: map.get($colorspace-map, $color-space);

  @if (not $color-space-config) {
    @error "The #{$color-space} must be either 'rgb', 'hsl', 'lch', or 'oklch'. Other color spaces are not currently supported.";
  }

  @if meta.type-of($alpha) != "number" {
    @warn "Invalid alpha value. Alpha must be a number or a percentage";
  }

  $adjusted-props: ();

  @each $key, $prop in $color-space-config {
    $get-props: if(map.get($color-space-config, $key) != 0, map.get($color-space-config, $key), $key);
    $adjusted-props: append($adjusted-props, $get-props);
  }

  $append-alpha: if($alpha != 1, " / #{$alpha}", "");

  @if ($color-space) == oklch {
    @return #{'lch(from #{$color} #{$adjusted-props}#{$append-alpha})'};
  }
  @return #{'#{$color-space}(from #{$color} #{$adjusted-props}#{$append-alpha})'};
}

From these two functions its possible create darken, lighten and transparent functions using the modern css color syntax (and a whole lot more). It took me a while to figure out the adjust function but I got there πŸ˜„ πŸŽ‰ 🀯 !!!!!

woodcox commented 1 year ago

For example:

@function opacity($color-space, $color, $alpha) {
  @return mix($color-space, $color, transparent, $alpha);
}

@function lighter($color-space, $color, $weight: 0.5) {
  @if $weight >= 0 {
    @return mix($color-space, $color, #fff, $weight);
  } @else {
    @return darker($color-space, $color, -$weight);
  }
}

@function darker($color-space, $color, $weight: 0.5) {
  @if $weight >= 0 {
    @return mix($color-space, $color, #000, $weight);
  } @else {
    @return lighter($color-space, $color, -$weight);
  }
}
mayank99 commented 1 year ago

hmm... those utility functions may be handy, but they look unrelated and could live in user-land or a different package outside open-props-scss. this package is only concerned with reexporting open-props CSS variables as Sass variables.

i spent some time looking into it, and i think i understand that colors-oklch and colors-oklch-hues are meant to be used together. but i'm a bit confused by gray-oklch. it doesn't come with any default chrome or hue, unlike the regular hex/hsl versions of gray.

are these new variables documented anywhere? i could not find any mention of it on https://open-props.style, which makes me think that it's unreleased/unstable.

mayank99 commented 1 year ago

colors-oklch and colors-oklch-hues can probably be combined into a single file:

$red-0: oklch(99% .03 25);
$red-1: oklch(95% .06 25);
$red-2: oklch(88% .12 25);
// ...

$pink-0: oklch(99% .03 350);
$pink-1: oklch(95% .06 350);
$pink-2: oklch(88% .12 350);

// ...

and gray can be left out from initial release, because i'm not sure if it's actually ready yet. can always be added in the future.

woodcox commented 1 year ago

Yes, I believe it’s a beta release as it’s documented on nerdy.dev rather than in the open props docs.

The grays-oklch have fallbacks of none for hue and chroma within the custom properties which can be overwritten if you given them a β€”-gray-hue and or β€”-gray-choma custom prop:

--gray-0: oklch(99% var(--gray-chroma, none) var(--gray-hue, none));
mayank99 commented 1 year ago

The grays-oklch have fallbacks of none for hue and chroma within the custom properties which can be overwritten if you given them a β€”-gray-hue and or β€”-gray-choma custom prop:

That's what i find weird though. The grays in the regular color palettes are all tinted, so they are ready to use out-of-the-box, whereas this one looks like an experiment.

Looking at that blog post, i see these two sets of variables for tinting the grays.

.gray-cool { 
  --gray-hue: 270; 
  --gray-chroma: .02;
}
.gray-warm { 
  --gray-hue: 50; 
  --gray-chroma: .01;
}

i would expect these to be built into open-props. Having predefined colors, to me, is the whole point of using open-props.

For this reason, i would again opt for leaving these grays out of the initial release. The user can always import gray-oklch from open-props instead of open-props-scss. In fact, it will be better that way because CSS variables work nicely for dynamically setting chroma/hue.

woodcox commented 1 year ago

I've started a discussion on the git repo for open-props regarding the gray-oklch.

I think your right its wise to leave it out until some predefined hues and chroma are included. Do you want a PR for colors-oklch and colors-oklch-hues where they are combined into one sass module?

Do you have a preference for the name? colors-oklch or colors-hd. I think colors-oklch is probably the better name as if other new HD colors get added it may result in renaming down the road.

mayank99 commented 1 year ago

yes, a single colors-oklch file would work

woodcox commented 1 year ago

I've realised that the oklch colors need to be wrapped in a function to be able to modify the $color-hue. Otherwise the default $color-hue: 0 !default: cannot be overiden (it can but only once globally).

it needs a function such as:

$hue-red: 25 !default;
$hue-pink: 350 !default;
$hue-purple: 310 !default;
// ...

@function add-hue($color, $hue: 0) {
  $color-hue: $hue;
  $color-0: oklch(99% 0.03 $color-hue);
  $color-1: oklch(95% 0.06 $color-hue);
  $color-2: oklch(88% 0.12 $color-hue);
  $color-3: oklch(80% 0.14 $color-hue);
  // ...
  $color-bright: oklch(65% 0.3 $color-hue);

  @if $color == color-0 {
      @return $color-0;
  } @else if ($color == color-1) {
      @return $color-1;
  // ...
  } @else {
  @return $color-bright;
  }
}

I think wherever there is a $sass-var in the expression (<variable>: <expression>) there will need to be a function. This would apply to animations.sccs, borders.scss and shadows.scss (which we already have a function for).

mayank99 commented 1 year ago

I'm not sure I understand the need for customizing these individual values. In my suggestion above, there isn't even any $color-hue, it's all hardcoded values.

$red-0: oklch(99% .03 25);
$red-1: oklch(95% .06 25);
$red-2: oklch(88% .12 25);
// ...

$pink-0: oklch(99% .03 350);
$pink-1: oklch(95% .06 350);
$pink-2: oklch(88% .12 350);

// ...
woodcox commented 1 year ago

doh! I misunderstood what you meant when you said to combine the files into one! I get what you mean now. I think they will likely need a prefix or suffix as the names will conflict with the hex colors.

mayank99 commented 1 year ago

no need for a prefix or suffix. this file should not be forwarded in the index. it will be a separate entrypoint, so the user can import into their own namespace

@use 'open-props-scss/colors-oklch' as hd;
woodcox commented 1 year ago

I’ve sent you a pull request πŸ˜€