JSFiddle - React, Tailwind, and code Playground

by Znarkus

HTML

<ul>
    <li><div></div><div></div><div></div></li>
    <li><div></div></li>
    <li><div></div><div></div><div></div><div></div><div></div></li>
    <li><div></div><div></div><div></div></li>
    <li><div></div><div></div><div></div><div></div><div></div><div></div><div></div></li>
    <li><div></div></li>
</ul>

CSS

div {
    background: #fed;
    width: 50px;
    height: 50px;
    float: left;
    margin: 0 10px 10px 0;
}

li {
    overflow: hidden;
    padding: 10px 10px 0;
    border: 1px dotted #000;
    margin: 10px;
    min-height: 60px;
}

li.empty {
    background: #eee;
}

.ui-sortable-placeholder {
    visibility: visible !important;
    background: none;
    outline: 1px dotted #ccc;
}

JavaScript

var $items = $('ul li'), mouse_move_timer;

function real_children($li) {
    return $li.children(':not(.ui-sortable-placeholder,.ui-sortable-helper)');
}

function mouse_move(e) {
    var $li;
    
    $items.each(function () {
        $li = $(this);
        
        if (Math.abs($li.offset().top + $li.outerHeight() - e.pageY) < 20) {
            if ($li.next('.empty').length == 0
            && real_children($li).length > 0
            && ($li.next().length == 0 || real_children($li.next()).length > 0)) {
                $li.siblings('.empty').remove();
                $li.after('<li class="empty"></li>');
                attach_sortable($li.next('.empty'));
                $items.sortable('refresh');
            }
        }
    });
    
    $li = $items.first();
    
    if (Math.abs($li.offset().top - e.pageY) < 20) {
        if (real_children($li).length > 0) {
            $li.siblings('.empty').remove();
            $li.before('<li class="empty"></li>');
            attach_sortable($li.prev('.empty'));
            $items.sortable('refresh');
        }
    }
}

function attach_sortable($e) {
    $e.sortable({
        connectWith: 'ul li',
        sort: function (e, ui) {
            clearTimeout(mouse_move_timer);
            mouse_move_timer = setTimeout(function () {
                mouse_move(e);
            }, 150);
        },
        stop: function (e, ui) {
            ui.item.parent().siblings('.empty').add(ui.item.parent('.empty')).each(function () {
                var $empty = $(this);
                
                if ($empty.children().length == 0) {
                    $empty.remove();
                } else {
                    $items = $items.add($empty.removeClass('empty'));
                }
            });
            
            $items.filter(':empty').remove();
        }
    });
}



attach_sortable($items);