@ou-imdt/utils
Version:
Utility library for interactive media development
109 lines (93 loc) • 3.46 kB
JavaScript
import { defaultState } from '../Base.js';
// defines a prop to reference a list like elements items
export const items = Symbol('items');
// defines a prop to track the index of a list like elements active item
export const activeItemIndex = Symbol('activeItemIndex');
// defines a prop to track the availability of a list like elements items
export const availableItemFlags = Symbol('availableItemFlags');
// defines a prop to track the selected state of a list like elements items
export const selectedItemFlags = Symbol('selectedItemFlags');
// defines a method to move the active item index to the first available item of a list like element
export const moveToFirst = Symbol('moveToFirst');
// defines a method to move the active item index to the last available item of a list like element
export const moveToLast = Symbol('moveToLast');
// defines a method to move the active item index to the next available item of a list like element
export const moveToNext = Symbol('moveToNext');
// defines a method to move the active item index to the previous available item of a list like element
export const moveToPrevious = Symbol('moveToPrevious');
// defines a flag to continually loop through items of a list like element
export const itemFocusLoop = Symbol('itemFocusLoop');
// defines a prop to hold a reference to the initial items, i.e. during connectedCallback
export const initialItems = Symbol('initialItems');
export default (superClass) => class ListMixin extends superClass {
static get [defaultState]() {
return {
...super[defaultState],
[activeItemIndex]: null,
[availableItemFlags]: [],
[selectedItemFlags]: [],
[itemFocusLoop]: false
};
}
constructor() {
super();
}
get [items]() {
return [];
}
/**
* @param {array} list
*/
set [items](list) {
this.append(...list); // remove DOM ref?
}
[moveToFirst]() {
return this.moveToIndex(0, 1);
}
[moveToLast]() {
return this.moveToIndex(this[items].length - 1, -1);
}
[moveToNext]() {
const index = this[items].length ? (this[activeItemIndex] ?? -1) + 1 : 0;
return this.moveToIndex(index, 1);
}
[moveToPrevious]() {
const index = this[items].length ? (this[activeItemIndex] ?? -1) - 1 : this[items].length - 1;
return this.moveToIndex(index, 1);
}
connectedCallback() {
super.connectedCallback();
requestAnimationFrame(() => {
this[initialItems] = Object.freeze(this[items]);
});
}
/**
* moves the pointer to index provided an item exists at that location
* @param {*} index
* @param {*} forward
* @returns
*/
moveToIndex(index) {
// moveToIndex(index, forward = true) {
// const index = this[closestAvailableItemIndex]({ from: value, forward });
if (this[items].length === 0) return;
if (typeof this[items][index] === 'undefined') {
if (!this[itemFocusLoop]) return false;
if (index < 0) return this[moveToLast]();
return this[moveToFirst]();
}
// console.log(`move to index ${index} from ${this[activeItemIndex]}`);
this[activeItemIndex] = index;
return true;
}
// sortAscending() {
// this[items] = this[items].sort(({ textContent: a }, { textContent: b }) => {
// if (a < b) return -1;
// if (a > b) return 1;
// return 0;
// });
// }
// sortDescending() {
// this[items] = this.sortAscending().reverse();
// }
}