@dxos/plugin-sheet 0.6.11 → 0.6.12-main.5cc132e

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 (106) hide show
  1. package/dist/lib/browser/{SheetContainer-U4H5D34A.mjs → SheetContainer-Y7ZMFBAP.mjs} +568 -109
  2. package/dist/lib/browser/SheetContainer-Y7ZMFBAP.mjs.map +7 -0
  3. package/dist/lib/browser/{chunk-D5AGLXJP.mjs → chunk-GNNVBNCX.mjs} +55 -47
  4. package/dist/lib/browser/chunk-GNNVBNCX.mjs.map +7 -0
  5. package/dist/lib/browser/{chunk-APHOLYUB.mjs → chunk-PGKZPKUD.mjs} +2 -2
  6. package/dist/lib/browser/chunk-VBF7YENS.mjs +8 -0
  7. package/dist/lib/browser/{chunk-FUAGSXA4.mjs → chunk-WUPTZUTX.mjs} +6 -3
  8. package/dist/lib/browser/chunk-WUPTZUTX.mjs.map +7 -0
  9. package/dist/lib/browser/index.mjs +15 -6
  10. package/dist/lib/browser/index.mjs.map +3 -3
  11. package/dist/lib/browser/meta.json +1 -1
  12. package/dist/lib/browser/testing.mjs +3 -3
  13. package/dist/lib/browser/types.mjs +1 -1
  14. package/dist/lib/node/{SheetContainer-AXQV3ZT5.cjs → SheetContainer-KEOKUKAQ.cjs} +509 -62
  15. package/dist/lib/node/SheetContainer-KEOKUKAQ.cjs.map +7 -0
  16. package/dist/lib/node/{chunk-PYXHNAAK.cjs → chunk-57PB2HPY.cjs} +5 -5
  17. package/dist/lib/node/{chunk-CN3RPESU.cjs → chunk-6LWBQAQZ.cjs} +9 -9
  18. package/dist/lib/node/{chunk-DSYKOI4E.cjs → chunk-VJU3NPUJ.cjs} +8 -5
  19. package/dist/lib/node/chunk-VJU3NPUJ.cjs.map +7 -0
  20. package/dist/lib/node/{chunk-5KKJ4NPP.cjs → chunk-ZRQZFV5T.cjs} +70 -57
  21. package/dist/lib/node/chunk-ZRQZFV5T.cjs.map +7 -0
  22. package/dist/lib/node/index.cjs +31 -23
  23. package/dist/lib/node/index.cjs.map +3 -3
  24. package/dist/lib/node/meta.json +1 -1
  25. package/dist/lib/node/testing.cjs +6 -6
  26. package/dist/lib/node/types.cjs +9 -9
  27. package/dist/lib/node/types.cjs.map +1 -1
  28. package/dist/lib/node-esm/SheetContainer-Y7ZMFBAP.mjs +2231 -0
  29. package/dist/lib/node-esm/SheetContainer-Y7ZMFBAP.mjs.map +7 -0
  30. package/dist/lib/node-esm/chunk-GNNVBNCX.mjs +3243 -0
  31. package/dist/lib/node-esm/chunk-GNNVBNCX.mjs.map +7 -0
  32. package/dist/lib/node-esm/chunk-JRL5LGCE.mjs +18 -0
  33. package/dist/lib/node-esm/chunk-JRL5LGCE.mjs.map +7 -0
  34. package/dist/lib/node-esm/chunk-PGKZPKUD.mjs +175 -0
  35. package/dist/lib/node-esm/chunk-PGKZPKUD.mjs.map +7 -0
  36. package/dist/lib/node-esm/chunk-VBF7YENS.mjs +8 -0
  37. package/dist/lib/node-esm/chunk-VBF7YENS.mjs.map +7 -0
  38. package/dist/lib/node-esm/chunk-WUPTZUTX.mjs +85 -0
  39. package/dist/lib/node-esm/chunk-WUPTZUTX.mjs.map +7 -0
  40. package/dist/lib/node-esm/index.mjs +257 -0
  41. package/dist/lib/node-esm/index.mjs.map +7 -0
  42. package/dist/lib/node-esm/meta.json +1 -0
  43. package/dist/lib/node-esm/meta.mjs +9 -0
  44. package/dist/lib/node-esm/meta.mjs.map +7 -0
  45. package/dist/lib/node-esm/testing.mjs +92 -0
  46. package/dist/lib/node-esm/testing.mjs.map +7 -0
  47. package/dist/lib/node-esm/types.mjs +22 -0
  48. package/dist/lib/node-esm/types.mjs.map +7 -0
  49. package/dist/types/src/SheetPlugin.d.ts.map +1 -1
  50. package/dist/types/src/components/Sheet/Sheet.d.ts.map +1 -1
  51. package/dist/types/src/components/Sheet/Sheet.stories.d.ts.map +1 -1
  52. package/dist/types/src/components/Sheet/decorations.d.ts +24 -0
  53. package/dist/types/src/components/Sheet/decorations.d.ts.map +1 -0
  54. package/dist/types/src/components/Sheet/formatting.d.ts.map +1 -1
  55. package/dist/types/src/components/Sheet/sheet-context.d.ts +2 -0
  56. package/dist/types/src/components/Sheet/sheet-context.d.ts.map +1 -1
  57. package/dist/types/src/components/Sheet/threads.d.ts +2 -0
  58. package/dist/types/src/components/Sheet/threads.d.ts.map +1 -0
  59. package/dist/types/src/components/SheetContainer.d.ts +2 -3
  60. package/dist/types/src/components/SheetContainer.d.ts.map +1 -1
  61. package/dist/types/src/components/Toolbar/Toolbar.d.ts +19 -3
  62. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
  63. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts +17 -12
  64. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -1
  65. package/dist/types/src/components/index.d.ts +1 -2
  66. package/dist/types/src/components/index.d.ts.map +1 -1
  67. package/dist/types/src/model/index.d.ts +1 -0
  68. package/dist/types/src/model/index.d.ts.map +1 -1
  69. package/dist/types/src/model/model.d.ts +0 -16
  70. package/dist/types/src/model/model.d.ts.map +1 -1
  71. package/dist/types/src/model/util.d.ts +24 -0
  72. package/dist/types/src/model/util.d.ts.map +1 -1
  73. package/dist/types/src/translations.d.ts +17 -12
  74. package/dist/types/src/translations.d.ts.map +1 -1
  75. package/dist/types/src/types.d.ts +72 -2
  76. package/dist/types/src/types.d.ts.map +1 -1
  77. package/package.json +36 -32
  78. package/src/SheetPlugin.tsx +8 -15
  79. package/src/components/CellEditor/extension.test.ts +1 -2
  80. package/src/components/ComputeGraph/graph.browser.test.ts +1 -2
  81. package/src/components/Sheet/Sheet.stories.tsx +5 -1
  82. package/src/components/Sheet/Sheet.tsx +45 -8
  83. package/src/components/Sheet/decorations.ts +62 -0
  84. package/src/components/Sheet/formatting.ts +3 -3
  85. package/src/components/Sheet/sheet-context.tsx +9 -1
  86. package/src/components/Sheet/threads.tsx +201 -0
  87. package/src/components/SheetContainer.tsx +72 -18
  88. package/src/components/Toolbar/Toolbar.tsx +54 -12
  89. package/src/model/index.ts +1 -0
  90. package/src/model/model.browser.test.ts +1 -2
  91. package/src/model/model.ts +9 -43
  92. package/src/model/types.test.ts +1 -2
  93. package/src/model/util.ts +67 -0
  94. package/src/translations.ts +6 -1
  95. package/src/types.ts +26 -3
  96. package/dist/lib/browser/SheetContainer-U4H5D34A.mjs.map +0 -7
  97. package/dist/lib/browser/chunk-D5AGLXJP.mjs.map +0 -7
  98. package/dist/lib/browser/chunk-FUAGSXA4.mjs.map +0 -7
  99. package/dist/lib/browser/chunk-NU4PBN33.mjs +0 -8
  100. package/dist/lib/node/SheetContainer-AXQV3ZT5.cjs.map +0 -7
  101. package/dist/lib/node/chunk-5KKJ4NPP.cjs.map +0 -7
  102. package/dist/lib/node/chunk-DSYKOI4E.cjs.map +0 -7
  103. /package/dist/lib/browser/{chunk-APHOLYUB.mjs.map → chunk-PGKZPKUD.mjs.map} +0 -0
  104. /package/dist/lib/browser/{chunk-NU4PBN33.mjs.map → chunk-VBF7YENS.mjs.map} +0 -0
  105. /package/dist/lib/node/{chunk-PYXHNAAK.cjs.map → chunk-57PB2HPY.cjs.map} +0 -0
  106. /package/dist/lib/node/{chunk-CN3RPESU.cjs.map → chunk-6LWBQAQZ.cjs.map} +0 -0
@@ -0,0 +1,2231 @@
1
+ import {
2
+ useComputeGraph
3
+ } from "./chunk-PGKZPKUD.mjs";
4
+ import {
5
+ SheetModel,
6
+ addressFromA1Notation,
7
+ addressFromIndex,
8
+ addressToA1Notation,
9
+ addressToIndex,
10
+ closest,
11
+ columnLetter,
12
+ defaultFunctions,
13
+ inRange,
14
+ posEquals,
15
+ rangeFromIndex,
16
+ rangeToA1Notation
17
+ } from "./chunk-GNNVBNCX.mjs";
18
+ import {
19
+ ValueTypeEnum
20
+ } from "./chunk-WUPTZUTX.mjs";
21
+ import {
22
+ SHEET_PLUGIN
23
+ } from "./chunk-JRL5LGCE.mjs";
24
+
25
+ // packages/plugins/plugin-sheet/src/components/SheetContainer.tsx
26
+ import React7, { useCallback as useCallback2 } from "react";
27
+ import { useIntentDispatcher as useIntentDispatcher2 } from "@dxos/app-framework";
28
+ import { fullyQualifiedId as fullyQualifiedId4 } from "@dxos/react-client/echo";
29
+ import { useIsDirectlyAttended } from "@dxos/react-ui-attention";
30
+ import { focusRing, mx as mx4 } from "@dxos/react-ui-theme";
31
+
32
+ // packages/plugins/plugin-sheet/src/components/Sheet/Sheet.tsx
33
+ import { DndContext, DragOverlay, KeyboardSensor, MouseSensor, TouchSensor, useDraggable, useDroppable, useSensor, useSensors } from "@dnd-kit/core";
34
+ import { restrictToHorizontalAxis, restrictToVerticalAxis } from "@dnd-kit/modifiers";
35
+ import { getEventCoordinates, useCombinedRefs } from "@dnd-kit/utilities";
36
+ import { Function as FunctionIcon } from "@phosphor-icons/react";
37
+ import { Resizable } from "re-resizable";
38
+ import React4, { forwardRef, useEffect as useEffect4, useImperativeHandle, useMemo as useMemo3, useRef, useState as useState4 } from "react";
39
+ import { createPortal } from "react-dom";
40
+ import { useResizeDetector } from "react-resize-detector";
41
+ import { debounce as debounce2 } from "@dxos/async";
42
+ import { fullyQualifiedId as fullyQualifiedId3, createDocAccessor } from "@dxos/client/echo";
43
+ import { log } from "@dxos/log";
44
+ import { createAttendableAttributes, useHasAttention } from "@dxos/react-ui-attention";
45
+ import { mx as mx3 } from "@dxos/react-ui-theme";
46
+
47
+ // packages/plugins/plugin-sheet/src/components/Sheet/grid.ts
48
+ import { useEffect, useState } from "react";
49
+ var axisWidth = "calc(var(--rail-size)-2px)";
50
+ var axisHeight = 34;
51
+ var minWidth = 40;
52
+ var maxWidth = 800;
53
+ var minHeight = axisHeight;
54
+ var maxHeight = 400;
55
+ var defaultWidth = 200;
56
+ var defaultHeight = minHeight;
57
+ var CELL_DATA_KEY = "cell";
58
+ var useGridLayout = ({ scroller, size, rows, columns, rowSizes, columnSizes }) => {
59
+ const [rowPositions, setRowPositions] = useState([]);
60
+ useEffect(() => {
61
+ if (!rowSizes) {
62
+ return;
63
+ }
64
+ let y = 0;
65
+ setRowPositions(rows.map((idx, i) => {
66
+ const height2 = rowSizes?.[idx] ?? defaultHeight;
67
+ const top = y;
68
+ y += height2 - 1;
69
+ return {
70
+ row: i,
71
+ top,
72
+ height: height2
73
+ };
74
+ }));
75
+ }, [
76
+ rows,
77
+ rowSizes
78
+ ]);
79
+ const [columnPositions, setColumnPositions] = useState([]);
80
+ useEffect(() => {
81
+ if (!columns) {
82
+ return;
83
+ }
84
+ let x = 0;
85
+ setColumnPositions(columns.map((idx, i) => {
86
+ const width2 = columnSizes?.[idx] ?? defaultWidth;
87
+ const left = x;
88
+ x += width2 - 1;
89
+ return {
90
+ column: i,
91
+ left,
92
+ width: width2
93
+ };
94
+ }));
95
+ }, [
96
+ columns,
97
+ columnSizes
98
+ ]);
99
+ const height = rowPositions.length ? rowPositions[rowPositions.length - 1].top + rowPositions[rowPositions.length - 1].height : 0;
100
+ const width = columnPositions.length ? columnPositions[columnPositions.length - 1].left + columnPositions[columnPositions.length - 1].width : 0;
101
+ const [{ rowRange, columnRange }, setWindow] = useState({
102
+ rowRange: [],
103
+ columnRange: []
104
+ });
105
+ useEffect(() => {
106
+ const handleScroll = () => {
107
+ if (!scroller) {
108
+ return;
109
+ }
110
+ const { scrollLeft: left, scrollTop: top, clientWidth: width2, clientHeight: height2 } = scroller;
111
+ let rowStart = 0;
112
+ let rowEnd = 0;
113
+ for (let i = 0; i < rowPositions.length; i++) {
114
+ const row = rowPositions[i];
115
+ if (row.top <= top) {
116
+ rowStart = i;
117
+ }
118
+ if (row.top + row.height >= top + height2) {
119
+ rowEnd = i;
120
+ break;
121
+ }
122
+ }
123
+ let columnStart = 0;
124
+ let columnEnd = 0;
125
+ for (let i = 0; i < columnPositions.length; i++) {
126
+ const column = columnPositions[i];
127
+ if (column.left <= left) {
128
+ columnStart = i;
129
+ }
130
+ if (column.left + column.width >= left + width2) {
131
+ columnEnd = i;
132
+ break;
133
+ }
134
+ }
135
+ const overscan = 5;
136
+ setWindow({
137
+ rowRange: rowPositions.slice(Math.max(0, rowStart - overscan), Math.min(rowPositions.length, rowEnd + overscan)),
138
+ columnRange: columnPositions.slice(Math.max(0, columnStart - overscan), Math.min(columnPositions.length, columnEnd + overscan))
139
+ });
140
+ };
141
+ scroller?.addEventListener("scroll", handleScroll);
142
+ handleScroll();
143
+ return () => {
144
+ scroller?.removeEventListener("scroll", handleScroll);
145
+ };
146
+ }, [
147
+ size.width,
148
+ size.height,
149
+ rowPositions,
150
+ columnPositions
151
+ ]);
152
+ return {
153
+ width,
154
+ height,
155
+ rowRange,
156
+ columnRange
157
+ };
158
+ };
159
+ var getCellAtPointer = (event) => {
160
+ const element = document.elementFromPoint(event.clientX, event.clientY);
161
+ const root = element?.closest(`[data-${CELL_DATA_KEY}]`);
162
+ if (root) {
163
+ const value = root.dataset[CELL_DATA_KEY];
164
+ if (value) {
165
+ return addressFromA1Notation(value);
166
+ }
167
+ }
168
+ };
169
+ var getCellElement = (root, cell) => {
170
+ const pos = addressToA1Notation(cell);
171
+ return root.querySelector(`[data-${CELL_DATA_KEY}="${pos}"]`);
172
+ };
173
+
174
+ // packages/plugins/plugin-sheet/src/components/Sheet/nav.ts
175
+ import { useState as useState2 } from "react";
176
+ var handleNav = (ev, cursor, range, size) => {
177
+ if (cursor && ev.shiftKey) {
178
+ const opposite = range?.to ?? {
179
+ ...cursor
180
+ };
181
+ switch (ev.key) {
182
+ case "ArrowUp": {
183
+ if (opposite.row > 0) {
184
+ opposite.row -= 1;
185
+ }
186
+ break;
187
+ }
188
+ case "ArrowDown": {
189
+ if (opposite.row < size.numRows - 1) {
190
+ opposite.row += 1;
191
+ }
192
+ break;
193
+ }
194
+ case "ArrowLeft": {
195
+ if (opposite.column > 0) {
196
+ opposite.column -= 1;
197
+ }
198
+ break;
199
+ }
200
+ case "ArrowRight": {
201
+ if (opposite.column < size.numColumns - 1) {
202
+ opposite.column += 1;
203
+ }
204
+ break;
205
+ }
206
+ }
207
+ return {
208
+ cursor,
209
+ range: {
210
+ from: cursor,
211
+ to: opposite
212
+ }
213
+ };
214
+ }
215
+ const next = handleArrowNav(ev, cursor, size);
216
+ return {
217
+ cursor: next
218
+ };
219
+ };
220
+ var handleArrowNav = (ev, cursor, { numRows, numColumns }) => {
221
+ switch (ev.key) {
222
+ case "ArrowUp":
223
+ if (cursor === void 0) {
224
+ return {
225
+ row: 0,
226
+ column: 0
227
+ };
228
+ } else if (cursor.row > 0) {
229
+ return {
230
+ row: ev.metaKey ? 0 : cursor.row - 1,
231
+ column: cursor.column
232
+ };
233
+ }
234
+ break;
235
+ case "ArrowDown":
236
+ if (cursor === void 0) {
237
+ return {
238
+ row: 0,
239
+ column: 0
240
+ };
241
+ } else if (cursor.row < numRows - 1) {
242
+ return {
243
+ row: ev.metaKey ? numRows - 1 : cursor.row + 1,
244
+ column: cursor.column
245
+ };
246
+ }
247
+ break;
248
+ case "ArrowLeft":
249
+ if (cursor === void 0) {
250
+ return {
251
+ row: 0,
252
+ column: 0
253
+ };
254
+ } else if (cursor.column > 0) {
255
+ return {
256
+ row: cursor.row,
257
+ column: ev.metaKey ? 0 : cursor.column - 1
258
+ };
259
+ }
260
+ break;
261
+ case "ArrowRight":
262
+ if (cursor === void 0) {
263
+ return {
264
+ row: 0,
265
+ column: 0
266
+ };
267
+ } else if (cursor.column < numColumns - 1) {
268
+ return {
269
+ row: cursor.row,
270
+ column: ev.metaKey ? numColumns - 1 : cursor.column + 1
271
+ };
272
+ }
273
+ break;
274
+ case "Home":
275
+ return {
276
+ row: 0,
277
+ column: 0
278
+ };
279
+ case "End":
280
+ return {
281
+ row: numRows - 1,
282
+ column: numColumns - 1
283
+ };
284
+ }
285
+ };
286
+ var useRangeSelect = (cb) => {
287
+ const [from, setFrom] = useState2();
288
+ const [to, setTo] = useState2();
289
+ const onMouseDown = (ev) => {
290
+ const current = getCellAtPointer(ev);
291
+ setFrom(current);
292
+ if (current) {
293
+ setTimeout(() => cb("start", {
294
+ from: current
295
+ }));
296
+ }
297
+ };
298
+ const onMouseMove = (ev) => {
299
+ if (from) {
300
+ let current = getCellAtPointer(ev);
301
+ if (posEquals(current, from)) {
302
+ current = void 0;
303
+ }
304
+ setTo(current);
305
+ setTimeout(() => cb("move", {
306
+ from,
307
+ to: current
308
+ }));
309
+ }
310
+ };
311
+ const onMouseUp = (ev) => {
312
+ if (from) {
313
+ let current = getCellAtPointer(ev);
314
+ if (posEquals(current, from)) {
315
+ current = void 0;
316
+ }
317
+ setFrom(void 0);
318
+ setTo(void 0);
319
+ setTimeout(() => cb("end", current ? {
320
+ from,
321
+ to: current
322
+ } : void 0));
323
+ }
324
+ };
325
+ return {
326
+ range: from ? {
327
+ from,
328
+ to
329
+ } : void 0,
330
+ handlers: {
331
+ onMouseDown,
332
+ onMouseMove,
333
+ onMouseUp
334
+ }
335
+ };
336
+ };
337
+
338
+ // packages/plugins/plugin-sheet/src/components/Sheet/sheet-context.tsx
339
+ import React, { createContext, useContext, useState as useState3, useEffect as useEffect2, useMemo } from "react";
340
+ import { invariant } from "@dxos/invariant";
341
+ import { fullyQualifiedId } from "@dxos/react-client/echo";
342
+
343
+ // packages/plugins/plugin-sheet/src/components/Sheet/decorations.ts
344
+ import { create } from "@dxos/echo-schema";
345
+ var createDecorations = () => {
346
+ const { decorations } = create({
347
+ decorations: {}
348
+ });
349
+ const addDecoration = (cellIndex, decorator) => {
350
+ decorations[cellIndex] = [
351
+ ...decorations[cellIndex] || [],
352
+ decorator
353
+ ];
354
+ };
355
+ const removeDecoration = (cellIndex, type) => {
356
+ if (type) {
357
+ decorations[cellIndex] = (decorations[cellIndex] || []).filter((d) => d.type !== type);
358
+ } else {
359
+ delete decorations[cellIndex];
360
+ }
361
+ };
362
+ const getDecorationsForCell = (cellIndex) => {
363
+ return decorations[cellIndex];
364
+ };
365
+ const getAllDecorations = () => {
366
+ const result = [];
367
+ for (const decoratorArray of Object.values(decorations)) {
368
+ for (const decorator of decoratorArray) {
369
+ result.push(decorator);
370
+ }
371
+ }
372
+ return result;
373
+ };
374
+ return {
375
+ addDecoration,
376
+ removeDecoration,
377
+ getDecorationsForCell,
378
+ getAllDecorations
379
+ };
380
+ };
381
+
382
+ // packages/plugins/plugin-sheet/src/components/Sheet/formatting.ts
383
+ var FormattingModel = class {
384
+ constructor(model) {
385
+ this.model = model;
386
+ }
387
+ /**
388
+ * Get formatted string value and className for cell.
389
+ */
390
+ getFormatting(cell) {
391
+ const value = this.model.getValue(cell);
392
+ if (value === void 0 || value === null) {
393
+ return {};
394
+ }
395
+ const locales = void 0;
396
+ const idx = addressToIndex(this.model.sheet, cell);
397
+ let formatting = this.model.sheet.formatting?.[idx] ?? {};
398
+ const classNames = [
399
+ ...formatting?.classNames ?? []
400
+ ];
401
+ for (const [idx2, _formatting] of Object.entries(this.model.sheet.formatting)) {
402
+ const range = rangeFromIndex(this.model.sheet, idx2);
403
+ if (inRange(range, cell)) {
404
+ if (_formatting.classNames) {
405
+ classNames.push(..._formatting.classNames);
406
+ }
407
+ if (_formatting.type) {
408
+ formatting = _formatting;
409
+ }
410
+ }
411
+ }
412
+ const defaultNumber = "justify-end font-mono";
413
+ const type = formatting?.type ?? this.model.getValueType(cell);
414
+ switch (type) {
415
+ case ValueTypeEnum.Boolean: {
416
+ return {
417
+ value: value.toLocaleString().toUpperCase(),
418
+ classNames: [
419
+ ...classNames,
420
+ value ? "!text-greenText" : "!text-orangeText"
421
+ ]
422
+ };
423
+ }
424
+ //
425
+ // Numbers.
426
+ //
427
+ case ValueTypeEnum.Number: {
428
+ return {
429
+ value: value.toLocaleString(locales),
430
+ classNames: [
431
+ ...classNames,
432
+ defaultNumber
433
+ ]
434
+ };
435
+ }
436
+ case ValueTypeEnum.Percent: {
437
+ return {
438
+ value: value * 100 + "%",
439
+ classNames: [
440
+ ...classNames,
441
+ defaultNumber
442
+ ]
443
+ };
444
+ }
445
+ case ValueTypeEnum.Currency: {
446
+ return {
447
+ value: value.toLocaleString(locales, {
448
+ style: "currency",
449
+ currency: "USD",
450
+ minimumFractionDigits: 2,
451
+ maximumFractionDigits: 2
452
+ }),
453
+ classNames: [
454
+ ...classNames,
455
+ defaultNumber
456
+ ]
457
+ };
458
+ }
459
+ //
460
+ // Dates.
461
+ //
462
+ case ValueTypeEnum.DateTime: {
463
+ const date = this.model.toLocalDate(value);
464
+ return {
465
+ value: date.toLocaleString(locales),
466
+ classNames
467
+ };
468
+ }
469
+ case ValueTypeEnum.Date: {
470
+ const date = this.model.toLocalDate(value);
471
+ return {
472
+ value: date.toLocaleDateString(locales),
473
+ classNames
474
+ };
475
+ }
476
+ case ValueTypeEnum.Time: {
477
+ const date = this.model.toLocalDate(value);
478
+ return {
479
+ value: date.toLocaleTimeString(locales),
480
+ classNames
481
+ };
482
+ }
483
+ default: {
484
+ return {
485
+ value: String(value),
486
+ classNames
487
+ };
488
+ }
489
+ }
490
+ }
491
+ };
492
+
493
+ // packages/plugins/plugin-sheet/src/components/Sheet/sheet-context.tsx
494
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/plugins/plugin-sheet/src/components/Sheet/sheet-context.tsx";
495
+ var OBJECT_ID_LENGTH = 60;
496
+ var SheetContext = /* @__PURE__ */ createContext(null);
497
+ var useSheetContext = () => {
498
+ const context = useContext(SheetContext);
499
+ invariant(context, void 0, {
500
+ F: __dxlog_file,
501
+ L: 49,
502
+ S: void 0,
503
+ A: [
504
+ "context",
505
+ ""
506
+ ]
507
+ });
508
+ return context;
509
+ };
510
+ var mapFormulaBindingToId = (functions) => (formula) => {
511
+ return formula.replace(/([a-zA-Z0-9]+)\((.*)\)/g, (match, binding, args) => {
512
+ if (defaultFunctions.find((fn2) => fn2.name === binding) || binding === "EDGE") {
513
+ return match;
514
+ }
515
+ const fn = functions.find((fn2) => fn2.binding === binding);
516
+ if (fn) {
517
+ return `${fullyQualifiedId(fn)}(${args})`;
518
+ } else {
519
+ return match;
520
+ }
521
+ });
522
+ };
523
+ var mapFormulaBindingFromId = (functions) => (formula) => {
524
+ return formula.replace(/([a-zA-Z0-9]+):([a-zA-Z0-9]+)\((.*)\)/g, (match, spaceId, objectId, args) => {
525
+ const id = `${spaceId}:${objectId}`;
526
+ if (id.length !== OBJECT_ID_LENGTH) {
527
+ return match;
528
+ }
529
+ const fn = functions.find((fn2) => fullyQualifiedId(fn2) === id);
530
+ if (fn?.binding) {
531
+ return `${fn.binding}(${args})`;
532
+ } else {
533
+ return match;
534
+ }
535
+ });
536
+ };
537
+ var SheetContextProvider = ({ children, sheet, space, readonly, onInfo, ...options }) => {
538
+ const graph = useComputeGraph(space, options);
539
+ const [cursor, setCursor] = useState3();
540
+ const [range, setRange] = useState3();
541
+ const [editing, setEditing] = useState3(false);
542
+ const decorations = useMemo(() => createDecorations(), []);
543
+ const [[model, formatting] = [], setModels] = useState3(void 0);
544
+ useEffect2(() => {
545
+ let model2;
546
+ let formatting2;
547
+ const t = setTimeout(async () => {
548
+ model2 = new SheetModel(graph, sheet, space, {
549
+ readonly,
550
+ mapFormulaBindingToId,
551
+ mapFormulaBindingFromId
552
+ });
553
+ await model2.initialize();
554
+ formatting2 = new FormattingModel(model2);
555
+ setModels([
556
+ model2,
557
+ formatting2
558
+ ]);
559
+ });
560
+ return () => {
561
+ clearTimeout(t);
562
+ void model2?.destroy();
563
+ };
564
+ }, [
565
+ graph,
566
+ readonly
567
+ ]);
568
+ if (!model || !formatting) {
569
+ return null;
570
+ }
571
+ return /* @__PURE__ */ React.createElement(SheetContext.Provider, {
572
+ value: {
573
+ model,
574
+ formatting,
575
+ cursor,
576
+ setCursor,
577
+ range,
578
+ setRange,
579
+ editing,
580
+ setEditing,
581
+ // TODO(burdon): Change to event.
582
+ onInfo,
583
+ decorations
584
+ }
585
+ }, children);
586
+ };
587
+
588
+ // packages/plugins/plugin-sheet/src/components/Sheet/threads.tsx
589
+ import { effect } from "@preact/signals-core";
590
+ import React2, { useCallback, useEffect as useEffect3, useMemo as useMemo2 } from "react";
591
+ import { LayoutAction, useIntentDispatcher, useIntentResolver } from "@dxos/app-framework";
592
+ import { debounce } from "@dxos/async";
593
+ import { fullyQualifiedId as fullyQualifiedId2 } from "@dxos/react-client/echo";
594
+ import { Icon, useTranslation } from "@dxos/react-ui";
595
+ import { mx } from "@dxos/react-ui-theme";
596
+ var CommentIndicator = () => {
597
+ return /* @__PURE__ */ React2.createElement("div", {
598
+ role: "none",
599
+ className: "absolute top-0 right-0 w-0 h-0 border-t-8 border-l-8 border-t-cmCommentSurface border-l-transparent"
600
+ });
601
+ };
602
+ var ThreadedCellWrapper = ({ children }) => {
603
+ const dispatch = useIntentDispatcher();
604
+ const [isHovered, setIsHovered] = React2.useState(true);
605
+ const { t } = useTranslation(SHEET_PLUGIN);
606
+ const handleClick = React2.useCallback((_event) => {
607
+ void dispatch({
608
+ action: LayoutAction.SET_LAYOUT,
609
+ data: {
610
+ element: "complementary",
611
+ state: true
612
+ }
613
+ });
614
+ }, [
615
+ dispatch
616
+ ]);
617
+ return /* @__PURE__ */ React2.createElement("div", {
618
+ role: "none",
619
+ className: mx("relative h-full is-full"),
620
+ onMouseEnter: () => {
621
+ setIsHovered(true);
622
+ },
623
+ onMouseLeave: () => {
624
+ setIsHovered(false);
625
+ }
626
+ }, /* @__PURE__ */ React2.createElement(CommentIndicator, null), isHovered && /* @__PURE__ */ React2.createElement("div", {
627
+ className: "absolute inset-0 flex items-center justify-end pr-1"
628
+ }, /* @__PURE__ */ React2.createElement("button", {
629
+ className: "ch-button text-xs min-bs-0 p-1",
630
+ onClick: handleClick,
631
+ "aria-label": t("open comment for sheet cell")
632
+ }, /* @__PURE__ */ React2.createElement(Icon, {
633
+ icon: "ph--chat--regular",
634
+ "aria-hidden": true
635
+ }))), children);
636
+ };
637
+ var createThreadDecoration = (cellIndex, threadId, sheetId) => {
638
+ return {
639
+ type: "comment",
640
+ cellIndex,
641
+ decorate: (props) => /* @__PURE__ */ React2.createElement(ThreadedCellWrapper, props)
642
+ };
643
+ };
644
+ var useUpdateCursorOnThreadSelection = () => {
645
+ const { setCursor, model } = useSheetContext();
646
+ const handleScrollIntoView = useCallback(({ action, data }) => {
647
+ switch (action) {
648
+ case LayoutAction.SCROLL_INTO_VIEW: {
649
+ if (!data?.id || data?.cursor === void 0 || data?.id !== fullyQualifiedId2(model.sheet)) {
650
+ return;
651
+ }
652
+ const cellAddress = addressFromIndex(model.sheet, data.cursor);
653
+ setCursor(cellAddress);
654
+ }
655
+ }
656
+ }, [
657
+ model.sheet,
658
+ setCursor
659
+ ]);
660
+ useIntentResolver(SHEET_PLUGIN, handleScrollIntoView);
661
+ };
662
+ var useSelectThreadOnCursorChange = () => {
663
+ const { cursor, model } = useSheetContext();
664
+ const dispatch = useIntentDispatcher();
665
+ const activeThreads = useMemo2(() => model.sheet.threads?.filter((thread) => !!thread && thread.status === "active") ?? [], [
666
+ JSON.stringify(model.sheet.threads)
667
+ ]);
668
+ const activeThreadAddresses = useMemo2(() => activeThreads.map((thread) => thread.anchor).filter((anchor) => anchor !== void 0).map((anchor) => addressFromIndex(model.sheet, anchor)), [
669
+ activeThreads,
670
+ model.sheet
671
+ ]);
672
+ const selectClosestThread = useCallback((cellAddress) => {
673
+ if (!cellAddress || !activeThreads) {
674
+ return;
675
+ }
676
+ const closestThreadAnchor = closest(cellAddress, activeThreadAddresses);
677
+ if (closestThreadAnchor) {
678
+ const closestThread = activeThreads.find((thread) => thread && thread.anchor === addressToIndex(model.sheet, closestThreadAnchor));
679
+ if (closestThread) {
680
+ void dispatch([
681
+ {
682
+ action: "dxos.org/plugin/thread/action/select",
683
+ data: {
684
+ current: fullyQualifiedId2(closestThread)
685
+ }
686
+ }
687
+ ]);
688
+ }
689
+ }
690
+ }, [
691
+ dispatch,
692
+ activeThreads,
693
+ activeThreadAddresses,
694
+ model.sheet
695
+ ]);
696
+ const debounced = useMemo2(() => {
697
+ return debounce((cursor2) => requestAnimationFrame(() => selectClosestThread(cursor2)), 50);
698
+ }, [
699
+ selectClosestThread
700
+ ]);
701
+ useEffect3(() => {
702
+ if (!cursor) {
703
+ return;
704
+ }
705
+ debounced(cursor);
706
+ }, [
707
+ cursor,
708
+ selectClosestThread
709
+ ]);
710
+ };
711
+ var useThreadDecorations = () => {
712
+ const { decorations, model } = useSheetContext();
713
+ const sheet = useMemo2(() => model.sheet, [
714
+ model.sheet
715
+ ]);
716
+ const sheetId = useMemo2(() => fullyQualifiedId2(sheet), [
717
+ sheet
718
+ ]);
719
+ useEffect3(() => {
720
+ const unsubscribe = effect(() => {
721
+ const activeThreadAnchors = /* @__PURE__ */ new Set();
722
+ if (!sheet.threads) {
723
+ return;
724
+ }
725
+ for (const thread of sheet.threads) {
726
+ if (!thread || thread.anchor === void 0 || thread.status === "resolved") {
727
+ continue;
728
+ }
729
+ activeThreadAnchors.add(thread.anchor);
730
+ const index = thread.anchor;
731
+ const existingDecorations = decorations.getDecorationsForCell(index);
732
+ if (!existingDecorations || !existingDecorations.some((d) => d.type === "comment")) {
733
+ decorations.addDecoration(index, createThreadDecoration(index, thread.id, sheetId));
734
+ }
735
+ }
736
+ for (const decoration of decorations.getAllDecorations()) {
737
+ if (decoration.type !== "comment") {
738
+ continue;
739
+ }
740
+ if (!activeThreadAnchors.has(decoration.cellIndex)) {
741
+ decorations.removeDecoration(decoration.cellIndex, "comment");
742
+ }
743
+ }
744
+ });
745
+ return () => unsubscribe();
746
+ });
747
+ };
748
+ var useThreads = () => {
749
+ useUpdateCursorOnThreadSelection();
750
+ useSelectThreadOnCursorChange();
751
+ useThreadDecorations();
752
+ };
753
+
754
+ // packages/plugins/plugin-sheet/src/components/Sheet/util.ts
755
+ var getRelativeClientRect = (root, element) => {
756
+ const rootRect = root.getBoundingClientRect();
757
+ const elementRect = element.getBoundingClientRect();
758
+ return new DOMRect(elementRect.left - rootRect.left + root.scrollLeft, elementRect.top - rootRect.top + root.scrollTop, elementRect.width, elementRect.height);
759
+ };
760
+ var getRectUnion = (b1, b2) => {
761
+ return {
762
+ left: Math.min(b1.left, b2.left),
763
+ top: Math.min(b1.top, b2.top),
764
+ width: Math.abs(b1.left - b2.left) + (b1.left > b2.left ? b1.width : b2.width),
765
+ height: Math.abs(b1.top - b2.top) + (b1.height > b2.height ? b1.height : b2.height)
766
+ };
767
+ };
768
+ var scrollIntoView = (scrollContainer, el) => {
769
+ el.scrollIntoView({
770
+ block: "nearest",
771
+ inline: "nearest"
772
+ });
773
+ const cellBounds = el.getBoundingClientRect();
774
+ const scrollerBounds = scrollContainer.getBoundingClientRect();
775
+ if (cellBounds.top < scrollerBounds.top) {
776
+ scrollContainer.scrollTop -= scrollerBounds.top - cellBounds.top;
777
+ } else if (cellBounds.bottom >= scrollerBounds.bottom - 1) {
778
+ scrollContainer.scrollTop += 2 + scrollerBounds.bottom - cellBounds.bottom;
779
+ }
780
+ if (cellBounds.left < scrollerBounds.left) {
781
+ scrollContainer.scrollLeft -= scrollerBounds.left - cellBounds.left;
782
+ } else if (cellBounds.right >= scrollerBounds.right) {
783
+ scrollContainer.scrollLeft += 2 + scrollerBounds.right - cellBounds.right;
784
+ }
785
+ };
786
+
787
+ // packages/plugins/plugin-sheet/src/components/CellEditor/CellEditor.tsx
788
+ import { EditorView, keymap } from "@codemirror/view";
789
+ import React3 from "react";
790
+ import { useThemeContext } from "@dxos/react-ui";
791
+ import { createBasicExtensions, createThemeExtensions, preventNewline, useTextEditor } from "@dxos/react-ui-editor";
792
+ var editorKeys = ({ onNav, onClose }) => {
793
+ return keymap.of([
794
+ {
795
+ key: "ArrowUp",
796
+ run: (editor) => {
797
+ const value = editor.state.doc.toString();
798
+ onNav?.(value, {
799
+ key: "ArrowUp"
800
+ });
801
+ return !!onNav;
802
+ }
803
+ },
804
+ {
805
+ key: "ArrowDown",
806
+ run: (editor) => {
807
+ const value = editor.state.doc.toString();
808
+ onNav?.(value, {
809
+ key: "ArrowDown"
810
+ });
811
+ return !!onNav;
812
+ }
813
+ },
814
+ {
815
+ key: "ArrowLeft",
816
+ run: (editor) => {
817
+ const value = editor.state.doc.toString();
818
+ onNav?.(value, {
819
+ key: "ArrowLeft"
820
+ });
821
+ return !!onNav;
822
+ }
823
+ },
824
+ {
825
+ key: "ArrowRight",
826
+ run: (editor) => {
827
+ const value = editor.state.doc.toString();
828
+ onNav?.(value, {
829
+ key: "ArrowRight"
830
+ });
831
+ return !!onNav;
832
+ }
833
+ },
834
+ {
835
+ key: "Enter",
836
+ run: (editor) => {
837
+ onClose(editor.state.doc.toString());
838
+ return true;
839
+ }
840
+ },
841
+ {
842
+ key: "Escape",
843
+ run: () => {
844
+ onClose(void 0);
845
+ return true;
846
+ }
847
+ }
848
+ ]);
849
+ };
850
+ var CellEditor = ({ value, extension, autoFocus, onBlur }) => {
851
+ const { themeMode } = useThemeContext();
852
+ const { parentRef } = useTextEditor(() => {
853
+ return {
854
+ autoFocus,
855
+ initialValue: value,
856
+ selection: {
857
+ anchor: value?.length ?? 0
858
+ },
859
+ extensions: [
860
+ extension ?? [],
861
+ preventNewline,
862
+ EditorView.focusChangeEffect.of((_, focusing) => {
863
+ if (!focusing) {
864
+ onBlur?.({
865
+ type: "blur"
866
+ });
867
+ }
868
+ return null;
869
+ }),
870
+ createBasicExtensions({
871
+ lineWrapping: false
872
+ }),
873
+ createThemeExtensions({
874
+ themeMode,
875
+ slots: {
876
+ editor: {
877
+ className: "flex w-full [&>.cm-scroller]:scrollbar-none"
878
+ },
879
+ content: {
880
+ className: "!px-2 !py-1"
881
+ }
882
+ }
883
+ })
884
+ ]
885
+ };
886
+ }, [
887
+ extension
888
+ ]);
889
+ return /* @__PURE__ */ React3.createElement("div", {
890
+ ref: parentRef,
891
+ className: "flex w-full"
892
+ });
893
+ };
894
+
895
+ // packages/plugins/plugin-sheet/src/components/CellEditor/extension.ts
896
+ import { acceptCompletion, autocompletion, completionStatus, startCompletion } from "@codemirror/autocomplete";
897
+ import { HighlightStyle, syntaxHighlighting } from "@codemirror/language";
898
+ import { Facet } from "@codemirror/state";
899
+ import { ViewPlugin, keymap as keymap2 } from "@codemirror/view";
900
+ import { tags } from "@lezer/highlight";
901
+ import { spreadsheet } from "codemirror-lang-spreadsheet";
902
+ import { mx as mx2 } from "@dxos/react-ui-theme";
903
+ var highlightStyles = HighlightStyle.define([
904
+ // Function.
905
+ {
906
+ tag: tags.name,
907
+ class: "text-accentText"
908
+ },
909
+ // Range.
910
+ {
911
+ tag: tags.tagName,
912
+ class: "text-pinkText"
913
+ },
914
+ // Values.
915
+ {
916
+ tag: tags.number,
917
+ class: "text-tealText"
918
+ },
919
+ {
920
+ tag: tags.bool,
921
+ class: "text-tealText"
922
+ },
923
+ {
924
+ tag: tags.string,
925
+ class: "text-tealText"
926
+ },
927
+ // Error.
928
+ {
929
+ tag: tags.invalid,
930
+ class: "text-unAccent"
931
+ }
932
+ ]);
933
+ var languageFacet = Facet.define();
934
+ var sheetExtension = ({ functions = [] }) => {
935
+ const { extension, language } = spreadsheet({
936
+ idiom: "en-US",
937
+ decimalSeparator: "."
938
+ });
939
+ const createCompletion = (name) => {
940
+ const { section = "Custom", description, syntax } = functions.find((value) => value.name === name) ?? {};
941
+ return {
942
+ section,
943
+ label: name,
944
+ info: () => {
945
+ if (!description && !syntax) {
946
+ return null;
947
+ }
948
+ const root = document.createElement("div");
949
+ root.className = "flex flex-col gap-2 text-sm";
950
+ const title = document.createElement("h2");
951
+ title.innerText = name;
952
+ title.className = "text-lg font-mono text-accentText";
953
+ root.appendChild(title);
954
+ if (description) {
955
+ const info = document.createElement("p");
956
+ info.innerText = description;
957
+ info.className = "text-subdued";
958
+ root.appendChild(info);
959
+ }
960
+ if (syntax) {
961
+ const detail = document.createElement("pre");
962
+ detail.innerText = syntax;
963
+ detail.className = "whitespace-pre-wrap text-greenText";
964
+ root.appendChild(detail);
965
+ }
966
+ return root;
967
+ },
968
+ apply: (view, completion, from, to) => {
969
+ const insertParens = to === view.state.doc.toString().length;
970
+ view.dispatch(view.state.update({
971
+ changes: {
972
+ from,
973
+ to,
974
+ insert: completion.label + (insertParens ? "()" : "")
975
+ },
976
+ selection: {
977
+ anchor: from + completion.label.length + 1
978
+ }
979
+ }));
980
+ }
981
+ };
982
+ };
983
+ return [
984
+ extension,
985
+ languageFacet.of(language),
986
+ language.data.of({
987
+ autocomplete: (context) => {
988
+ if (context.state.doc.toString()[0] !== "=") {
989
+ return null;
990
+ }
991
+ const match = context.matchBefore(/\w*/);
992
+ if (!match || match.from === match.to) {
993
+ return null;
994
+ }
995
+ const text = match.text.toUpperCase();
996
+ if (!context.explicit && match.text.length < 2) {
997
+ return null;
998
+ }
999
+ return {
1000
+ from: match.from,
1001
+ options: functions?.filter(({ name }) => name.startsWith(text)).map(({ name }) => createCompletion(name)) ?? []
1002
+ };
1003
+ }
1004
+ }),
1005
+ syntaxHighlighting(highlightStyles),
1006
+ autocompletion({
1007
+ aboveCursor: false,
1008
+ defaultKeymap: true,
1009
+ activateOnTyping: true,
1010
+ // NOTE: Useful for debugging.
1011
+ closeOnBlur: false,
1012
+ icons: false,
1013
+ tooltipClass: () => mx2(
1014
+ // TODO(burdon): Factor out fragments.
1015
+ // TODO(burdon): Size to make width same as column.
1016
+ "!-left-[1px] !top-[33px] !-m-0 border !border-t-0 [&>ul]:!min-w-[198px]",
1017
+ "[&>ul>li[aria-selected]]:!bg-accentSurface",
1018
+ "border-separator"
1019
+ )
1020
+ }),
1021
+ keymap2.of([
1022
+ {
1023
+ key: "Tab",
1024
+ run: (view) => {
1025
+ return completionStatus(view.state) === "active" ? acceptCompletion(view) : startCompletion(view);
1026
+ }
1027
+ }
1028
+ ])
1029
+ ];
1030
+ };
1031
+ var rangeExtension = (onInit) => {
1032
+ let view;
1033
+ let activeRange;
1034
+ const provider = (range) => {
1035
+ if (activeRange) {
1036
+ view.dispatch(view.state.update({
1037
+ changes: {
1038
+ ...activeRange,
1039
+ insert: range.toString()
1040
+ },
1041
+ selection: {
1042
+ anchor: activeRange.from + range.length
1043
+ }
1044
+ }));
1045
+ }
1046
+ view.focus();
1047
+ };
1048
+ return ViewPlugin.fromClass(class {
1049
+ constructor(_view) {
1050
+ view = _view;
1051
+ onInit(provider);
1052
+ }
1053
+ update(view2) {
1054
+ const { anchor } = view2.state.selection.ranges[0];
1055
+ activeRange = void 0;
1056
+ const [language] = view2.state.facet(languageFacet);
1057
+ const { topNode } = language.parser.parse(view2.state.doc.toString());
1058
+ visitTree(topNode, ({ type, from, to }) => {
1059
+ if (from <= anchor && to >= anchor) {
1060
+ switch (type.name) {
1061
+ case "Function": {
1062
+ activeRange = {
1063
+ from: to,
1064
+ to
1065
+ };
1066
+ break;
1067
+ }
1068
+ case "CloseParen": {
1069
+ activeRange = {
1070
+ from,
1071
+ to: from
1072
+ };
1073
+ break;
1074
+ }
1075
+ case "RangeToken":
1076
+ case "CellToken":
1077
+ activeRange = {
1078
+ from,
1079
+ to
1080
+ };
1081
+ return true;
1082
+ }
1083
+ }
1084
+ return false;
1085
+ });
1086
+ if (!activeRange && view2.state.doc.toString()[0] === "=") {
1087
+ activeRange = {
1088
+ from: 1,
1089
+ to: view2.state.doc.toString().length
1090
+ };
1091
+ }
1092
+ }
1093
+ });
1094
+ };
1095
+ var visitTree = (node, callback) => {
1096
+ if (callback(node)) {
1097
+ return true;
1098
+ }
1099
+ for (let child = node.firstChild; child !== null; child = child.nextSibling) {
1100
+ if (visitTree(child, callback)) {
1101
+ return true;
1102
+ }
1103
+ }
1104
+ return false;
1105
+ };
1106
+
1107
+ // packages/plugins/plugin-sheet/src/components/Sheet/Sheet.tsx
1108
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/plugins/plugin-sheet/src/components/Sheet/Sheet.tsx";
1109
+ var fragments = {
1110
+ axis: "bg-axisSurface text-axisText text-xs select-none",
1111
+ axisSelected: "bg-attention text-baseText",
1112
+ cell: "bg-gridCell",
1113
+ cellSelected: "bg-gridCellSelected text-baseText border !border-accentSurface"
1114
+ };
1115
+ var SheetRoot = ({ children, ...props }) => {
1116
+ return /* @__PURE__ */ React4.createElement(SheetContextProvider, props, children);
1117
+ };
1118
+ var SheetMain = /* @__PURE__ */ forwardRef(({ classNames, numRows, numColumns }, forwardRef2) => {
1119
+ const { model, cursor, setCursor, setRange, setEditing } = useSheetContext();
1120
+ const { rowsRef, columnsRef, contentRef } = useScrollHandlers();
1121
+ useThreads();
1122
+ const [rows, setRows] = useState4([
1123
+ ...model.sheet.rows
1124
+ ]);
1125
+ const [columns, setColumns] = useState4([
1126
+ ...model.sheet.columns
1127
+ ]);
1128
+ useEffect4(() => {
1129
+ const rowsAccessor = createDocAccessor(model.sheet, [
1130
+ "rows"
1131
+ ]);
1132
+ const columnsAccessor = createDocAccessor(model.sheet, [
1133
+ "columns"
1134
+ ]);
1135
+ const handleUpdate = debounce2(() => {
1136
+ setRows([
1137
+ ...model.sheet.rows
1138
+ ]);
1139
+ setColumns([
1140
+ ...model.sheet.columns
1141
+ ]);
1142
+ }, 100);
1143
+ rowsAccessor.handle.addListener("change", handleUpdate);
1144
+ columnsAccessor.handle.addListener("change", handleUpdate);
1145
+ handleUpdate();
1146
+ return () => {
1147
+ rowsAccessor.handle.removeListener("change", handleUpdate);
1148
+ columnsAccessor.handle.removeListener("change", handleUpdate);
1149
+ };
1150
+ }, [
1151
+ model
1152
+ ]);
1153
+ useEffect4(() => {
1154
+ model.reset();
1155
+ }, [
1156
+ rows,
1157
+ columns
1158
+ ]);
1159
+ const handleMoveRows = (from, to, num = 1) => {
1160
+ const cursorIdx = cursor ? addressToIndex(model.sheet, cursor) : void 0;
1161
+ const [rows2] = model.sheet.rows.splice(from, num);
1162
+ model.sheet.rows.splice(to, 0, rows2);
1163
+ if (cursorIdx) {
1164
+ setCursor(addressFromIndex(model.sheet, cursorIdx));
1165
+ }
1166
+ setRows([
1167
+ ...model.sheet.rows
1168
+ ]);
1169
+ };
1170
+ const handleMoveColumns = (from, to, num = 1) => {
1171
+ const cursorIdx = cursor ? addressToIndex(model.sheet, cursor) : void 0;
1172
+ const columns2 = model.sheet.columns.splice(from, num);
1173
+ model.sheet.columns.splice(to, 0, ...columns2);
1174
+ if (cursorIdx) {
1175
+ setCursor(addressFromIndex(model.sheet, cursorIdx));
1176
+ }
1177
+ setColumns([
1178
+ ...model.sheet.columns
1179
+ ]);
1180
+ };
1181
+ const [rowSizes, setRowSizes] = useState4();
1182
+ const [columnSizes, setColumnSizes] = useState4();
1183
+ useEffect4(() => {
1184
+ const rowAccessor = createDocAccessor(model.sheet, [
1185
+ "rowMeta"
1186
+ ]);
1187
+ const columnAccessor = createDocAccessor(model.sheet, [
1188
+ "columnMeta"
1189
+ ]);
1190
+ const handleUpdate = debounce2(() => {
1191
+ const mapSizes = (values) => values.reduce((map, [idx, meta]) => {
1192
+ if (meta.size) {
1193
+ map[idx] = meta.size;
1194
+ }
1195
+ return map;
1196
+ }, {});
1197
+ setRowSizes(mapSizes(Object.entries(model.sheet.rowMeta)));
1198
+ setColumnSizes(mapSizes(Object.entries(model.sheet.columnMeta)));
1199
+ }, 100);
1200
+ rowAccessor.handle.addListener("change", handleUpdate);
1201
+ columnAccessor.handle.addListener("change", handleUpdate);
1202
+ handleUpdate();
1203
+ return () => {
1204
+ rowAccessor.handle.removeListener("change", handleUpdate);
1205
+ columnAccessor.handle.removeListener("change", handleUpdate);
1206
+ };
1207
+ }, [
1208
+ model
1209
+ ]);
1210
+ const handleResizeRow = (idx, size, save) => {
1211
+ if (save) {
1212
+ model.sheet.rowMeta[idx] ??= {};
1213
+ model.sheet.rowMeta[idx].size = size;
1214
+ } else {
1215
+ setRowSizes((sizes) => ({
1216
+ ...sizes,
1217
+ [idx]: size
1218
+ }));
1219
+ }
1220
+ };
1221
+ const handleResizeColumn = (idx, size, save) => {
1222
+ if (save) {
1223
+ model.sheet.columnMeta[idx] ??= {};
1224
+ model.sheet.columnMeta[idx].size = size;
1225
+ } else {
1226
+ setColumnSizes((sizes) => ({
1227
+ ...sizes,
1228
+ [idx]: size
1229
+ }));
1230
+ }
1231
+ };
1232
+ return /* @__PURE__ */ React4.createElement("div", {
1233
+ role: "none",
1234
+ className: mx3("grid grid-cols-[calc(var(--rail-size)-2px)_1fr] grid-rows-[32px_1fr_32px] bs-full is-full overflow-hidden", classNames)
1235
+ }, /* @__PURE__ */ React4.createElement(GridCorner, {
1236
+ onClick: () => {
1237
+ setCursor(void 0);
1238
+ setRange(void 0);
1239
+ setEditing(false);
1240
+ }
1241
+ }), /* @__PURE__ */ React4.createElement(SheetColumns, {
1242
+ ref: columnsRef,
1243
+ columns,
1244
+ sizes: columnSizes,
1245
+ selected: cursor?.column,
1246
+ onSelect: (column) => setCursor(cursor?.column === column ? void 0 : {
1247
+ row: -1,
1248
+ column
1249
+ }),
1250
+ onResize: handleResizeColumn,
1251
+ onMove: handleMoveColumns
1252
+ }), /* @__PURE__ */ React4.createElement(SheetRows, {
1253
+ ref: rowsRef,
1254
+ rows,
1255
+ sizes: rowSizes,
1256
+ selected: cursor?.row,
1257
+ onSelect: (row) => setCursor(cursor?.row === row ? void 0 : {
1258
+ row,
1259
+ column: -1
1260
+ }),
1261
+ onResize: handleResizeRow,
1262
+ onMove: handleMoveRows
1263
+ }), /* @__PURE__ */ React4.createElement(SheetGrid, {
1264
+ ref: contentRef,
1265
+ size: {
1266
+ numRows: numRows ?? rows.length,
1267
+ numColumns: numColumns ?? columns.length
1268
+ },
1269
+ rows,
1270
+ columns,
1271
+ rowSizes,
1272
+ columnSizes
1273
+ }), /* @__PURE__ */ React4.createElement(GridCorner, null), /* @__PURE__ */ React4.createElement(SheetStatusBar, null));
1274
+ });
1275
+ var useScrollHandlers = () => {
1276
+ const rowsRef = useRef(null);
1277
+ const columnsRef = useRef(null);
1278
+ const contentRef = useRef(null);
1279
+ useEffect4(() => {
1280
+ const handleRowsScroll = (ev) => {
1281
+ const { scrollTop } = ev.target;
1282
+ if (!rowsRef.current.dataset.locked) {
1283
+ contentRef.current.scrollTop = scrollTop;
1284
+ }
1285
+ };
1286
+ const handleColumnsScroll = (ev) => {
1287
+ const { scrollLeft } = ev.target;
1288
+ if (!columnsRef.current.dataset.locked) {
1289
+ contentRef.current.scrollLeft = scrollLeft;
1290
+ }
1291
+ };
1292
+ const handleContentScroll = (ev) => {
1293
+ const { scrollTop, scrollLeft } = ev.target;
1294
+ rowsRef.current.scrollTop = scrollTop;
1295
+ columnsRef.current.scrollLeft = scrollLeft;
1296
+ };
1297
+ const rows = rowsRef.current;
1298
+ const columns = columnsRef.current;
1299
+ const content = contentRef.current;
1300
+ rows.addEventListener("scroll", handleRowsScroll);
1301
+ columns.addEventListener("scroll", handleColumnsScroll);
1302
+ content.addEventListener("scroll", handleContentScroll);
1303
+ return () => {
1304
+ rows.removeEventListener("scroll", handleRowsScroll);
1305
+ columns.removeEventListener("scroll", handleColumnsScroll);
1306
+ content.removeEventListener("scroll", handleContentScroll);
1307
+ };
1308
+ }, []);
1309
+ return {
1310
+ rowsRef,
1311
+ columnsRef,
1312
+ contentRef
1313
+ };
1314
+ };
1315
+ var GridCorner = (props) => {
1316
+ return /* @__PURE__ */ React4.createElement("div", {
1317
+ className: fragments.axis,
1318
+ ...props
1319
+ });
1320
+ };
1321
+ var MovingOverlay = ({ label }) => {
1322
+ return /* @__PURE__ */ React4.createElement("div", {
1323
+ className: "flex w-full h-full justify-center items-center text-sm p-1 bg-gridOverlay cursor-pointer"
1324
+ }, label);
1325
+ };
1326
+ var mouseConstraints = {
1327
+ distance: 10
1328
+ };
1329
+ var touchConstraints = {
1330
+ delay: 250,
1331
+ tolerance: 5
1332
+ };
1333
+ var SheetRows = /* @__PURE__ */ forwardRef(({ rows, sizes, selected, onSelect, onResize, onMove }, forwardRef2) => {
1334
+ const mouseSensor = useSensor(MouseSensor, {
1335
+ activationConstraint: mouseConstraints
1336
+ });
1337
+ const touchSensor = useSensor(TouchSensor, {
1338
+ activationConstraint: touchConstraints
1339
+ });
1340
+ const keyboardSensor = useSensor(KeyboardSensor, {});
1341
+ const sensors = useSensors(mouseSensor, touchSensor, keyboardSensor);
1342
+ const [active, setActive] = useState4(null);
1343
+ const handleDragStart = ({ active: active2 }) => {
1344
+ setActive(active2);
1345
+ };
1346
+ const handleDragEnd = ({ over, active: active2 }) => {
1347
+ if (over && over.id !== active2.id) {
1348
+ setActive(null);
1349
+ onMove?.(active2.data.current.index, over.data.current.index);
1350
+ }
1351
+ };
1352
+ const snapToCenter = ({ activatorEvent, draggingNodeRect, transform }) => {
1353
+ if (draggingNodeRect && activatorEvent) {
1354
+ const activatorCoordinates = getEventCoordinates(activatorEvent);
1355
+ if (!activatorCoordinates) {
1356
+ return transform;
1357
+ }
1358
+ const offset = activatorCoordinates.y - draggingNodeRect.top;
1359
+ return {
1360
+ ...transform,
1361
+ y: transform.y + offset - draggingNodeRect.height / 2
1362
+ };
1363
+ }
1364
+ return transform;
1365
+ };
1366
+ return /* @__PURE__ */ React4.createElement("div", {
1367
+ className: "relative flex grow overflow-hidden"
1368
+ }, /* @__PURE__ */ React4.createElement("div", {
1369
+ className: mx3("z-20 absolute inset-0 border-y border-gridLine pointer-events-none"),
1370
+ style: {
1371
+ width: axisWidth
1372
+ }
1373
+ }), /* @__PURE__ */ React4.createElement("div", {
1374
+ ref: forwardRef2,
1375
+ role: "rowheader",
1376
+ className: "grow overflow-y-auto scrollbar-none"
1377
+ }, /* @__PURE__ */ React4.createElement(DndContext, {
1378
+ sensors,
1379
+ modifiers: [
1380
+ restrictToVerticalAxis,
1381
+ snapToCenter
1382
+ ],
1383
+ onDragStart: handleDragStart,
1384
+ onDragEnd: handleDragEnd
1385
+ }, /* @__PURE__ */ React4.createElement("div", {
1386
+ className: "flex flex-col",
1387
+ style: {
1388
+ width: axisWidth
1389
+ }
1390
+ }, rows.map((idx, index) => /* @__PURE__ */ React4.createElement(GridRowCell, {
1391
+ key: idx,
1392
+ idx,
1393
+ index,
1394
+ label: String(index + 1),
1395
+ size: sizes?.[idx] ?? defaultHeight,
1396
+ resize: index < rows.length - 1,
1397
+ selected: selected === index,
1398
+ onResize,
1399
+ onSelect
1400
+ }))), /* @__PURE__ */ createPortal(/* @__PURE__ */ React4.createElement(DragOverlay, null, active && /* @__PURE__ */ React4.createElement(MovingOverlay, {
1401
+ label: String(active.data.current.index + 1)
1402
+ })), document.body))));
1403
+ });
1404
+ var GridRowCell = ({ idx, index, label, size, resize, selected, onSelect, onResize }) => {
1405
+ const { setNodeRef: setDroppableNodeRef } = useDroppable({
1406
+ id: idx,
1407
+ data: {
1408
+ index
1409
+ }
1410
+ });
1411
+ const { setNodeRef: setDraggableNodeRef, attributes, listeners, isDragging, over } = useDraggable({
1412
+ id: idx,
1413
+ data: {
1414
+ index
1415
+ }
1416
+ });
1417
+ const setNodeRef = useCombinedRefs(setDroppableNodeRef, setDraggableNodeRef);
1418
+ const [initialSize, setInitialSize] = useState4(size);
1419
+ const [resizing, setResizing] = useState4(false);
1420
+ const scrollHandler = useRef();
1421
+ const handleResizeStart = (_ev, _dir, elementRef) => {
1422
+ const scrollContainer = elementRef.closest('[role="rowheader"]');
1423
+ const scrollTop = scrollContainer.scrollTop;
1424
+ scrollHandler.current = (ev) => ev.target.scrollTop = scrollTop;
1425
+ scrollContainer.addEventListener("scroll", scrollHandler.current);
1426
+ scrollContainer.dataset.locked = "true";
1427
+ setResizing(true);
1428
+ };
1429
+ const handleResize = (_ev, _dir, _elementRef, { height }) => {
1430
+ onResize?.(idx, initialSize + height);
1431
+ };
1432
+ const handleResizeStop = (_ev, _dir, elementRef, { height }) => {
1433
+ const scrollContainer = elementRef.closest('[role="rowheader"]');
1434
+ scrollContainer.removeEventListener("scroll", scrollHandler.current);
1435
+ delete scrollContainer.dataset.locked;
1436
+ scrollHandler.current = void 0;
1437
+ setInitialSize(initialSize + height);
1438
+ onResize?.(idx, initialSize + height, true);
1439
+ setResizing(false);
1440
+ };
1441
+ return /* @__PURE__ */ React4.createElement(Resizable, {
1442
+ enable: {
1443
+ bottom: resize
1444
+ },
1445
+ size: {
1446
+ height: size - 1
1447
+ },
1448
+ minHeight: minHeight - 1,
1449
+ maxHeight,
1450
+ onResizeStart: handleResizeStart,
1451
+ onResize: handleResize,
1452
+ onResizeStop: handleResizeStop
1453
+ }, /* @__PURE__ */ React4.createElement("div", {
1454
+ ref: setNodeRef,
1455
+ ...attributes,
1456
+ ...listeners,
1457
+ className: mx3("flex h-full items-center justify-center cursor-pointer", "border-t border-gridLine focus-visible:outline-none", fragments.axis, selected && fragments.axisSelected, isDragging && fragments.axisSelected),
1458
+ onClick: () => onSelect?.(index)
1459
+ }, /* @__PURE__ */ React4.createElement("span", {
1460
+ className: "flex w-full justify-center"
1461
+ }, label), over?.id === idx && !isDragging && /* @__PURE__ */ React4.createElement("div", {
1462
+ className: "z-20 absolute top-0 w-full min-h-[4px] border-b-4 border-accentSurface"
1463
+ }), resizing && /* @__PURE__ */ React4.createElement("div", {
1464
+ className: "z-20 absolute bottom-0 w-full min-h-[4px] border-b-4 border-accentSurface"
1465
+ })));
1466
+ };
1467
+ var SheetColumns = /* @__PURE__ */ forwardRef(({ columns, sizes, selected, onSelect, onResize, onMove }, forwardRef2) => {
1468
+ const mouseSensor = useSensor(MouseSensor, {
1469
+ activationConstraint: mouseConstraints
1470
+ });
1471
+ const touchSensor = useSensor(TouchSensor, {
1472
+ activationConstraint: touchConstraints
1473
+ });
1474
+ const keyboardSensor = useSensor(KeyboardSensor, {});
1475
+ const sensors = useSensors(mouseSensor, touchSensor, keyboardSensor);
1476
+ const [active, setActive] = useState4(null);
1477
+ const handleDragStart = ({ active: active2 }) => {
1478
+ setActive(active2);
1479
+ };
1480
+ const handleDragEnd = ({ active: active2, over }) => {
1481
+ if (over && over.id !== active2.id) {
1482
+ setActive(null);
1483
+ onMove?.(active2.data.current.index, over.data.current.index);
1484
+ }
1485
+ };
1486
+ const snapToCenter = ({ activatorEvent, draggingNodeRect, transform }) => {
1487
+ if (draggingNodeRect && activatorEvent) {
1488
+ const activatorCoordinates = getEventCoordinates(activatorEvent);
1489
+ if (!activatorCoordinates) {
1490
+ return transform;
1491
+ }
1492
+ const offset = activatorCoordinates.x - draggingNodeRect.left;
1493
+ return {
1494
+ ...transform,
1495
+ x: transform.x + offset - draggingNodeRect.width / 2
1496
+ };
1497
+ }
1498
+ return transform;
1499
+ };
1500
+ return /* @__PURE__ */ React4.createElement("div", {
1501
+ className: "relative flex grow overflow-hidden"
1502
+ }, /* @__PURE__ */ React4.createElement("div", {
1503
+ className: mx3("z-20 absolute inset-0 border-x border-gridLine pointer-events-none"),
1504
+ style: {
1505
+ height: axisHeight
1506
+ }
1507
+ }), /* @__PURE__ */ React4.createElement("div", {
1508
+ ref: forwardRef2,
1509
+ role: "columnheader",
1510
+ className: "grow overflow-x-auto scrollbar-none"
1511
+ }, /* @__PURE__ */ React4.createElement(DndContext, {
1512
+ autoScroll: {
1513
+ enabled: true
1514
+ },
1515
+ sensors,
1516
+ modifiers: [
1517
+ restrictToHorizontalAxis,
1518
+ snapToCenter
1519
+ ],
1520
+ onDragStart: handleDragStart,
1521
+ onDragEnd: handleDragEnd
1522
+ }, /* @__PURE__ */ React4.createElement("div", {
1523
+ className: "flex h-full",
1524
+ style: {
1525
+ height: axisHeight
1526
+ }
1527
+ }, columns.map((idx, index) => /* @__PURE__ */ React4.createElement(GridColumnCell, {
1528
+ key: idx,
1529
+ idx,
1530
+ index,
1531
+ label: columnLetter(index),
1532
+ size: sizes?.[idx] ?? defaultWidth,
1533
+ resize: index < columns.length - 1,
1534
+ selected: selected === index,
1535
+ onResize,
1536
+ onSelect
1537
+ }))), /* @__PURE__ */ createPortal(/* @__PURE__ */ React4.createElement(DragOverlay, null, active && /* @__PURE__ */ React4.createElement(MovingOverlay, {
1538
+ label: columnLetter(active.data.current.index)
1539
+ })), document.body))));
1540
+ });
1541
+ var GridColumnCell = ({ idx, index, label, size, resize, selected, onSelect, onResize }) => {
1542
+ const { setNodeRef: setDroppableNodeRef } = useDroppable({
1543
+ id: idx,
1544
+ data: {
1545
+ index
1546
+ }
1547
+ });
1548
+ const { setNodeRef: setDraggableNodeRef, attributes, listeners, over, isDragging } = useDraggable({
1549
+ id: idx,
1550
+ data: {
1551
+ index
1552
+ }
1553
+ });
1554
+ const setNodeRef = useCombinedRefs(setDroppableNodeRef, setDraggableNodeRef);
1555
+ const [initialSize, setInitialSize] = useState4(size);
1556
+ const [resizing, setResizing] = useState4(false);
1557
+ const scrollHandler = useRef();
1558
+ const handleResizeStart = (_ev, _dir, elementRef) => {
1559
+ const scrollContainer = elementRef.closest('[role="columnheader"]');
1560
+ const scrollLeft = scrollContainer.scrollLeft;
1561
+ scrollHandler.current = (ev) => ev.target.scrollLeft = scrollLeft;
1562
+ scrollContainer.addEventListener("scroll", scrollHandler.current);
1563
+ scrollContainer.dataset.locked = "true";
1564
+ setResizing(true);
1565
+ };
1566
+ const handleResize = (_ev, _dir, _elementRef, { width }) => {
1567
+ onResize?.(idx, initialSize + width);
1568
+ };
1569
+ const handleResizeStop = (_ev, _dir, elementRef, { width }) => {
1570
+ const scrollContainer = elementRef.closest('[role="columnheader"]');
1571
+ scrollContainer.removeEventListener("scroll", scrollHandler.current);
1572
+ delete scrollContainer.dataset.locked;
1573
+ scrollHandler.current = void 0;
1574
+ setInitialSize(initialSize + width);
1575
+ onResize?.(idx, initialSize + width, true);
1576
+ setResizing(false);
1577
+ };
1578
+ return /* @__PURE__ */ React4.createElement(Resizable, {
1579
+ enable: {
1580
+ right: resize
1581
+ },
1582
+ size: {
1583
+ width: size - 1
1584
+ },
1585
+ minWidth: minWidth - 1,
1586
+ maxWidth,
1587
+ onResizeStart: handleResizeStart,
1588
+ onResize: handleResize,
1589
+ onResizeStop: handleResizeStop
1590
+ }, /* @__PURE__ */ React4.createElement("div", {
1591
+ ref: setNodeRef,
1592
+ ...attributes,
1593
+ ...listeners,
1594
+ className: mx3("flex h-full items-center justify-center cursor-pointer", "border-l border-gridLine focus-visible:outline-none", fragments.axis, selected && fragments.axisSelected, isDragging && fragments.axisSelected),
1595
+ onClick: () => onSelect?.(index)
1596
+ }, /* @__PURE__ */ React4.createElement("span", {
1597
+ className: "flex w-full justify-center"
1598
+ }, label), over?.id === idx && !isDragging && /* @__PURE__ */ React4.createElement("div", {
1599
+ className: "z-20 absolute left-0 h-full min-w-[4px] border-l-4 border-accentSurface"
1600
+ }), resizing && /* @__PURE__ */ React4.createElement("div", {
1601
+ className: "z-20 absolute right-0 h-full min-h-[4px] border-l-4 border-accentSurface"
1602
+ })));
1603
+ };
1604
+ var SheetGrid = /* @__PURE__ */ forwardRef(({ size, rows, columns, rowSizes, columnSizes }, forwardRef2) => {
1605
+ const { ref: containerRef, width: containerWidth = 0, height: containerHeight = 0 } = useResizeDetector({
1606
+ refreshRate: 200
1607
+ });
1608
+ const scrollerRef = useRef(null);
1609
+ useImperativeHandle(forwardRef2, () => scrollerRef.current);
1610
+ const { model, cursor, range, editing, setCursor, setRange, setEditing, onInfo } = useSheetContext();
1611
+ const initialText = useRef();
1612
+ const quickEdit = useRef(false);
1613
+ const [, forceUpdate] = useState4({});
1614
+ useEffect4(() => {
1615
+ const unsubscribe = model.update.on(() => {
1616
+ log("updated", {
1617
+ id: model.id
1618
+ }, {
1619
+ F: __dxlog_file2,
1620
+ L: 737,
1621
+ S: void 0,
1622
+ C: (f, a) => f(...a)
1623
+ });
1624
+ forceUpdate({});
1625
+ });
1626
+ return () => {
1627
+ unsubscribe();
1628
+ };
1629
+ }, [
1630
+ model
1631
+ ]);
1632
+ const inputRef = useRef(null);
1633
+ const handleKeyDown = (ev) => {
1634
+ const isMacOS = /Mac|iPhone|iPod|iPad/.test(navigator.userAgent);
1635
+ if (cursor && (isMacOS && ev.metaKey || ev.ctrlKey)) {
1636
+ switch (ev.key) {
1637
+ case "x": {
1638
+ model.cut(range ?? {
1639
+ from: cursor
1640
+ });
1641
+ return;
1642
+ }
1643
+ case "c": {
1644
+ model.copy(range ?? {
1645
+ from: cursor
1646
+ });
1647
+ return;
1648
+ }
1649
+ case "v": {
1650
+ model.paste(cursor);
1651
+ return;
1652
+ }
1653
+ case "z": {
1654
+ if (ev.shiftKey) {
1655
+ model.redo();
1656
+ } else {
1657
+ model.undo();
1658
+ }
1659
+ return;
1660
+ }
1661
+ }
1662
+ }
1663
+ switch (ev.key) {
1664
+ case "ArrowUp":
1665
+ case "ArrowDown":
1666
+ case "ArrowLeft":
1667
+ case "ArrowRight":
1668
+ case "Home":
1669
+ case "End": {
1670
+ const next = handleNav(ev, cursor, range, size);
1671
+ setRange(next.range);
1672
+ if (next.cursor) {
1673
+ setCursor(next.cursor);
1674
+ const element = getCellElement(scrollerRef.current, next.cursor);
1675
+ if (element) {
1676
+ scrollIntoView(scrollerRef.current, element);
1677
+ }
1678
+ }
1679
+ break;
1680
+ }
1681
+ case "Backspace": {
1682
+ if (cursor) {
1683
+ if (range) {
1684
+ model.clear(range);
1685
+ } else {
1686
+ model.setValue(cursor, null);
1687
+ }
1688
+ }
1689
+ break;
1690
+ }
1691
+ case "Escape": {
1692
+ setRange(void 0);
1693
+ break;
1694
+ }
1695
+ case "Enter": {
1696
+ ev.stopPropagation();
1697
+ if (cursor) {
1698
+ setEditing(true);
1699
+ }
1700
+ break;
1701
+ }
1702
+ case "?": {
1703
+ onInfo?.();
1704
+ break;
1705
+ }
1706
+ default: {
1707
+ if (ev.key.length === 1) {
1708
+ initialText.current = ev.key;
1709
+ quickEdit.current = true;
1710
+ setEditing(true);
1711
+ }
1712
+ }
1713
+ }
1714
+ };
1715
+ const { handlers } = useRangeSelect((event, range2) => {
1716
+ switch (event) {
1717
+ case "start": {
1718
+ setRange(void 0);
1719
+ break;
1720
+ }
1721
+ default: {
1722
+ setRange(range2);
1723
+ }
1724
+ }
1725
+ });
1726
+ const { width, height, rowRange, columnRange } = useGridLayout({
1727
+ scroller: scrollerRef.current,
1728
+ size: {
1729
+ width: containerWidth,
1730
+ height: containerHeight
1731
+ },
1732
+ rows,
1733
+ columns,
1734
+ rowSizes,
1735
+ columnSizes
1736
+ });
1737
+ const id = fullyQualifiedId3(model.sheet);
1738
+ const attendableAttrs = createAttendableAttributes(id);
1739
+ const hasAttention = useHasAttention(id);
1740
+ return /* @__PURE__ */ React4.createElement("div", {
1741
+ ref: containerRef,
1742
+ role: "grid",
1743
+ className: "relative flex grow overflow-hidden"
1744
+ }, /* @__PURE__ */ React4.createElement("div", {
1745
+ className: mx3("z-20 absolute inset-0 border border-gridLine pointer-events-none")
1746
+ }), /* @__PURE__ */ React4.createElement("div", {
1747
+ ref: scrollerRef,
1748
+ className: mx3("grow", hasAttention && "overflow-auto scrollbar-thin")
1749
+ }, /* @__PURE__ */ React4.createElement("div", {
1750
+ className: "relative select-none",
1751
+ style: {
1752
+ width,
1753
+ height
1754
+ },
1755
+ onClick: () => inputRef.current?.focus(),
1756
+ ...handlers
1757
+ }, scrollerRef.current && /* @__PURE__ */ React4.createElement(SelectionOverlay, {
1758
+ root: scrollerRef.current
1759
+ }), rowRange.map(({ row, top, height: height2 }) => {
1760
+ return columnRange.map(({ column, left, width: width2 }) => {
1761
+ const style = {
1762
+ position: "absolute",
1763
+ top,
1764
+ left,
1765
+ width: width2,
1766
+ height: height2
1767
+ };
1768
+ const cell = {
1769
+ row,
1770
+ column
1771
+ };
1772
+ const id2 = addressToA1Notation(cell);
1773
+ const idx = addressToIndex(model.sheet, cell);
1774
+ const active = posEquals(cursor, cell);
1775
+ if (active && editing) {
1776
+ const value = initialText.current ?? model.getCellText(cell) ?? "";
1777
+ const handleClose = (value2) => {
1778
+ initialText.current = void 0;
1779
+ quickEdit.current = false;
1780
+ if (value2 !== void 0) {
1781
+ model.setValue(cell, value2);
1782
+ const next = handleArrowNav({
1783
+ key: "ArrowDown",
1784
+ metaKey: false
1785
+ }, cursor, size);
1786
+ if (next) {
1787
+ setCursor(next);
1788
+ }
1789
+ }
1790
+ inputRef.current?.focus();
1791
+ setEditing(false);
1792
+ };
1793
+ const handleNav2 = (value2, { key }) => {
1794
+ initialText.current = void 0;
1795
+ model.setValue(cell, value2 ?? null);
1796
+ const next = handleArrowNav({
1797
+ key,
1798
+ metaKey: false
1799
+ }, cursor, size);
1800
+ if (next) {
1801
+ setCursor(next);
1802
+ }
1803
+ inputRef.current?.focus();
1804
+ setEditing(false);
1805
+ };
1806
+ return /* @__PURE__ */ React4.createElement(GridCellEditor, {
1807
+ key: idx,
1808
+ value,
1809
+ style,
1810
+ onNav: quickEdit.current ? handleNav2 : void 0,
1811
+ onClose: handleClose
1812
+ });
1813
+ }
1814
+ return /* @__PURE__ */ React4.createElement(SheetCell, {
1815
+ key: id2,
1816
+ id: id2,
1817
+ cell,
1818
+ active,
1819
+ style,
1820
+ onSelect: (cell2, edit) => {
1821
+ setEditing(edit);
1822
+ setCursor(cell2);
1823
+ }
1824
+ });
1825
+ });
1826
+ }))), /* @__PURE__ */ createPortal(/* @__PURE__ */ React4.createElement("input", {
1827
+ ref: inputRef,
1828
+ autoFocus: true,
1829
+ className: "absolute w-[1px] h-[1px] bg-transparent outline-none border-none caret-transparent",
1830
+ onKeyDown: handleKeyDown,
1831
+ ...attendableAttrs
1832
+ }), document.body));
1833
+ });
1834
+ var SelectionOverlay = ({ root }) => {
1835
+ const { range } = useSheetContext();
1836
+ if (!range) {
1837
+ return null;
1838
+ }
1839
+ const c1 = getCellElement(root, range.from);
1840
+ const c2 = range.to ? getCellElement(root, range.to) : c1;
1841
+ if (!c1 || !c2) {
1842
+ return null;
1843
+ }
1844
+ const b1 = getRelativeClientRect(root, c1);
1845
+ const b2 = getRelativeClientRect(root, c2);
1846
+ const bounds = getRectUnion(b1, b2);
1847
+ return /* @__PURE__ */ React4.createElement("div", {
1848
+ role: "none",
1849
+ style: bounds,
1850
+ className: "z-10 absolute pointer-events-none bg-gridSelectionOverlay border border-gridOverlay"
1851
+ });
1852
+ };
1853
+ var SheetCell = ({ id, cell, style, active, onSelect }) => {
1854
+ const { formatting, editing, setRange, decorations, model: { sheet } } = useSheetContext();
1855
+ const { value, classNames } = formatting.getFormatting(cell);
1856
+ const decorationsForCell = decorations.getDecorationsForCell(addressToIndex(sheet, cell)) ?? [];
1857
+ const decorationAddedClasses = useMemo3(() => decorationsForCell.flatMap((d) => d.classNames ?? []), [
1858
+ decorationsForCell
1859
+ ]);
1860
+ const decoratedContent = decorationsForCell.reduce((children, { decorate }) => {
1861
+ if (!decorate) {
1862
+ return children;
1863
+ }
1864
+ const DecoratorComponent = decorate;
1865
+ return /* @__PURE__ */ React4.createElement(DecoratorComponent, null, children);
1866
+ }, /* @__PURE__ */ React4.createElement("div", {
1867
+ role: "none",
1868
+ className: mx3("flex flex-grow bs-full is-full px-2 items-center truncate cursor-pointer", ...decorationAddedClasses)
1869
+ }, value));
1870
+ return /* @__PURE__ */ React4.createElement("div", {
1871
+ [`data-${CELL_DATA_KEY}`]: id,
1872
+ role: "cell",
1873
+ style,
1874
+ className: mx3("border border-gridLine cursor-pointer", fragments.cell, active && [
1875
+ "z-20",
1876
+ fragments.cellSelected
1877
+ ], classNames),
1878
+ onClick: () => {
1879
+ if (editing) {
1880
+ setRange?.({
1881
+ from: cell
1882
+ });
1883
+ } else {
1884
+ onSelect?.(cell, false);
1885
+ }
1886
+ },
1887
+ onDoubleClick: () => onSelect?.(cell, true)
1888
+ }, decoratedContent);
1889
+ };
1890
+ var GridCellEditor = ({ style, value, onNav, onClose }) => {
1891
+ const { model, range } = useSheetContext();
1892
+ const notifier = useRef();
1893
+ useEffect4(() => {
1894
+ if (range) {
1895
+ notifier.current?.(rangeToA1Notation(range));
1896
+ }
1897
+ }, [
1898
+ range
1899
+ ]);
1900
+ const extension = useMemo3(() => [
1901
+ editorKeys({
1902
+ onNav,
1903
+ onClose
1904
+ }),
1905
+ sheetExtension({
1906
+ functions: model.functions
1907
+ }),
1908
+ rangeExtension((fn) => notifier.current = fn)
1909
+ ], [
1910
+ model
1911
+ ]);
1912
+ return /* @__PURE__ */ React4.createElement("div", {
1913
+ role: "cell",
1914
+ style,
1915
+ className: mx3("z-20 flex", fragments.cellSelected),
1916
+ onClick: (ev) => ev.stopPropagation()
1917
+ }, /* @__PURE__ */ React4.createElement(CellEditor, {
1918
+ autoFocus: true,
1919
+ value,
1920
+ extension
1921
+ }));
1922
+ };
1923
+ var SheetStatusBar = () => {
1924
+ const { model, cursor, range } = useSheetContext();
1925
+ let value;
1926
+ let isFormula = false;
1927
+ if (cursor) {
1928
+ value = model.getCellValue(cursor);
1929
+ if (typeof value === "string" && value.charAt(0) === "=") {
1930
+ value = model.mapFormulaBindingFromId(model.mapFormulaIndicesToRefs(value));
1931
+ isFormula = true;
1932
+ } else if (value != null) {
1933
+ value = String(value);
1934
+ }
1935
+ }
1936
+ return /* @__PURE__ */ React4.createElement("div", {
1937
+ className: mx3("flex shrink-0 justify-between items-center px-4 py-1 text-sm border-x border-gridLine")
1938
+ }, /* @__PURE__ */ React4.createElement("div", {
1939
+ className: "flex gap-4 items-center"
1940
+ }, /* @__PURE__ */ React4.createElement("div", {
1941
+ className: "flex w-16 items-center font-mono"
1942
+ }, range && rangeToA1Notation(range) || cursor && addressToA1Notation(cursor)), /* @__PURE__ */ React4.createElement("div", {
1943
+ className: "flex gap-2 items-center"
1944
+ }, /* @__PURE__ */ React4.createElement(FunctionIcon, {
1945
+ className: mx3("text-greenText", isFormula ? "visible" : "invisible")
1946
+ }), /* @__PURE__ */ React4.createElement("span", {
1947
+ className: "font-mono"
1948
+ }, value))));
1949
+ };
1950
+ var SheetDebug = () => {
1951
+ const { model, cursor, range } = useSheetContext();
1952
+ const [, forceUpdate] = useState4({});
1953
+ useEffect4(() => {
1954
+ const accessor = createDocAccessor(model.sheet, []);
1955
+ const handleUpdate = () => forceUpdate({});
1956
+ accessor.handle.addListener("change", handleUpdate);
1957
+ handleUpdate();
1958
+ return () => {
1959
+ accessor.handle.removeListener("change", handleUpdate);
1960
+ };
1961
+ }, [
1962
+ model
1963
+ ]);
1964
+ return /* @__PURE__ */ React4.createElement("div", {
1965
+ className: mx3("z-20 absolute right-0 top-20 bottom-20 w-[30rem] overflow-auto scrollbar-thin", "border border-gridLine text-xs bg-neutral-50 dark:bg-black text-cyan-500 font-mono p-1 opacity-80")
1966
+ }, /* @__PURE__ */ React4.createElement("pre", {
1967
+ className: "whitespace-pre-wrap"
1968
+ }, JSON.stringify({
1969
+ cursor,
1970
+ range,
1971
+ cells: model.sheet.cells,
1972
+ rowMeta: model.sheet.rowMeta,
1973
+ columnMeta: model.sheet.columnMeta,
1974
+ formatting: model.sheet.formatting
1975
+ }, void 0, 2)));
1976
+ };
1977
+ var Sheet = {
1978
+ Root: SheetRoot,
1979
+ Main: SheetMain,
1980
+ Rows: SheetRows,
1981
+ Columns: SheetColumns,
1982
+ Grid: SheetGrid,
1983
+ Cell: SheetCell,
1984
+ StatusBar: SheetStatusBar,
1985
+ Debug: SheetDebug
1986
+ };
1987
+
1988
+ // packages/plugins/plugin-sheet/src/components/Toolbar/Toolbar.tsx
1989
+ import { Calendar, ChatText, CurrencyDollar, Eraser, HighlighterCircle, TextAlignCenter, TextAlignLeft, TextAlignRight } from "@phosphor-icons/react";
1990
+ import { createContext as createContext2 } from "@radix-ui/react-context";
1991
+ import React6 from "react";
1992
+ import { DensityProvider, ElevationProvider, Toolbar as NaturalToolbar2, useTranslation as useTranslation2 } from "@dxos/react-ui";
1993
+ import { nonNullable } from "@dxos/util";
1994
+
1995
+ // packages/plugins/plugin-sheet/src/components/Toolbar/common.tsx
1996
+ import React5 from "react";
1997
+ import { Toolbar as NaturalToolbar, Tooltip } from "@dxos/react-ui";
1998
+ import { getSize } from "@dxos/react-ui-theme";
1999
+ var iconStyles = getSize(5);
2000
+ var buttonStyles = "min-bs-0 p-2";
2001
+ var tooltipProps = {
2002
+ side: "top",
2003
+ classNames: "z-10"
2004
+ };
2005
+ var ToolbarSeparator = () => /* @__PURE__ */ React5.createElement("div", {
2006
+ role: "separator",
2007
+ className: "grow"
2008
+ });
2009
+ var ToolbarButton = ({ Icon: Icon2, children, ...props }) => {
2010
+ return /* @__PURE__ */ React5.createElement(Tooltip.Root, null, /* @__PURE__ */ React5.createElement(Tooltip.Trigger, {
2011
+ asChild: true
2012
+ }, /* @__PURE__ */ React5.createElement(NaturalToolbar.Button, {
2013
+ variant: "ghost",
2014
+ ...props,
2015
+ classNames: buttonStyles
2016
+ }, /* @__PURE__ */ React5.createElement(Icon2, {
2017
+ className: iconStyles
2018
+ }), /* @__PURE__ */ React5.createElement("span", {
2019
+ className: "sr-only"
2020
+ }, children))), /* @__PURE__ */ React5.createElement(Tooltip.Portal, null, /* @__PURE__ */ React5.createElement(Tooltip.Content, tooltipProps, children, /* @__PURE__ */ React5.createElement(Tooltip.Arrow, null))));
2021
+ };
2022
+ var ToolbarToggleButton = ({ Icon: Icon2, children, ...props }) => {
2023
+ return /* @__PURE__ */ React5.createElement(Tooltip.Root, null, /* @__PURE__ */ React5.createElement(Tooltip.Trigger, {
2024
+ asChild: true
2025
+ }, /* @__PURE__ */ React5.createElement(NaturalToolbar.ToggleGroupItem, {
2026
+ variant: "ghost",
2027
+ ...props,
2028
+ classNames: buttonStyles
2029
+ }, /* @__PURE__ */ React5.createElement(Icon2, {
2030
+ className: iconStyles
2031
+ }), /* @__PURE__ */ React5.createElement("span", {
2032
+ className: "sr-only"
2033
+ }, children))), /* @__PURE__ */ React5.createElement(Tooltip.Portal, null, /* @__PURE__ */ React5.createElement(Tooltip.Content, tooltipProps, children, /* @__PURE__ */ React5.createElement(Tooltip.Arrow, null))));
2034
+ };
2035
+
2036
+ // packages/plugins/plugin-sheet/src/components/Toolbar/Toolbar.tsx
2037
+ var [ToolbarContextProvider, useToolbarContext] = createContext2("Toolbar");
2038
+ var ToolbarRoot = ({ children, onAction, classNames }) => {
2039
+ return /* @__PURE__ */ React6.createElement(ToolbarContextProvider, {
2040
+ onAction
2041
+ }, /* @__PURE__ */ React6.createElement(DensityProvider, {
2042
+ density: "fine"
2043
+ }, /* @__PURE__ */ React6.createElement(ElevationProvider, {
2044
+ elevation: "chrome"
2045
+ }, /* @__PURE__ */ React6.createElement(NaturalToolbar2.Root, {
2046
+ classNames: [
2047
+ "is-full shrink-0 overflow-x-auto overflow-y-hidden p-1",
2048
+ classNames
2049
+ ]
2050
+ }, children))));
2051
+ };
2052
+ var formatOptions = [
2053
+ {
2054
+ type: "date",
2055
+ Icon: Calendar,
2056
+ getState: (state) => false
2057
+ },
2058
+ {
2059
+ type: "currency",
2060
+ Icon: CurrencyDollar,
2061
+ getState: (state) => false
2062
+ }
2063
+ ];
2064
+ var Format = () => {
2065
+ const { onAction } = useToolbarContext("Format");
2066
+ const { t } = useTranslation2(SHEET_PLUGIN);
2067
+ return /* @__PURE__ */ React6.createElement(NaturalToolbar2.ToggleGroup, {
2068
+ type: "single"
2069
+ }, formatOptions.map(({ type, getState, Icon: Icon2 }) => /* @__PURE__ */ React6.createElement(ToolbarToggleButton, {
2070
+ key: type,
2071
+ value: type,
2072
+ Icon: Icon2,
2073
+ // disabled={state?.blockType === 'codeblock'}
2074
+ // onClick={state ? () => onAction?.({ type, data: !getState(state) }) : undefined}
2075
+ onClick: () => onAction?.({
2076
+ type
2077
+ })
2078
+ }, t(`toolbar ${type} label`))));
2079
+ };
2080
+ var alignmentOptions = [
2081
+ {
2082
+ type: "left",
2083
+ Icon: TextAlignLeft,
2084
+ getState: (state) => false
2085
+ },
2086
+ {
2087
+ type: "center",
2088
+ Icon: TextAlignCenter,
2089
+ getState: (state) => false
2090
+ },
2091
+ {
2092
+ type: "right",
2093
+ Icon: TextAlignRight,
2094
+ getState: (state) => false
2095
+ }
2096
+ ];
2097
+ var Alignment = () => {
2098
+ const { onAction } = useToolbarContext("Alignment");
2099
+ const { t } = useTranslation2(SHEET_PLUGIN);
2100
+ return /* @__PURE__ */ React6.createElement(NaturalToolbar2.ToggleGroup, {
2101
+ type: "single"
2102
+ }, alignmentOptions.map(({ type, getState, Icon: Icon2 }) => /* @__PURE__ */ React6.createElement(ToolbarToggleButton, {
2103
+ key: type,
2104
+ value: type,
2105
+ Icon: Icon2,
2106
+ // disabled={state?.blockType === 'codeblock'}
2107
+ // onClick={state ? () => onAction?.({ type, data: !getState(state) }) : undefined}
2108
+ onClick: () => onAction?.({
2109
+ type
2110
+ })
2111
+ }, t(`toolbar ${type} label`))));
2112
+ };
2113
+ var styleOptions = [
2114
+ {
2115
+ type: "clear",
2116
+ Icon: Eraser,
2117
+ getState: (state) => false
2118
+ },
2119
+ {
2120
+ type: "highlight",
2121
+ Icon: HighlighterCircle,
2122
+ getState: (state) => false
2123
+ }
2124
+ ];
2125
+ var Styles = () => {
2126
+ const { onAction } = useToolbarContext("Alignment");
2127
+ const { t } = useTranslation2(SHEET_PLUGIN);
2128
+ return /* @__PURE__ */ React6.createElement(NaturalToolbar2.ToggleGroup, {
2129
+ type: "single"
2130
+ }, styleOptions.map(({ type, getState, Icon: Icon2 }) => /* @__PURE__ */ React6.createElement(ToolbarToggleButton, {
2131
+ key: type,
2132
+ value: type,
2133
+ Icon: Icon2,
2134
+ // disabled={state?.blockType === 'codeblock'}
2135
+ // onClick={state ? () => onAction?.({ type, data: !getState(state) }) : undefined}
2136
+ onClick: () => onAction?.({
2137
+ type
2138
+ })
2139
+ }, t(`toolbar ${type} label`))));
2140
+ };
2141
+ var Actions = () => {
2142
+ const { onAction } = useToolbarContext("Actions");
2143
+ const { cursor, range, model } = useSheetContext();
2144
+ const { t } = useTranslation2(SHEET_PLUGIN);
2145
+ const overlapsCommentAnchor = (model.sheet.threads ?? []).filter(nonNullable).filter((thread) => thread.status !== "resolved").some((thread) => {
2146
+ if (!cursor) {
2147
+ return false;
2148
+ }
2149
+ return addressToIndex(model.sheet, cursor) === thread.anchor;
2150
+ });
2151
+ const hasCursor = !!cursor;
2152
+ const cursorOnly = hasCursor && !range && !overlapsCommentAnchor;
2153
+ const tooltipLabelKey = !hasCursor ? "no cursor label" : overlapsCommentAnchor ? "selection overlaps existing comment label" : range ? "comment ranges not supported label" : "comment label";
2154
+ return /* @__PURE__ */ React6.createElement(ToolbarButton, {
2155
+ value: "comment",
2156
+ Icon: ChatText,
2157
+ "data-testid": "editor.toolbar.comment",
2158
+ onClick: () => {
2159
+ if (!cursor) {
2160
+ return;
2161
+ }
2162
+ return onAction?.({
2163
+ type: "comment",
2164
+ anchor: addressToIndex(model.sheet, cursor),
2165
+ cellContent: model.getCellText(cursor)
2166
+ });
2167
+ },
2168
+ disabled: !cursorOnly || overlapsCommentAnchor
2169
+ }, t(tooltipLabelKey));
2170
+ };
2171
+ var Toolbar = {
2172
+ Root: ToolbarRoot,
2173
+ Separator: ToolbarSeparator,
2174
+ Alignment,
2175
+ Format,
2176
+ Styles,
2177
+ Actions
2178
+ };
2179
+
2180
+ // packages/plugins/plugin-sheet/src/components/SheetContainer.tsx
2181
+ var attentionFragment = mx4("group-focus-within/editor:attention-surface group-[[aria-current]]/editor:attention-surface", "group-focus-within/editor:border-separator");
2182
+ var sectionToolbarLayout = "bs-[--rail-action] bg-[--sticky-bg] sticky block-start-0 __-block-start-px transition-opacity";
2183
+ var SheetContainer = ({ sheet, space, role, remoteFunctionUrl }) => {
2184
+ const dispatch = useIntentDispatcher2();
2185
+ const id = fullyQualifiedId4(sheet);
2186
+ const isDirectlyAttended = useIsDirectlyAttended(id);
2187
+ const handleAction = useCallback2((action) => {
2188
+ switch (action.type) {
2189
+ case "comment": {
2190
+ void dispatch({
2191
+ action: "dxos.org/plugin/thread/action/create",
2192
+ data: {
2193
+ cursor: action.anchor,
2194
+ name: action.cellContent,
2195
+ subject: sheet
2196
+ }
2197
+ });
2198
+ }
2199
+ }
2200
+ }, [
2201
+ sheet,
2202
+ dispatch
2203
+ ]);
2204
+ return /* @__PURE__ */ React7.createElement("div", {
2205
+ role: "none",
2206
+ className: role === "article" ? "row-span-2 grid grid-rows-subgrid" : void 0
2207
+ }, /* @__PURE__ */ React7.createElement(Sheet.Root, {
2208
+ sheet,
2209
+ space,
2210
+ remoteFunctionUrl
2211
+ }, /* @__PURE__ */ React7.createElement("div", {
2212
+ role: "none",
2213
+ className: mx4("flex flex-0 justify-center overflow-x-auto")
2214
+ }, /* @__PURE__ */ React7.createElement(Toolbar.Root, {
2215
+ onAction: handleAction,
2216
+ classNames: mx4(role === "section" ? [
2217
+ "z-[2] group-focus-within/section:visible",
2218
+ !isDirectlyAttended && "invisible",
2219
+ sectionToolbarLayout
2220
+ ] : "group-focus-within/editor:border-separator group-[[aria-current]]/editor:border-separator")
2221
+ }, /* @__PURE__ */ React7.createElement(Toolbar.Separator, null), /* @__PURE__ */ React7.createElement(Toolbar.Actions, null))), /* @__PURE__ */ React7.createElement("div", {
2222
+ role: "none",
2223
+ className: mx4(role === "section" && "aspect-square border-is border-bs border-be border-separator", role === "article" && "flex is-full overflow-hidden focus-visible:ring-inset row-span-1 data-[toolbar=disabled]:pbs-2 data-[toolbar=disabled]:row-span-2 border-bs border-separator", focusRing, attentionFragment)
2224
+ }, /* @__PURE__ */ React7.createElement(Sheet.Main, null))));
2225
+ };
2226
+ var SheetContainer_default = SheetContainer;
2227
+ export {
2228
+ SheetContainer_default as default,
2229
+ sectionToolbarLayout
2230
+ };
2231
+ //# sourceMappingURL=SheetContainer-Y7ZMFBAP.mjs.map