diff --git a/package.json b/package.json index aca60f0..3e13f06 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "modern_spreadsheet", "private": false, - "version": "0.0.21", + "version": "0.0.23", "exports": { ".": { "import": "./dist/main.js", diff --git a/src/components/editor.ts b/src/components/editor.ts index 68a4d6f..e0a5bbf 100644 --- a/src/components/editor.ts +++ b/src/components/editor.ts @@ -1,4 +1,4 @@ -import Spreadsheet from "../main"; +import Spreadsheet, { CSS_PREFIX } from "../main"; import { Position } from "../modules/cell"; import { RenderBox } from "../modules/renderBox"; @@ -8,7 +8,7 @@ export class Editor { constructor(root: Spreadsheet) { this.root = root const element = document.createElement('input') - element.classList.add('editor') + element.classList.add(CSS_PREFIX + 'editor') this.element = element this.hide() } @@ -19,11 +19,11 @@ export class Editor { this.element.blur() window.removeEventListener('click', this.handleClickOutside) this.element.removeEventListener('keydown', this.handleKeydown) - + this.root.focusTable() } - show(position: Position) { + show(position: Position, initialString?: string) { const { height, width, x, y } = new RenderBox(this.root.config, position); const cell = this.root.getCell(position) this.element.classList.remove('hide') @@ -36,15 +36,17 @@ export class Editor { window.addEventListener('click', this.handleClickOutside) this.element.addEventListener('keydown', this.handleKeydown) - this.element.value = cell.value + this.element.value = initialString ? initialString : cell.value this.element.focus() - this.element.select() + if (!initialString) this.element.select() + + } - handleKeydown = (event: KeyboardEvent) => { - const {key} = event - - switch(key) { + handleKeydown = (event: KeyboardEvent) => { + const { key } = event + + switch (key) { case 'Escape': { this.hide(); break; diff --git a/src/components/scroller.ts b/src/components/scroller.ts index fb692f0..60aa2ab 100644 --- a/src/components/scroller.ts +++ b/src/components/scroller.ts @@ -1,4 +1,4 @@ -import Spreadsheet from "../main" +import Spreadsheet, { CSS_PREFIX } from "../main" export interface ViewportRect { top: number @@ -107,11 +107,15 @@ export class Scroller { } } } + const keysRegex = /^([a-z]|[а-я])$/ if (!event.metaKey && !event.ctrlKey) { //* Prevent handle shortcutrs - if (event.key === 'F2' || /^([a-z]|[а-я])$/.test(event.key.toLowerCase())) { //* English and Russian keyboard. Or F2 button + const isPressedLetterKey = keysRegex.test(event.key.toLowerCase()) + + if (event.key === 'F2' || isPressedLetterKey) { //* English and Russian keyboard. Or F2 button event.preventDefault() if (!this.root.selection.selectedCell) return; - this.root.showEditor(this.root.selection.selectedCell) + + this.root.showEditor(this.root.selection.selectedCell, isPressedLetterKey ? event.key : undefined) } } @@ -177,7 +181,7 @@ export class Scroller { this.verticalScroller = verticalScroller this.horizontalScroller = horizontalScroller scroller.appendChild(groupScrollers) - scroller.classList.add('scroller') + scroller.classList.add(CSS_PREFIX + 'scroller') return { scroller, verticalScroller, horizontalScroller } } diff --git a/src/components/sheet.ts b/src/components/sheet.ts index 7367d39..d64f524 100644 --- a/src/components/sheet.ts +++ b/src/components/sheet.ts @@ -1,4 +1,4 @@ -import Spreadsheet from "../main" +import Spreadsheet, { CSS_PREFIX } from "../main" import { Position } from "../modules/cell" /** @@ -11,7 +11,7 @@ export class Sheet { constructor(root: Spreadsheet) { this.root = root const canvas = document.createElement('canvas') - canvas.classList.add('sheet') + canvas.classList.add(CSS_PREFIX + 'sheet') //* Set up canvas sizes based on provided root config canvas.height = this.root.config.view.height diff --git a/src/components/table.ts b/src/components/table.ts index 903b188..e4cf6d2 100644 --- a/src/components/table.ts +++ b/src/components/table.ts @@ -1,4 +1,4 @@ -import Spreadsheet from "../main" +import Spreadsheet, { CSS_PREFIX } from "../main" import { ViewProperties } from "../modules/config" /** Base (root) component */ @@ -8,7 +8,7 @@ export class Table { constructor(root: Spreadsheet) { this.root = root const container = document.createElement('div') - container.classList.add('spreadsheet_container') + container.classList.add(CSS_PREFIX + 'spreadsheet_container') this.element = container this.changeElementSizes(this.root.viewProps) diff --git a/src/components/toolbar.ts b/src/components/toolbar.ts index b75e668..8dfdef0 100644 --- a/src/components/toolbar.ts +++ b/src/components/toolbar.ts @@ -1,4 +1,4 @@ -import Spreadsheet from "../main" +import Spreadsheet, { CSS_PREFIX } from "../main" export class Toolbar { element: HTMLDivElement @@ -6,7 +6,7 @@ export class Toolbar { constructor(root: Spreadsheet) { this.root = root const toolbarElement = document.createElement('div') - toolbarElement.classList.add('toolbar') + toolbarElement.classList.add(CSS_PREFIX + 'toolbar') this.element = toolbarElement } } \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index e1891f3..72c5ca9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -24,3 +24,11 @@ function loadDataFromLS() { saveButton.addEventListener('click', saveDataToLS) loadButton.addEventListener('click', loadDataFromLS) +sheet.changeCellStyles({column: 1, row: 1}, { + background: 'black', + borderColor: 'white', + fontColor: 'white', + fontSize: 20, + selectedBackground: 'green', + selectedFontColor: 'black' +}) \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index 9122bd4..16b34e1 100644 --- a/src/main.ts +++ b/src/main.ts @@ -4,7 +4,7 @@ import { Scroller } from "./components/scroller"; import { Sheet } from "./components/sheet"; import { Table } from "./components/table"; import { Toolbar } from "./components/toolbar"; -import { Cell, CellConstructorProps, Position, SerializableCell } from "./modules/cell"; +import { Cell, CellConstructorProps, CellStyles, Position, SerializableCell } from "./modules/cell"; import { Config, ViewProperties } from "./modules/config"; import { RangeSelectionType, Selection } from "./modules/selection"; import { Styles } from "./modules/styles"; @@ -32,6 +32,8 @@ interface SpreadsheetConstructorProperties { view?: ViewProperties } +export const CSS_PREFIX = "modern_sc_" + export default class Spreadsheet { private table: Table private scroller: Scroller @@ -115,7 +117,7 @@ export default class Spreadsheet { content.appendChild(this.header.element) content.appendChild(this.sheet.element) - content.classList.add('content') + content.classList.add(CSS_PREFIX + 'content') this.table.element.appendChild(this.toolbar.element) this.table.element.appendChild(content) @@ -175,6 +177,12 @@ export default class Spreadsheet { this.renderCell(row, column) } + changeCellStyles(position: Position, styles: CellStyles) { + const { column, row } = position + this.data[row][column].changeStyles(styles) + this.renderCell(row, column) + } + applyActionToRange(range: RangeSelectionType, callback: (cell: Cell) => any): void { const fromRow = Math.min(range.from.row, range.to.row) const toRow = Math.max(range.from.row, range.to.row) @@ -211,8 +219,8 @@ export default class Spreadsheet { } } - showEditor(position: Position) { - this.editor.show(position) + showEditor(position: Position, initialString?: string) { + this.editor.show(position, initialString) } renderSheet() { @@ -238,7 +246,8 @@ export default class Spreadsheet { displayValue: cell.displayValue, position: cell.position, resultValue: cell.resultValue, - value: cell.value + value: cell.value, + style: cell.style })) } formattedData.push(innerRow) diff --git a/src/modules/cell.ts b/src/modules/cell.ts index f4a0890..dac0b3b 100644 --- a/src/modules/cell.ts +++ b/src/modules/cell.ts @@ -6,6 +6,7 @@ export type CellConstructorProps = { displayValue: string resultValue: string position: Position + style: CellStyles | null } interface CellStylesConstructorProps { @@ -48,7 +49,7 @@ export class SerializableCell { displayValue: string resultValue: string position: Position - style: CellStyles + style: CellStyles | null constructor(props: SerializableCell | SerializableCell) { this.value = props.value this.displayValue = props.displayValue @@ -59,18 +60,21 @@ export class SerializableCell { } export class Cell { + /** True value (data) */ value: string + /** Value to render */ displayValue: string /** This refers to the values ​​​​that were obtained by calculations, for example, after calculating the formula */ resultValue: string position: Position - style: CellStyles = new CellStyles() + style: CellStyles | null = null constructor(props: CellConstructorProps) { this.value = props.value this.displayValue = props.displayValue this.resultValue = props.resultValue this.position = props.position + this.style = props.style } public getSerializableCell(): SerializableCell { @@ -84,6 +88,10 @@ export class Cell { return cell } + changeStyles(styles: CellStyles) { + this.style = styles + } + changeValues(values: Partial>) { Object.assign(this, values) } @@ -109,15 +117,17 @@ export class Cell { y -= root.viewport.top x -= root.viewport.left + const styles = this.style ?? root.styles.cells + ctx.clearRect(x, y, width, height) - ctx.fillStyle = isCellSelected || isCellInRange ? this.style.selectedBackground : this.style.background + ctx.fillStyle = isCellSelected || isCellInRange ? styles.selectedBackground : styles.background ctx.strokeStyle = 'black' ctx.fillRect(x, y, width - 1, height - 1) ctx.strokeRect(x, y, width, height) - ctx.fillStyle = isCellSelected || isCellInRange ? this.style.selectedFontColor : this.style.fontColor + ctx.fillStyle = isCellSelected || isCellInRange ? styles.selectedFontColor : styles.fontColor ctx.textAlign = 'left' - ctx.font = `${this.style.fontSize}px Arial` + ctx.font = `${styles.fontSize}px Arial` ctx.textBaseline = 'middle' ctx.fillText(this.displayValue, x + 2, y + height / 2) } diff --git a/src/modules/styles.ts b/src/modules/styles.ts index 76a17b3..3207abf 100644 --- a/src/modules/styles.ts +++ b/src/modules/styles.ts @@ -1,4 +1,9 @@ +import { CellStyles } from "./cell"; export class Styles { + cells: CellStyles + constructor() { + this.cells = new CellStyles() + } } \ No newline at end of file diff --git a/src/scss/_global.scss b/src/scss/_global.scss index 7ea5983..e8007e4 100644 --- a/src/scss/_global.scss +++ b/src/scss/_global.scss @@ -1,4 +1,4 @@ body { padding: 0px; margin: 0px; -} \ No newline at end of file +} diff --git a/src/scss/_spreadsheet.scss b/src/scss/_spreadsheet.scss index 84b490c..0717913 100644 --- a/src/scss/_spreadsheet.scss +++ b/src/scss/_spreadsheet.scss @@ -1,25 +1,23 @@ +$css_prefix: "modern_sc_"; - -.content { +.#{$css_prefix}content { position: absolute; top: 0; left: 0; } -.spreadsheet_container { +.#{$css_prefix}spreadsheet_container { position: relative; isolation: isolate; border: 2px solid black; - - } -.sheet{ +.#{$css_prefix}sheet{ display: block; contain: strict; } -.scroller { +.#{$css_prefix}scroller { overflow: scroll; box-sizing: border-box; transform: translateZ(0); @@ -28,13 +26,13 @@ } } -.editor { +.#{$css_prefix}editor { position: absolute; box-sizing: border-box; font-size: 16px; font-family: Arial, Helvetica, sans-serif; } -.hide { +.#{$css_prefix}hide { visibility: hidden; } \ No newline at end of file