// Eryn Wells 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; } #ruby-switch-both { } `; } #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.innerHTML = 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);