From 8612429104da2fd44cdf370ea0b44dcfda181288 Mon Sep 17 00:00:00 2001 From: Dmitry Sharabin Date: Sun, 24 Nov 2024 14:57:18 +0100 Subject: [PATCH 01/13] [channel-picker] Use radio buttons instead of `` element of [``](../space-picker/). | -| `color-channel-base` | The internal `` element of [``](../space-picker/). | +| `color-channel-base` | The internal ``; +
+ + + +
+
+ `; constructor () { super(); @@ -25,14 +30,14 @@ const Self = class ChannelPicker extends ColorElement { connectedCallback () { super.connectedCallback?.(); - this._el.picker.addEventListener("input", this); + this._el.channels.addEventListener("change", this); } disconnectedCallback () { super.disconnectedCallback?.(); this._el.space_picker.removeEventListener("spacechange", this); - this._el.picker.removeEventListener("input", this); + this._el.channels.removeEventListener("change", this); } get selectedSpace () { @@ -40,7 +45,18 @@ const Self = class ChannelPicker extends ColorElement { } get selectedChannel () { - return this.selectedSpace.coords?.[this._el.picker.value]; + return this.selectedSpace.coords?.[this.#checkedChannel]; + } + + get #checkedChannel () { + return this._el.channels.querySelector("input[type=radio][name=channel]:checked")?.value; + } + + set #checkedChannel (value) { + let input = this._el.channels.querySelector(`input[type=radio][name=channel][value="${ value }"]`); + if (input) { + input.checked = true; + } } /** @@ -58,8 +74,9 @@ const Self = class ChannelPicker extends ColorElement { return; } - this._el.picker.innerHTML = Object.entries(coords) - .map(([id, coord]) => ``) + // By default, the first channel is selected + this._el.channels.innerHTML = Object.entries(coords) + .map(([id, coord], index) => ``) .join("\n"); let [prevSpace, prevChannel] = this.value?.split(".") ?? []; @@ -68,11 +85,11 @@ const Self = class ChannelPicker extends ColorElement { let currentChannelName = coords[prevChannel]?.name; if (prevChannelName === currentChannelName) { // Preserve the channel if it exists in the new space and has the same name ("b" in "oklab" is not the same as "b" in "p3") - this._el.picker.value = prevChannel; + this.#checkedChannel = prevChannel; } else if (this.#history?.[space.id]) { // Otherwise, try to restore the last channel used - this._el.picker.value = this.#history[space.id]; + this.#checkedChannel = this.#history[space.id]; } } } @@ -82,8 +99,8 @@ const Self = class ChannelPicker extends ColorElement { this.#render(); } - if ([this._el.space_picker, this._el.picker].includes(event.target)) { - let value = `${ this._el.space_picker.value }.${ this._el.picker.value }`; + if (this._el.space_picker === event.target || event.target.matches("input[type=radio]")) { + let value = `${ this._el.space_picker.value }.${ this.#checkedChannel }`; if (value !== this.value) { this.value = value; } @@ -95,7 +112,7 @@ const Self = class ChannelPicker extends ColorElement { let [space, channel] = (this.value + "").split("."); let currentSpace = this._el.space_picker.value; - let currentCoord = this._el.picker.value; + let currentCoord = this.#checkedChannel; let currentValue = `${ currentSpace }.${ currentCoord }`; if (!space || !channel) { @@ -118,7 +135,7 @@ const Self = class ChannelPicker extends ColorElement { let coords = Object.keys(this.selectedSpace.coords ?? {}); if (coords.includes(channel)) { - this._el.picker.value = channel; + this.#checkedChannel = channel; } else { currentCoord = coords.includes(currentCoord) ? currentCoord : coords[0]; @@ -149,12 +166,12 @@ const Self = class ChannelPicker extends ColorElement { static events = { change: { from () { - return [this._el.space_picker, this._el.picker]; + return [this._el.space_picker, this._el.channels]; }, }, input: { from () { - return [this._el.space_picker, this._el.picker]; + return [this._el.space_picker, this._el.channels]; }, }, valuechange: { From 1d62bf6e9bf0456d7442909742a6d58d73ac6544 Mon Sep 17 00:00:00 2001 From: Dmitry Sharabin Date: Sun, 24 Nov 2024 16:24:49 +0100 Subject: [PATCH 02/13] Capture the `change` event --- src/channel-picker/channel-picker.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/channel-picker/channel-picker.js b/src/channel-picker/channel-picker.js index 24bf1b42..4bece5cd 100644 --- a/src/channel-picker/channel-picker.js +++ b/src/channel-picker/channel-picker.js @@ -30,14 +30,14 @@ const Self = class ChannelPicker extends ColorElement { connectedCallback () { super.connectedCallback?.(); - this._el.channels.addEventListener("change", this); + this._el.channels.addEventListener("change", this, {capture: true}); } disconnectedCallback () { super.disconnectedCallback?.(); this._el.space_picker.removeEventListener("spacechange", this); - this._el.channels.removeEventListener("change", this); + this._el.channels.removeEventListener("change", this, {capture: true}); } get selectedSpace () { From 07e358ba8b42d78b0a29f74320f517fc75332d4b Mon Sep 17 00:00:00 2001 From: Dmitry Sharabin Date: Mon, 25 Nov 2024 15:45:36 +0100 Subject: [PATCH 03/13] Rename `space_picker` to `space-picker` to be aligned with other components --- src/channel-picker/README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/channel-picker/README.md b/src/channel-picker/README.md index 5f3b2197..b16a5945 100644 --- a/src/channel-picker/README.md +++ b/src/channel-picker/README.md @@ -103,8 +103,9 @@ These properties are read-only. ### Parts -| Name | Description | -| -------------------- | ------------------------------------------------------------------------ | -| `color-space` | The internal [``](../space-picker/) element. | -| `color-space-base` | The internal `` element. | +| Name | Description | +| ------------------ | ------------------------------------------------------------------------ | +| `wrapper` | The component's wrapper element. | +| `color-space` | The internal [``](../space-picker/) element. | +| `color-space-base` | The internal ` ${ coord.name }`) + .map(([id, coord], index) => ``) .join("\n"); let [prevSpace, prevChannel] = this.value?.split(".") ?? []; From 9ac90a07dd2a883817cc395fdd316f594d81f448 Mon Sep 17 00:00:00 2001 From: Dmitry Sharabin Date: Mon, 25 Nov 2024 16:08:50 +0100 Subject: [PATCH 05/13] Listen to the `input` event instead of `change` --- src/channel-picker/channel-picker.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/channel-picker/channel-picker.js b/src/channel-picker/channel-picker.js index 8bd60119..30277e91 100644 --- a/src/channel-picker/channel-picker.js +++ b/src/channel-picker/channel-picker.js @@ -26,14 +26,14 @@ const Self = class ChannelPicker extends ColorElement { connectedCallback () { super.connectedCallback?.(); - this._el.channels.addEventListener("change", this, {capture: true}); + this._el.channels.addEventListener("input", this, {capture: true}); } disconnectedCallback () { super.disconnectedCallback?.(); this._el.space_picker.removeEventListener("spacechange", this); - this._el.channels.removeEventListener("change", this, {capture: true}); + this._el.channels.removeEventListener("input", this, {capture: true}); } get selectedSpace () { From daecea64980c8219c34d8b4e87b7f7878bb325b9 Mon Sep 17 00:00:00 2001 From: Dmitry Sharabin Date: Mon, 25 Nov 2024 23:17:28 +0100 Subject: [PATCH 06/13] Add the `compact` attribute to support an alternative way to render the picker Plus, some style tweaks --- src/channel-picker/README.md | 37 +++++++--- src/channel-picker/channel-picker.css | 101 +++++++++++++++++--------- src/channel-picker/channel-picker.js | 73 ++++++++++++++++--- 3 files changed, 159 insertions(+), 52 deletions(-) diff --git a/src/channel-picker/README.md b/src/channel-picker/README.md index b16a5945..c510fecc 100644 --- a/src/channel-picker/README.md +++ b/src/channel-picker/README.md @@ -15,8 +15,19 @@ default `oklch.l` will be used: ``` -You can hide the `color-space` part with CSS to show only the coordinates of the -specified space: +If you need a more compact version of the picker, add the `compact` boolean attribute to get one: + +```html + +``` + +If you need a more compact version of the picker, add the `compact` boolean attribute to get one: + +```html + +``` + +You can hide the `color-space` part with CSS to show only the coordinates of the specified space: ```html @@ -46,9 +57,14 @@ preserved (if it is in the new space) or reset to the first available one: All properties are reactive and can be set programmatically: ```html - + + +``` + +```html + ``` @@ -83,6 +99,7 @@ All properties are reactive and can be set programmatically: | Attribute | Property | Property type | Default value | Description | | --------- | -------- | ------------- | ------------- | -------------------------------- | | `value` | `value` | `string` | `oklch.l` | The current value of the picker. | +| `compact` | `compact` | `boolean` | `false` | Whether the picker should be rendered compact or not. | ### Getters @@ -103,9 +120,9 @@ These properties are read-only. ### Parts -| Name | Description | -| ------------------ | ------------------------------------------------------------------------ | -| `wrapper` | The component's wrapper element. | -| `color-space` | The internal [``](../space-picker/) element. | +| Name | Description | +|----------------|------------------------------------------------------| +| `color-space` | The internal [``](../space-picker/) element. | | `color-space-base` | The internal `` element used to render the channels. | diff --git a/src/channel-picker/channel-picker.css b/src/channel-picker/channel-picker.css index f8624f75..71531841 100644 --- a/src/channel-picker/channel-picker.css +++ b/src/channel-picker/channel-picker.css @@ -16,53 +16,88 @@ display: flex; gap: .3em; align-items: baseline; + inline-size: fit-content; } -[part="space-picker"] { - &:not(:hover) { - border-color: transparent; - } -} - - -#channels { - display: flex; - inline-size: fit-content; +:host(:is(.compact, [compact])) { + padding: .3em .5em; border: var(--_border-width) solid var(--_border-color); border-radius: var(--_border-radius); - label { - display: grid; - place-items: center; - min-inline-size: 5ch; - padding: .3em .5em; + [part="space-picker"] { + padding: initial; + padding-inline-end: .4em; + border-radius: 0; + border: none; + border-inline-end: var(--_border-width) solid var(--_border-color); + } + [part="picker"] { + font: inherit; + color: inherit; + background: inherit; + border: none; + field-sizing: content; cursor: pointer; - &:hover { - background-color: var(--_accent-color); + &:focus:not(:focus-visible) { + outline: none; } + } +} - & + & { - border-inline-start: var(--_border-width) solid var(--_border-color); - } +:host(:not(.compact, [compact])) { + [part="space-picker"] { + font-weight: 600; - &:has(:checked) { - background: var(--_selected-channel-background); - box-shadow: var(--_selected-channel-shadow); + &:not(:hover) { + border-color: transparent; } } - .sr-only { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip: rect(0, 0, 0, 0); - white-space: nowrap; - border-width: 0; + #channels { + display: flex; + inline-size: fit-content; + + border: var(--_border-width) solid var(--_border-color); + border-radius: var(--_border-radius); + + font-size: 80%; + + label { + display: grid; + place-items: center; + min-inline-size: 5ch; + padding: .3em .5em; + + cursor: pointer; + + &:hover { + background-color: var(--_accent-color); + } + + & + & { + border-inline-start: var(--_border-width) solid var(--_border-color); + } + + &:has(:checked) { + background: var(--_selected-channel-background); + box-shadow: var(--_selected-channel-shadow); + } + } + + /* Visually hide the radio buttons */ + .sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; + } } } diff --git a/src/channel-picker/channel-picker.js b/src/channel-picker/channel-picker.js index 30277e91..41bbcf7d 100644 --- a/src/channel-picker/channel-picker.js +++ b/src/channel-picker/channel-picker.js @@ -41,7 +41,7 @@ const Self = class ChannelPicker extends ColorElement { } get selectedChannel () { - return this.selectedSpace.coords?.[this.#checkedChannel]; + return this.selectedSpace.coords?.[this.compact ? this.#channelSelect.value : this.#checkedChannel]; } get #checkedChannel () { @@ -55,6 +55,10 @@ const Self = class ChannelPicker extends ColorElement { } } + get #channelSelect () { + return this._el.channels.querySelector("select[part=picker]"); + } + /** * Previously selected channels for each space. * Keys are space IDs. Values are coords. @@ -70,10 +74,23 @@ const Self = class ChannelPicker extends ColorElement { return; } + let compact = this.compact; + this.classList.toggle("compact", compact); + + let html = compact ? ` ${ coord.name }`) + html += Object.entries(coords) + .map(([id, coord], index) => { + if (compact) { + return ``; + } + else { + return ``; + } + }) .join("\n"); + html += compact ? "" : ""; + this._el.channels.innerHTML = html; let [prevSpace, prevChannel] = this.value?.split(".") ?? []; if (prevSpace && prevChannel) { @@ -81,11 +98,21 @@ const Self = class ChannelPicker extends ColorElement { let currentChannelName = coords[prevChannel]?.name; if (prevChannelName === currentChannelName) { // Preserve the channel if it exists in the new space and has the same name ("b" in "oklab" is not the same as "b" in "p3") - this.#checkedChannel = prevChannel; + if (compact) { + this.#channelSelect.value = prevChannel; + } + else { + this.#checkedChannel = prevChannel; + } } else if (this.#history?.[space.id]) { // Otherwise, try to restore the last channel used - this.#checkedChannel = this.#history[space.id]; + if (compact) { + this.#channelSelect.value = this.#history[space.id]; + } + else { + this.#checkedChannel = this.#history[space.id]; + } } } } @@ -95,8 +122,10 @@ const Self = class ChannelPicker extends ColorElement { this.#render(); } - if (this._el.space_picker === event.target || event.target.matches("input[type=radio]")) { - let value = `${ this._el.space_picker.value }.${ this.#checkedChannel }`; + if (this._el.space_picker === event.target || this.#channelSelect === event.target || event.target.matches("input[type=radio]")) { + let space = this._el.space_picker.value; + let channel = this.compact ? this.#channelSelect.value : this.#checkedChannel; + let value = `${ space }.${ channel }`; if (value !== this.value) { this.value = value; } @@ -108,7 +137,7 @@ const Self = class ChannelPicker extends ColorElement { let [space, channel] = (this.value + "").split("."); let currentSpace = this._el.space_picker.value; - let currentCoord = this.#checkedChannel; + let currentCoord = this.compact ? this.#channelSelect?.value : this.#checkedChannel; let currentValue = `${ currentSpace }.${ currentCoord }`; if (!space || !channel) { @@ -131,7 +160,12 @@ const Self = class ChannelPicker extends ColorElement { let coords = Object.keys(this.selectedSpace.coords ?? {}); if (coords.includes(channel)) { - this.#checkedChannel = channel; + if (this.compact) { + this.#channelSelect.value = channel; + } + else { + this.#checkedChannel = channel; + } } else { currentCoord = coords.includes(currentCoord) ? currentCoord : coords[0]; @@ -151,12 +185,33 @@ const Self = class ChannelPicker extends ColorElement { } } } + + if (name === "compact") { + this.#render(); + } } static props = { value: { default: "oklch.l", }, + + compact: { + default: false, + parse (value) { + if (value === undefined || value === null || value === false || value === "false") { + return false; + } + + if (value === "" || value === "compact" || value === true || value === "true") { + // Boolean attribute + return true; + } + }, + reflect: { + from: true, + }, + }, }; static events = { From 3345a0e629267978f65df6178d0680f4dac60677 Mon Sep 17 00:00:00 2001 From: Dmitry Sharabin Date: Thu, 28 Nov 2024 11:44:42 +0100 Subject: [PATCH 07/13] Some style tweaks --- src/channel-picker/channel-picker.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/channel-picker/channel-picker.css b/src/channel-picker/channel-picker.css index 71531841..7400787f 100644 --- a/src/channel-picker/channel-picker.css +++ b/src/channel-picker/channel-picker.css @@ -15,7 +15,7 @@ display: flex; gap: .3em; - align-items: baseline; + align-items: center; inline-size: fit-content; } @@ -63,13 +63,13 @@ border: var(--_border-width) solid var(--_border-color); border-radius: var(--_border-radius); - font-size: 80%; + font-size: 70%; label { display: grid; place-items: center; min-inline-size: 5ch; - padding: .3em .5em; + padding: .3em 1.2em; cursor: pointer; From 68dc36e2917bbb7148f5200bd376439c3ca7a4b9 Mon Sep 17 00:00:00 2001 From: Dmitry Sharabin Date: Thu, 28 Nov 2024 12:11:42 +0100 Subject: [PATCH 08/13] Refactor to use array instead of string --- src/channel-picker/channel-picker.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/channel-picker/channel-picker.js b/src/channel-picker/channel-picker.js index 41bbcf7d..f8f148be 100644 --- a/src/channel-picker/channel-picker.js +++ b/src/channel-picker/channel-picker.js @@ -77,9 +77,9 @@ const Self = class ChannelPicker extends ColorElement { let compact = this.compact; this.classList.toggle("compact", compact); - let html = compact ? ``] : []; + html.push(...Object.entries(coords) + // By default, the first channel is selected .map(([id, coord], index) => { if (compact) { return ``; @@ -87,10 +87,11 @@ const Self = class ChannelPicker extends ColorElement { else { return ``; } - }) - .join("\n"); - html += compact ? "" : ""; - this._el.channels.innerHTML = html; + })); + if (compact) { + html.push(""); + } + this._el.channels.innerHTML = html.join("\n"); let [prevSpace, prevChannel] = this.value?.split(".") ?? []; if (prevSpace && prevChannel) { From 0d7a725b4dd5b9334a5f4277a2260d6c4f255bc8 Mon Sep 17 00:00:00 2001 From: Dmitry Sharabin Date: Thu, 28 Nov 2024 12:12:35 +0100 Subject: [PATCH 09/13] `input` bubbles, so we shouldn't need `capture` --- src/channel-picker/channel-picker.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/channel-picker/channel-picker.js b/src/channel-picker/channel-picker.js index f8f148be..d6db087e 100644 --- a/src/channel-picker/channel-picker.js +++ b/src/channel-picker/channel-picker.js @@ -26,14 +26,14 @@ const Self = class ChannelPicker extends ColorElement { connectedCallback () { super.connectedCallback?.(); - this._el.channels.addEventListener("input", this, {capture: true}); + this._el.channels.addEventListener("input", this); } disconnectedCallback () { super.disconnectedCallback?.(); this._el.space_picker.removeEventListener("spacechange", this); - this._el.channels.removeEventListener("input", this, {capture: true}); + this._el.channels.removeEventListener("input", this); } get selectedSpace () { From c8e62d3559d51f633eb2a6bf08d6c37b0007cc7e Mon Sep 17 00:00:00 2001 From: Dmitry Sharabin Date: Wed, 4 Dec 2024 22:20:27 +0100 Subject: [PATCH 10/13] Implement style with connector --- src/channel-picker/channel-picker.css | 79 +++++++++++++++++---------- 1 file changed, 50 insertions(+), 29 deletions(-) diff --git a/src/channel-picker/channel-picker.css b/src/channel-picker/channel-picker.css index 7400787f..f5f37f82 100644 --- a/src/channel-picker/channel-picker.css +++ b/src/channel-picker/channel-picker.css @@ -13,49 +13,72 @@ --_border-color: var(--border-color, var(--_color-neutral-20a)); --_border-radius: var(--border-radius, .2em); + --_gap: 1.5rem; + display: flex; - gap: .3em; + gap: var(--_gap); align-items: center; inline-size: fit-content; -} -:host(:is(.compact, [compact])) { - padding: .3em .5em; + [part="space-picker"] { + position: relative; - border: var(--_border-width) solid var(--_border-color); - border-radius: var(--_border-radius); + font-size: 120%; - [part="space-picker"] { - padding: initial; - padding-inline-end: .4em; - border-radius: 0; - border: none; - border-inline-end: var(--_border-width) solid var(--_border-color); + &::before, + &::after { + --_line-height: calc(1.6 * var(--_border-width)); + position: absolute; + content: ""; + } + + /* Line */ + &::before { + inset-block-start: calc(50% - var(--_line-height) / 2); + inset-inline-start: calc(100% + var(--_border-width)); + inline-size: var(--_gap); + block-size: var(--_line-height); + background-color: var(--_border-color); + } + + /* Circle */ + &::after { + --_radius: .12em; + + inset-block-start: calc(50% - var(--_radius)); + inset-inline-start: calc(100% - var(--_border-width) / 4 + var(--_gap) - var(--_radius) / 2); + border-radius: 50%; + block-size: calc(2 * var(--_radius)); + aspect-ratio: 1; + background-color: color-mix(in oklch, var(--_color-neutral) 30%, canvas); + } } - [part="picker"] { - font: inherit; + #channels { + font-size: 75%; + color: inherit; background: inherit; - border: none; - field-sizing: content; - cursor: pointer; - - &:focus:not(:focus-visible) { - outline: none; - } } } -:host(:not(.compact, [compact])) { - [part="space-picker"] { - font-weight: 600; +:host(:is(.compact, [compact])) { + [part="picker"] { + padding-block: .65em; + padding-inline: .5em .4em; - &:not(:hover) { - border-color: transparent; - } + border: var(--_border-width) solid var(--_border-color); + border-radius: var(--_border-radius); + + font: inherit; + + field-sizing: content; + + cursor: pointer; } +} +:host(:not(.compact, [compact])) { #channels { display: flex; inline-size: fit-content; @@ -63,8 +86,6 @@ border: var(--_border-width) solid var(--_border-color); border-radius: var(--_border-radius); - font-size: 70%; - label { display: grid; place-items: center; From 2abca2da380928f9f0582f51fe443b2b9e0c1786 Mon Sep 17 00:00:00 2001 From: Dmitry Sharabin Date: Mon, 9 Dec 2024 15:09:00 +0100 Subject: [PATCH 11/13] Resolve merge conflicts --- src/channel-picker/README.md | 10 ++-------- src/channel-picker/channel-picker.css | 4 ++-- src/channel-picker/channel-picker.js | 4 ++-- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/channel-picker/README.md b/src/channel-picker/README.md index c510fecc..b37dca55 100644 --- a/src/channel-picker/README.md +++ b/src/channel-picker/README.md @@ -8,8 +8,8 @@ ``` -If no color channel is provided (via the `value` attribute/property), the -default `oklch.l` will be used: +If no color channel is provided (via the `value` attribute/property), +the default `oklch.l` will be used: ```html @@ -21,12 +21,6 @@ If you need a more compact version of the picker, add the `compact` boolean attr ``` -If you need a more compact version of the picker, add the `compact` boolean attribute to get one: - -```html - -``` - You can hide the `color-space` part with CSS to show only the coordinates of the specified space: ```html diff --git a/src/channel-picker/channel-picker.css b/src/channel-picker/channel-picker.css index f5f37f82..025cc30c 100644 --- a/src/channel-picker/channel-picker.css +++ b/src/channel-picker/channel-picker.css @@ -20,7 +20,7 @@ align-items: center; inline-size: fit-content; - [part="space-picker"] { + [part="color-space"] { position: relative; font-size: 120%; @@ -63,7 +63,7 @@ } :host(:is(.compact, [compact])) { - [part="picker"] { + [part="color-channel-base"] { padding-block: .65em; padding-inline: .5em .4em; diff --git a/src/channel-picker/channel-picker.js b/src/channel-picker/channel-picker.js index d6db087e..4b7dbd21 100644 --- a/src/channel-picker/channel-picker.js +++ b/src/channel-picker/channel-picker.js @@ -56,7 +56,7 @@ const Self = class ChannelPicker extends ColorElement { } get #channelSelect () { - return this._el.channels.querySelector("select[part=picker]"); + return this._el.channels.querySelector("select[part=color-channel-base]"); } /** @@ -77,7 +77,7 @@ const Self = class ChannelPicker extends ColorElement { let compact = this.compact; this.classList.toggle("compact", compact); - let html = compact ? [``] : []; html.push(...Object.entries(coords) // By default, the first channel is selected .map(([id, coord], index) => { From a337ea5204730274a255189608bb3132ca49eca0 Mon Sep 17 00:00:00 2001 From: Dmitry Sharabin Date: Mon, 9 Dec 2024 15:12:38 +0100 Subject: [PATCH 12/13] Update docs --- src/channel-picker/README.md | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/src/channel-picker/README.md b/src/channel-picker/README.md index b37dca55..b6c1bdcf 100644 --- a/src/channel-picker/README.md +++ b/src/channel-picker/README.md @@ -35,14 +35,11 @@ You can hide the `color-space` part with CSS to show only the coordinates of the ### Events -You can listen to the `valuechange` event to get the current value (the `value` -property). When a new color space is selected, the channel will be either -preserved (if it is in the new space) or reset to the first available one: +You can listen to the `valuechange` event to get the current value (the `value` property). When a new color space is selected, +the channel will be either preserved (if it is in the new space) or reset to the first available one: ```html - + ``` @@ -62,8 +59,7 @@ All properties are reactive and can be set programmatically: ``` -`` plays nicely with other color elements, like -[``](../channel-slider): +`` plays nicely with other color elements, like [``](../channel-slider): ```html @@ -91,7 +87,7 @@ All properties are reactive and can be set programmatically: ### Attributes & Properties | Attribute | Property | Property type | Default value | Description | -| --------- | -------- | ------------- | ------------- | -------------------------------- | +|-----------|----------|---------------|---------------|----------------------------------| | `value` | `value` | `string` | `oklch.l` | The current value of the picker. | | `compact` | `compact` | `boolean` | `false` | Whether the picker should be rendered compact or not. | @@ -99,18 +95,18 @@ All properties are reactive and can be set programmatically: These properties are read-only. -| Property | Type | Description | -| ----------------- | ------------ | ------------------------------------------------------------------- | -| `selectedSpace` | `ColorSpace` | Color space object corresponding to the space picker current value. | -| `selectedChannel` | `object` | The current channel metadata. | +| Property | Type | Description | +|----------|------|-------------| +| `selectedSpace` | `ColorSpace` | Color space object corresponding to the space picker current value. | +| `selectedChannel` | `object` | The current channel metadata.| ### Events -| Name | Description | -| ------------- | ---------------------------------------------------------------------------- | -| `input` | Fired when the color space or channel changes due to user action. | -| `change` | Fired when the color space or channel changes due to user action. | -| `valuechange` | Fired when the value changes for any reason, and once during initialization. | +| Name | Description | +|-----------------|--------------------------------------------------------------------------------| +| `input` | Fired when the color space or channel changes due to user action. | +| `change` | Fired when the color space or channel changes due to user action. | +| `valuechange` | Fired when the value changes for any reason, and once during initialization. | ### Parts @@ -118,5 +114,5 @@ These properties are read-only. |----------------|------------------------------------------------------| | `color-space` | The internal [``](../space-picker/) element. | | `color-space-base` | The internal `` element used to render the channels. | +| `channels` | The container that wraps the current color space channels. | From 2f68190ca61f079b24f89c99823a600eac392fde Mon Sep 17 00:00:00 2001 From: Dmitry Sharabin Date: Fri, 13 Dec 2024 17:41:21 +0100 Subject: [PATCH 13/13] Fix dark mode --- src/channel-picker/channel-picker.css | 48 ++++++++++++++++++++------- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/src/channel-picker/channel-picker.css b/src/channel-picker/channel-picker.css index 025cc30c..487b0384 100644 --- a/src/channel-picker/channel-picker.css +++ b/src/channel-picker/channel-picker.css @@ -1,20 +1,42 @@ :host { - --_color-neutral: var(--neutral-color, hsl(0 0% 0%)); - --_color-neutral-5a: color-mix(in oklch, var(--_color-neutral) 5%, oklch(none none none / 0)); - --_color-neutral-7a: color-mix(in oklch, var(--_color-neutral) 7%, oklch(none none none / 0)); - --_color-neutral-10a: color-mix(in oklch, var(--_color-neutral) 10%, oklch(none none none / 0)); - --_color-neutral-20a: color-mix(in oklch, var(--_color-neutral) 20%, oklch(none none none / 0)); - - --_accent-color: var(--accent-color, var(--_color-neutral-5a)); - - --_selected-channel-background: var(--selected-channel-background, var(--_color-neutral-5a)); - --_selected-channel-shadow: 0 .1em .2em var(--_color-neutral-10a) inset, 0 0 0 2em var(--_color-neutral-7a) inset; + --_color-neutral: var(--color-neutral, oklch(50% 0.03 230)); + --_color-neutral-5a: color-mix(in oklch, var(--_color-neutral) 5%, canvas); + --_color-neutral-10a: color-mix(in oklch, var(--_color-neutral) 10%, canvas); + --_color-neutral-15a: color-mix(in oklch, var(--_color-neutral) 15%, canvas); + --_color-neutral-20a: color-mix(in oklch, var(--_color-neutral) 20%, canvas); + --_color-neutral-30a: color-mix(in oklch, var(--_color-neutral) 30%, canvas); + --_color-neutral-40a: color-mix(in oklch, var(--_color-neutral) 40%, canvas); + --_color-neutral-50a: color-mix(in oklch, var(--_color-neutral) 50%, canvas); + --_color-neutral-70a: color-mix(in oklch, var(--_color-neutral) 70%, canvas); + --_color-neutral-90a: color-mix(in oklch, var(--_color-neutral) 90%, canvas); + + --_accent-color: var(--accent-color, var(--_color-neutral-15a)); + + --_selected-channel-background: var(--selected-channel-background, var(--_color-neutral-15a)); + --_selected-channel-shadow: 0 .1em .2em var(--_color-neutral-40a) inset, 0 0 0 2em var(--_color-neutral-20a) inset; + + --_border-color: var(--border-color, var(--_color-neutral-30a)); --_border-width: var(--border-width, 1px); - --_border-color: var(--border-color, var(--_color-neutral-20a)); --_border-radius: var(--border-radius, .2em); --_gap: 1.5rem; + @supports (color: light-dark(white, black)) { + --_accent-color-light: var(--accent-color-light, var(--_color-neutral-5a)); + --_accent-color-dark: var(--accent-color-dark, var(--_color-neutral-20a)); + --_accent-color: light-dark(var(--_accent-color-light), var(--_accent-color-dark)); + + --_selected-channel-background-light: var(--selected-channel-background-light, var(--_color-neutral-5a)); + --_selected-channel-background-dark: var(--selected-channel-background-dark, var(--_color-neutral-20a)); + --_selected-channel-background: light-dark(var(--_selected-channel-background-light), var(--_selected-channel-background-dark)); + + --_selected-channel-shadow: 0 .1em .2em light-dark(var(--_color-neutral-20a), var(--_color-neutral-50a)) inset, 0 0 0 2em light-dark(var(--_color-neutral-10a), var(--_color-neutral-40a)) inset; + + --_border-color-light: var(--border-color-light, var(--_color-neutral-30a)); + --_border-color-dark: var(--border-color-dark, var(--_color-neutral-70a)); + --_border-color: light-dark(var(--_border-color-light), var(--_border-color-dark)); + } + display: flex; gap: var(--_gap); align-items: center; @@ -23,6 +45,7 @@ [part="color-space"] { position: relative; + border-color: var(--_border-color); font-size: 120%; &::before, @@ -50,7 +73,8 @@ border-radius: 50%; block-size: calc(2 * var(--_radius)); aspect-ratio: 1; - background-color: color-mix(in oklch, var(--_color-neutral) 30%, canvas); + background-color: var(--_color-neutral-50a); + background-color: light-dark(var(--_color-neutral-30a), var(--_color-neutral-90a)); } }