@dxos/plugin-sheet 0.6.11-staging.e6894a4 → 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 (107) hide show
  1. package/dist/lib/browser/{SheetContainer-4XOKHKKZ.mjs → SheetContainer-Y7ZMFBAP.mjs} +582 -121
  2. package/dist/lib/browser/SheetContainer-Y7ZMFBAP.mjs.map +7 -0
  3. package/dist/lib/browser/{chunk-P7SSL3EG.mjs → chunk-GNNVBNCX.mjs} +61 -53
  4. package/dist/lib/browser/chunk-GNNVBNCX.mjs.map +7 -0
  5. package/dist/lib/browser/{chunk-FWGRE3EG.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 +29 -18
  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-IQT6TR4Z.cjs → SheetContainer-KEOKUKAQ.cjs} +528 -79
  15. package/dist/lib/node/SheetContainer-KEOKUKAQ.cjs.map +7 -0
  16. package/dist/lib/node/{chunk-5EPCDAZC.cjs → chunk-57PB2HPY.cjs} +5 -5
  17. package/dist/lib/node/{chunk-727C6YNP.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-SVAIIXWQ.cjs → chunk-ZRQZFV5T.cjs} +76 -63
  21. package/dist/lib/node/chunk-ZRQZFV5T.cjs.map +7 -0
  22. package/dist/lib/node/index.cjs +43 -33
  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 +19 -20
  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 +11 -9
  82. package/src/components/Sheet/Sheet.tsx +57 -29
  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 -20
  88. package/src/components/Toolbar/Toolbar.stories.tsx +5 -10
  89. package/src/components/Toolbar/Toolbar.tsx +54 -12
  90. package/src/model/index.ts +1 -0
  91. package/src/model/model.browser.test.ts +1 -2
  92. package/src/model/model.ts +11 -46
  93. package/src/model/types.test.ts +1 -2
  94. package/src/model/util.ts +67 -0
  95. package/src/translations.ts +6 -1
  96. package/src/types.ts +26 -3
  97. package/dist/lib/browser/SheetContainer-4XOKHKKZ.mjs.map +0 -7
  98. package/dist/lib/browser/chunk-FUAGSXA4.mjs.map +0 -7
  99. package/dist/lib/browser/chunk-P7SSL3EG.mjs.map +0 -7
  100. package/dist/lib/browser/chunk-YPU3R7FA.mjs +0 -8
  101. package/dist/lib/node/SheetContainer-IQT6TR4Z.cjs.map +0 -7
  102. package/dist/lib/node/chunk-DSYKOI4E.cjs.map +0 -7
  103. package/dist/lib/node/chunk-SVAIIXWQ.cjs.map +0 -7
  104. /package/dist/lib/browser/{chunk-FWGRE3EG.mjs.map → chunk-PGKZPKUD.mjs.map} +0 -0
  105. /package/dist/lib/browser/{chunk-YPU3R7FA.mjs.map → chunk-VBF7YENS.mjs.map} +0 -0
  106. /package/dist/lib/node/{chunk-5EPCDAZC.cjs.map → chunk-57PB2HPY.cjs.map} +0 -0
  107. /package/dist/lib/node/{chunk-727C6YNP.cjs.map → chunk-6LWBQAQZ.cjs.map} +0 -0
@@ -1,24 +1,33 @@
1
1
  import {
2
2
  useComputeGraph
3
- } from "./chunk-FWGRE3EG.mjs";
3
+ } from "./chunk-PGKZPKUD.mjs";
4
4
  import {
5
5
  SheetModel,
6
6
  addressFromA1Notation,
7
+ addressFromIndex,
7
8
  addressToA1Notation,
9
+ addressToIndex,
10
+ closest,
8
11
  columnLetter,
9
12
  defaultFunctions,
10
13
  inRange,
11
14
  posEquals,
15
+ rangeFromIndex,
12
16
  rangeToA1Notation
13
- } from "./chunk-P7SSL3EG.mjs";
17
+ } from "./chunk-GNNVBNCX.mjs";
14
18
  import {
15
19
  ValueTypeEnum
16
- } from "./chunk-FUAGSXA4.mjs";
17
- import "./chunk-JRL5LGCE.mjs";
20
+ } from "./chunk-WUPTZUTX.mjs";
21
+ import {
22
+ SHEET_PLUGIN
23
+ } from "./chunk-JRL5LGCE.mjs";
18
24
 
19
25
  // packages/plugins/plugin-sheet/src/components/SheetContainer.tsx
20
- import React4 from "react";
21
- import { mx as mx3 } from "@dxos/react-ui-theme";
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";
22
31
 
23
32
  // packages/plugins/plugin-sheet/src/components/Sheet/Sheet.tsx
24
33
  import { DndContext, DragOverlay, KeyboardSensor, MouseSensor, TouchSensor, useDraggable, useDroppable, useSensor, useSensors } from "@dnd-kit/core";
@@ -26,14 +35,14 @@ import { restrictToHorizontalAxis, restrictToVerticalAxis } from "@dnd-kit/modif
26
35
  import { getEventCoordinates, useCombinedRefs } from "@dnd-kit/utilities";
27
36
  import { Function as FunctionIcon } from "@phosphor-icons/react";
28
37
  import { Resizable } from "re-resizable";
29
- import React3, { forwardRef, useEffect as useEffect3, useImperativeHandle, useMemo, useRef, useState as useState4 } from "react";
38
+ import React4, { forwardRef, useEffect as useEffect4, useImperativeHandle, useMemo as useMemo3, useRef, useState as useState4 } from "react";
30
39
  import { createPortal } from "react-dom";
31
40
  import { useResizeDetector } from "react-resize-detector";
32
- import { debounce } from "@dxos/async";
33
- import { fullyQualifiedId as fullyQualifiedId2, createDocAccessor } from "@dxos/client/echo";
41
+ import { debounce as debounce2 } from "@dxos/async";
42
+ import { fullyQualifiedId as fullyQualifiedId3, createDocAccessor } from "@dxos/client/echo";
34
43
  import { log } from "@dxos/log";
35
- import { createAttendableAttributes } from "@dxos/react-ui-attention";
36
- import { mx as mx2 } from "@dxos/react-ui-theme";
44
+ import { createAttendableAttributes, useHasAttention } from "@dxos/react-ui-attention";
45
+ import { mx as mx3 } from "@dxos/react-ui-theme";
37
46
 
38
47
  // packages/plugins/plugin-sheet/src/components/Sheet/grid.ts
39
48
  import { useEffect, useState } from "react";
@@ -327,10 +336,49 @@ var useRangeSelect = (cb) => {
327
336
  };
328
337
 
329
338
  // packages/plugins/plugin-sheet/src/components/Sheet/sheet-context.tsx
330
- import React, { createContext, useContext, useState as useState3, useEffect as useEffect2 } from "react";
339
+ import React, { createContext, useContext, useState as useState3, useEffect as useEffect2, useMemo } from "react";
331
340
  import { invariant } from "@dxos/invariant";
332
341
  import { fullyQualifiedId } from "@dxos/react-client/echo";
333
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
+
334
382
  // packages/plugins/plugin-sheet/src/components/Sheet/formatting.ts
335
383
  var FormattingModel = class {
336
384
  constructor(model) {
@@ -345,13 +393,13 @@ var FormattingModel = class {
345
393
  return {};
346
394
  }
347
395
  const locales = void 0;
348
- const idx = this.model.addressToIndex(cell);
396
+ const idx = addressToIndex(this.model.sheet, cell);
349
397
  let formatting = this.model.sheet.formatting?.[idx] ?? {};
350
398
  const classNames = [
351
399
  ...formatting?.classNames ?? []
352
400
  ];
353
401
  for (const [idx2, _formatting] of Object.entries(this.model.sheet.formatting)) {
354
- const range = this.model.rangeFromIndex(idx2);
402
+ const range = rangeFromIndex(this.model.sheet, idx2);
355
403
  if (inRange(range, cell)) {
356
404
  if (_formatting.classNames) {
357
405
  classNames.push(..._formatting.classNames);
@@ -373,6 +421,9 @@ var FormattingModel = class {
373
421
  ]
374
422
  };
375
423
  }
424
+ //
425
+ // Numbers.
426
+ //
376
427
  case ValueTypeEnum.Number: {
377
428
  return {
378
429
  value: value.toLocaleString(locales),
@@ -405,6 +456,9 @@ var FormattingModel = class {
405
456
  ]
406
457
  };
407
458
  }
459
+ //
460
+ // Dates.
461
+ //
408
462
  case ValueTypeEnum.DateTime: {
409
463
  const date = this.model.toLocalDate(value);
410
464
  return {
@@ -444,7 +498,7 @@ var useSheetContext = () => {
444
498
  const context = useContext(SheetContext);
445
499
  invariant(context, void 0, {
446
500
  F: __dxlog_file,
447
- L: 45,
501
+ L: 49,
448
502
  S: void 0,
449
503
  A: [
450
504
  "context",
@@ -485,6 +539,7 @@ var SheetContextProvider = ({ children, sheet, space, readonly, onInfo, ...optio
485
539
  const [cursor, setCursor] = useState3();
486
540
  const [range, setRange] = useState3();
487
541
  const [editing, setEditing] = useState3(false);
542
+ const decorations = useMemo(() => createDecorations(), []);
488
543
  const [[model, formatting] = [], setModels] = useState3(void 0);
489
544
  useEffect2(() => {
490
545
  let model2;
@@ -524,11 +579,178 @@ var SheetContextProvider = ({ children, sheet, space, readonly, onInfo, ...optio
524
579
  editing,
525
580
  setEditing,
526
581
  // TODO(burdon): Change to event.
527
- onInfo
582
+ onInfo,
583
+ decorations
528
584
  }
529
585
  }, children);
530
586
  };
531
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
+
532
754
  // packages/plugins/plugin-sheet/src/components/Sheet/util.ts
533
755
  var getRelativeClientRect = (root, element) => {
534
756
  const rootRect = root.getBoundingClientRect();
@@ -564,7 +786,7 @@ var scrollIntoView = (scrollContainer, el) => {
564
786
 
565
787
  // packages/plugins/plugin-sheet/src/components/CellEditor/CellEditor.tsx
566
788
  import { EditorView, keymap } from "@codemirror/view";
567
- import React2 from "react";
789
+ import React3 from "react";
568
790
  import { useThemeContext } from "@dxos/react-ui";
569
791
  import { createBasicExtensions, createThemeExtensions, preventNewline, useTextEditor } from "@dxos/react-ui-editor";
570
792
  var editorKeys = ({ onNav, onClose }) => {
@@ -664,7 +886,7 @@ var CellEditor = ({ value, extension, autoFocus, onBlur }) => {
664
886
  }, [
665
887
  extension
666
888
  ]);
667
- return /* @__PURE__ */ React2.createElement("div", {
889
+ return /* @__PURE__ */ React3.createElement("div", {
668
890
  ref: parentRef,
669
891
  className: "flex w-full"
670
892
  });
@@ -677,7 +899,7 @@ import { Facet } from "@codemirror/state";
677
899
  import { ViewPlugin, keymap as keymap2 } from "@codemirror/view";
678
900
  import { tags } from "@lezer/highlight";
679
901
  import { spreadsheet } from "codemirror-lang-spreadsheet";
680
- import { mx } from "@dxos/react-ui-theme";
902
+ import { mx as mx2 } from "@dxos/react-ui-theme";
681
903
  var highlightStyles = HighlightStyle.define([
682
904
  // Function.
683
905
  {
@@ -788,7 +1010,7 @@ var sheetExtension = ({ functions = [] }) => {
788
1010
  // NOTE: Useful for debugging.
789
1011
  closeOnBlur: false,
790
1012
  icons: false,
791
- tooltipClass: () => mx(
1013
+ tooltipClass: () => mx2(
792
1014
  // TODO(burdon): Factor out fragments.
793
1015
  // TODO(burdon): Size to make width same as column.
794
1016
  "!-left-[1px] !top-[33px] !-m-0 border !border-t-0 [&>ul]:!min-w-[198px]",
@@ -888,29 +1110,29 @@ var fragments = {
888
1110
  axis: "bg-axisSurface text-axisText text-xs select-none",
889
1111
  axisSelected: "bg-attention text-baseText",
890
1112
  cell: "bg-gridCell",
891
- cellSelected: "bg-gridCellSelected text-baseText border !border-accentSurface",
892
- border: "border-gridLine"
1113
+ cellSelected: "bg-gridCellSelected text-baseText border !border-accentSurface"
893
1114
  };
894
1115
  var SheetRoot = ({ children, ...props }) => {
895
- return /* @__PURE__ */ React3.createElement(SheetContextProvider, props, children);
1116
+ return /* @__PURE__ */ React4.createElement(SheetContextProvider, props, children);
896
1117
  };
897
1118
  var SheetMain = /* @__PURE__ */ forwardRef(({ classNames, numRows, numColumns }, forwardRef2) => {
898
1119
  const { model, cursor, setCursor, setRange, setEditing } = useSheetContext();
899
1120
  const { rowsRef, columnsRef, contentRef } = useScrollHandlers();
1121
+ useThreads();
900
1122
  const [rows, setRows] = useState4([
901
1123
  ...model.sheet.rows
902
1124
  ]);
903
1125
  const [columns, setColumns] = useState4([
904
1126
  ...model.sheet.columns
905
1127
  ]);
906
- useEffect3(() => {
1128
+ useEffect4(() => {
907
1129
  const rowsAccessor = createDocAccessor(model.sheet, [
908
1130
  "rows"
909
1131
  ]);
910
1132
  const columnsAccessor = createDocAccessor(model.sheet, [
911
1133
  "columns"
912
1134
  ]);
913
- const handleUpdate = debounce(() => {
1135
+ const handleUpdate = debounce2(() => {
914
1136
  setRows([
915
1137
  ...model.sheet.rows
916
1138
  ]);
@@ -928,29 +1150,29 @@ var SheetMain = /* @__PURE__ */ forwardRef(({ classNames, numRows, numColumns },
928
1150
  }, [
929
1151
  model
930
1152
  ]);
931
- useEffect3(() => {
1153
+ useEffect4(() => {
932
1154
  model.reset();
933
1155
  }, [
934
1156
  rows,
935
1157
  columns
936
1158
  ]);
937
1159
  const handleMoveRows = (from, to, num = 1) => {
938
- const cursorIdx = cursor ? model.addressToIndex(cursor) : void 0;
1160
+ const cursorIdx = cursor ? addressToIndex(model.sheet, cursor) : void 0;
939
1161
  const [rows2] = model.sheet.rows.splice(from, num);
940
1162
  model.sheet.rows.splice(to, 0, rows2);
941
1163
  if (cursorIdx) {
942
- setCursor(model.addressFromIndex(cursorIdx));
1164
+ setCursor(addressFromIndex(model.sheet, cursorIdx));
943
1165
  }
944
1166
  setRows([
945
1167
  ...model.sheet.rows
946
1168
  ]);
947
1169
  };
948
1170
  const handleMoveColumns = (from, to, num = 1) => {
949
- const cursorIdx = cursor ? model.addressToIndex(cursor) : void 0;
1171
+ const cursorIdx = cursor ? addressToIndex(model.sheet, cursor) : void 0;
950
1172
  const columns2 = model.sheet.columns.splice(from, num);
951
1173
  model.sheet.columns.splice(to, 0, ...columns2);
952
1174
  if (cursorIdx) {
953
- setCursor(model.addressFromIndex(cursorIdx));
1175
+ setCursor(addressFromIndex(model.sheet, cursorIdx));
954
1176
  }
955
1177
  setColumns([
956
1178
  ...model.sheet.columns
@@ -958,14 +1180,14 @@ var SheetMain = /* @__PURE__ */ forwardRef(({ classNames, numRows, numColumns },
958
1180
  };
959
1181
  const [rowSizes, setRowSizes] = useState4();
960
1182
  const [columnSizes, setColumnSizes] = useState4();
961
- useEffect3(() => {
1183
+ useEffect4(() => {
962
1184
  const rowAccessor = createDocAccessor(model.sheet, [
963
1185
  "rowMeta"
964
1186
  ]);
965
1187
  const columnAccessor = createDocAccessor(model.sheet, [
966
1188
  "columnMeta"
967
1189
  ]);
968
- const handleUpdate = debounce(() => {
1190
+ const handleUpdate = debounce2(() => {
969
1191
  const mapSizes = (values) => values.reduce((map, [idx, meta]) => {
970
1192
  if (meta.size) {
971
1193
  map[idx] = meta.size;
@@ -1007,16 +1229,16 @@ var SheetMain = /* @__PURE__ */ forwardRef(({ classNames, numRows, numColumns },
1007
1229
  }));
1008
1230
  }
1009
1231
  };
1010
- return /* @__PURE__ */ React3.createElement("div", {
1232
+ return /* @__PURE__ */ React4.createElement("div", {
1011
1233
  role: "none",
1012
- 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)
1013
- }, /* @__PURE__ */ React3.createElement(GridCorner, {
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, {
1014
1236
  onClick: () => {
1015
1237
  setCursor(void 0);
1016
1238
  setRange(void 0);
1017
1239
  setEditing(false);
1018
1240
  }
1019
- }), /* @__PURE__ */ React3.createElement(SheetColumns, {
1241
+ }), /* @__PURE__ */ React4.createElement(SheetColumns, {
1020
1242
  ref: columnsRef,
1021
1243
  columns,
1022
1244
  sizes: columnSizes,
@@ -1027,7 +1249,7 @@ var SheetMain = /* @__PURE__ */ forwardRef(({ classNames, numRows, numColumns },
1027
1249
  }),
1028
1250
  onResize: handleResizeColumn,
1029
1251
  onMove: handleMoveColumns
1030
- }), /* @__PURE__ */ React3.createElement(SheetRows, {
1252
+ }), /* @__PURE__ */ React4.createElement(SheetRows, {
1031
1253
  ref: rowsRef,
1032
1254
  rows,
1033
1255
  sizes: rowSizes,
@@ -1038,7 +1260,7 @@ var SheetMain = /* @__PURE__ */ forwardRef(({ classNames, numRows, numColumns },
1038
1260
  }),
1039
1261
  onResize: handleResizeRow,
1040
1262
  onMove: handleMoveRows
1041
- }), /* @__PURE__ */ React3.createElement(SheetGrid, {
1263
+ }), /* @__PURE__ */ React4.createElement(SheetGrid, {
1042
1264
  ref: contentRef,
1043
1265
  size: {
1044
1266
  numRows: numRows ?? rows.length,
@@ -1048,13 +1270,13 @@ var SheetMain = /* @__PURE__ */ forwardRef(({ classNames, numRows, numColumns },
1048
1270
  columns,
1049
1271
  rowSizes,
1050
1272
  columnSizes
1051
- }), /* @__PURE__ */ React3.createElement(GridCorner, null), /* @__PURE__ */ React3.createElement(SheetStatusBar, null));
1273
+ }), /* @__PURE__ */ React4.createElement(GridCorner, null), /* @__PURE__ */ React4.createElement(SheetStatusBar, null));
1052
1274
  });
1053
1275
  var useScrollHandlers = () => {
1054
1276
  const rowsRef = useRef(null);
1055
1277
  const columnsRef = useRef(null);
1056
1278
  const contentRef = useRef(null);
1057
- useEffect3(() => {
1279
+ useEffect4(() => {
1058
1280
  const handleRowsScroll = (ev) => {
1059
1281
  const { scrollTop } = ev.target;
1060
1282
  if (!rowsRef.current.dataset.locked) {
@@ -1091,13 +1313,13 @@ var useScrollHandlers = () => {
1091
1313
  };
1092
1314
  };
1093
1315
  var GridCorner = (props) => {
1094
- return /* @__PURE__ */ React3.createElement("div", {
1316
+ return /* @__PURE__ */ React4.createElement("div", {
1095
1317
  className: fragments.axis,
1096
1318
  ...props
1097
1319
  });
1098
1320
  };
1099
1321
  var MovingOverlay = ({ label }) => {
1100
- return /* @__PURE__ */ React3.createElement("div", {
1322
+ return /* @__PURE__ */ React4.createElement("div", {
1101
1323
  className: "flex w-full h-full justify-center items-center text-sm p-1 bg-gridOverlay cursor-pointer"
1102
1324
  }, label);
1103
1325
  };
@@ -1141,18 +1363,18 @@ var SheetRows = /* @__PURE__ */ forwardRef(({ rows, sizes, selected, onSelect, o
1141
1363
  }
1142
1364
  return transform;
1143
1365
  };
1144
- return /* @__PURE__ */ React3.createElement("div", {
1366
+ return /* @__PURE__ */ React4.createElement("div", {
1145
1367
  className: "relative flex grow overflow-hidden"
1146
- }, /* @__PURE__ */ React3.createElement("div", {
1147
- className: mx2("z-20 absolute inset-0 border-y pointer-events-none", fragments.border),
1368
+ }, /* @__PURE__ */ React4.createElement("div", {
1369
+ className: mx3("z-20 absolute inset-0 border-y border-gridLine pointer-events-none"),
1148
1370
  style: {
1149
1371
  width: axisWidth
1150
1372
  }
1151
- }), /* @__PURE__ */ React3.createElement("div", {
1373
+ }), /* @__PURE__ */ React4.createElement("div", {
1152
1374
  ref: forwardRef2,
1153
1375
  role: "rowheader",
1154
1376
  className: "grow overflow-y-auto scrollbar-none"
1155
- }, /* @__PURE__ */ React3.createElement(DndContext, {
1377
+ }, /* @__PURE__ */ React4.createElement(DndContext, {
1156
1378
  sensors,
1157
1379
  modifiers: [
1158
1380
  restrictToVerticalAxis,
@@ -1160,12 +1382,12 @@ var SheetRows = /* @__PURE__ */ forwardRef(({ rows, sizes, selected, onSelect, o
1160
1382
  ],
1161
1383
  onDragStart: handleDragStart,
1162
1384
  onDragEnd: handleDragEnd
1163
- }, /* @__PURE__ */ React3.createElement("div", {
1385
+ }, /* @__PURE__ */ React4.createElement("div", {
1164
1386
  className: "flex flex-col",
1165
1387
  style: {
1166
1388
  width: axisWidth
1167
1389
  }
1168
- }, rows.map((idx, index) => /* @__PURE__ */ React3.createElement(GridRowCell, {
1390
+ }, rows.map((idx, index) => /* @__PURE__ */ React4.createElement(GridRowCell, {
1169
1391
  key: idx,
1170
1392
  idx,
1171
1393
  index,
@@ -1175,7 +1397,7 @@ var SheetRows = /* @__PURE__ */ forwardRef(({ rows, sizes, selected, onSelect, o
1175
1397
  selected: selected === index,
1176
1398
  onResize,
1177
1399
  onSelect
1178
- }))), /* @__PURE__ */ createPortal(/* @__PURE__ */ React3.createElement(DragOverlay, null, active && /* @__PURE__ */ React3.createElement(MovingOverlay, {
1400
+ }))), /* @__PURE__ */ createPortal(/* @__PURE__ */ React4.createElement(DragOverlay, null, active && /* @__PURE__ */ React4.createElement(MovingOverlay, {
1179
1401
  label: String(active.data.current.index + 1)
1180
1402
  })), document.body))));
1181
1403
  });
@@ -1216,7 +1438,7 @@ var GridRowCell = ({ idx, index, label, size, resize, selected, onSelect, onResi
1216
1438
  onResize?.(idx, initialSize + height, true);
1217
1439
  setResizing(false);
1218
1440
  };
1219
- return /* @__PURE__ */ React3.createElement(Resizable, {
1441
+ return /* @__PURE__ */ React4.createElement(Resizable, {
1220
1442
  enable: {
1221
1443
  bottom: resize
1222
1444
  },
@@ -1228,17 +1450,17 @@ var GridRowCell = ({ idx, index, label, size, resize, selected, onSelect, onResi
1228
1450
  onResizeStart: handleResizeStart,
1229
1451
  onResize: handleResize,
1230
1452
  onResizeStop: handleResizeStop
1231
- }, /* @__PURE__ */ React3.createElement("div", {
1453
+ }, /* @__PURE__ */ React4.createElement("div", {
1232
1454
  ref: setNodeRef,
1233
1455
  ...attributes,
1234
1456
  ...listeners,
1235
- 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),
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),
1236
1458
  onClick: () => onSelect?.(index)
1237
- }, /* @__PURE__ */ React3.createElement("span", {
1459
+ }, /* @__PURE__ */ React4.createElement("span", {
1238
1460
  className: "flex w-full justify-center"
1239
- }, label), over?.id === idx && !isDragging && /* @__PURE__ */ React3.createElement("div", {
1461
+ }, label), over?.id === idx && !isDragging && /* @__PURE__ */ React4.createElement("div", {
1240
1462
  className: "z-20 absolute top-0 w-full min-h-[4px] border-b-4 border-accentSurface"
1241
- }), resizing && /* @__PURE__ */ React3.createElement("div", {
1463
+ }), resizing && /* @__PURE__ */ React4.createElement("div", {
1242
1464
  className: "z-20 absolute bottom-0 w-full min-h-[4px] border-b-4 border-accentSurface"
1243
1465
  })));
1244
1466
  };
@@ -1275,18 +1497,18 @@ var SheetColumns = /* @__PURE__ */ forwardRef(({ columns, sizes, selected, onSel
1275
1497
  }
1276
1498
  return transform;
1277
1499
  };
1278
- return /* @__PURE__ */ React3.createElement("div", {
1500
+ return /* @__PURE__ */ React4.createElement("div", {
1279
1501
  className: "relative flex grow overflow-hidden"
1280
- }, /* @__PURE__ */ React3.createElement("div", {
1281
- className: mx2("z-20 absolute inset-0 border-x pointer-events-none", fragments.border),
1502
+ }, /* @__PURE__ */ React4.createElement("div", {
1503
+ className: mx3("z-20 absolute inset-0 border-x border-gridLine pointer-events-none"),
1282
1504
  style: {
1283
1505
  height: axisHeight
1284
1506
  }
1285
- }), /* @__PURE__ */ React3.createElement("div", {
1507
+ }), /* @__PURE__ */ React4.createElement("div", {
1286
1508
  ref: forwardRef2,
1287
1509
  role: "columnheader",
1288
1510
  className: "grow overflow-x-auto scrollbar-none"
1289
- }, /* @__PURE__ */ React3.createElement(DndContext, {
1511
+ }, /* @__PURE__ */ React4.createElement(DndContext, {
1290
1512
  autoScroll: {
1291
1513
  enabled: true
1292
1514
  },
@@ -1297,12 +1519,12 @@ var SheetColumns = /* @__PURE__ */ forwardRef(({ columns, sizes, selected, onSel
1297
1519
  ],
1298
1520
  onDragStart: handleDragStart,
1299
1521
  onDragEnd: handleDragEnd
1300
- }, /* @__PURE__ */ React3.createElement("div", {
1522
+ }, /* @__PURE__ */ React4.createElement("div", {
1301
1523
  className: "flex h-full",
1302
1524
  style: {
1303
1525
  height: axisHeight
1304
1526
  }
1305
- }, columns.map((idx, index) => /* @__PURE__ */ React3.createElement(GridColumnCell, {
1527
+ }, columns.map((idx, index) => /* @__PURE__ */ React4.createElement(GridColumnCell, {
1306
1528
  key: idx,
1307
1529
  idx,
1308
1530
  index,
@@ -1312,7 +1534,7 @@ var SheetColumns = /* @__PURE__ */ forwardRef(({ columns, sizes, selected, onSel
1312
1534
  selected: selected === index,
1313
1535
  onResize,
1314
1536
  onSelect
1315
- }))), /* @__PURE__ */ createPortal(/* @__PURE__ */ React3.createElement(DragOverlay, null, active && /* @__PURE__ */ React3.createElement(MovingOverlay, {
1537
+ }))), /* @__PURE__ */ createPortal(/* @__PURE__ */ React4.createElement(DragOverlay, null, active && /* @__PURE__ */ React4.createElement(MovingOverlay, {
1316
1538
  label: columnLetter(active.data.current.index)
1317
1539
  })), document.body))));
1318
1540
  });
@@ -1353,7 +1575,7 @@ var GridColumnCell = ({ idx, index, label, size, resize, selected, onSelect, onR
1353
1575
  onResize?.(idx, initialSize + width, true);
1354
1576
  setResizing(false);
1355
1577
  };
1356
- return /* @__PURE__ */ React3.createElement(Resizable, {
1578
+ return /* @__PURE__ */ React4.createElement(Resizable, {
1357
1579
  enable: {
1358
1580
  right: resize
1359
1581
  },
@@ -1365,17 +1587,17 @@ var GridColumnCell = ({ idx, index, label, size, resize, selected, onSelect, onR
1365
1587
  onResizeStart: handleResizeStart,
1366
1588
  onResize: handleResize,
1367
1589
  onResizeStop: handleResizeStop
1368
- }, /* @__PURE__ */ React3.createElement("div", {
1590
+ }, /* @__PURE__ */ React4.createElement("div", {
1369
1591
  ref: setNodeRef,
1370
1592
  ...attributes,
1371
1593
  ...listeners,
1372
- 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),
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),
1373
1595
  onClick: () => onSelect?.(index)
1374
- }, /* @__PURE__ */ React3.createElement("span", {
1596
+ }, /* @__PURE__ */ React4.createElement("span", {
1375
1597
  className: "flex w-full justify-center"
1376
- }, label), over?.id === idx && !isDragging && /* @__PURE__ */ React3.createElement("div", {
1598
+ }, label), over?.id === idx && !isDragging && /* @__PURE__ */ React4.createElement("div", {
1377
1599
  className: "z-20 absolute left-0 h-full min-w-[4px] border-l-4 border-accentSurface"
1378
- }), resizing && /* @__PURE__ */ React3.createElement("div", {
1600
+ }), resizing && /* @__PURE__ */ React4.createElement("div", {
1379
1601
  className: "z-20 absolute right-0 h-full min-h-[4px] border-l-4 border-accentSurface"
1380
1602
  })));
1381
1603
  };
@@ -1389,13 +1611,13 @@ var SheetGrid = /* @__PURE__ */ forwardRef(({ size, rows, columns, rowSizes, col
1389
1611
  const initialText = useRef();
1390
1612
  const quickEdit = useRef(false);
1391
1613
  const [, forceUpdate] = useState4({});
1392
- useEffect3(() => {
1614
+ useEffect4(() => {
1393
1615
  const unsubscribe = model.update.on(() => {
1394
1616
  log("updated", {
1395
1617
  id: model.id
1396
1618
  }, {
1397
1619
  F: __dxlog_file2,
1398
- L: 735,
1620
+ L: 737,
1399
1621
  S: void 0,
1400
1622
  C: (f, a) => f(...a)
1401
1623
  });
@@ -1512,19 +1734,19 @@ var SheetGrid = /* @__PURE__ */ forwardRef(({ size, rows, columns, rowSizes, col
1512
1734
  rowSizes,
1513
1735
  columnSizes
1514
1736
  });
1515
- const qualifiedSubjectId = fullyQualifiedId2(model.sheet);
1516
- const attendableAttrs = createAttendableAttributes(qualifiedSubjectId);
1517
- const attended = true;
1518
- return /* @__PURE__ */ React3.createElement("div", {
1737
+ const id = fullyQualifiedId3(model.sheet);
1738
+ const attendableAttrs = createAttendableAttributes(id);
1739
+ const hasAttention = useHasAttention(id);
1740
+ return /* @__PURE__ */ React4.createElement("div", {
1519
1741
  ref: containerRef,
1520
1742
  role: "grid",
1521
1743
  className: "relative flex grow overflow-hidden"
1522
- }, /* @__PURE__ */ React3.createElement("div", {
1523
- className: mx2("z-20 absolute inset-0 border pointer-events-none", fragments.border)
1524
- }), /* @__PURE__ */ React3.createElement("div", {
1744
+ }, /* @__PURE__ */ React4.createElement("div", {
1745
+ className: mx3("z-20 absolute inset-0 border border-gridLine pointer-events-none")
1746
+ }), /* @__PURE__ */ React4.createElement("div", {
1525
1747
  ref: scrollerRef,
1526
- className: mx2("grow", attended && "overflow-auto scrollbar-thin")
1527
- }, /* @__PURE__ */ React3.createElement("div", {
1748
+ className: mx3("grow", hasAttention && "overflow-auto scrollbar-thin")
1749
+ }, /* @__PURE__ */ React4.createElement("div", {
1528
1750
  className: "relative select-none",
1529
1751
  style: {
1530
1752
  width,
@@ -1532,7 +1754,7 @@ var SheetGrid = /* @__PURE__ */ forwardRef(({ size, rows, columns, rowSizes, col
1532
1754
  },
1533
1755
  onClick: () => inputRef.current?.focus(),
1534
1756
  ...handlers
1535
- }, scrollerRef.current && /* @__PURE__ */ React3.createElement(SelectionOverlay, {
1757
+ }, scrollerRef.current && /* @__PURE__ */ React4.createElement(SelectionOverlay, {
1536
1758
  root: scrollerRef.current
1537
1759
  }), rowRange.map(({ row, top, height: height2 }) => {
1538
1760
  return columnRange.map(({ column, left, width: width2 }) => {
@@ -1547,8 +1769,8 @@ var SheetGrid = /* @__PURE__ */ forwardRef(({ size, rows, columns, rowSizes, col
1547
1769
  row,
1548
1770
  column
1549
1771
  };
1550
- const id = addressToA1Notation(cell);
1551
- const idx = model.addressToIndex(cell);
1772
+ const id2 = addressToA1Notation(cell);
1773
+ const idx = addressToIndex(model.sheet, cell);
1552
1774
  const active = posEquals(cursor, cell);
1553
1775
  if (active && editing) {
1554
1776
  const value = initialText.current ?? model.getCellText(cell) ?? "";
@@ -1581,7 +1803,7 @@ var SheetGrid = /* @__PURE__ */ forwardRef(({ size, rows, columns, rowSizes, col
1581
1803
  inputRef.current?.focus();
1582
1804
  setEditing(false);
1583
1805
  };
1584
- return /* @__PURE__ */ React3.createElement(GridCellEditor, {
1806
+ return /* @__PURE__ */ React4.createElement(GridCellEditor, {
1585
1807
  key: idx,
1586
1808
  value,
1587
1809
  style,
@@ -1589,9 +1811,9 @@ var SheetGrid = /* @__PURE__ */ forwardRef(({ size, rows, columns, rowSizes, col
1589
1811
  onClose: handleClose
1590
1812
  });
1591
1813
  }
1592
- return /* @__PURE__ */ React3.createElement(SheetCell, {
1593
- key: id,
1594
- id,
1814
+ return /* @__PURE__ */ React4.createElement(SheetCell, {
1815
+ key: id2,
1816
+ id: id2,
1595
1817
  cell,
1596
1818
  active,
1597
1819
  style,
@@ -1601,7 +1823,7 @@ var SheetGrid = /* @__PURE__ */ forwardRef(({ size, rows, columns, rowSizes, col
1601
1823
  }
1602
1824
  });
1603
1825
  });
1604
- }))), /* @__PURE__ */ createPortal(/* @__PURE__ */ React3.createElement("input", {
1826
+ }))), /* @__PURE__ */ createPortal(/* @__PURE__ */ React4.createElement("input", {
1605
1827
  ref: inputRef,
1606
1828
  autoFocus: true,
1607
1829
  className: "absolute w-[1px] h-[1px] bg-transparent outline-none border-none caret-transparent",
@@ -1622,20 +1844,34 @@ var SelectionOverlay = ({ root }) => {
1622
1844
  const b1 = getRelativeClientRect(root, c1);
1623
1845
  const b2 = getRelativeClientRect(root, c2);
1624
1846
  const bounds = getRectUnion(b1, b2);
1625
- return /* @__PURE__ */ React3.createElement("div", {
1847
+ return /* @__PURE__ */ React4.createElement("div", {
1626
1848
  role: "none",
1627
1849
  style: bounds,
1628
1850
  className: "z-10 absolute pointer-events-none bg-gridSelectionOverlay border border-gridOverlay"
1629
1851
  });
1630
1852
  };
1631
1853
  var SheetCell = ({ id, cell, style, active, onSelect }) => {
1632
- const { formatting, editing, setRange } = useSheetContext();
1854
+ const { formatting, editing, setRange, decorations, model: { sheet } } = useSheetContext();
1633
1855
  const { value, classNames } = formatting.getFormatting(cell);
1634
- return /* @__PURE__ */ React3.createElement("div", {
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", {
1635
1871
  [`data-${CELL_DATA_KEY}`]: id,
1636
1872
  role: "cell",
1637
1873
  style,
1638
- className: mx2("flex w-full h-full truncate items-center border cursor-pointer", "px-2 py-1", fragments.cell, fragments.border, active && [
1874
+ className: mx3("border border-gridLine cursor-pointer", fragments.cell, active && [
1639
1875
  "z-20",
1640
1876
  fragments.cellSelected
1641
1877
  ], classNames),
@@ -1649,19 +1885,19 @@ var SheetCell = ({ id, cell, style, active, onSelect }) => {
1649
1885
  }
1650
1886
  },
1651
1887
  onDoubleClick: () => onSelect?.(cell, true)
1652
- }, value);
1888
+ }, decoratedContent);
1653
1889
  };
1654
1890
  var GridCellEditor = ({ style, value, onNav, onClose }) => {
1655
1891
  const { model, range } = useSheetContext();
1656
1892
  const notifier = useRef();
1657
- useEffect3(() => {
1893
+ useEffect4(() => {
1658
1894
  if (range) {
1659
1895
  notifier.current?.(rangeToA1Notation(range));
1660
1896
  }
1661
1897
  }, [
1662
1898
  range
1663
1899
  ]);
1664
- const extension = useMemo(() => [
1900
+ const extension = useMemo3(() => [
1665
1901
  editorKeys({
1666
1902
  onNav,
1667
1903
  onClose
@@ -1673,12 +1909,12 @@ var GridCellEditor = ({ style, value, onNav, onClose }) => {
1673
1909
  ], [
1674
1910
  model
1675
1911
  ]);
1676
- return /* @__PURE__ */ React3.createElement("div", {
1912
+ return /* @__PURE__ */ React4.createElement("div", {
1677
1913
  role: "cell",
1678
1914
  style,
1679
- className: mx2("z-20 flex", fragments.cellSelected),
1915
+ className: mx3("z-20 flex", fragments.cellSelected),
1680
1916
  onClick: (ev) => ev.stopPropagation()
1681
- }, /* @__PURE__ */ React3.createElement(CellEditor, {
1917
+ }, /* @__PURE__ */ React4.createElement(CellEditor, {
1682
1918
  autoFocus: true,
1683
1919
  value,
1684
1920
  extension
@@ -1697,24 +1933,24 @@ var SheetStatusBar = () => {
1697
1933
  value = String(value);
1698
1934
  }
1699
1935
  }
1700
- return /* @__PURE__ */ React3.createElement("div", {
1701
- className: mx2("flex shrink-0 justify-between items-center px-4 py-1 text-sm border-x", fragments.border)
1702
- }, /* @__PURE__ */ React3.createElement("div", {
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", {
1703
1939
  className: "flex gap-4 items-center"
1704
- }, /* @__PURE__ */ React3.createElement("div", {
1940
+ }, /* @__PURE__ */ React4.createElement("div", {
1705
1941
  className: "flex w-16 items-center font-mono"
1706
- }, range && rangeToA1Notation(range) || cursor && addressToA1Notation(cursor)), /* @__PURE__ */ React3.createElement("div", {
1942
+ }, range && rangeToA1Notation(range) || cursor && addressToA1Notation(cursor)), /* @__PURE__ */ React4.createElement("div", {
1707
1943
  className: "flex gap-2 items-center"
1708
- }, /* @__PURE__ */ React3.createElement(FunctionIcon, {
1709
- className: mx2("text-greenText", isFormula ? "visible" : "invisible")
1710
- }), /* @__PURE__ */ React3.createElement("span", {
1944
+ }, /* @__PURE__ */ React4.createElement(FunctionIcon, {
1945
+ className: mx3("text-greenText", isFormula ? "visible" : "invisible")
1946
+ }), /* @__PURE__ */ React4.createElement("span", {
1711
1947
  className: "font-mono"
1712
1948
  }, value))));
1713
1949
  };
1714
1950
  var SheetDebug = () => {
1715
1951
  const { model, cursor, range } = useSheetContext();
1716
1952
  const [, forceUpdate] = useState4({});
1717
- useEffect3(() => {
1953
+ useEffect4(() => {
1718
1954
  const accessor = createDocAccessor(model.sheet, []);
1719
1955
  const handleUpdate = () => forceUpdate({});
1720
1956
  accessor.handle.addListener("change", handleUpdate);
@@ -1725,9 +1961,9 @@ var SheetDebug = () => {
1725
1961
  }, [
1726
1962
  model
1727
1963
  ]);
1728
- return /* @__PURE__ */ React3.createElement("div", {
1729
- 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)
1730
- }, /* @__PURE__ */ React3.createElement("pre", {
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", {
1731
1967
  className: "whitespace-pre-wrap"
1732
1968
  }, JSON.stringify({
1733
1969
  cursor,
@@ -1749,22 +1985,247 @@ var Sheet = {
1749
1985
  Debug: SheetDebug
1750
1986
  };
1751
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
+
1752
2180
  // packages/plugins/plugin-sheet/src/components/SheetContainer.tsx
1753
- var SheetContainer = ({ sheet, space, role, coordinate = {
1754
- part: "main",
1755
- entryId: ""
1756
- }, remoteFunctionUrl }) => {
1757
- return /* @__PURE__ */ React4.createElement("div", {
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", {
1758
2205
  role: "none",
1759
- className: mx3("flex", role === "article" && "row-span-2", role === "section" && "aspect-square border-y border-is border-separator", coordinate.part !== "solo" && "border-is border-separator")
1760
- }, /* @__PURE__ */ React4.createElement(Sheet.Root, {
2206
+ className: role === "article" ? "row-span-2 grid grid-rows-subgrid" : void 0
2207
+ }, /* @__PURE__ */ React7.createElement(Sheet.Root, {
1761
2208
  sheet,
1762
2209
  space,
1763
2210
  remoteFunctionUrl
1764
- }, /* @__PURE__ */ React4.createElement(Sheet.Main, null)));
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))));
1765
2225
  };
1766
2226
  var SheetContainer_default = SheetContainer;
1767
2227
  export {
1768
- SheetContainer_default as default
2228
+ SheetContainer_default as default,
2229
+ sectionToolbarLayout
1769
2230
  };
1770
- //# sourceMappingURL=SheetContainer-4XOKHKKZ.mjs.map
2231
+ //# sourceMappingURL=SheetContainer-Y7ZMFBAP.mjs.map