($selectedCellId = null)}
- on:mouseenter={() => ($hoveredRowId = null)}
-/>
-
-
diff --git a/packages/client/src/components/app/spreadsheet/index.js b/packages/client/src/components/app/spreadsheet/index.js
deleted file mode 100644
index 223ab462fa..0000000000
--- a/packages/client/src/components/app/spreadsheet/index.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default as spreadsheet } from "./Spreadsheet.svelte"
diff --git a/packages/frontend-core/src/components/index.js b/packages/frontend-core/src/components/index.js
index 7ca21c4ff9..8e5959ef14 100644
--- a/packages/frontend-core/src/components/index.js
+++ b/packages/frontend-core/src/components/index.js
@@ -1,2 +1,3 @@
export { default as SplitPage } from "./SplitPage.svelte"
export { default as TestimonialPage } from "./TestimonialPage.svelte"
+export { default as Sheet } from "./sheet/Sheet.svelte"
diff --git a/packages/client/src/components/app/spreadsheet/stores/resize.js b/packages/frontend-core/src/components/sheet/ResizeOverlay.svelte
similarity index 67%
rename from packages/client/src/components/app/spreadsheet/stores/resize.js
rename to packages/frontend-core/src/components/sheet/ResizeOverlay.svelte
index 8327f0e79d..aca8f59ac1 100644
--- a/packages/client/src/components/app/spreadsheet/stores/resize.js
+++ b/packages/frontend-core/src/components/sheet/ResizeOverlay.svelte
@@ -1,26 +1,16 @@
-import { writable, get } from "svelte/store"
-import { domDebounce } from "../../../../utils/domDebounce.js"
+
+
+{#each $columns as col}
+
startResizing(col.idx, e)}
+ style="--left:{col.left + col.width}px;"
+ >
+
+
+{/each}
+
+
diff --git a/packages/client/src/components/app/spreadsheet/Spreadsheet.svelte b/packages/frontend-core/src/components/sheet/Sheet.svelte
similarity index 52%
rename from packages/client/src/components/app/spreadsheet/Spreadsheet.svelte
rename to packages/frontend-core/src/components/sheet/Sheet.svelte
index ee1d75d0af..4c3c58e5e1 100644
--- a/packages/client/src/components/app/spreadsheet/Spreadsheet.svelte
+++ b/packages/frontend-core/src/components/sheet/Sheet.svelte
@@ -1,27 +1,24 @@
-
-
-
-
-
-
-
-
-
- {#each $columns as field, fieldIdx}
- reorder.actions.startReordering(fieldIdx, e)}
- width={field.width}
- left={field.left}
- >
-
-
- {field.name}
-
-
-
- {/each}
-
-
-
- {#each renderedRows as row, rowIdx (row._id)}
-
- {/each}
-
-
-
+
+
+
+
+
+
+
+
+ {#each $columns as field, fieldIdx}
($hoveredRowId = "new")}
- rowHovered={$hoveredRowId === "new"}
- width="40"
- left="0"
+ header
+ sticky={fieldIdx === 0}
+ reorderSource={$reorder.columnIdx === fieldIdx}
+ reorderTarget={$reorder.swapColumnIdx === fieldIdx}
+ on:mousedown={e => reorder.actions.startReordering(fieldIdx, e)}
+ width={field.width}
+ left={field.left}
>
-
-
- {#each $columns as field, fieldIdx}
- addRow(field)}
- on:mouseenter={() => ($hoveredRowId = "new")}
- width={field.width}
- left={field.left}
+
- {/each}
-
-
+
+ {field.name}
+
+
+ {/each}
+
-
-
-
+
+ {#each renderedRows as row, rowIdx (row._id)}
+
+ {/each}
+
+
+
+ ($hoveredRowId = "new")}
+ rowHovered={$hoveredRowId === "new"}
+ width="40"
+ left="0"
+ >
+
+
+ {#each $columns as field, fieldIdx}
+ addRow(field)}
+ on:mouseenter={() => ($hoveredRowId = "new")}
+ width={field.width}
+ left={field.left}
+ />
+ {/each}
+
+
+
diff --git a/packages/client/src/components/app/spreadsheet/SpreadsheetBody.svelte b/packages/frontend-core/src/components/sheet/SheetBody.svelte
similarity index 94%
rename from packages/client/src/components/app/spreadsheet/SpreadsheetBody.svelte
rename to packages/frontend-core/src/components/sheet/SheetBody.svelte
index b6fd5e94ae..12bd2dff70 100644
--- a/packages/client/src/components/app/spreadsheet/SpreadsheetBody.svelte
+++ b/packages/frontend-core/src/components/sheet/SheetBody.svelte
@@ -1,6 +1,6 @@
+ import { getContext } from "svelte"
+ import { ActionButton, Modal, ModalContent } from "@budibase/bbui"
+
+ const {
+ selectedRows,
+ rows,
+ selectedCellId,
+ hoveredRowId,
+ tableId,
+ spreadsheetAPI,
+ API,
+ } = getContext("spreadsheet")
+
+ let modal
+
+ $: selectedRowCount = Object.values($selectedRows).filter(x => !!x).length
+ $: rowCount = $rows.length
+ $: rowsToDelete = Object.entries($selectedRows)
+ .map(entry => {
+ if (entry[1] === true) {
+ return $rows.find(x => x._id === entry[0])
+ } else {
+ return null
+ }
+ })
+ .filter(x => x != null)
+
+ // Deletion callback when confirmed
+ const performDeletion = async () => {
+ await API.deleteRows({
+ tableId,
+ rows: rowsToDelete,
+ })
+ await spreadsheetAPI.refreshData()
+
+ // Refresh state
+ $selectedCellId = null
+ $hoveredRowId = null
+ $selectedRows = {}
+ }
+
+
+
+
+
+
+ {#if selectedRowCount}
+
+ Delete {selectedRowCount} row{selectedRowCount === 1 ? "" : "s"}
+
+ {:else}
+ {rowCount} row{rowCount === 1 ? "" : "s"}
+ {/if}
+
+
+
+
+
+ Are you sure you want to delete {selectedRowCount}
+ row{selectedRowCount === 1 ? "" : "s"}?
+
+
+
+
diff --git a/packages/client/src/components/app/spreadsheet/SpreadsheetRow.svelte b/packages/frontend-core/src/components/sheet/SheetRow.svelte
similarity index 98%
rename from packages/client/src/components/app/spreadsheet/SpreadsheetRow.svelte
rename to packages/frontend-core/src/components/sheet/SheetRow.svelte
index 595f2d1742..0a174e1548 100644
--- a/packages/client/src/components/app/spreadsheet/SpreadsheetRow.svelte
+++ b/packages/frontend-core/src/components/sheet/SheetRow.svelte
@@ -1,6 +1,6 @@