You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

115 lines
4.2 KiB
JavaScript

// Shared Data/Table Actions
// Data Table (only) ---
/** Svelte Action for applying sort asc/dsc classes. */
export function tableInteraction(node) {
const classAsc = 'table-sort-asc';
const classDsc = 'table-sort-dsc';
// Click Handler
const onClick = (e) => {
if (!(e.target instanceof Element))
return;
const sortTarget = e.target;
// Get target state before modification
const targetAscSorted = sortTarget.classList.contains(classAsc);
const sortTargetKey = sortTarget.getAttribute('data-sort');
// Clear asc class
const elemAsc = node.querySelector(`.${classAsc}`);
if (elemAsc)
elemAsc.classList.remove(classAsc);
// Clear dsc class
const elemDsc = node.querySelector(`.${classDsc}`);
if (elemDsc)
elemDsc.classList.remove(classDsc);
// Set new sort class
if (sortTargetKey) {
const classToApply = targetAscSorted ? classDsc : classAsc;
e.target.classList.add(classToApply);
}
};
// Events
node.addEventListener('click', onClick);
// Lifecycle
return {
destroy() {
node.removeEventListener('click', onClick);
}
};
}
// Shared ---
/** Svelte Action for handling table a11y keyboard interactions. */
export function tableA11y(node) {
const keyWhitelist = ['ArrowRight', 'ArrowUp', 'ArrowLeft', 'ArrowDown', 'Home', 'End'];
// on:keydown
const onKeyDown = (event) => {
// console.log('keydown triggered');
if (keyWhitelist.includes(event.code)) {
event.preventDefault();
// prettier-ignore
switch (event.code) {
case 'ArrowUp':
a11ySetActiveCell(node, 0, -1);
break;
case 'ArrowDown':
a11ySetActiveCell(node, 0, 1);
break;
case 'ArrowLeft':
a11ySetActiveCell(node, -1, 0);
break;
case 'ArrowRight':
a11ySetActiveCell(node, 1, 0);
break;
case 'Home':
a11yJumpToOuterColumn(node, 'first');
break;
case 'End':
a11yJumpToOuterColumn(node, 'last');
break;
default: break;
}
}
};
// Event Listener
node.addEventListener('keydown', onKeyDown);
// Lifecycle
return {
destroy() {
node.removeEventListener('keydown', onKeyDown);
}
};
}
function a11ySetActiveCell(node, x, y) {
// Focused Element
const focusedElem = document.activeElement;
if (!focusedElem || !focusedElem.parentElement || !focusedElem.parentElement.ariaRowIndex || !focusedElem.ariaColIndex)
return;
const focusedElemRowIndex = parseInt(focusedElem.parentElement.ariaRowIndex);
const focusedElemColIndex = parseInt(focusedElem.ariaColIndex);
// Target Element
const targetRowElement = node.querySelector(`[aria-rowindex="${focusedElemRowIndex + y}"]`);
if (targetRowElement !== null) {
const targetColElement = targetRowElement.querySelector(`[aria-colindex="${focusedElemColIndex + x}"]`);
if (targetColElement !== null)
targetColElement.focus();
}
}
function a11yGetTargetElem(node) {
// Focused Element
const focusedElem = document.activeElement;
if (!focusedElem || !focusedElem.parentElement || !focusedElem.parentElement.ariaRowIndex)
return null;
const focusedElemRowIndex = parseInt(focusedElem.parentElement.ariaRowIndex);
// Return Target Element
return node.querySelector(`[aria-rowindex="${focusedElemRowIndex}"]`);
}
function a11yJumpToOuterColumn(node, type = 'first') {
const targetRowElement = a11yGetTargetElem(node);
if (targetRowElement === null)
return;
const lastIndex = targetRowElement.children.length;
const selected = type === 'first' ? 1 : lastIndex;
const targetColElement = targetRowElement.querySelector(`[aria-colindex="${selected}"]`);
if (targetColElement === null)
return;
targetColElement.focus();
}