1
0
Fork 0
mirror of synced 2024-10-06 04:54:52 +13:00

Add copy and paste to spreadsheet and add immediate editing of cells without additional click

This commit is contained in:
Andrew Kingston 2023-04-14 09:19:47 +01:00
parent 6f20c3dff8
commit ddc11ab88c
2 changed files with 83 additions and 28 deletions

View file

@ -49,7 +49,9 @@
blur: () => api?.blur(), blur: () => api?.blur(),
onKeyDown: (...params) => api?.onKeyDown(...params), onKeyDown: (...params) => api?.onKeyDown(...params),
isReadonly: () => readonly, isReadonly: () => readonly,
updateValue: value => { getType: () => column.schema.type,
getValue: () => row[column.name],
setValue: value => {
validation.actions.setError(cellId, null) validation.actions.setError(cellId, null)
updateRow(row._id, column.name, value) updateRow(row._id, column.name, value)
}, },
@ -72,7 +74,7 @@
bind:api bind:api
value={row[column.name]} value={row[column.name]}
schema={column.schema} schema={column.schema}
onChange={cellAPI.updateValue} onChange={cellAPI.setValue}
{focused} {focused}
{readonly} {readonly}
{invertY} {invertY}

View file

@ -11,11 +11,14 @@
focusedCellAPI, focusedCellAPI,
} = getContext("sheet") } = getContext("sheet")
let copiedValue
// Global key listener which intercepts all key events
const handleKeyDown = e => { const handleKeyDown = e => {
// If nothing selected avoid processing further key presses // If nothing selected avoid processing further key presses
if (!$focusedCellId) { if (!$focusedCellId) {
if (e.key === "Tab") { if (e.key === "Tab") {
selectFirstCell() focusFirstCell()
} }
return return
} }
@ -26,7 +29,7 @@
api?.blur?.() api?.blur?.()
} else if (e.key === "Tab") { } else if (e.key === "Tab") {
api?.blur?.() api?.blur?.()
changeSelectedColumn(1) changeFocusedColumn(1)
} }
// Pass the key event to the selected cell and let it decide whether to // Pass the key event to the selected cell and let it decide whether to
@ -40,29 +43,43 @@
e.preventDefault() e.preventDefault()
// Handle the key ourselves // Handle the key ourselves
switch (e.key) { if (e.metaKey || e.ctrlKey) {
case "ArrowLeft": switch (e.key) {
changeSelectedColumn(-1) case "c":
break copy()
case "ArrowRight": break
changeSelectedColumn(1) case "v":
break paste()
case "ArrowUp": break
changeSelectedRow(-1) }
break } else {
case "ArrowDown": switch (e.key) {
changeSelectedRow(1) case "ArrowLeft":
break changeFocusedColumn(-1)
case "Delete": break
deleteSelectedCell() case "ArrowRight":
break changeFocusedColumn(1)
case "Enter": break
focusSelectedCell() case "ArrowUp":
break changeFocusedRow(-1)
break
case "ArrowDown":
changeFocusedRow(1)
break
case "Delete":
deleteSelectedCell()
break
case "Enter":
focusCell()
break
default:
startEnteringValue(e.key, e.which)
}
} }
} }
const selectFirstCell = () => { // Focuses the first cell in the spreadsheet
const focusFirstCell = () => {
const firstRow = $enrichedRows[0] const firstRow = $enrichedRows[0]
if (!firstRow) { if (!firstRow) {
return return
@ -74,7 +91,8 @@
focusedCellId.set(`${firstRow._id}-${firstColumn.name}`) focusedCellId.set(`${firstRow._id}-${firstColumn.name}`)
} }
const changeSelectedColumn = delta => { // Changes the focused cell by moving it left or right to a different column
const changeFocusedColumn = delta => {
if (!$focusedCellId) { if (!$focusedCellId) {
return return
} }
@ -98,7 +116,8 @@
} }
} }
const changeSelectedRow = delta => { // Changes the focused cell by moving it up or down to a new row
const changeFocusedRow = delta => {
if (!$focusedRow) { if (!$focusedRow) {
return return
} }
@ -114,16 +133,50 @@
if ($focusedCellAPI?.isReadonly()) { if ($focusedCellAPI?.isReadonly()) {
return return
} }
$focusedCellAPI.updateValue(null) $focusedCellAPI.setValue(null)
}, 100) }, 100)
const focusSelectedCell = () => { // Focuses the current cell for editing
const focusCell = () => {
if ($focusedCellAPI?.isReadonly()) { if ($focusedCellAPI?.isReadonly()) {
return return
} }
$focusedCellAPI?.focus?.() $focusedCellAPI?.focus?.()
} }
// Copies the value from the current cell
const copy = () => {
copiedValue = $focusedCellAPI?.getValue()
}
// Pastes the copied value
const paste = () => {
if (copiedValue != null) {
$focusedCellAPI?.setValue(copiedValue)
}
}
// Utils to identify a key code
const keyCodeIsNumber = keyCode => keyCode >= 48 && keyCode <= 57
const keyCodeIsLetter = keyCode => keyCode >= 65 && keyCode <= 90
// Focuses the cell and starts entering a new value
const startEnteringValue = (key, keyCode) => {
if ($focusedCellAPI) {
const type = $focusedCellAPI.getType()
if (type === "number" && keyCodeIsNumber(keyCode)) {
$focusedCellAPI.setValue(parseInt(key))
$focusedCellAPI.focus()
} else if (
["string", "barcodeqr", "longform"].includes(type) &&
(keyCodeIsLetter(keyCode) || keyCodeIsNumber(keyCode))
) {
$focusedCellAPI.setValue(key)
$focusedCellAPI.focus()
}
}
}
onMount(() => { onMount(() => {
document.addEventListener("keydown", handleKeyDown) document.addEventListener("keydown", handleKeyDown)
return () => { return () => {