Update new row component to render inline where possible
This commit is contained in:
parent
98430138fe
commit
5cbaf2f58a
|
@ -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 ||
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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" />
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue