Skip to content

Commit

Permalink
Quick fix: old <css-color> while new one is broken
Browse files Browse the repository at this point in the history
  • Loading branch information
LeaVerou committed Mar 27, 2024
1 parent 7f0774d commit ed313f1
Show file tree
Hide file tree
Showing 5 changed files with 311 additions and 3 deletions.
4 changes: 2 additions & 2 deletions apps/gamut-mapping/gradients.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<title>Gamut Mapping Experiments - Gradients</title>
<link rel="stylesheet" href="gradients.css" />
<link rel="shortcut icon" />
<script type="module" src="../../elements/css-color/css-color.js"></script>
<script type="module" src="../../elements/css-color-0/css-color.js"></script>
<script type="module" src="gradients.js"></script>
</head>
<body>
Expand Down Expand Up @@ -44,7 +44,7 @@ <h1>Gamut Mapping Gradients</h1>
</details>
<div class="gradient">
<div v-for="[title, step] in oogSteps" :style="{'--step-color': step}" :title="title"></div>
</div>
</div>
</div>
<div :class="{flush, 'gradients': true}">
<article class="method" v-for="(i, method) of methods">
Expand Down
2 changes: 1 addition & 1 deletion apps/gamut-mapping/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<title>Gamut Mapping Experiments</title>
<link rel="stylesheet" href="style.css" />
<link rel="shortcut icon" />
<script type="module" src="../../elements/css-color/css-color.js"></script>
<script type="module" src="../../elements/css-color-0/css-color.js"></script>
<script type="module" src="index.js"></script>
</head>
<body>
Expand Down
175 changes: 175 additions & 0 deletions elements/css-color-0/css-color.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import Color from "../../dist/color.js";
// const styles = await fetch("./style.css").then(r => r.text());

const gamuts = ["srgb", "p3", "rec2020"];

let styleURL = new URL("./style.css", import.meta.url);
let importIncrementable = import("https://incrementable.verou.me/incrementable.mjs").then(m => m.default);

export default class CSSColor extends HTMLElement {
#dom = {};

constructor () {
super();
this.attachShadow({mode: "open"});
this.shadowRoot.innerHTML = `
<style>@import url("${ styleURL }")</style>
<slot name="swatch">
<div id="swatch" part="swatch"></div>
</slot>
<div id="wrapper">
<slot></slot>
<span id="gamut" part="gamut"></span>
</div>
`;
}

#initialized;

connectedCallback () {
if (!this.#initialized) {
this.#initialize();
}

// This should eventually be a custom state
this.#dom.wrapper.classList.toggle("static", !this.#dom.input);

if (this.#dom.input) {
if (!this.#dom.input.incrementable) {
// Increment numbers by keyboard arrow keys
importIncrementable.then(Incrementable => new Incrementable(this.#dom.input));
}
}

this.#render();
}

#errorTimeout;

#initialize () {
this.#dom.wrapper = this.shadowRoot.querySelector("#wrapper");
this.#dom.input = this.querySelector("input");
this.#dom.gamutIndicator = this.shadowRoot.querySelector("#gamut");

if (this.#dom.input) {
this.#dom.input.addEventListener("input", evt => {
this.#render();
});
}
this.#initialized = true;
}

#render () {
if (!this.#initialized) {
return;
}

clearTimeout(this.#errorTimeout);

if (!this.isConnected) {
return;
}

let value = this.value;
this.#color = null;

if (value) {
try {
this.#color = new Color(value);
}
catch (e) {
// Why a timeout? We don't want to produce errors for intermediate states while typing,
// but if this is a genuine error, we do want to communicate it.

this.#errorTimeout = setTimeout(_ => this.#dom.input?.setCustomValidity(e.message), 500);
}

if (this.#color) {
this.#setColor(this.#color);
this.#dom.input?.setCustomValidity("");
}

this.dispatchEvent(new CustomEvent("colorchange", {
detail: {
color: this.#color,
},
}));
}

if (this.#color) {
this.#renderGamut();
}
}

#renderGamut () {
if (this.#color) {
let gamut = gamuts.find(gamut => this.#color.inGamut(gamut)) ?? "";
this.dataset.gamut = this.#gamut = gamut;
}
else {
this.#gamut = null;
this.removeAttribute("data-gamut");
}
}

#gamut;
get gamut () {
return this.#gamut;
}

get value () {
return this.#dom.input?.value ?? this.textContent.trim();
}

set value (value) {
let oldValue = this.value;
if (value === oldValue) {
return;
}
this.#setValue(value);
this.#render();
}

#setValue (value) {
if (!this.#initialized) {
this.#initialize();
}

if (this.#dom.input) {
this.#dom.input.value = value;
}
else {
this.textContent = value;
}
}

#color;
get color () {
return this.#color;
}

set color (color) {
if (typeof color === "string") {
color = new Color(color);
}

this.#setColor(color);
this.#setValue(color.toString({ precision: 2, inGamut: false}));
this.#renderGamut();
}

#setColor (color) {
this.#color = color;

try {
this.style.setProperty("--color", this.#color.display({inGamut: false}));
}
catch (e) {
this.style.setProperty("--color", this.value);
}
}

static observedAttributes = ["for"];
}

customElements.define("css-color", CSSColor);
28 changes: 28 additions & 0 deletions elements/css-color-0/index.njk
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<h1><code>&lt;css-color></code> Web Component</h1>

<script src="./css-color.js" type="module"></script>
<h2>Static</h2>
<css-color>oklch(70% 0.25 138)</css-color>
<css-color swatch="large">oklch(70% 0.25 138)</css-color>

<h2>Editable</h2>
<css-color>
<input value="oklch(70% 0.25 138)" />
</css-color>
<css-color swatch="large">
<input value="oklch(70% 0.25 138)" />
</css-color>

<h2>Update via JS</h2>
<h3>Static</h3>
<css-color id="dynamic_static">oklch(70% 0.25 138)</css-color>
<script type="module">
dynamic_static.color = "oklch(60% 0.15 0)"
</script>
<h3>Editable</h3>
<css-color id="dynamic_editable">
<input value="oklch(70% 0.25 138)" />
</css-color>
<script type="module">
dynamic_editable.color = "oklch(60% 0.15 0)"
</script>
105 changes: 105 additions & 0 deletions elements/css-color-0/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
:host {
display: inline-flex;
gap: .3em;
width: min-content;
white-space: nowrap;
--background-checkerboard: repeating-conic-gradient(rgb(0 0 0 / .12) 0 25%, transparent 0 50%) 0 0 / 1em 1em;
}

:host([data-gamut="srgb"]) {
--gamut-color: var(--color-green, yellowgreen);
--gamut-label: "sRGB";
}

:host([data-gamut="p3"]) {
--gamut-color: var(--color-yellow, gold);
--gamut-label: "P3";
}

:host([data-gamut="rec2020"]) {
--gamut-color: var(--color-orange, orange);
--gamut-label: "P3+";
}

:host([data-gamut=""]) {
--gamut-color: var(--color-red, red);
--gamut-label: "P3+";
}

#gamut {
display: flex;
align-items: center;
justify-content: center;
border-radius: .2em;
color: white;
background: var(--gamut-color, var(--color-neutral-60, hsl(220 10% 60%)));
font-weight: bold;
padding-inline: .3em;
line-height: 1;
font-size: 80%;

&::before {
content: var(--gamut-label);
}

&:is([data-gamut="srgb"] *) {
display: none;
}

&:is(:host([data-gamut="p3"]) *) {
color: black;
}
}

#wrapper {
display: flex;
position: relative;

&.static {
gap: .4em;
}

&:not(.static) {
#gamut {
position: absolute;
inset: .3em;
inset-inline-start: auto;
}

::slotted(input) {
padding-inline-end: 1em;
}

&:is(:host([data-gamut="rec2020"]), :host([data-gamut=""])) {
::slotted(input) {
/* Accomodate the + suffix */
padding-inline-end: 2em;
}
}
}
}

:host(:not([for])) #swatch {
display: block;
inline-size: 2em;
border-radius: .2em;
background: linear-gradient(var(--color, transparent) 0 100%), var(--background-checkerboard);
}

:host([swatch="none"]) #swatch {
display: none;
}

:host(:not([for])):host([swatch="large"]) {
flex-flow: column;
}

:host(:not([for])):host([swatch="large"]) #swatch {
inline-size: auto;
block-size: 5em;
}

:host(:not([for])):host([swatch="large"]) #wrapper.static slot {
display: flex;
flex: 1;
}

0 comments on commit ed313f1

Please sign in to comment.