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 // Deletion callback when confirmed
const performDeletion = async () => { const performDeletion = async () => {
await rows.actions.deleteRows(rowsToDelete) await rows.actions.deleteRows(rowsToDelete)
// Refresh state
$selectedCellId = null
$selectedRows = {}
} }
</script> </script>

View File

@ -6,6 +6,8 @@
import { createRowsStore } from "./stores/rows" import { createRowsStore } from "./stores/rows"
import { createColumnsStores } from "./stores/columns" import { createColumnsStores } from "./stores/columns"
import { createScrollStores } from "./stores/scroll" import { createScrollStores } from "./stores/scroll"
import { createBoundsStores } from "./stores/bounds"
import { createInterfaceStores } from "./stores/interface"
import DeleteButton from "./DeleteButton.svelte" import DeleteButton from "./DeleteButton.svelte"
import SheetBody from "./SheetBody.svelte" import SheetBody from "./SheetBody.svelte"
import SheetRow from "./SheetRow.svelte" import SheetRow from "./SheetRow.svelte"
@ -38,42 +40,23 @@
allowAddColumns, allowAddColumns,
allowSelectRows, 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 = { let context = {
API: API || createAPIClient(), API: API || createAPIClient(),
rand, rand,
selectedCellId,
selectedRows,
cellHeight, cellHeight,
bounds,
scroll,
hoveredRowId,
config, config,
dispatch, dispatch,
} }
const { rows, schema } = createRowsStore(context) context = { ...context, ...createRowsStore(context) }
context = { ...context, rows, schema } context = { ...context, ...createColumnsStores(context) }
const { columns, stickyColumn } = createColumnsStores(context) context = { ...context, ...createBoundsStores(context) }
context = { ...context, columns, stickyColumn }
context = { ...context, ...createScrollStores(context) } context = { ...context, ...createScrollStores(context) }
const { visibleRows, visibleColumns } = createViewportStores(context) context = { ...context, ...createViewportStores(context) }
context = { ...context, visibleRows, visibleColumns } context = { ...context, ...createReorderStores(context) }
const { reorder } = createReorderStores(context) context = { ...context, ...createInterfaceStores(context) }
context = { ...context, reorder }
// Keep config store up to date // Keep config store up to date
$: config.set({ $: config.set({
@ -94,14 +77,7 @@
<StickyColumn /> <StickyColumn />
<div class="sheet-main"> <div class="sheet-main">
<HeaderRow /> <HeaderRow />
<SheetBody> <SheetBody />
{#each $visibleRows as row}
<SheetRow {row} />
{/each}
{#if allowAddRows}
<NewRow />
{/if}
</SheetBody>
</div> </div>
<DeleteButton /> <DeleteButton />
<ResizeOverlay /> <ResizeOverlay />

View File

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

View File

@ -37,10 +37,16 @@
} }
const selectRow = id => { const selectRow = id => {
selectedRows.update(state => ({ selectedRows.update(state => {
...state, let newState = {
[id]: !state[id], ...state,
})) [id]: !state[id],
}
if (!newState[id]) {
delete newState[id]
}
return newState
})
} }
const addRow = async field => { 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" import { notifications } from "@budibase/bbui"
export const createRowsStore = context => { export const createRowsStore = context => {
const { config, API, scroll } = context const { config, API } = context
const tableId = derived(config, $config => $config.tableId) const tableId = derived(config, $config => $config.tableId)
const filter = derived(config, $config => $config.filter) const filter = derived(config, $config => $config.filter)
@ -64,9 +64,6 @@ export const createRowsStore = context => {
newSchema[primaryDisplay].primaryDisplay = true newSchema[primaryDisplay].primaryDisplay = true
} }
schema.set(newSchema) schema.set(newSchema)
// Reset scroll state for fresh dataset
scroll.set({ left: 0, top: 0 })
} }
// Process new rows // 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 => { export const createScrollStores = context => {
const { scroll, rows, columns, stickyColumn, bounds, cellHeight } = context const { rows, columns, stickyColumn, bounds, cellHeight } = context
const padding = 180 const padding = 180
const scroll = writable({
left: 0,
top: 0,
})
// Memoize store primitives // Memoize store primitives
const scrollTop = derived(scroll, $scroll => $scroll.top) const scrollTop = derived(scroll, $scroll => $scroll.top)
@ -77,6 +81,7 @@ export const createScrollStores = context => {
}) })
return { return {
scroll,
contentHeight, contentHeight,
contentWidth, contentWidth,
maxScrollTop, maxScrollTop,