diff options
-rw-r--r-- | scripts/gui-common/widgets.js | 62 | ||||
-rw-r--r-- | styles/widgets.css | 97 |
2 files changed, 101 insertions, 58 deletions
diff --git a/scripts/gui-common/widgets.js b/scripts/gui-common/widgets.js index 2c5ed26..1be8ac3 100644 --- a/scripts/gui-common/widgets.js +++ b/scripts/gui-common/widgets.js @@ -14,7 +14,10 @@ class Widget extends EventTarget{ /** @type {boolean} */ #inactive = false; - + + /** @type {Array<string>} */ + prevent_keys = []; + /** * Construct a new widget */ @@ -137,9 +140,11 @@ class Widget extends EventTarget{ this.element.classList.add("touch"); else if (event.type == "keyup") this.element.classList.remove("touch"); - event.preventDefault(); } + + if (this.prevent_keys.indexOf(event.key) != -1) + event.preventDefault(); } /** @param {FocusEvent} event */ @@ -355,6 +360,8 @@ class WidgetToggle extends Widget super(); this.element.classList.add("button"); this.element.classList.add("toggle"); + this.element.setAttribute("aria-role", "switch"); + this.element.setAttribute("aria-checked", value === tv ? "true" : "false"); this.addEventListener("mousedown", this.#prime); this.addEventListener("mouseup", this.#toggle); this.addEventListener("mouseleave", this.#leave); @@ -396,7 +403,7 @@ class WidgetToggle extends Widget update() { - this.element.classList.toggle("active", this.get() === this.get("true")); + this.element.setAttribute("aria-checked", this.get() === this.get("true") ? "true" : "false"); } /** @param {MouseEvent} event */ @@ -467,6 +474,7 @@ class WidgetCheckbox extends WidgetToggle { constructor(value = false, tv = true, fv = false) { super(value, tv, fv); + this.element.setAttribute("aria-role", "checkbox"); this.element.classList.remove("toggle"); this.element.classList.add("checkbox"); } @@ -638,6 +646,7 @@ class WidgetSlider extends WidgetDragable { super(1); this.element.classList.add("slider"); + this.element.setAttribute("aria-orientation", "vertical"); let fill = document.createElement("div"); fill.classList.add("fill"); this.element.appendChild(fill); @@ -649,6 +658,7 @@ class WidgetSlider extends WidgetDragable this.#u_detail = this.#update_detail.bind(this); this.addEventListener("change", this.#change); + this.addEventListener("keydown", this.#keypress); super.set_by_id("max", max); super.set_by_id("min", min); @@ -656,13 +666,15 @@ class WidgetSlider extends WidgetDragable super.set_by_id("prec", precision); super.set_by_id("perc", percent); this.set(value); + + this.prevent_keys = ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "PageUp", "PageDown", "End", "Home"]; } #common_move(x, y) { let rect = this.element.getBoundingClientRect(); let top = 0, bot = 0, point = 0; - if (this.element.classList.contains("h")) + if (this.element.getAttribute("aria-orientation") == "horizontal") { top = rect.right; bot = rect.left; @@ -757,6 +769,42 @@ class WidgetSlider extends WidgetDragable this.#u_detail = updater; } + /** @param {KeyboardEvent} event */ + #keypress(event) { + if (event.key == "Home") { + this.set(this.get("min")); + return; + } else if (event.key == "End") { + this.set(this.get("max")); + return; + } + + let change = 0; + if (event.key == "PageUp") + change = 5; + else if (event.key == "PageDown") + change = -5; + else if (this.element.getAttribute("aria-orientation") == "horizontal") { + if (event.key == "ArrowRight") + change = 1; + else if (event.key == "ArrowLeft") + change = -1; + } else { + if (event.key == "ArrowUp") + change = 1; + else if (event.key == "ArrowDown") + change = -1; + } + + let val = this.get(); + let min = this.get("min") + let max = this.get("max") + let step = this.get("step"); + val += step * change; + val = Math.min(Math.max(min, val), max); + this.set(val); + } + /** * @param {string} id * @param {*} v @@ -1349,6 +1397,7 @@ class WidgetScrubber extends WidgetDragable super(1); this.element.classList.add("scrubber"); + this.element.setAttribute("aria-orientation", "vertical"); this.#fill = document.createElement("div"); this.#fill.classList.add("fill"); @@ -1386,7 +1435,7 @@ class WidgetScrubber extends WidgetDragable { let rect = this.element.getBoundingClientRect(); let point = 0, dist = 0; - if (this.element.classList.contains("h")) + if (this.element.getAttribute("aria-orientation") == "horizontal") { dist = rect.width / 2; point = x - (rect.left + dist); @@ -1554,6 +1603,7 @@ class WidgetRadio extends Widget { super(); this.element.classList.add("button"); this.element.classList.add("radio"); + this.element.setAttribute("aria-checked", value === tv ? "true" : false); this.addEventListener("mousedown", this.#prime); this.addEventListener("mouseup", this.#toggle); this.addEventListener("mouseleave", this.#leave); @@ -1592,7 +1642,7 @@ class WidgetRadio extends Widget { update() { - this.element.classList.toggle("active", this.get() === this.get("true")); + this.element.setAttribute("aria-checked", this.get() === this.get("true") ? "true" : false); } /** @param {MouseEvent} event */ diff --git a/styles/widgets.css b/styles/widgets.css index dbb8383..d92258a 100644 --- a/styles/widgets.css +++ b/styles/widgets.css @@ -118,7 +118,7 @@ font-weight: bold; } -.toggle.active { +.toggle[aria-checked="true"] { --w-bg: var(--w-tg-active-bg); --w-bg-hover: var(--w-tg-active-bg-hover); --w-bg-active: var(--w-tg-active-bg-active); @@ -135,7 +135,7 @@ overflow: unset; } -.slider.h { +.slider[aria-orientation="horizontal"] { --width: 3; --height: 1; } @@ -162,7 +162,7 @@ content: ''; } -.slider.h > .fill::before { +.slider[aria-orientation="horizontal"] > .fill::before { width: calc(100% * var(--percent)); height: 100%; } @@ -188,7 +188,7 @@ content: ''; } -.slider.h::after { +.slider[aria-orientation="horizontal"]::after { top: calc(50% - var(--w-sl-dots-size) / 2); left: 6px; width: calc(100% - var(--w-sl-dots-size) * 2); @@ -225,7 +225,7 @@ transition-duration: 0.15s; } -.slider.h > .detail, .color-light.h > .detail, .color-temp.h > .detail { +.slider[aria-orientation="horizontal"] > .detail, .color-light[aria-orientation="horizontal"] > .detail, .color-temp[aria-orientation="horizontal"] > .detail { bottom: calc(100% + 20px); right: calc(-1.2 * var(--base-unit) / 2 + 100% * (1 - var(--percent))); } @@ -329,7 +329,7 @@ content: ''; } -.checkbox:checked, .checkbox.active { +.checkbox[aria-checked="true"] { --w-bg: var(--w-cb-active-bg); --w-bg-hover: var(--w-cb-active-bg-hover); --w-bg-active: var(--w-cb-active-bg-active); @@ -337,26 +337,24 @@ box-shadow: 1px 1px var(--w-shadow), 3px 3px var(--w-shadow), 5px 5px var(--w-shadow); } -.checkbox:checked::after, .checkbox.active::after +.checkbox[aria-checked="true"]::after { border-width: 0px 5px 5px 0px; } -.checkbox.inactive:checked, .checkbox.active.inactive, .checkbox:disabled:checked { +.checkbox.inactive[aria-checked="true"], .checkbox:disabled[aria-checked="true"] { box-shadow: 1px 1px var(--w-shadow-inactive), 3px 3px var(--w-shadow-inactive), 5px 5px var(--w-shadow-inactive); } -.checkbox.inactive:checked:active, -.checkbox.active.inactive:active, -.checkbox:disabled:checked:active, -.checkbox.inactive.touch:checked, -.checkbox.active.inactive.touch, -.checkbox:disabled.touch:checked { +.checkbox.inactive[aria-checked="true"]:active, +.checkbox[aria-checked="true"]:disabled:active, +.checkbox.inactive.touch[aria-checked="true"], +.checkbox.touch[aria-checked="true"]:disabled { border: none; box-shadow: 1px 1px var(--w-shadow-inactive), 3px 3px var(--w-shadow-inactive), 5px 5px var(--w-shadow-inactive) !important; } -.checkbox.inactive:checked::before, .checkbox.active.inactive::before, .checkbox:disabled:checked::before { +.checkbox.inactive[aria-checked="true"]::before, .checkbox[aria-checked="true"]:disabled::before { width: 100%; height: 100%; top: 0; @@ -429,7 +427,7 @@ overflow: unset; } -.color-temp.h { +.color-temp[aria-orientation="horizontal"] { --width: 3; --height: 1; background: linear-gradient(to left, rgb(190, 200, 255), white 15%, rgb(250, 160, 100)); @@ -443,7 +441,7 @@ overflow: unset; } -.color-light.h { +.color-light[aria-orientation="horizontal"] { --width: 3; --height: 1; background: linear-gradient(to left, white, black); @@ -469,7 +467,8 @@ border-color: color-mix(in srgb, white calc(100% * (1 - var(--percent))), black calc(100% * var(--percent))); } -.color-temp.h > .fill::after, .color-light.h > .fill::after { +.color-temp[aria-orientation="horizontal"] > .fill::after, +.color-light[aria-orientation="horizontal"] > .fill::after { left: calc(100% * var(--percent) - 7.5px); bottom: calc(50% - 7.5px); } @@ -624,7 +623,7 @@ overflow-x: auto; } -.sel-button.h { +.sel-button[aria-orientation="horizontal"] { flex-direction: column; height: 100%; overflow-y: auto; @@ -673,7 +672,7 @@ overflow: unset; } -.scrubber.h { +.scrubber[aria-orientation="horizontal"] { --width: 44; --height: 1; } @@ -706,7 +705,7 @@ transition-duration: 0.15s; } -.scrubber.h > .fill::after { +.scrubber[aria-orientation="horizontal"] > .fill::after { left: calc(50% - (var(--base-unit) - 10px) / 2 + (50% * var(--percent))); bottom: calc(50% - (var(--base-unit) - 10px) / 2); } @@ -734,7 +733,7 @@ transition-duration: 0.15s; } -.scrubber.h > .fill > .zone +.scrubber[aria-orientation="horizontal"] > .fill > .zone { height: 100%; width: calc(50% / var(--zones)); @@ -779,7 +778,7 @@ transition-duration: 0.15s; } -.scrubber.h > .detail { +.scrubber[aria-orientation="horizontal"] > .detail { bottom: calc(100% + 20px); right: calc(50% - 1.2 * var(--base-unit) / 2); } @@ -797,8 +796,8 @@ .radio { min-width: 0; min-height: 0; - --width: 0.9; - --height: 0.9; + --width: 0.8; + --height: 0.8; --w-bg: rgba(0, 0, 0, 0); --w-bg-hover: rgba(0, 0, 0, 0); @@ -842,8 +841,8 @@ .radio::after { - height: calc(var(--base-unit) * 0.4); - width: calc(var(--base-unit) * 0.4); + height: calc(var(--base-unit) * 0.25); + width: calc(var(--base-unit) * 0.25); box-sizing: border-box; @@ -856,64 +855,57 @@ box-shadow: none; padding: 0; - top: calc(50% - var(--base-unit) * 0.4 / 2); - left: calc(50% - var(--base-unit) * 0.4 / 2); + top: calc(50% - var(--base-unit) * 0.25 / 2); + left: calc(50% - var(--base-unit) * 0.25 / 2); transition-duration: 0.35s; content: ''; } -.radio:checked, .radio.active { +.radio[aria-checked="true"] { border-color: var(--w-radio-active); } -.radio:checked:hover, .radio.active:hover, -.radio:checked:focus-within, .radio.active:focus-within { +.radio[aria-checked="true"]:hover, +.radio[aria-checked="true"]:focus-within { border-color: var(--w-radio-active-hover); } -.radio:checked:hover::after, .radio.active:hover::after, -.radio:checked:focus-within::after, .radio.active:focus-within::after { +.radio[aria-checked="true"]:hover::after, +.radio[aria-checked="true"]:focus-within::after { background-color: var(--w-radio-active-hover); } -.radio:checked::after, .radio.active::after +.radio[aria-checked="true"]::after { background-color: var(--w-radio-active); - box-shadow: 1px 1px var(--w-shadow), 3px 3px var(--w-shadow), 5px 5px var(--w-shadow); } -.radio:checked:active, -.radio:checked.touch, -.radio.active:active, -.radio.active.touch { +.radio[aria-checked="true"]:active, +.radio[aria-checked="true"].touch { border-color: var(--w-radio-active-active); } -.radio:checked:active::after, -.radio:checked.touch::after, -.radio.active:active::after, -.radio.active.touch::after { +.radio[aria-checked="true"]:active::after, +.radio[aria-checked="true"].touch::after { background-color: var(--w-radio-active-active); box-shadow: none; } -.radio.inactive:checked, .radio.active.inactive, .radio:disabled:checked { +.radio.inactive[aria-checked="true"], .radio[aria-checked="true"]:disabled { box-shadow: 1px 1px var(--w-shadow-inactive), 3px 3px var(--w-shadow-inactive), 5px 5px var(--w-shadow-inactive); } -.radio.inactive:checked:active, -.radio.active.inactive:active, -.radio:disabled:checked:active, -.radio.inactive.touch:checked, -.radio.active.inactive.touch, -.radio:disabled.touch:checked { +.radio.inactive[aria-checked="true"]:active, +.radio[aria-checked="true"]:disabled:active, +.radio.inactive.touch[aria-checked="true"], +.radio.touch[aria-checked="true"]:disabled { box-shadow: 1px 1px var(--w-shadow-inactive), 3px 3px var(--w-shadow-inactive), 5px 5px var(--w-shadow-inactive) !important; } -.radio.inactive:checked::before, .radio.active.inactive::before, .radio:disabled:checked::before { +.radio.inactive[aria-checked="true"]::before, .radio[aria-checked="true"]:disabled::before { width: 100%; height: 100%; top: 0; @@ -933,6 +925,7 @@ --width: 3; --height: 2; justify-content: space-around; + overflow-y: auto; } .radio-group.h { |