/** * @fileoverview * Utility functions for drag interactions, e.g. sorting items in a grid/list. */ /** * From an xy position and a list of boxes {top, left, bottom, right}, return there * corresponding box index the position is over. The boxes are in a (possibly wrapped) * list, the only requirement being all boxes are flush against the edges, that is, * if they are along an outer edge, the position of that edge is identical. * This functionality works for a single column of items, a wrapped list with * many rows, or a single row of items. * @param {{x: number, y: number}} position The xy coordinates to retreive the corresponding index of. * @param {Array.<DOMRect>} boxes The rects of the items, returned from `getBoundingClientRect` * @return {?number} index of the corresponding box, or null if one could not be found. */ const indexForPositionOnList = ({x, y}, boxes) => { if (boxes.length === 0) return null; let index = null; const leftEdge = Math.min.apply(null, boxes.map(b => b.left)); const rightEdge = Math.max.apply(null, boxes.map(b => b.right)); const topEdge = Math.min.apply(null, boxes.map(b => b.top)); const bottomEdge = Math.max.apply(null, boxes.map(b => b.bottom)); for (let n = 0; n < boxes.length; n++) { const box = boxes[n]; // Construct an "extended" box for each, extending out to infinity if // the box is along a boundary. const minX = box.left === leftEdge ? -Infinity : box.left; const minY = box.top === topEdge ? -Infinity : box.top; const maxY = box.bottom === bottomEdge ? Infinity : box.bottom; // The last item in the wrapped list gets a right edge at infinity, even // if it isn't the farthest right. Add this as an "or" condition for extension. const maxX = (n === boxes.length - 1 || box.right === rightEdge) ? Infinity : box.right; // Check if the point is in the bounds. if (x > minX && x <= maxX && y > minY && y <= maxY) { index = n; break; // No need to keep looking. } } return index; }; export { indexForPositionOnList };