From e13ef18980e301283cc95b35cc8c105be6583341 Mon Sep 17 00:00:00 2001 From: Dmitry Sharabin Date: Tue, 11 Jun 2024 18:51:35 +0200 Subject: [PATCH 01/23] [color-swatch] Add support for deltas from other color --- src/color-swatch/color-swatch.css | 57 ++++++++++++++++++------ src/color-swatch/color-swatch.js | 73 +++++++++++++++++++++++++------ 2 files changed, 103 insertions(+), 27 deletions(-) diff --git a/src/color-swatch/color-swatch.css b/src/color-swatch/color-swatch.css index 01fcba6a..4b5a733f 100644 --- a/src/color-swatch/color-swatch.css +++ b/src/color-swatch/color-swatch.css @@ -7,6 +7,8 @@ 0 0 / calc(2 * var(--_transparency-cell-size)) calc(2 * var(--_transparency-cell-size)) content-box border-box var(--_transparency-background) ); + --_positive-deltaE-color: var(--positive-deltaE-color, hsl(120, 80%, 25%)); + --_negative-deltaE-color: var(--negative-deltaE-color, hsl(0, 85%, 40%)); position: relative; display: inline-flex; @@ -49,31 +51,48 @@ slot { } } -[part="coords"] { +[part="coords"], [part="deltaE"] { margin: 0; display: inline-flex; gap: .5em; + dd { + margin: 0; + font-weight: bold; + font-variant-numeric: tabular-nums; + } + &:is(:host([size="large"]) &) { display: grid; - grid-template-columns: max-content auto; - gap: .3em; - font-size: max(9px, 80%); - justify-content: start; - - .coord { - display: contents; - } + grid-template-columns: subgrid; } +} +[part="coords"] { .coord { display: flex; gap: .2em; - dd { - margin: 0; - font-weight: bold; - font-variant-numeric: tabular-nums; + dd.deltaE { + color: var(--_deltaE-color); + + &.positive { + --_deltaE-color: var(--_positive-deltaE-color); + } + + &.negative { + --_deltaE-color: var(--_negative-deltaE-color); + } + } + } + + &:is(:host([size="large"]) &) { + .coord { + display: contents; + + dd:not(.deltaE, :has(~ dd)) { + grid-column: span 2; + } } } } @@ -97,6 +116,18 @@ slot { @container color-swatch (width <= 5rem) { font-size: 80%; } + + &:is(:host([size="large"]) &) { + display: grid; + grid-template-columns: repeat(3, max-content); + gap: .1em .2em; + font-size: max(9px, 80%); + justify-content: start; + + & > * { + grid-column: 1 / -1; + } + } } [part="color-wrapper"] { diff --git a/src/color-swatch/color-swatch.js b/src/color-swatch/color-swatch.js index a8ce82c6..2ec5295c 100644 --- a/src/color-swatch/color-swatch.js +++ b/src/color-swatch/color-swatch.js @@ -109,27 +109,68 @@ const Self = class ColorSwatch extends NudeElement { this.style.setProperty("--color", colorString); } - if (name === "coords") { - if (!this.coords.length) { - return; - } + if (name === "coords" || name === "vs") { + if (this.coords.length) { + this._el.coords ??= Object.assign(document.createElement("dl"), {part: "coords"}); + if (!this._el.coords.parentNode) { + this._el.colorWrapper.after(this._el.coords); + } + + let coords = []; + for (let coord of this.coords) { + let [label, channel] = Object.entries(coord)[0]; + let {space, index} = Color.Space.resolveCoord(channel); + + let value = this.color.get(channel); + + let deltaString; + if (typeof value === "number" && this.vs) { + let spaceCoords = Object.values(space.coords); + let deltas = this.color.deltas(this.vs, this.color, {space}).coords; + + let delta = deltas[index]; + if (typeof delta === "number" && delta !== 0) { + let isAngle = spaceCoords[index].type === "angle"; + if (!isAngle) { + delta = Math.abs(delta - value) / delta; + } + delta = Number(delta.toPrecision(4)); + + let sign = delta > 0 ? "+" : ""; + let className = delta > 0 ? "positive" : "negative"; + deltaString = `
(${ sign }${ delta }${ !isAngle ? "%" : ""})
`; + } + } + + value = typeof value === "number" ? Number(value.toPrecision(4)) : value; + let html = `
${ label }
${ value }
`; + if (deltaString) { + html += deltaString; + } + + coords.push(`
${ html }
`); + } - this._el.coords ??= Object.assign(document.createElement("dl"), {part: "coords"}); - if (!this._el.coords.parentNode) { - this._el.colorWrapper.after(this._el.coords); + this._el.coords.innerHTML = coords.join("\n"); } + } - let coords = []; - for (let coord of this.coords) { - let [label, channel] = Object.entries(coord)[0]; + if (name === "vs") { + if (!this.vs) { + this._el.deltaE?.remove(); + this._el.deltaE = null; + } + else { + this._el.deltaE ??= Object.assign(document.createElement("dl"), {part: "deltaE"}); + if (!this._el.deltaE.parentNode) { + (this._el.coords ?? this._el.colorWrapper).after(this._el.deltaE); + } - let value = this.color.get(channel); + let value = this.color.deltaE(this.vs); value = typeof value === "number" ? Number(value.toPrecision(4)) : value; - coords.push(`
${ label }
${ value }
`); + this._el.deltaE.innerHTML = `
ΔE
${ value }
`; } - - this._el.coords.innerHTML = coords.join("\n"); } } @@ -179,6 +220,10 @@ const Self = class ColorSwatch extends NudeElement { }, dependencies: ["color"], }, + vs: { + type: Color, + dependencies: ["color"], + }, } static events = { From d6c7f7fbb5d498f02eb15c5bf76ce2f1034b9b5d Mon Sep 17 00:00:00 2001 From: Dmitry Sharabin Date: Tue, 11 Jun 2024 18:51:47 +0200 Subject: [PATCH 02/23] [color-scale] Add support for deltas from other color --- src/color-scale/color-scale.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/color-scale/color-scale.js b/src/color-scale/color-scale.js index 2dda037a..e7105d3f 100644 --- a/src/color-scale/color-scale.js +++ b/src/color-scale/color-scale.js @@ -71,6 +71,9 @@ const Self = class ColorScale extends NudeElement { if (this.coords) { swatch.coords = this.coords; } + if (this.vs) { + swatch.vs = this.vs; + } i++; } @@ -152,6 +155,9 @@ const Self = class ColorScale extends NudeElement { additionalDependencies: ["coords"], }, coords: {}, + vs: { + type: Color, + }, }; } From 4525cff1f7e80f9fc935ceadccefd3038d5f9fdd Mon Sep 17 00:00:00 2001 From: Dmitry Sharabin Date: Tue, 11 Jun 2024 19:09:15 +0200 Subject: [PATCH 03/23] Move vars to the block where they are used --- src/color-swatch/color-swatch.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/color-swatch/color-swatch.js b/src/color-swatch/color-swatch.js index 2ec5295c..07f163aa 100644 --- a/src/color-swatch/color-swatch.js +++ b/src/color-swatch/color-swatch.js @@ -119,12 +119,11 @@ const Self = class ColorSwatch extends NudeElement { let coords = []; for (let coord of this.coords) { let [label, channel] = Object.entries(coord)[0]; - let {space, index} = Color.Space.resolveCoord(channel); - let value = this.color.get(channel); let deltaString; if (typeof value === "number" && this.vs) { + let {space, index} = Color.Space.resolveCoord(channel); let spaceCoords = Object.values(space.coords); let deltas = this.color.deltas(this.vs, this.color, {space}).coords; From e6428912807f9cf43ac4e327e9042173c957ed7f Mon Sep 17 00:00:00 2001 From: Dmitry Sharabin Date: Tue, 11 Jun 2024 19:16:38 +0200 Subject: [PATCH 04/23] Don't show the delta if it's zero --- src/color-swatch/color-swatch.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/color-swatch/color-swatch.js b/src/color-swatch/color-swatch.js index 07f163aa..93c3800d 100644 --- a/src/color-swatch/color-swatch.js +++ b/src/color-swatch/color-swatch.js @@ -160,15 +160,16 @@ const Self = class ColorSwatch extends NudeElement { this._el.deltaE = null; } else { - this._el.deltaE ??= Object.assign(document.createElement("dl"), {part: "deltaE"}); - if (!this._el.deltaE.parentNode) { - (this._el.coords ?? this._el.colorWrapper).after(this._el.deltaE); - } - let value = this.color.deltaE(this.vs); value = typeof value === "number" ? Number(value.toPrecision(4)) : value; + if (value !== 0) { + this._el.deltaE ??= Object.assign(document.createElement("dl"), {part: "deltaE"}); + if (!this._el.deltaE.parentNode) { + (this._el.coords ?? this._el.colorWrapper).after(this._el.deltaE); + } - this._el.deltaE.innerHTML = `
ΔE
${ value }
`; + this._el.deltaE.innerHTML = `
ΔE
${ value }
`; + } } } } From 85428d87f49a82948161556c6d4f7deb18b8c7aa Mon Sep 17 00:00:00 2001 From: Dmitry Sharabin Date: Tue, 11 Jun 2024 19:25:14 +0200 Subject: [PATCH 05/23] Minor refactor --- src/color-swatch/color-swatch.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/color-swatch/color-swatch.js b/src/color-swatch/color-swatch.js index 93c3800d..ca1bb91e 100644 --- a/src/color-swatch/color-swatch.js +++ b/src/color-swatch/color-swatch.js @@ -124,12 +124,12 @@ const Self = class ColorSwatch extends NudeElement { let deltaString; if (typeof value === "number" && this.vs) { let {space, index} = Color.Space.resolveCoord(channel); - let spaceCoords = Object.values(space.coords); let deltas = this.color.deltas(this.vs, this.color, {space}).coords; let delta = deltas[index]; if (typeof delta === "number" && delta !== 0) { - let isAngle = spaceCoords[index].type === "angle"; + let spaceCoord = Object.values(space.coords)[index]; + let isAngle = spaceCoord.type === "angle"; if (!isAngle) { delta = Math.abs(delta - value) / delta; } From 6242c06528e073184ce6024e88f0a1bd674d9519 Mon Sep 17 00:00:00 2001 From: Dmitry Sharabin Date: Tue, 11 Jun 2024 20:19:18 +0200 Subject: [PATCH 06/23] Support different precision for angles and numbers --- src/color-swatch/color-swatch.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/color-swatch/color-swatch.js b/src/color-swatch/color-swatch.js index ca1bb91e..52e22fe7 100644 --- a/src/color-swatch/color-swatch.js +++ b/src/color-swatch/color-swatch.js @@ -133,7 +133,7 @@ const Self = class ColorSwatch extends NudeElement { if (!isAngle) { delta = Math.abs(delta - value) / delta; } - delta = Number(delta.toPrecision(4)); + delta = Number(delta.toPrecision(isAngle ? 4 : 1)); let sign = delta > 0 ? "+" : ""; let className = delta > 0 ? "positive" : "negative"; From 9c886522e5d3cda5d4859ba43bc1d99f8d454cd2 Mon Sep 17 00:00:00 2001 From: Dmitry Sharabin Date: Tue, 11 Jun 2024 21:58:03 +0200 Subject: [PATCH 07/23] Add support for the primary use case Show deltas within the scale. --- src/color-scale/color-scale.js | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/color-scale/color-scale.js b/src/color-scale/color-scale.js index e7105d3f..2a113afd 100644 --- a/src/color-scale/color-scale.js +++ b/src/color-scale/color-scale.js @@ -70,9 +70,18 @@ const Self = class ColorScale extends NudeElement { swatch.textContent = name; if (this.coords) { swatch.coords = this.coords; - } - if (this.vs) { - swatch.vs = this.vs; + + // Deltas don't make sense without coords + if (this.deltas) { + if (this.vs) { + // If there is a vs color, use it as the reference for the deltas + swatch.vs = this.vs; + } + else if (i > 0) { + // Otherwise, use the previous color + swatch.vs = colors[i - 1].color; + } + } } i++; } @@ -152,12 +161,15 @@ const Self = class ColorScale extends NudeElement { return colors; }, - additionalDependencies: ["coords"], + additionalDependencies: ["coords", "vs", "deltas"], }, coords: {}, vs: { type: Color, }, + deltas: { + type: Boolean, + }, }; } From bd4df349871749bf7d25cd9573c4fa1202af8763 Mon Sep 17 00:00:00 2001 From: Dmitry Sharabin Date: Tue, 11 Jun 2024 23:07:32 +0200 Subject: [PATCH 08/23] =?UTF-8?q?=F0=9F=A4=A6=E2=80=8D=E2=99=82=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/color-swatch/color-swatch.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/color-swatch/color-swatch.js b/src/color-swatch/color-swatch.js index 52e22fe7..aff4f787 100644 --- a/src/color-swatch/color-swatch.js +++ b/src/color-swatch/color-swatch.js @@ -124,14 +124,14 @@ const Self = class ColorSwatch extends NudeElement { let deltaString; if (typeof value === "number" && this.vs) { let {space, index} = Color.Space.resolveCoord(channel); - let deltas = this.color.deltas(this.vs, this.color, {space}).coords; + let deltas = this.color.deltas(this.vs, {space}).coords; let delta = deltas[index]; if (typeof delta === "number" && delta !== 0) { let spaceCoord = Object.values(space.coords)[index]; let isAngle = spaceCoord.type === "angle"; if (!isAngle) { - delta = Math.abs(delta - value) / delta; + delta = delta / value * 100; } delta = Number(delta.toPrecision(isAngle ? 4 : 1)); From 5ddf3a143d9baa9826c85774a8ed9e4d4170d959 Mon Sep 17 00:00:00 2001 From: Dmitry Sharabin Date: Tue, 11 Jun 2024 23:25:23 +0200 Subject: [PATCH 09/23] Increase precision for percents --- src/color-swatch/color-swatch.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/color-swatch/color-swatch.js b/src/color-swatch/color-swatch.js index aff4f787..64dafe1b 100644 --- a/src/color-swatch/color-swatch.js +++ b/src/color-swatch/color-swatch.js @@ -133,7 +133,7 @@ const Self = class ColorSwatch extends NudeElement { if (!isAngle) { delta = delta / value * 100; } - delta = Number(delta.toPrecision(isAngle ? 4 : 1)); + delta = Number(delta.toPrecision(isAngle ? 4 : 2)); let sign = delta > 0 ? "+" : ""; let className = delta > 0 ? "positive" : "negative"; From fea82ad7733828e5e2c45533be233aab8b310bd2 Mon Sep 17 00:00:00 2001 From: Dmitry Sharabin Date: Wed, 12 Jun 2024 12:06:50 +0200 Subject: [PATCH 10/23] [color-swatch] Add docs on the `vs` prop (attribute) --- src/color-swatch/README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/color-swatch/README.md b/src/color-swatch/README.md index 1582e30c..47bb5589 100644 --- a/src/color-swatch/README.md +++ b/src/color-swatch/README.md @@ -120,6 +120,24 @@ By default, the coord name will be used as a coord label. Add a label before the ``` +### The `vs` attribute + +You can pass another color via the `vs` attribute to show the delta (if it is not zero) between the current and that color. + +```html + + oklch(70% 0.25 138) + +``` + +If the color coords are also specified, the (not zero) deltas from that color in its coordinates will also be shown. + +```html + + oklch(70% 0.25 138) + +``` + ### With slot content Before and after: @@ -222,6 +240,7 @@ If you don’t, the `` element will be used. | `coords` | `coords` | `string` | - | Comma-separated list of coords of the current color to be shown. | | `value` | `value` | `string` | - | The current value of the swatch. | | `size` | - | `large` | - | The size of the swatch. Currently, it is used only to make a large swatch. | +| `vs` | `vs` | `Color` | `string` | - | The second color to use when calculating the difference (delta) with the current color. | | `property` | `property` | `string` | - | CSS property to bind to. | | `scope` | `scope` | `string` | `:root` | CSS selector to use as the scope for the specified CSS property. | | `gamuts` | `gamuts` | `string` | `srgb, p3, rec2020: P3+, prophoto: PP` | Comma-separated list of gamuts to be used by the gamut indicator. | From 5cfe1b5c502353ca092c2321aa14c1141f6d31ea Mon Sep 17 00:00:00 2001 From: Dmitry Sharabin Date: Wed, 12 Jun 2024 12:23:58 +0200 Subject: [PATCH 11/23] [color-scale] Add docs on the `coords`, `deltas`, and `vs` attributes --- src/color-scale/README.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/color-scale/README.md b/src/color-scale/README.md index 2e357f11..ff798478 100644 --- a/src/color-scale/README.md +++ b/src/color-scale/README.md @@ -37,6 +37,42 @@ You can only specify your core colors, and insert steps via interpolation: If you have more than 2 colors listed, this will insert steps between each pair. + +### The `coords`, `delta`, and `vs` attributes + +You can show any of the colors coords in _any_ color space the same way you can do it for [``](../color-swatch/#the-coords-attribute): + +```html + +``` + +By specifying the `deltas` boolean attribute, you can also show deltas between the current and the previous color: + +```html + +``` + +If you need to show the difference between every color in the scale and another color, you can specify that color via the `vs` attribute: + +```html + +``` +