# All files / behaviors/Selectable Selectable.js

0% Statements 0/73
0% Branches 0/16
0% Functions 0/10
0% Lines 0/15

    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

     import React from 'react';
    import PropTypes from 'prop-types';
    import styled from 'styled-components';
    import { noop } from 'lodash';

    class Selectable extends React.Component {
      static propTypes = {
        /**
         * Render prop to render the selectable items. Supports the following props:
         *
         * *selectItem*: A function that should be invoked with a unique key as its argument whenever an item should be selected.
         *
         * *deselectItem*: A function that should be invoked with a unique key as its argument whenever an item should be deselected.
         *
         * *toggleItem*: A function that should be invoked with a unique key as its argument whenever an item should be toggled.
         *
         * *selected*: A **Set** of selected items represented by their key values.
         */
        render: PropTypes.func,
        /**
         * Callback for when an item is selected. Passed one argument, which is the key of the item that was selected.
         */
        onItemSelected: PropTypes.func,
        /**
         * Callback for when an item is deselected. Passed one argument, which is the key of the item that was deselected.
         */
        onItemDeselected: PropTypes.func,
        /**
         * Limits selection to only one item at a time.
         */
        exclusive: PropTypes.bool,
        /**
         * Control the inital selection.
         */
        initial: PropTypes.object,
      };

      constructor(props) {
        super(props);
        const selected = new Set();
        if (props.initial) selected.add(props.initial);
        this.state = { selected };
      }

      static defaultProps = {
        render: noop,
        onItemSelected: noop,
        onItemDeselected: noop,
      };

      selectItem = key => {
        const {
          props: { onItemSelected, exclusive },
          state: { selected },
          deselectItem,
        } = this;
        if (selected.has(key)) {
          return;
        }
        if (exclusive) {
          Array.from(selected).map(deselectItem);
        }
        onItemSelected(key);
        this.setState(state => ({
          selected: state.selected.add(key),
        }));
      };

      deselectItem = key => {
        const { props: { onItemDeselected }, state: { selected } } = this;
        if (!selected.has(key)) {
          return;
        }
        onItemDeselected(key);
        this.setState(state => {
          state.selected.delete(key);
          return { selected: state.selected };
        });
      };

      toggleItem = key => {
        const { state: { selected }, selectItem, deselectItem } = this;
        selected.has(key) ? deselectItem(key) : selectItem(key);
      };

      render() {
        const {
          props: { render },
          state: { selected },
          selectItem,
          deselectItem,
          toggleItem,
        } = this;
        return render({
          selectItem,
          deselectItem,
          toggleItem,
          selected,
        });
      }
    }

    export default Selectable;