Skip to content

Instantly share code, notes, and snippets.

@johnatandias
Last active July 5, 2019 00:47
Show Gist options
  • Save johnatandias/8692f78c0f8911df8019e7236ee2330d to your computer and use it in GitHub Desktop.
Save johnatandias/8692f78c0f8911df8019e7236ee2330d to your computer and use it in GitHub Desktop.
KaiOS navigation with React Hooks
import React from 'react';
import css from './Input.module.css'
export const Input = ({ label, type }) => {
return (
<div className={css.content}>
<input className={css.input} type={type} nav-selectable="true" />
<label className={css.label}>{label}</label>
</div>
)
}
.content {
display: flex;
flex-direction: column;
margin: 5px 10px;
position: relative;
padding-top: 5px;
}
.input {
font-family: inherit;
width: 100%;
border: 0;
border-bottom: 1px solid #d2d2d2;
outline: 0;
font-size: 16px;
color: #212121;
padding: 7px 0;
background: transparent;
transition: border-color 0.2s;
}
.label {
position: absolute;
bottom: 0;
color: #9b9b9b;
}
.input::placeholder {
color: transparent;
}
.input:placeholder-shown~.label {
font-size: 16px;
cursor: text;
top: 20px;
}
.input[nav-selected="true"]~.label {
position: absolute;
top: 0;
display: block;
transition: 0.2s;
font-size: 12px;
color: #9b9b9b;
}
.input[nav-selected="true"]~.label {
color: #7367F0;
}
.input[nav-selected="true"] {
padding-bottom: 6px;
border-bottom: 2px solid #7367F0;
}
import { useState, useEffect } from 'react';
export const useNavigation = () => {
useEffect(() => {
document.addEventListener('keydown', onKeyDown);
setNavigation(0);
return () => document.removeEventListener('keydown', onKeyDown);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const [current, setCurrent] = useState({ type: null, index: null });
const getAllElements = () => document.querySelectorAll('[nav-selectable]');
const getTheIndexOfTheSelectedElement = () => {
const element = document.querySelector('[nav-selected=true]');
return element ? parseInt(element.getAttribute('nav-index')) : 0;
}
const setNavigation = index => selectElement(getAllElements()[index] || document.body);
const onKeyDown = evt => {
if (evt.key !== 'ArrowDown' && evt.key !== 'ArrowUp') return;
const allElements = getAllElements();
const currentIndex = getTheIndexOfTheSelectedElement();
let setIndex;
switch (evt.key) {
case 'ArrowDown':
const goToFirstElement = currentIndex + 1 > allElements.length - 1;
setIndex = goToFirstElement ? 0 : currentIndex + 1;
return selectElement(allElements[setIndex] || allElements[0], setIndex);
case 'ArrowUp':
const goToLastElement = currentIndex === 0;
setIndex = goToLastElement ? allElements.length - 1 : currentIndex - 1;
return selectElement(allElements[setIndex] || allElements[0], setIndex);
default:
break;
}
}
const selectElement = (selectElement, setIndex = 0) => {
if (selectElement) {
[].forEach.call(getAllElements(), (element, index) => {
element.setAttribute('nav-selected', element === selectElement)
element.setAttribute('nav-index', index)
});
setCurrent({ type: selectElement.tagName, index: setIndex });
} else {
setNavigation(0);
}
}
return [current, setNavigation];
};
@jackesdavid
Copy link

Beautiful

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment