Sortable

<div class="js-sortable" data-name="">
    <ol class="Sortable">
    </ol>
</div>
<div class="js-sortable" data-name="{{name}}">
    <ol class="Sortable">
        {{#each items}}
            <li class="Sortable-item" data-value="{{value}}">{{text}}</li>
        {{/each}}
    </ol>
</div>
/* No context defined for this component. */
  • Content:
    import PropTypes from 'prop-types';
    import React, { Component } from 'react';
    import update from 'react/lib/update';
    import cx from 'classnames';
    import { DragDropContext } from 'react-dnd';
    import TouchBackend from 'react-dnd-touch-backend';
    import SortableItem from './Sortable-item/SortableItem';
    
    class Container extends Component {
        static propTypes = {
            style: PropTypes.object,
            modifier: PropTypes.string,
            items: PropTypes.array,
            name: PropTypes.string
        };
    
        constructor(props) {
            super(props);
            this.state = {
                selected: null,
                items: this.props.items
            };
        }
    
        serializeItems = ()=> {
            return this.state.items
                .map((item)=> item.value)
                .join(',');
        };
    
        moveItem = (dragIndex, hoverIndex)=> {
            const { items } = this.state;
            const dragItem = items[dragIndex];
    
            this.setState(update(this.state, {
                items: {
                    $splice: [
                        [dragIndex, 1],
                        [hoverIndex, 0, dragItem]
                    ]
                }
            }));
        };
    
        selectItem = (index)=> {
            return (event)=> {
                event.preventDefault();
                this.setState({
                    selected: index
                });
            };
        };
    
        shiftItem = (amount)=> {
            return (event)=> {
                event.preventDefault();
                const { items, selected } = this.state;
                const dragItem = items[selected];
                const newIndex = selected + amount;
    
                if (newIndex < 0) return;
                if (newIndex > items.length - 1) return;
    
                this.setState(update(this.state, {
                    items: {
                        $splice: [
                            [selected, 1],
                            [newIndex, 0, dragItem]
                        ]
                    }
                }));
    
                this.selectItem(newIndex)(event);
            };
        };
    
        shiftItemUp = this.shiftItem(-1);
        shiftItemDown = this.shiftItem(1);
    
        onKeyDown = (index)=> {
            return (event)=> {
                const { selected } = this.state;
    
                if (event.keyCode == 32) {
                    // Spacebar
                    this.selectItem(index)(event);
                } else if (selected != null && event.keyCode == 38) {
                    // Up arrow
                    this.shiftItemUp(event);
                } else if (selected != null && event.keyCode == 40) {
                    // Down arrow
                    this.shiftItemDown(event);
                }
            };
        };
    
        render() {
            const { items } = this.state;
            return (
                <ol
                    style={this.props.style}
                    className={cx('Sortable', this.props.modifier)}
                >
                    {items.map((item, i) => (
                        <SortableItem
                            key={item.id}
                            index={i}
                            id={item.id}
                            text={item.text}
                            moveItem={this.moveItem}
                            selectItem={this.selectItem(i)}
                            onKeyDown={this.onKeyDown(i)}
                            isSelected={this.state.selected === i}
                        />
                    ))}
                    <input
                        type="hidden"
                        name={this.props.name}
                        defaultValue={this.serializeItems()}
                    />
                </ol>
            );
        }
    }
    
    export default DragDropContext(TouchBackend({
        enableMouseEvents: true
    }))(Container);
    
  • URL: /components/raw/sortable/Sortable.jsx
  • Filesystem Path: components/molecules/Sortable/Sortable.jsx
  • Size: 3.6 KB
  • Content:
    $transition: transform $transition-time-default $transition-move-default;
    .Sortable {
        @include unstyled-list;
    }
    .Sortable-item {
        @include Elevation("Card");
        position: relative;
        display: flex;
        padding: .5rem 1rem;
        align-items: center;
        text-align: left;
        background-color: get-color(neutral, 0);
        border: 1px solid get-color(neutral, 100);
        border-radius: $Border-radius--500;
        outline: 0;
        cursor: grab;
        transition: $transition;
        &:hover {
            @include Elevate("Card-hover");
            @include ZIndex("Card-hover");
        }
        &:active,
        &:focus {
            @include Elevate("Card-pressed");
            @include ZIndex("Card-pressed");
        }
    }
    .Sortable-item + .Sortable-item {
        margin-top: .5rem;
    }
    .Sortable-item .DragHandle {
        margin-right: 1rem;
    }
    
  • URL: /components/raw/sortable/Sortable.scss
  • Filesystem Path: components/molecules/Sortable/Sortable.scss
  • Size: 807 Bytes

There are no notes for this item.