Merge pull request #11935 from Budibase/grid-mobile-scrolling
Grid mobile scrolling support
This commit is contained in:
commit
ac92640931
|
@ -35,7 +35,7 @@
|
|||
</script>
|
||||
|
||||
<div bind:this={body} class="grid-body">
|
||||
<GridScrollWrapper scrollHorizontally scrollVertically wheelInteractive>
|
||||
<GridScrollWrapper scrollHorizontally scrollVertically attachHandlers>
|
||||
{#each $renderedRows as row, idx}
|
||||
<GridRow
|
||||
{row}
|
||||
|
|
|
@ -17,7 +17,11 @@
|
|||
|
||||
export let scrollVertically = false
|
||||
export let scrollHorizontally = false
|
||||
export let wheelInteractive = false
|
||||
export let attachHandlers = false
|
||||
|
||||
// Used for tracking touch events
|
||||
let initialTouchX
|
||||
let initialTouchY
|
||||
|
||||
$: style = generateStyle($scroll, $rowHeight, $hiddenColumnsWidth)
|
||||
|
||||
|
@ -27,17 +31,47 @@
|
|||
return `transform: translate3d(${offsetX}px, ${offsetY}px, 0);`
|
||||
}
|
||||
|
||||
// Handles a wheel even and updates the scroll offsets
|
||||
// Handles a mouse wheel event and updates scroll state
|
||||
const handleWheel = e => {
|
||||
e.preventDefault()
|
||||
debouncedHandleWheel(e.deltaX, e.deltaY, e.clientY)
|
||||
updateScroll(e.deltaX, e.deltaY, e.clientY)
|
||||
|
||||
// If a context menu was visible, hide it
|
||||
if ($menu.visible) {
|
||||
menu.actions.close()
|
||||
}
|
||||
}
|
||||
const debouncedHandleWheel = domDebounce((deltaX, deltaY, clientY) => {
|
||||
|
||||
// Handles touch start events
|
||||
const handleTouchStart = e => {
|
||||
if (!e.touches?.[0]) return
|
||||
initialTouchX = e.touches[0].clientX
|
||||
initialTouchY = e.touches[0].clientY
|
||||
}
|
||||
|
||||
// Handles touch move events and updates scroll state
|
||||
const handleTouchMove = e => {
|
||||
if (!e.touches?.[0]) return
|
||||
e.preventDefault()
|
||||
|
||||
// Compute delta from previous event, and update scroll
|
||||
const deltaX = initialTouchX - e.touches[0].clientX
|
||||
const deltaY = initialTouchY - e.touches[0].clientY
|
||||
updateScroll(deltaX, deltaY)
|
||||
|
||||
// Store position to reference in next event
|
||||
initialTouchX = e.touches[0].clientX
|
||||
initialTouchY = e.touches[0].clientY
|
||||
|
||||
// If a context menu was visible, hide it
|
||||
if ($menu.visible) {
|
||||
menu.actions.close()
|
||||
}
|
||||
}
|
||||
|
||||
// Updates the scroll offset by a certain delta, and ensure scrolling
|
||||
// stays within sensible bounds. Debounced for performance.
|
||||
const updateScroll = domDebounce((deltaX, deltaY, clientY) => {
|
||||
const { top, left } = $scroll
|
||||
|
||||
// Calculate new scroll top
|
||||
|
@ -55,15 +89,19 @@
|
|||
})
|
||||
|
||||
// Hover row under cursor
|
||||
const y = clientY - $bounds.top + (newScrollTop % $rowHeight)
|
||||
const hoveredRow = $renderedRows[Math.floor(y / $rowHeight)]
|
||||
hoveredRowId.set(hoveredRow?._id)
|
||||
if (clientY != null) {
|
||||
const y = clientY - $bounds.top + (newScrollTop % $rowHeight)
|
||||
const hoveredRow = $renderedRows[Math.floor(y / $rowHeight)]
|
||||
hoveredRowId.set(hoveredRow?._id)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="outer"
|
||||
on:wheel={wheelInteractive ? handleWheel : null}
|
||||
on:wheel={attachHandlers ? handleWheel : null}
|
||||
on:touchstart={attachHandlers ? handleTouchStart : null}
|
||||
on:touchmove={attachHandlers ? handleTouchMove : null}
|
||||
on:click|self={() => ($focusedCellId = null)}
|
||||
>
|
||||
<div {style} class="inner">
|
||||
|
|
|
@ -205,7 +205,7 @@
|
|||
{/if}
|
||||
</div>
|
||||
<div class="normal-columns" transition:fade|local={{ duration: 130 }}>
|
||||
<GridScrollWrapper scrollHorizontally wheelInteractive>
|
||||
<GridScrollWrapper scrollHorizontally attachHandlers>
|
||||
<div class="row">
|
||||
{#each $renderedColumns as column, columnIdx}
|
||||
{@const cellId = `new-${column.name}`}
|
||||
|
|
|
@ -64,7 +64,7 @@
|
|||
</div>
|
||||
|
||||
<div class="content" on:mouseleave={() => ($hoveredRowId = null)}>
|
||||
<GridScrollWrapper scrollVertically wheelInteractive>
|
||||
<GridScrollWrapper scrollVertically attachHandlers>
|
||||
{#each $renderedRows as row, idx}
|
||||
{@const rowSelected = !!$selectedRows[row._id]}
|
||||
{@const rowHovered = $hoveredRowId === row._id}
|
||||
|
|
|
@ -53,18 +53,27 @@
|
|||
}
|
||||
}
|
||||
|
||||
const getLocation = e => {
|
||||
return {
|
||||
y: e.touches?.[0]?.clientY ?? e.clientY,
|
||||
x: e.touches?.[0]?.clientX ?? e.clientX,
|
||||
}
|
||||
}
|
||||
|
||||
// V scrollbar drag handlers
|
||||
const startVDragging = e => {
|
||||
e.preventDefault()
|
||||
initialMouse = e.clientY
|
||||
initialMouse = getLocation(e).y
|
||||
initialScroll = $scrollTop
|
||||
document.addEventListener("mousemove", moveVDragging)
|
||||
document.addEventListener("touchmove", moveVDragging)
|
||||
document.addEventListener("mouseup", stopVDragging)
|
||||
document.addEventListener("touchend", stopVDragging)
|
||||
isDraggingV = true
|
||||
closeMenu()
|
||||
}
|
||||
const moveVDragging = domDebounce(e => {
|
||||
const delta = e.clientY - initialMouse
|
||||
const delta = getLocation(e).y - initialMouse
|
||||
const weight = delta / availHeight
|
||||
const newScrollTop = initialScroll + weight * $maxScrollTop
|
||||
scroll.update(state => ({
|
||||
|
@ -74,22 +83,26 @@
|
|||
})
|
||||
const stopVDragging = () => {
|
||||
document.removeEventListener("mousemove", moveVDragging)
|
||||
document.removeEventListener("touchmove", moveVDragging)
|
||||
document.removeEventListener("mouseup", stopVDragging)
|
||||
document.removeEventListener("touchend", stopVDragging)
|
||||
isDraggingV = false
|
||||
}
|
||||
|
||||
// H scrollbar drag handlers
|
||||
const startHDragging = e => {
|
||||
e.preventDefault()
|
||||
initialMouse = e.clientX
|
||||
initialMouse = getLocation(e).x
|
||||
initialScroll = $scrollLeft
|
||||
document.addEventListener("mousemove", moveHDragging)
|
||||
document.addEventListener("touchmove", moveHDragging)
|
||||
document.addEventListener("mouseup", stopHDragging)
|
||||
document.addEventListener("touchend", stopHDragging)
|
||||
isDraggingH = true
|
||||
closeMenu()
|
||||
}
|
||||
const moveHDragging = domDebounce(e => {
|
||||
const delta = e.clientX - initialMouse
|
||||
const delta = getLocation(e).x - initialMouse
|
||||
const weight = delta / availWidth
|
||||
const newScrollLeft = initialScroll + weight * $maxScrollLeft
|
||||
scroll.update(state => ({
|
||||
|
@ -99,7 +112,9 @@
|
|||
})
|
||||
const stopHDragging = () => {
|
||||
document.removeEventListener("mousemove", moveHDragging)
|
||||
document.removeEventListener("touchmove", moveHDragging)
|
||||
document.removeEventListener("mouseup", stopHDragging)
|
||||
document.removeEventListener("touchend", stopHDragging)
|
||||
isDraggingH = false
|
||||
}
|
||||
</script>
|
||||
|
@ -109,6 +124,7 @@
|
|||
class="v-scrollbar"
|
||||
style="--size:{ScrollBarSize}px; top:{barTop}px; height:{barHeight}px;"
|
||||
on:mousedown={startVDragging}
|
||||
on:touchstart={startVDragging}
|
||||
class:dragging={isDraggingV}
|
||||
/>
|
||||
{/if}
|
||||
|
@ -117,6 +133,7 @@
|
|||
class="h-scrollbar"
|
||||
style="--size:{ScrollBarSize}px; left:{barLeft}px; width:{barWidth}px;"
|
||||
on:mousedown={startHDragging}
|
||||
on:touchstart={startHDragging}
|
||||
class:dragging={isDraggingH}
|
||||
/>
|
||||
{/if}
|
||||
|
|
Loading…
Reference in New Issue