Refactor stores and make state more modular

This commit is contained in:
Andrew Kingston 2023-03-03 09:02:19 +00:00
parent b82e7582db
commit 37393c4e2a
8 changed files with 92 additions and 51 deletions

View File

@ -20,10 +20,6 @@
// Deletion callback when confirmed
const performDeletion = async () => {
await rows.actions.deleteRows(rowsToDelete)
// Refresh state
$selectedCellId = null
$selectedRows = {}
}
</script>

View File

@ -6,6 +6,8 @@
import { createRowsStore } from "./stores/rows"
import { createColumnsStores } from "./stores/columns"
import { createScrollStores } from "./stores/scroll"
import { createBoundsStores } from "./stores/bounds"
import { createInterfaceStores } from "./stores/interface"
import DeleteButton from "./DeleteButton.svelte"
import SheetBody from "./SheetBody.svelte"
import SheetRow from "./SheetRow.svelte"
@ -38,42 +40,23 @@
allowAddColumns,
allowSelectRows,
})
const selectedCellId = writable()
const selectedRows = writable({})
const hoveredRowId = writable()
const scroll = writable({
left: 0,
top: 0,
})
const bounds = writable({
left: 0,
top: 0,
width: 0,
height: 0,
})
// Build up spreadsheet context and additional stores
// Build up spreadsheet context
// Stores are listed in order of dependency on each other
let context = {
API: API || createAPIClient(),
rand,
selectedCellId,
selectedRows,
cellHeight,
bounds,
scroll,
hoveredRowId,
config,
dispatch,
}
const { rows, schema } = createRowsStore(context)
context = { ...context, rows, schema }
const { columns, stickyColumn } = createColumnsStores(context)
context = { ...context, columns, stickyColumn }
context = { ...context, ...createRowsStore(context) }
context = { ...context, ...createColumnsStores(context) }
context = { ...context, ...createBoundsStores(context) }
context = { ...context, ...createScrollStores(context) }
const { visibleRows, visibleColumns } = createViewportStores(context)
context = { ...context, visibleRows, visibleColumns }
const { reorder } = createReorderStores(context)
context = { ...context, reorder }
context = { ...context, ...createViewportStores(context) }
context = { ...context, ...createReorderStores(context) }
context = { ...context, ...createInterfaceStores(context) }
// Keep config store up to date
$: config.set({
@ -94,14 +77,7 @@
<StickyColumn />
<div class="sheet-main">
<HeaderRow />
<SheetBody>
{#each $visibleRows as row}
<SheetRow {row} />
{/each}
{#if allowAddRows}
<NewRow />
{/if}
</SheetBody>
<SheetBody />
</div>
<DeleteButton />
<ResizeOverlay />

View File

@ -1,8 +1,11 @@
<script>
import { getContext, onMount } from "svelte"
import SheetScrollWrapper from "./SheetScrollWrapper.svelte"
import NewRow from "./NewRow.svelte"
import SheetRow from "./SheetRow.svelte"
const { selectedCellId, bounds } = getContext("spreadsheet")
const { selectedCellId, bounds, visibleRows, config } =
getContext("spreadsheet")
let ref
@ -24,7 +27,12 @@
on:click|self={() => ($selectedCellId = null)}
>
<SheetScrollWrapper>
<slot />
{#each $visibleRows as row}
<SheetRow {row} />
{/each}
{#if $config.allowAddRows}
<NewRow />
{/if}
</SheetScrollWrapper>
</div>

View File

@ -37,10 +37,16 @@
}
const selectRow = id => {
selectedRows.update(state => ({
selectedRows.update(state => {
let newState = {
...state,
[id]: !state[id],
}))
}
if (!newState[id]) {
delete newState[id]
}
return newState
})
}
const addRow = async field => {

View File

@ -0,0 +1,11 @@
import { writable } from "svelte/store"
export const createBoundsStores = () => {
const bounds = writable({
left: 0,
top: 0,
width: 0,
height: 0,
})
return { bounds }
}

View File

@ -0,0 +1,42 @@
import { writable, get } from "svelte/store"
export const createInterfaceStores = context => {
const { rows } = context
const selectedCellId = writable(null)
const selectedRows = writable({})
const hoveredRowId = writable(null)
// Ensure we clear invalid rows from state if they disappear
rows.subscribe($rows => {
const $selectedCellId = get(selectedCellId)
const $selectedRows = get(selectedRows)
const $hoveredRowId = get(hoveredRowId)
// Check selected cell
const selectedRowId = $selectedCellId?.split("-")[0]
if (selectedRowId && !$rows.find(row => row._id === selectedRowId)) {
selectedCellId.set(null)
}
// Check hovered row
if ($hoveredRowId && !$rows.find(row => row._id === $hoveredRowId)) {
hoveredRowId.set(null)
}
// Check selected rows
let newSelectedRows = { ...$selectedRows }
let selectedRowsNeedsUpdate = false
const selectedIds = Object.keys($selectedRows)
for (let i = 0; i < selectedIds.length; i++) {
if (!$rows.find(row => row._id === selectedIds[i])) {
delete newSelectedRows[selectedIds[i]]
selectedRowsNeedsUpdate = true
}
}
if (selectedRowsNeedsUpdate) {
selectedRows.set(newSelectedRows)
}
})
return { selectedCellId, selectedRows, hoveredRowId }
}

View File

@ -4,7 +4,7 @@ import { fetchData } from "../../../fetch/fetchData"
import { notifications } from "@budibase/bbui"
export const createRowsStore = context => {
const { config, API, scroll } = context
const { config, API } = context
const tableId = derived(config, $config => $config.tableId)
const filter = derived(config, $config => $config.filter)
@ -64,9 +64,6 @@ export const createRowsStore = context => {
newSchema[primaryDisplay].primaryDisplay = true
}
schema.set(newSchema)
// Reset scroll state for fresh dataset
scroll.set({ left: 0, top: 0 })
}
// Process new rows

View File

@ -1,8 +1,12 @@
import { derived, get } from "svelte/store"
import { derived, get, writable } from "svelte/store"
export const createScrollStores = context => {
const { scroll, rows, columns, stickyColumn, bounds, cellHeight } = context
const { rows, columns, stickyColumn, bounds, cellHeight } = context
const padding = 180
const scroll = writable({
left: 0,
top: 0,
})
// Memoize store primitives
const scrollTop = derived(scroll, $scroll => $scroll.top)
@ -77,6 +81,7 @@ export const createScrollStores = context => {
})
return {
scroll,
contentHeight,
contentWidth,
maxScrollTop,