thebespokepixel/n-selector

View on GitHub
src/index.js

Summary

Maintainability
A
0 mins
Test Coverage
/* ───────────╮
 │ n-selector │ Multi-gang (1 x n, 2 x n ... n x n) selection latch and emitter
 ╰────────────┴──────────────────────────────────────────────────────────────── */

import _ from 'lodash'
import sparkles from 'sparkles'
import uuid from './lib/uuid'
import {addGang} from './lib/classes/gang'

/**
 * Create an NSelector instance
 * @return {NSelector}        NSelector ganged selector.
 */
export class NSelector {
    /**
     * @param  {Array[]} matrix    An array or array of arrays of selectable items.
     * @param  {number} selection Current selection.
     * @param  {string} ns        Sparkles namespace.
     */
    constructor(matrix, selection, ns = uuid()) {
        this.ns = ns
        this.emtr = sparkles(this.ns)

        if (Array.isArray(matrix[0])) {
            this.matrix = _.map(matrix, (gang, idx) => addGang(gang, idx === 0))
        } else {
            this.matrix = [addGang(matrix, true)]
        }

        this.primary = _.head(_.filter(this.matrix, member => member.isPrimary))
        this.select(selection)
    }

    /**
     * Find the largest (maximal) index in the selector.
     * @return {number} Largest index value.
     */
    findLargestIndex() {
        return _.maxBy(this.matrix, member => member.memberCount)
    }

    /**
     * Find the primary index.
     * @param  {string} idx The index to find.
     * @return {number}     The position of the index.
     */
    findSelectionIndex(idx) {
        return this.primary.indexOf(idx)
    }

    /**
     * Find the position of the ID string.
     * @param  {number|string} id The ID to find.
     * @return {string}    [description]
     */
    findSelectionIndexByID(id) {
        return this.findSelectionIndex(_.isInteger(id) ?
            id : this.primary.indexOfMember(id))
    }

    /**
     * Get currently selected item.
     * @return {any} Selected value.
     */
    get selected() {
        const result = _.map(this.matrix, member => member.selection(this.selectedPosition))
        return result.length === 1 ? _.head(result) : result
    }

    /**
     * Get Sparkles namespace
     * @return {string} Namespace.
     */
    get namespace() {
        return this.ns
    }

    /**
     * Get Sparkles emitter
     * @return {EventEmitter} Event emitter.
     */
    get emitter() {
        return this.emtr
    }

    /**
     * Select an index in the selector.
     * @param  {number} id Index.
     * @return {any} Returned value.
     */
    select(id) {
        this.selectedIndex = this.findSelectionIndexByID(id)
        this.selectedPosition = this.primary.position(this.selectedIndex)
        this.emtr.emit('select', this.selected)
        return this.selected
    }
}

/**
 * Create a new n-selector.
 * @param  {Array[]} matrix    Array or array of arrays of selectable options.
 * @param  {number} selection Current selection.
 * @param  {string} ns        Sparkles emitter namespace.
 * @return {NSelector} NSelector ganged selector.
 */
export function createSelector(matrix, selection = 0, ns = uuid()) {
    if (matrix === undefined || !Array.isArray(matrix)) {
        throw new Error('Selector requires an array (or an array of arrays) as the first parameter.')
    }

    return new NSelector(matrix, selection, ns)
}