@dxos/plugin-sheet 0.6.8-main.046e6cf

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.
Files changed (147) hide show
  1. package/LICENSE +8 -0
  2. package/README.md +14 -0
  3. package/dist/lib/browser/SheetContainer-H22IDJ43.mjs +3740 -0
  4. package/dist/lib/browser/SheetContainer-H22IDJ43.mjs.map +7 -0
  5. package/dist/lib/browser/chunk-6VPEAUG6.mjs +82 -0
  6. package/dist/lib/browser/chunk-6VPEAUG6.mjs.map +7 -0
  7. package/dist/lib/browser/chunk-AT2FJXQX.mjs +861 -0
  8. package/dist/lib/browser/chunk-AT2FJXQX.mjs.map +7 -0
  9. package/dist/lib/browser/chunk-JRL5LGCE.mjs +18 -0
  10. package/dist/lib/browser/chunk-JRL5LGCE.mjs.map +7 -0
  11. package/dist/lib/browser/index.mjs +213 -0
  12. package/dist/lib/browser/index.mjs.map +7 -0
  13. package/dist/lib/browser/meta.json +1 -0
  14. package/dist/lib/browser/meta.mjs +9 -0
  15. package/dist/lib/browser/meta.mjs.map +7 -0
  16. package/dist/lib/browser/types.mjs +22 -0
  17. package/dist/lib/browser/types.mjs.map +7 -0
  18. package/dist/lib/node/SheetContainer-S32KTNZ6.cjs +3731 -0
  19. package/dist/lib/node/SheetContainer-S32KTNZ6.cjs.map +7 -0
  20. package/dist/lib/node/chunk-4CE6FK5Z.cjs +108 -0
  21. package/dist/lib/node/chunk-4CE6FK5Z.cjs.map +7 -0
  22. package/dist/lib/node/chunk-BJ6ZD7MN.cjs +51 -0
  23. package/dist/lib/node/chunk-BJ6ZD7MN.cjs.map +7 -0
  24. package/dist/lib/node/chunk-FCKJ4QRM.cjs +881 -0
  25. package/dist/lib/node/chunk-FCKJ4QRM.cjs.map +7 -0
  26. package/dist/lib/node/index.cjs +226 -0
  27. package/dist/lib/node/index.cjs.map +7 -0
  28. package/dist/lib/node/meta.cjs +30 -0
  29. package/dist/lib/node/meta.cjs.map +7 -0
  30. package/dist/lib/node/meta.json +1 -0
  31. package/dist/lib/node/types.cjs +44 -0
  32. package/dist/lib/node/types.cjs.map +7 -0
  33. package/dist/types/src/SheetPlugin.d.ts +4 -0
  34. package/dist/types/src/SheetPlugin.d.ts.map +1 -0
  35. package/dist/types/src/components/CellEditor/CellEditor.d.ts +14 -0
  36. package/dist/types/src/components/CellEditor/CellEditor.d.ts.map +1 -0
  37. package/dist/types/src/components/CellEditor/CellEditor.stories.d.ts +29 -0
  38. package/dist/types/src/components/CellEditor/CellEditor.stories.d.ts.map +1 -0
  39. package/dist/types/src/components/CellEditor/extension.d.ts +18 -0
  40. package/dist/types/src/components/CellEditor/extension.d.ts.map +1 -0
  41. package/dist/types/src/components/CellEditor/extension.test.d.ts +2 -0
  42. package/dist/types/src/components/CellEditor/extension.test.d.ts.map +1 -0
  43. package/dist/types/src/components/CellEditor/functions.d.ts +66 -0
  44. package/dist/types/src/components/CellEditor/functions.d.ts.map +1 -0
  45. package/dist/types/src/components/CellEditor/index.d.ts +3 -0
  46. package/dist/types/src/components/CellEditor/index.d.ts.map +1 -0
  47. package/dist/types/src/components/ComputeGraph/async-function.d.ts +52 -0
  48. package/dist/types/src/components/ComputeGraph/async-function.d.ts.map +1 -0
  49. package/dist/types/src/components/ComputeGraph/custom.d.ts +21 -0
  50. package/dist/types/src/components/ComputeGraph/custom.d.ts.map +1 -0
  51. package/dist/types/src/components/ComputeGraph/edge-function.d.ts +20 -0
  52. package/dist/types/src/components/ComputeGraph/edge-function.d.ts.map +1 -0
  53. package/dist/types/src/components/ComputeGraph/graph-context.d.ts +11 -0
  54. package/dist/types/src/components/ComputeGraph/graph-context.d.ts.map +1 -0
  55. package/dist/types/src/components/ComputeGraph/graph.browser.test.d.ts +2 -0
  56. package/dist/types/src/components/ComputeGraph/graph.browser.test.d.ts.map +1 -0
  57. package/dist/types/src/components/ComputeGraph/graph.d.ts +21 -0
  58. package/dist/types/src/components/ComputeGraph/graph.d.ts.map +1 -0
  59. package/dist/types/src/components/ComputeGraph/index.d.ts +4 -0
  60. package/dist/types/src/components/ComputeGraph/index.d.ts.map +1 -0
  61. package/dist/types/src/components/Sheet/Sheet.d.ts +55 -0
  62. package/dist/types/src/components/Sheet/Sheet.d.ts.map +1 -0
  63. package/dist/types/src/components/Sheet/Sheet.stories.d.ts +54 -0
  64. package/dist/types/src/components/Sheet/Sheet.stories.d.ts.map +1 -0
  65. package/dist/types/src/components/Sheet/formatting.d.ts +14 -0
  66. package/dist/types/src/components/Sheet/formatting.d.ts.map +1 -0
  67. package/dist/types/src/components/Sheet/grid.d.ts +52 -0
  68. package/dist/types/src/components/Sheet/grid.d.ts.map +1 -0
  69. package/dist/types/src/components/Sheet/index.d.ts +2 -0
  70. package/dist/types/src/components/Sheet/index.d.ts.map +1 -0
  71. package/dist/types/src/components/Sheet/nav.d.ts +29 -0
  72. package/dist/types/src/components/Sheet/nav.d.ts.map +1 -0
  73. package/dist/types/src/components/Sheet/sheet-context.d.ts +24 -0
  74. package/dist/types/src/components/Sheet/sheet-context.d.ts.map +1 -0
  75. package/dist/types/src/components/Sheet/util.d.ts +18 -0
  76. package/dist/types/src/components/Sheet/util.d.ts.map +1 -0
  77. package/dist/types/src/components/SheetContainer.d.ts +9 -0
  78. package/dist/types/src/components/SheetContainer.d.ts.map +1 -0
  79. package/dist/types/src/components/Toolbar/Toolbar.d.ts +21 -0
  80. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -0
  81. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts +35 -0
  82. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -0
  83. package/dist/types/src/components/Toolbar/common.d.ts +20 -0
  84. package/dist/types/src/components/Toolbar/common.d.ts.map +1 -0
  85. package/dist/types/src/components/Toolbar/index.d.ts +2 -0
  86. package/dist/types/src/components/Toolbar/index.d.ts.map +1 -0
  87. package/dist/types/src/components/index.d.ts +7 -0
  88. package/dist/types/src/components/index.d.ts.map +1 -0
  89. package/dist/types/src/index.d.ts +4 -0
  90. package/dist/types/src/index.d.ts.map +1 -0
  91. package/dist/types/src/meta.d.ts +15 -0
  92. package/dist/types/src/meta.d.ts.map +1 -0
  93. package/dist/types/src/model/index.d.ts +3 -0
  94. package/dist/types/src/model/index.d.ts.map +1 -0
  95. package/dist/types/src/model/model.browser.test.d.ts +2 -0
  96. package/dist/types/src/model/model.browser.test.d.ts.map +1 -0
  97. package/dist/types/src/model/model.d.ts +142 -0
  98. package/dist/types/src/model/model.d.ts.map +1 -0
  99. package/dist/types/src/model/types.d.ts +17 -0
  100. package/dist/types/src/model/types.d.ts.map +1 -0
  101. package/dist/types/src/model/types.test.d.ts +2 -0
  102. package/dist/types/src/model/types.test.d.ts.map +1 -0
  103. package/dist/types/src/model/util.d.ts +15 -0
  104. package/dist/types/src/model/util.d.ts.map +1 -0
  105. package/dist/types/src/translations.d.ts +16 -0
  106. package/dist/types/src/translations.d.ts.map +1 -0
  107. package/dist/types/src/types.d.ts +94 -0
  108. package/dist/types/src/types.d.ts.map +1 -0
  109. package/package.json +122 -0
  110. package/src/SheetPlugin.tsx +150 -0
  111. package/src/components/CellEditor/CellEditor.stories.tsx +88 -0
  112. package/src/components/CellEditor/CellEditor.tsx +113 -0
  113. package/src/components/CellEditor/extension.test.ts +42 -0
  114. package/src/components/CellEditor/extension.ts +286 -0
  115. package/src/components/CellEditor/functions.ts +2017 -0
  116. package/src/components/CellEditor/index.ts +6 -0
  117. package/src/components/ComputeGraph/async-function.ts +148 -0
  118. package/src/components/ComputeGraph/custom.ts +70 -0
  119. package/src/components/ComputeGraph/edge-function.ts +60 -0
  120. package/src/components/ComputeGraph/graph-context.tsx +37 -0
  121. package/src/components/ComputeGraph/graph.browser.test.ts +49 -0
  122. package/src/components/ComputeGraph/graph.ts +52 -0
  123. package/src/components/ComputeGraph/index.ts +7 -0
  124. package/src/components/Sheet/Sheet.stories.tsx +329 -0
  125. package/src/components/Sheet/Sheet.tsx +1164 -0
  126. package/src/components/Sheet/formatting.ts +106 -0
  127. package/src/components/Sheet/grid.ts +191 -0
  128. package/src/components/Sheet/index.ts +5 -0
  129. package/src/components/Sheet/nav.ts +157 -0
  130. package/src/components/Sheet/sheet-context.tsx +101 -0
  131. package/src/components/Sheet/util.ts +56 -0
  132. package/src/components/SheetContainer.tsx +30 -0
  133. package/src/components/Toolbar/Toolbar.stories.tsx +36 -0
  134. package/src/components/Toolbar/Toolbar.tsx +198 -0
  135. package/src/components/Toolbar/common.tsx +72 -0
  136. package/src/components/Toolbar/index.ts +5 -0
  137. package/src/components/index.ts +10 -0
  138. package/src/index.ts +9 -0
  139. package/src/meta.tsx +18 -0
  140. package/src/model/index.ts +6 -0
  141. package/src/model/model.browser.test.ts +100 -0
  142. package/src/model/model.ts +480 -0
  143. package/src/model/types.test.ts +92 -0
  144. package/src/model/types.ts +71 -0
  145. package/src/model/util.ts +36 -0
  146. package/src/translations.ts +22 -0
  147. package/src/types.ts +110 -0
@@ -0,0 +1,861 @@
1
+ import {
2
+ ValueTypeEnum
3
+ } from "./chunk-6VPEAUG6.mjs";
4
+
5
+ // packages/plugins/plugin-sheet/src/components/ComputeGraph/graph.ts
6
+ import { HyperFormula } from "hyperformula";
7
+ import { Event } from "@dxos/async";
8
+ import { PublicKey } from "@dxos/keys";
9
+ import { log as log2 } from "@dxos/log";
10
+
11
+ // packages/plugins/plugin-sheet/src/components/ComputeGraph/async-function.ts
12
+ import { CellError, ErrorType, EmptyValue, FunctionPlugin } from "hyperformula";
13
+ import { debounce } from "@dxos/async";
14
+ import { log } from "@dxos/log";
15
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/plugins/plugin-sheet/src/components/ComputeGraph/async-function.ts";
16
+ var defaultFunctionContextOptions = {
17
+ defaultTtl: 5e3,
18
+ recalculationDelay: 200
19
+ };
20
+ var FunctionContext = class _FunctionContext {
21
+ // Mangle name with params.
22
+ static createInvocationKey(name, ...args) {
23
+ return JSON.stringify({
24
+ name,
25
+ ...args
26
+ });
27
+ }
28
+ constructor(_hf, _space, onUpdate, _options = defaultFunctionContextOptions) {
29
+ this._hf = _hf;
30
+ this._space = _space;
31
+ this._options = _options;
32
+ this._cache = /* @__PURE__ */ new Map();
33
+ this._pending = /* @__PURE__ */ new Map();
34
+ this._invocations = {};
35
+ this._onUpdate = debounce(() => {
36
+ this._hf.resumeEvaluation();
37
+ onUpdate(this);
38
+ }, this._options.recalculationDelay);
39
+ }
40
+ get space() {
41
+ return this._space;
42
+ }
43
+ get info() {
44
+ return {
45
+ cache: this._cache.size,
46
+ invocations: this._invocations
47
+ };
48
+ }
49
+ flush() {
50
+ this._cache.clear();
51
+ this._invocations = {};
52
+ }
53
+ /**
54
+ * Exec the function if TTL has expired.
55
+ * Return the cached value.
56
+ */
57
+ invokeFunction(name, state, args, cb, options) {
58
+ const ttl = options?.ttl ?? this._options.defaultTtl;
59
+ const { formulaAddress: cell } = state;
60
+ const invocationKey = _FunctionContext.createInvocationKey(name, ...args);
61
+ const { value = void 0, ts = 0 } = this._cache.get(invocationKey) ?? {};
62
+ const now = Date.now();
63
+ const delta = now - ts;
64
+ if ((!ts || delta > ttl) && !this._pending.has(invocationKey)) {
65
+ this._pending.set(invocationKey, now);
66
+ setTimeout(async () => {
67
+ this._invocations[name] = (this._invocations[name] ?? 0) + 1;
68
+ try {
69
+ const value2 = await cb(...args);
70
+ this._cache.set(invocationKey, {
71
+ value: value2,
72
+ ts: Date.now()
73
+ });
74
+ log("set", {
75
+ cell,
76
+ value: value2
77
+ }, {
78
+ F: __dxlog_file,
79
+ L: 116,
80
+ S: this,
81
+ C: (f, a) => f(...a)
82
+ });
83
+ this._onUpdate();
84
+ } catch (err) {
85
+ log.warn("failed", {
86
+ cell,
87
+ err
88
+ }, {
89
+ F: __dxlog_file,
90
+ L: 120,
91
+ S: this,
92
+ C: (f, a) => f(...a)
93
+ });
94
+ this._cache.set(invocationKey, {
95
+ value: new CellError(ErrorType.ERROR, "Function failed."),
96
+ ts: Date.now()
97
+ });
98
+ } finally {
99
+ this._pending.delete(invocationKey);
100
+ }
101
+ });
102
+ }
103
+ log("invoke", {
104
+ cell,
105
+ name,
106
+ args,
107
+ cache: value
108
+ }, {
109
+ F: __dxlog_file,
110
+ L: 128,
111
+ S: this,
112
+ C: (f, a) => f(...a)
113
+ });
114
+ return value;
115
+ }
116
+ };
117
+ var FunctionPluginAsync = class extends FunctionPlugin {
118
+ get context() {
119
+ return this.config.context;
120
+ }
121
+ runAsyncFunction(ast, state, cb, options) {
122
+ const { procedureName } = ast;
123
+ const metadata = this.metadata(procedureName);
124
+ return this.runFunction(ast.args, state, metadata, (...args) => {
125
+ return this.context.invokeFunction(procedureName, state, args, cb, options) ?? EmptyValue;
126
+ });
127
+ }
128
+ };
129
+
130
+ // packages/plugins/plugin-sheet/src/components/ComputeGraph/custom.ts
131
+ import { FunctionArgumentType } from "hyperformula";
132
+ import { getDeep } from "@dxos/util";
133
+ var parseNumberString = (str) => {
134
+ return parseFloat(str.replace(/[^\d.]/g, ""));
135
+ };
136
+ var CustomPlugin = class extends FunctionPluginAsync {
137
+ test(ast, state) {
138
+ const handler = async () => {
139
+ return Math.random();
140
+ };
141
+ return this.runAsyncFunction(ast, state, handler);
142
+ }
143
+ crypto(ast, state) {
144
+ const handler = async (_currency) => {
145
+ const currency = (_currency || "USD").toUpperCase();
146
+ const result = await fetch(`https://api.coindesk.com/v1/bpi/currentprice/${currency}.json`);
147
+ const data = await result.json();
148
+ const rate = getDeep(data, [
149
+ "bpi",
150
+ currency,
151
+ "rate"
152
+ ]);
153
+ if (!rate) {
154
+ return NaN;
155
+ }
156
+ return parseNumberString(rate);
157
+ };
158
+ return this.runAsyncFunction(ast, state, handler, {
159
+ ttl: 1e4
160
+ });
161
+ }
162
+ };
163
+ CustomPlugin.implementedFunctions = {
164
+ TEST: {
165
+ method: "test",
166
+ parameters: [],
167
+ isVolatile: true
168
+ },
169
+ CRYPTO: {
170
+ method: "crypto",
171
+ parameters: [
172
+ {
173
+ argumentType: FunctionArgumentType.STRING,
174
+ optionalArg: true
175
+ }
176
+ ],
177
+ isVolatile: true
178
+ }
179
+ };
180
+ var CustomPluginTranslations = {
181
+ enGB: {
182
+ TEST: "TEST",
183
+ CRYPTO: "CRYPTO"
184
+ },
185
+ enUS: {
186
+ TEST: "TEST",
187
+ CRYPTO: "CRYPTO"
188
+ }
189
+ };
190
+
191
+ // packages/plugins/plugin-sheet/src/components/ComputeGraph/edge-function.ts
192
+ import { CellError as CellError2, ErrorType as ErrorType2, FunctionArgumentType as FunctionArgumentType2 } from "hyperformula";
193
+ import { Filter, getMeta } from "@dxos/client/echo";
194
+ import { getUserFunctionUrlInMetadata } from "@dxos/plugin-script/edge";
195
+ import { ScriptType } from "@dxos/plugin-script/types";
196
+ var EdgeFunctionPlugin = class extends FunctionPluginAsync {
197
+ edge(ast, state) {
198
+ const handler = async (binding) => {
199
+ const space = this.context.space;
200
+ if (!space) {
201
+ return new CellError2(ErrorType2.VALUE, "No space");
202
+ }
203
+ const { objects: [script] } = await space.db.query(Filter.schema(ScriptType, {
204
+ binding
205
+ })).run();
206
+ if (!script) {
207
+ return new CellError2(ErrorType2.VALUE, "No script");
208
+ }
209
+ const path = getUserFunctionUrlInMetadata(getMeta(script));
210
+ const result = await fetch(`https://functions-staging.dxos.workers.dev${path}`, {
211
+ method: "POST"
212
+ });
213
+ return await result.text();
214
+ };
215
+ return this.runAsyncFunction(ast, state, handler, {
216
+ ttl: 1e4
217
+ });
218
+ }
219
+ };
220
+ EdgeFunctionPlugin.implementedFunctions = {
221
+ EDGE: {
222
+ method: "edge",
223
+ parameters: [
224
+ {
225
+ argumentType: FunctionArgumentType2.STRING
226
+ }
227
+ ],
228
+ isVolatile: true
229
+ }
230
+ };
231
+ var EdgeFunctionPluginTranslations = {
232
+ enGB: {
233
+ EDGE: "EDGE"
234
+ },
235
+ enUS: {
236
+ EDGE: "EDGE"
237
+ }
238
+ };
239
+
240
+ // packages/plugins/plugin-sheet/src/components/ComputeGraph/graph.ts
241
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/plugins/plugin-sheet/src/components/ComputeGraph/graph.ts";
242
+ var createComputeGraph = (space) => {
243
+ HyperFormula.registerFunctionPlugin(CustomPlugin, CustomPluginTranslations);
244
+ HyperFormula.registerFunctionPlugin(EdgeFunctionPlugin, EdgeFunctionPluginTranslations);
245
+ const hf = HyperFormula.buildEmpty({
246
+ licenseKey: "gpl-v3"
247
+ });
248
+ return new ComputeGraph(hf, space);
249
+ };
250
+ var ComputeGraph = class {
251
+ constructor(hf, _space) {
252
+ this.hf = hf;
253
+ this._space = _space;
254
+ this.id = `graph-${PublicKey.random().truncate()}`;
255
+ this.update = new Event();
256
+ this.context = new FunctionContext(this.hf, this._space, () => {
257
+ this.refresh();
258
+ });
259
+ this.hf.updateConfig({
260
+ context: this.context
261
+ });
262
+ }
263
+ refresh() {
264
+ log2("refresh", {
265
+ id: this.id
266
+ }, {
267
+ F: __dxlog_file2,
268
+ L: 49,
269
+ S: this,
270
+ C: (f, a) => f(...a)
271
+ });
272
+ this.update.emit();
273
+ }
274
+ };
275
+
276
+ // packages/plugins/plugin-sheet/src/components/ComputeGraph/graph-context.tsx
277
+ import React, { createContext, useContext, useEffect } from "react";
278
+ var ComputeGraphContext = /* @__PURE__ */ createContext({
279
+ graphs: {},
280
+ setGraph: () => {
281
+ }
282
+ });
283
+ var ComputeGraphContextProvider = ({ children, graphs, setGraph }) => {
284
+ return /* @__PURE__ */ React.createElement(ComputeGraphContext.Provider, {
285
+ value: {
286
+ graphs,
287
+ setGraph
288
+ }
289
+ }, children);
290
+ };
291
+ var useComputeGraph = (space) => {
292
+ const { graphs, setGraph } = useContext(ComputeGraphContext);
293
+ const graph = graphs[space.id] ?? createComputeGraph(space);
294
+ useEffect(() => {
295
+ if (!graphs[space.id]) {
296
+ setGraph(space.id, graph);
297
+ }
298
+ }, [
299
+ space
300
+ ]);
301
+ return graph;
302
+ };
303
+
304
+ // packages/plugins/plugin-sheet/src/model/types.ts
305
+ import { invariant } from "@dxos/invariant";
306
+ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/plugins/plugin-sheet/src/model/types.ts";
307
+ var MAX_COLUMNS = 26 * 26;
308
+ var posEquals = (a, b) => {
309
+ return a?.column === b?.column && a?.row === b?.row;
310
+ };
311
+ var columnLetter = (column) => {
312
+ invariant(column < MAX_COLUMNS, `Invalid column: ${column}`, {
313
+ F: __dxlog_file3,
314
+ L: 17,
315
+ S: void 0,
316
+ A: [
317
+ "column < MAX_COLUMNS",
318
+ "`Invalid column: ${column}`"
319
+ ]
320
+ });
321
+ return (column >= 26 ? String.fromCharCode("A".charCodeAt(0) + Math.floor(column / 26) - 1) : "") + String.fromCharCode("A".charCodeAt(0) + column % 26);
322
+ };
323
+ var addressToA1Notation = ({ column, row }) => {
324
+ return `${columnLetter(column)}${row + 1}`;
325
+ };
326
+ var addressFromA1Notation = (ref) => {
327
+ const match = ref.match(/([A-Z]+)(\d+)/);
328
+ invariant(match, `Invalid notation: ${ref}`, {
329
+ F: __dxlog_file3,
330
+ L: 30,
331
+ S: void 0,
332
+ A: [
333
+ "match",
334
+ "`Invalid notation: ${ref}`"
335
+ ]
336
+ });
337
+ return {
338
+ row: parseInt(match[2], 10) - 1,
339
+ column: match[1].split("").reduce((acc, c) => acc * 26 + c.charCodeAt(0) - "A".charCodeAt(0) + 1, 0) - 1
340
+ };
341
+ };
342
+ var rangeToA1Notation = (range) => {
343
+ return [
344
+ range?.from && addressToA1Notation(range?.from),
345
+ range?.to && addressToA1Notation(range?.to)
346
+ ].filter(Boolean).join(":");
347
+ };
348
+ var inRange = (range, cell) => {
349
+ if (!range) {
350
+ return false;
351
+ }
352
+ const { from, to } = range;
353
+ if (from && posEquals(from, cell) || to && posEquals(to, cell)) {
354
+ return true;
355
+ }
356
+ if (!from || !to) {
357
+ return false;
358
+ }
359
+ const { column: c1, row: r1 } = from;
360
+ const { column: c2, row: r2 } = to;
361
+ const cMin = Math.min(c1, c2);
362
+ const cMax = Math.max(c1, c2);
363
+ const rMin = Math.min(r1, r2);
364
+ const rMax = Math.max(r1, r2);
365
+ const { column, row } = cell;
366
+ return column >= cMin && column <= cMax && row >= rMin && row <= rMax;
367
+ };
368
+
369
+ // packages/plugins/plugin-sheet/src/model/model.ts
370
+ import { DetailedCellError, ExportedCellChange } from "hyperformula";
371
+ import { Event as Event2 } from "@dxos/async";
372
+ import { Context } from "@dxos/context";
373
+ import { invariant as invariant2 } from "@dxos/invariant";
374
+ import { PublicKey as PublicKey2 } from "@dxos/keys";
375
+ import { log as log3 } from "@dxos/log";
376
+
377
+ // packages/plugins/plugin-sheet/src/model/util.ts
378
+ import { randomBytes } from "@dxos/crypto";
379
+ var ApiError = class extends Error {
380
+ };
381
+ var ReadonlyException = class extends ApiError {
382
+ };
383
+ var RangeException = class extends ApiError {
384
+ constructor(n) {
385
+ super();
386
+ }
387
+ };
388
+ var createIndex = (length = 8) => {
389
+ const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
390
+ const charactersLength = characters.length;
391
+ const randomBuffer = randomBytes(length);
392
+ return Array.from(randomBuffer, (byte) => characters[byte % charactersLength]).join("");
393
+ };
394
+ var createIndices = (length) => Array.from({
395
+ length
396
+ }).map(() => createIndex());
397
+
398
+ // packages/plugins/plugin-sheet/src/model/model.ts
399
+ var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/plugins/plugin-sheet/src/model/model.ts";
400
+ var DEFAULT_ROWS = 500;
401
+ var DEFAULT_COLUMNS = 26 * 2;
402
+ var typeMap = {
403
+ BOOLEAN: ValueTypeEnum.Boolean,
404
+ NUMBER_RAW: ValueTypeEnum.Number,
405
+ NUMBER_PERCENT: ValueTypeEnum.Percent,
406
+ NUMBER_CURRENCY: ValueTypeEnum.Currency,
407
+ NUMBER_DATETIME: ValueTypeEnum.DateTime,
408
+ NUMBER_DATE: ValueTypeEnum.Date,
409
+ NUMBER_TIME: ValueTypeEnum.Time
410
+ };
411
+ var defaultOptions = {
412
+ rows: 50,
413
+ columns: 26
414
+ };
415
+ var getTopLeft = (range) => {
416
+ const to = range.to ?? range.from;
417
+ return {
418
+ row: Math.min(range.from.row, to.row),
419
+ column: Math.min(range.from.column, to.column)
420
+ };
421
+ };
422
+ var toSimpleCellAddress = (sheet, cell) => ({
423
+ sheet,
424
+ row: cell.row,
425
+ col: cell.column
426
+ });
427
+ var toModelRange = (sheet, range) => ({
428
+ start: toSimpleCellAddress(sheet, range.from),
429
+ end: toSimpleCellAddress(sheet, range.to ?? range.from)
430
+ });
431
+ var SheetModel = class {
432
+ constructor(_graph, _sheet, options = {}) {
433
+ this._graph = _graph;
434
+ this._sheet = _sheet;
435
+ this.id = `model-${PublicKey2.random().truncate()}`;
436
+ this._ctx = void 0;
437
+ this.update = new Event2();
438
+ const name = this._sheet.id;
439
+ if (!this._graph.hf.doesSheetExist(name)) {
440
+ this._graph.hf.addSheet(name);
441
+ }
442
+ this._sheetId = this._graph.hf.getSheetId(name);
443
+ this._options = {
444
+ ...defaultOptions,
445
+ ...options
446
+ };
447
+ this.reset();
448
+ }
449
+ get graph() {
450
+ return this._graph;
451
+ }
452
+ get sheet() {
453
+ return this._sheet;
454
+ }
455
+ get readonly() {
456
+ return this._options.readonly;
457
+ }
458
+ get bounds() {
459
+ return {
460
+ rows: this._sheet.rows.length,
461
+ columns: this._sheet.columns.length
462
+ };
463
+ }
464
+ get functions() {
465
+ return this._graph.hf.getRegisteredFunctionNames();
466
+ }
467
+ get initialized() {
468
+ return !!this._ctx;
469
+ }
470
+ /**
471
+ * Initialize sheet and engine.
472
+ */
473
+ async initialize() {
474
+ log3("initialize", {
475
+ id: this.id
476
+ }, {
477
+ F: __dxlog_file4,
478
+ L: 130,
479
+ S: this,
480
+ C: (f, a) => f(...a)
481
+ });
482
+ invariant2(!this.initialized, "Already initialized.", {
483
+ F: __dxlog_file4,
484
+ L: 131,
485
+ S: this,
486
+ A: [
487
+ "!this.initialized",
488
+ "'Already initialized.'"
489
+ ]
490
+ });
491
+ this._ctx = new Context(void 0, {
492
+ F: __dxlog_file4,
493
+ L: 132
494
+ });
495
+ if (!this._sheet.rows.length) {
496
+ this._insertIndices(this._sheet.rows, 0, this._options.rows, DEFAULT_ROWS);
497
+ }
498
+ if (!this._sheet.columns.length) {
499
+ this._insertIndices(this._sheet.columns, 0, this._options.columns, DEFAULT_COLUMNS);
500
+ }
501
+ this.reset();
502
+ const unsubscribe = this._graph.update.on(() => this.update.emit());
503
+ this._ctx.onDispose(unsubscribe);
504
+ return this;
505
+ }
506
+ async destroy() {
507
+ log3("destroy", {
508
+ id: this.id
509
+ }, {
510
+ F: __dxlog_file4,
511
+ L: 149,
512
+ S: this,
513
+ C: (f, a) => f(...a)
514
+ });
515
+ if (this._ctx) {
516
+ await this._ctx.dispose();
517
+ this._ctx = void 0;
518
+ }
519
+ }
520
+ /**
521
+ * Update engine.
522
+ * NOTE: This resets the undo history.
523
+ * @deprecated
524
+ */
525
+ reset() {
526
+ this._graph.hf.clearSheet(this._sheetId);
527
+ Object.entries(this._sheet.cells).forEach(([key, { value }]) => {
528
+ const { column, row } = this.addressFromIndex(key);
529
+ if (typeof value === "string" && value.charAt(0) === "=") {
530
+ value = this.mapFormulaIndicesToRefs(value);
531
+ }
532
+ this._graph.hf.setCellContents({
533
+ sheet: this._sheetId,
534
+ row,
535
+ col: column
536
+ }, value);
537
+ });
538
+ }
539
+ /**
540
+ * Recalculate formulas.
541
+ * NOTE: This resets the undo history.
542
+ * https://hyperformula.handsontable.com/guide/volatile-functions.html#volatile-actions
543
+ * @deprecated
544
+ */
545
+ // TODO(burdon): Remove.
546
+ recalculate() {
547
+ this._graph.hf.rebuildAndRecalculate();
548
+ }
549
+ insertRows(i, n = 1) {
550
+ this._insertIndices(this._sheet.rows, i, n, DEFAULT_ROWS);
551
+ this.reset();
552
+ }
553
+ insertColumns(i, n = 1) {
554
+ this._insertIndices(this._sheet.columns, i, n, DEFAULT_COLUMNS);
555
+ this.reset();
556
+ }
557
+ //
558
+ // Undoable actions.
559
+ // TODO(burdon): Group undoable methods; consistently update hf/sheet.
560
+ //
561
+ /**
562
+ * Clear range of values.
563
+ */
564
+ clear(range) {
565
+ const topLeft = getTopLeft(range);
566
+ const values = this._iterRange(range, () => null);
567
+ this._graph.hf.setCellContents(toSimpleCellAddress(this._sheetId, topLeft), values);
568
+ this._iterRange(range, (cell) => {
569
+ const idx = this.addressToIndex(cell);
570
+ delete this._sheet.cells[idx];
571
+ });
572
+ }
573
+ cut(range) {
574
+ this._graph.hf.cut(toModelRange(this._sheetId, range));
575
+ this._iterRange(range, (cell) => {
576
+ const idx = this.addressToIndex(cell);
577
+ delete this._sheet.cells[idx];
578
+ });
579
+ }
580
+ copy(range) {
581
+ this._graph.hf.copy(toModelRange(this._sheetId, range));
582
+ }
583
+ paste(cell) {
584
+ if (!this._graph.hf.isClipboardEmpty()) {
585
+ const changes = this._graph.hf.paste(toSimpleCellAddress(this._sheetId, cell));
586
+ for (const change of changes) {
587
+ if (change instanceof ExportedCellChange) {
588
+ const { address, newValue } = change;
589
+ const idx = this.addressToIndex({
590
+ row: address.row,
591
+ column: address.col
592
+ });
593
+ this._sheet.cells[idx] = {
594
+ value: newValue
595
+ };
596
+ }
597
+ }
598
+ }
599
+ }
600
+ // TODO(burdon): Display undo/redo state.
601
+ undo() {
602
+ if (this._graph.hf.isThereSomethingToUndo()) {
603
+ this._graph.hf.undo();
604
+ this.update.emit();
605
+ }
606
+ }
607
+ redo() {
608
+ if (this._graph.hf.isThereSomethingToRedo()) {
609
+ this._graph.hf.redo();
610
+ this.update.emit();
611
+ }
612
+ }
613
+ /**
614
+ * Get value from sheet.
615
+ */
616
+ getCellValue(cell) {
617
+ const idx = this.addressToIndex(cell);
618
+ return this._sheet.cells[idx]?.value ?? null;
619
+ }
620
+ /**
621
+ * Get value as a string for editing.
622
+ */
623
+ getCellText(cell) {
624
+ const value = this.getCellValue(cell);
625
+ if (value == null) {
626
+ return void 0;
627
+ }
628
+ if (typeof value === "string" && value.charAt(0) === "=") {
629
+ return this.mapFormulaIndicesToRefs(value);
630
+ } else {
631
+ return String(value);
632
+ }
633
+ }
634
+ /**
635
+ * Get array of raw values from sheet.
636
+ */
637
+ getCellValues(range) {
638
+ return this._iterRange(range, (cell) => this.getCellValue(cell));
639
+ }
640
+ /**
641
+ * Gets the regular or computed value from the engine.
642
+ */
643
+ getValue(cell) {
644
+ const value = this._graph.hf.getCellValue(toSimpleCellAddress(this._sheetId, cell));
645
+ if (value instanceof DetailedCellError) {
646
+ return value.toString();
647
+ }
648
+ return value;
649
+ }
650
+ /**
651
+ * Get value type.
652
+ */
653
+ getValueType(cell) {
654
+ const addr = toSimpleCellAddress(this._sheetId, cell);
655
+ const type = this._graph.hf.getCellValueDetailedType(addr);
656
+ return typeMap[type];
657
+ }
658
+ /**
659
+ * Sets the value, updating the sheet and engine.
660
+ */
661
+ setValue(cell, value) {
662
+ if (this._options.readonly) {
663
+ throw new ReadonlyException();
664
+ }
665
+ let refresh = false;
666
+ if (cell.row >= this._sheet.rows.length) {
667
+ this._insertIndices(this._sheet.rows, cell.row, 1, DEFAULT_ROWS);
668
+ refresh = true;
669
+ }
670
+ if (cell.column >= this._sheet.columns.length) {
671
+ this._insertIndices(this._sheet.columns, cell.column, 1, DEFAULT_COLUMNS);
672
+ refresh = true;
673
+ }
674
+ if (refresh) {
675
+ this.reset();
676
+ }
677
+ this._graph.hf.setCellContents({
678
+ sheet: this._sheetId,
679
+ row: cell.row,
680
+ col: cell.column
681
+ }, [
682
+ [
683
+ value
684
+ ]
685
+ ]);
686
+ const idx = this.addressToIndex(cell);
687
+ if (value === void 0 || value === null) {
688
+ delete this._sheet.cells[idx];
689
+ } else {
690
+ if (typeof value === "string" && value.charAt(0) === "=") {
691
+ value = this.mapFormulaRefsToIndices(value);
692
+ }
693
+ this._sheet.cells[idx] = {
694
+ value
695
+ };
696
+ }
697
+ }
698
+ /**
699
+ * Sets values from a simple map.
700
+ */
701
+ setValues(values) {
702
+ Object.entries(values).forEach(([key, { value }]) => {
703
+ this.setValue(addressFromA1Notation(key), value);
704
+ });
705
+ }
706
+ /**
707
+ * Iterate range.
708
+ */
709
+ _iterRange(range, cb) {
710
+ const to = range.to ?? range.from;
711
+ const rowRange = [
712
+ Math.min(range.from.row, to.row),
713
+ Math.max(range.from.row, to.row)
714
+ ];
715
+ const columnRange = [
716
+ Math.min(range.from.column, to.column),
717
+ Math.max(range.from.column, to.column)
718
+ ];
719
+ const rows = [];
720
+ for (let row = rowRange[0]; row <= rowRange[1]; row++) {
721
+ const rowCells = [];
722
+ for (let column = columnRange[0]; column <= columnRange[1]; column++) {
723
+ const value = cb({
724
+ row,
725
+ column
726
+ });
727
+ if (value !== void 0) {
728
+ rowCells.push(value);
729
+ }
730
+ }
731
+ rows.push(rowCells);
732
+ }
733
+ return rows;
734
+ }
735
+ /**
736
+ *
737
+ */
738
+ // TODO(burdon): Insert indices into sheet.
739
+ _insertIndices(indices, i, n, max) {
740
+ if (i + n > max) {
741
+ throw new RangeException(i + n);
742
+ }
743
+ const idx = createIndices(n);
744
+ indices.splice(i, 0, ...idx);
745
+ }
746
+ // TODO(burdon): Delete index.
747
+ _deleteIndices(indices, i, n) {
748
+ throw new Error("Not implemented");
749
+ }
750
+ // TODO(burdon): Move. Cannot use fractional without changing. Switch back to using unique IDs?
751
+ _moveIndices(indices, i, j, n) {
752
+ throw new Error("Not implemented");
753
+ }
754
+ //
755
+ // Indices.
756
+ //
757
+ /**
758
+ * E.g., "A1" => "x1@y1".
759
+ */
760
+ addressToIndex(cell) {
761
+ return `${this._sheet.columns[cell.column]}@${this._sheet.rows[cell.row]}`;
762
+ }
763
+ /**
764
+ * E.g., "x1@y1" => "A1".
765
+ */
766
+ addressFromIndex(idx) {
767
+ const [column, row] = idx.split("@");
768
+ return {
769
+ column: this._sheet.columns.indexOf(column),
770
+ row: this._sheet.rows.indexOf(row)
771
+ };
772
+ }
773
+ /**
774
+ * E.g., "A1:B2" => "x1@y1:x2@y2".
775
+ */
776
+ rangeToIndex(range) {
777
+ return [
778
+ range.from,
779
+ range.to ?? range.from
780
+ ].map((cell) => this.addressToIndex(cell)).join(":");
781
+ }
782
+ /**
783
+ * E.g., "x1@y1:x2@y2" => "A1:B2".
784
+ */
785
+ rangeFromIndex(idx) {
786
+ const [from, to] = idx.split(":").map((idx2) => this.addressFromIndex(idx2));
787
+ return {
788
+ from,
789
+ to
790
+ };
791
+ }
792
+ /**
793
+ * Map from A1 notation to indices.
794
+ */
795
+ mapFormulaRefsToIndices(formula) {
796
+ invariant2(formula.charAt(0) === "=", void 0, {
797
+ F: __dxlog_file4,
798
+ L: 439,
799
+ S: this,
800
+ A: [
801
+ "formula.charAt(0) === '='",
802
+ ""
803
+ ]
804
+ });
805
+ return formula.replace(/([a-zA-Z]+)([0-9]+)/g, (match) => {
806
+ return this.addressToIndex(addressFromA1Notation(match));
807
+ });
808
+ }
809
+ /**
810
+ * Map from indices to A1 notation.
811
+ */
812
+ mapFormulaIndicesToRefs(formula) {
813
+ invariant2(formula.charAt(0) === "=", void 0, {
814
+ F: __dxlog_file4,
815
+ L: 449,
816
+ S: this,
817
+ A: [
818
+ "formula.charAt(0) === '='",
819
+ ""
820
+ ]
821
+ });
822
+ return formula.replace(/([a-zA-Z0-9]+)@([a-zA-Z0-9]+)/g, (idx) => {
823
+ return addressToA1Notation(this.addressFromIndex(idx));
824
+ });
825
+ }
826
+ //
827
+ // Values
828
+ //
829
+ /**
830
+ * https://hyperformula.handsontable.com/guide/date-and-time-handling.html#example
831
+ * https://hyperformula.handsontable.com/api/interfaces/configparams.html#nulldate
832
+ * NOTE: TODAY() is number of FULL days since nullDate. It will typically be -1 days from NOW().
833
+ */
834
+ toLocalDate(num) {
835
+ const { year, month, day, hours, minutes, seconds } = this.toDateTime(num);
836
+ return new Date(year, month - 1, day, hours, minutes, seconds);
837
+ }
838
+ toDateTime(num) {
839
+ return this._graph.hf.numberToDateTime(num);
840
+ }
841
+ toDate(num) {
842
+ return this._graph.hf.numberToDate(num);
843
+ }
844
+ toTime(num) {
845
+ return this._graph.hf.numberToTime(num);
846
+ }
847
+ };
848
+
849
+ export {
850
+ createComputeGraph,
851
+ ComputeGraphContextProvider,
852
+ useComputeGraph,
853
+ posEquals,
854
+ columnLetter,
855
+ addressToA1Notation,
856
+ addressFromA1Notation,
857
+ rangeToA1Notation,
858
+ inRange,
859
+ SheetModel
860
+ };
861
+ //# sourceMappingURL=chunk-AT2FJXQX.mjs.map