@exmg/exmg-radio-group
Version:
Paper style radio group element
122 lines • 3.83 kB
JavaScript
import { ExmgRadioGroupItem } from './exmg-radio-group-item.js';
/**
* Unique symbol for marking roots
*/
const selectionController = Symbol('selection controller');
class SelectionSet {
constructor() {
this.selected = null;
this.focused = null;
this.ordered = null;
this.set = new Set();
}
}
export class SelectionController {
static getController(element) {
const root = element;
if (!root[selectionController]) {
root[selectionController] = new SelectionController(root);
}
return root[selectionController];
}
constructor(element) {
this.sets = {};
this.mouseIsDown = false;
this.updating = false;
// console.log('SelectionController constructor', element);
element.addEventListener('keydown', (e) => this.keyDownHandler(e));
element.addEventListener('mousedown', () => this.mousedownHandler());
element.addEventListener('mouseup', () => this.mouseupHandler());
}
keyDownHandler(e) {
if (!(e.target instanceof ExmgRadioGroupItem)) {
return;
}
const element = e.target;
if (!this.has(element)) {
return;
}
if (e.key === 'ArrowRight' || e.key === 'ArrowDown') {
this.next(element);
}
else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') {
this.previous(element);
}
}
mousedownHandler() {
this.mouseIsDown = true;
}
mouseupHandler() {
this.mouseIsDown = false;
}
has(element) {
const set = this.getSet(element.name);
return set.set.has(element);
}
previous(element) {
const order = this.getOrdered(element);
const i = order.indexOf(element);
this.focus(order[i - 1] || order[order.length - 1]);
}
next(element) {
const order = this.getOrdered(element);
const i = order.indexOf(element);
this.focus(order[i + 1] || order[0]);
}
select(element) {
element.click();
}
/**
* Helps to track the focused selection group and if it changes, focuses
* the selected item in the group. This matches native radio button behavior.
*/
focus(element) {
// Only manage focus state when using keyboard
if (this.mouseIsDown) {
return;
}
element.focusNative();
}
getOrdered(element) {
const set = this.getSet(element.name);
if (!set.ordered) {
set.ordered = Array.from(set.set);
set.ordered.sort((a, b) => (a.compareDocumentPosition(b) === Node.DOCUMENT_POSITION_PRECEDING ? 1 : 0));
}
return set.ordered.filter((item) => !item.disabled);
}
getSet(name) {
if (!this.sets[name]) {
this.sets[name] = new SelectionSet();
}
return this.sets[name];
}
register(element) {
const set = this.getSet(element.name);
set.set.add(element);
set.ordered = null;
}
unregister(element) {
const set = this.getSet(element.name);
set.set.delete(element);
set.ordered = null;
if (set.selected === element) {
set.selected = null;
}
}
update(element) {
if (this.updating) {
return;
}
this.updating = true;
if (element.checked) {
const set = this.getSet(element.name);
for (const e of set.set) {
e.checked = e === element;
}
set.selected = element;
}
this.updating = false;
}
}
//# sourceMappingURL=exmg-selection-controller.js.map