Update new row component to render inline where possible

This commit is contained in:
Andrew Kingston 2023-04-24 12:50:35 +01:00
parent 98430138fe
commit 5cbaf2f58a
7 changed files with 74 additions and 57 deletions

View File

@ -27,12 +27,6 @@
// Get the error for this cell if the row is focused // Get the error for this cell if the row is focused
$: error = getErrorStore(rowFocused, cellId) $: error = getErrorStore(rowFocused, cellId)
$: {
if ($error) {
console.log(cellId, $error)
}
}
// Determine if the cell is editable // Determine if the cell is editable
$: readonly = $: readonly =
column.schema.autocolumn || column.schema.autocolumn ||

View File

@ -45,7 +45,7 @@
style="width:{renderColumnsWidth}px" style="width:{renderColumnsWidth}px"
on:mouseenter={() => ($hoveredRowId = BlankRowID)} on:mouseenter={() => ($hoveredRowId = BlankRowID)}
on:mouseleave={() => ($hoveredRowId = null)} on:mouseleave={() => ($hoveredRowId = null)}
on:click={() => dispatch("add-row-inline", true)} on:click={() => dispatch("add-row-inline")}
/> />
{/if} {/if}
</GridScrollWrapper> </GridScrollWrapper>

View File

@ -1,5 +1,4 @@
<script> <script>
import GridCell from "../cells/GridCell.svelte"
import { getContext, onDestroy, onMount, tick } from "svelte" import { getContext, onDestroy, onMount, tick } from "svelte"
import { Icon, Button } from "@budibase/bbui" import { Icon, Button } from "@budibase/bbui"
import GridScrollWrapper from "./GridScrollWrapper.svelte" import GridScrollWrapper from "./GridScrollWrapper.svelte"
@ -14,18 +13,23 @@
focusedCellId, focusedCellId,
stickyColumn, stickyColumn,
scroll, scroll,
config,
dispatch, dispatch,
rows, rows,
focusedCellAPI, focusedCellAPI,
tableId, tableId,
subscribe, subscribe,
renderedRows,
renderedColumns, renderedColumns,
rowHeight,
hasNextPage,
maxScrollTop,
} = getContext("grid") } = getContext("grid")
let isAdding = false let isAdding = false
let newRow = {} let newRow = {}
let offset = 0
$: minimumDesiredRenderHeight = $rowHeight + 96
$: firstColumn = $stickyColumn || $renderedColumns[0] $: firstColumn = $stickyColumn || $renderedColumns[0]
$: width = GutterWidth + ($stickyColumn?.width || 0) $: width = GutterWidth + ($stickyColumn?.width || 0)
$: $tableId, (isAdding = false) $: $tableId, (isAdding = false)
@ -36,13 +40,10 @@
await tick() await tick()
// Create row // Create row
const savedRow = await rows.actions.addRow(newRow, 0) const newRowIndex = offset ? undefined : 0
const savedRow = await rows.actions.addRow(newRow, newRowIndex)
if (savedRow) { if (savedRow) {
// Reset state // Reset state
scroll.update(state => ({
...state,
top: 0,
}))
clear() clear()
// Select the first cell if possible // Select the first cell if possible
@ -63,6 +64,24 @@
if (isAdding) { if (isAdding) {
return return
} }
// If we have a next page of data then we aren't truly at the bottom, so we
// render the add row component at the top
if ($hasNextPage) {
offset = 0
}
// If we don't have a next page then we're at the bottom and can scroll to
// the max available offset
else {
scroll.update(state => ({
...state,
top: $maxScrollTop,
}))
offset =
$renderedRows.length * $rowHeight - ($maxScrollTop % $rowHeight) - 1
}
document.addEventListener("keydown", handleKeyPress) document.addEventListener("keydown", handleKeyPress)
newRow = {} newRow = {}
isAdding = true isAdding = true
@ -105,7 +124,11 @@
<!-- Only show new row functionality if we have any columns --> <!-- Only show new row functionality if we have any columns -->
{#if isAdding} {#if isAdding}
<div class="container"> <div
class="container"
class:floating={offset > 0}
style="--offset:{offset}px"
>
<div <div
class="underlay sticky" class="underlay sticky"
style="width:{width}px;" style="width:{width}px;"
@ -134,25 +157,27 @@
/> />
{/if} {/if}
</div> </div>
<GridScrollWrapper scrollHorizontally wheelInteractive> <div class="normal-columns">
<div class="row" transition:fade={{ duration: 130 }}> <GridScrollWrapper scrollHorizontally wheelInteractive>
{#each $renderedColumns as column} <div class="row" transition:fade={{ duration: 130 }}>
{@const cellId = `new-${column.name}`} {#each $renderedColumns as column}
{#key cellId} {@const cellId = `new-${column.name}`}
<DataCell {#key cellId}
{cellId} <DataCell
{column} {cellId}
{updateValue} {column}
rowFocused {updateValue}
row={newRow} rowFocused
focused={$focusedCellId === cellId} row={newRow}
width={column.width} focused={$focusedCellId === cellId}
rowIdx={0} width={column.width}
/> rowIdx={0}
{/key} />
{/each} {/key}
</div> {/each}
</GridScrollWrapper> </div>
</GridScrollWrapper>
</div>
<div class="buttons" transition:fade={{ duration: 130 }}> <div class="buttons" transition:fade={{ duration: 130 }}>
<Button size="M" cta on:click={addRow}>Save</Button> <Button size="M" cta on:click={addRow}>Save</Button>
<Button size="M" secondary newStyles on:click={clear}>Cancel</Button> <Button size="M" secondary newStyles on:click={clear}>Cancel</Button>
@ -174,13 +199,17 @@
.container :global(.cell) { .container :global(.cell) {
--cell-background: var(--spectrum-global-color-gray-75) !important; --cell-background: var(--spectrum-global-color-gray-75) !important;
} }
.container.floating :global(.cell) {
height: calc(var(--row-height) + 1px);
border-top: var(--cell-border);
}
/* Underlay sits behind everything */ /* Underlay sits behind everything */
.underlay { .underlay {
position: absolute; position: absolute;
content: ""; content: "";
left: 0; left: 0;
top: var(--row-height); top: 0;
height: 100%; height: 100%;
width: 100%; width: 100%;
background: var(--cell-background); background: var(--cell-background);
@ -198,8 +227,8 @@
pointer-events: all; pointer-events: all;
z-index: 3; z-index: 3;
position: absolute; position: absolute;
top: calc(var(--row-height) + 24px); top: calc(var(--row-height) + var(--offset) + 24px);
left: 32px; left: var(--gutter-width);
} }
/* Sticky column styles */ /* Sticky column styles */
@ -212,20 +241,9 @@
.sticky-column :global(.cell:not(:last-child)) { .sticky-column :global(.cell:not(:last-child)) {
border-right: none; border-right: none;
} }
.gutter { .sticky-column,
flex: 1 1 auto; .normal-columns {
display: grid; margin-top: var(--offset);
align-items: center;
padding: var(--cell-padding);
grid-template-columns: 1fr auto;
gap: var(--cell-spacing);
}
.number {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
color: var(--spectrum-global-color-gray-500);
} }
/* Normal column styles */ /* Normal column styles */

View File

@ -91,7 +91,7 @@
class="row new" class="row new"
on:mouseenter={() => ($hoveredRowId = BlankRowID)} on:mouseenter={() => ($hoveredRowId = BlankRowID)}
on:mouseleave={() => ($hoveredRowId = null)} on:mouseleave={() => ($hoveredRowId = null)}
on:click={() => dispatch("add-row-inline", true)} on:click={() => dispatch("add-row-inline")}
> >
<GutterCell disableExpand rowHovered={$hoveredRowId === BlankRowID}> <GutterCell disableExpand rowHovered={$hoveredRowId === BlankRowID}>
<Icon name="Add" /> <Icon name="Add" />

View File

@ -1,4 +1,4 @@
export const Padding = 276 export const Padding = 128
export const MaxCellRenderHeight = 252 export const MaxCellRenderHeight = 252
export const MaxCellRenderWidthOverflow = 200 export const MaxCellRenderWidthOverflow = 200
export const ScrollBarSize = 8 export const ScrollBarSize = 8
@ -11,3 +11,4 @@ export const LargeRowHeight = 92
export const DefaultRowHeight = SmallRowHeight export const DefaultRowHeight = SmallRowHeight
export const NewRowID = "new" export const NewRowID = "new"
export const BlankRowID = "blank" export const BlankRowID = "blank"
export const RowPageSize = 100

View File

@ -1,7 +1,7 @@
import { writable, derived, get } from "svelte/store" import { writable, derived, get } from "svelte/store"
import { fetchData } from "../../../fetch/fetchData" import { fetchData } from "../../../fetch/fetchData"
import { notifications } from "@budibase/bbui" import { notifications } from "@budibase/bbui"
import { NewRowID } from "../lib/constants" import { NewRowID, RowPageSize } from "../lib/constants"
const initialSortState = { const initialSortState = {
column: null, column: null,
@ -17,6 +17,7 @@ export const createStores = () => {
const sort = writable(initialSortState) const sort = writable(initialSortState)
const rowChangeCache = writable({}) const rowChangeCache = writable({})
const inProgressChanges = writable({}) const inProgressChanges = writable({})
const hasNextPage = writable(false)
// Generate a lookup map to quick find a row by ID // Generate a lookup map to quick find a row by ID
const rowLookupMap = derived( const rowLookupMap = derived(
@ -51,6 +52,7 @@ export const createStores = () => {
sort, sort,
rowChangeCache, rowChangeCache,
inProgressChanges, inProgressChanges,
hasNextPage,
} }
} }
@ -71,6 +73,7 @@ export const deriveStores = context => {
rowChangeCache, rowChangeCache,
inProgressChanges, inProgressChanges,
previousFocusedRowId, previousFocusedRowId,
hasNextPage,
} = context } = context
const instanceLoaded = writable(false) const instanceLoaded = writable(false)
const fetch = writable(null) const fetch = writable(null)
@ -115,7 +118,7 @@ export const deriveStores = context => {
filter: [], filter: [],
sortColumn: initialSortState.column, sortColumn: initialSortState.column,
sortOrder: initialSortState.order, sortOrder: initialSortState.order,
limit: 100, limit: RowPageSize,
paginate: true, paginate: true,
}, },
}) })
@ -123,6 +126,7 @@ export const deriveStores = context => {
// Subscribe to changes of this fetch model // Subscribe to changes of this fetch model
unsubscribe = newFetch.subscribe($fetch => { unsubscribe = newFetch.subscribe($fetch => {
if ($fetch.loaded && !$fetch.loading) { if ($fetch.loaded && !$fetch.loading) {
hasNextPage.set($fetch.hasNextPage)
const $instanceLoaded = get(instanceLoaded) const $instanceLoaded = get(instanceLoaded)
const resetRows = $fetch.resetKey !== lastResetKey const resetRows = $fetch.resetKey !== lastResetKey
lastResetKey = $fetch.resetKey lastResetKey = $fetch.resetKey

View File

@ -29,7 +29,7 @@ export const deriveStores = context => {
// Derive vertical limits // Derive vertical limits
const contentHeight = derived( const contentHeight = derived(
[rows, rowHeight], [rows, rowHeight],
([$rows, $rowHeight]) => $rows.length * $rowHeight + Padding, ([$rows, $rowHeight]) => ($rows.length + 1) * $rowHeight + Padding,
0 0
) )
const maxScrollTop = derived( const maxScrollTop = derived(
@ -138,7 +138,7 @@ export const initialise = context => {
const $scroll = get(scroll) const $scroll = get(scroll)
const $bounds = get(bounds) const $bounds = get(bounds)
const $rowHeight = get(rowHeight) const $rowHeight = get(rowHeight)
const verticalOffset = DefaultRowHeight * 1.5 const verticalOffset = 60
// Ensure vertical position is viewable // Ensure vertical position is viewable
if ($focusedRow) { if ($focusedRow) {