diff options
Diffstat (limited to 'client-web/source')
-rw-r--r-- | client-web/source/helper.ts | 5 | ||||
-rw-r--r-- | client-web/source/logger.ts | 2 | ||||
-rw-r--r-- | client-web/source/menu.ts | 91 | ||||
-rw-r--r-- | client-web/source/preferences/ui.ts | 2 | ||||
-rw-r--r-- | client-web/source/resource/track.ts | 1 | ||||
-rw-r--r-- | client-web/source/room_watches.ts | 4 | ||||
-rw-r--r-- | client-web/source/user/mod.ts | 4 |
7 files changed, 59 insertions, 50 deletions
diff --git a/client-web/source/helper.ts b/client-web/source/helper.ts index 655d894..49ec121 100644 --- a/client-web/source/helper.ts +++ b/client-web/source/helper.ts @@ -17,9 +17,9 @@ interface Opts<E> { alt?: string, onclick?: (e: E) => void, onchange?: (e: E) => void, - role?: "dialog" + role?: "dialog" | "separator" | "switch" | "button" | "log" | "group", aria_label?: string - aria_live?: "polite" | "assertive" + aria_live?: "polite" | "assertive" | "off", aria_modal?: boolean aria_popup?: "menu" icon?: string, @@ -36,6 +36,7 @@ function apply_opts<E extends HTMLElement>(el: E, o: Opts<E>) { if (o.alt !== undefined && el instanceof HTMLImageElement) el.alt = o.alt; if (typeof o?.class == "string") el.classList.add(o.class) if (typeof o?.class == "object") el.classList.add(...o.class) + if (o.role) el.role = o.role; if (o.aria_modal) el.ariaModal = "true" if (o.aria_popup) el.ariaHasPopup = o.aria_popup if (o.aria_label) el.ariaLabel = o.aria_label diff --git a/client-web/source/logger.ts b/client-web/source/logger.ts index 5f5d313..8ff4cab 100644 --- a/client-web/source/logger.ts +++ b/client-web/source/logger.ts @@ -7,7 +7,7 @@ import { e } from "./helper.ts"; -export const LOGGER_CONTAINER = e("div", { class: "logger-container" }) +export const LOGGER_CONTAINER = e("div", { class: "logger-container", role: "log", aria_live: "off" }) const log_scope_color = { "*": "#ff4a7c", diff --git a/client-web/source/menu.ts b/client-web/source/menu.ts index f253bc3..ee2cdca 100644 --- a/client-web/source/menu.ts +++ b/client-web/source/menu.ts @@ -48,7 +48,14 @@ export function control_bar(state: AppState, side_ui_container: HTMLElement): HT e("button", { icon: "file", onclick: () => state.room?.local_user.await_add_resource(create_file_res()) }, "File"), ] chat_control = chat.set_state; - return e("nav", { class: "control-bar" }, leave, "|", chat.el, prefs.el, rwatches.el, "|", ...local_controls) + return e("nav", { class: "control-bar" }, + leave, + e("span", { role: "separator" }, "|"), + chat.el, + prefs.el, + rwatches.el, + e("span", { role: "separator" }, "|"), + ...local_controls) } export interface SideUI { el: HTMLElement, set_state: (s?: boolean) => void } @@ -56,49 +63,49 @@ let close_active: (() => void) | undefined; let cancel_slide: number | undefined export function side_ui(container: HTMLElement, content: HTMLElement, icon: string, label: string, handlers = { focus() { } }): SideUI { const tray = e("div", { class: "side-tray" }, content) - let last_state = false; - const checkbox = e("input", { - type: "checkbox", - onchange: async () => { - if (last_state == checkbox.checked) return - if (checkbox.checked) { - el.classList.add("checked") - if (close_active) { - close_active() - await sleep(200) - } - close_active = () => set_state(false) - if (cancel_slide) { - clearTimeout(cancel_slide) - cancel_slide = undefined - tray.classList.remove("animate-out") - } - tray.classList.add("animate-in") - container.appendChild(tray) - cancel_slide = setTimeout(() => { - handlers.focus() - }, 200) - } else { - el.classList.remove("checked") - close_active = undefined - if (cancel_slide) { - clearTimeout(cancel_slide) - cancel_slide = undefined - } - tray.classList.remove("animate-in") - tray.classList.add("animate-out") - cancel_slide = setTimeout(() => { - tray.classList.remove("animate-out") - container.removeChild(tray) - }, 200) + let checked = false; + const el = e("button", { + class: "side-ui-control", + icon, + onclick: () => set_state() + }, label) + const set_state = async (s?: boolean) => { + if (s == checked) return + checked = s ?? !checked + if (checked) { + el.classList.add("checked") + el.ariaPressed = "false"; + if (close_active) { + close_active() + await sleep(200) } - last_state = checkbox.checked; + close_active = () => set_state(false) + if (cancel_slide) { + clearTimeout(cancel_slide) + cancel_slide = undefined + tray.classList.remove("animate-out") + } + tray.classList.add("animate-in") + container.appendChild(tray) + cancel_slide = setTimeout(() => { + handlers.focus() + }, 200) + } else { + el.classList.remove("checked") + el.ariaPressed = "true"; + close_active = undefined + if (cancel_slide) { + clearTimeout(cancel_slide) + cancel_slide = undefined + } + tray.classList.remove("animate-in") + tray.classList.add("animate-out") + cancel_slide = setTimeout(() => { + tray.classList.remove("animate-out") + container.removeChild(tray) + }, 200) } - }) - const set_state = (s: boolean | undefined) => { - checkbox.checked = s ?? !checkbox.checked; - if (checkbox.onchange) checkbox.onchange(undefined as unknown as Event) } - const el = e("label", { class: "side-ui-control", icon }, label, checkbox) + el.ariaPressed = "false" return { el, set_state } } diff --git a/client-web/source/preferences/ui.ts b/client-web/source/preferences/ui.ts index 0259b2b..44b3e4e 100644 --- a/client-web/source/preferences/ui.ts +++ b/client-web/source/preferences/ui.ts @@ -94,7 +94,7 @@ export function ui_preferences(): HTMLElement { const table = document.createElement("table") table.append(...rows) - return e("div", { class: "preferences" }, + return e("div", { class: "preferences", role: "dialog", aria_label: "settings" }, e("h2", {}, "Settings"), notification_perm, e("br", {}), table, e("br", {}), diff --git a/client-web/source/resource/track.ts b/client-web/source/resource/track.ts index bc8844e..05b0588 100644 --- a/client-web/source/resource/track.ts +++ b/client-web/source/resource/track.ts @@ -81,6 +81,7 @@ function create_track_display(target: HTMLElement, track: TrackHandle): HTMLElem media_el.srcObject = stream media_el.autoplay = true media_el.controls = true + media_el.ariaLabel = `${track.kind} stream` media_el.addEventListener("pause", () => media_el.play()) if (track.local) media_el.muted = true diff --git a/client-web/source/room_watches.ts b/client-web/source/room_watches.ts index fd7d54b..f9d8c1b 100644 --- a/client-web/source/room_watches.ts +++ b/client-web/source/room_watches.ts @@ -41,7 +41,7 @@ export function ui_room_watches(conn: SignalingConnection): HTMLElement { }) let edit = false; - + const update_listing = () => { listing.innerHTML = "" for (let wi = 0; wi < watches.length; wi++) { @@ -96,7 +96,7 @@ export function ui_room_watches(conn: SignalingConnection): HTMLElement { button_finish.hidden = !e; edit = e; } - return e("div", { class: "room-watches" }, + return e("div", { class: "room-watches", role: "dialog", aria_label: "known rooms" }, e("h2", {}, "Known Rooms"), listing, button_edit = e("button", { diff --git a/client-web/source/user/mod.ts b/client-web/source/user/mod.ts index da326b9..7c6c212 100644 --- a/client-web/source/user/mod.ts +++ b/client-web/source/user/mod.ts @@ -10,14 +10,14 @@ import { Room } from "../room.ts"; export class User { private _name?: string - set name(v: string | undefined) { this._name = v; this.name_el.textContent = this.display_name } + set name(v: string | undefined) { this._name = v; this.name_el.textContent = this.display_name; this.el.ariaLabel = "user " + this.display_name } get name() { return this._name } get display_name() { return this.name ?? "Unknown" } name_el = e("span", {}, this.display_name) status_el = e("span", { class: ["connection-status", "status-neutral"] }, "") stats_el = e("pre", {}) - el = e("div", { class: "user" }) + el = e("div", { class: "user", role: "group", aria_label: `unknown user` }) constructor(public room: Room, public id: number) { const info_el = e("div", { class: "info" }) |