Fix reorder

This commit is contained in:
Andrew Kingston 2024-06-24 13:03:33 +01:00
parent ada3367b49
commit 42538e114a
No known key found for this signature in database
5 changed files with 64 additions and 69 deletions

View File

@ -1,37 +1,33 @@
<script> <script>
import { getContext } from "svelte" import { getContext } from "svelte"
import GridScrollWrapper from "../layout/GridScrollWrapper.svelte" import GridScrollWrapper from "../layout/GridScrollWrapper.svelte"
import { DefaultRowHeight, GutterWidth } from "../lib/constants" import { DefaultRowHeight } from "../lib/constants"
const { const {
isReordering, isReordering,
reorder, reorder,
visibleColumnLookupMap, visibleColumnLookupMap,
displayColumn,
rowHeight, rowHeight,
renderedRows, renderedRows,
scrollLeft, scrollLeft,
bodyLeft,
} = getContext("grid") } = getContext("grid")
$: targetColumn = $visibleColumnLookupMap[$reorder.targetColumn] $: targetColumn = $visibleColumnLookupMap[$reorder.targetColumn]
$: console.log(targetColumn) $: insertAfter = $reorder.insertAfter
$: minLeft = GutterWidth + ($displayColumn?.width || 0) $: left = getLeft(targetColumn, insertAfter, $scrollLeft)
$: left = getLeft(targetColumn, $displayColumn, $scrollLeft)
$: height = $rowHeight * $renderedRows.length + DefaultRowHeight $: height = $rowHeight * $renderedRows.length + DefaultRowHeight
$: style = `left:${left}px; height:${height}px;` $: style = `left:${left}px; height:${height}px;`
$: visible = $isReordering && left >= minLeft $: visible = $isReordering && left >= $bodyLeft
const getLeft = (targetColumn, displayColumn, scrollLeft) => { const getLeft = (targetColumn, insertAfter, scrollLeft) => {
if (!targetColumn) { if (!targetColumn) {
return 0 return 0
} }
let left = GutterWidth + (displayColumn?.width || 0) - scrollLeft let left = targetColumn.__left - scrollLeft
if (insertAfter) {
// If this is not the sticky column, add additional left space left += targetColumn.width
if (!targetColumn.primaryDisplay) {
left += targetColumn.__left + targetColumn.width
} }
return left return left
} }
</script> </script>

View File

@ -1,41 +1,28 @@
<script> <script>
import { getContext } from "svelte" import { getContext } from "svelte"
import { GutterWidth } from "../lib/constants"
const { resize, visibleColumns, displayColumn, isReordering, scrollLeft } = const { resize, visibleColumns, isReordering, scrollLeft } =
getContext("grid") getContext("grid")
$: offset = GutterWidth + ($displayColumn?.width || 0) const getStyle = (column, scrollLeft) => {
$: activeColumn = $resize.column let left = column.__left + column.width
if (!column.primaryDisplay) {
const getStyle = (column, offset, scrollLeft) => { left -= scrollLeft
const left = offset + column.__left + column.width - scrollLeft }
return `left:${left}px;` return `left:${left}px;`
} }
</script> </script>
<!-- svelte-ignore a11y-no-static-element-interactions --> <!-- svelte-ignore a11y-no-static-element-interactions -->
{#if !$isReordering} {#if !$isReordering}
{#if $displayColumn}
<div
class="resize-slider"
class:visible={activeColumn === $displayColumn.name}
on:mousedown={e => resize.actions.startResizing($displayColumn, e)}
on:touchstart={e => resize.actions.startResizing($displayColumn, e)}
on:dblclick={() => resize.actions.resetSize($displayColumn)}
style="left:{GutterWidth + $displayColumn.width}px;"
>
<div class="resize-indicator" />
</div>
{/if}
{#each $visibleColumns as column} {#each $visibleColumns as column}
<div <div
class="resize-slider" class="resize-slider"
class:visible={activeColumn === column.name} class:visible={$resize.column === column.name}
on:mousedown={e => resize.actions.startResizing(column, e)} on:mousedown={e => resize.actions.startResizing(column, e)}
on:touchstart={e => resize.actions.startResizing(column, e)} on:touchstart={e => resize.actions.startResizing(column, e)}
on:dblclick={() => resize.actions.resetSize(column)} on:dblclick={() => resize.actions.resetSize(column)}
style={getStyle(column, offset, $scrollLeft)} style={getStyle(column, $scrollLeft)}
> >
<div class="resize-indicator" /> <div class="resize-indicator" />
</div> </div>

View File

@ -1,5 +1,5 @@
import { derived, get, writable } from "svelte/store" import { derived, get, writable } from "svelte/store"
import { DefaultColumnWidth } from "../lib/constants" import { DefaultColumnWidth, GutterWidth } from "../lib/constants"
export const createStores = () => { export const createStores = () => {
const columns = writable([]) const columns = writable([])
@ -39,16 +39,16 @@ export const deriveStores = context => {
// Derived list of columns which have not been explicitly hidden, and enrich // Derived list of columns which have not been explicitly hidden, and enrich
// with an index so we can easily select nearby columns // with an index so we can easily select nearby columns
const visibleColumns = derived(columns, $columns => { const visibleColumns = derived(columns, $columns => {
let offset = 0 let offset = GutterWidth
return $columns return $columns
.filter(col => col.visible) .filter(col => col.visible)
.map((column, idx) => { .map((col, idx) => {
const enriched = { const enriched = {
...column, ...col,
__left: offset, __left: offset,
__idx: idx, __idx: idx,
} }
offset += column.width offset += col.width
return enriched return enriched
}) })
}) })

View File

@ -4,10 +4,10 @@ import { parseEventLocation } from "../lib/utils"
const reorderInitialState = { const reorderInitialState = {
sourceColumn: null, sourceColumn: null,
targetColumn: null, targetColumn: null,
insertAfter: false,
breakpoints: [], breakpoints: [],
gridLeft: 0, gridLeft: 0,
width: 0, width: 0,
latestX: 0,
increment: 0, increment: 0,
} }
@ -35,10 +35,11 @@ export const createActions = context => {
bounds, bounds,
visibleColumns, visibleColumns,
maxScrollLeft, maxScrollLeft,
width,
datasource, datasource,
bodyLeft,
width,
} = context } = context
let latestX = 0
let autoScrollInterval let autoScrollInterval
let isAutoScrolling let isAutoScrolling
@ -46,13 +47,25 @@ export const createActions = context => {
const startReordering = (column, e) => { const startReordering = (column, e) => {
const $scrollableColumns = get(scrollableColumns) const $scrollableColumns = get(scrollableColumns)
const $bounds = get(bounds) const $bounds = get(bounds)
const $bodyLeft = get(bodyLeft)
// Generate new breakpoints for the current columns // Generate new breakpoints for the current columns
const breakpoints = $scrollableColumns.map(col => ({ const breakpoints = $scrollableColumns.map(col => ({
x: col.__left + col.width, x: col.__left - $bodyLeft,
column: col.name, column: col.name,
insertAfter: false,
})) }))
// Add a very left breakpoint as well
const lastCol = $scrollableColumns[$scrollableColumns.length - 1]
if (lastCol) {
breakpoints.push({
x: lastCol.__left + lastCol.width - $bodyLeft,
column: lastCol.name,
insertAfter: true,
})
}
// Update state // Update state
reorder.set({ reorder.set({
sourceColumn: column, sourceColumn: column,
@ -77,10 +90,7 @@ export const createActions = context => {
const onReorderMouseMove = e => { const onReorderMouseMove = e => {
// Immediately handle the current position // Immediately handle the current position
const { x } = parseEventLocation(e) const { x } = parseEventLocation(e)
reorder.update(state => ({ latestX = x
...state,
latestX: x,
}))
considerReorderPosition() considerReorderPosition()
// Check if we need to start auto-scrolling // Check if we need to start auto-scrolling
@ -110,20 +120,25 @@ export const createActions = context => {
const $scroll = get(scroll) const $scroll = get(scroll)
// Compute the closest breakpoint to the current position // Compute the closest breakpoint to the current position
let targetColumn let breakpoint
let minDistance = Number.MAX_SAFE_INTEGER let minDistance = Number.MAX_SAFE_INTEGER
const mouseX = $reorder.latestX - $reorder.gridLeft + $scroll.left const mouseX = latestX - $reorder.gridLeft + $scroll.left
$reorder.breakpoints.forEach(point => { $reorder.breakpoints.forEach(point => {
const distance = Math.abs(point.x - mouseX) const distance = Math.abs(point.x - mouseX)
if (distance < minDistance) { if (distance < minDistance) {
minDistance = distance minDistance = distance
targetColumn = point.column breakpoint = point
} }
}) })
if (targetColumn !== $reorder.targetColumn) { if (
breakpoint &&
(breakpoint.column !== $reorder.targetColumn ||
breakpoint.insertAfter !== $reorder.insertAfter)
) {
reorder.update(state => ({ reorder.update(state => ({
...state, ...state,
targetColumn, targetColumn: breakpoint.column,
insertAfter: breakpoint.insertAfter,
})) }))
} }
} }

View File

@ -32,44 +32,40 @@ export const deriveStores = context => {
} = context } = context
// Memoize store primitives // Memoize store primitives
const stickyColumnWidth = derived(displayColumn, $col => $col?.width || 0, 0) const bodyLeft = derived(displayColumn, $displayColumn => {
return ($displayColumn?.width || 0) + GutterWidth
})
// Derive vertical limits // Derive vertical limits
const contentHeight = derived( const contentHeight = derived(
[rows, rowHeight], [rows, rowHeight],
([$rows, $rowHeight]) => ($rows.length + 1) * $rowHeight + Padding, ([$rows, $rowHeight]) => ($rows.length + 1) * $rowHeight + Padding
0
) )
const maxScrollTop = derived( const maxScrollTop = derived(
[height, contentHeight], [height, contentHeight],
([$height, $contentHeight]) => Math.max($contentHeight - $height, 0), ([$height, $contentHeight]) => Math.max($contentHeight - $height, 0)
0
) )
// Derive horizontal limits // Derive horizontal limits
const contentWidth = derived( const contentWidth = derived(
[visibleColumns, stickyColumnWidth, buttonColumnWidth], [visibleColumns, buttonColumnWidth],
([$visibleColumns, $stickyColumnWidth, $buttonColumnWidth]) => { ([$visibleColumns, $buttonColumnWidth]) => {
const space = Math.max(Padding, $buttonColumnWidth - 1) const space = Math.max(Padding, $buttonColumnWidth - 1)
let width = GutterWidth + space + $stickyColumnWidth let width = GutterWidth + space
$visibleColumns.forEach(col => { $visibleColumns.forEach(col => {
width += col.width width += col.width
}) })
return width return width
}, }
0
)
const screenWidth = derived(
[width, stickyColumnWidth],
([$width, $stickyColumnWidth]) => $width + GutterWidth + $stickyColumnWidth,
0
) )
const screenWidth = derived([width, bodyLeft], ([$width, $bodyLeft]) => {
return $width + $bodyLeft
})
const maxScrollLeft = derived( const maxScrollLeft = derived(
[contentWidth, screenWidth], [contentWidth, screenWidth],
([$contentWidth, $screenWidth]) => { ([$contentWidth, $screenWidth]) => {
return Math.max($contentWidth - $screenWidth, 0) return Math.max($contentWidth - $screenWidth, 0)
}, }
0
) )
// Derive whether to show scrollbars or not // Derive whether to show scrollbars or not
@ -87,6 +83,7 @@ export const deriveStores = context => {
) )
return { return {
bodyLeft,
contentHeight, contentHeight,
contentWidth, contentWidth,
screenWidth, screenWidth,