From fcb8b9e9b1a322be83f5119fbf0c2cebd20edcce Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 31 Mar 2023 20:33:08 +0100 Subject: [PATCH] Add resizable rows --- .../sheet/cells/AttachmentCell.svelte | 4 +- .../sheet/cells/LongFormCell.svelte | 2 +- .../components/sheet/cells/OptionsCell.svelte | 4 +- .../sheet/cells/RelationshipCell.svelte | 6 +- .../components/sheet/cells/SheetCell.svelte | 4 +- .../sheet/controls/RowHeightButton.svelte | 58 +++++++++++++++++++ .../components/sheet/layout/HeaderRow.svelte | 4 +- .../components/sheet/layout/NewRowTop.svelte | 2 +- .../src/components/sheet/layout/Sheet.svelte | 6 +- .../components/sheet/layout/SheetBody.svelte | 5 +- .../sheet/layout/SheetControls.svelte | 2 + .../sheet/layout/SheetScrollWrapper.svelte | 8 +-- .../sheet/overlays/ResizeOverlay.svelte | 6 +- .../sheet/overlays/ScrollOverlay.svelte | 4 +- .../src/components/sheet/stores/max-scroll.js | 11 ++-- .../src/components/sheet/stores/menu.js | 5 +- .../src/components/sheet/stores/ui.js | 2 + .../src/components/sheet/stores/viewport.js | 14 ++--- .../src/components/sheet/stores/wheel.js | 7 ++- 19 files changed, 108 insertions(+), 46 deletions(-) create mode 100644 packages/frontend-core/src/components/sheet/controls/RowHeightButton.svelte diff --git a/packages/frontend-core/src/components/sheet/cells/AttachmentCell.svelte b/packages/frontend-core/src/components/sheet/cells/AttachmentCell.svelte index 7f3b065845..9cd48cfaca 100644 --- a/packages/frontend-core/src/components/sheet/cells/AttachmentCell.svelte +++ b/packages/frontend-core/src/components/sheet/cells/AttachmentCell.svelte @@ -122,7 +122,7 @@ flex-direction: row; justify-content: flex-start; align-items: center; - height: calc(var(--cell-height) - 12px); + height: calc(var(--row-height) - 12px); padding: 0 8px; color: var(--spectrum-global-color-gray-800); border: 1px solid var(--spectrum-global-color-gray-300); @@ -133,7 +133,7 @@ user-select: none; } img { - height: calc(var(--cell-height) - 12px); + height: calc(var(--row-height) - 12px); max-width: 64px; } .dropzone { diff --git a/packages/frontend-core/src/components/sheet/cells/LongFormCell.svelte b/packages/frontend-core/src/components/sheet/cells/LongFormCell.svelte index 1392cccfc4..1c9eaa06ca 100644 --- a/packages/frontend-core/src/components/sheet/cells/LongFormCell.svelte +++ b/packages/frontend-core/src/components/sheet/cells/LongFormCell.svelte @@ -92,7 +92,7 @@ top: -1px; left: -1px; width: calc(100% + 100px); - height: calc(5 * var(--cell-height) + 1px); + height: calc(5 * var(--row-height) + 1px); border: var(--cell-border); box-shadow: inset 0 0 0 2px var(--spectrum-global-color-blue-400); } diff --git a/packages/frontend-core/src/components/sheet/cells/OptionsCell.svelte b/packages/frontend-core/src/components/sheet/cells/OptionsCell.svelte index f0755abf4a..5f30e80f9f 100644 --- a/packages/frontend-core/src/components/sheet/cells/OptionsCell.svelte +++ b/packages/frontend-core/src/components/sheet/cells/OptionsCell.svelte @@ -192,7 +192,7 @@ top: 0; } .option { - flex: 0 0 var(--cell-height); + flex: 0 0 var(--row-height); padding: 0 var(--cell-padding); display: flex; flex-direction: row; @@ -202,7 +202,7 @@ background-color: var(--cell-background-hover); } .option:first-child { - flex: 0 0 calc(var(--cell-height) - 1px); + flex: 0 0 calc(var(--row-height) - 1px); } .option:hover, .option.focused { diff --git a/packages/frontend-core/src/components/sheet/cells/RelationshipCell.svelte b/packages/frontend-core/src/components/sheet/cells/RelationshipCell.svelte index 725a57d26b..98c45058a7 100644 --- a/packages/frontend-core/src/components/sheet/cells/RelationshipCell.svelte +++ b/packages/frontend-core/src/components/sheet/cells/RelationshipCell.svelte @@ -316,7 +316,7 @@ } .result { padding: 0 var(--cell-padding); - flex: 0 0 var(--cell-height); + flex: 0 0 var(--row-height); display: flex; gap: var(--cell-spacing); justify-content: space-between; @@ -331,7 +331,7 @@ } .search { - flex: 0 0 calc(var(--cell-height) - 1px); + flex: 0 0 calc(var(--row-height) - 1px); display: flex; align-items: center; margin: 0 var(--cell-padding); @@ -349,7 +349,7 @@ color: var(--spectrum-global-color-gray-600); font-size: 12px; padding: var(--cell-padding); - flex: 0 0 var(--cell-height); + flex: 0 0 var(--row-height); display: flex; align-items: center; white-space: nowrap; diff --git a/packages/frontend-core/src/components/sheet/cells/SheetCell.svelte b/packages/frontend-core/src/components/sheet/cells/SheetCell.svelte index e80757d537..725de655d9 100644 --- a/packages/frontend-core/src/components/sheet/cells/SheetCell.svelte +++ b/packages/frontend-core/src/components/sheet/cells/SheetCell.svelte @@ -54,7 +54,7 @@ diff --git a/packages/frontend-core/src/components/sheet/layout/HeaderRow.svelte b/packages/frontend-core/src/components/sheet/layout/HeaderRow.svelte index 53d2ef2279..187848ed6d 100644 --- a/packages/frontend-core/src/components/sheet/layout/HeaderRow.svelte +++ b/packages/frontend-core/src/components/sheet/layout/HeaderRow.svelte @@ -33,7 +33,7 @@ border-bottom: var(--cell-border); position: relative; z-index: 2; - height: var(--cell-height); + height: var(--row-height); } .row { display: flex; @@ -42,7 +42,7 @@ position: absolute; right: 0; top: 0; - height: var(--cell-height); + height: var(--row-height); background: var(--spectrum-global-color-gray-100); display: grid; place-items: center; diff --git a/packages/frontend-core/src/components/sheet/layout/NewRowTop.svelte b/packages/frontend-core/src/components/sheet/layout/NewRowTop.svelte index 9240f60b03..abda73b0fc 100644 --- a/packages/frontend-core/src/components/sheet/layout/NewRowTop.svelte +++ b/packages/frontend-core/src/components/sheet/layout/NewRowTop.svelte @@ -149,7 +149,7 @@ .container { pointer-events: none; position: absolute; - top: var(--cell-height); + top: var(--row-height); transform: translateY(-100%); z-index: 1; transition: transform 130ms ease-out; diff --git a/packages/frontend-core/src/components/sheet/layout/Sheet.svelte b/packages/frontend-core/src/components/sheet/layout/Sheet.svelte index 1f414b10eb..57bfdea45d 100644 --- a/packages/frontend-core/src/components/sheet/layout/Sheet.svelte +++ b/packages/frontend-core/src/components/sheet/layout/Sheet.svelte @@ -40,7 +40,6 @@ export let allowEditRows = true // Sheet constants - const cellHeight = 36 const gutterWidth = 72 const rand = Math.random() @@ -60,7 +59,6 @@ let context = { API: API || createAPIClient(), rand, - cellHeight, gutterWidth, config, tableId: tableIdStore, @@ -81,7 +79,7 @@ context = { ...context, ...createWheelStores(context) } // Reference some stores for local use - const { isResizing, isReordering, ui, loaded } = context + const { isResizing, isReordering, ui, loaded, rowHeight } = context // Keep stores up to date $: tableIdStore.set(tableId) @@ -109,7 +107,7 @@ id="sheet-{rand}" class:is-resizing={$isResizing} class:is-reordering={$isReordering} - style="--cell-height:{cellHeight}px; --gutter-width:{gutterWidth}px; --max-cell-render-height:{MaxCellRenderHeight}px;" + style="--row-height:{$rowHeight}px; --gutter-width:{gutterWidth}px; --max-cell-render-height:{MaxCellRenderHeight}px;" >
diff --git a/packages/frontend-core/src/components/sheet/layout/SheetBody.svelte b/packages/frontend-core/src/components/sheet/layout/SheetBody.svelte index 18f1cefbc1..ef335074e2 100644 --- a/packages/frontend-core/src/components/sheet/layout/SheetBody.svelte +++ b/packages/frontend-core/src/components/sheet/layout/SheetBody.svelte @@ -4,14 +4,13 @@ import SheetRow from "./SheetRow.svelte" import { MaxCellRenderHeight } from "../lib/constants" - const { bounds, renderedRows, visualRowCapacity, cellHeight } = + const { bounds, renderedRows, visualRowCapacity, rowHeight } = getContext("sheet") let body $: inversionIdx = - $visualRowCapacity - Math.ceil(MaxCellRenderHeight / cellHeight) - 2 - $: console.log(inversionIdx) + $visualRowCapacity - Math.ceil(MaxCellRenderHeight / $rowHeight) - 2 onMount(() => { // Observe and record the height of the body diff --git a/packages/frontend-core/src/components/sheet/layout/SheetControls.svelte b/packages/frontend-core/src/components/sheet/layout/SheetControls.svelte index 133b3abff8..b8e13a6419 100644 --- a/packages/frontend-core/src/components/sheet/layout/SheetControls.svelte +++ b/packages/frontend-core/src/components/sheet/layout/SheetControls.svelte @@ -2,8 +2,10 @@ import SortButton from "../controls/SortButton.svelte" import HideColumnsButton from "../controls/HideColumnsButton.svelte" import AddRowButton from "../controls/AddRowButton.svelte" + import RowHeightButton from "../controls/RowHeightButton.svelte" + diff --git a/packages/frontend-core/src/components/sheet/layout/SheetScrollWrapper.svelte b/packages/frontend-core/src/components/sheet/layout/SheetScrollWrapper.svelte index 372cee82c5..1e701c4cc2 100644 --- a/packages/frontend-core/src/components/sheet/layout/SheetScrollWrapper.svelte +++ b/packages/frontend-core/src/components/sheet/layout/SheetScrollWrapper.svelte @@ -2,7 +2,7 @@ import { getContext } from "svelte" const { - cellHeight, + rowHeight, scroll, visibleColumns, renderedColumns, @@ -15,11 +15,11 @@ export let wheelInteractive = true $: hiddenWidths = calculateHiddenWidths($renderedColumns) - $: style = generateStyle($scroll, hiddenWidths) + $: style = generateStyle($scroll, $rowHeight, hiddenWidths) - const generateStyle = (scroll, hiddenWidths) => { + const generateStyle = (scroll, rowHeight, hiddenWidths) => { const offsetX = scrollHorizontally ? -1 * scroll.left + hiddenWidths : 0 - const offsetY = scrollVertically ? -1 * (scroll.top % cellHeight) : 0 + const offsetY = scrollVertically ? -1 * (scroll.top % rowHeight) : 0 return `transform: translate3d(${offsetX}px, ${offsetY}px, 0);` } diff --git a/packages/frontend-core/src/components/sheet/overlays/ResizeOverlay.svelte b/packages/frontend-core/src/components/sheet/overlays/ResizeOverlay.svelte index 929ae0a23e..40644fd669 100644 --- a/packages/frontend-core/src/components/sheet/overlays/ResizeOverlay.svelte +++ b/packages/frontend-core/src/components/sheet/overlays/ResizeOverlay.svelte @@ -51,8 +51,8 @@ .resize-slider { position: absolute; top: 0; - z-index: 1; - height: var(--cell-height); + z-index: 2; + height: var(--row-height); opacity: 0; padding: 0 8px; transform: translateX(-50%); @@ -64,7 +64,7 @@ opacity: 1; } .resize-slider.sticky { - z-index: 2; + z-index: 3; } .resize-indicator { margin-left: -1px; diff --git a/packages/frontend-core/src/components/sheet/overlays/ScrollOverlay.svelte b/packages/frontend-core/src/components/sheet/overlays/ScrollOverlay.svelte index 66ff743014..f95b5d617d 100644 --- a/packages/frontend-core/src/components/sheet/overlays/ScrollOverlay.svelte +++ b/packages/frontend-core/src/components/sheet/overlays/ScrollOverlay.svelte @@ -5,7 +5,7 @@ const { scroll, bounds, - cellHeight, + rowHeight, contentHeight, maxScrollTop, contentWidth, @@ -35,7 +35,7 @@ $: renderHeight = height - 2 * barOffset $: barHeight = Math.max(50, (height / $contentHeight) * renderHeight) $: availHeight = renderHeight - barHeight - $: barTop = barOffset + cellHeight + availHeight * (scrollTop / $maxScrollTop) + $: barTop = barOffset + $rowHeight + availHeight * (scrollTop / $maxScrollTop) // Calculate H scrollbar size and offset $: renderWidth = $screenWidth - 2 * barOffset diff --git a/packages/frontend-core/src/components/sheet/stores/max-scroll.js b/packages/frontend-core/src/components/sheet/stores/max-scroll.js index 9d19e93978..9cf09703e3 100644 --- a/packages/frontend-core/src/components/sheet/stores/max-scroll.js +++ b/packages/frontend-core/src/components/sheet/stores/max-scroll.js @@ -6,7 +6,7 @@ export const createMaxScrollStores = context => { visibleColumns, stickyColumn, bounds, - cellHeight, + rowHeight, scroll, selectedCellRow, selectedCellId, @@ -23,8 +23,8 @@ export const createMaxScrollStores = context => { const height = derived(bounds, $bounds => $bounds.height, 0) const width = derived(bounds, $bounds => $bounds.width, 0) const contentHeight = derived( - rows, - $rows => $rows.length * cellHeight + padding, + [rows, rowHeight], + ([$rows, $rowHeight]) => $rows.length * $rowHeight + padding, 0 ) const maxScrollTop = derived( @@ -94,12 +94,13 @@ export const createMaxScrollStores = context => { } const $scroll = get(scroll) const $bounds = get(bounds) + const $rowHeight = get(rowHeight) const scrollBarOffset = 16 // Ensure row is not below bottom of screen - const rowYPos = row.__idx * cellHeight + const rowYPos = row.__idx * $rowHeight const bottomCutoff = - $scroll.top + $bounds.height - cellHeight - scrollBarOffset + $scroll.top + $bounds.height - $rowHeight - scrollBarOffset let delta = rowYPos - bottomCutoff if (delta > 0) { scroll.update(state => ({ diff --git a/packages/frontend-core/src/components/sheet/stores/menu.js b/packages/frontend-core/src/components/sheet/stores/menu.js index c003631784..901ac54f95 100644 --- a/packages/frontend-core/src/components/sheet/stores/menu.js +++ b/packages/frontend-core/src/components/sheet/stores/menu.js @@ -1,7 +1,7 @@ import { writable, get } from "svelte/store" export const createMenuStores = context => { - const { bounds, selectedCellId, stickyColumn, cellHeight } = context + const { bounds, selectedCellId, stickyColumn, rowHeight } = context const menu = writable({ x: 0, y: 0, @@ -12,11 +12,12 @@ export const createMenuStores = context => { const open = (cellId, e) => { const $bounds = get(bounds) const $stickyColumn = get(stickyColumn) + const $rowHeight = get(rowHeight) e.preventDefault() selectedCellId.set(cellId) menu.set({ left: e.clientX - $bounds.left + 44 + ($stickyColumn?.width || 0), - top: e.clientY - $bounds.top + cellHeight + 4, + top: e.clientY - $bounds.top + $rowHeight + 4, visible: true, }) } diff --git a/packages/frontend-core/src/components/sheet/stores/ui.js b/packages/frontend-core/src/components/sheet/stores/ui.js index 427a6be694..d1687c581e 100644 --- a/packages/frontend-core/src/components/sheet/stores/ui.js +++ b/packages/frontend-core/src/components/sheet/stores/ui.js @@ -6,6 +6,7 @@ export const createUIStores = context => { const selectedRows = writable({}) const hoveredRowId = writable(null) const selectedCellAPI = writable(null) + const rowHeight = writable(36) // Derive the row that contains the selected cell. const selectedCellRow = derived( @@ -92,6 +93,7 @@ export const createUIStores = context => { hoveredRowId, selectedCellRow, selectedCellAPI, + rowHeight, ui: { actions: { blur, diff --git a/packages/frontend-core/src/components/sheet/stores/viewport.js b/packages/frontend-core/src/components/sheet/stores/viewport.js index df91258b79..f5f9c6ff66 100644 --- a/packages/frontend-core/src/components/sheet/stores/viewport.js +++ b/packages/frontend-core/src/components/sheet/stores/viewport.js @@ -1,7 +1,7 @@ import { derived, get } from "svelte/store" export const createViewportStores = context => { - const { cellHeight, visibleColumns, rows, scroll, bounds } = context + const { rowHeight, visibleColumns, rows, scroll, bounds } = context const scrollTop = derived(scroll, $scroll => $scroll.top, 0) const scrollLeft = derived(scroll, $scroll => $scroll.left, 0) @@ -13,16 +13,16 @@ export const createViewportStores = context => { // Split into multiple stores containing primitives to optimise invalidation // as much as possible const scrolledRowCount = derived( - scrollTop, - $scrollTop => { - return Math.floor($scrollTop / cellHeight) + [scrollTop, rowHeight], + ([$scrollTop, $rowHeight]) => { + return Math.floor($scrollTop / $rowHeight) }, 0 ) const visualRowCapacity = derived( - height, - $height => { - return Math.ceil($height / cellHeight) + 1 + [height, rowHeight], + ([$height, $rowHeight]) => { + return Math.ceil($height / $rowHeight) + 1 }, 0 ) diff --git a/packages/frontend-core/src/components/sheet/stores/wheel.js b/packages/frontend-core/src/components/sheet/stores/wheel.js index 45938bbdf3..82dc757fc2 100644 --- a/packages/frontend-core/src/components/sheet/stores/wheel.js +++ b/packages/frontend-core/src/components/sheet/stores/wheel.js @@ -9,7 +9,7 @@ export const createWheelStores = context => { renderedRows, bounds, scroll, - cellHeight, + rowHeight, } = context // Handles a wheel even and updates the scroll offsets @@ -22,6 +22,7 @@ export const createWheelStores = context => { } const debouncedHandleWheel = domDebounce((deltaX, deltaY, clientY) => { const { top, left } = get(scroll) + const $rowHeight = get(rowHeight) // Calculate new scroll top let newScrollTop = top + deltaY @@ -38,8 +39,8 @@ export const createWheelStores = context => { }) // Hover row under cursor - const y = clientY - get(bounds).top + (newScrollTop % cellHeight) - const hoveredRow = get(renderedRows)[Math.floor(y / cellHeight)] + const y = clientY - get(bounds).top + (newScrollTop % $rowHeight) + const hoveredRow = get(renderedRows)[Math.floor(y / $rowHeight)] hoveredRowId.set(hoveredRow?._id) })