All files / src/custom-element/mixins/components/selectable SelectableMixin.ts

29.63% Statements 8/27
0% Branches 0/6
33.33% Functions 3/9
29.63% Lines 8/27

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 1302x   2x 2x   2x         2x   1x             1x         3x                                                                                                                                                                                                                  
import mergeStyles from "../../../helpers/mergeStyles";
import { CustomElementPropertyMetadata } from "../../../interfaces";
import HoverableMixin from "../hoverable/HoverableMixin";
import styles from "./SelectableMixin.css";
 
export const selectionChanged = 'selectionChanged';
 
/**
 * Allows a component to be selected when clicked
 */
export default function SelectableMixin(Base): any {
 
    return class Selectable extends
        HoverableMixin( // Selectable items are also hoverable by default
            Base
        ) {
 
        static get styles(): string {
 
            return mergeStyles(super.styles, styles);
        }
 
        static get properties(): Record<string, CustomElementPropertyMetadata> {
 
            return {
 
                /**
                 * Whether the component is selectable
                 */
                selectable: {
                    type: Boolean,
                    value: true,
                    reflect: true,
                    inherit: true
                },
 
                /**
                 * Whether the item is selected
                 */
                selected: {
                    type: Boolean,
                    mutable: true, // It also acts as state
                    reflect: true
                },
 
                /**
                 * The value to return when the component gets selected
                 */
                selectValue: {
                    attribute: 'select-value',
                    type: [String, Object]
                }
            };
        }
 
        constructor() {
 
            super();
 
            this.toggleSelect = this.toggleSelect.bind(this);
        }
 
        connectedCallback() {
 
            super.connectedCallback?.();
 
            this.addEventListener('click', this.toggleSelect);
        }
 
        disconnectedCallback() {
 
            super.disconnectedCallback?.();
 
            this.removeEventListener('click', this.toggleSelect);
        }
 
        toggleSelect() {
 
            let {
                selected
            } = this;
 
            selected = !selected; // Toggle
 
            this._setSelection(selected);
        }
 
        /**
         * Select this component programmatically
         */
        select() {
 
            let {
                selected
            } = this;
 
            if (selected === true) {
 
                return;
            }
 
            this._setSelection(true);
        }
 
        private _setSelection(selected: boolean) {
 
            if (!this.selectable) {
 
                return;
            }
 
            if (this.selected === selected) {
 
                return; // Nothing to select
            }
 
            this.selected = selected;
 
            this.dispatchEvent(new CustomEvent(selectionChanged, {
                detail: {
                    element: this,
                    selected,
                    value: this.selectValue
                },
                bubbles: true,
                composed: true
            }));
        }
    }
}