Fix gray chroma bugs

This commit is contained in:
Lea Verou
2025-03-18 13:18:46 -04:00
parent 0b883866d1
commit 8dee82a44a
4 changed files with 161 additions and 48 deletions

View File

@@ -151,8 +151,9 @@
:model-value="computedGrayChroma"
@update:model-value="grayChroma = $event"
:default-color="baseCoreColors[computedGrayColor]"
:default-value="baseCoreColors[originalGrayColor].oklch.c"
:min="0" :max-relative="maxGrayChroma" :step="0.01"
:base-value="baseCoreColors[originalGrayColor].oklch.c"
:default-value-relative="originalGrayChroma"
:min="0" :max-relative="maxGrayChroma" :step="0.00001"
label="Gray colorfulness" label-min="Neutral" :label-max="moreHue[computedGrayColor]"
></color-slider>
</template>
@@ -177,7 +178,7 @@
:default-value="seedColors[colorToIndex[hue].core].inputColor?.oklch.c"
coord="c"
:min="Math.max(coreColors.gray.oklch.c, ...Object.keys(seedHues[hue]).filter(t => t !== coreLevels[hue]).map(t => seedHues[hue][t].oklch.c))"
:max="getMaxChroma(colors[hue].core?.oklch.l, colors[hue].core?.oklch.h) - 0.001" :step="0.001"
:max="getMaxChroma(colors[hue].core?.oklch.l, colors[hue].core?.oklch.h) - 0.001" :step="0.00001"
label="Adjust colorfulness" label-min="More muted" label-max="More vibrant"
label-default="Entered color"
format-type="scale"

View File

@@ -11,10 +11,10 @@ const template = `
v-model:color="color" :default-value="inputLCH[2]" ></color-slider>
<color-slider label="Colorfulness" label-default="Entered color"
coord="c" :min="0" :max="maxChroma" :step="0.001"
v-model:color="color" :default-value="inputLCH[1]" format-type="scale" :base-value="maxChroma" ></color-slider>
v-model:color="color" :default-value="inputLCH[1]" format-type="scale" :format-base-value="maxChroma" ></color-slider>
<color-slider label="Lightness" label-default="Entered color"
coord="l" :min="0" :max="1" :step="0.01"
v-model:color="color" :default-value="inputLCH[0]" format-type="scale" :base-value="1" ></color-slider>
v-model:color="color" :default-value="inputLCH[0]" format-type="scale" :format-base-value="1" ></color-slider>
</template>
</color-popup>

View File

@@ -32,18 +32,17 @@ export default {
return ['l', 'c', 'h'].includes(value);
},
},
color: {
type: Color,
},
defaultColor: {
type: Color,
},
color: Color,
defaultColor: Color,
defaultValue: {
type: Number,
},
/** Used for formatting only. Only specify if different from default value. */
baseValue: {
defaultValue: Number,
defaultValueRelative: Number,
/** Used for relative types. Defaults to defaultValue if not provided. */
baseValue: Number,
/** Used for formatting only. Only specify if different from base value. */
formatBaseValue: {
type: Number,
default: undefined,
},
@@ -91,11 +90,7 @@ export default {
}
if (this.modelValue !== undefined) {
this.value = getAbsoluteValue({
type: this.type,
relativeValue: this.modelValue,
baseValue: this.computedDefaultValue,
});
this.value = this.getAbsoluteValue(this.modelValue);
} else if (this.color) {
this.value = this.colorCoords[this.coordIndex];
}
@@ -114,11 +109,7 @@ export default {
computed: {
computedMin() {
if (this.minRelative !== undefined) {
return getAbsoluteValue({
type: this.type,
relativeValue: this.minRelative,
baseValue: this.computedDefaultValue,
});
return getAbsoluteValue(this.minRelative);
}
return this.min;
@@ -126,11 +117,7 @@ export default {
computedMax() {
if (this.maxRelative !== undefined) {
return getAbsoluteValue({
type: this.type,
relativeValue: this.maxRelative,
baseValue: this.computedDefaultValue,
});
return this.getAbsoluteValue(this.maxRelative);
}
return this.max;
@@ -183,8 +170,36 @@ export default {
return this.getColorAt(this.computedMax);
},
isRelative() {
return this.type && this.type !== 'raw';
},
computedBaseValue() {
if (!this.isRelative) {
return;
}
if (this.baseValue !== undefined) {
return this.baseValue;
}
return this.computedDefaultValue;
},
computedDefaultValue() {
return this.defaultValue ?? this.defaultCoords[this.coordIndex];
if (this.defaultValue !== undefined) {
return this.defaultValue;
}
if (this.defaultValueRelative !== undefined) {
return this.getAbsoluteValue(this.defaultValueRelative);
}
if (this.baseValue !== undefined) {
return this.baseValue;
}
return this.defaultCoords[this.coordIndex];
},
computedDefaultColor() {
@@ -200,16 +215,37 @@ export default {
defaultProgress() {
return (this.computedDefaultValue - this.computedMin) / (this.computedMax - this.computedMin);
},
relativeValue() {
this.computedBaseValue;
return this.getRelativeValue(this.value);
},
},
methods: {
capitalize,
getAbsoluteValue(relativeValue) {
return getAbsoluteValue({
type: this.type,
relativeValue,
baseValue: this.baseValue ?? this.computedBaseValue,
});
},
getRelativeValue(absoluteValue) {
return getRelativeValue({
type: this.type,
absoluteValue,
baseValue: this.baseValue ?? this.computedBaseValue,
});
},
formatValue(value = this.value) {
let formatType = this.formatType ?? this.type;
let style = formatType === 'scale' ? 'percent' : undefined;
if (formatType && formatType !== 'raw') {
let baseValue = this.baseValue ?? this.computedDefaultValue;
let baseValue = this.formatBaseValue ?? this.computedBaseValue;
value = getRelativeValue({ type: formatType, absoluteValue: value, baseValue });
}
@@ -227,15 +263,7 @@ export default {
handleInput(value) {
this.value = value;
this.tweaking = true;
let modelValue = getRelativeValue({
type: this.type,
absoluteValue: value,
baseValue: this.computedDefaultValue,
});
this.$emit('update:modelValue', modelValue);
this.$emit('input', modelValue);
this.$emit('input', value);
},
inputEnd() {
@@ -261,16 +289,15 @@ export default {
if (this.colorCoords[this.coordIndex] !== this.value) {
this.value = this.colorCoords[this.coordIndex];
let modelValue = getRelativeValue({
type: this.type,
absoluteValue: this.value,
baseValue: this.computedDefaultValue,
});
let modelValue = this.getRelativeValue(this.value);
this.$emit('update:modelValue', modelValue);
}
}
},
relativeValue() {
this.$emit('update:modelValue', this.relativeValue);
},
},
template,
components: { InfoTip },

View File

@@ -0,0 +1,85 @@
const template = `
<color-popup :title :token="token" :color="modelValue"
:pinned :pinnable @pin="$emit('pin')" :deletable @delete="$emit('delete')">
<div slot="trigger" class="color swatch" :style="{ '--color': modelValue, colorScheme: level > 60 ? 'light' : 'dark' }">
<wa-icon class="pinned-icon" name="thumbtack" variant="regular" v-if="pinned"></wa-icon>
<wa-icon name="sliders-simple" class="tweak-icon"></wa-icon>
</div>
<template #content>
<color-slider v-if="(isEdge || pinned) && tweakBase && HUE_RANGES[hue]"
:color="modelValue" @update:model-value="$emit('update:modelValue', $event)" :default-value="colors[hue][tweakBase].oklch.h"
@input="!pinned ? $emit('pin') : null"
coord="h" :min="HUE_RANGES[hue].min + 1" :max="HUE_RANGES[hue].max" :step="1"
label="Hue shift" :label-min="moreHue[hueBefore[hue]]" :label-max="moreHue[hueAfter[hue]]"
:label-default="\`\${capitalize(hue)} \${tweakBase}\`"
></color-slider>
</template>
</color-popup>
`;
import Color from 'https://colorjs.io/dist/color.js';
import ColorPopup from './color-popup.js';
import ColorSlider from './color-slider.js';
import InfoTip from './info-tip.js';
import { HUE_RANGES, hueAfter, hueBefore, hues, moreHue } from '/assets/scripts/tweak/data.js';
import { capitalize, clamp, promise, roundTo } from '/assets/scripts/tweak/util.js';
export default {
props: {
modelValue: Color,
hue: {
type: String,
required: true,
},
level: {
type: [String, Number],
required: true,
},
coreLevel: {
type: [String, Number],
required: true,
},
pinned: Boolean,
pinnable: Boolean,
deletable: Boolean,
colors: {
type: Object,
required: true,
},
tweakBase: [String, Number],
},
emits: ['update:modelValue', 'pin', 'delete'],
data() {
return {};
},
created() {
// Attach non-reactive data
Object.assign(this, { moreHue, HUE_RANGES });
},
computed: {
title() {
return capitalize(this.hue) + ' ' + this.level;
},
hueBefore() {
return hueBefore[this.hue];
},
hueAfter() {
return hueAfter[this.hue];
},
token() {
return `--wa-color-${this.hue}-${this.level}`;
},
isEdge() {
return this.level == '95' || this.level == '05';
},
isCore() {
return this.level == this.coreLevel;
},
},
methods: { capitalize },
template,
components: { InfoTip, ColorSlider, ColorPopup },
compilerOptions: {
isCustomElement: tag => tag.startsWith('wa-'),
},
};