Fix reorder
This commit is contained in:
parent
ada3367b49
commit
42538e114a
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -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,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue