@candidstartup/simple-spreadsheet-data 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,29 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2023-2024, Tim Wiegand
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ 3. Neither the name of the copyright holder nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package/README.md ADDED
@@ -0,0 +1,10 @@
1
+ [![NPM Type Definitions](https://img.shields.io/npm/types/@candidstartup/simple-spreadsheet-data)](https://www.npmjs.com/package/@candidstartup/simple-spreadsheet-data)
2
+ [![NPM Version](https://img.shields.io/npm/v/@candidstartup/simple-spreadsheet-data)](https://www.npmjs.com/package/@candidstartup/simple-spreadsheet-data)
3
+ [![NPM bundle size](https://img.shields.io/bundlephobia/minzip/@candidstartup/simple-spreadsheet-data)](https://www.npmjs.com/package/@candidstartup/simple-spreadsheet-data)
4
+ [![Build Status](https://github.com/TheCandidStartup/infinisheet/actions/workflows/build.yml/badge.svg?event=push)](https://github.com/TheCandidStartup/infinisheet/actions/workflows/build.yml)
5
+
6
+ [GitHub](https://github.com/TheCandidStartup/infinisheet/tree/main/packages/simple-spreadsheet-data) | [NPM](https://www.npmjs.com/package/@candidstartup/simple-spreadsheet-data) | [API](https://www.thecandidstartup.org/infinisheet/modules/_candidstartup_simple-spreadsheet-data.html)
7
+
8
+ # @candidstartup/simple-spreadsheet-data
9
+
10
+ Reference implementations of `SpreadsheetData`
@@ -0,0 +1,99 @@
1
+ import { SpreadsheetData, ItemOffsetMapping, CellValue } from '@candidstartup/infinisheet-types';
2
+
3
+ /**
4
+ * Branding Enum. Used by {@link SimpleSnapshot} to ensure that
5
+ * you'll get a type error if you pass some random object where a `SimpleSnapshot`
6
+ * is expected.
7
+ * @internal
8
+ */
9
+ declare enum _SimpleSnapshotBrand {
10
+ _DO_NOT_USE = ""
11
+ }
12
+ /**
13
+ * Opaque type representing a {@link SimpleSpreadsheetData} snapshot. All the
14
+ * internal implementation details are hidden from the exported API.
15
+ */
16
+ interface SimpleSnapshot {
17
+ /** @internal */
18
+ _brand: _SimpleSnapshotBrand;
19
+ }
20
+ /**
21
+ * Reference implementation of {@link SpreadsheetData}
22
+ *
23
+ * Editable in-memory spreadsheet data container. Starts out empty. Use the API to fill
24
+ * with data!
25
+ *
26
+ * Intended for use as a mock, to compare with an optimized implementation when testing and
27
+ * for simple sample apps. Simplest possible implementation, no attempt at optimization.
28
+ */
29
+ declare class SimpleSpreadsheetData implements SpreadsheetData<SimpleSnapshot> {
30
+ #private;
31
+ constructor();
32
+ subscribe(onDataChange: () => void): () => void;
33
+ getSnapshot(): SimpleSnapshot;
34
+ getRowCount(snapshot: SimpleSnapshot): number;
35
+ getRowItemOffsetMapping(_snapshot: SimpleSnapshot): ItemOffsetMapping;
36
+ getColumnCount(snapshot: SimpleSnapshot): number;
37
+ getColumnItemOffsetMapping(_snapshot: SimpleSnapshot): ItemOffsetMapping;
38
+ getCellValue(snapshot: SimpleSnapshot, row: number, column: number): CellValue;
39
+ getCellFormat(snapshot: SimpleSnapshot, row: number, column: number): string | undefined;
40
+ setCellValueAndFormat(row: number, column: number, value: CellValue, format: string | undefined): boolean;
41
+ }
42
+
43
+ /**
44
+ * Branding Enum. Used by {@link LayeredSnapshot} to ensure that
45
+ * you'll get a type error if you pass some random object where a `LayeredSnapshot`
46
+ * is expected.
47
+ * @internal
48
+ */
49
+ declare enum _LayeredSnapshotBrand {
50
+ _DO_NOT_USE = ""
51
+ }
52
+ /**
53
+ * Opaque type representing a {@link LayeredSpreadsheetData} snapshot. All the
54
+ * internal implementation details are hidden from the exported API.
55
+ */
56
+ interface LayeredSnapshot<BaseSnapshot, EditSnapshot> {
57
+ /** @internal */
58
+ _brand: [_LayeredSnapshotBrand, BaseSnapshot, EditSnapshot];
59
+ }
60
+ /**
61
+ * Extracts the snapshot type from a {@link SpreadsheetData} instance
62
+ */
63
+ type SnapshotType<T> = T extends SpreadsheetData<infer TResult> ? TResult : never;
64
+ /**
65
+ * Implementation of {@link SpreadsheetData} that layers two other `SpreadsheetData` instances on top of each other.
66
+ *
67
+ * There's an "edit" layer on top where any changes are stored, with a "base" layer underneath. If a value is `undefined` in the edit layer,
68
+ * the corresponding value is returned from the base layer instead.
69
+ *
70
+ * Common use case is a read only reference data source as the base layer with an initially empty edit layer that accepts changes.
71
+ *
72
+ * @typeParam BaseData - Type of base layer `SpreadsheetData` instance
73
+ * @typeParam EditData - Type of edit layer `SpreadsheetData` instance
74
+ * @typeParam BaseSnapshot - Type of snapshot used by `BaseData`. By default, inferred from `BaseData`.
75
+ * @typeParam EditSnapshot - Type of snapshot used by `EditData`. By default, inferred from `EditData`.
76
+ */
77
+ declare class LayeredSpreadsheetData<BaseData extends SpreadsheetData<BaseSnapshot>, EditData extends SpreadsheetData<EditSnapshot>, BaseSnapshot = SnapshotType<BaseData>, EditSnapshot = SnapshotType<EditData>> implements SpreadsheetData<LayeredSnapshot<BaseSnapshot, EditSnapshot>> {
78
+ #private;
79
+ /**
80
+ * Creates a `LayeredSpreadsheetData` instance from two existing `SpreadsheetData` instances.
81
+ *
82
+ * All type parameters can be inferred from the constructor arguments.
83
+ *
84
+ * @param base - `SpreadsheetData` instance to use for the base layer
85
+ * @param edit - `SpreadsheetData` instance to use for the edit layer
86
+ */
87
+ constructor(base: BaseData, edit: EditData);
88
+ subscribe(onDataChange: () => void): () => void;
89
+ getSnapshot(): LayeredSnapshot<BaseSnapshot, EditSnapshot>;
90
+ getRowCount(snapshot: LayeredSnapshot<BaseSnapshot, EditSnapshot>): number;
91
+ getRowItemOffsetMapping(snapshot: LayeredSnapshot<BaseSnapshot, EditSnapshot>): ItemOffsetMapping;
92
+ getColumnCount(snapshot: LayeredSnapshot<BaseSnapshot, EditSnapshot>): number;
93
+ getColumnItemOffsetMapping(snapshot: LayeredSnapshot<BaseSnapshot, EditSnapshot>): ItemOffsetMapping;
94
+ getCellValue(snapshot: LayeredSnapshot<BaseSnapshot, EditSnapshot>, row: number, column: number): CellValue;
95
+ getCellFormat(snapshot: LayeredSnapshot<BaseSnapshot, EditSnapshot>, row: number, column: number): string | undefined;
96
+ setCellValueAndFormat(row: number, column: number, value: CellValue, format: string | undefined): boolean;
97
+ }
98
+
99
+ export { type LayeredSnapshot, LayeredSpreadsheetData, type SimpleSnapshot, SimpleSpreadsheetData, type SnapshotType, _LayeredSnapshotBrand, _SimpleSnapshotBrand };
package/dist/index.js ADDED
@@ -0,0 +1,184 @@
1
+ import { FixedSizeItemOffsetMapping, rowColCoordsToRef } from '@candidstartup/infinisheet-types';
2
+
3
+ /**
4
+ * Branding Enum. Used by {@link SimpleSnapshot} to ensure that
5
+ * you'll get a type error if you pass some random object where a `SimpleSnapshot`
6
+ * is expected.
7
+ * @internal
8
+ */
9
+ var _SimpleSnapshotBrand;
10
+ (function (_SimpleSnapshotBrand) {
11
+ _SimpleSnapshotBrand["_DO_NOT_USE"] = "";
12
+ })(_SimpleSnapshotBrand || (_SimpleSnapshotBrand = {}));
13
+ const rowItemOffsetMapping = new FixedSizeItemOffsetMapping(30);
14
+ const columnItemOffsetMapping = new FixedSizeItemOffsetMapping(100);
15
+ function asContent$1(snapshot) {
16
+ return snapshot;
17
+ }
18
+ function asSnapshot$1(snapshot) {
19
+ return snapshot;
20
+ }
21
+ /**
22
+ * Reference implementation of {@link SpreadsheetData}
23
+ *
24
+ * Editable in-memory spreadsheet data container. Starts out empty. Use the API to fill
25
+ * with data!
26
+ *
27
+ * Intended for use as a mock, to compare with an optimized implementation when testing and
28
+ * for simple sample apps. Simplest possible implementation, no attempt at optimization.
29
+ */
30
+ class SimpleSpreadsheetData {
31
+ constructor() {
32
+ this.#listeners = [];
33
+ this.#content = {
34
+ values: {},
35
+ rowCount: 0,
36
+ colCount: 0
37
+ };
38
+ }
39
+ subscribe(onDataChange) {
40
+ this.#listeners = [...this.#listeners, onDataChange];
41
+ return () => {
42
+ this.#listeners = this.#listeners.filter(l => l !== onDataChange);
43
+ };
44
+ }
45
+ getSnapshot() {
46
+ return asSnapshot$1(this.#content);
47
+ }
48
+ getRowCount(snapshot) {
49
+ return asContent$1(snapshot).rowCount;
50
+ }
51
+ getRowItemOffsetMapping(_snapshot) {
52
+ return rowItemOffsetMapping;
53
+ }
54
+ getColumnCount(snapshot) {
55
+ return asContent$1(snapshot).colCount;
56
+ }
57
+ getColumnItemOffsetMapping(_snapshot) {
58
+ return columnItemOffsetMapping;
59
+ }
60
+ getCellValue(snapshot, row, column) {
61
+ const ref = rowColCoordsToRef(row, column);
62
+ return asContent$1(snapshot).values[ref]?.value;
63
+ }
64
+ getCellFormat(snapshot, row, column) {
65
+ const ref = rowColCoordsToRef(row, column);
66
+ return asContent$1(snapshot).values[ref]?.format;
67
+ }
68
+ setCellValueAndFormat(row, column, value, format) {
69
+ const curr = this.#content;
70
+ const ref = rowColCoordsToRef(row, column);
71
+ // Snapshot semantics preserved by treating SimpleSnapshot as an immutable data structure which is
72
+ // replaced with a modified copy on every update. Yes, this is horribly inefficient.
73
+ // For simplicity, setting a value to undefined stores it explicitly rather than removing it. Functional
74
+ // behavior is the same.
75
+ this.#content = {
76
+ values: { ...curr.values, [ref]: { value, format } },
77
+ rowCount: Math.max(curr.rowCount, row + 1),
78
+ colCount: Math.max(curr.colCount, column + 1)
79
+ };
80
+ this.#notifyListeners();
81
+ return true;
82
+ }
83
+ #notifyListeners() {
84
+ for (const listener of this.#listeners)
85
+ listener();
86
+ }
87
+ #listeners;
88
+ #content;
89
+ }
90
+
91
+ /**
92
+ * Branding Enum. Used by {@link LayeredSnapshot} to ensure that
93
+ * you'll get a type error if you pass some random object where a `LayeredSnapshot`
94
+ * is expected.
95
+ * @internal
96
+ */
97
+ var _LayeredSnapshotBrand;
98
+ (function (_LayeredSnapshotBrand) {
99
+ _LayeredSnapshotBrand["_DO_NOT_USE"] = "";
100
+ })(_LayeredSnapshotBrand || (_LayeredSnapshotBrand = {}));
101
+ function asContent(snapshot) {
102
+ return snapshot;
103
+ }
104
+ function asSnapshot(snapshot) {
105
+ return snapshot;
106
+ }
107
+ /**
108
+ * Implementation of {@link SpreadsheetData} that layers two other `SpreadsheetData` instances on top of each other.
109
+ *
110
+ * There's an "edit" layer on top where any changes are stored, with a "base" layer underneath. If a value is `undefined` in the edit layer,
111
+ * the corresponding value is returned from the base layer instead.
112
+ *
113
+ * Common use case is a read only reference data source as the base layer with an initially empty edit layer that accepts changes.
114
+ *
115
+ * @typeParam BaseData - Type of base layer `SpreadsheetData` instance
116
+ * @typeParam EditData - Type of edit layer `SpreadsheetData` instance
117
+ * @typeParam BaseSnapshot - Type of snapshot used by `BaseData`. By default, inferred from `BaseData`.
118
+ * @typeParam EditSnapshot - Type of snapshot used by `EditData`. By default, inferred from `EditData`.
119
+ */
120
+ class LayeredSpreadsheetData {
121
+ /**
122
+ * Creates a `LayeredSpreadsheetData` instance from two existing `SpreadsheetData` instances.
123
+ *
124
+ * All type parameters can be inferred from the constructor arguments.
125
+ *
126
+ * @param base - `SpreadsheetData` instance to use for the base layer
127
+ * @param edit - `SpreadsheetData` instance to use for the edit layer
128
+ */
129
+ constructor(base, edit) {
130
+ this.#base = base;
131
+ this.#edit = edit;
132
+ }
133
+ subscribe(onDataChange) {
134
+ const unsubscribeBase = this.#base.subscribe(onDataChange);
135
+ const unsubscribeEdit = this.#edit.subscribe(onDataChange);
136
+ return () => {
137
+ unsubscribeBase();
138
+ unsubscribeEdit();
139
+ };
140
+ }
141
+ getSnapshot() {
142
+ const baseSnapshot = this.#base.getSnapshot();
143
+ const editSnapshot = this.#edit.getSnapshot();
144
+ if (!this.#content || this.#content.base != baseSnapshot || this.#content.edit != editSnapshot) {
145
+ this.#content = { base: baseSnapshot, edit: editSnapshot };
146
+ }
147
+ return asSnapshot(this.#content);
148
+ }
149
+ getRowCount(snapshot) {
150
+ const content = asContent(snapshot);
151
+ return Math.max(this.#base.getRowCount(content.base), this.#edit.getRowCount(content.edit));
152
+ }
153
+ getRowItemOffsetMapping(snapshot) {
154
+ return this.#base.getRowItemOffsetMapping(asContent(snapshot).base);
155
+ }
156
+ getColumnCount(snapshot) {
157
+ const content = asContent(snapshot);
158
+ return Math.max(this.#base.getColumnCount(content.base), this.#edit.getColumnCount(content.edit));
159
+ }
160
+ getColumnItemOffsetMapping(snapshot) {
161
+ return this.#base.getColumnItemOffsetMapping(asContent(snapshot).base);
162
+ }
163
+ getCellValue(snapshot, row, column) {
164
+ const content = asContent(snapshot);
165
+ const editValue = this.#edit.getCellValue(content.edit, row, column);
166
+ if (editValue !== undefined)
167
+ return editValue;
168
+ return this.#base.getCellValue(content.base, row, column);
169
+ }
170
+ getCellFormat(snapshot, row, column) {
171
+ const content = asContent(snapshot);
172
+ const editValue = this.#edit.getCellValue(content.edit, row, column);
173
+ return (editValue === undefined) ? this.#base.getCellFormat(content.base, row, column) : this.#edit.getCellFormat(content.edit, row, column);
174
+ }
175
+ setCellValueAndFormat(row, column, value, format) {
176
+ return this.#edit.setCellValueAndFormat(row, column, value, format);
177
+ }
178
+ #base;
179
+ #edit;
180
+ #content;
181
+ }
182
+
183
+ export { LayeredSpreadsheetData, SimpleSpreadsheetData, _LayeredSnapshotBrand, _SimpleSnapshotBrand };
184
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/SimpleSpreadsheetData.ts","../src/LayeredSpreadsheetData.ts"],"sourcesContent":["import type { CellValue, SpreadsheetData, RowColRef, ItemOffsetMapping } from \"@candidstartup/infinisheet-types\";\nimport { FixedSizeItemOffsetMapping, rowColCoordsToRef } from \"@candidstartup/infinisheet-types\";\n\ninterface CellContent {\n value: CellValue;\n format: string|undefined;\n}\n\ninterface SimpleSnapshotContent {\n values: Record<RowColRef,CellContent>;\n rowCount: number;\n colCount: number;\n}\n\n/** \n * Branding Enum. Used by {@link SimpleSnapshot} to ensure that\n * you'll get a type error if you pass some random object where a `SimpleSnapshot`\n * is expected.\n * @internal\n */\nexport enum _SimpleSnapshotBrand { _DO_NOT_USE=\"\" };\n\n/**\n * Opaque type representing a {@link SimpleSpreadsheetData} snapshot. All the\n * internal implementation details are hidden from the exported API.\n */\nexport interface SimpleSnapshot {\n /** @internal */\n _brand: _SimpleSnapshotBrand;\n}\n\nconst rowItemOffsetMapping = new FixedSizeItemOffsetMapping(30);\nconst columnItemOffsetMapping = new FixedSizeItemOffsetMapping(100);\n\nfunction asContent(snapshot: SimpleSnapshot) {\n return snapshot as unknown as SimpleSnapshotContent;\n}\n\nfunction asSnapshot(snapshot: SimpleSnapshotContent) {\n return snapshot as unknown as SimpleSnapshot;\n}\n\n/**\n * Reference implementation of {@link SpreadsheetData}\n * \n * Editable in-memory spreadsheet data container. Starts out empty. Use the API to fill\n * with data!\n * \n * Intended for use as a mock, to compare with an optimized implementation when testing and\n * for simple sample apps. Simplest possible implementation, no attempt at optimization.\n */\nexport class SimpleSpreadsheetData implements SpreadsheetData<SimpleSnapshot> {\n constructor () {\n this.#listeners = [];\n this.#content = {\n values: {},\n rowCount: 0,\n colCount: 0\n }\n }\n\n subscribe(onDataChange: () => void): () => void {\n this.#listeners = [...this.#listeners, onDataChange];\n return () => {\n this.#listeners = this.#listeners.filter(l => l !== onDataChange);\n }\n }\n\n getSnapshot(): SimpleSnapshot {\n return asSnapshot(this.#content);\n }\n\n getRowCount(snapshot: SimpleSnapshot): number {\n return asContent(snapshot).rowCount;\n }\n\n getRowItemOffsetMapping(_snapshot: SimpleSnapshot): ItemOffsetMapping {\n return rowItemOffsetMapping;\n }\n\n getColumnCount(snapshot: SimpleSnapshot): number {\n return asContent(snapshot).colCount;\n }\n\n getColumnItemOffsetMapping(_snapshot: SimpleSnapshot): ItemOffsetMapping {\n return columnItemOffsetMapping\n }\n\n getCellValue(snapshot: SimpleSnapshot, row: number, column: number): CellValue {\n const ref = rowColCoordsToRef(row, column);\n return asContent(snapshot).values[ref]?.value;\n }\n\n getCellFormat(snapshot: SimpleSnapshot, row: number, column: number): string | undefined {\n const ref = rowColCoordsToRef(row, column);\n return asContent(snapshot).values[ref]?.format;\n }\n\n setCellValueAndFormat(row: number, column: number, value: CellValue, format: string | undefined): boolean {\n const curr = this.#content;\n const ref = rowColCoordsToRef(row, column);\n\n // Snapshot semantics preserved by treating SimpleSnapshot as an immutable data structure which is \n // replaced with a modified copy on every update. Yes, this is horribly inefficient. \n // For simplicity, setting a value to undefined stores it explicitly rather than removing it. Functional\n // behavior is the same.\n this.#content = {\n values: { ...curr.values, [ref]: { value, format }},\n rowCount: Math.max(curr.rowCount, row+1),\n colCount: Math.max(curr.colCount, column+1)\n }\n this.#notifyListeners();\n\n return true;\n }\n\n #notifyListeners() {\n for (const listener of this.#listeners)\n listener();\n }\n\n #listeners: (() => void)[];\n #content: SimpleSnapshotContent;\n}\n","import type { CellValue, SpreadsheetData, ItemOffsetMapping } from \"@candidstartup/infinisheet-types\";\n\ninterface LayeredSnapshotContent<BaseSnapshot, EditSnapshot> {\n base: BaseSnapshot,\n edit: EditSnapshot\n}\n\n/** \n * Branding Enum. Used by {@link LayeredSnapshot} to ensure that\n * you'll get a type error if you pass some random object where a `LayeredSnapshot`\n * is expected.\n * @internal\n */\nexport enum _LayeredSnapshotBrand { _DO_NOT_USE=\"\" };\n\n/**\n * Opaque type representing a {@link LayeredSpreadsheetData} snapshot. All the\n * internal implementation details are hidden from the exported API.\n */\nexport interface LayeredSnapshot<BaseSnapshot,EditSnapshot> {\n /** @internal */\n _brand: [ _LayeredSnapshotBrand, BaseSnapshot, EditSnapshot ]\n}\n\nfunction asContent<Base,Edit>(snapshot: LayeredSnapshot<Base,Edit>) {\n return snapshot as unknown as LayeredSnapshotContent<Base,Edit>;\n}\n\nfunction asSnapshot<Base,Edit>(snapshot: LayeredSnapshotContent<Base,Edit>) {\n return snapshot as unknown as LayeredSnapshot<Base,Edit>;\n}\n\n/**\n * Extracts the snapshot type from a {@link SpreadsheetData} instance\n */\nexport type SnapshotType<T> = T extends SpreadsheetData<infer TResult> ? TResult : never;\n\n/**\n * Implementation of {@link SpreadsheetData} that layers two other `SpreadsheetData` instances on top of each other.\n * \n * There's an \"edit\" layer on top where any changes are stored, with a \"base\" layer underneath. If a value is `undefined` in the edit layer, \n * the corresponding value is returned from the base layer instead.\n * \n * Common use case is a read only reference data source as the base layer with an initially empty edit layer that accepts changes.\n * \n * @typeParam BaseData - Type of base layer `SpreadsheetData` instance\n * @typeParam EditData - Type of edit layer `SpreadsheetData` instance\n * @typeParam BaseSnapshot - Type of snapshot used by `BaseData`. By default, inferred from `BaseData`.\n * @typeParam EditSnapshot - Type of snapshot used by `EditData`. By default, inferred from `EditData`.\n */\nexport class LayeredSpreadsheetData<BaseData extends SpreadsheetData<BaseSnapshot>, \n EditData extends SpreadsheetData<EditSnapshot>, BaseSnapshot = SnapshotType<BaseData>, EditSnapshot = SnapshotType<EditData>>\n implements SpreadsheetData<LayeredSnapshot<BaseSnapshot, EditSnapshot>> {\n\n /**\n * Creates a `LayeredSpreadsheetData` instance from two existing `SpreadsheetData` instances.\n * \n * All type parameters can be inferred from the constructor arguments.\n * \n * @param base - `SpreadsheetData` instance to use for the base layer\n * @param edit - `SpreadsheetData` instance to use for the edit layer\n */\n constructor(base: BaseData, edit: EditData) {\n this.#base = base;\n this.#edit = edit;\n }\n\n subscribe(onDataChange: () => void): () => void {\n const unsubscribeBase = this.#base.subscribe(onDataChange);\n const unsubscribeEdit = this.#edit.subscribe(onDataChange);\n return () => {\n unsubscribeBase();\n unsubscribeEdit();\n }\n }\n\n getSnapshot(): LayeredSnapshot<BaseSnapshot, EditSnapshot> {\n const baseSnapshot = this.#base.getSnapshot();\n const editSnapshot = this.#edit.getSnapshot();\n\n if (!this.#content || this.#content.base != baseSnapshot || this.#content.edit != editSnapshot) {\n this.#content = { base: baseSnapshot, edit: editSnapshot } ;\n }\n\n return asSnapshot(this.#content);\n }\n\n getRowCount(snapshot: LayeredSnapshot<BaseSnapshot, EditSnapshot>): number {\n const content = asContent(snapshot);\n return Math.max(this.#base.getRowCount(content.base), this.#edit.getRowCount(content.edit));\n }\n\n getRowItemOffsetMapping(snapshot: LayeredSnapshot<BaseSnapshot, EditSnapshot>): ItemOffsetMapping {\n return this.#base.getRowItemOffsetMapping(asContent(snapshot).base);\n }\n\n getColumnCount(snapshot: LayeredSnapshot<BaseSnapshot, EditSnapshot>): number {\n const content = asContent(snapshot);\n return Math.max(this.#base.getColumnCount(content.base), this.#edit.getColumnCount(content.edit));\n }\n\n getColumnItemOffsetMapping(snapshot: LayeredSnapshot<BaseSnapshot, EditSnapshot>): ItemOffsetMapping {\n return this.#base.getColumnItemOffsetMapping(asContent(snapshot).base);\n }\n\n getCellValue(snapshot: LayeredSnapshot<BaseSnapshot, EditSnapshot>, row: number, column: number): CellValue {\n const content = asContent(snapshot);\n const editValue = this.#edit.getCellValue(content.edit, row, column);\n if (editValue !== undefined)\n return editValue;\n\n return this.#base.getCellValue(content.base, row, column);\n }\n\n getCellFormat(snapshot: LayeredSnapshot<BaseSnapshot, EditSnapshot>, row: number, column: number): string | undefined {\n const content = asContent(snapshot);\n const editValue = this.#edit.getCellValue(content.edit, row, column);\n return (editValue === undefined) ? this.#base.getCellFormat(content.base, row, column) : this.#edit.getCellFormat(content.edit, row, column);\n }\n\n setCellValueAndFormat(row: number, column: number, value: CellValue, format: string | undefined): boolean {\n return this.#edit.setCellValueAndFormat(row, column, value, format);\n }\n\n #base: BaseData;\n #edit: EditData;\n #content: LayeredSnapshotContent<BaseSnapshot, EditSnapshot> | undefined;\n}\n"],"names":["asContent","asSnapshot"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@candidstartup/simple-spreadsheet-data",
3
+ "private": false,
4
+ "version": "0.8.0",
5
+ "description": "Reference implementations of SpreadsheetData",
6
+ "author": "Tim Wiegand <tim.wiegand@thecandidstartup.org>",
7
+ "license": "BSD-3-Clause",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/TheCandidStartup/infinisheet.git",
11
+ "directory": "packages/simple-spreadsheet-data"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/TheCandidStartup/infinisheet/issues"
15
+ },
16
+ "homepage": "https://github.com/TheCandidStartup/infinisheet/blob/main/packages/simple-spreadsheet-data/README.md",
17
+ "keywords": [
18
+ "typescript",
19
+ "spreadsheet",
20
+ "infinisheet"
21
+ ],
22
+ "publishConfig": {
23
+ "access": "public"
24
+ },
25
+ "type": "module",
26
+ "files": [
27
+ "dist"
28
+ ],
29
+ "module": "./dist/index.js",
30
+ "types": "./dist/index.d.ts",
31
+ "exports": {
32
+ ".": {
33
+ "types": "./dist/index.d.ts",
34
+ "import": "./dist/index.js"
35
+ }
36
+ },
37
+ "scripts": {
38
+ "dev": "vite",
39
+ "clean": "rimraf {dist,temp}",
40
+ "prebuild": "npm run clean",
41
+ "typecheck": "tsc -p tsconfig.json",
42
+ "build-tsc": "tsc -p tsconfig.build.json",
43
+ "build-rollup": "rollup -c ../rollup.config.mjs",
44
+ "build": "npm run build-rollup",
45
+ "lint": "eslint . --report-unused-disable-directives --max-warnings 0",
46
+ "devapi": "api-extractor run --local",
47
+ "prodapi": "api-extractor run",
48
+ "devbuild": "npm run build && npm run lint && npm run devapi",
49
+ "test": "vitest"
50
+ },
51
+ "dependencies": {
52
+ "@candidstartup/infinisheet-types": "^0.8.0"
53
+ },
54
+ "gitHead": "5f783ed7b6eef96cbc72fb8972ba04d6033f9ece"
55
+ }