haltu / muuri

Infinite responsive, sortable, filterable and draggable layouts
https://muuri.dev
MIT License
10.77k stars 644 forks source link

Kanban Item Horizontal Scrolling? #477

Open ibrychgo opened 3 years ago

ibrychgo commented 3 years ago

First, this is an AMAZING library. So much better than other drag-and-drop libraries than I've used in the past. Thank you to the entire community for creating and supporting Muuri!

I'm working on a kanban-like board and having a bit of trouble moving items to columns that are off screen.

The Requirements are:

  1. Board can have any number of columns
  2. Each column can have any number of items
  3. User should be able to manually scroll left/right to review all columns & items.
  4. Columns can be dragged and re-ordered
  5. When dragging a column, auto-scroll-x to place columns anywhere in the series, even if target sibling is currently offscreen.
  6. Items can be dragged vertically within columns, and horizontally and between columns
  7. When dragging an item to the left or right edge, auto-scroll-x so they can be placed in columns that are currently off screen

I've based this on the Kanban examples mentioned here: https://codepen.io/niklasramo/pen/KKKYKWG

EVERYTHING is working EXCEPT for Number 7: When dragging items around, the board does not scroll left and right when the item is dragged to the edges.

This auto-scrolling works fine when dragging columns to the edges, but not for Items.

I can't figure out what I'm missing here. I kinda assumed this behavior would be baked into the library. I have a suspicion it has to do with dragSort or dragAutoScroll but I'm not sure what to provide those options other than the columnGrids and the window.

Any help or pointers would be appreciated! Thanks!

My HTML:

<div class="board-container small-scrollbar">
      <div class="drag-container"></div>
      <div class="board">
        <div class="board-column todo">
          <div class="board-column-header">To do</div>
          <div class="board-column-content-wrapper">
            <div class="board-column-content">
              <div class="board-item"><div class="board-item-content"><span>Item #</span>1</div></div>
              <div class="board-item"><div class="board-item-content"><span>Item #</span>2</div></div>
              <div class="board-item"><div class="board-item-content"><span>Item #</span>3</div></div>
              <div class="board-item"><div class="board-item-content"><span>Item #</span>4</div></div>
              <div class="board-item"><div class="board-item-content"><span>Item #</span>5</div></div>
            </div>
           </div>
        </div>
        <div class="board-column todo">
          <div class="board-column-header">To do</div>
          <div class="board-column-content-wrapper">
            <div class="board-column-content">
              <div class="board-item"><div class="board-item-content"><span>Item #</span>1</div></div>
              <div class="board-item"><div class="board-item-content"><span>Item #</span>2</div></div>
              <div class="board-item"><div class="board-item-content"><span>Item #</span>3</div></div>
              <div class="board-item"><div class="board-item-content"><span>Item #</span>4</div></div>
              <div class="board-item"><div class="board-item-content"><span>Item #</span>5</div></div>
            </div>
           </div>
        </div>
        <div class="board-column working">
          <div class="board-column-header">Working</div>
          <div class="board-column-content-wrapper">
            <div class="board-column-content">
              <div class="board-item"><div class="board-item-content"><span>Item #</span>6</div></div>
              <div class="board-item"><div class="board-item-content"><span>Item #</span>7</div></div>
              <div class="board-item"><div class="board-item-content"><span>Item #</span>8</div></div>
              <div class="board-item"><div class="board-item-content"><span>Item #</span>9</div></div>
              <div class="board-item"><div class="board-item-content"><span>Item #</span>10</div></div>
            </div>
          </div>
        </div>
    </div>
  </div>

My Javascript:

var dragContainer = document.querySelector('.drag-container'), 
boardContainer = document.querySelector('.board-container');

// set our dimensions
var contentHeight = $('.board-container').height(),
boardHeight = contentHeight - 50;
$('.board').height(boardHeight)
$('.board-column-content-wrapper').height(boardHeight - 50);

var itemContainers = [].slice.call(document.querySelectorAll('.board-column-content'));
var columnGrids = [];
var boardGrid;

// Define the column grids so we can drag those items around.
itemContainers.forEach(function (container) {

  // Instantiate column grid.
  var grid = new Muuri(container, {
    items: '.board-item',
    layoutDuration: 400,
    layoutEasing: 'ease',
    dragEnabled: true,
    dragSort: function () {
      return columnGrids;
    },
    dragSortInterval: 0,
    dragContainer: dragContainer,
    dragReleaseDuration: 400,
    dragReleaseEasing: 'ease',
    dragAutoScroll: {
       targets:  (item) => {
          return [
            { element: window, priority: 0 },
            { element: item.getGrid().getElement().parentNode, priority: 1 },
          ];
        }
      }
  });

  // Add the column grid reference to the column grids
  // array, so we can access it later on.
  columnGrids.push(grid);

});

// Instantiate the board grid so we can drag those
// columns around.
boardGrid = new Muuri('.board', {
  layout: {
    horizontal: true,
  },
  layoutDuration: 400,
  layoutEasing: 'ease',
  dragEnabled: true,
  dragAxis: 'x',
  dragSortInterval: 0,
     dragHandle: '.board-column-header',
  dragStartPredicate: {
    handle: '.board-column-header'
  },
  dragReleaseDuration: 400,
  dragReleaseEasing: 'ease',
  dragAutoScroll: {
    sortDuringScroll: true,
     targets:  (item) => {
        return [
          { element: window, priority: 0 },
          { element: item.getGrid().getElement().parentNode, priority: 1 },
        ];
      }
    },
});

My SCSS:

.board-container{
 // so users can scroll the board left/right manually
  overflow-x: scroll;
  position: relative;
  width: 100%;
  height: 100%;
}

.drag-container {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 1000;
}

.board {
  position: relative;
  height: 100%;
  margin-top: 20px;
}
.board-column {
  position: absolute;
  width: 300px;
  margin: 0 10px;
  border-radius: 3px;
  z-index: 1;
}
.board-column.muuri-item-releasing {
  z-index: 2;
}
.board-column.muuri-item-dragging {
  z-index: 3;
  cursor: move;
}
.board-column-header {
  position: relative;
  height: 50px;
  line-height: 50px;
  overflow: hidden;
  padding: 0 20px;
  text-align: center;
  background: #333;
  color: #fff;
  border-radius: 3px 3px 0 0;
}
@media (max-width: 600px) {
  .board-column-header {
    text-indent: -1000px;
  }
}
.board-column.todo .board-column-header {
  background: #4A9FF9;
}
.board-column.working .board-column-header {
  background: #f9944a;
}
.board-column.done .board-column-header {
  background: #2ac06d;
}
/* This is the secret sauce,
   always use a wrapper for setting
   the "overflow: scroll/auto" */
.board-column-content-wrapper {
  position: relative;
  max-height: 100%;
  overflow-y: auto;
}
/* Never ever set "overflow: auto/scroll"
   to the muuri element, stuff will break */
.board-column-content {
  position: relative;
  border: 10px solid transparent;
  min-height: 95px;
  background: #f0f0f0;
  height: auto;
  border-radius: 0 0 4px 4px;
}
.board-item {
  position: absolute;
  width: 100%;
  margin: 5px 0;
}
.board-item.muuri-item-releasing {
  z-index: 9998;
}
.board-item.muuri-item-dragging {
  z-index: 9999;
  cursor: move;
}
.board-item.muuri-item-hidden {
  z-index: 0;
}
.board-item-content {
  position: relative;
  padding: 20px;
  background: #fff;
  border-radius: 4px;
  font-size: 17px;
  cursor: pointer;
  -webkit-box-shadow: 0px 1px 3px 0 rgba(0,0,0,0.2);
  box-shadow: 0px 1px 3px 0 rgba(0,0,0,0.2);
}
@media (max-width: 600px) {
  .board-item-content {
    text-align: center;
  }
  .board-item-content span {
    display: none;
  }
}
niklasramo commented 3 years ago

@ibrychgo All of those features are implemented in the kanban demo here AFAIK (7 included): https://muuri.dev/, you can peek the code here: https://github.com/haltu/muuri/tree/gh-pages. Hope that helps :)

ibrychgo commented 3 years ago

You seriously ROCK!

None of the other kanban demos had that particular dragAutoScroll setting and, admittedly, it's an option I'm still trying to get my head around.

Simply swapping my dragAutoScroll settings for items with the one from the doc source did the trick.

This is DEFINITELY the library we are moving forward with. THANK YOU!