Ruby Switch script v1
This commit is contained in:
parent
c56f91da2c
commit
abb85f701d
1 changed files with 164 additions and 0 deletions
164
assets/scripts/ruby_switch.js
Normal file
164
assets/scripts/ruby_switch.js
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
class RubySwitch extends HTMLElement {
|
||||||
|
static controlSizeInPixels = 32;
|
||||||
|
static thumbTransitionDuration = 0.1;
|
||||||
|
|
||||||
|
static settings = [
|
||||||
|
{
|
||||||
|
id: "ruby-switch-none",
|
||||||
|
value: "none",
|
||||||
|
label: "あ"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "ruby-switch-both",
|
||||||
|
value: "both",
|
||||||
|
label: "あa",
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "ruby-switch-hidden",
|
||||||
|
value: "hidden",
|
||||||
|
label: "ab"
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
#root;
|
||||||
|
#thumb;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.#updateValue(RubySwitch.settings.find(obj => obj.default).value);
|
||||||
|
this.addEventListener("RubyStyleChanged", event => {
|
||||||
|
this.#updateValue(event.detail.style);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.#root = this.attachShadow({ mode: "closed" });
|
||||||
|
this.#buildShadowDOM();
|
||||||
|
|
||||||
|
this.#updateThumbPosition(this.#root.querySelector(".control[data-default]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#updateValue(style) {
|
||||||
|
this.setAttribute("value", style);
|
||||||
|
}
|
||||||
|
|
||||||
|
get #stylesheet() {
|
||||||
|
const controlSize = RubySwitch.controlSizeInPixels;
|
||||||
|
const halfControlSize = controlSize / 2;
|
||||||
|
|
||||||
|
return `
|
||||||
|
#ruby-controls {
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
#controls {
|
||||||
|
border: none;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: inline grid;
|
||||||
|
grid-template-columns: repeat(3, ${controlSize}px);
|
||||||
|
margin: 0;
|
||||||
|
overflow: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#thumb {
|
||||||
|
box-sizing: border-box;
|
||||||
|
box-shadow: 2px 2px 6px #ccc;
|
||||||
|
border: 0.5px solid #aaa;
|
||||||
|
border-radius: ${halfControlSize}px;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
height: ${controlSize}px;
|
||||||
|
width: ${controlSize}px;
|
||||||
|
z-index: 50;
|
||||||
|
transition: left ${RubySwitch.thumbTransitionDuration}s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control {
|
||||||
|
aspect-ratio: 1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: ${controlSize}px;
|
||||||
|
width: ${controlSize}px;
|
||||||
|
}
|
||||||
|
|
||||||
|
b {
|
||||||
|
font-weight: normal;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
z-index: 2;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
#buildShadowDOM() {
|
||||||
|
const root = this.#root;
|
||||||
|
|
||||||
|
const style = document.createElement("style");
|
||||||
|
style.textContent = this.#stylesheet;
|
||||||
|
root.appendChild(style);
|
||||||
|
|
||||||
|
let container = document.createElement("div");
|
||||||
|
container.id = "ruby-controls";
|
||||||
|
root.appendChild(container);
|
||||||
|
|
||||||
|
let controls = document.createElement("div");
|
||||||
|
controls.id = "controls";
|
||||||
|
container.appendChild(controls);
|
||||||
|
|
||||||
|
for (const desc of RubySwitch.settings) {
|
||||||
|
let control = document.createElement("div");
|
||||||
|
control.classList.add("control")
|
||||||
|
control.id = desc.id;
|
||||||
|
|
||||||
|
control.dataset.value = desc.value;
|
||||||
|
if (desc.default) {
|
||||||
|
control.dataset.default = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
controls.appendChild(control);
|
||||||
|
|
||||||
|
control.addEventListener("click", event => {
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
this.#updateThumbPosition(event.currentTarget);
|
||||||
|
|
||||||
|
this.#root.dispatchEvent(new CustomEvent("RubyStyleChanged", {
|
||||||
|
bubbles: true,
|
||||||
|
composed: true,
|
||||||
|
detail: {
|
||||||
|
style: control.dataset.value,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}, { capture: true });
|
||||||
|
|
||||||
|
const label = document.createElement("b");
|
||||||
|
label.textContent = desc.label;
|
||||||
|
control.appendChild(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
const thumb = document.createElement("div");
|
||||||
|
this.#thumb = thumb;
|
||||||
|
thumb.id = "thumb";
|
||||||
|
container.appendChild(thumb);
|
||||||
|
}
|
||||||
|
|
||||||
|
#updateThumbPosition(selectedControl) {
|
||||||
|
const controls = this.#root.querySelector("#controls");
|
||||||
|
|
||||||
|
const trackBoundingRect = controls.getBoundingClientRect();
|
||||||
|
const controlBoundingRect = selectedControl.getBoundingClientRect();
|
||||||
|
|
||||||
|
const offset = controlBoundingRect.left - trackBoundingRect.left;
|
||||||
|
this.#thumb.style.left = `${offset}px`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define("ruby-switch", RubySwitch);
|
Loading…
Add table
Add a link
Reference in a new issue