@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,3740 @@
1
+ import {
2
+ SheetModel,
3
+ addressFromA1Notation,
4
+ addressToA1Notation,
5
+ columnLetter,
6
+ inRange,
7
+ posEquals,
8
+ rangeToA1Notation,
9
+ useComputeGraph
10
+ } from "./chunk-AT2FJXQX.mjs";
11
+ import {
12
+ ValueTypeEnum
13
+ } from "./chunk-6VPEAUG6.mjs";
14
+ import "./chunk-JRL5LGCE.mjs";
15
+
16
+ // packages/plugins/plugin-sheet/src/components/SheetContainer.tsx
17
+ import React4 from "react";
18
+ import { mx as mx3 } from "@dxos/react-ui-theme";
19
+
20
+ // packages/plugins/plugin-sheet/src/components/Sheet/Sheet.tsx
21
+ import { DndContext, DragOverlay, KeyboardSensor, MouseSensor, TouchSensor, useDraggable, useDroppable, useSensor, useSensors } from "@dnd-kit/core";
22
+ import { restrictToHorizontalAxis, restrictToVerticalAxis } from "@dnd-kit/modifiers";
23
+ import { getEventCoordinates, useCombinedRefs } from "@dnd-kit/utilities";
24
+ import { Function as FunctionIcon } from "@phosphor-icons/react";
25
+ import { Resizable } from "re-resizable";
26
+ import React3, { forwardRef, useEffect as useEffect3, useImperativeHandle, useRef, useState as useState4 } from "react";
27
+ import { createPortal } from "react-dom";
28
+ import { useResizeDetector } from "react-resize-detector";
29
+ import { debounce } from "@dxos/async";
30
+ import { fullyQualifiedId, createDocAccessor } from "@dxos/client/echo";
31
+ import { log } from "@dxos/log";
32
+ import { createAttendableAttributes } from "@dxos/react-ui-attention";
33
+ import { mx as mx2 } from "@dxos/react-ui-theme";
34
+
35
+ // packages/plugins/plugin-sheet/src/components/Sheet/grid.ts
36
+ import { useEffect, useState } from "react";
37
+ var axisWidth = "calc(var(--rail-size)-2px)";
38
+ var axisHeight = 34;
39
+ var minWidth = 40;
40
+ var maxWidth = 800;
41
+ var minHeight = axisHeight;
42
+ var maxHeight = 400;
43
+ var defaultWidth = 200;
44
+ var defaultHeight = minHeight;
45
+ var CELL_DATA_KEY = "cell";
46
+ var useGridLayout = ({ scroller, size, rows, columns, rowSizes, columnSizes }) => {
47
+ const [rowPositions, setRowPositions] = useState([]);
48
+ useEffect(() => {
49
+ if (!rowSizes) {
50
+ return;
51
+ }
52
+ let y = 0;
53
+ setRowPositions(rows.map((idx, i) => {
54
+ const height2 = rowSizes?.[idx] ?? defaultHeight;
55
+ const top = y;
56
+ y += height2 - 1;
57
+ return {
58
+ row: i,
59
+ top,
60
+ height: height2
61
+ };
62
+ }));
63
+ }, [
64
+ rows,
65
+ rowSizes
66
+ ]);
67
+ const [columnPositions, setColumnPositions] = useState([]);
68
+ useEffect(() => {
69
+ if (!columns) {
70
+ return;
71
+ }
72
+ let x = 0;
73
+ setColumnPositions(columns.map((idx, i) => {
74
+ const width2 = columnSizes?.[idx] ?? defaultWidth;
75
+ const left = x;
76
+ x += width2 - 1;
77
+ return {
78
+ column: i,
79
+ left,
80
+ width: width2
81
+ };
82
+ }));
83
+ }, [
84
+ columns,
85
+ columnSizes
86
+ ]);
87
+ const height = rowPositions.length ? rowPositions[rowPositions.length - 1].top + rowPositions[rowPositions.length - 1].height : 0;
88
+ const width = columnPositions.length ? columnPositions[columnPositions.length - 1].left + columnPositions[columnPositions.length - 1].width : 0;
89
+ const [{ rowRange, columnRange }, setWindow] = useState({
90
+ rowRange: [],
91
+ columnRange: []
92
+ });
93
+ useEffect(() => {
94
+ const handleScroll = () => {
95
+ if (!scroller) {
96
+ return;
97
+ }
98
+ const { scrollLeft: left, scrollTop: top, clientWidth: width2, clientHeight: height2 } = scroller;
99
+ let rowStart = 0;
100
+ let rowEnd = 0;
101
+ for (let i = 0; i < rowPositions.length; i++) {
102
+ const row = rowPositions[i];
103
+ if (row.top <= top) {
104
+ rowStart = i;
105
+ }
106
+ if (row.top + row.height >= top + height2) {
107
+ rowEnd = i;
108
+ break;
109
+ }
110
+ }
111
+ let columnStart = 0;
112
+ let columnEnd = 0;
113
+ for (let i = 0; i < columnPositions.length; i++) {
114
+ const column = columnPositions[i];
115
+ if (column.left <= left) {
116
+ columnStart = i;
117
+ }
118
+ if (column.left + column.width >= left + width2) {
119
+ columnEnd = i;
120
+ break;
121
+ }
122
+ }
123
+ const overscan = 5;
124
+ setWindow({
125
+ rowRange: rowPositions.slice(Math.max(0, rowStart - overscan), Math.min(rowPositions.length, rowEnd + overscan)),
126
+ columnRange: columnPositions.slice(Math.max(0, columnStart - overscan), Math.min(columnPositions.length, columnEnd + overscan))
127
+ });
128
+ };
129
+ scroller?.addEventListener("scroll", handleScroll);
130
+ handleScroll();
131
+ return () => {
132
+ scroller?.removeEventListener("scroll", handleScroll);
133
+ };
134
+ }, [
135
+ size.width,
136
+ size.height,
137
+ rowPositions,
138
+ columnPositions
139
+ ]);
140
+ return {
141
+ width,
142
+ height,
143
+ rowRange,
144
+ columnRange
145
+ };
146
+ };
147
+ var getCellAtPointer = (event) => {
148
+ const element = document.elementFromPoint(event.clientX, event.clientY);
149
+ const root = element?.closest(`[data-${CELL_DATA_KEY}]`);
150
+ if (root) {
151
+ const value = root.dataset[CELL_DATA_KEY];
152
+ if (value) {
153
+ return addressFromA1Notation(value);
154
+ }
155
+ }
156
+ };
157
+ var getCellElement = (root, cell) => {
158
+ const pos = addressToA1Notation(cell);
159
+ return root.querySelector(`[data-${CELL_DATA_KEY}="${pos}"]`);
160
+ };
161
+
162
+ // packages/plugins/plugin-sheet/src/components/Sheet/nav.ts
163
+ import { useState as useState2 } from "react";
164
+ var handleNav = (ev, cursor, range, size) => {
165
+ if (cursor && ev.shiftKey) {
166
+ const opposite = range?.to ?? {
167
+ ...cursor
168
+ };
169
+ switch (ev.key) {
170
+ case "ArrowUp": {
171
+ if (opposite.row > 0) {
172
+ opposite.row -= 1;
173
+ }
174
+ break;
175
+ }
176
+ case "ArrowDown": {
177
+ if (opposite.row < size.numRows - 1) {
178
+ opposite.row += 1;
179
+ }
180
+ break;
181
+ }
182
+ case "ArrowLeft": {
183
+ if (opposite.column > 0) {
184
+ opposite.column -= 1;
185
+ }
186
+ break;
187
+ }
188
+ case "ArrowRight": {
189
+ if (opposite.column < size.numColumns - 1) {
190
+ opposite.column += 1;
191
+ }
192
+ break;
193
+ }
194
+ }
195
+ return {
196
+ cursor,
197
+ range: {
198
+ from: cursor,
199
+ to: opposite
200
+ }
201
+ };
202
+ }
203
+ const next = handleArrowNav(ev, cursor, size);
204
+ return {
205
+ cursor: next
206
+ };
207
+ };
208
+ var handleArrowNav = (ev, cursor, { numRows, numColumns }) => {
209
+ switch (ev.key) {
210
+ case "ArrowUp":
211
+ if (cursor === void 0) {
212
+ return {
213
+ row: 0,
214
+ column: 0
215
+ };
216
+ } else if (cursor.row > 0) {
217
+ return {
218
+ row: ev.metaKey ? 0 : cursor.row - 1,
219
+ column: cursor.column
220
+ };
221
+ }
222
+ break;
223
+ case "ArrowDown":
224
+ if (cursor === void 0) {
225
+ return {
226
+ row: 0,
227
+ column: 0
228
+ };
229
+ } else if (cursor.row < numRows - 1) {
230
+ return {
231
+ row: ev.metaKey ? numRows - 1 : cursor.row + 1,
232
+ column: cursor.column
233
+ };
234
+ }
235
+ break;
236
+ case "ArrowLeft":
237
+ if (cursor === void 0) {
238
+ return {
239
+ row: 0,
240
+ column: 0
241
+ };
242
+ } else if (cursor.column > 0) {
243
+ return {
244
+ row: cursor.row,
245
+ column: ev.metaKey ? 0 : cursor.column - 1
246
+ };
247
+ }
248
+ break;
249
+ case "ArrowRight":
250
+ if (cursor === void 0) {
251
+ return {
252
+ row: 0,
253
+ column: 0
254
+ };
255
+ } else if (cursor.column < numColumns - 1) {
256
+ return {
257
+ row: cursor.row,
258
+ column: ev.metaKey ? numColumns - 1 : cursor.column + 1
259
+ };
260
+ }
261
+ break;
262
+ case "Home":
263
+ return {
264
+ row: 0,
265
+ column: 0
266
+ };
267
+ case "End":
268
+ return {
269
+ row: numRows - 1,
270
+ column: numColumns - 1
271
+ };
272
+ }
273
+ };
274
+ var useRangeSelect = (cb) => {
275
+ const [from, setFrom] = useState2();
276
+ const [to, setTo] = useState2();
277
+ const onMouseDown = (ev) => {
278
+ const current = getCellAtPointer(ev);
279
+ setFrom(current);
280
+ if (current) {
281
+ setTimeout(() => cb("start", {
282
+ from: current
283
+ }));
284
+ }
285
+ };
286
+ const onMouseMove = (ev) => {
287
+ if (from) {
288
+ let current = getCellAtPointer(ev);
289
+ if (posEquals(current, from)) {
290
+ current = void 0;
291
+ }
292
+ setTo(current);
293
+ setTimeout(() => cb("move", {
294
+ from,
295
+ to: current
296
+ }));
297
+ }
298
+ };
299
+ const onMouseUp = (ev) => {
300
+ if (from) {
301
+ let current = getCellAtPointer(ev);
302
+ if (posEquals(current, from)) {
303
+ current = void 0;
304
+ }
305
+ setFrom(void 0);
306
+ setTo(void 0);
307
+ setTimeout(() => cb("end", current ? {
308
+ from,
309
+ to: current
310
+ } : void 0));
311
+ }
312
+ };
313
+ return {
314
+ range: from ? {
315
+ from,
316
+ to
317
+ } : void 0,
318
+ handlers: {
319
+ onMouseDown,
320
+ onMouseMove,
321
+ onMouseUp
322
+ }
323
+ };
324
+ };
325
+
326
+ // packages/plugins/plugin-sheet/src/components/Sheet/sheet-context.tsx
327
+ import React, { createContext, useContext, useState as useState3, useEffect as useEffect2 } from "react";
328
+ import { invariant } from "@dxos/invariant";
329
+
330
+ // packages/plugins/plugin-sheet/src/components/Sheet/formatting.ts
331
+ var FormattingModel = class {
332
+ constructor(model) {
333
+ this.model = model;
334
+ }
335
+ /**
336
+ * Get formatted string value and className for cell.
337
+ */
338
+ getFormatting(cell) {
339
+ const value = this.model.getValue(cell);
340
+ if (value === void 0 || value === null) {
341
+ return {};
342
+ }
343
+ const locales = void 0;
344
+ const idx = this.model.addressToIndex(cell);
345
+ let formatting = this.model.sheet.formatting?.[idx] ?? {};
346
+ const classNames = [
347
+ ...formatting?.classNames ?? []
348
+ ];
349
+ for (const [idx2, _formatting] of Object.entries(this.model.sheet.formatting)) {
350
+ const range = this.model.rangeFromIndex(idx2);
351
+ if (inRange(range, cell)) {
352
+ if (_formatting.classNames) {
353
+ classNames.push(..._formatting.classNames);
354
+ }
355
+ if (_formatting.type) {
356
+ formatting = _formatting;
357
+ }
358
+ }
359
+ }
360
+ const defaultNumber = "justify-end font-mono";
361
+ const type = formatting?.type ?? this.model.getValueType(cell);
362
+ switch (type) {
363
+ case ValueTypeEnum.Boolean: {
364
+ return {
365
+ value: value.toLocaleString().toUpperCase(),
366
+ classNames: [
367
+ ...classNames,
368
+ value ? "!text-green-500" : "!text-orange-500"
369
+ ]
370
+ };
371
+ }
372
+ case ValueTypeEnum.Number: {
373
+ return {
374
+ value: value.toLocaleString(locales),
375
+ classNames: [
376
+ ...classNames,
377
+ defaultNumber
378
+ ]
379
+ };
380
+ }
381
+ case ValueTypeEnum.Percent: {
382
+ return {
383
+ value: value * 100 + "%",
384
+ classNames: [
385
+ ...classNames,
386
+ defaultNumber
387
+ ]
388
+ };
389
+ }
390
+ case ValueTypeEnum.Currency: {
391
+ return {
392
+ value: value.toLocaleString(locales, {
393
+ style: "currency",
394
+ currency: "USD",
395
+ minimumFractionDigits: 2,
396
+ maximumFractionDigits: 2
397
+ }),
398
+ classNames: [
399
+ ...classNames,
400
+ defaultNumber
401
+ ]
402
+ };
403
+ }
404
+ case ValueTypeEnum.DateTime: {
405
+ const date = this.model.toLocalDate(value);
406
+ return {
407
+ value: date.toLocaleString(locales),
408
+ classNames
409
+ };
410
+ }
411
+ case ValueTypeEnum.Date: {
412
+ const date = this.model.toLocalDate(value);
413
+ return {
414
+ value: date.toLocaleDateString(locales),
415
+ classNames
416
+ };
417
+ }
418
+ case ValueTypeEnum.Time: {
419
+ const date = this.model.toLocalDate(value);
420
+ return {
421
+ value: date.toLocaleTimeString(locales),
422
+ classNames
423
+ };
424
+ }
425
+ default: {
426
+ return {
427
+ value: String(value),
428
+ classNames
429
+ };
430
+ }
431
+ }
432
+ }
433
+ };
434
+
435
+ // packages/plugins/plugin-sheet/src/components/Sheet/sheet-context.tsx
436
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/plugins/plugin-sheet/src/components/Sheet/sheet-context.tsx";
437
+ var SheetContext = /* @__PURE__ */ createContext(null);
438
+ var useSheetContext = () => {
439
+ const context = useContext(SheetContext);
440
+ invariant(context, void 0, {
441
+ F: __dxlog_file,
442
+ L: 39,
443
+ S: void 0,
444
+ A: [
445
+ "context",
446
+ ""
447
+ ]
448
+ });
449
+ return context;
450
+ };
451
+ var SheetContextProvider = ({ children, sheet, space, readonly, onInfo }) => {
452
+ const graph = useComputeGraph(space);
453
+ const [cursor, setCursor] = useState3();
454
+ const [range, setRange] = useState3();
455
+ const [editing, setEditing] = useState3(false);
456
+ const [[model, formatting] = [], setModels] = useState3(void 0);
457
+ useEffect2(() => {
458
+ let model2;
459
+ let formatting2;
460
+ const t = setTimeout(async () => {
461
+ model2 = new SheetModel(graph, sheet, {
462
+ readonly
463
+ });
464
+ await model2.initialize();
465
+ formatting2 = new FormattingModel(model2);
466
+ setModels([
467
+ model2,
468
+ formatting2
469
+ ]);
470
+ });
471
+ return () => {
472
+ clearTimeout(t);
473
+ void model2?.destroy();
474
+ };
475
+ }, [
476
+ graph,
477
+ readonly
478
+ ]);
479
+ if (!model || !formatting) {
480
+ return null;
481
+ }
482
+ return /* @__PURE__ */ React.createElement(SheetContext.Provider, {
483
+ value: {
484
+ model,
485
+ formatting,
486
+ cursor,
487
+ setCursor,
488
+ range,
489
+ setRange,
490
+ editing,
491
+ setEditing,
492
+ // TODO(burdon): Change to event.
493
+ onInfo
494
+ }
495
+ }, children);
496
+ };
497
+
498
+ // packages/plugins/plugin-sheet/src/components/Sheet/util.ts
499
+ var getRelativeClientRect = (root, element) => {
500
+ const rootRect = root.getBoundingClientRect();
501
+ const elementRect = element.getBoundingClientRect();
502
+ return new DOMRect(elementRect.left - rootRect.left + root.scrollLeft, elementRect.top - rootRect.top + root.scrollTop, elementRect.width, elementRect.height);
503
+ };
504
+ var getRectUnion = (b1, b2) => {
505
+ return {
506
+ left: Math.min(b1.left, b2.left),
507
+ top: Math.min(b1.top, b2.top),
508
+ width: Math.abs(b1.left - b2.left) + (b1.left > b2.left ? b1.width : b2.width),
509
+ height: Math.abs(b1.top - b2.top) + (b1.height > b2.height ? b1.height : b2.height)
510
+ };
511
+ };
512
+ var scrollIntoView = (scrollContainer, el) => {
513
+ el.scrollIntoView({
514
+ block: "nearest",
515
+ inline: "nearest"
516
+ });
517
+ const cellBounds = el.getBoundingClientRect();
518
+ const scrollerBounds = scrollContainer.getBoundingClientRect();
519
+ if (cellBounds.top < scrollerBounds.top) {
520
+ scrollContainer.scrollTop -= scrollerBounds.top - cellBounds.top;
521
+ } else if (cellBounds.bottom >= scrollerBounds.bottom - 1) {
522
+ scrollContainer.scrollTop += 2 + scrollerBounds.bottom - cellBounds.bottom;
523
+ }
524
+ if (cellBounds.left < scrollerBounds.left) {
525
+ scrollContainer.scrollLeft -= scrollerBounds.left - cellBounds.left;
526
+ } else if (cellBounds.right >= scrollerBounds.right) {
527
+ scrollContainer.scrollLeft += 2 + scrollerBounds.right - cellBounds.right;
528
+ }
529
+ };
530
+
531
+ // packages/plugins/plugin-sheet/src/components/CellEditor/CellEditor.tsx
532
+ import { EditorView, keymap } from "@codemirror/view";
533
+ import React2 from "react";
534
+ import { useThemeContext } from "@dxos/react-ui";
535
+ import { createBasicExtensions, createThemeExtensions, preventNewline, useTextEditor } from "@dxos/react-ui-editor";
536
+ var editorKeys = ({ onNav, onClose }) => {
537
+ return keymap.of([
538
+ {
539
+ key: "ArrowUp",
540
+ run: (editor) => {
541
+ const value = editor.state.doc.toString();
542
+ onNav?.(value, {
543
+ key: "ArrowUp"
544
+ });
545
+ return !!onNav;
546
+ }
547
+ },
548
+ {
549
+ key: "ArrowDown",
550
+ run: (editor) => {
551
+ const value = editor.state.doc.toString();
552
+ onNav?.(value, {
553
+ key: "ArrowDown"
554
+ });
555
+ return !!onNav;
556
+ }
557
+ },
558
+ {
559
+ key: "ArrowLeft",
560
+ run: (editor) => {
561
+ const value = editor.state.doc.toString();
562
+ onNav?.(value, {
563
+ key: "ArrowLeft"
564
+ });
565
+ return !!onNav;
566
+ }
567
+ },
568
+ {
569
+ key: "ArrowRight",
570
+ run: (editor) => {
571
+ const value = editor.state.doc.toString();
572
+ onNav?.(value, {
573
+ key: "ArrowRight"
574
+ });
575
+ return !!onNav;
576
+ }
577
+ },
578
+ {
579
+ key: "Enter",
580
+ run: (editor) => {
581
+ onClose(editor.state.doc.toString());
582
+ return true;
583
+ }
584
+ },
585
+ {
586
+ key: "Escape",
587
+ run: () => {
588
+ onClose(void 0);
589
+ return true;
590
+ }
591
+ }
592
+ ]);
593
+ };
594
+ var CellEditor = ({ value, extension, autoFocus, onBlur }) => {
595
+ const { themeMode } = useThemeContext();
596
+ const { parentRef } = useTextEditor(() => {
597
+ return {
598
+ autoFocus,
599
+ initialValue: value,
600
+ selection: {
601
+ anchor: value?.length ?? 0
602
+ },
603
+ extensions: [
604
+ extension ?? [],
605
+ preventNewline,
606
+ EditorView.focusChangeEffect.of((_, focusing) => {
607
+ if (!focusing) {
608
+ onBlur?.({
609
+ type: "blur"
610
+ });
611
+ }
612
+ return null;
613
+ }),
614
+ createBasicExtensions({
615
+ lineWrapping: false
616
+ }),
617
+ createThemeExtensions({
618
+ themeMode,
619
+ slots: {
620
+ editor: {
621
+ className: "flex w-full [&>.cm-scroller]:scrollbar-none"
622
+ },
623
+ content: {
624
+ className: "!px-2 !py-1"
625
+ }
626
+ }
627
+ })
628
+ ]
629
+ };
630
+ }, [
631
+ extension
632
+ ]);
633
+ return /* @__PURE__ */ React2.createElement("div", {
634
+ ref: parentRef,
635
+ className: "flex w-full"
636
+ });
637
+ };
638
+
639
+ // packages/plugins/plugin-sheet/src/components/CellEditor/extension.ts
640
+ import { acceptCompletion, autocompletion, completionStatus, startCompletion } from "@codemirror/autocomplete";
641
+ import { HighlightStyle, syntaxHighlighting } from "@codemirror/language";
642
+ import { Facet } from "@codemirror/state";
643
+ import { ViewPlugin, keymap as keymap2 } from "@codemirror/view";
644
+ import { tags } from "@lezer/highlight";
645
+ import { spreadsheet } from "codemirror-lang-spreadsheet";
646
+ import { mx } from "@dxos/react-ui-theme";
647
+
648
+ // packages/plugins/plugin-sheet/src/components/CellEditor/functions.ts
649
+ var functions = {
650
+ Array: [
651
+ {
652
+ function: "ARRAYFORMULA",
653
+ description: "Enables the array arithmetic mode for a single formula.",
654
+ syntax: "ARRAYFORMULA(Formula)"
655
+ },
656
+ {
657
+ function: "FILTER",
658
+ description: "Filters an array, based on multiple conditions (boolean arrays).",
659
+ syntax: "FILTER(SourceArray, BoolArray1, BoolArray2, ...BoolArrayN)"
660
+ },
661
+ {
662
+ function: "ARRAY_CONSTRAIN",
663
+ description: "Truncates an array to given dimensions.",
664
+ syntax: "ARRAY_CONSTRAIN(Array, Height, Width)"
665
+ }
666
+ ],
667
+ "Date and time": [
668
+ {
669
+ function: "DATE",
670
+ description: "Returns the specified date as the number of full days since nullDate.",
671
+ syntax: "DATE(Year, Month, Day)"
672
+ },
673
+ {
674
+ function: "DATEDIF",
675
+ description: "Calculates distance between two dates, in provided unit parameter.",
676
+ syntax: "DATEDIF(Date1, Date2, Units)"
677
+ },
678
+ {
679
+ function: "DATEVALUE",
680
+ description: "Parses a date string and returns it as the number of full days since nullDate.",
681
+ syntax: "DATEVALUE(Datestring)"
682
+ },
683
+ {
684
+ function: "DAY",
685
+ description: "Returns the day of the given date value.",
686
+ syntax: "DAY(Number)"
687
+ },
688
+ {
689
+ function: "DAYS",
690
+ description: "Calculates the difference between two date values.",
691
+ syntax: "DAYS(Date2, Date1)"
692
+ },
693
+ {
694
+ function: "DAYS360",
695
+ description: "Calculates the difference between two date values in days, in 360-day basis.",
696
+ syntax: "DAYS360(Date2, Date1[, Format])"
697
+ },
698
+ {
699
+ function: "EDATE",
700
+ description: "Shifts the given startdate by given number of months and returns it as the number of full days since nullDate.",
701
+ syntax: "EDATE(Startdate, Months)"
702
+ },
703
+ {
704
+ function: "EOMONTH",
705
+ description: "Returns the date of the last day of a month which falls months away from the start date.",
706
+ syntax: "EOMONTH(Startdate, Months)"
707
+ },
708
+ {
709
+ function: "HOUR",
710
+ description: "Returns hour component of given time.",
711
+ syntax: "HOUR(Time)"
712
+ },
713
+ {
714
+ function: "INTERVAL",
715
+ description: "Returns interval string from given number of seconds.",
716
+ syntax: "INTERVAL(Seconds)"
717
+ },
718
+ {
719
+ function: "ISOWEEKNUM",
720
+ description: "Returns an ISO week number that corresponds to the week of year.",
721
+ syntax: "ISOWEEKNUM(Date)"
722
+ },
723
+ {
724
+ function: "MINUTE",
725
+ description: "Returns minute component of given time.",
726
+ syntax: "MINUTE(Time)"
727
+ },
728
+ {
729
+ function: "MONTH",
730
+ description: "Returns the month for the given date value.",
731
+ syntax: "MONTH(Number)"
732
+ },
733
+ {
734
+ function: "NETWORKDAYS",
735
+ description: "Returns the number of working days between two given dates.",
736
+ syntax: "NETWORKDAYS(Date1, Date2[, Holidays])"
737
+ },
738
+ {
739
+ function: "NETWORKDAYS.INTL",
740
+ description: "Returns the number of working days between two given dates.",
741
+ syntax: "NETWORKDAYS.INTL(Date1, Date2[, Mode [, Holidays]])"
742
+ },
743
+ {
744
+ function: "NOW",
745
+ description: "Returns current date + time as a number of days since nullDate.",
746
+ syntax: "NOW()"
747
+ },
748
+ {
749
+ function: "SECOND",
750
+ description: "Returns second component of given time.",
751
+ syntax: "SECOND(Time)"
752
+ },
753
+ {
754
+ function: "TIME",
755
+ description: "Returns the number that represents a given time as a fraction of full day.",
756
+ syntax: "TIME(Hour, Minute, Second)"
757
+ },
758
+ {
759
+ function: "TIMEVALUE",
760
+ description: "Parses a time string and returns a number that represents it as a fraction of a full day.",
761
+ syntax: "TIMEVALUE(Timestring)"
762
+ },
763
+ {
764
+ function: "TODAY",
765
+ description: "Returns an integer representing the current date as the number of full days since nullDate.",
766
+ syntax: "TODAY()"
767
+ },
768
+ {
769
+ function: "WEEKDAY",
770
+ description: "Computes a number between 1-7 representing the day of week.",
771
+ syntax: "WEEKDAY(Date, Type)"
772
+ },
773
+ {
774
+ function: "WEEKNUM",
775
+ description: "Returns a week number that corresponds to the week of year.",
776
+ syntax: "WEEKNUM(Date, Type)"
777
+ },
778
+ {
779
+ function: "WORKDAY",
780
+ description: "Returns the working day number of days from start day.",
781
+ syntax: "WORKDAY(Date, Shift[, Holidays])"
782
+ },
783
+ {
784
+ function: "WORKDAY.INTL",
785
+ description: "Returns the working day number of days from start day.",
786
+ syntax: "WORKDAY.INTL(Date, Shift[, Mode[, Holidays]])"
787
+ },
788
+ {
789
+ function: "YEAR",
790
+ description: "Returns the year as a number according to the internal calculation rules.",
791
+ syntax: "YEAR(Number)"
792
+ },
793
+ {
794
+ function: "YEARFRAC",
795
+ description: "Computes the difference between two date values, in fraction of years.",
796
+ syntax: "YEARFRAC(Date2, Date1[, Format])"
797
+ }
798
+ ],
799
+ Engineering: [
800
+ {
801
+ function: "BIN2DEC",
802
+ description: "The result is the decimal number for the binary number entered.",
803
+ syntax: "BIN2DEC(Number)"
804
+ },
805
+ {
806
+ function: "BIN2HEX",
807
+ description: "The result is the hexadecimal number for the binary number entered.",
808
+ syntax: "BIN2HEX(Number, Places)"
809
+ },
810
+ {
811
+ function: "BIN2OCT",
812
+ description: "The result is the octal number for the binary number entered.",
813
+ syntax: "BIN2OCT(Number, Places)"
814
+ },
815
+ {
816
+ function: "BITAND",
817
+ description: "Returns a bitwise logical 'and' of the parameters.",
818
+ syntax: "BITAND(Number1, Number2)"
819
+ },
820
+ {
821
+ function: "BITLSHIFT",
822
+ description: "Shifts a number left by n bits.",
823
+ syntax: "BITLSHIFT(Number, Shift)"
824
+ },
825
+ {
826
+ function: "BITOR",
827
+ description: "Returns a bitwise logical 'or' of the parameters.",
828
+ syntax: "BITOR(Number1, Number2)"
829
+ },
830
+ {
831
+ function: "BITRSHIFT",
832
+ description: "Shifts a number right by n bits.",
833
+ syntax: "BITRSHIFT(Number, Shift)"
834
+ },
835
+ {
836
+ function: "BITXOR",
837
+ description: "Returns a bitwise logical 'exclusive or' of the parameters.",
838
+ syntax: "BITXOR(Number1, Number2)"
839
+ },
840
+ {
841
+ function: "COMPLEX",
842
+ description: "Returns complex number from Re and Im parts.",
843
+ syntax: "COMPLEX(Re, Im[, Symbol])"
844
+ },
845
+ {
846
+ function: "DEC2BIN",
847
+ description: "Returns the binary number for the decimal number entered between \u2013512 and 511.",
848
+ syntax: "DEC2BIN(Number, Places)"
849
+ },
850
+ {
851
+ function: "DEC2HEX",
852
+ description: "Returns the hexadecimal number for the decimal number entered.",
853
+ syntax: "DEC2HEX(Number, Places)"
854
+ },
855
+ {
856
+ function: "DEC2OCT",
857
+ description: "Returns the octal number for the decimal number entered.",
858
+ syntax: "DEC2OCT(Number, Places)"
859
+ },
860
+ {
861
+ function: "DELTA",
862
+ description: "Returns TRUE (1) if both numbers are equal, otherwise returns FALSE (0).",
863
+ syntax: "DELTA(Number_1, Number_2)"
864
+ },
865
+ {
866
+ function: "ERF",
867
+ description: "Returns values of the Gaussian error integral.",
868
+ syntax: "ERF(Lower_Limit, Upper_Limit)"
869
+ },
870
+ {
871
+ function: "ERFC",
872
+ description: "Returns complementary values of the Gaussian error integral between x and infinity.",
873
+ syntax: "ERFC(Lower_Limit)"
874
+ },
875
+ {
876
+ function: "HEX2BIN",
877
+ description: "The result is the binary number for the hexadecimal number entered.",
878
+ syntax: "HEX2BIN(Number, Places)"
879
+ },
880
+ {
881
+ function: "HEX2DEC",
882
+ description: "The result is the decimal number for the hexadecimal number entered.",
883
+ syntax: "HEX2DEC(Number)"
884
+ },
885
+ {
886
+ function: "HEX2OCT",
887
+ description: "The result is the octal number for the hexadecimal number entered.",
888
+ syntax: "HEX2OCT(Number, Places)"
889
+ },
890
+ {
891
+ function: "IMABS",
892
+ description: "Returns module of a complex number.",
893
+ syntax: "IMABS(Complex)"
894
+ },
895
+ {
896
+ function: "IMAGINARY",
897
+ description: "Returns imaginary part of a complex number.",
898
+ syntax: "IMAGINARY(Complex)"
899
+ },
900
+ {
901
+ function: "IMARGUMENT",
902
+ description: "Returns argument of a complex number.",
903
+ syntax: "IMARGUMENT(Complex)"
904
+ },
905
+ {
906
+ function: "IMCONJUGATE",
907
+ description: "Returns conjugate of a complex number.",
908
+ syntax: "IMCONJUGATE(Complex)"
909
+ },
910
+ {
911
+ function: "IMCOS",
912
+ description: "Returns cosine of a complex number.",
913
+ syntax: "IMCOS(Complex)"
914
+ },
915
+ {
916
+ function: "IMCOSH",
917
+ description: "Returns hyperbolic cosine of a complex number.",
918
+ syntax: "IMCOSH(Complex)"
919
+ },
920
+ {
921
+ function: "IMCOT",
922
+ description: "Returns cotangens of a complex number.",
923
+ syntax: "IMCOT(Complex)"
924
+ },
925
+ {
926
+ function: "IMCSC",
927
+ description: "Returns cosecans of a complex number.",
928
+ syntax: "IMCSC(Complex)"
929
+ },
930
+ {
931
+ function: "IMCSCH",
932
+ description: "Returns hyperbolic cosecans of a complex number.",
933
+ syntax: "IMCSCH(Complex)"
934
+ },
935
+ {
936
+ function: "IMDIV",
937
+ description: "Divides two complex numbers.",
938
+ syntax: "IMDIV(Complex1, Complex2)"
939
+ },
940
+ {
941
+ function: "IMEXP",
942
+ description: "Returns exponent of a complex number.",
943
+ syntax: "IMEXP(Complex)"
944
+ },
945
+ {
946
+ function: "IMLN",
947
+ description: "Returns natural logarithm of a complex number.",
948
+ syntax: "IMLN(Complex)"
949
+ },
950
+ {
951
+ function: "IMLOG2",
952
+ description: "Returns binary logarithm of a complex number.",
953
+ syntax: "IMLOG2(Complex)"
954
+ },
955
+ {
956
+ function: "IMLOG10",
957
+ description: "Returns base-10 logarithm of a complex number.",
958
+ syntax: "IMLOG10(Complex)"
959
+ },
960
+ {
961
+ function: "IMPOWER",
962
+ description: "Returns a complex number raised to a given power.",
963
+ syntax: "IMPOWER(Complex, Number)"
964
+ },
965
+ {
966
+ function: "IMPRODUCT",
967
+ description: "Multiplies complex numbers.",
968
+ syntax: "IMPRODUCT(Complex1, Complex2, ...ComplexN)"
969
+ },
970
+ {
971
+ function: "IMREAL",
972
+ description: "Returns real part of a complex number.",
973
+ syntax: "IMREAL(Complex)"
974
+ },
975
+ {
976
+ function: "IMSEC",
977
+ description: "Returns the secant of a complex number.",
978
+ syntax: "IMSEC(Complex)"
979
+ },
980
+ {
981
+ function: "IMSECH",
982
+ description: "Returns the hyperbolic secant of a complex number.",
983
+ syntax: "IMSECH(Complex)"
984
+ },
985
+ {
986
+ function: "IMSIN",
987
+ description: "Returns sine of a complex number.",
988
+ syntax: "IMSIN(Complex)"
989
+ },
990
+ {
991
+ function: "IMSINH",
992
+ description: "Returns hyperbolic sine of a complex number.",
993
+ syntax: "IMSINH(Complex)"
994
+ },
995
+ {
996
+ function: "IMSQRT",
997
+ description: "Returns a square root of a complex number.",
998
+ syntax: "IMSQRT(Complex)"
999
+ },
1000
+ {
1001
+ function: "IMSUB",
1002
+ description: "Subtracts two complex numbers.",
1003
+ syntax: "IMSUB(Complex1, Complex2)"
1004
+ },
1005
+ {
1006
+ function: "IMSUM",
1007
+ description: "Adds complex numbers.",
1008
+ syntax: "IMSUM(Complex1, Complex2, ..ComplexN)"
1009
+ },
1010
+ {
1011
+ function: "IMTAN",
1012
+ description: "Returns the tangent of a complex number.",
1013
+ syntax: "IMTAN(Complex)"
1014
+ },
1015
+ {
1016
+ function: "OCT2BIN",
1017
+ description: "The result is the binary number for the octal number entered.",
1018
+ syntax: "OCT2BIN(Number, Places)"
1019
+ },
1020
+ {
1021
+ function: "OCT2DEC",
1022
+ description: "The result is the decimal number for the octal number entered.",
1023
+ syntax: "OCT2DEC(Number)"
1024
+ },
1025
+ {
1026
+ function: "OCT2HEX",
1027
+ description: "The result is the hexadecimal number for the octal number entered.",
1028
+ syntax: "OCT2HEX(Number, Places)"
1029
+ }
1030
+ ],
1031
+ Information: [
1032
+ {
1033
+ function: "ISBINARY",
1034
+ description: "Returns TRUE if provided value is a valid binary number.",
1035
+ syntax: "ISBINARY(Value)"
1036
+ },
1037
+ {
1038
+ function: "ISBLANK",
1039
+ description: "Returns TRUE if the reference to a cell is blank.",
1040
+ syntax: "ISBLANK(Value)"
1041
+ },
1042
+ {
1043
+ function: "ISERR",
1044
+ description: "Returns TRUE if the value is error value except #N/A!.",
1045
+ syntax: "ISERR(Value)"
1046
+ },
1047
+ {
1048
+ function: "ISERROR",
1049
+ description: "Returns TRUE if the value is general error value.",
1050
+ syntax: "ISERROR(Value)"
1051
+ },
1052
+ {
1053
+ function: "ISEVEN",
1054
+ description: "Returns TRUE if the value is an even integer, or FALSE if the value is odd.",
1055
+ syntax: "ISEVEN(Value)"
1056
+ },
1057
+ {
1058
+ function: "ISFORMULA",
1059
+ description: "Checks whether referenced cell is a formula.",
1060
+ syntax: "ISFORMULA(Value)"
1061
+ },
1062
+ {
1063
+ function: "ISLOGICAL",
1064
+ description: "Tests for a logical value (TRUE or FALSE).",
1065
+ syntax: "ISLOGICAL(Value)"
1066
+ },
1067
+ {
1068
+ function: "ISNA",
1069
+ description: "Returns TRUE if the value is #N/A! error.",
1070
+ syntax: "ISNA(Value)"
1071
+ },
1072
+ {
1073
+ function: "ISNONTEXT",
1074
+ description: "Tests if the cell contents are text or numbers, and returns FALSE if the contents are text.",
1075
+ syntax: "ISNONTEXT(Value)"
1076
+ },
1077
+ {
1078
+ function: "ISNUMBER",
1079
+ description: "Returns TRUE if the value refers to a number.",
1080
+ syntax: "ISNUMBER(Value)"
1081
+ },
1082
+ {
1083
+ function: "ISODD",
1084
+ description: "Returns TRUE if the value is odd, or FALSE if the number is even.",
1085
+ syntax: "ISODD(Value)"
1086
+ },
1087
+ {
1088
+ function: "ISREF",
1089
+ description: "Returns TRUE if provided value is #REF! error.",
1090
+ syntax: "ISREF(Value)"
1091
+ },
1092
+ {
1093
+ function: "ISTEXT",
1094
+ description: "Returns TRUE if the cell contents reference text.",
1095
+ syntax: "ISTEXT(Value)"
1096
+ },
1097
+ {
1098
+ function: "SHEET",
1099
+ description: "Returns sheet number of a given value or a formula sheet number if no argument is provided.",
1100
+ syntax: "SHEET([Value])"
1101
+ },
1102
+ {
1103
+ function: "SHEETS",
1104
+ description: "Returns number of sheet of a given reference or number of all sheets in workbook when no argument is provided.",
1105
+ syntax: "SHEETS([Value])"
1106
+ },
1107
+ {
1108
+ function: "NA",
1109
+ description: "Returns #N/A! error value.",
1110
+ syntax: "NA(Value)"
1111
+ }
1112
+ ],
1113
+ Financial: [
1114
+ {
1115
+ function: "CUMIPMT",
1116
+ description: "Returns the cumulative interest paid on a loan between a start period and an end period.",
1117
+ syntax: "CUMIPMT(Rate, Nper, Pv, Start, End, type)"
1118
+ },
1119
+ {
1120
+ function: "CUMPRINC",
1121
+ description: "Returns the cumulative principal paid on a loan between a start period and an end period.",
1122
+ syntax: "CUMPRINC(Rate, Nper, Pv, Start, End, Type)"
1123
+ },
1124
+ {
1125
+ function: "DB",
1126
+ description: "Returns the depreciation of an asset for a period using the fixed-declining balance method.",
1127
+ syntax: "DB(Cost, Salvage, Life, Period[, Month])"
1128
+ },
1129
+ {
1130
+ function: "DDB",
1131
+ description: "Returns the depreciation of an asset for a period using the double-declining balance method.",
1132
+ syntax: "DDB(Cost, Salvage, Life, Period[, Factor])"
1133
+ },
1134
+ {
1135
+ function: "DOLLARDE",
1136
+ description: "Converts a price entered with a special notation to a price displayed as a decimal number.",
1137
+ syntax: "DOLLARDE(Price, Fraction)"
1138
+ },
1139
+ {
1140
+ function: "DOLLARFR",
1141
+ description: "Converts a price displayed as a decimal number to a price entered with a special notation.",
1142
+ syntax: "DOLLARFR(Price, Fraction)"
1143
+ },
1144
+ {
1145
+ function: "EFFECT",
1146
+ description: "Calculates the effective annual interest rate from a nominal interest rate and the number of compounding periods per year.",
1147
+ syntax: "EFFECT(Nominal_rate, Npery)"
1148
+ },
1149
+ {
1150
+ function: "FV",
1151
+ description: "Returns the future value of an investment.",
1152
+ syntax: "FV(Rate, Nper, Pmt[, Pv,[ Type]])"
1153
+ },
1154
+ {
1155
+ function: "FVSCHEDULE",
1156
+ description: "Returns the future value of an investment based on a rate schedule.",
1157
+ syntax: "FVSCHEDULE(Pv, Schedule)"
1158
+ },
1159
+ {
1160
+ function: "IPMT",
1161
+ description: "Returns the interest portion of a given loan payment in a given payment period.",
1162
+ syntax: "IPMT(Rate, Per, Nper, Pv[, Fv[, Type]])"
1163
+ },
1164
+ {
1165
+ function: "ISPMT",
1166
+ description: "Returns the interest paid for a given period of an investment with equal principal payments.",
1167
+ syntax: "ISPMT(Rate, Per, Nper, Value)"
1168
+ },
1169
+ {
1170
+ function: "MIRR",
1171
+ description: "Returns modified internal value for cashflows.",
1172
+ syntax: "MIRR(Flows, FRate, RRate)"
1173
+ },
1174
+ {
1175
+ function: "NOMINAL",
1176
+ description: "Returns the nominal interest rate.",
1177
+ syntax: "NOMINAL(Effect_rate, Npery)"
1178
+ },
1179
+ {
1180
+ function: "NPER",
1181
+ description: "Returns the number of periods for an investment assuming periodic, constant payments and a constant interest rate.",
1182
+ syntax: "NPER(Rate, Pmt, Pv[, Fv[, Type]])"
1183
+ },
1184
+ {
1185
+ function: "NPV",
1186
+ description: "Returns net present value.",
1187
+ syntax: "NPV(Rate, Value1, Value2, ...ValueN)"
1188
+ },
1189
+ {
1190
+ function: "PDURATION",
1191
+ description: "Returns number of periods to reach specific value.",
1192
+ syntax: "PDURATION(Rate, Pv, Fv)"
1193
+ },
1194
+ {
1195
+ function: "PMT",
1196
+ description: "Returns the periodic payment for a loan.",
1197
+ syntax: "PMT(Rate, Nper, Pv[, Fv[, Type]])"
1198
+ },
1199
+ {
1200
+ function: "PPMT",
1201
+ description: "Calculates the principal portion of a given loan payment.",
1202
+ syntax: "PPMT(Rate, Per, Nper, Pv[, Fv[, Type]])"
1203
+ },
1204
+ {
1205
+ function: "PV",
1206
+ description: "Returns the present value of an investment.",
1207
+ syntax: "PV(Rate, Nper, Pmt[, Fv[, Type]])"
1208
+ },
1209
+ {
1210
+ function: "RATE",
1211
+ description: "Returns the interest rate per period of an annuity.",
1212
+ syntax: "RATE(Nper, Pmt, Pv[, Fv[, Type[, guess]]])"
1213
+ },
1214
+ {
1215
+ function: "RRI",
1216
+ description: "Returns an equivalent interest rate for the growth of an investment.",
1217
+ syntax: "RRI(Nper, Pv, Fv)"
1218
+ },
1219
+ {
1220
+ function: "SLN",
1221
+ description: "Returns the depreciation of an asset for one period, based on a straight-line method.",
1222
+ syntax: "SLN(Cost, Salvage, Life)"
1223
+ },
1224
+ {
1225
+ function: "SYD",
1226
+ description: "Returns the 'sum-of-years' depreciation for an asset in a period.",
1227
+ syntax: "SYD(Cost, Salvage, Life, Period)"
1228
+ },
1229
+ {
1230
+ function: "TBILLEQ",
1231
+ description: "Returns the bond-equivalent yield for a Treasury bill.",
1232
+ syntax: "TBILLEQ(Settlement, Maturity, Discount)"
1233
+ },
1234
+ {
1235
+ function: "TBILLPRICE",
1236
+ description: "Returns the price per $100 face value for a Treasury bill.",
1237
+ syntax: "TBILLPRICE(Settlement, Maturity, Discount)"
1238
+ },
1239
+ {
1240
+ function: "TBILLYIELD",
1241
+ description: "Returns the yield for a Treasury bill.",
1242
+ syntax: "TBILLYIELD(Settlement, Maturity, Price)"
1243
+ },
1244
+ {
1245
+ function: "XNPV",
1246
+ description: "Returns net present value.",
1247
+ syntax: "XNPV(Rate, Payments, Dates)"
1248
+ }
1249
+ ],
1250
+ Logical: [
1251
+ {
1252
+ function: "AND",
1253
+ description: "Returns TRUE if all arguments are TRUE.",
1254
+ syntax: "AND(Logical_value1, Logical_value2, ...Logical_valueN)"
1255
+ },
1256
+ {
1257
+ function: "FALSE",
1258
+ description: "Returns the logical value FALSE.",
1259
+ syntax: "FALSE()"
1260
+ },
1261
+ {
1262
+ function: "IF",
1263
+ description: "Specifies a logical test to be performed.",
1264
+ syntax: "IF(Test, Then_value, Otherwise_value)"
1265
+ },
1266
+ {
1267
+ function: "IFS",
1268
+ description: "Evaluates multiple logical tests and returns a value that corresponds to the first true condition.",
1269
+ syntax: "IFS(Condition1, Value1 [, Condition2, Value2 [, ...ConditionN, ValueN]])"
1270
+ },
1271
+ {
1272
+ function: "IFNA",
1273
+ description: "Returns the value if the cell does not contains the #N/A (value not available) error value, or the alternative value if it does.",
1274
+ syntax: "IFNA(Value, Alternate_value)"
1275
+ },
1276
+ {
1277
+ function: "IFERROR",
1278
+ description: "Returns the value if the cell does not contains an error value, or the alternative value if it does.",
1279
+ syntax: "IFERROR(Value, Alternate_value)"
1280
+ },
1281
+ {
1282
+ function: "NOT",
1283
+ description: "Complements (inverts) a logical value.",
1284
+ syntax: "NOT(Logicalvalue)"
1285
+ },
1286
+ {
1287
+ function: "SWITCH",
1288
+ description: "Evaluates a list of arguments, consisting of an expression followed by a value.",
1289
+ syntax: "SWITCH(Expression1, Value1 [, Expression2, Value2 [, ...ExpressionN, ValueN]])"
1290
+ },
1291
+ {
1292
+ function: "OR",
1293
+ description: "Returns TRUE if at least one argument is TRUE.",
1294
+ syntax: "OR(Logical_value1, Logical_value2, ...Logical_valueN)"
1295
+ },
1296
+ {
1297
+ function: "TRUE",
1298
+ description: "The logical value is set to TRUE.",
1299
+ syntax: "TRUE()"
1300
+ },
1301
+ {
1302
+ function: "XOR",
1303
+ description: "Returns true if an odd number of arguments evaluates to TRUE.",
1304
+ syntax: "XOR(Logical_value1, Logical_value2, ...Logical_valueN)"
1305
+ }
1306
+ ],
1307
+ "Lookup and reference": [
1308
+ {
1309
+ function: "ADDRESS",
1310
+ description: "Returns a cell reference as a string.",
1311
+ syntax: "ADDRESS(Row, Column[, AbsoluteRelativeMode[, UseA1Notation[, Sheet]]])"
1312
+ },
1313
+ {
1314
+ function: "CHOOSE",
1315
+ description: "Uses an index to return a value from a list of values.",
1316
+ syntax: "CHOOSE(Index, Value1, Value2, ...ValueN)"
1317
+ },
1318
+ {
1319
+ function: "COLUMN",
1320
+ description: "Returns column number of a given reference or formula reference if argument not provided.",
1321
+ syntax: "COLUMNS([Reference])"
1322
+ },
1323
+ {
1324
+ function: "COLUMNS",
1325
+ description: "Returns the number of columns in the given reference.",
1326
+ syntax: "COLUMNS(Array)"
1327
+ },
1328
+ {
1329
+ function: "FORMULATEXT",
1330
+ description: "Returns a formula in a given cell as a string.",
1331
+ syntax: "FORMULATEXT(Reference)"
1332
+ },
1333
+ {
1334
+ function: "HLOOKUP",
1335
+ description: "Searches horizontally with reference to adjacent cells to the bottom.",
1336
+ syntax: "HLOOKUP(Search_Criterion, Array, Index, Sort_Order)"
1337
+ },
1338
+ {
1339
+ function: "HYPERLINK",
1340
+ description: "Stores the url in the cell's metadata.",
1341
+ syntax: "HYPERLINK(Url[, LinkLabel])"
1342
+ },
1343
+ {
1344
+ function: "INDEX",
1345
+ description: "Returns the contents of a cell specified by row and column number. The column number is optional and defaults to 1.",
1346
+ syntax: "INDEX(Range, Row [, Column])"
1347
+ },
1348
+ {
1349
+ function: "MATCH",
1350
+ description: "Returns the relative position of an item in an array that matches a specified value.",
1351
+ syntax: "MATCH(Searchcriterion, Lookuparray [, MatchType])"
1352
+ },
1353
+ {
1354
+ function: "OFFSET",
1355
+ description: "Returns the value of a cell offset by a certain number of rows and columns from a given reference point.",
1356
+ syntax: "OFFSET(Reference, Rows, Columns, Height, Width)"
1357
+ },
1358
+ {
1359
+ function: "ROW",
1360
+ description: "Returns row number of a given reference or formula reference if argument not provided.",
1361
+ syntax: "ROW([Reference])"
1362
+ },
1363
+ {
1364
+ function: "ROWS",
1365
+ description: "Returns the number of rows in the given reference.",
1366
+ syntax: "ROWS(Array)"
1367
+ },
1368
+ {
1369
+ function: "VLOOKUP",
1370
+ description: "Searches vertically with reference to adjacent cells to the right.",
1371
+ syntax: "VLOOKUP(Search_Criterion, Array, Index, Sort_Order)"
1372
+ }
1373
+ ],
1374
+ "Math and trigonometry": [
1375
+ {
1376
+ function: "ABS",
1377
+ description: "Returns the absolute value of a number.",
1378
+ syntax: "ABS(Number)"
1379
+ },
1380
+ {
1381
+ function: "ACOS",
1382
+ description: "Returns the inverse trigonometric cosine of a number.",
1383
+ syntax: "ACOS(Number)"
1384
+ },
1385
+ {
1386
+ function: "ACOSH",
1387
+ description: "Returns the inverse hyperbolic cosine of a number.",
1388
+ syntax: "ACOSH(Number)"
1389
+ },
1390
+ {
1391
+ function: "ACOT",
1392
+ description: "Returns the inverse trigonometric cotangent of a number.",
1393
+ syntax: "ACOT(Number)"
1394
+ },
1395
+ {
1396
+ function: "ACOTH",
1397
+ description: "Returns the inverse hyperbolic cotangent of a number.",
1398
+ syntax: "ACOTH(Number)"
1399
+ },
1400
+ {
1401
+ function: "ARABIC",
1402
+ description: "Converts number from roman form.",
1403
+ syntax: "ARABIC(String)"
1404
+ },
1405
+ {
1406
+ function: "ASIN",
1407
+ description: "Returns the inverse trigonometric sine of a number.",
1408
+ syntax: "ASIN(Number)"
1409
+ },
1410
+ {
1411
+ function: "ASINH",
1412
+ description: "Returns the inverse hyperbolic sine of a number.",
1413
+ syntax: "ASINH(Number)"
1414
+ },
1415
+ {
1416
+ function: "ATAN",
1417
+ description: "Returns the inverse trigonometric tangent of a number.",
1418
+ syntax: "ATAN(Number)"
1419
+ },
1420
+ {
1421
+ function: "ATAN2",
1422
+ description: "Returns the inverse trigonometric tangent of the specified x and y coordinates.",
1423
+ syntax: "ATAN2(Numberx, Numbery)"
1424
+ },
1425
+ {
1426
+ function: "ATANH",
1427
+ description: "Returns the inverse hyperbolic tangent of a number.",
1428
+ syntax: "ATANH(Number)"
1429
+ },
1430
+ {
1431
+ function: "BASE",
1432
+ description: "Converts a positive integer to a specified base into a text from the numbering system.",
1433
+ syntax: "BASE(Number, Radix, [Minimumlength])"
1434
+ },
1435
+ {
1436
+ function: "CEILING",
1437
+ description: "Rounds a number up to the nearest multiple of Significance.",
1438
+ syntax: "CEILING(Number, Significance)"
1439
+ },
1440
+ {
1441
+ function: "CEILING.MATH",
1442
+ description: "Rounds a number up to the nearest multiple of Significance.",
1443
+ syntax: "CEILING.MATH(Number[, Significance[, Mode]])"
1444
+ },
1445
+ {
1446
+ function: "CEILING.PRECISE",
1447
+ description: "Rounds a number up to the nearest multiple of Significance.",
1448
+ syntax: "CEILING.PRECISE(Number[, Significance])"
1449
+ },
1450
+ {
1451
+ function: "COMBIN",
1452
+ description: "Returns number of combinations (without repetitions).",
1453
+ syntax: "COMBIN(Number, Number)"
1454
+ },
1455
+ {
1456
+ function: "COMBINA",
1457
+ description: "Returns number of combinations (with repetitions).",
1458
+ syntax: "COMBINA(Number, Number)"
1459
+ },
1460
+ {
1461
+ function: "COS",
1462
+ description: "Returns the cosine of the given angle (in radians).",
1463
+ syntax: "COS(Number)"
1464
+ },
1465
+ {
1466
+ function: "COSH",
1467
+ description: "Returns the hyperbolic cosine of the given value.",
1468
+ syntax: "COSH(Number)"
1469
+ },
1470
+ {
1471
+ function: "COT",
1472
+ description: "Returns the cotangent of the given angle (in radians).",
1473
+ syntax: "COT(Number)"
1474
+ },
1475
+ {
1476
+ function: "COTH",
1477
+ description: "Returns the hyperbolic cotangent of the given value.",
1478
+ syntax: "COTH(Number)"
1479
+ },
1480
+ {
1481
+ function: "COUNTUNIQUE",
1482
+ description: "Counts the number of unique values in a list of specified values and ranges.",
1483
+ syntax: "COUNTUNIQUE(Value1, Value2, ...ValueN)"
1484
+ },
1485
+ {
1486
+ function: "CSC",
1487
+ description: "Returns the cosecans of the given angle (in radians).",
1488
+ syntax: "CSC(Number)"
1489
+ },
1490
+ {
1491
+ function: "CSCH",
1492
+ description: "Returns the hyperbolic cosecant of the given value.",
1493
+ syntax: "CSCH(Number)"
1494
+ },
1495
+ {
1496
+ function: "DECIMAL",
1497
+ description: "Converts text with characters from a number system to a positive integer in the base radix given.",
1498
+ syntax: 'DECIMAL("Text", Radix)'
1499
+ },
1500
+ {
1501
+ function: "DEGREES",
1502
+ description: "Converts radians into degrees.",
1503
+ syntax: "DEGREES(Number)"
1504
+ },
1505
+ {
1506
+ function: "EVEN",
1507
+ description: "Rounds a positive number up to the next even integer and a negative number down to the next even integer.",
1508
+ syntax: "EVEN(Number)"
1509
+ },
1510
+ {
1511
+ function: "EXP",
1512
+ description: "Returns constant e raised to the power of a number.",
1513
+ syntax: "EXP(Number)"
1514
+ },
1515
+ {
1516
+ function: "FACT",
1517
+ description: "Returns a factorial of a number.",
1518
+ syntax: "FACT(Number)"
1519
+ },
1520
+ {
1521
+ function: "FACTDOUBLE",
1522
+ description: "Returns a double factorial of a number.",
1523
+ syntax: "FACTDOUBLE(Number)"
1524
+ },
1525
+ {
1526
+ function: "FLOOR",
1527
+ description: "Rounds a number down to the nearest multiple of Significance.",
1528
+ syntax: "FLOOR(Number, Significance)"
1529
+ },
1530
+ {
1531
+ function: "FLOOR.MATH",
1532
+ description: "Rounds a number down to the nearest multiple of Significance.",
1533
+ syntax: "FLOOR.MATH(Number[, Significance[, Mode]])"
1534
+ },
1535
+ {
1536
+ function: "FLOOR.PRECISE",
1537
+ description: "Rounds a number down to the nearest multiple of Significance.",
1538
+ syntax: "FLOOR.PRECISE(Number[, Significance])"
1539
+ },
1540
+ {
1541
+ function: "GCD",
1542
+ description: "Computes greatest common divisor of numbers.",
1543
+ syntax: "GCD(Number1, Number2, ...NumberN)"
1544
+ },
1545
+ {
1546
+ function: "INT",
1547
+ description: "Rounds a number down to the nearest integer.",
1548
+ syntax: "INT(Number)"
1549
+ },
1550
+ {
1551
+ function: "ISO.CEILING",
1552
+ description: "Rounds a number up to the nearest multiple of Significance.",
1553
+ syntax: "ISO.CEILING(Number[, Significance])"
1554
+ },
1555
+ {
1556
+ function: "LCM",
1557
+ description: "Computes least common multiplicity of numbers.",
1558
+ syntax: "LCM(Number1, Number2, ...NumberN)"
1559
+ },
1560
+ {
1561
+ function: "LN",
1562
+ description: "Returns the natural logarithm based on the constant e of a number.",
1563
+ syntax: "LN(Number)"
1564
+ },
1565
+ {
1566
+ function: "LOG",
1567
+ description: "Returns the logarithm of a number to the specified base.",
1568
+ syntax: "LOG(Number, Base)"
1569
+ },
1570
+ {
1571
+ function: "LOG10",
1572
+ description: "Returns the base-10 logarithm of a number.",
1573
+ syntax: "LOG10(Number)"
1574
+ },
1575
+ {
1576
+ function: "MOD",
1577
+ description: "Returns the remainder when one integer is divided by another.",
1578
+ syntax: "MOD(Dividend, Divisor)"
1579
+ },
1580
+ {
1581
+ function: "MROUND",
1582
+ description: "Rounds number to the nearest multiplicity.",
1583
+ syntax: "MROUND(Number, Base)"
1584
+ },
1585
+ {
1586
+ function: "MULTINOMIAL",
1587
+ description: "Returns number of multiset combinations.",
1588
+ syntax: "MULTINOMIAL(Number1, Number2, ...NumberN)"
1589
+ },
1590
+ {
1591
+ function: "ODD",
1592
+ description: "Rounds a positive number up to the nearest odd integer and a negative number down to the nearest odd integer.",
1593
+ syntax: "ODD(Number)"
1594
+ },
1595
+ {
1596
+ function: "PI",
1597
+ description: "Returns 3.14159265358979, the value of the mathematical constant PI to 14 decimal places.",
1598
+ syntax: "PI()"
1599
+ },
1600
+ {
1601
+ function: "POWER",
1602
+ description: "Returns a number raised to another number.",
1603
+ syntax: "POWER(Base, Exponent)"
1604
+ },
1605
+ {
1606
+ function: "PRODUCT",
1607
+ description: "Returns product of numbers.",
1608
+ syntax: "PRODUCT(Number1, Number2, ...NumberN)"
1609
+ },
1610
+ {
1611
+ function: "QUOTIENT",
1612
+ description: "Returns integer part of a division.",
1613
+ syntax: "QUOTIENT(Dividend, Divisor)"
1614
+ },
1615
+ {
1616
+ function: "RADIANS",
1617
+ description: "Converts degrees to radians.",
1618
+ syntax: "RADIANS(Number)"
1619
+ },
1620
+ {
1621
+ function: "RAND",
1622
+ description: "Returns a random number between 0 and 1.",
1623
+ syntax: "RAND()"
1624
+ },
1625
+ {
1626
+ function: "RANDBETWEEN",
1627
+ description: "Returns a random integer between two numbers.",
1628
+ syntax: "RAND(Lowerbound, Upperbound)"
1629
+ },
1630
+ {
1631
+ function: "ROMAN",
1632
+ description: "Converts number to roman form.",
1633
+ syntax: "ROMAN(Number[, Mode])"
1634
+ },
1635
+ {
1636
+ function: "ROUND",
1637
+ description: "Rounds a number to a certain number of decimal places.",
1638
+ syntax: "ROUND(Number, Count)"
1639
+ },
1640
+ {
1641
+ function: "ROUNDDOWN",
1642
+ description: "Rounds a number down, toward zero, to a certain precision.",
1643
+ syntax: "ROUNDDOWN(Number, Count)"
1644
+ },
1645
+ {
1646
+ function: "ROUNDUP",
1647
+ description: "Rounds a number up, away from zero, to a certain precision.",
1648
+ syntax: "ROUNDUP(Number, Count)"
1649
+ },
1650
+ {
1651
+ function: "SEC",
1652
+ description: "Returns the secant of the given angle (in radians).",
1653
+ syntax: "SEC(Number)"
1654
+ },
1655
+ {
1656
+ function: "SECH",
1657
+ description: "Returns the hyperbolic secant of the given angle (in radians).",
1658
+ syntax: "SEC(Number)"
1659
+ },
1660
+ {
1661
+ function: "SERIESSUM",
1662
+ description: "Evaluates series at a point.",
1663
+ syntax: "SERIESSUM(Number, Number, Number, Coefficients)"
1664
+ },
1665
+ {
1666
+ function: "SIN",
1667
+ description: "Returns the sine of the given angle (in radians).",
1668
+ syntax: "SIN(Number)"
1669
+ },
1670
+ {
1671
+ function: "SINH",
1672
+ description: "Returns the hyperbolic sine of the given value.",
1673
+ syntax: "SINH(Number)"
1674
+ },
1675
+ {
1676
+ function: "SIGN",
1677
+ description: "Returns sign of a number.",
1678
+ syntax: "SIGN(Number)"
1679
+ },
1680
+ {
1681
+ function: "SQRT",
1682
+ description: "Returns the positive square root of a number.",
1683
+ syntax: "SQRT(Number)"
1684
+ },
1685
+ {
1686
+ function: "SQRTPI",
1687
+ description: "Returns sqrt of number times pi.",
1688
+ syntax: "SQRTPI(Number)"
1689
+ },
1690
+ {
1691
+ function: "SUBTOTAL",
1692
+ description: "Computes aggregation using function specified by number.",
1693
+ syntax: "SUBTOTAL(Function, Number1, Number2, ...NumberN)"
1694
+ },
1695
+ {
1696
+ function: "SUM",
1697
+ description: "Sums up the values of the specified cells.",
1698
+ syntax: "SUM(Number1, Number2, ...NumberN)"
1699
+ },
1700
+ {
1701
+ function: "SUMIF",
1702
+ description: "Sums up the values of cells that belong to the specified range and meet the specified condition.",
1703
+ syntax: "SUMIF(Range, Criteria, Sumrange)"
1704
+ },
1705
+ {
1706
+ function: "SUMIFS",
1707
+ description: "Sums up the values of cells that belong to the specified range and meet the specified sets of conditions.",
1708
+ syntax: "SUMIFS(Sum_Range, Criterion_range1, Criterion1 [, Criterion_range2, Criterion2 [, ...Criterion_rangeN, CriterionN]])"
1709
+ },
1710
+ {
1711
+ function: "SUMPRODUCT",
1712
+ description: "Multiplies corresponding elements in the given arrays, and returns the sum of those products.",
1713
+ syntax: "SUMPRODUCT(Array1, Array2, ...ArrayN)"
1714
+ },
1715
+ {
1716
+ function: "SUMSQ",
1717
+ description: "Returns the sum of the squares of the arguments",
1718
+ syntax: "SUMSQ(Number1, Number2, ...NumberN)"
1719
+ },
1720
+ {
1721
+ function: "SUMX2MY2",
1722
+ description: "Returns the sum of the square differences.",
1723
+ syntax: "SUMX2MY2(Range1, Range2)"
1724
+ },
1725
+ {
1726
+ function: "SUMX2PY2",
1727
+ description: "Returns the sum of the square sums.",
1728
+ syntax: "SUMX2PY2(Range1, Range2)"
1729
+ },
1730
+ {
1731
+ function: "SUMXMY2",
1732
+ description: "Returns the sum of the square of differences.",
1733
+ syntax: "SUMXMY2(Range1, Range2)"
1734
+ },
1735
+ {
1736
+ function: "TAN",
1737
+ description: "Returns the tangent of the given angle (in radians).",
1738
+ syntax: "TAN(Number)"
1739
+ },
1740
+ {
1741
+ function: "TANH",
1742
+ description: "Returns the hyperbolic tangent of the given value.",
1743
+ syntax: "TANH(Number)"
1744
+ },
1745
+ {
1746
+ function: "TRUNC",
1747
+ description: "Truncates a number by removing decimal places.",
1748
+ syntax: "TRUNC(Number, Count)"
1749
+ }
1750
+ ],
1751
+ "Matrix functions": [
1752
+ {
1753
+ function: "MMULT",
1754
+ description: "Calculates the array product of two arrays.",
1755
+ syntax: "MMULT(Array, Array)"
1756
+ },
1757
+ {
1758
+ function: "MEDIANPOOL",
1759
+ description: "Calculates a smaller range which is a median of a Window_size, in a given Range, for every Stride element.",
1760
+ syntax: "MEDIANPOOL(Range, Window_size, Stride)"
1761
+ },
1762
+ {
1763
+ function: "MAXPOOL",
1764
+ description: "Calculates a smaller range which is a maximum of a Window_size, in a given Range, for every Stride element.",
1765
+ syntax: "MAXPOOL(Range, Window_size, Stride)"
1766
+ },
1767
+ {
1768
+ function: "TRANSPOSE",
1769
+ description: "Transposes the rows and columns of an array.",
1770
+ syntax: "TRANSPOSE(Array)"
1771
+ }
1772
+ ],
1773
+ Operator: [
1774
+ {
1775
+ function: "HF.ADD",
1776
+ description: "Adds two values.",
1777
+ syntax: "HF.ADD(Number, Number)"
1778
+ },
1779
+ {
1780
+ function: "HF.CONCAT",
1781
+ description: "Concatenates two strings.",
1782
+ syntax: "HF.CONCAT(String, String)"
1783
+ },
1784
+ {
1785
+ function: "HF.DIVIDE",
1786
+ description: "Divides two values.",
1787
+ syntax: "HF.DIVIDE(Number, Number)"
1788
+ },
1789
+ {
1790
+ function: "HF.EQ",
1791
+ description: "Tests two values for equality.",
1792
+ syntax: "HF.EQ(Value, Value)"
1793
+ },
1794
+ {
1795
+ function: "HF.LTE",
1796
+ description: "Tests two values for less-equal relation.",
1797
+ syntax: "HF.LEQ(Value, Value)"
1798
+ },
1799
+ {
1800
+ function: "HF.LT",
1801
+ description: "Tests two values for less-than relation.",
1802
+ syntax: "HF.LT(Value, Value)"
1803
+ },
1804
+ {
1805
+ function: "HF.GTE",
1806
+ description: "Tests two values for greater-equal relation.",
1807
+ syntax: "HF.GEQ(Value, Value)"
1808
+ },
1809
+ {
1810
+ function: "HF.GT",
1811
+ description: "Tests two values for greater-than relation.",
1812
+ syntax: "HF.GT(Value, Value)"
1813
+ },
1814
+ {
1815
+ function: "HF.MINUS",
1816
+ description: "Subtracts two values.",
1817
+ syntax: "HF.MINUS(Number, Number)"
1818
+ },
1819
+ {
1820
+ function: "HF.MULTIPLY",
1821
+ description: "Multiplies two values.",
1822
+ syntax: "HF.MULTIPLY(Number, Number)"
1823
+ },
1824
+ {
1825
+ function: "HF.NE",
1826
+ description: "Tests two values for inequality.",
1827
+ syntax: "HF.NE(Value, Value)"
1828
+ },
1829
+ {
1830
+ function: "HF.POW",
1831
+ description: "Computes power of two values.",
1832
+ syntax: "HF.POW(Number, Number)"
1833
+ },
1834
+ {
1835
+ function: "HF.UMINUS",
1836
+ description: "Negates the value.",
1837
+ syntax: "HF.UMINUS(Number)"
1838
+ },
1839
+ {
1840
+ function: "HF.UNARY_PERCENT",
1841
+ description: "Applies percent operator.",
1842
+ syntax: "HF.UNARY_PERCENT(Number)"
1843
+ },
1844
+ {
1845
+ function: "HF.UPLUS",
1846
+ description: "Applies unary plus.",
1847
+ syntax: "HF.UPLUS(Number)"
1848
+ }
1849
+ ],
1850
+ Statistical: [
1851
+ {
1852
+ function: "AVEDEV",
1853
+ description: "Returns the average deviation of the arguments.",
1854
+ syntax: "AVEDEV(Number1, Number2, ...NumberN)"
1855
+ },
1856
+ {
1857
+ function: "AVERAGE",
1858
+ description: "Returns the average of the arguments.",
1859
+ syntax: "AVERAGE(Number1, Number2, ...NumberN)"
1860
+ },
1861
+ {
1862
+ function: "AVERAGEA",
1863
+ description: "Returns the average of the arguments.",
1864
+ syntax: "AVERAGEA(Value1, Value2, ...ValueN)"
1865
+ },
1866
+ {
1867
+ function: "AVERAGEIF",
1868
+ description: "Returns the arithmetic mean of all cells in a range that satisfy a given condition.",
1869
+ syntax: "AVERAGEIF(Range, Criterion [, Average_Range ])"
1870
+ },
1871
+ {
1872
+ function: "BESSELI",
1873
+ description: "Returns value of Bessel function.",
1874
+ syntax: "BESSELI(x, n)"
1875
+ },
1876
+ {
1877
+ function: "BESSELJ",
1878
+ description: "Returns value of Bessel function.",
1879
+ syntax: "BESSELJ(x, n)"
1880
+ },
1881
+ {
1882
+ function: "BESSELK",
1883
+ description: "Returns value of Bessel function.",
1884
+ syntax: "BESSELK(x, n)"
1885
+ },
1886
+ {
1887
+ function: "BESSELY",
1888
+ description: "Returns value of Bessel function.",
1889
+ syntax: "BESSELY(x, n)"
1890
+ },
1891
+ {
1892
+ function: "BETA.DIST",
1893
+ description: "Returns the density of Beta distribution.",
1894
+ syntax: "BETA.DIST(Number1, Number2, Number3, Boolean[, Number4[, Number5]])"
1895
+ },
1896
+ {
1897
+ function: "BETADIST",
1898
+ description: "Returns the density of Beta distribution.",
1899
+ syntax: "BETADIST(Number1, Number2, Number3, Boolean[, Number4[, Number5]])"
1900
+ },
1901
+ {
1902
+ function: "BETA.INV",
1903
+ description: "Returns the inverse Beta distribution value.",
1904
+ syntax: "BETA.INV(Number1, Number2, Number3[, Number4[, Number5]])"
1905
+ },
1906
+ {
1907
+ function: "BETAINV",
1908
+ description: "Returns the inverse of Beta distribution value.",
1909
+ syntax: "BETAINV(Number1, Number2, Number3[, Number4[, Number5]])"
1910
+ },
1911
+ {
1912
+ function: "BINOM.DIST",
1913
+ description: "Returns density of binomial distribution.",
1914
+ syntax: "BINOM.DIST(Number1, Number2, Number3, Boolean)"
1915
+ },
1916
+ {
1917
+ function: "BINOMDIST",
1918
+ description: "Returns density of binomial distribution.",
1919
+ syntax: "BINOMDIST(Number1, Number2, Number3, Boolean)"
1920
+ },
1921
+ {
1922
+ function: "BINOM.INV",
1923
+ description: "Returns inverse binomial distribution value.",
1924
+ syntax: "BINOM.INV(Number1, Number2, Number3)"
1925
+ },
1926
+ {
1927
+ function: "CHIDIST",
1928
+ description: "Returns probability of chi-square right-side distribution.",
1929
+ syntax: "CHIDIST(X, Degrees)"
1930
+ },
1931
+ {
1932
+ function: "CHIINV",
1933
+ description: "Returns inverse of chi-square right-side distribution.",
1934
+ syntax: "CHIINV(P, Degrees)"
1935
+ },
1936
+ {
1937
+ function: "CHIINVRT",
1938
+ description: "Returns inverse of chi-square right-side distribution.",
1939
+ syntax: "CHIINVRT(P, Degrees)"
1940
+ },
1941
+ {
1942
+ function: "CHISQ.DIST",
1943
+ description: "Returns value of chi-square distribution.",
1944
+ syntax: "CHISQ.DIST(X, Degrees, Mode)"
1945
+ },
1946
+ {
1947
+ function: "CHIDISTRT",
1948
+ description: "Returns probability of chi-square right-side distribution.",
1949
+ syntax: "CHIDISTRT(X, Degrees)"
1950
+ },
1951
+ {
1952
+ function: "CHISQ.DIST.RT",
1953
+ description: "Returns probability of chi-square right-side distribution.",
1954
+ syntax: "CHISQ.DIST.RT(X, Degrees)"
1955
+ },
1956
+ {
1957
+ function: "CHISQ.INV",
1958
+ description: "Returns inverse of chi-square distribution.",
1959
+ syntax: "CHISQ.INV.RT(P, Degrees)"
1960
+ },
1961
+ {
1962
+ function: "CHISQ.INV.RT",
1963
+ description: "Returns inverse of chi-square right-side distribution.",
1964
+ syntax: "CHISQ.INV.RT(P, Degrees)"
1965
+ },
1966
+ {
1967
+ function: "CHISQ.TEST",
1968
+ description: "Returns chi-squared-test value for a dataset.",
1969
+ syntax: "CHISQ.TEST(Array1, Array2)"
1970
+ },
1971
+ {
1972
+ function: "CHITEST",
1973
+ description: "Returns chi-squared-test value for a dataset.",
1974
+ syntax: "CHITEST(Array1, Array2)"
1975
+ },
1976
+ {
1977
+ function: "CONFIDENCE",
1978
+ description: "Returns upper confidence bound for normal distribution.",
1979
+ syntax: "CONFIDENCE(Alpha, Stdev, Size)"
1980
+ },
1981
+ {
1982
+ function: "CONFIDENCE.NORM",
1983
+ description: "Returns upper confidence bound for normal distribution.",
1984
+ syntax: "CONFIDENCE.NORM(Alpha, Stdev, Size)"
1985
+ },
1986
+ {
1987
+ function: "CONFIDENCE.T",
1988
+ description: "Returns upper confidence bound for T distribution.",
1989
+ syntax: "CONFIDENCE.T(Alpha, Stdev, Size)"
1990
+ },
1991
+ {
1992
+ function: "CORREL",
1993
+ description: "Returns the correlation coefficient between two data sets.",
1994
+ syntax: "CORREL(Data1, Data2)"
1995
+ },
1996
+ {
1997
+ function: "COUNT",
1998
+ description: "Counts how many numbers are in the list of arguments.",
1999
+ syntax: "COUNT(Value1, Value2, ...ValueN)"
2000
+ },
2001
+ {
2002
+ function: "COUNTA",
2003
+ description: "Counts how many values are in the list of arguments.",
2004
+ syntax: "COUNTA(Value1, Value2, ...ValueN)"
2005
+ },
2006
+ {
2007
+ function: "COUNTBLANK",
2008
+ description: "Returns the number of empty cells.",
2009
+ syntax: "COUNTBLANK(Range)"
2010
+ },
2011
+ {
2012
+ function: "COUNTIF",
2013
+ description: "Returns the number of cells that meet with certain criteria within a cell range.",
2014
+ syntax: "COUNTIF(Range, Criteria)"
2015
+ },
2016
+ {
2017
+ function: "COUNTIFS",
2018
+ description: "Returns the count of rows or columns that meet criteria in multiple ranges.",
2019
+ syntax: "COUNTIFS(Range1, Criterion1 [, Range2, Criterion2 [, ...RangeN, CriterionN]])"
2020
+ },
2021
+ {
2022
+ function: "COVAR",
2023
+ description: "Returns the covariance between two data sets, population normalized.",
2024
+ syntax: "COVAR(Data1, Data2)"
2025
+ },
2026
+ {
2027
+ function: "COVARIANCE.P",
2028
+ description: "Returns the covariance between two data sets, population normalized.",
2029
+ syntax: "COVARIANCE.P(Data1, Data2)"
2030
+ },
2031
+ {
2032
+ function: "COVARIANCEP",
2033
+ description: "Returns the covariance between two data sets, population normalized.",
2034
+ syntax: "COVARIANCEP(Data1, Data2)"
2035
+ },
2036
+ {
2037
+ function: "COVARIANCE.S",
2038
+ description: "Returns the covariance between two data sets, sample normalized.",
2039
+ syntax: "COVARIANCE.S(Data1, Data2)"
2040
+ },
2041
+ {
2042
+ function: "COVARIANCES",
2043
+ description: "Returns the covariance between two data sets, sample normalized.",
2044
+ syntax: "COVARIANCES(Data1, Data2)"
2045
+ },
2046
+ {
2047
+ function: "CRITBINOM",
2048
+ description: "Returns inverse binomial distribution value.",
2049
+ syntax: "CRITBINOM(Number1, Number2, Number3)"
2050
+ },
2051
+ {
2052
+ function: "DEVSQ",
2053
+ description: "Returns sum of squared deviations.",
2054
+ syntax: "DEVSQ(Number1, Number2, ...NumberN)"
2055
+ },
2056
+ {
2057
+ function: "EXPON.DIST",
2058
+ description: "Returns density of an exponential distribution.",
2059
+ syntax: "EXPON.DIST(Number1, Number2, Boolean)"
2060
+ },
2061
+ {
2062
+ function: "EXPONDIST",
2063
+ description: "Returns density of an exponential distribution.",
2064
+ syntax: "EXPONDIST(Number1, Number2, Boolean)"
2065
+ },
2066
+ {
2067
+ function: "FDIST",
2068
+ description: "Returns probability of F right-side distribution.",
2069
+ syntax: "FDIST(X, Degree1, Degree2)"
2070
+ },
2071
+ {
2072
+ function: "FINV",
2073
+ description: "Returns inverse of F right-side distribution.",
2074
+ syntax: "FINV(P, Degree1, Degree2)"
2075
+ },
2076
+ {
2077
+ function: "F.DIST",
2078
+ description: "Returns value of F distribution.",
2079
+ syntax: "F.DIST(X, Degree1, Degree2, Mode)"
2080
+ },
2081
+ {
2082
+ function: "F.DIST.RT",
2083
+ description: "Returns probability of F right-side distribution.",
2084
+ syntax: "F.DIST.RT(X, Degree1, Degree2)"
2085
+ },
2086
+ {
2087
+ function: "FDISTRT",
2088
+ description: "Returns probability of F right-side distribution.",
2089
+ syntax: "FDISTRT(X, Degree1, Degree2)"
2090
+ },
2091
+ {
2092
+ function: "F.INV",
2093
+ description: "Returns inverse of F distribution.",
2094
+ syntax: "F.INV.RT(P, Degree1, Degree2)"
2095
+ },
2096
+ {
2097
+ function: "F.INV.RT",
2098
+ description: "Returns inverse of F right-side distribution.",
2099
+ syntax: "F.INV.RT(P, Degree1, Degree2)"
2100
+ },
2101
+ {
2102
+ function: "FINVRT",
2103
+ description: "Returns inverse of F right-side distribution.",
2104
+ syntax: "FINVRT(P, Degree1, Degree2)"
2105
+ },
2106
+ {
2107
+ function: "FISHER",
2108
+ description: "Returns Fisher transformation value.",
2109
+ syntax: "FISHER(Number)"
2110
+ },
2111
+ {
2112
+ function: "FISHERINV",
2113
+ description: "Returns inverse Fisher transformation value.",
2114
+ syntax: "FISHERINV(Number)"
2115
+ },
2116
+ {
2117
+ function: "F.TEST",
2118
+ description: "Returns f-test value for a dataset.",
2119
+ syntax: "Z.TEST(Array1, Array2)"
2120
+ },
2121
+ {
2122
+ function: "FTEST",
2123
+ description: "Returns f-test value for a dataset.",
2124
+ syntax: "ZTEST(Array1, Array2)"
2125
+ },
2126
+ {
2127
+ function: "GAMMA",
2128
+ description: "Returns value of Gamma function.",
2129
+ syntax: "GAMMA(Number)"
2130
+ },
2131
+ {
2132
+ function: "GAMMA.DIST",
2133
+ description: "Returns density of Gamma distribution.",
2134
+ syntax: "GAMMA.DIST(Number1, Number2, Number3, Boolean)"
2135
+ },
2136
+ {
2137
+ function: "GAMMADIST",
2138
+ description: "Returns density of Gamma distribution.",
2139
+ syntax: "GAMMADIST(Number1, Number2, Number3, Boolean)"
2140
+ },
2141
+ {
2142
+ function: "GAMMALN",
2143
+ description: "Returns natural logarithm of Gamma function.",
2144
+ syntax: "GAMMALN(Number)"
2145
+ },
2146
+ {
2147
+ function: "GAMMALN.PRECISE",
2148
+ description: "Returns natural logarithm of Gamma function.",
2149
+ syntax: "GAMMALN.PRECISE(Number)"
2150
+ },
2151
+ {
2152
+ function: "GAMMA.INV",
2153
+ description: "Returns inverse Gamma distribution value.",
2154
+ syntax: "GAMMA.INV(Number1, Number2, Number3)"
2155
+ },
2156
+ {
2157
+ function: "GAMMAINV",
2158
+ description: "Returns inverse Gamma distribution value.",
2159
+ syntax: "GAMMAINV(Number1, Number2, Number3)"
2160
+ },
2161
+ {
2162
+ function: "GAUSS",
2163
+ description: "Returns the probability of gaussian variable fall more than this many times standard deviation from mean.",
2164
+ syntax: "GAUSS(Number)"
2165
+ },
2166
+ {
2167
+ function: "GEOMEAN",
2168
+ description: "Returns the geometric average.",
2169
+ syntax: "GEOMEAN(Number1, Number2, ...NumberN)"
2170
+ },
2171
+ {
2172
+ function: "HARMEAN",
2173
+ description: "Returns the harmonic average.",
2174
+ syntax: "HARMEAN(Number1, Number2, ...NumberN)"
2175
+ },
2176
+ {
2177
+ function: "HYPGEOMDIST",
2178
+ description: "Returns density of hypergeometric distribution.",
2179
+ syntax: "HYPGEOMDIST(Number1, Number2, Number3, Number4, Boolean)"
2180
+ },
2181
+ {
2182
+ function: "HYPGEOM.DIST",
2183
+ description: "Returns density of hypergeometric distribution.",
2184
+ syntax: "HYPGEOM.DIST(Number1, Number2, Number3, Number4, Boolean)"
2185
+ },
2186
+ {
2187
+ function: "LARGE",
2188
+ description: "Returns k-th largest value in a range.",
2189
+ syntax: "LARGE(Range, K)"
2190
+ },
2191
+ {
2192
+ function: "LOGNORM.DIST",
2193
+ description: "Returns density of lognormal distribution.",
2194
+ syntax: "LOGNORM.DIST(X, Mean, Stddev, Mode)"
2195
+ },
2196
+ {
2197
+ function: "LOGNORMDIST",
2198
+ description: "Returns density of lognormal distribution.",
2199
+ syntax: "LOGNORMDIST(X, Mean, Stddev, Mode)"
2200
+ },
2201
+ {
2202
+ function: "LOGNORM.INV",
2203
+ description: "Returns value of inverse lognormal distribution.",
2204
+ syntax: "LOGNORM.INV(P, Mean, Stddev)"
2205
+ },
2206
+ {
2207
+ function: "LOGNORMINV",
2208
+ description: "Returns value of inverse lognormal distribution.",
2209
+ syntax: "LOGNORMINV(P, Mean, Stddev)"
2210
+ },
2211
+ {
2212
+ function: "LOGINV",
2213
+ description: "Returns value of inverse lognormal distribution.",
2214
+ syntax: "LOGINV(P, Mean, Stddev)"
2215
+ },
2216
+ {
2217
+ function: "MAX",
2218
+ description: "Returns the maximum value in a list of arguments.",
2219
+ syntax: "MAX(Number1, Number2, ...NumberN)"
2220
+ },
2221
+ {
2222
+ function: "MAXA",
2223
+ description: "Returns the maximum value in a list of arguments.",
2224
+ syntax: "MAXA(Value1, Value2, ...ValueN)"
2225
+ },
2226
+ {
2227
+ function: "MAXIFS",
2228
+ description: "Returns the maximum value of the cells in a range that meet a set of criteria.",
2229
+ syntax: "MAXIFS(Max_Range, Criterion_range1, Criterion1 [, Criterion_range2, Criterion2 [, ...Criterion_rangeN, CriterionN]])"
2230
+ },
2231
+ {
2232
+ function: "MEDIAN",
2233
+ description: "Returns the median of a set of numbers.",
2234
+ syntax: "MEDIAN(Number1, Number2, ...NumberN)"
2235
+ },
2236
+ {
2237
+ function: "MIN",
2238
+ description: "Returns the minimum value in a list of arguments.",
2239
+ syntax: "MIN(Number1, Number2, ...NumberN)"
2240
+ },
2241
+ {
2242
+ function: "MINA",
2243
+ description: "Returns the minimum value in a list of arguments.",
2244
+ syntax: "MINA(Value1, Value2, ...ValueN)"
2245
+ },
2246
+ {
2247
+ function: "MINIFS",
2248
+ description: "Returns the minimum value of the cells in a range that meet a set of criteria.",
2249
+ syntax: "MINIFS(Min_Range, Criterion_range1, Criterion1 [, Criterion_range2, Criterion2 [, ...Criterion_rangeN, CriterionN]])"
2250
+ },
2251
+ {
2252
+ function: "NEGBINOM.DIST",
2253
+ description: "Returns density of negative binomial distribution.",
2254
+ syntax: "NEGBINOM.DIST(Number1, Number2, Number3, Mode)"
2255
+ },
2256
+ {
2257
+ function: "NEGBINOMDIST",
2258
+ description: "Returns density of negative binomial distribution.",
2259
+ syntax: "NEGBINOMDIST(Number1, Number2, Number3, Mode)"
2260
+ },
2261
+ {
2262
+ function: "NORM.DIST",
2263
+ description: "Returns density of normal distribution.",
2264
+ syntax: "NORM.DIST(X, Mean, Stddev, Mode)"
2265
+ },
2266
+ {
2267
+ function: "NORMDIST",
2268
+ description: "Returns density of normal distribution.",
2269
+ syntax: "NORMDIST(X, Mean, Stddev, Mode)"
2270
+ },
2271
+ {
2272
+ function: "NORM.S.DIST",
2273
+ description: "Returns density of normal distribution.",
2274
+ syntax: "NORM.S.DIST(X, Mode)"
2275
+ },
2276
+ {
2277
+ function: "NORMDIST",
2278
+ description: "Returns density of normal distribution.",
2279
+ syntax: "NORMSDIST(X, Mode)"
2280
+ },
2281
+ {
2282
+ function: "NORM.INV",
2283
+ description: "Returns value of inverse normal distribution.",
2284
+ syntax: "NORM.INV(P, Mean, Stddev)"
2285
+ },
2286
+ {
2287
+ function: "NORMINV",
2288
+ description: "Returns value of inverse normal distribution.",
2289
+ syntax: "NORMINV(P, Mean, Stddev)"
2290
+ },
2291
+ {
2292
+ function: "NORM.S.INV",
2293
+ description: "Returns value of inverse normal distribution.",
2294
+ syntax: "NORM.S.INV(P)"
2295
+ },
2296
+ {
2297
+ function: "NORMSINV",
2298
+ description: "Returns value of inverse normal distribution.",
2299
+ syntax: "NORMSINV(P)"
2300
+ },
2301
+ {
2302
+ function: "PEARSON",
2303
+ description: "Returns the correlation coefficient between two data sets.",
2304
+ syntax: "PEARSON(Data1, Data2)"
2305
+ },
2306
+ {
2307
+ function: "PHI",
2308
+ description: "Returns probability density of normal distribution.",
2309
+ syntax: "PHI(X)"
2310
+ },
2311
+ {
2312
+ function: "POISSON",
2313
+ description: "Returns density of Poisson distribution.",
2314
+ syntax: "POISSON(X, Mean, Mode)"
2315
+ },
2316
+ {
2317
+ function: "POISSON.DIST",
2318
+ description: "Returns density of Poisson distribution.",
2319
+ syntax: "POISSON.DIST(X, Mean, Mode)"
2320
+ },
2321
+ {
2322
+ function: "POISSONDIST",
2323
+ description: "Returns density of Poisson distribution.",
2324
+ syntax: "POISSONDIST(X, Mean, Mode)"
2325
+ },
2326
+ {
2327
+ function: "RSQ",
2328
+ description: "Returns the squared correlation coefficient between two data sets.",
2329
+ syntax: "RSQ(Data1, Data2)"
2330
+ },
2331
+ {
2332
+ function: "SKEW",
2333
+ description: "Returns skewness of a sample.",
2334
+ syntax: "SKEW(Number1, Number2, ...NumberN)"
2335
+ },
2336
+ {
2337
+ function: "SKEW.P",
2338
+ description: "Returns skewness of a population.",
2339
+ syntax: "SKEW.P(Number1, Number2, ...NumberN)"
2340
+ },
2341
+ {
2342
+ function: "SKEWP",
2343
+ description: "Returns skewness of a population.",
2344
+ syntax: "SKEWP(Number1, Number2, ...NumberN)"
2345
+ },
2346
+ {
2347
+ function: "SLOPE",
2348
+ description: "Returns the slope of a linear regression line.",
2349
+ syntax: "SLOPE(Array1, Array2)"
2350
+ },
2351
+ {
2352
+ function: "SMALL",
2353
+ description: "Returns k-th smallest value in a range.",
2354
+ syntax: "SMALL(Range, K)"
2355
+ },
2356
+ {
2357
+ function: "STANDARDIZE",
2358
+ description: "Returns normalized value with respect to expected value and standard deviation.",
2359
+ syntax: "STANDARDIZE(X, Mean, Stddev)"
2360
+ },
2361
+ {
2362
+ function: "STDEV",
2363
+ description: "Returns standard deviation of a sample.",
2364
+ syntax: "STDEV(Value1, Value2, ...ValueN)"
2365
+ },
2366
+ {
2367
+ function: "STDEVA",
2368
+ description: "Returns standard deviation of a sample.",
2369
+ syntax: "STDEVA(Value1, Value2, ...ValueN)"
2370
+ },
2371
+ {
2372
+ function: "STDEVP",
2373
+ description: "Returns standard deviation of a population.",
2374
+ syntax: "STDEVP(Value1, Value2, ...ValueN)"
2375
+ },
2376
+ {
2377
+ function: "STDEV.P",
2378
+ description: "Returns standard deviation of a population.",
2379
+ syntax: "STDEV.P(Value1, Value2, ...ValueN)"
2380
+ },
2381
+ {
2382
+ function: "STDEVPA",
2383
+ description: "Returns standard deviation of a population.",
2384
+ syntax: "STDEVPA(Value1, Value2, ...ValueN)"
2385
+ },
2386
+ {
2387
+ function: "STDEV.S",
2388
+ description: "Returns standard deviation of a sample.",
2389
+ syntax: "STDEV.S(Value1, Value2, ...ValueN)"
2390
+ },
2391
+ {
2392
+ function: "STDEVS",
2393
+ description: "Returns standard deviation of a sample.",
2394
+ syntax: "STDEVS(Value1, Value2, ...ValueN)"
2395
+ },
2396
+ {
2397
+ function: "STEYX",
2398
+ description: "Returns standard error for predicted of the predicted y value for each x value.",
2399
+ syntax: "STEYX(Array1, Array2)"
2400
+ },
2401
+ {
2402
+ function: "TDIST",
2403
+ description: "Returns density of Student-t distribution, both-sided or right-tailed.",
2404
+ syntax: "TDIST(X, Degrees, Mode)"
2405
+ },
2406
+ {
2407
+ function: "T.DIST",
2408
+ description: "Returns density of Student-t distribution.",
2409
+ syntax: "T.DIST(X, Degrees, Mode)"
2410
+ },
2411
+ {
2412
+ function: "T.DIST.2T",
2413
+ description: "Returns density of Student-t distribution, both-sided.",
2414
+ syntax: "T.DIST.2T(X, Degrees)"
2415
+ },
2416
+ {
2417
+ function: "TDIST2T",
2418
+ description: "Returns density of Student-t distribution, both-sided.",
2419
+ syntax: "TDIST2T(X, Degrees)"
2420
+ },
2421
+ {
2422
+ function: "T.DIST.RT",
2423
+ description: "Returns density of Student-t distribution, right-tailed.",
2424
+ syntax: "T.DIST.RT(X, Degrees)"
2425
+ },
2426
+ {
2427
+ function: "TDISTRT",
2428
+ description: "Returns density of Student-t distribution, right-tailed.",
2429
+ syntax: "TDISTRT(X, Degrees)"
2430
+ },
2431
+ {
2432
+ function: "TINV",
2433
+ description: "Returns inverse Student-t distribution, both-sided.",
2434
+ syntax: "TINV(P, Degrees)"
2435
+ },
2436
+ {
2437
+ function: "T.INV",
2438
+ description: "Returns inverse Student-t distribution.",
2439
+ syntax: "T.INV(P, Degrees)"
2440
+ },
2441
+ {
2442
+ function: "T.INV.2T",
2443
+ description: "Returns inverse Student-t distribution, both-sided.",
2444
+ syntax: "T.INV.2T(P, Degrees)"
2445
+ },
2446
+ {
2447
+ function: "TINV2T",
2448
+ description: "Returns inverse Student-t distribution, both-sided.",
2449
+ syntax: "TINV2T(P, Degrees)"
2450
+ },
2451
+ {
2452
+ function: "TTEST",
2453
+ description: "Returns t-test value for a dataset.",
2454
+ syntax: "TTEST(Array1, Array2)"
2455
+ },
2456
+ {
2457
+ function: "T.TEST",
2458
+ description: "Returns t-test value for a dataset.",
2459
+ syntax: "T.TEST(Array1, Array2)"
2460
+ },
2461
+ {
2462
+ function: "VAR",
2463
+ description: "Returns variance of a sample.",
2464
+ syntax: "VAR(Value1, Value2, ...ValueN)"
2465
+ },
2466
+ {
2467
+ function: "VARA",
2468
+ description: "Returns variance of a sample.",
2469
+ syntax: "VARA(Value1, Value2, ...ValueN)"
2470
+ },
2471
+ {
2472
+ function: "VARP",
2473
+ description: "Returns variance of a population.",
2474
+ syntax: "VARP(Value1, Value2, ...ValueN)"
2475
+ },
2476
+ {
2477
+ function: "VAR.P",
2478
+ description: "Returns variance of a population.",
2479
+ syntax: "VAR.P(Value1, Value2, ...ValueN)"
2480
+ },
2481
+ {
2482
+ function: "VARPA",
2483
+ description: "Returns variance of a population.",
2484
+ syntax: "VARPA(Value1, Value2, ...ValueN)"
2485
+ },
2486
+ {
2487
+ function: "VAR.S",
2488
+ description: "Returns variance of a sample.",
2489
+ syntax: "VAR.S(Value1, Value2, ...ValueN)"
2490
+ },
2491
+ {
2492
+ function: "VARS",
2493
+ description: "Returns variance of a sample.",
2494
+ syntax: "VARS(Value1, Value2, ...ValueN)"
2495
+ },
2496
+ {
2497
+ function: "WEIBULL",
2498
+ description: "Returns density of Weibull distribution.",
2499
+ syntax: "WEIBULL(Number1, Number2, Number3, Boolean)"
2500
+ },
2501
+ {
2502
+ function: "WEIBULL.DIST",
2503
+ description: "Returns density of Weibull distribution.",
2504
+ syntax: "WEIBULL.DIST(Number1, Number2, Number3, Boolean)"
2505
+ },
2506
+ {
2507
+ function: "WEIBULLDIST",
2508
+ description: "Returns density of Weibull distribution.",
2509
+ syntax: "WEIBULLDIST(Number1, Number2, Number3, Boolean)"
2510
+ },
2511
+ {
2512
+ function: "Z.TEST",
2513
+ description: "Returns z-test value for a dataset.",
2514
+ syntax: "Z.TEST(Array, X[, Sigma])"
2515
+ },
2516
+ {
2517
+ function: "ZTEST",
2518
+ description: "Returns z-test value for a dataset.",
2519
+ syntax: "ZTEST(Array, X[, Sigma])"
2520
+ }
2521
+ ],
2522
+ Text: [
2523
+ {
2524
+ function: "CHAR",
2525
+ description: "Converts a number into a character according to the current code table.",
2526
+ syntax: "CHAR(Number)"
2527
+ },
2528
+ {
2529
+ function: "CLEAN",
2530
+ description: 'Returns text that has been "cleaned" of line breaks and other non-printable characters.',
2531
+ syntax: 'CLEAN("Text")'
2532
+ },
2533
+ {
2534
+ function: "CODE",
2535
+ description: "Returns a numeric code for the first character in a text string.",
2536
+ syntax: 'CODE("Text")'
2537
+ },
2538
+ {
2539
+ function: "CONCATENATE",
2540
+ description: "Combines several text strings into one string.",
2541
+ syntax: 'CONCATENATE("Text1", "Text2", ..."TextN")'
2542
+ },
2543
+ {
2544
+ function: "EXACT",
2545
+ description: "Returns TRUE if both text strings are exactly the same.",
2546
+ syntax: "EXACT(Text, Text)"
2547
+ },
2548
+ {
2549
+ function: "FIND",
2550
+ description: "Returns the location of one text string inside another.",
2551
+ syntax: 'FIND( "Text1", "Text2"[, Number])'
2552
+ },
2553
+ {
2554
+ function: "LEFT",
2555
+ description: "Extracts a given number of characters from the left side of a text string.",
2556
+ syntax: 'LEFT("Text", Number)'
2557
+ },
2558
+ {
2559
+ function: "LEN",
2560
+ description: "Returns length of a given text.",
2561
+ syntax: 'LEN("Text")'
2562
+ },
2563
+ {
2564
+ function: "LOWER",
2565
+ description: "Returns text converted to lowercase.",
2566
+ syntax: "LOWER(Text)"
2567
+ },
2568
+ {
2569
+ function: "MID",
2570
+ description: "Returns substring of a given length starting from Start_position.",
2571
+ syntax: "MID(Text, Start_position, Length)"
2572
+ },
2573
+ {
2574
+ function: "PROPER",
2575
+ description: "Capitalizes words given text string.",
2576
+ syntax: 'PROPER("Text")'
2577
+ },
2578
+ {
2579
+ function: "REPLACE",
2580
+ description: "Replaces substring of a text of a given length that starts at given position.",
2581
+ syntax: "REPLACE(Text, Start_position, Length, New_text)"
2582
+ },
2583
+ {
2584
+ function: "REPT",
2585
+ description: "Repeats text a given number of times.",
2586
+ syntax: 'REPT("Text", Number)'
2587
+ },
2588
+ {
2589
+ function: "RIGHT",
2590
+ description: "Extracts a given number of characters from the right side of a text string.",
2591
+ syntax: 'RIGHT("Text", Number)'
2592
+ },
2593
+ {
2594
+ function: "SEARCH",
2595
+ description: "Returns the location of Search_string inside Text. Case-insensitive. Allows the use of wildcards.",
2596
+ syntax: "SEARCH(Search_string, Text[, Start_position])"
2597
+ },
2598
+ {
2599
+ function: "SPLIT",
2600
+ description: "Divides the provided text using the space character as a separator and returns the substring at the zero-based position specified by the second argument.",
2601
+ syntax: "SPLIT(Text, Index)"
2602
+ },
2603
+ {
2604
+ function: "SUBSTITUTE",
2605
+ description: "Returns string where occurrences of Old_text are replaced by New_text. Replaces only specific occurrence if last parameter is provided.",
2606
+ syntax: "SUBSTITUTE(Text, Old_text, New_text, [Occurrence])"
2607
+ },
2608
+ {
2609
+ function: "T",
2610
+ description: "Returns text if given value is text, empty string otherwise.",
2611
+ syntax: "T(Value)"
2612
+ },
2613
+ {
2614
+ function: "TEXT",
2615
+ description: "Converts a number into text according to a given format.",
2616
+ syntax: "TEXT(Number, Format)"
2617
+ },
2618
+ {
2619
+ function: "TRIM",
2620
+ description: "Strips extra spaces from text.",
2621
+ syntax: 'TRIM("Text")'
2622
+ },
2623
+ {
2624
+ function: "UNICHAR",
2625
+ description: "Returns the character created by using provided code point.",
2626
+ syntax: "UNICHAR(Number)"
2627
+ },
2628
+ {
2629
+ function: "UNICODE",
2630
+ description: "Returns the Unicode code point of a first character of a text.",
2631
+ syntax: "UNICODE(Text)"
2632
+ },
2633
+ {
2634
+ function: "UPPER",
2635
+ description: "Returns text converted to uppercase.",
2636
+ syntax: "UPPER(Text)"
2637
+ }
2638
+ ]
2639
+ };
2640
+
2641
+ // packages/plugins/plugin-sheet/src/components/CellEditor/extension.ts
2642
+ var highlightStyles = HighlightStyle.define([
2643
+ // Function.
2644
+ {
2645
+ tag: tags.name,
2646
+ class: "text-primary-500"
2647
+ },
2648
+ // Range.
2649
+ {
2650
+ tag: tags.tagName,
2651
+ class: "text-pink-500"
2652
+ },
2653
+ // Values.
2654
+ {
2655
+ tag: tags.number,
2656
+ class: "text-teal-500"
2657
+ },
2658
+ {
2659
+ tag: tags.bool,
2660
+ class: "text-teal-500"
2661
+ },
2662
+ {
2663
+ tag: tags.string,
2664
+ class: "text-teal-500"
2665
+ },
2666
+ // Error.
2667
+ {
2668
+ tag: tags.invalid,
2669
+ class: "text-neutral-500"
2670
+ }
2671
+ ]);
2672
+ var languageFacet = Facet.define();
2673
+ var sheetExtension = ({ functions: functions2 }) => {
2674
+ const { extension, language } = spreadsheet({
2675
+ idiom: "en-US",
2676
+ decimalSeparator: "."
2677
+ });
2678
+ const functionInfo = Object.entries(functions).reduce((map, [section, values]) => {
2679
+ values.forEach(({ function: id, ...props }) => {
2680
+ map.set(id, {
2681
+ function: id,
2682
+ ...props,
2683
+ section
2684
+ });
2685
+ });
2686
+ return map;
2687
+ }, /* @__PURE__ */ new Map());
2688
+ const createCompletion = (name) => {
2689
+ const { section, description, syntax } = functionInfo.get(name) ?? {
2690
+ section: "Custom"
2691
+ };
2692
+ return {
2693
+ section,
2694
+ label: name,
2695
+ info: () => {
2696
+ if (!description && !syntax) {
2697
+ return null;
2698
+ }
2699
+ const root = document.createElement("div");
2700
+ root.className = "flex flex-col gap-2 text-sm";
2701
+ const title = document.createElement("h2");
2702
+ title.innerText = name;
2703
+ title.className = "text-lg font-mono text-primary-500";
2704
+ root.appendChild(title);
2705
+ if (description) {
2706
+ const info = document.createElement("p");
2707
+ info.innerText = description;
2708
+ info.className = "fg-subdued";
2709
+ root.appendChild(info);
2710
+ }
2711
+ if (syntax) {
2712
+ const detail = document.createElement("pre");
2713
+ detail.innerText = syntax;
2714
+ detail.className = "whitespace-pre-wrap text-green-500";
2715
+ root.appendChild(detail);
2716
+ }
2717
+ return root;
2718
+ },
2719
+ apply: (view, completion, from, to) => {
2720
+ const insertParens = to === view.state.doc.toString().length;
2721
+ view.dispatch(view.state.update({
2722
+ changes: {
2723
+ from,
2724
+ to,
2725
+ insert: completion.label + (insertParens ? "()" : "")
2726
+ },
2727
+ selection: {
2728
+ anchor: from + completion.label.length + 1
2729
+ }
2730
+ }));
2731
+ }
2732
+ };
2733
+ };
2734
+ return [
2735
+ extension,
2736
+ languageFacet.of(language),
2737
+ language.data.of({
2738
+ autocomplete: (context) => {
2739
+ if (context.state.doc.toString()[0] !== "=") {
2740
+ return null;
2741
+ }
2742
+ const match = context.matchBefore(/\w*/);
2743
+ if (!match || match.from === match.to) {
2744
+ return null;
2745
+ }
2746
+ const text = match.text.toUpperCase();
2747
+ if (!context.explicit && match.text.length < 2) {
2748
+ return null;
2749
+ }
2750
+ return {
2751
+ from: match.from,
2752
+ options: functions2?.filter((name) => name.startsWith(text)).map((name) => createCompletion(name)) ?? []
2753
+ };
2754
+ }
2755
+ }),
2756
+ syntaxHighlighting(highlightStyles),
2757
+ autocompletion({
2758
+ aboveCursor: false,
2759
+ defaultKeymap: true,
2760
+ activateOnTyping: true,
2761
+ // NOTE: Useful for debugging.
2762
+ closeOnBlur: false,
2763
+ icons: false,
2764
+ tooltipClass: () => mx(
2765
+ // TODO(burdon): Factor out fragments.
2766
+ // TODO(burdon): Size to make width same as column.
2767
+ "!-left-[1px] !top-[33px] !-m-0 border !border-t-0 [&>ul]:!min-w-[198px]",
2768
+ "[&>ul>li[aria-selected]]:!bg-primary-700",
2769
+ "border-neutral-200 dark:border-neutral-700"
2770
+ )
2771
+ }),
2772
+ keymap2.of([
2773
+ {
2774
+ key: "Tab",
2775
+ run: (view) => {
2776
+ return completionStatus(view.state) === "active" ? acceptCompletion(view) : startCompletion(view);
2777
+ }
2778
+ }
2779
+ ])
2780
+ ];
2781
+ };
2782
+ var rangeExtension = (onInit) => {
2783
+ let view;
2784
+ let activeRange;
2785
+ const provider = (range) => {
2786
+ if (activeRange) {
2787
+ view.dispatch(view.state.update({
2788
+ changes: {
2789
+ ...activeRange,
2790
+ insert: range.toString()
2791
+ },
2792
+ selection: {
2793
+ anchor: activeRange.from + range.length
2794
+ }
2795
+ }));
2796
+ }
2797
+ view.focus();
2798
+ };
2799
+ return ViewPlugin.fromClass(class {
2800
+ constructor(_view) {
2801
+ view = _view;
2802
+ onInit(provider);
2803
+ }
2804
+ update(view2) {
2805
+ const { anchor } = view2.state.selection.ranges[0];
2806
+ activeRange = void 0;
2807
+ const [language] = view2.state.facet(languageFacet);
2808
+ const { topNode } = language.parser.parse(view2.state.doc.toString());
2809
+ visitTree(topNode, ({ type, from, to }) => {
2810
+ if (from <= anchor && to >= anchor) {
2811
+ switch (type.name) {
2812
+ case "Function": {
2813
+ activeRange = {
2814
+ from: to,
2815
+ to
2816
+ };
2817
+ break;
2818
+ }
2819
+ case "RangeToken":
2820
+ case "CellToken":
2821
+ activeRange = {
2822
+ from,
2823
+ to
2824
+ };
2825
+ return true;
2826
+ }
2827
+ }
2828
+ return false;
2829
+ });
2830
+ if (!activeRange && view2.state.doc.toString()[0] === "=") {
2831
+ activeRange = {
2832
+ from: 1,
2833
+ to: view2.state.doc.toString().length
2834
+ };
2835
+ }
2836
+ }
2837
+ });
2838
+ };
2839
+ var visitTree = (node, callback) => {
2840
+ if (callback(node)) {
2841
+ return true;
2842
+ }
2843
+ for (let child = node.firstChild; child !== null; child = child.nextSibling) {
2844
+ if (visitTree(child, callback)) {
2845
+ return true;
2846
+ }
2847
+ }
2848
+ return false;
2849
+ };
2850
+
2851
+ // packages/plugins/plugin-sheet/src/components/Sheet/Sheet.tsx
2852
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/plugins/plugin-sheet/src/components/Sheet/Sheet.tsx";
2853
+ var fragments = {
2854
+ axis: "bg-neutral-50 text-neutral-800 dark:bg-neutral-800 dark:text-neutral-200 text-xs select-none",
2855
+ axisSelected: "bg-neutral-100 dark:bg-neutral-900 text-black dark:text-white",
2856
+ cell: "dark:bg-neutral-850",
2857
+ cellSelected: "bg-neutral-50 dark:bg-neutral-900 text-black dark:text-white border !border-primary-500",
2858
+ border: "border-neutral-200 dark:border-neutral-700"
2859
+ };
2860
+ var SheetRoot = ({ children, ...props }) => {
2861
+ return /* @__PURE__ */ React3.createElement(SheetContextProvider, props, children);
2862
+ };
2863
+ var SheetMain = /* @__PURE__ */ forwardRef(({ classNames, numRows, numColumns }, forwardRef2) => {
2864
+ const { model, cursor, setCursor, setRange, setEditing } = useSheetContext();
2865
+ const { rowsRef, columnsRef, contentRef } = useScrollHandlers();
2866
+ const [rows, setRows] = useState4([
2867
+ ...model.sheet.rows
2868
+ ]);
2869
+ const [columns, setColumns] = useState4([
2870
+ ...model.sheet.columns
2871
+ ]);
2872
+ useEffect3(() => {
2873
+ const rowsAccessor = createDocAccessor(model.sheet, [
2874
+ "rows"
2875
+ ]);
2876
+ const columnsAccessor = createDocAccessor(model.sheet, [
2877
+ "columns"
2878
+ ]);
2879
+ const handleUpdate = debounce(() => {
2880
+ setRows([
2881
+ ...model.sheet.rows
2882
+ ]);
2883
+ setColumns([
2884
+ ...model.sheet.columns
2885
+ ]);
2886
+ }, 100);
2887
+ rowsAccessor.handle.addListener("change", handleUpdate);
2888
+ columnsAccessor.handle.addListener("change", handleUpdate);
2889
+ handleUpdate();
2890
+ return () => {
2891
+ rowsAccessor.handle.removeListener("change", handleUpdate);
2892
+ columnsAccessor.handle.removeListener("change", handleUpdate);
2893
+ };
2894
+ }, [
2895
+ model
2896
+ ]);
2897
+ useEffect3(() => {
2898
+ model.reset();
2899
+ }, [
2900
+ rows,
2901
+ columns
2902
+ ]);
2903
+ const handleMoveRows = (from, to, num = 1) => {
2904
+ const cursorIdx = cursor ? model.addressToIndex(cursor) : void 0;
2905
+ const [rows2] = model.sheet.rows.splice(from, num);
2906
+ model.sheet.rows.splice(to, 0, rows2);
2907
+ if (cursorIdx) {
2908
+ setCursor(model.addressFromIndex(cursorIdx));
2909
+ }
2910
+ setRows([
2911
+ ...model.sheet.rows
2912
+ ]);
2913
+ };
2914
+ const handleMoveColumns = (from, to, num = 1) => {
2915
+ const cursorIdx = cursor ? model.addressToIndex(cursor) : void 0;
2916
+ const columns2 = model.sheet.columns.splice(from, num);
2917
+ model.sheet.columns.splice(to, 0, ...columns2);
2918
+ if (cursorIdx) {
2919
+ setCursor(model.addressFromIndex(cursorIdx));
2920
+ }
2921
+ setColumns([
2922
+ ...model.sheet.columns
2923
+ ]);
2924
+ };
2925
+ const [rowSizes, setRowSizes] = useState4();
2926
+ const [columnSizes, setColumnSizes] = useState4();
2927
+ useEffect3(() => {
2928
+ const rowAccessor = createDocAccessor(model.sheet, [
2929
+ "rowMeta"
2930
+ ]);
2931
+ const columnAccessor = createDocAccessor(model.sheet, [
2932
+ "columnMeta"
2933
+ ]);
2934
+ const handleUpdate = debounce(() => {
2935
+ const mapSizes = (values) => values.reduce((map, [idx, meta]) => {
2936
+ if (meta.size) {
2937
+ map[idx] = meta.size;
2938
+ }
2939
+ return map;
2940
+ }, {});
2941
+ setRowSizes(mapSizes(Object.entries(model.sheet.rowMeta)));
2942
+ setColumnSizes(mapSizes(Object.entries(model.sheet.columnMeta)));
2943
+ }, 100);
2944
+ rowAccessor.handle.addListener("change", handleUpdate);
2945
+ columnAccessor.handle.addListener("change", handleUpdate);
2946
+ handleUpdate();
2947
+ return () => {
2948
+ rowAccessor.handle.removeListener("change", handleUpdate);
2949
+ columnAccessor.handle.removeListener("change", handleUpdate);
2950
+ };
2951
+ }, [
2952
+ model
2953
+ ]);
2954
+ const handleResizeRow = (idx, size, save) => {
2955
+ if (save) {
2956
+ model.sheet.rowMeta[idx] ??= {};
2957
+ model.sheet.rowMeta[idx].size = size;
2958
+ } else {
2959
+ setRowSizes((sizes) => ({
2960
+ ...sizes,
2961
+ [idx]: size
2962
+ }));
2963
+ }
2964
+ };
2965
+ const handleResizeColumn = (idx, size, save) => {
2966
+ if (save) {
2967
+ model.sheet.columnMeta[idx] ??= {};
2968
+ model.sheet.columnMeta[idx].size = size;
2969
+ } else {
2970
+ setColumnSizes((sizes) => ({
2971
+ ...sizes,
2972
+ [idx]: size
2973
+ }));
2974
+ }
2975
+ };
2976
+ return /* @__PURE__ */ React3.createElement("div", {
2977
+ role: "none",
2978
+ className: mx2("grid grid-cols-[calc(var(--rail-size)-2px)_1fr] grid-rows-[32px_1fr_32px] bs-full is-full overflow-hidden", fragments.border, classNames)
2979
+ }, /* @__PURE__ */ React3.createElement(GridCorner, {
2980
+ onClick: () => {
2981
+ setCursor(void 0);
2982
+ setRange(void 0);
2983
+ setEditing(false);
2984
+ }
2985
+ }), /* @__PURE__ */ React3.createElement(SheetColumns, {
2986
+ ref: columnsRef,
2987
+ columns,
2988
+ sizes: columnSizes,
2989
+ selected: cursor?.column,
2990
+ onSelect: (column) => setCursor(cursor?.column === column ? void 0 : {
2991
+ row: -1,
2992
+ column
2993
+ }),
2994
+ onResize: handleResizeColumn,
2995
+ onMove: handleMoveColumns
2996
+ }), /* @__PURE__ */ React3.createElement(SheetRows, {
2997
+ ref: rowsRef,
2998
+ rows,
2999
+ sizes: rowSizes,
3000
+ selected: cursor?.row,
3001
+ onSelect: (row) => setCursor(cursor?.row === row ? void 0 : {
3002
+ row,
3003
+ column: -1
3004
+ }),
3005
+ onResize: handleResizeRow,
3006
+ onMove: handleMoveRows
3007
+ }), /* @__PURE__ */ React3.createElement(SheetGrid, {
3008
+ ref: contentRef,
3009
+ size: {
3010
+ numRows: numRows ?? rows.length,
3011
+ numColumns: numColumns ?? columns.length
3012
+ },
3013
+ rows,
3014
+ columns,
3015
+ rowSizes,
3016
+ columnSizes
3017
+ }), /* @__PURE__ */ React3.createElement(GridCorner, null), /* @__PURE__ */ React3.createElement(SheetStatusBar, null));
3018
+ });
3019
+ var useScrollHandlers = () => {
3020
+ const rowsRef = useRef(null);
3021
+ const columnsRef = useRef(null);
3022
+ const contentRef = useRef(null);
3023
+ useEffect3(() => {
3024
+ const handleRowsScroll = (ev) => {
3025
+ const { scrollTop } = ev.target;
3026
+ if (!rowsRef.current.dataset.locked) {
3027
+ contentRef.current.scrollTop = scrollTop;
3028
+ }
3029
+ };
3030
+ const handleColumnsScroll = (ev) => {
3031
+ const { scrollLeft } = ev.target;
3032
+ if (!columnsRef.current.dataset.locked) {
3033
+ contentRef.current.scrollLeft = scrollLeft;
3034
+ }
3035
+ };
3036
+ const handleContentScroll = (ev) => {
3037
+ const { scrollTop, scrollLeft } = ev.target;
3038
+ rowsRef.current.scrollTop = scrollTop;
3039
+ columnsRef.current.scrollLeft = scrollLeft;
3040
+ };
3041
+ const rows = rowsRef.current;
3042
+ const columns = columnsRef.current;
3043
+ const content = contentRef.current;
3044
+ rows.addEventListener("scroll", handleRowsScroll);
3045
+ columns.addEventListener("scroll", handleColumnsScroll);
3046
+ content.addEventListener("scroll", handleContentScroll);
3047
+ return () => {
3048
+ rows.removeEventListener("scroll", handleRowsScroll);
3049
+ columns.removeEventListener("scroll", handleColumnsScroll);
3050
+ content.removeEventListener("scroll", handleContentScroll);
3051
+ };
3052
+ }, []);
3053
+ return {
3054
+ rowsRef,
3055
+ columnsRef,
3056
+ contentRef
3057
+ };
3058
+ };
3059
+ var GridCorner = (props) => {
3060
+ return /* @__PURE__ */ React3.createElement("div", {
3061
+ className: fragments.axis,
3062
+ ...props
3063
+ });
3064
+ };
3065
+ var MovingOverlay = ({ label }) => {
3066
+ return /* @__PURE__ */ React3.createElement("div", {
3067
+ className: "flex w-full h-full justify-center items-center text-sm p-1 bg-primary-500/50 cursor-pointer"
3068
+ }, label);
3069
+ };
3070
+ var mouseConstraints = {
3071
+ distance: 10
3072
+ };
3073
+ var touchConstraints = {
3074
+ delay: 250,
3075
+ tolerance: 5
3076
+ };
3077
+ var SheetRows = /* @__PURE__ */ forwardRef(({ rows, sizes, selected, onSelect, onResize, onMove }, forwardRef2) => {
3078
+ const mouseSensor = useSensor(MouseSensor, {
3079
+ activationConstraint: mouseConstraints
3080
+ });
3081
+ const touchSensor = useSensor(TouchSensor, {
3082
+ activationConstraint: touchConstraints
3083
+ });
3084
+ const keyboardSensor = useSensor(KeyboardSensor, {});
3085
+ const sensors = useSensors(mouseSensor, touchSensor, keyboardSensor);
3086
+ const [active, setActive] = useState4(null);
3087
+ const handleDragStart = ({ active: active2 }) => {
3088
+ setActive(active2);
3089
+ };
3090
+ const handleDragEnd = ({ over, active: active2 }) => {
3091
+ if (over && over.id !== active2.id) {
3092
+ setActive(null);
3093
+ onMove?.(active2.data.current.index, over.data.current.index);
3094
+ }
3095
+ };
3096
+ const snapToCenter = ({ activatorEvent, draggingNodeRect, transform }) => {
3097
+ if (draggingNodeRect && activatorEvent) {
3098
+ const activatorCoordinates = getEventCoordinates(activatorEvent);
3099
+ if (!activatorCoordinates) {
3100
+ return transform;
3101
+ }
3102
+ const offset = activatorCoordinates.y - draggingNodeRect.top;
3103
+ return {
3104
+ ...transform,
3105
+ y: transform.y + offset - draggingNodeRect.height / 2
3106
+ };
3107
+ }
3108
+ return transform;
3109
+ };
3110
+ return /* @__PURE__ */ React3.createElement("div", {
3111
+ className: "relative flex grow overflow-hidden"
3112
+ }, /* @__PURE__ */ React3.createElement("div", {
3113
+ className: mx2("z-20 absolute inset-0 border-y pointer-events-none", fragments.border),
3114
+ style: {
3115
+ width: axisWidth
3116
+ }
3117
+ }), /* @__PURE__ */ React3.createElement("div", {
3118
+ ref: forwardRef2,
3119
+ role: "rowheader",
3120
+ className: "grow overflow-y-auto scrollbar-none"
3121
+ }, /* @__PURE__ */ React3.createElement(DndContext, {
3122
+ sensors,
3123
+ modifiers: [
3124
+ restrictToVerticalAxis,
3125
+ snapToCenter
3126
+ ],
3127
+ onDragStart: handleDragStart,
3128
+ onDragEnd: handleDragEnd
3129
+ }, /* @__PURE__ */ React3.createElement("div", {
3130
+ className: "flex flex-col",
3131
+ style: {
3132
+ width: axisWidth
3133
+ }
3134
+ }, rows.map((idx, index) => /* @__PURE__ */ React3.createElement(GridRowCell, {
3135
+ key: idx,
3136
+ idx,
3137
+ index,
3138
+ label: String(index + 1),
3139
+ size: sizes?.[idx] ?? defaultHeight,
3140
+ resize: index < rows.length - 1,
3141
+ selected: selected === index,
3142
+ onResize,
3143
+ onSelect
3144
+ }))), /* @__PURE__ */ createPortal(/* @__PURE__ */ React3.createElement(DragOverlay, null, active && /* @__PURE__ */ React3.createElement(MovingOverlay, {
3145
+ label: String(active.data.current.index + 1)
3146
+ })), document.body))));
3147
+ });
3148
+ var GridRowCell = ({ idx, index, label, size, resize, selected, onSelect, onResize }) => {
3149
+ const { setNodeRef: setDroppableNodeRef } = useDroppable({
3150
+ id: idx,
3151
+ data: {
3152
+ index
3153
+ }
3154
+ });
3155
+ const { setNodeRef: setDraggableNodeRef, attributes, listeners, isDragging, over } = useDraggable({
3156
+ id: idx,
3157
+ data: {
3158
+ index
3159
+ }
3160
+ });
3161
+ const setNodeRef = useCombinedRefs(setDroppableNodeRef, setDraggableNodeRef);
3162
+ const [initialSize, setInitialSize] = useState4(size);
3163
+ const [resizing, setResizing] = useState4(false);
3164
+ const scrollHandler = useRef();
3165
+ const handleResizeStart = (_ev, _dir, elementRef) => {
3166
+ const scrollContainer = elementRef.closest('[role="rowheader"]');
3167
+ const scrollTop = scrollContainer.scrollTop;
3168
+ scrollHandler.current = (ev) => ev.target.scrollTop = scrollTop;
3169
+ scrollContainer.addEventListener("scroll", scrollHandler.current);
3170
+ scrollContainer.dataset.locked = "true";
3171
+ setResizing(true);
3172
+ };
3173
+ const handleResize = (_ev, _dir, _elementRef, { height }) => {
3174
+ onResize?.(idx, initialSize + height);
3175
+ };
3176
+ const handleResizeStop = (_ev, _dir, elementRef, { height }) => {
3177
+ const scrollContainer = elementRef.closest('[role="rowheader"]');
3178
+ scrollContainer.removeEventListener("scroll", scrollHandler.current);
3179
+ delete scrollContainer.dataset.locked;
3180
+ scrollHandler.current = void 0;
3181
+ setInitialSize(initialSize + height);
3182
+ onResize?.(idx, initialSize + height, true);
3183
+ setResizing(false);
3184
+ };
3185
+ return /* @__PURE__ */ React3.createElement(Resizable, {
3186
+ enable: {
3187
+ bottom: resize
3188
+ },
3189
+ size: {
3190
+ height: size - 1
3191
+ },
3192
+ minHeight: minHeight - 1,
3193
+ maxHeight,
3194
+ onResizeStart: handleResizeStart,
3195
+ onResize: handleResize,
3196
+ onResizeStop: handleResizeStop
3197
+ }, /* @__PURE__ */ React3.createElement("div", {
3198
+ ref: setNodeRef,
3199
+ ...attributes,
3200
+ ...listeners,
3201
+ className: mx2("flex h-full items-center justify-center cursor-pointer", "border-t focus-visible:outline-none", fragments.border, fragments.axis, selected && fragments.axisSelected, isDragging && fragments.axisSelected),
3202
+ onClick: () => onSelect?.(index)
3203
+ }, /* @__PURE__ */ React3.createElement("span", {
3204
+ className: "flex w-full justify-center"
3205
+ }, label), over?.id === idx && !isDragging && /* @__PURE__ */ React3.createElement("div", {
3206
+ className: "z-20 absolute top-0 w-full min-h-[4px] border-b-4 border-primary-500"
3207
+ }), resizing && /* @__PURE__ */ React3.createElement("div", {
3208
+ className: "z-20 absolute bottom-0 w-full min-h-[4px] border-b-4 border-primary-500"
3209
+ })));
3210
+ };
3211
+ var SheetColumns = /* @__PURE__ */ forwardRef(({ columns, sizes, selected, onSelect, onResize, onMove }, forwardRef2) => {
3212
+ const mouseSensor = useSensor(MouseSensor, {
3213
+ activationConstraint: mouseConstraints
3214
+ });
3215
+ const touchSensor = useSensor(TouchSensor, {
3216
+ activationConstraint: touchConstraints
3217
+ });
3218
+ const keyboardSensor = useSensor(KeyboardSensor, {});
3219
+ const sensors = useSensors(mouseSensor, touchSensor, keyboardSensor);
3220
+ const [active, setActive] = useState4(null);
3221
+ const handleDragStart = ({ active: active2 }) => {
3222
+ setActive(active2);
3223
+ };
3224
+ const handleDragEnd = ({ active: active2, over }) => {
3225
+ if (over && over.id !== active2.id) {
3226
+ setActive(null);
3227
+ onMove?.(active2.data.current.index, over.data.current.index);
3228
+ }
3229
+ };
3230
+ const snapToCenter = ({ activatorEvent, draggingNodeRect, transform }) => {
3231
+ if (draggingNodeRect && activatorEvent) {
3232
+ const activatorCoordinates = getEventCoordinates(activatorEvent);
3233
+ if (!activatorCoordinates) {
3234
+ return transform;
3235
+ }
3236
+ const offset = activatorCoordinates.x - draggingNodeRect.left;
3237
+ return {
3238
+ ...transform,
3239
+ x: transform.x + offset - draggingNodeRect.width / 2
3240
+ };
3241
+ }
3242
+ return transform;
3243
+ };
3244
+ return /* @__PURE__ */ React3.createElement("div", {
3245
+ className: "relative flex grow overflow-hidden"
3246
+ }, /* @__PURE__ */ React3.createElement("div", {
3247
+ className: mx2("z-20 absolute inset-0 border-x pointer-events-none", fragments.border),
3248
+ style: {
3249
+ height: axisHeight
3250
+ }
3251
+ }), /* @__PURE__ */ React3.createElement("div", {
3252
+ ref: forwardRef2,
3253
+ role: "columnheader",
3254
+ className: "grow overflow-x-auto scrollbar-none"
3255
+ }, /* @__PURE__ */ React3.createElement(DndContext, {
3256
+ autoScroll: {
3257
+ enabled: true
3258
+ },
3259
+ sensors,
3260
+ modifiers: [
3261
+ restrictToHorizontalAxis,
3262
+ snapToCenter
3263
+ ],
3264
+ onDragStart: handleDragStart,
3265
+ onDragEnd: handleDragEnd
3266
+ }, /* @__PURE__ */ React3.createElement("div", {
3267
+ className: "flex h-full",
3268
+ style: {
3269
+ height: axisHeight
3270
+ }
3271
+ }, columns.map((idx, index) => /* @__PURE__ */ React3.createElement(GridColumnCell, {
3272
+ key: idx,
3273
+ idx,
3274
+ index,
3275
+ label: columnLetter(index),
3276
+ size: sizes?.[idx] ?? defaultWidth,
3277
+ resize: index < columns.length - 1,
3278
+ selected: selected === index,
3279
+ onResize,
3280
+ onSelect
3281
+ }))), /* @__PURE__ */ createPortal(/* @__PURE__ */ React3.createElement(DragOverlay, null, active && /* @__PURE__ */ React3.createElement(MovingOverlay, {
3282
+ label: columnLetter(active.data.current.index)
3283
+ })), document.body))));
3284
+ });
3285
+ var GridColumnCell = ({ idx, index, label, size, resize, selected, onSelect, onResize }) => {
3286
+ const { setNodeRef: setDroppableNodeRef } = useDroppable({
3287
+ id: idx,
3288
+ data: {
3289
+ index
3290
+ }
3291
+ });
3292
+ const { setNodeRef: setDraggableNodeRef, attributes, listeners, over, isDragging } = useDraggable({
3293
+ id: idx,
3294
+ data: {
3295
+ index
3296
+ }
3297
+ });
3298
+ const setNodeRef = useCombinedRefs(setDroppableNodeRef, setDraggableNodeRef);
3299
+ const [initialSize, setInitialSize] = useState4(size);
3300
+ const [resizing, setResizing] = useState4(false);
3301
+ const scrollHandler = useRef();
3302
+ const handleResizeStart = (_ev, _dir, elementRef) => {
3303
+ const scrollContainer = elementRef.closest('[role="columnheader"]');
3304
+ const scrollLeft = scrollContainer.scrollLeft;
3305
+ scrollHandler.current = (ev) => ev.target.scrollLeft = scrollLeft;
3306
+ scrollContainer.addEventListener("scroll", scrollHandler.current);
3307
+ scrollContainer.dataset.locked = "true";
3308
+ setResizing(true);
3309
+ };
3310
+ const handleResize = (_ev, _dir, _elementRef, { width }) => {
3311
+ onResize?.(idx, initialSize + width);
3312
+ };
3313
+ const handleResizeStop = (_ev, _dir, elementRef, { width }) => {
3314
+ const scrollContainer = elementRef.closest('[role="columnheader"]');
3315
+ scrollContainer.removeEventListener("scroll", scrollHandler.current);
3316
+ delete scrollContainer.dataset.locked;
3317
+ scrollHandler.current = void 0;
3318
+ setInitialSize(initialSize + width);
3319
+ onResize?.(idx, initialSize + width, true);
3320
+ setResizing(false);
3321
+ };
3322
+ return /* @__PURE__ */ React3.createElement(Resizable, {
3323
+ enable: {
3324
+ right: resize
3325
+ },
3326
+ size: {
3327
+ width: size - 1
3328
+ },
3329
+ minWidth: minWidth - 1,
3330
+ maxWidth,
3331
+ onResizeStart: handleResizeStart,
3332
+ onResize: handleResize,
3333
+ onResizeStop: handleResizeStop
3334
+ }, /* @__PURE__ */ React3.createElement("div", {
3335
+ ref: setNodeRef,
3336
+ ...attributes,
3337
+ ...listeners,
3338
+ className: mx2("flex h-full items-center justify-center cursor-pointer", "border-l focus-visible:outline-none", fragments.border, fragments.axis, selected && fragments.axisSelected, isDragging && fragments.axisSelected),
3339
+ onClick: () => onSelect?.(index)
3340
+ }, /* @__PURE__ */ React3.createElement("span", {
3341
+ className: "flex w-full justify-center"
3342
+ }, label), over?.id === idx && !isDragging && /* @__PURE__ */ React3.createElement("div", {
3343
+ className: "z-20 absolute left-0 h-full min-w-[4px] border-l-4 border-primary-500"
3344
+ }), resizing && /* @__PURE__ */ React3.createElement("div", {
3345
+ className: "z-20 absolute right-0 h-full min-h-[4px] border-l-4 border-primary-500"
3346
+ })));
3347
+ };
3348
+ var SheetGrid = /* @__PURE__ */ forwardRef(({ size, rows, columns, rowSizes, columnSizes }, forwardRef2) => {
3349
+ const { ref: containerRef, width: containerWidth = 0, height: containerHeight = 0 } = useResizeDetector({
3350
+ refreshRate: 200
3351
+ });
3352
+ const scrollerRef = useRef(null);
3353
+ useImperativeHandle(forwardRef2, () => scrollerRef.current);
3354
+ const { model, cursor, range, editing, setCursor, setRange, setEditing, onInfo } = useSheetContext();
3355
+ const initialText = useRef();
3356
+ const quickEdit = useRef(false);
3357
+ const [, forceUpdate] = useState4({});
3358
+ useEffect3(() => {
3359
+ const unsubscribe = model.update.on(() => {
3360
+ log("updated", {
3361
+ id: model.id
3362
+ }, {
3363
+ F: __dxlog_file2,
3364
+ L: 734,
3365
+ S: void 0,
3366
+ C: (f, a) => f(...a)
3367
+ });
3368
+ forceUpdate({});
3369
+ });
3370
+ return () => {
3371
+ unsubscribe();
3372
+ };
3373
+ }, [
3374
+ model
3375
+ ]);
3376
+ const inputRef = useRef(null);
3377
+ const handleKeyDown = (ev) => {
3378
+ const isMacOS = /Mac|iPhone|iPod|iPad/.test(navigator.userAgent);
3379
+ if (cursor && (isMacOS && ev.metaKey || ev.ctrlKey)) {
3380
+ switch (ev.key) {
3381
+ case "x": {
3382
+ model.cut(range ?? {
3383
+ from: cursor
3384
+ });
3385
+ return;
3386
+ }
3387
+ case "c": {
3388
+ model.copy(range ?? {
3389
+ from: cursor
3390
+ });
3391
+ return;
3392
+ }
3393
+ case "v": {
3394
+ model.paste(cursor);
3395
+ return;
3396
+ }
3397
+ case "z": {
3398
+ if (ev.shiftKey) {
3399
+ model.redo();
3400
+ } else {
3401
+ model.undo();
3402
+ }
3403
+ return;
3404
+ }
3405
+ }
3406
+ }
3407
+ switch (ev.key) {
3408
+ case "ArrowUp":
3409
+ case "ArrowDown":
3410
+ case "ArrowLeft":
3411
+ case "ArrowRight":
3412
+ case "Home":
3413
+ case "End": {
3414
+ const next = handleNav(ev, cursor, range, size);
3415
+ setRange(next.range);
3416
+ if (next.cursor) {
3417
+ setCursor(next.cursor);
3418
+ const element = getCellElement(scrollerRef.current, next.cursor);
3419
+ if (element) {
3420
+ scrollIntoView(scrollerRef.current, element);
3421
+ }
3422
+ }
3423
+ break;
3424
+ }
3425
+ case "Backspace": {
3426
+ if (cursor) {
3427
+ if (range) {
3428
+ model.clear(range);
3429
+ } else {
3430
+ model.setValue(cursor, null);
3431
+ }
3432
+ }
3433
+ break;
3434
+ }
3435
+ case "Escape": {
3436
+ setRange(void 0);
3437
+ break;
3438
+ }
3439
+ case "Enter": {
3440
+ ev.stopPropagation();
3441
+ if (cursor) {
3442
+ setEditing(true);
3443
+ }
3444
+ break;
3445
+ }
3446
+ case "?": {
3447
+ onInfo?.();
3448
+ break;
3449
+ }
3450
+ default: {
3451
+ if (ev.key.length === 1) {
3452
+ initialText.current = ev.key;
3453
+ quickEdit.current = true;
3454
+ setEditing(true);
3455
+ }
3456
+ }
3457
+ }
3458
+ };
3459
+ const { handlers } = useRangeSelect((event, range2) => {
3460
+ switch (event) {
3461
+ case "start": {
3462
+ setRange(void 0);
3463
+ break;
3464
+ }
3465
+ default: {
3466
+ setRange(range2);
3467
+ }
3468
+ }
3469
+ });
3470
+ const { width, height, rowRange, columnRange } = useGridLayout({
3471
+ scroller: scrollerRef.current,
3472
+ size: {
3473
+ width: containerWidth,
3474
+ height: containerHeight
3475
+ },
3476
+ rows,
3477
+ columns,
3478
+ rowSizes,
3479
+ columnSizes
3480
+ });
3481
+ const qualifiedSubjectId = fullyQualifiedId(model.sheet);
3482
+ const attendableAttrs = createAttendableAttributes(qualifiedSubjectId);
3483
+ return /* @__PURE__ */ React3.createElement("div", {
3484
+ ref: containerRef,
3485
+ role: "grid",
3486
+ className: "relative flex grow overflow-hidden"
3487
+ }, /* @__PURE__ */ React3.createElement("div", {
3488
+ className: mx2("z-20 absolute inset-0 border pointer-events-none", fragments.border)
3489
+ }), /* @__PURE__ */ React3.createElement("div", {
3490
+ ref: scrollerRef,
3491
+ className: "grow overflow-auto scrollbar-thin"
3492
+ }, /* @__PURE__ */ React3.createElement("div", {
3493
+ className: "relative select-none",
3494
+ style: {
3495
+ width,
3496
+ height
3497
+ },
3498
+ onClick: () => inputRef.current?.focus(),
3499
+ ...handlers
3500
+ }, scrollerRef.current && /* @__PURE__ */ React3.createElement(SelectionOverlay, {
3501
+ root: scrollerRef.current
3502
+ }), rowRange.map(({ row, top, height: height2 }) => {
3503
+ return columnRange.map(({ column, left, width: width2 }) => {
3504
+ const style = {
3505
+ position: "absolute",
3506
+ top,
3507
+ left,
3508
+ width: width2,
3509
+ height: height2
3510
+ };
3511
+ const cell = {
3512
+ row,
3513
+ column
3514
+ };
3515
+ const id = addressToA1Notation(cell);
3516
+ const idx = model.addressToIndex(cell);
3517
+ const active = posEquals(cursor, cell);
3518
+ if (active && editing) {
3519
+ const value = initialText.current ?? model.getCellText(cell) ?? "";
3520
+ const handleClose = (value2) => {
3521
+ initialText.current = void 0;
3522
+ quickEdit.current = false;
3523
+ if (value2 !== void 0) {
3524
+ model.setValue(cell, value2);
3525
+ const next = handleArrowNav({
3526
+ key: "ArrowDown",
3527
+ metaKey: false
3528
+ }, cursor, size);
3529
+ if (next) {
3530
+ setCursor(next);
3531
+ }
3532
+ }
3533
+ inputRef.current?.focus();
3534
+ setEditing(false);
3535
+ };
3536
+ const handleNav2 = (value2, { key }) => {
3537
+ initialText.current = void 0;
3538
+ model.setValue(cell, value2 ?? null);
3539
+ const next = handleArrowNav({
3540
+ key,
3541
+ metaKey: false
3542
+ }, cursor, size);
3543
+ if (next) {
3544
+ setCursor(next);
3545
+ }
3546
+ inputRef.current?.focus();
3547
+ setEditing(false);
3548
+ };
3549
+ return /* @__PURE__ */ React3.createElement(GridCellEditor, {
3550
+ key: idx,
3551
+ value,
3552
+ style,
3553
+ onNav: quickEdit.current ? handleNav2 : void 0,
3554
+ onClose: handleClose
3555
+ });
3556
+ }
3557
+ return /* @__PURE__ */ React3.createElement(SheetCell, {
3558
+ key: id,
3559
+ id,
3560
+ cell,
3561
+ active,
3562
+ style,
3563
+ onSelect: (cell2, edit) => {
3564
+ setEditing(edit);
3565
+ setCursor(cell2);
3566
+ }
3567
+ });
3568
+ });
3569
+ }))), /* @__PURE__ */ createPortal(/* @__PURE__ */ React3.createElement("input", {
3570
+ ref: inputRef,
3571
+ autoFocus: true,
3572
+ className: "absolute w-[1px] h-[1px] bg-transparent outline-none border-none caret-transparent",
3573
+ onKeyDown: handleKeyDown,
3574
+ ...attendableAttrs
3575
+ }), document.body));
3576
+ });
3577
+ var SelectionOverlay = ({ root }) => {
3578
+ const { range } = useSheetContext();
3579
+ if (!range) {
3580
+ return null;
3581
+ }
3582
+ const c1 = getCellElement(root, range.from);
3583
+ const c2 = range.to ? getCellElement(root, range.to) : c1;
3584
+ if (!c1 || !c2) {
3585
+ return null;
3586
+ }
3587
+ const b1 = getRelativeClientRect(root, c1);
3588
+ const b2 = getRelativeClientRect(root, c2);
3589
+ const bounds = getRectUnion(b1, b2);
3590
+ return /* @__PURE__ */ React3.createElement("div", {
3591
+ role: "none",
3592
+ style: bounds,
3593
+ className: "z-10 absolute pointer-events-none bg-primary-500/20 border border-primary-500/50"
3594
+ });
3595
+ };
3596
+ var SheetCell = ({ id, cell, style, active, onSelect }) => {
3597
+ const { formatting, editing, setRange } = useSheetContext();
3598
+ const { value, classNames } = formatting.getFormatting(cell);
3599
+ return /* @__PURE__ */ React3.createElement("div", {
3600
+ [`data-${CELL_DATA_KEY}`]: id,
3601
+ role: "cell",
3602
+ style,
3603
+ className: mx2("flex w-full h-full truncate items-center border cursor-pointer", "px-2 py-1", fragments.cell, fragments.border, active && [
3604
+ "z-20",
3605
+ fragments.cellSelected
3606
+ ], classNames),
3607
+ onClick: () => {
3608
+ if (editing) {
3609
+ setRange?.({
3610
+ from: cell
3611
+ });
3612
+ } else {
3613
+ onSelect?.(cell, false);
3614
+ }
3615
+ },
3616
+ onDoubleClick: () => onSelect?.(cell, true)
3617
+ }, value);
3618
+ };
3619
+ var GridCellEditor = ({ style, value, onNav, onClose }) => {
3620
+ const { model, range } = useSheetContext();
3621
+ const notifier = useRef();
3622
+ useEffect3(() => {
3623
+ if (range) {
3624
+ notifier.current?.(rangeToA1Notation(range));
3625
+ }
3626
+ }, [
3627
+ range
3628
+ ]);
3629
+ const [extension] = useState4(() => {
3630
+ return [
3631
+ editorKeys({
3632
+ onNav,
3633
+ onClose
3634
+ }),
3635
+ sheetExtension({
3636
+ functions: model.functions
3637
+ }),
3638
+ rangeExtension((fn) => notifier.current = fn)
3639
+ ];
3640
+ });
3641
+ return /* @__PURE__ */ React3.createElement("div", {
3642
+ role: "cell",
3643
+ style,
3644
+ className: mx2("z-20 flex", fragments.cellSelected),
3645
+ onClick: (ev) => ev.stopPropagation()
3646
+ }, /* @__PURE__ */ React3.createElement(CellEditor, {
3647
+ autoFocus: true,
3648
+ value,
3649
+ extension
3650
+ }));
3651
+ };
3652
+ var SheetStatusBar = () => {
3653
+ const { model, cursor, range } = useSheetContext();
3654
+ let value;
3655
+ let isFormula = false;
3656
+ if (cursor) {
3657
+ value = model.getCellValue(cursor);
3658
+ if (typeof value === "string" && value.charAt(0) === "=") {
3659
+ value = model.mapFormulaIndicesToRefs(value);
3660
+ isFormula = true;
3661
+ } else if (value != null) {
3662
+ value = String(value);
3663
+ }
3664
+ }
3665
+ return /* @__PURE__ */ React3.createElement("div", {
3666
+ className: mx2("flex shrink-0 justify-between items-center px-4 py-1 text-sm border-x", fragments.border)
3667
+ }, /* @__PURE__ */ React3.createElement("div", {
3668
+ className: "flex gap-4 items-center"
3669
+ }, /* @__PURE__ */ React3.createElement("div", {
3670
+ className: "flex w-16 items-center font-mono"
3671
+ }, range && rangeToA1Notation(range) || cursor && addressToA1Notation(cursor)), /* @__PURE__ */ React3.createElement("div", {
3672
+ className: "flex gap-2 items-center"
3673
+ }, /* @__PURE__ */ React3.createElement(FunctionIcon, {
3674
+ className: mx2("text-green-500", isFormula ? "visible" : "invisible")
3675
+ }), /* @__PURE__ */ React3.createElement("span", {
3676
+ className: "font-mono"
3677
+ }, value))));
3678
+ };
3679
+ var SheetDebug = () => {
3680
+ const { model, cursor, range } = useSheetContext();
3681
+ const [, forceUpdate] = useState4({});
3682
+ useEffect3(() => {
3683
+ const accessor = createDocAccessor(model.sheet, []);
3684
+ const handleUpdate = () => forceUpdate({});
3685
+ accessor.handle.addListener("change", handleUpdate);
3686
+ handleUpdate();
3687
+ return () => {
3688
+ accessor.handle.removeListener("change", handleUpdate);
3689
+ };
3690
+ }, [
3691
+ model
3692
+ ]);
3693
+ return /* @__PURE__ */ React3.createElement("div", {
3694
+ className: mx2("z-20 absolute right-0 top-20 bottom-20 w-[30rem] overflow-auto scrollbar-thin", "border text-xs bg-neutral-50 dark:bg-black text-cyan-500 font-mono p-1 opacity-80", fragments.border)
3695
+ }, /* @__PURE__ */ React3.createElement("pre", {
3696
+ className: "whitespace-pre-wrap"
3697
+ }, JSON.stringify({
3698
+ cursor,
3699
+ range,
3700
+ cells: model.sheet.cells,
3701
+ rowMeta: model.sheet.rowMeta,
3702
+ columnMeta: model.sheet.columnMeta,
3703
+ formatting: model.sheet.formatting
3704
+ }, void 0, 2)));
3705
+ };
3706
+ var Sheet = {
3707
+ Root: SheetRoot,
3708
+ Main: SheetMain,
3709
+ Rows: SheetRows,
3710
+ Columns: SheetColumns,
3711
+ Grid: SheetGrid,
3712
+ Cell: SheetCell,
3713
+ StatusBar: SheetStatusBar,
3714
+ Debug: SheetDebug
3715
+ };
3716
+
3717
+ // packages/plugins/plugin-sheet/src/components/SheetContainer.tsx
3718
+ var SheetContainer = ({ sheet, space, role, coordinate = {
3719
+ part: "main",
3720
+ entryId: ""
3721
+ } }) => {
3722
+ return /* @__PURE__ */ React4.createElement("div", {
3723
+ role: "none",
3724
+ className: mx3(role === "section" && "aspect-square", role === "article" && "row-span-2")
3725
+ }, /* @__PURE__ */ React4.createElement(Sheet.Root, {
3726
+ sheet,
3727
+ space
3728
+ }, /* @__PURE__ */ React4.createElement(Sheet.Main, {
3729
+ // TODO(burdon): Standardize for other components (e.g., table).
3730
+ classNames: [
3731
+ coordinate.part !== "solo" && "border-is",
3732
+ role === "section" && "border-y border-is"
3733
+ ]
3734
+ })));
3735
+ };
3736
+ var SheetContainer_default = SheetContainer;
3737
+ export {
3738
+ SheetContainer_default as default
3739
+ };
3740
+ //# sourceMappingURL=SheetContainer-H22IDJ43.mjs.map