From f3ea83ccb47e801e839a134e4112ee83b1d0e83b Mon Sep 17 00:00:00 2001 From: Sam McElligott Date: Mon, 3 Jan 2022 12:30:41 +0000 Subject: [PATCH] Feature - add keyboard navigation support --- src/components/MovieRow.css | 9 +++++++ src/components/MovieRow.js | 8 +++++- src/components/NumberSelector.css | 7 +++++- src/components/NumberSelector.js | 7 +++++- src/components/SelectBox.css | 4 +++ src/components/SelectBox.js | 30 +++++++++++++++------- src/components/Title.css | 11 +++++++++ src/components/Title.js | 20 ++++++++++----- src/components/TypeSelector.css | 5 ++++ src/components/TypeSelector.js | 41 ++++++++++++++++++++----------- src/views/Search.css | 5 ++++ src/views/Search.js | 10 ++++++-- 12 files changed, 123 insertions(+), 34 deletions(-) diff --git a/src/components/MovieRow.css b/src/components/MovieRow.css index a8153064..de87da9c 100644 --- a/src/components/MovieRow.css +++ b/src/components/MovieRow.css @@ -60,6 +60,15 @@ transform: translateX(.3rem) translateY(.1rem); } +.movieRow:focus-visible { + border: 1px solid #fff; + background-color: var(--content-hover); +} + +.movieRow:focus-visible .watch .arrow { + transform: translateX(.3rem) translateY(.1rem); +} + .attribute { color: var(--text); background-color: var(--theme-color); diff --git a/src/components/MovieRow.js b/src/components/MovieRow.js index 60b6783e..438a148c 100644 --- a/src/components/MovieRow.js +++ b/src/components/MovieRow.js @@ -19,8 +19,14 @@ export function MovieRow(props) { } } + function handleKeyPress(event){ + if ((event.code === 'Enter' || event.code === 'Space') && props.onClick){ + props.onClick(); + } + } + return ( -
props.onClick && props.onClick()}> +
props.onClick && props.onClick()}> { props.source === "lookmovie" && (
diff --git a/src/components/NumberSelector.css b/src/components/NumberSelector.css index 3c8d5f06..5ec06fc7 100644 --- a/src/components/NumberSelector.css +++ b/src/components/NumberSelector.css @@ -39,10 +39,15 @@ box-sizing: border-box; } -.numberSelector .choice:hover { +.numberSelector .choice:hover, +.numberSelector .choiceWrapper:focus-visible .choice { background-color: var(--choice-hover); } +.numberSelector .choiceWrapper:focus-visible { + border: 1px solid #fff; +} + .numberSelector .choice.selected { color: var(--choice-active-text, var(--text)); background-color: var(--choice-active); diff --git a/src/components/NumberSelector.js b/src/components/NumberSelector.js index 1bcf3d20..eb41530c 100644 --- a/src/components/NumberSelector.js +++ b/src/components/NumberSelector.js @@ -7,10 +7,15 @@ import { PercentageOverlay } from './PercentageOverlay'; // choices: { label: string, value: string }[] // selected: string export function NumberSelector({ setType, choices, selected }) { + const handleKeyPress = choice => event => { + if (event.code === 'Space' || event.code === 'Enter'){ + setType(choice); + } + } return (
{choices.map(v=>( -
+
setType(v.value)}> {v.label} diff --git a/src/components/SelectBox.css b/src/components/SelectBox.css index d33f2413..1ca3e8b3 100644 --- a/src/components/SelectBox.css +++ b/src/components/SelectBox.css @@ -8,6 +8,10 @@ position: relative; } +.select-box:focus-visible .selected { + border: 1px solid #fff; +} + .select-box > * { box-sizing: border-box; } diff --git a/src/components/SelectBox.js b/src/components/SelectBox.js index 2bf13348..a094f910 100644 --- a/src/components/SelectBox.js +++ b/src/components/SelectBox.js @@ -1,9 +1,9 @@ import { useRef, useState, useEffect } from "react" import "./SelectBox.css" -function Option({ option, onClick }) { +function Option({ option, ...props }) { return ( -
+
{ + if (event.code === 'Enter' || event.code === 'Space'){ + setActive(a => !a); + } + } + + const handleOptionKeyPress = (option, i) => event => { + if (event.code === 'Enter' || event.code === 'Space'){ + onOptionClick(event, option, i); + } + } + return ( -
setActive(a => !a)}> -
- {options.map((opt, i) => ( -
-
+
setActive(a => !a)} > +
{options ? (
+
+ {options.map((opt, i) => ( +
) } diff --git a/src/components/Title.css b/src/components/Title.css index 5e749821..d789f69f 100644 --- a/src/components/Title.css +++ b/src/components/Title.css @@ -29,6 +29,15 @@ cursor: pointer; } +.title.accent.title-accent-link:focus-visible { + border: 1px solid #ffffff; +} + +.title.accent.title-accent-link:focus-visible .arrow { + transform: translateY(.1rem) translateX(-.5rem); +} + + .title-accent.title-accent-link .arrow { transition: transform 100ms ease-in-out; transform: translateY(.1rem); @@ -39,3 +48,5 @@ transform: translateY(.1rem) translateX(-.5rem); } + + diff --git a/src/components/Title.js b/src/components/Title.js index b03f1aa8..19ecf844 100644 --- a/src/components/Title.js +++ b/src/components/Title.js @@ -14,16 +14,24 @@ export function Title(props) { const accentLink = props.accentLink || ""; const accent = props.accent || ""; + + function handleAccentClick(){ + if (accentLink.length > 0) { + history.push(`/${streamData.type}`); + resetStreamData(); + } + } + + function handleKeyPress(event){ + if (event.code === 'Enter' || event.code === 'Space'){ + handleAccentClick(); + } + } return (
{accent.length > 0 ? ( -

{ - if (accentLink.length > 0) { - history.push(`/${streamData.type}`); - resetStreamData(); - } - }} className={`title-accent ${accentLink.length > 0 ? 'title-accent-link' : ''}`}> +

0 ? 'title-accent-link' : ''}`} tabIndex={accentLink.length > 0 ? 0 : undefined} onKeyPress={handleKeyPress}> {accentLink.length > 0 ? () : null}{accent}

) : null} diff --git a/src/components/TypeSelector.css b/src/components/TypeSelector.css index 2a3d0743..82ada085 100644 --- a/src/components/TypeSelector.css +++ b/src/components/TypeSelector.css @@ -39,6 +39,11 @@ color: var(--text-secondary); } +.typeSelector .choice:focus-visible { + border: 1px solid #fff; + color: var(--text-secondary); +} + .typeSelector .choice.selected { color: var(--text); } diff --git a/src/components/TypeSelector.js b/src/components/TypeSelector.js index 2af819f4..3102c4d8 100644 --- a/src/components/TypeSelector.js +++ b/src/components/TypeSelector.js @@ -1,23 +1,36 @@ import React from 'react'; -import './TypeSelector.css' +import './TypeSelector.css'; // setType: (txt: string) => void // choices: { label: string, value: string }[] // selected: string export function TypeSelector({ setType, choices, selected, noWrap = false }) { - const selectedIndex = choices.findIndex(v=>v.value===selected); - const transformStyles = { - opacity: selectedIndex!==-1?1:0, - transform: `translateX(${selectedIndex!==-1?selectedIndex*7:0}rem)` + const selectedIndex = choices.findIndex(v => v.value === selected); + const transformStyles = { + opacity: selectedIndex !== -1 ? 1 : 0, + transform: `translateX(${selectedIndex !== -1 ? selectedIndex * 7 : 0}rem)`, + }; + + const handleKeyPress = choice => event => { + if (event.code === 'Enter' || event.code === 'Space') { + setType(choice); } - return ( -
- {choices.map(v=>( -
setType(v.value)}> - {v.label} -
- ))} -
+ }; + + return ( +
+ {choices.map(v => ( +
setType(v.value)} + onKeyPress={handleKeyPress(v.value)} + tabIndex={0} + > + {v.label}
- ) + ))} +
+
+ ); } diff --git a/src/views/Search.css b/src/views/Search.css index ca4f80e9..d3ce7d38 100644 --- a/src/views/Search.css +++ b/src/views/Search.css @@ -18,6 +18,11 @@ border-radius: 4px; color: var(--text); } + +.cardView nav span:focus-visible { + border: 1px solid #fff; +} + .cardView nav span:not(.selected-link) { cursor: pointer; } diff --git a/src/views/Search.js b/src/views/Search.js index f79dc294..775de439 100644 --- a/src/views/Search.js +++ b/src/views/Search.js @@ -207,6 +207,12 @@ export function SearchView() { return } + const handleKeyPress = page => event => { + if (event.code === 'Enter' || event.code === 'Space'){ + setPage(page); + } + } + return (
@@ -215,9 +221,9 @@ export function SearchView() { {/* Nav */}