196 lines
4.8 KiB
JavaScript
196 lines
4.8 KiB
JavaScript
// rgb-slider.js
|
|
|
|
export class RGBSlider extends HTMLElement {
|
|
constructor() {
|
|
super();
|
|
const shadow = this.attachShadow({ mode: "open" });
|
|
|
|
shadow.innerHTML = `
|
|
<style>
|
|
.container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
padding: 1em;
|
|
border: 1px solid #ccc;
|
|
border-radius: 8px;
|
|
width: 50%;
|
|
|
|
font-family: sans-serif;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.preview {
|
|
width: 50%;
|
|
height: 60px;
|
|
border-radius: 6px;
|
|
border: 1px solid #000;
|
|
background-color: rgb(0, 0, 0);
|
|
margin-bottom: 1em;
|
|
}
|
|
|
|
.sliders {
|
|
display: flex;
|
|
gap: 50px;
|
|
justify-content: center;
|
|
margin-bottom: 1em;
|
|
}
|
|
|
|
.slider-group {
|
|
display: flex;
|
|
flex-direction: column-reverse;
|
|
align-items: center;
|
|
}
|
|
|
|
.slider-group input[type="range"] {
|
|
writing-mode: vertical-lr;
|
|
direction: rtl;
|
|
|
|
width: 10px;
|
|
height: 120px;
|
|
}
|
|
|
|
.slider-group label {
|
|
margin-top: 8px;
|
|
font-size: 0.8em;
|
|
}
|
|
|
|
.rgb-inputs {
|
|
display: flex;
|
|
gap: 8px;
|
|
}
|
|
|
|
.rgb-inputs input {
|
|
width: 6ch;
|
|
padding: 2px;
|
|
font-family: monospace;
|
|
text-align: right;
|
|
}
|
|
|
|
.rgb-inputs label {
|
|
font-size: 0.8em;
|
|
text-align: center;
|
|
}
|
|
|
|
.rgb-input-group {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
}
|
|
|
|
/* Mobile styles */
|
|
@media (max-width: 600px) {
|
|
.preview {
|
|
height: 80px;
|
|
}
|
|
|
|
.slider-group input[type="range"] {
|
|
height: 180px;
|
|
width: 14px;
|
|
}
|
|
|
|
.rgb-inputs input {
|
|
font-size: 1em;
|
|
padding: 4px;
|
|
width: 7ch;
|
|
}
|
|
|
|
.slider-group label,
|
|
.rgb-inputs label {
|
|
font-size: 1em;
|
|
}
|
|
|
|
.container {
|
|
padding: 1.5em;
|
|
}
|
|
}
|
|
</style>
|
|
|
|
|
|
<div class="container">
|
|
<div class="preview" id="preview"></div>
|
|
|
|
<div class="sliders">
|
|
<div class="slider-group">
|
|
<input type="range" min="0" max="255" value="0" id="r">
|
|
<label>R</label>
|
|
</div>
|
|
<div class="slider-group">
|
|
<input type="range" min="0" max="255" value="0" id="g">
|
|
<label>G</label>
|
|
</div>
|
|
<div class="slider-group">
|
|
<input type="range" min="0" max="255" value="0" id="b">
|
|
<label>B</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rgb-inputs">
|
|
<div class="rgb-input-group">
|
|
<label for="rInput">R</label>
|
|
<input type="number" min="0" max="255" id="rInput" value="0">
|
|
</div>
|
|
<div class="rgb-input-group">
|
|
<label for="gInput">G</label>
|
|
<input type="number" min="0" max="255" id="gInput" value="0">
|
|
</div>
|
|
<div class="rgb-input-group">
|
|
<label for="bInput">B</label>
|
|
<input type="number" min="0" max="255" id="bInput" value="0">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
const get = (id) => shadow.querySelector(id);
|
|
this.r = get("#r");
|
|
this.g = get("#g");
|
|
this.b = get("#b");
|
|
this.rInput = get("#rInput");
|
|
this.gInput = get("#gInput");
|
|
this.bInput = get("#bInput");
|
|
this.preview = get("#preview");
|
|
|
|
const updateColor = (r, g, b) => {
|
|
this.preview.style.backgroundColor = `rgb(${r}, ${g}, ${b})`;
|
|
this.rInput.value = r;
|
|
this.gInput.value = g;
|
|
this.bInput.value = b;
|
|
this.dispatchEvent(
|
|
new CustomEvent("color-change", {
|
|
detail: { r, g, b },
|
|
bubbles: true,
|
|
composed: true,
|
|
}),
|
|
);
|
|
};
|
|
|
|
const syncFromSliders = () => {
|
|
const r = +this.r.value;
|
|
const g = +this.g.value;
|
|
const b = +this.b.value;
|
|
updateColor(r, g, b);
|
|
};
|
|
|
|
const syncFromInputs = () => {
|
|
const r = Math.min(255, Math.max(0, +this.rInput.value));
|
|
const g = Math.min(255, Math.max(0, +this.gInput.value));
|
|
const b = Math.min(255, Math.max(0, +this.bInput.value));
|
|
this.r.value = r;
|
|
this.g.value = g;
|
|
this.b.value = b;
|
|
updateColor(r, g, b);
|
|
};
|
|
|
|
this.r.addEventListener("input", syncFromSliders);
|
|
this.g.addEventListener("input", syncFromSliders);
|
|
this.b.addEventListener("input", syncFromSliders);
|
|
|
|
this.rInput.addEventListener("change", syncFromInputs);
|
|
this.gInput.addEventListener("change", syncFromInputs);
|
|
this.bInput.addEventListener("change", syncFromInputs);
|
|
}
|
|
}
|
|
|
|
customElements.define("rgb-slider", RGBSlider);
|