Fix table loading states and remove virtual table rendering

This commit is contained in:
Andrew Kingston 2022-02-18 14:12:29 +00:00
parent 268d06a120
commit 5e98b01d4e
3 changed files with 62 additions and 98 deletions

View File

@ -4,6 +4,7 @@
import CellRenderer from "./CellRenderer.svelte" import CellRenderer from "./CellRenderer.svelte"
import SelectEditRenderer from "./SelectEditRenderer.svelte" import SelectEditRenderer from "./SelectEditRenderer.svelte"
import { cloneDeep, deepGet } from "../helpers" import { cloneDeep, deepGet } from "../helpers"
import ProgressCircle from "../ProgressCircle/ProgressCircle.svelte"
/** /**
* The expected schema is our normal couch schemas for our tables. * The expected schema is our normal couch schemas for our tables.
@ -14,6 +15,7 @@
* sortable: Set to false to disable sorting data by a certain column * sortable: Set to false to disable sorting data by a certain column
* editable: Set to false to disable editing a certain column if the * editable: Set to false to disable editing a certain column if the
* allowEditColumns prop is true * allowEditColumns prop is true
* width: the width of the column
*/ */
export let data = [] export let data = []
export let schema = {} export let schema = {}
@ -31,14 +33,11 @@
export let autoSortColumns = true export let autoSortColumns = true
export let compact = false export let compact = false
rowCount = 5
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
// Config // Config
$: rowHeight = compact ? 46 : 55 $: rowHeight = compact ? 46 : 55
const headerHeight = 36 const headerHeight = 36
const rowPreload = 5
// Sorting state // Sorting state
let sortColumn let sortColumn
@ -57,26 +56,6 @@
$: gridStyle = getGridStyle(fields, schema, showEditColumn) $: gridStyle = getGridStyle(fields, schema, showEditColumn)
$: showEditColumn = allowEditRows || allowSelectRows $: showEditColumn = allowEditRows || allowSelectRows
// Scrolling state
let timeout
let nextScrollTop = 0
let scrollTop = 0
$: firstVisibleRow = calculateFirstVisibleRow(scrollTop)
$: lastVisibleRow = calculateLastVisibleRow(
firstVisibleRow,
visibleRowCount,
rows.length
)
// Reset state when data changes
$: rows.length, reset()
const reset = () => {
nextScrollTop = 0
scrollTop = 0
clearTimeout(timeout)
timeout = null
}
const fixSchema = schema => { const fixSchema = schema => {
let fixedSchema = {} let fixedSchema = {}
Object.entries(schema || {}).forEach(([fieldName, fieldSchema]) => { Object.entries(schema || {}).forEach(([fieldName, fieldSchema]) => {
@ -193,28 +172,6 @@
.map(column => column.name) .map(column => column.name)
} }
const onScroll = event => {
nextScrollTop = event.target.scrollTop
if (timeout) {
return
}
timeout = setTimeout(() => {
scrollTop = nextScrollTop
timeout = null
}, 50)
}
const calculateFirstVisibleRow = scrollTop => {
return Math.max(Math.floor(scrollTop / (rowHeight + 1)) - rowPreload, 0)
}
const calculateLastVisibleRow = (firstRow, visibleRowCount, allRowCount) => {
if (visibleRowCount === 0) {
return -1
}
return Math.min(firstRow + visibleRowCount + 2 * rowPreload, allRowCount)
}
const editColumn = (e, field) => { const editColumn = (e, field) => {
e.stopPropagation() e.stopPropagation()
dispatch("editcolumn", field) dispatch("editcolumn", field)
@ -245,16 +202,16 @@
style={`--row-height: ${rowHeight}px; --header-height: ${headerHeight}px;`} style={`--row-height: ${rowHeight}px; --header-height: ${headerHeight}px;`}
> >
{#if !loaded} {#if !loaded}
<div class="loading" style={contentStyle} /> <div class="loading" style={contentStyle}>
<ProgressCircle />
</div>
{:else} {:else}
<div <div class="spectrum-Table" style={`${contentStyle}${gridStyle}`}>
on:scroll={onScroll}
class="spectrum-Table"
style={`${contentStyle}${gridStyle}`}
>
{#if fields.length} {#if fields.length}
{#if showEditColumn} {#if showEditColumn}
<div class="spectrum-Table-headCell spectrum-Table-headCell--divider"> <div
class="spectrum-Table-headCell spectrum-Table-headCell--divider spectrum-Table-headCell--edit"
>
{editColumnTitle || ""} {editColumnTitle || ""}
</div> </div>
{/if} {/if}
@ -307,38 +264,36 @@
on:click={() => dispatch("click", row)} on:click={() => dispatch("click", row)}
on:click={() => toggleSelectRow(row)} on:click={() => toggleSelectRow(row)}
> >
{#if idx >= firstVisibleRow && idx <= lastVisibleRow} {#if showEditColumn}
{#if showEditColumn} <div
<div class="spectrum-Table-cell spectrum-Table-cell--divider"> class="spectrum-Table-cell spectrum-Table-cell--divider spectrum-Table-cell--edit"
<SelectEditRenderer >
data={row} <SelectEditRenderer
selected={selectedRows.includes(row)} data={row}
onToggleSelection={() => toggleSelectRow(row)} selected={selectedRows.includes(row)}
onEdit={e => editRow(e, row)} onToggleSelection={() => toggleSelectRow(row)}
{allowSelectRows} onEdit={e => editRow(e, row)}
{allowEditRows} {allowSelectRows}
/> {allowEditRows}
</div> />
{/if} </div>
{#each fields as field}
<div
class="spectrum-Table-cell"
class:spectrum-Table-cell--divider={!!schema[field].divider}
>
<CellRenderer
{customRenderers}
{row}
schema={schema[field]}
value={deepGet(row, field)}
on:clickrelationship
>
<slot />
</CellRenderer>
</div>
{/each}
{:else}
<div class="spectrum-Table-cell spectrum-Table-cell--empty" />
{/if} {/if}
{#each fields as field}
<div
class="spectrum-Table-cell"
class:spectrum-Table-cell--divider={!!schema[field].divider}
>
<CellRenderer
{customRenderers}
{row}
schema={schema[field]}
value={deepGet(row, field)}
on:clickrelationship
>
<slot />
</CellRenderer>
</div>
{/each}
</div> </div>
{/each} {/each}
{:else} {:else}
@ -361,13 +316,14 @@
position: relative; position: relative;
z-index: 0; z-index: 0;
overflow: auto; overflow: auto;
background-color: var(--table-bg);
--table-bg: var(--spectrum-global-color-gray-50); --table-bg: var(--spectrum-global-color-gray-50);
--table-border: 1px solid var(--spectrum-alias-border-color-mid); --table-border: 1px solid var(--spectrum-alias-border-color-mid);
--cell-padding: 20px; --cell-padding: 20px;
--hover-bg: var(--spectrum-global-color-gray-100);
} }
.wrapper--quiet { .wrapper--quiet {
--table-bg: var(--spectrum-alias-background-color-transparent); --table-bg: var(--spectrum-alias-background-color-transparent);
--hover-bg: var(--spectrum-global-color-gray-200);
} }
.wrapper--compact { .wrapper--compact {
/*--spectrum-table-header-padding-x: 5px;*/ /*--spectrum-table-header-padding-x: 5px;*/
@ -375,6 +331,13 @@
--cell-padding: 12px; --cell-padding: 12px;
} }
/* Loading */
.loading {
display: grid;
place-items: center;
min-height: 100px;
}
/* Table */ /* Table */
.spectrum-Table { .spectrum-Table {
width: 100%; width: 100%;
@ -383,15 +346,6 @@
} }
/* Header */ /* Header */
.spectrum-Table-head {
display: flex;
position: sticky;
top: 0;
width: fit-content;
border-bottom: var(--table-border);
border-right: 2px solid transparent;
min-width: calc(100% - 2px);
}
.spectrum-Table-headCell { .spectrum-Table-headCell {
vertical-align: middle; vertical-align: middle;
height: var(--header-height); height: var(--header-height);
@ -408,6 +362,11 @@
.spectrum-Table-headCell--divider { .spectrum-Table-headCell--divider {
padding-right: var(--cell-padding); padding-right: var(--cell-padding);
} }
.spectrum-Table-headCell--edit {
position: sticky;
left: 0;
z-index: 3;
}
.spectrum-Table-headCell-content { .spectrum-Table-headCell-content {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
@ -447,7 +406,7 @@
display: contents; display: contents;
} }
.spectrum-Table-row:hover .spectrum-Table-cell { .spectrum-Table-row:hover .spectrum-Table-cell {
background-color: var(--spectrum-alias-highlight-hover); background-color: var(--hover-bg);
} }
.wrapper--quiet .spectrum-Table-row { .wrapper--quiet .spectrum-Table-row {
border-left: none; border-left: none;
@ -482,12 +441,16 @@
border-bottom: 1px solid var(--spectrum-alias-border-color-mid); border-bottom: 1px solid var(--spectrum-alias-border-color-mid);
padding-left: var(--cell-padding); padding-left: var(--cell-padding);
padding-right: 0; padding-right: 0;
background-color: var(--table-bg);
z-index: 1;
} }
.spectrum-Table-cell--divider { .spectrum-Table-cell--divider {
padding-right: var(--cell-padding); padding-right: var(--cell-padding);
} }
.spectrum-Table-cell--empty { .spectrum-Table-cell--edit {
grid-column: 1 / -1; position: sticky;
left: 0;
z-index: 2;
} }
/* Placeholder */ /* Placeholder */
@ -499,6 +462,7 @@
border: var(--table-border); border: var(--table-border);
border-top: none; border-top: none;
grid-column: 1 / -1; grid-column: 1 / -1;
background-color: var(--table-bg);
} }
.placeholder--no-fields { .placeholder--no-fields {
border-top: var(--table-border); border-top: var(--table-border);

View File

@ -98,7 +98,7 @@
tableId={id} tableId={id}
data={$fetch.rows} data={$fetch.rows}
bind:hideAutocolumns bind:hideAutocolumns
loading={$fetch.loading} loading={!$fetch.loaded}
on:sort={onSort} on:sort={onSort}
allowEditing allowEditing
disableSorting disableSorting

View File

@ -136,7 +136,7 @@
</div> </div>
</div> </div>
{#key tableId} {#key tableId}
<div class="table-wrapper" in:fade={{ delay: 200, duration: 100 }}> <div class="table-wrapper">
<Table <Table
{data} {data}
{schema} {schema}