Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions src/channel-picker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ the default `oklch.l` will be used:
<channel-picker></channel-picker>
```

If you need a more compact version of the picker, add the `compact` boolean attribute to get one:

```html
<channel-picker value="oklch.c" compact></channel-picker>
```

You can hide the `color-space` part with CSS to show only the coordinates of the specified space:

```html
Expand Down Expand Up @@ -46,6 +52,13 @@ All properties are reactive and can be set programmatically:
<channel-picker></channel-picker>
```

```html
<label>
<input type="checkbox" onchange="this.parentElement.nextElementSibling.compact = this.checked" /> Compact picker
</label>
<channel-picker></channel-picker>
```

`<channel-picker>` plays nicely with other color elements, like [`<channel-slider>`](../channel-slider):

```html
Expand All @@ -64,7 +77,7 @@ All properties are reactive and can be set programmatically:
channel_slider.space = space;
channel_slider.channel = channel;
}

channel_picker.onvaluechange = updateSlider;
</script>
```
Expand All @@ -76,6 +89,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

Expand All @@ -100,4 +114,5 @@ These properties are read-only.
|----------------|------------------------------------------------------|
| `color-space` | The internal [`<space-picker>`](../space-picker/) element. |
| `color-space-base` | The internal `<select>` element of [`<space-picker>`](../space-picker/). |
| `color-channel-base` | The internal `<select>` element. |
| `color-channel-base` | If the picker is compact, the internal `<select>` element used to render the channels. |
| `channels` | The container that wraps the current color space channels. |
159 changes: 138 additions & 21 deletions src/channel-picker/channel-picker.css
Original file line number Diff line number Diff line change
@@ -1,31 +1,148 @@
:host {
--border-width: 1px;
--border-color: rgb(0 0 0 / .2);
--border-radius: .2em;
--_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);

padding: .3em .5em;
--_accent-color: var(--accent-color, var(--_color-neutral-15a));

border: var(--border-width) solid var(--border-color);
border-radius: var(--border-radius);
--_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-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;
inline-size: fit-content;

[part="color-space"] {
position: relative;

border-color: var(--_border-color);
font-size: 120%;

&::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: var(--_color-neutral-50a);
background-color: light-dark(var(--_color-neutral-30a), var(--_color-neutral-90a));
}
}

#channels {
font-size: 75%;

color: inherit;
background: inherit;
}
}

#picker {
font: inherit;
color: inherit;
background: inherit;
border: none;
field-sizing: content;
cursor: pointer;
:host(:is(.compact, [compact])) {
[part="color-channel-base"] {
padding-block: .65em;
padding-inline: .5em .4em;

border: var(--_border-width) solid var(--_border-color);
border-radius: var(--_border-radius);

&:focus:not(:focus-visible) {
outline: none;
font: inherit;

field-sizing: content;

cursor: pointer;
}
}

#space_picker {
padding: initial;
padding-inline-end: .4em;
border-radius: 0;
border: none;
border-inline-end: var(--border-width) solid var(--border-color);
:host(:not(.compact, [compact])) {
#channels {
display: flex;
inline-size: fit-content;

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 1.2em;

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;
}
}
}
Loading