New features: serialize and load data

Fixed imports in modules
This commit is contained in:
Eugene 2023-07-25 12:33:25 +03:00
parent 73645c14f6
commit 11376f13ac
27 changed files with 182 additions and 64 deletions

View File

@ -14,4 +14,7 @@ const target = document.getElementById('spreadsheet')
const sheet = new Spreadsheet(target)
```
<span>Load data</span>
</div>

View File

@ -1,4 +1,4 @@
import { Spreadsheet } from "../main";
import Spreadsheet from "../main";
import { Position } from "../modules/cell";
export declare class Editor {
element: HTMLInputElement;

View File

@ -1,4 +1,4 @@
import { Spreadsheet } from "../main";
import Spreadsheet from "../main";
export declare class Header {
element: HTMLHeadElement;
root: Spreadsheet;

View File

@ -1,4 +1,4 @@
import { Spreadsheet } from "../main";
import Spreadsheet from "../main";
export interface ViewportRect {
top: number;
left: number;

View File

@ -1,4 +1,4 @@
import { Spreadsheet } from "../main";
import Spreadsheet from "../main";
import { Position } from "../modules/cell";
/**
* Display (CANVAS) element where cells render

View File

@ -1,4 +1,4 @@
import { Spreadsheet } from "../main";
import Spreadsheet from "../main";
import { ViewProperties } from "../modules/config";
/** Base (root) component */
export declare class Table {

View File

@ -1,4 +1,4 @@
import { Spreadsheet } from "../main";
import Spreadsheet from "../main";
export declare class Toolbar {
element: HTMLDivElement;
root: Spreadsheet;

6
dist/main.cjs vendored

File diff suppressed because one or more lines are too long

2
dist/main.cjs.map vendored

File diff suppressed because one or more lines are too long

15
dist/main.d.ts vendored
View File

@ -9,7 +9,7 @@ interface SpreadsheetConstructorProperties {
config?: Omit<Config, 'view'>;
view?: ViewProperties;
}
export declare class Spreadsheet {
export default class Spreadsheet {
private table;
private scroller;
private toolbar;
@ -37,7 +37,16 @@ export declare class Spreadsheet {
showEditor(position: Position): void;
renderSheet(): void;
renderCell(row: number, col: number): void;
loadData(data: Cell[][]): void;
loadData(data: Cell[][]): Spreadsheet;
private makeConfigFromData;
}
export {};
export * from './modules/cache';
export * from './modules/cell';
export * from './modules/column';
export * from './modules/config';
export * from './modules/renderBox';
export * from './modules/row';
export * from './modules/selection';
export * from './modules/styles';
export * from './modules/viewport';
export * from './utils/createData';

76
dist/main.js vendored
View File

@ -1,6 +1,6 @@
var f = Object.defineProperty;
var C = (r, t, e) => t in r ? f(r, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : r[t] = e;
var o = (r, t, e) => (C(r, typeof t != "symbol" ? t + "" : t, e), e);
var p = Object.defineProperty;
var y = (r, t, e) => t in r ? p(r, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : r[t] = e;
var o = (r, t, e) => (y(r, typeof t != "symbol" ? t + "" : t, e), e);
class w {
constructor(t, e) {
o(this, "x");
@ -22,7 +22,7 @@ class w {
return s;
}
}
class p {
class S {
constructor(t) {
o(this, "element");
o(this, "root");
@ -56,7 +56,7 @@ class p {
this.element.classList.remove("hide"), this.element.style.top = n - this.root.viewport.top + "px", this.element.style.left = l - this.root.viewport.left + "px", this.element.style.width = s + "px", this.element.style.height = e + "px", this.element.style.display = "block", window.addEventListener("click", this.handleClickOutside), this.element.addEventListener("keydown", this.handleKeydown), this.element.value = i.value, this.element.focus(), this.element.select();
}
}
class y {
class v {
constructor(t) {
o(this, "element");
o(this, "root");
@ -65,7 +65,7 @@ class y {
e.classList.add(), this.element = e;
}
}
class v {
class x {
constructor(t) {
o(this, "element");
o(this, "verticalScroller");
@ -160,7 +160,7 @@ class v {
this.horizontalScroller.style.width = t + "px";
}
}
class S {
class R {
constructor(t) {
o(this, "fontSize", 16);
o(this, "fontColor", "black");
@ -171,21 +171,21 @@ class S {
t && Object.assign(this, t);
}
}
class x {
class b {
constructor(t, e) {
o(this, "row");
o(this, "column");
this.row = t, this.column = e;
}
}
class R {
class k {
constructor(t) {
o(this, "value");
o(this, "displayValue");
/** This refers to the values that were obtained by calculations, for example, after calculating the formula */
o(this, "resultValue");
o(this, "position");
o(this, "style", new S());
o(this, "style", new R());
this.value = t.value, this.displayValue = t.displayValue, this.resultValue = t.resultValue, this.position = t.position;
}
changeValues(t) {
@ -205,7 +205,7 @@ class R {
n -= t.viewport.top, l -= t.viewport.left, i.clearRect(l, n, s, e), i.fillStyle = c || h ? this.style.selectedBackground : this.style.background, i.strokeStyle = "black", i.fillRect(l, n, s - 1, e - 1), i.strokeRect(l, n, s, e), i.fillStyle = c || h ? this.style.selectedFontColor : this.style.fontColor, i.textAlign = "left", i.font = `${this.style.fontSize}px Arial`, i.textBaseline = "middle", i.fillText(this.displayValue, l + 2, n + e / 2);
}
}
class b {
class E {
constructor(t) {
o(this, "element");
o(this, "ctx");
@ -225,7 +225,7 @@ class b {
let n = 0, i = 0;
for (; i <= t && (i += this.root.config.columns[n].width, !(i >= t)); )
n++;
return new x(s, n);
return new b(s, n);
}
renderCell(t) {
const { column: e, row: s } = t;
@ -238,7 +238,7 @@ class b {
this.renderCell({ column: i, row: n });
}
}
class k {
class I {
constructor(t) {
o(this, "element");
o(this, "root");
@ -251,7 +251,7 @@ class k {
this.element.style.width = s + "px", this.element.style.height = e + "px";
}
}
class E {
class V {
constructor(t) {
o(this, "element");
o(this, "root");
@ -271,13 +271,13 @@ class d {
this.columns = t.columns, this.rows = t.rows, this.view = t.view;
}
}
class I {
class L {
constructor() {
o(this, "selectedCell", null);
o(this, "selectedRange", null);
}
}
class V {
class B {
}
class u {
constructor(t, e) {
@ -332,12 +332,12 @@ class g {
this.height = t.height, this.title = t.title;
}
}
function L(r, t, e = !1) {
function f(r, t, e = !1) {
const s = [];
for (let l = 0; l <= r; l++) {
const n = [];
for (let i = 0; i <= t; i++) {
const c = e ? `${l}:${i}` : "", h = new R({
const c = e ? `${l}:${i}` : "", h = new k({
displayValue: c,
resultValue: c,
value: c,
@ -352,7 +352,7 @@ function L(r, t, e = !1) {
}
return s;
}
function B(r, t) {
function C(r, t) {
const e = [];
for (let n = 0; n <= r; n++) {
const i = new g({
@ -378,6 +378,10 @@ function B(r, t) {
}
});
}
function z(r, t) {
const e = f(r, t), s = C(r, t);
return { data: e, config: s };
}
class A {
constructor(t) {
o(this, "xPos");
@ -392,7 +396,7 @@ class M {
this.yPos = t.yPos, this.rowIdx = t.rowIdx;
}
}
class T {
class D {
constructor(t) {
o(this, "columns");
o(this, "rows");
@ -417,7 +421,7 @@ class T {
return e;
}
}
class D {
class F {
constructor(t, e) {
o(this, "table");
o(this, "scroller");
@ -431,10 +435,10 @@ class D {
o(this, "viewport");
o(this, "selection");
o(this, "cache");
const s = B(500, 500);
e != null && e.view && (s.view = e.view), this.config = new d(s), this.sheet = new b(this);
const l = L(500, 500);
this.table = new k(this), this.scroller = new v(this), this.toolbar = new E(this), this.header = new y(this), this.editor = new p(this), this.cache = this.getInitialCache(), this.viewport = new u(this, this.scroller.getViewportBoundlingRect()), this.selection = new I(), this.data = l, this.styles = new V(), this.buildComponent(), this.appendTableToTarget(t), this.renderSheet();
const s = C(500, 500);
e != null && e.view && (s.view = e.view), this.config = new d(s), this.sheet = new E(this);
const l = f(500, 500);
this.table = new I(this), this.scroller = new x(this), this.toolbar = new V(this), this.header = new v(this), this.editor = new S(this), this.cache = this.getInitialCache(), this.viewport = new u(this, this.scroller.getViewportBoundlingRect()), this.selection = new L(), this.data = l, this.styles = new B(), this.buildComponent(), this.appendTableToTarget(t), this.renderSheet();
}
getInitialCache() {
const t = [];
@ -459,7 +463,7 @@ class D {
});
s.push(h);
}
const n = new T({
const n = new D({
columns: t,
rows: s
});
@ -536,7 +540,7 @@ class D {
this.data[t][e].render(this);
}
loadData(t) {
this.data = t, this.config = this.makeConfigFromData(t, this.config.view), this.cache = this.getInitialCache(), this.scroller.updateScrollerSize(), this.viewport = new u(this, this.scroller.getViewportBoundlingRect()), this.renderSheet();
return this.data = t, this.config = this.makeConfigFromData(t, this.config.view), this.cache = this.getInitialCache(), this.scroller.updateScrollerSize(), this.viewport = new u(this, this.scroller.getViewportBoundlingRect()), this.renderSheet(), this;
}
makeConfigFromData(t, e) {
const s = t.length - 1, l = t[0] ? t[0].length : 0, n = [];
@ -559,6 +563,22 @@ class D {
}
}
export {
D as Spreadsheet
D as Cache,
A as CachedColumn,
M as CachedRow,
k as Cell,
R as CellStyles,
m as Column,
d as Config,
b as Position,
w as RenderBox,
g as Row,
L as Selection,
B as Styles,
u as Viewport,
C as createSampleConfig,
f as createSampleData,
F as default,
z as makeSpreadsheetConfigAndData
};
//# sourceMappingURL=main.js.map

2
dist/main.js.map vendored

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
import { Spreadsheet } from "../main";
import Spreadsheet from "../main";
export type CellConstructorProps = {
value: string;
displayValue: string;

View File

@ -1,4 +1,4 @@
import { Spreadsheet } from "../main";
import Spreadsheet from "../main";
export type ViewportConstructorProps = {
top: number;
left: number;

View File

@ -2,9 +2,8 @@ import { Cell } from "../modules/cell";
import { Config } from "../modules/config";
export declare function createSampleData(rows: number, columns: number, fillCellsByCoords?: boolean): Cell[][];
export declare function createSampleConfig(rows: number, columns: number): Config;
type SpreadsheetConfigAndDataReturnType = {
export type SpreadsheetConfigAndDataReturnType = {
config: Config;
data: Cell[][];
};
export declare function makeSpreadsheetConfigAndData(rows: number, columns: number): SpreadsheetConfigAndDataReturnType;
export {};

View File

@ -8,6 +8,8 @@
</head>
<body>
<div id="spreadsheet"></div>
<button id="save_button">Save sheet</button>
<button id="load_button">Load sheet</button>
<script type="module" src="/src/index.ts"></script>
</body>
</html>

View File

@ -1,7 +1,7 @@
{
"name": "modern_spreadsheet",
"private": false,
"version": "0.0.19",
"version": "0.0.20",
"exports": {
".": {
"import": "./dist/main.js",

View File

@ -1,4 +1,4 @@
import { Spreadsheet } from "../main";
import Spreadsheet from "../main";
import { Position } from "../modules/cell";
import { RenderBox } from "../modules/renderBox";

View File

@ -1,4 +1,4 @@
import { Spreadsheet } from "../main"
import Spreadsheet from "../main"
export class Header {
element: HTMLHeadElement

View File

@ -1,4 +1,4 @@
import { Spreadsheet } from "../main"
import Spreadsheet from "../main"
export interface ViewportRect {
top: number

View File

@ -1,4 +1,4 @@
import { Spreadsheet } from "../main"
import Spreadsheet from "../main"
import { Position } from "../modules/cell"
/**

View File

@ -1,4 +1,4 @@
import { Spreadsheet } from "../main"
import Spreadsheet from "../main"
import { ViewProperties } from "../modules/config"
/** Base (root) component */

View File

@ -1,4 +1,4 @@
import { Spreadsheet } from "../main"
import Spreadsheet from "../main"
export class Toolbar {
element: HTMLDivElement

View File

@ -1,5 +1,23 @@
import Spreadsheet, { createSampleData, } from './main'
import Spreadsheet from './main'
const sheet = new Spreadsheet('#spreadsheet').loadData(createSampleData(20, 20, true))
const saveButton = document.querySelector('#save_button')
const loadButton = document.querySelector('#load_button')
console.log(sheet)
if(!saveButton || !loadButton) throw new Error("LOST")
const sheet = new Spreadsheet('#spreadsheet')
function saveDataToLS() {
const serializableData = sheet.serializeData()
localStorage.setItem('sheet', JSON.stringify(serializableData))
}
function loadDataFromLS() {
const data = localStorage.getItem('sheet')
if(!data) return
const json = JSON.parse(data)
sheet.loadData(json)
}
saveButton.addEventListener('click', saveDataToLS)
loadButton.addEventListener('click', loadDataFromLS)

View File

@ -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 } from "./modules/cell";
import { Cell, CellConstructorProps, Position, SerializableCell } from "./modules/cell";
import { Config, ViewProperties } from "./modules/config";
import { RangeSelectionType, Selection } from "./modules/selection";
import { Styles } from "./modules/styles";
@ -47,14 +47,15 @@ export default class Spreadsheet {
public cache: Cache
constructor(target: string | HTMLElement, props?: SpreadsheetConstructorProperties) {
const config = createSampleConfig(500, 500)
const data = createSampleData(40, 40)
const config = this.makeConfigFromData(data, props?.view ?? { height: 600, width: 800 })
if (props?.view) {
config.view = props.view
}
this.config = new Config(config)
this.sheet = new Sheet(this)
const data = createSampleData(500, 500)
this.table = new Table(this)
this.scroller = new Scroller(this)
this.toolbar = new Toolbar(this)
@ -209,9 +210,32 @@ export default class Spreadsheet {
this.data[row][col].render(this)
}
public loadData(data: Cell[][]): Spreadsheet {
this.data = data
this.config = this.makeConfigFromData(data, this.config.view)
public loadData(data: Cell[][] | SerializableCell[][]): Spreadsheet {
const rowsLength = data.length
const colsLength = data[0] ? this.data[0].length : 0
this.data = []
const formattedData: Cell[][] = []
for (let row = 0; row < rowsLength; row++) {
const innerRow: Cell[] = []
for (let col = 0; col < colsLength; col++) {
const cell = data[row][col]
innerRow.push(new Cell({
displayValue: cell.displayValue,
position: cell.position,
resultValue: cell.resultValue,
value: cell.value
}))
}
formattedData.push(innerRow)
}
this.data = formattedData
this.selection.selectedCell = null
this.selection.selectedRange = null
this.config = this.makeConfigFromData(formattedData, this.config.view)
this.cache = this.getInitialCache()
this.scroller.updateScrollerSize()
this.viewport = new Viewport(this, this.scroller.getViewportBoundlingRect())
@ -249,6 +273,23 @@ export default class Spreadsheet {
return config
}
public serializeData(): SerializableCell[][] {
const rowsLength = this.data.length
const colsLength = this.data[0] ? this.data[0].length : 0
const cellsArray: SerializableCell[][] = []
for (let row = 0; row < rowsLength; row++) {
const innerRow: SerializableCell[] = []
for (let col = 0; col < colsLength; col++) {
innerRow.push(this.data[row][col].getSerializableCell())
}
cellsArray.push(innerRow)
}
return cellsArray
}
}
export * from './modules/cache'

View File

@ -1,4 +1,4 @@
import { Spreadsheet } from "../main"
import Spreadsheet from "../main"
import { RenderBox } from "./renderBox"
export type CellConstructorProps = {
@ -43,6 +43,21 @@ export class Position {
}
}
export class SerializableCell {
value: string
displayValue: string
resultValue: string
position: Position
style: CellStyles
constructor(props: SerializableCell | SerializableCell) {
this.value = props.value
this.displayValue = props.displayValue
this.resultValue = props.resultValue
this.position = props.position
this.style = props.style
}
}
export class Cell {
value: string
displayValue: string
@ -58,6 +73,17 @@ export class Cell {
this.position = props.position
}
public getSerializableCell(): SerializableCell {
const cell:SerializableCell = new SerializableCell({
displayValue: this.displayValue,
position: this.position,
resultValue: this.resultValue,
style: this.style,
value: this.value
})
return cell
}
changeValues(values: Partial<Omit<CellConstructorProps, 'position'>>) {
Object.assign(this, values)
}

View File

@ -1,4 +1,4 @@
import { Spreadsheet } from "../main"
import Spreadsheet from "../main"
export type ViewportConstructorProps = {
top: number