From b1f2fe326a38aeaddc7ecbff6d9d9a9b8d3ff6db Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 27 Feb 2023 13:59:35 +0000 Subject: [PATCH] Fix multiple issues with z-index, reordering and resizing --- .../src/components/sheet/ResizeOverlay.svelte | 28 ++++---- .../src/components/sheet/Sheet.svelte | 30 ++++---- .../src/components/sheet/SheetCell.svelte | 68 +++++-------------- .../src/components/sheet/SheetRow.svelte | 60 ++++++++-------- .../components/sheet/cells/OptionsCell.svelte | 8 --- .../src/components/sheet/stores/reorder.js | 55 ++------------- .../src/components/sheet/stores/viewport.js | 25 ++++--- 7 files changed, 98 insertions(+), 176 deletions(-) diff --git a/packages/frontend-core/src/components/sheet/ResizeOverlay.svelte b/packages/frontend-core/src/components/sheet/ResizeOverlay.svelte index 2c40f34f7d..6ed31268e6 100644 --- a/packages/frontend-core/src/components/sheet/ResizeOverlay.svelte +++ b/packages/frontend-core/src/components/sheet/ResizeOverlay.svelte @@ -1,5 +1,4 @@ {#each $visibleColumns as col} -
startResizing(col.idx, e)} - style="--left:{col.left + - col.width - - (col.idx === 0 ? 0 : $scroll.left)}px;" - > -
-
+ {#if col.idx === 0 || col.left + col.width > cutoff} +
startResizing(col.idx, e)} + style="--left:{col.left + + col.width - + (col.idx === 0 ? 0 : $scroll.left)}px;" + > +
+
+ {/if} {/each} diff --git a/packages/frontend-core/src/components/sheet/SheetCell.svelte b/packages/frontend-core/src/components/sheet/SheetCell.svelte index 7a40bf92ed..f4d5bbb1f7 100644 --- a/packages/frontend-core/src/components/sheet/SheetCell.svelte +++ b/packages/frontend-core/src/components/sheet/SheetCell.svelte @@ -1,8 +1,6 @@ -
- ($hoveredRowId = row._id)} - on:click={() => selectRow(row._id)} - > - {#if rowSelected || rowHovered} +
+ selectRow(row._id)}> +
- {:else} - - {row.__idx + 1} - - {/if} +
+
+ {row.__idx + 1} +
{#each $visibleColumns as column (column.name)} {@const cellIdx = `${row._id}-${column.name}`} ($hoveredRowId = row._id)} on:click={() => ($selectedCellId = cellIdx)} width={column.width} left={column.left} @@ -101,14 +85,36 @@ .row { display: flex; position: absolute; - top: 0; - transform: translateY(var(--top)); + top: var(--top); width: inherit; } - .row.contains-selected-cell { - z-index: 1; + .row:hover :global(.cell) { + background: var(--cell-background-hover); } + /* Styles for label cell */ + .checkbox { + display: none; + } + input[type="checkbox"] { + margin: 0; + } + .number { + display: none; + min-width: 14px; + text-align: center; + color: var(--spectrum-global-color-gray-500); + } + .row:hover .checkbox, + .checkbox.visible, + .number.visible { + display: block; + } + .row:hover .number { + display: none; + } + + /* Add right border to last cell */ .row :global(> :last-child) { border-right-width: 1px; } diff --git a/packages/frontend-core/src/components/sheet/cells/OptionsCell.svelte b/packages/frontend-core/src/components/sheet/cells/OptionsCell.svelte index 754bac35a2..6f4e3dea42 100644 --- a/packages/frontend-core/src/components/sheet/cells/OptionsCell.svelte +++ b/packages/frontend-core/src/components/sheet/cells/OptionsCell.svelte @@ -151,13 +151,6 @@ var(--cell-background) 40% ); } - :global(.cell.hovered) .arrow { - background: linear-gradient( - to right, - transparent 0%, - var(--cell-background-hover) 40% - ); - } .options { min-width: 100%; position: absolute; @@ -170,7 +163,6 @@ align-items: stretch; max-height: calc(6 * var(--cell-height) - 1px); overflow-y: auto; - z-index: 1; } .option { flex: 0 0 var(--cell-height); diff --git a/packages/frontend-core/src/components/sheet/stores/reorder.js b/packages/frontend-core/src/components/sheet/stores/reorder.js index 8549452aff..dd07cd043a 100644 --- a/packages/frontend-core/src/components/sheet/stores/reorder.js +++ b/packages/frontend-core/src/components/sheet/stores/reorder.js @@ -1,7 +1,7 @@ import { get, writable } from "svelte/store" export const createReorderStores = context => { - const { columns, bounds, rows, scroll, rand } = context + const { columns, visibleColumns, rand, scroll, bounds } = context const reorderInitialState = { columnIdx: null, swapColumnIdx: null, @@ -10,33 +10,14 @@ export const createReorderStores = context => { } const reorder = writable(reorderInitialState) - // This is broken into its own store as it is rapidly updated, and we want to - // ensure good performance by avoiding updating other components which depend - // on other reordering state - const placeholderInitialState = { - x: null, - initialX: null, - width: null, - height: null, - } - const placeholder = writable(placeholderInitialState) - // Callback when dragging on a colum header and starting reordering const startReordering = (columnIdx, e) => { const $columns = get(columns) const $bounds = get(bounds) - const $rows = get(rows) const $scroll = get(scroll) // Generate new breakpoints for the current columns - let breakpoints = [] - $columns.forEach((col, idx) => { - breakpoints.push(col.left) - if (idx === $columns.length - 1) { - breakpoints.push(col.left + col.width) - } - }) - const self = $columns[columnIdx] + let breakpoints = $columns.map(col => col.left + col.width) // Update state reorder.set({ @@ -44,15 +25,8 @@ export const createReorderStores = context => { breakpoints, swapColumnIdx: null, initialMouseX: e.clientX, - }) - placeholder.set({ - initialX: self.left, - x: self.left, - width: self.width, - height: ($rows.length + 2) * 32, - sheetLeft: $bounds.left, - maxX: $bounds.width - self.width, scrollLeft: $scroll.left, + sheetLeft: $bounds.left, }) // Add listeners to handle mouse movement @@ -71,34 +45,18 @@ export const createReorderStores = context => { return } - // Compute new placeholder position - const $placeholder = get(placeholder) - let newX = - e.clientX - - $reorder.initialMouseX + - $placeholder.initialX - - $placeholder.scrollLeft - newX = Math.max(0, newX) - newX = Math.min($placeholder.maxX, newX) - // Compute the closest breakpoint to the current position let swapColumnIdx let minDistance = Number.MAX_SAFE_INTEGER + const mouseX = e.clientX - $reorder.sheetLeft + $reorder.scrollLeft $reorder.breakpoints.forEach((point, idx) => { - const distance = Math.abs( - point - e.clientX + $placeholder.sheetLeft - $placeholder.scrollLeft - ) + const distance = Math.abs(point - mouseX) if (distance < minDistance) { minDistance = distance swapColumnIdx = idx } }) - // Update state - placeholder.update(state => { - state.x = newX - return state - }) if (swapColumnIdx !== $reorder.swapColumnIdx) { reorder.update(state => { state.swapColumnIdx = swapColumnIdx @@ -111,6 +69,7 @@ export const createReorderStores = context => { const stopReordering = () => { // Swap position of columns let { columnIdx, swapColumnIdx } = get(reorder) + swapColumnIdx++ columns.update(state => { const removed = state.splice(columnIdx, 1) if (--swapColumnIdx < columnIdx) { @@ -131,7 +90,6 @@ export const createReorderStores = context => { // Reset state reorder.set(reorderInitialState) - placeholder.set(placeholderInitialState) // Remove event handlers document.removeEventListener("mousemove", onReorderMouseMove) @@ -147,6 +105,5 @@ export const createReorderStores = context => { stopReordering, }, }, - reorderPlaceholder: placeholder, } } diff --git a/packages/frontend-core/src/components/sheet/stores/viewport.js b/packages/frontend-core/src/components/sheet/stores/viewport.js index ad501147da..f4801dcfba 100644 --- a/packages/frontend-core/src/components/sheet/stores/viewport.js +++ b/packages/frontend-core/src/components/sheet/stores/viewport.js @@ -1,4 +1,5 @@ import { writable, derived } from "svelte/store" +import { Utils } from "../../../utils" export const createViewportStores = context => { const { cellHeight, columns, rows, scroll, bounds } = context @@ -16,15 +17,17 @@ export const createViewportStores = context => { // Debounce scroll updates so we can slow down visible row computation scroll.subscribe(({ left, top }) => { - // Only update local state when big changes occur - if (Math.abs(top - scrollTop) > cellHeight * 2) { - scrollTop = top - scrollTopStore.set(top) - } - if (Math.abs(left - scrollLeft) > 100) { - scrollLeft = left - scrollLeftStore.set(left) - } + window.requestAnimationFrame(() => { + // Only update local state when big changes occur + if (Math.abs(top - scrollTop) > cellHeight * 2) { + scrollTop = top + scrollTopStore.set(top) + } + if (Math.abs(left - scrollLeft) > 100) { + scrollLeft = left + scrollLeftStore.set(left) + } + }) }) // Derive visible rows @@ -32,8 +35,8 @@ export const createViewportStores = context => { [rows, scrollTopStore, height], ([$rows, $scrollTop, $height]) => { console.log("new rows") - const maxRows = Math.ceil($height / cellHeight) + 8 - const firstRow = Math.max(0, Math.floor($scrollTop / cellHeight) - 4) + const maxRows = Math.ceil($height / cellHeight) + 16 + const firstRow = Math.max(0, Math.floor($scrollTop / cellHeight) - 8) return $rows.slice(firstRow, firstRow + maxRows) } )