Resolve a11y for tag options buttons (#2787)

* resolve TagAddButton a11y
better comments to document tagindex reasoning

* resolved a11y for TagsSelectedButton
allow focus to TagsSelectedButton with Shift+Tab and Enter or Space to show popover

* safely ignore a11y warning as container for interactables is not itself interactable

* Update CONTRIBUTORS

* quick fix syntax

* quick fix syntax

* quick fix syntax

* quick fix syntax

* resolved a11y in accordance with ARIA APG Disclure pattern

* resolved a11y
ideally should replace with  with
a11y-click-events-have-key-events is explicitly ignored as the alternative (adding ) seems more clunky

* resolved SpinBox a11y
cannot focus on these buttons, so no key event handling needed (keyboard editting already possible by just typing in the field)
widget already properly follows ARIA APG Spinbutton pattern

* cleanup

* onEnterOrSpace() function implemented as discussed in #2787 and #2564

* quick syntax and such changes
This commit is contained in:
Ben Olson 2023-11-13 17:40:04 -08:00 committed by GitHub
parent 9cd4f04677
commit 7bcb57b89e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 43 additions and 5 deletions

View file

@ -148,6 +148,7 @@ user1823 <92206575+user1823@users.noreply.github.com>
Gustaf Carefall <https://github.com/Gustaf-C>
virinci <github.com/virinci>
snowtimeglass <snowtimeglass@gmail.com>
Ben Olson <github.com/grepgrok>
********************

View file

@ -4,6 +4,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
-->
<script lang="ts">
import * as tr from "@tslib/ftl";
import { onEnterOrSpace } from "@tslib/keys";
import { slide } from "svelte/transition";
import Badge from "../components/Badge.svelte";
@ -29,7 +30,14 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<div class="alert alert-warning" in:slide out:slide>
{#if unused.length > maxItems}
<div class="clickable" on:click={() => (collapsed = !collapsed)}>
<div
class="clickable"
on:click={() => (collapsed = !collapsed)}
on:keydown={onEnterOrSpace(() => (collapsed = !collapsed))}
role="button"
tabindex="0"
aria-expanded={!collapsed}
>
<Badge iconSize={80}>
{@html icon}
</Badge>

View file

@ -96,11 +96,13 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
on:focusout={() => (focused = false)}
/>
{#if isDesktop()}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
class="spinner decrement"
class:active={value > min}
tabindex="-1"
title={tr.actionsDecrementValue()}
role="button"
on:click={() => {
input.focus();
if (value > min) {
@ -122,11 +124,13 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
{@html chevronDown}
</IconConstrain>
</div>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
class="spinner increment"
class:active={value < max}
tabindex="-1"
title={tr.actionsIncrementValue()}
role="button"
on:click={() => {
input.focus();
if (value < max) {

View file

@ -120,3 +120,14 @@ export function isArrowDown(event: KeyboardEvent): boolean {
return isApplePlatform() && metaPressed(event) && event.code === "KeyN";
}
export function onEnterOrSpace(callback: () => void): (event: KeyboardEvent) => void {
return (event: KeyboardEvent) => {
switch (event.code) {
case "Enter":
case "Space":
callback();
break;
}
};
}

View file

@ -2,7 +2,9 @@
Copyright: Ankitects Pty Ltd and contributors
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
-->
<div class="tag-spacer" on:click>
<!-- on:click allows clicking focus to the tag editor -->
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div class="tag-spacer" on:click role="textbox" tabindex="-1">
<br />
</div>

View file

@ -21,10 +21,13 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
}
</script>
<!-- toggle tabindex to allow Shift+Tab to move focus to the last field -->
<!-- toggle tabindex to allow Tab to move focus to the tag editor from the last field -->
<!-- and allow Shift+Tab to move focus to the last field while inputting tag -->
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
class="tag-add-button"
title="{tr.editingTagsAdd()} ({getPlatformString(keyCombination)})"
role="button"
tabindex={$currentTagInput ? -1 : 0}
on:click={appendTag}
on:focus={appendTag}

View file

@ -11,6 +11,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
export let keyCombination: string;
</script>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div
class="tag-options-button gap"
bind:offsetHeight={badgeHeight}

View file

@ -13,6 +13,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import * as tr from "@tslib/ftl";
import { getPlatformString } from "@tslib/shortcuts";
import { dotsIcon } from "./icons";
import { onEnterOrSpace } from "@tslib/keys";
const dispatch = createEventDispatcher();
@ -29,7 +30,14 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
shift={0}
let:asReference
>
<div class="tags-selected-button" use:asReference on:click={() => (show = !show)}>
<div
class="tags-selected-button"
use:asReference
role="button"
tabindex="0"
on:click={() => (show = !show)}
on:keydown={onEnterOrSpace(() => (show = !show))}
>
<IconConstrain>{@html dotsIcon}</IconConstrain>
</div>
@ -50,8 +58,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<style lang="scss">
.tags-selected-button {
line-height: 1;
:global(svg) {
padding-bottom: 2px;
cursor: pointer;
fill: currentColor;
opacity: 0.6;