From 29b95c6b73e4136df5061f1f8f6097f59740be31 Mon Sep 17 00:00:00 2001 From: Eugene Date: Fri, 21 Jul 2023 18:32:38 +0300 Subject: [PATCH] Added keyboard navigation --- index.html | 2 +- src/components/editor.ts | 3 ++ src/components/scroller.ts | 61 +++++++++++++++++++++++++++++++++----- src/components/sheet.ts | 2 -- src/main.ts | 8 ++++- src/scss/_spreadsheet.scss | 5 ++++ 6 files changed, 70 insertions(+), 11 deletions(-) diff --git a/index.html b/index.html index fecfbe5..e65b7cf 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ - Vite + TS + Spreadsheet example
diff --git a/src/components/editor.ts b/src/components/editor.ts index 81f525c..10a08bc 100644 --- a/src/components/editor.ts +++ b/src/components/editor.ts @@ -18,6 +18,9 @@ export class Editor { this.element.classList.add('hide') this.element.blur() window.removeEventListener('click', this.handleClickOutside) + this.element.removeEventListener('keydown', this.handleKeydown) + + this.root.focusTable() } show(position: Position) { diff --git a/src/components/scroller.ts b/src/components/scroller.ts index 38af8c0..4c8e7ed 100644 --- a/src/components/scroller.ts +++ b/src/components/scroller.ts @@ -12,7 +12,7 @@ export class Scroller { private verticalScroller: HTMLDivElement private horizontalScroller: HTMLDivElement private root: Spreadsheet - + private isSelecting = false constructor(root: Spreadsheet) { @@ -24,6 +24,7 @@ export class Scroller { this.element.style.height = this.root.config.view.height + 'px' this.element.style.width = this.root.config.view.width + 'px' + this.element.tabIndex = -1 this.updateScrollerSize() //* Init size set @@ -31,10 +32,10 @@ export class Scroller { this.element.addEventListener('mousedown', this.handleClick) this.element.addEventListener('mousemove', event => { - if(!this.isSelecting) return; - const {offsetX, offsetY} = event + if (!this.isSelecting) return; + const { offsetX, offsetY } = event const lastSelectedCell = this.root.getCellByCoords(offsetX, offsetY) - if(this.root.selection.selectedRange) { + if (this.root.selection.selectedRange) { this.root.selection.selectedRange.to = lastSelectedCell } this.root.renderSheet() @@ -49,18 +50,64 @@ export class Scroller { this.root.showEditor(position) }) + this.element.addEventListener('keydown', this.handleKeydown) + } + + private handleKeydown = (event: KeyboardEvent) => { + event.preventDefault() + console.log(event.key) + //* Navigation + if (['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(event.key)) { + this.root.selection.selectedRange = null + switch (event.key) { + case 'ArrowLeft': { + if (this.root.selection.selectedCell && this.root.selection.selectedCell.column > 0) { + console.log('tick') + this.root.selection.selectedCell.column -= 1 + this.root.renderSheet() + } + break; + } + case 'ArrowRight': { + if (this.root.selection.selectedCell && this.root.selection.selectedCell.column < this.root.config.columns.length - 1) { + this.root.selection.selectedCell.column += 1 + this.root.renderSheet() + } + break; + } + case 'ArrowUp': { + if (this.root.selection.selectedCell && this.root.selection.selectedCell.row > 0) { + this.root.selection.selectedCell.row -= 1 + this.root.renderSheet() + } + break; + } + case 'ArrowDown': { + if (this.root.selection.selectedCell && this.root.selection.selectedCell.row < this.root.config.rows.length - 1) { + this.root.selection.selectedCell.row += 1 + this.root.renderSheet() + } + break; + } + } + } + + if(event.key === 'F2') { + if(!this.root.selection.selectedCell) return; + this.root.showEditor(this.root.selection.selectedCell) + } } private handleClick = (event: MouseEvent) => { - if(event.button !== 0) return; // Left mouse button - const {offsetX, offsetY} = event + if (event.button !== 0) return; // Left mouse button + const { offsetX, offsetY } = event const clickedCell = this.root.getCellByCoords(offsetX, offsetY) this.isSelecting = true this.root.selection.selectedRange = { from: clickedCell, to: clickedCell } - this.root.selection.selectedCell = clickedCell + this.root.selection.selectedCell = clickedCell this.root.renderSheet() } diff --git a/src/components/sheet.ts b/src/components/sheet.ts index 89c5bc8..c620505 100644 --- a/src/components/sheet.ts +++ b/src/components/sheet.ts @@ -59,13 +59,11 @@ export class Sheet { const firstColIdx = this.root.viewport.firstCol for(let row = firstRowIdx; row <= lastRowIdx; row++) { - for(let col = firstColIdx; col <= lastColIdx; col++ ) { if(!this.root.config.columns[col] || !this.root.config.rows[row]) break; //* Prevent read undefined this.renderCell({column: col, row}) } - } } diff --git a/src/main.ts b/src/main.ts index a91a6f2..f8e047f 100644 --- a/src/main.ts +++ b/src/main.ts @@ -67,11 +67,13 @@ export class Spreadsheet { } private buildComponent(): void { + const content = document.createElement('div') //* Abstract - content.classList.add('content') content.appendChild(this.header.element) content.appendChild(this.sheet.element) + content.classList.add('content') + this.table.element.appendChild(this.toolbar.element) this.table.element.appendChild(content) this.table.element.appendChild(this.scroller.element) @@ -97,6 +99,10 @@ export class Spreadsheet { return this.config.view } + focusTable() { + this.scroller.element.focus() + } + getCellByCoords(x: number, y: number) { return this.sheet.getCellByCoords(x, y) } diff --git a/src/scss/_spreadsheet.scss b/src/scss/_spreadsheet.scss index 51319ba..84b490c 100644 --- a/src/scss/_spreadsheet.scss +++ b/src/scss/_spreadsheet.scss @@ -10,6 +10,8 @@ position: relative; isolation: isolate; border: 2px solid black; + + } .sheet{ @@ -21,6 +23,9 @@ overflow: scroll; box-sizing: border-box; transform: translateZ(0); + &:focus { + outline: none; + } } .editor {