@dxos/react-ui-editor 0.4.8-main.5f46a83 → 0.4.8-main.6d7437e

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 (46) hide show
  1. package/dist/lib/browser/index.mjs +907 -905
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +1 -1
  5. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
  6. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -1
  7. package/dist/types/src/extensions/automerge/automerge.stories.d.ts.map +1 -1
  8. package/dist/types/src/{hooks → extensions/awareness}/awareness-provider.d.ts +1 -1
  9. package/dist/types/src/extensions/awareness/awareness-provider.d.ts.map +1 -0
  10. package/dist/types/src/extensions/awareness/awareness.d.ts.map +1 -0
  11. package/dist/types/src/extensions/awareness/index.d.ts +3 -0
  12. package/dist/types/src/extensions/awareness/index.d.ts.map +1 -0
  13. package/dist/types/src/extensions/comments.d.ts +1 -1
  14. package/dist/types/src/extensions/comments.d.ts.map +1 -1
  15. package/dist/types/src/extensions/cursor.d.ts +1 -1
  16. package/dist/types/src/extensions/cursor.d.ts.map +1 -1
  17. package/dist/types/src/{hooks/extension-utils.d.ts → extensions/factories.d.ts} +2 -7
  18. package/dist/types/src/extensions/factories.d.ts.map +1 -0
  19. package/dist/types/src/extensions/index.d.ts +2 -0
  20. package/dist/types/src/extensions/index.d.ts.map +1 -1
  21. package/dist/types/src/{hooks/defs.d.ts → extensions/types.d.ts} +1 -1
  22. package/dist/types/src/extensions/types.d.ts.map +1 -0
  23. package/dist/types/src/hooks/index.d.ts +1 -3
  24. package/dist/types/src/hooks/index.d.ts.map +1 -1
  25. package/dist/types/src/hooks/useDocAccessor.d.ts +7 -0
  26. package/dist/types/src/hooks/useDocAccessor.d.ts.map +1 -0
  27. package/package.json +24 -24
  28. package/src/components/TextEditor/TextEditor.stories.tsx +5 -7
  29. package/src/components/Toolbar/Toolbar.stories.tsx +5 -9
  30. package/src/extensions/automerge/automerge.stories.tsx +2 -1
  31. package/src/{hooks → extensions/awareness}/awareness-provider.ts +1 -1
  32. package/src/extensions/{awareness.ts → awareness/awareness.ts} +1 -1
  33. package/src/extensions/awareness/index.ts +6 -0
  34. package/src/extensions/comments.ts +1 -1
  35. package/src/extensions/cursor.ts +1 -1
  36. package/src/{hooks/extension-utils.ts → extensions/factories.ts} +3 -18
  37. package/src/extensions/index.ts +2 -0
  38. package/src/{hooks/defs.ts → extensions/types.ts} +1 -0
  39. package/src/hooks/index.ts +1 -4
  40. package/src/hooks/useDocAccessor.ts +21 -0
  41. package/src/hooks/useTextEditor.stories.tsx +1 -1
  42. package/dist/types/src/extensions/awareness.d.ts.map +0 -1
  43. package/dist/types/src/hooks/awareness-provider.d.ts.map +0 -1
  44. package/dist/types/src/hooks/defs.d.ts.map +0 -1
  45. package/dist/types/src/hooks/extension-utils.d.ts.map +0 -1
  46. /package/dist/types/src/extensions/{awareness.d.ts → awareness/awareness.d.ts} +0 -0
@@ -29,12 +29,12 @@ import { TextKind } from "@dxos/protocols/proto/dxos/echo/model/text";
29
29
  import { Doc, YText, YXmlFragment } from "@dxos/text-model";
30
30
 
31
31
  // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
32
- import { EditorState } from "@codemirror/state";
33
- import { EditorView as EditorView15 } from "@codemirror/view";
32
+ import { EditorState as EditorState2 } from "@codemirror/state";
33
+ import { EditorView as EditorView16 } from "@codemirror/view";
34
34
  import { useFocusableGroup } from "@fluentui/react-tabster";
35
35
  import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useRef, useState as useState2 } from "react";
36
- import { log as log7 } from "@dxos/log";
37
- import { isNotFalsy as isNotFalsy2 } from "@dxos/util";
36
+ import { log as log9 } from "@dxos/log";
37
+ import { isNotFalsy as isNotFalsy3 } from "@dxos/util";
38
38
 
39
39
  // packages/ui/react-ui-editor/src/extensions/annotations.ts
40
40
  import { StateField } from "@codemirror/state";
@@ -492,7 +492,7 @@ var automerge = (accessor) => {
492
492
  ];
493
493
  };
494
494
 
495
- // packages/ui/react-ui-editor/src/extensions/awareness.ts
495
+ // packages/ui/react-ui-editor/src/extensions/awareness/awareness.ts
496
496
  import { Annotation as Annotation2, Facet as Facet2, RangeSet } from "@codemirror/state";
497
497
  import { Decoration as Decoration2, EditorView as EditorView3, ViewPlugin as ViewPlugin2, WidgetType } from "@codemirror/view";
498
498
  import { Event } from "@dxos/async";
@@ -727,11 +727,115 @@ var styles2 = EditorView3.baseTheme({
727
727
  }
728
728
  });
729
729
 
730
+ // packages/ui/react-ui-editor/src/extensions/awareness/awareness-provider.ts
731
+ import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
732
+ import { Context as Context2 } from "@dxos/context";
733
+ import { invariant } from "@dxos/invariant";
734
+ import { log as log2 } from "@dxos/log";
735
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/awareness/awareness-provider.ts";
736
+ var DEBOUNCE_INTERVAL = 100;
737
+ var SpaceAwarenessProvider = class {
738
+ constructor(params) {
739
+ this._remoteStates = /* @__PURE__ */ new Map();
740
+ this.remoteStateChange = new Event2();
741
+ this._space = params.space;
742
+ this._channel = params.channel;
743
+ this._peerId = params.peerId;
744
+ this._info = params.info;
745
+ }
746
+ open() {
747
+ this._ctx = new Context2();
748
+ this._postTask = new DeferredTask(this._ctx, async () => {
749
+ if (this._localState) {
750
+ await this._space.postMessage(this._channel, {
751
+ kind: "post",
752
+ state: this._localState
753
+ });
754
+ await sleep(DEBOUNCE_INTERVAL);
755
+ }
756
+ });
757
+ this._ctx.onDispose(this._space.listen(this._channel, (message) => {
758
+ switch (message.payload.kind) {
759
+ case "query": {
760
+ this._handleQueryMessage();
761
+ break;
762
+ }
763
+ case "post": {
764
+ this._handlePostMessage(message.payload);
765
+ break;
766
+ }
767
+ }
768
+ }));
769
+ void this._space.postMessage(this._channel, {
770
+ kind: "query"
771
+ }).catch((err) => {
772
+ log2.debug("failed to query awareness", {
773
+ err
774
+ }, {
775
+ F: __dxlog_file2,
776
+ L: 89,
777
+ S: this,
778
+ C: (f, a) => f(...a)
779
+ });
780
+ });
781
+ }
782
+ close() {
783
+ void this._ctx?.dispose();
784
+ this._ctx = void 0;
785
+ this._postTask = void 0;
786
+ }
787
+ getRemoteStates() {
788
+ return Array.from(this._remoteStates.values());
789
+ }
790
+ update(position) {
791
+ invariant(this._postTask, void 0, {
792
+ F: __dxlog_file2,
793
+ L: 104,
794
+ S: this,
795
+ A: [
796
+ "this._postTask",
797
+ ""
798
+ ]
799
+ });
800
+ this._localState = {
801
+ peerId: this._peerId,
802
+ position,
803
+ info: this._info
804
+ };
805
+ this._postTask.schedule();
806
+ }
807
+ _handleQueryMessage() {
808
+ invariant(this._postTask, void 0, {
809
+ F: __dxlog_file2,
810
+ L: 115,
811
+ S: this,
812
+ A: [
813
+ "this._postTask",
814
+ ""
815
+ ]
816
+ });
817
+ this._postTask.schedule();
818
+ }
819
+ _handlePostMessage(message) {
820
+ invariant(message.kind === "post", void 0, {
821
+ F: __dxlog_file2,
822
+ L: 120,
823
+ S: this,
824
+ A: [
825
+ "message.kind === 'post'",
826
+ ""
827
+ ]
828
+ });
829
+ this._remoteStates.set(message.state.peerId, message.state);
830
+ this.remoteStateChange.emit();
831
+ }
832
+ };
833
+
730
834
  // packages/ui/react-ui-editor/src/extensions/blast.ts
731
835
  import { EditorView as EditorView4, keymap as keymap2 } from "@codemirror/view";
732
836
  import defaultsDeep from "lodash.defaultsdeep";
733
- import { invariant } from "@dxos/invariant";
734
- var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
837
+ import { invariant as invariant2 } from "@dxos/invariant";
838
+ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
735
839
  var defaultOptions = {
736
840
  effect: 2,
737
841
  maxParticles: 200,
@@ -857,8 +961,8 @@ var Blaster = class {
857
961
  return this._node;
858
962
  }
859
963
  initialize() {
860
- invariant(!this._canvas && !this._ctx, void 0, {
861
- F: __dxlog_file2,
964
+ invariant2(!this._canvas && !this._ctx, void 0, {
965
+ F: __dxlog_file3,
862
966
  L: 141,
863
967
  S: this,
864
968
  A: [
@@ -894,8 +998,8 @@ var Blaster = class {
894
998
  }
895
999
  }
896
1000
  start() {
897
- invariant(this._canvas && this._ctx, void 0, {
898
- F: __dxlog_file2,
1001
+ invariant2(this._canvas && this._ctx, void 0, {
1002
+ F: __dxlog_file3,
899
1003
  L: 180,
900
1004
  S: this,
901
1005
  A: [
@@ -1261,7 +1365,7 @@ import { hoverTooltip, keymap as keymap4, Decoration as Decoration4, EditorView
1261
1365
  import sortBy from "lodash.sortby";
1262
1366
  import { useEffect } from "react";
1263
1367
  import { debounce } from "@dxos/async";
1264
- import { log as log3 } from "@dxos/log";
1368
+ import { log as log4 } from "@dxos/log";
1265
1369
  import { nonNullable } from "@dxos/util";
1266
1370
 
1267
1371
  // packages/ui/react-ui-editor/src/styles/markdown.ts
@@ -1299,14 +1403,14 @@ var editorFillLayoutRoot = "bs-full relative";
1299
1403
  var editorFillLayoutEditor = "!absolute inset-0";
1300
1404
 
1301
1405
  // packages/ui/react-ui-editor/src/util.ts
1302
- import { log as log2 } from "@dxos/log";
1303
- var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util.ts";
1406
+ import { log as log3 } from "@dxos/log";
1407
+ var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util.ts";
1304
1408
  var callbackWrapper = (fn) => (...args) => {
1305
1409
  try {
1306
1410
  return fn(...args);
1307
1411
  } catch (err) {
1308
- log2.catch(err, void 0, {
1309
- F: __dxlog_file3,
1412
+ log3.catch(err, void 0, {
1413
+ F: __dxlog_file4,
1310
1414
  L: 18,
1311
1415
  S: void 0,
1312
1416
  C: (f, a) => f(...a)
@@ -1329,10 +1433,10 @@ var logChanges = (trs) => {
1329
1433
  return changes2;
1330
1434
  }).filter(Boolean);
1331
1435
  if (changes.length) {
1332
- log2.info("changes", {
1436
+ log3.info("changes", {
1333
1437
  changes
1334
1438
  }, {
1335
- F: __dxlog_file3,
1439
+ F: __dxlog_file4,
1336
1440
  L: 39,
1337
1441
  S: void 0,
1338
1442
  C: (f, a) => f(...a)
@@ -1341,7 +1445,7 @@ var logChanges = (trs) => {
1341
1445
  };
1342
1446
 
1343
1447
  // packages/ui/react-ui-editor/src/extensions/comments.ts
1344
- var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/comments.ts";
1448
+ var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/comments.ts";
1345
1449
  var documentId = Facet4.define({
1346
1450
  combine: (values) => values[0]
1347
1451
  });
@@ -1427,8 +1531,8 @@ var commentsDecorations = EditorView7.decorations.compute([
1427
1531
  const decorations = sortBy(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
1428
1532
  const range = comment.range;
1429
1533
  if (!range || range.from === range.to) {
1430
- log3.warn("Invalid range:", range, {
1431
- F: __dxlog_file4,
1534
+ log4.warn("Invalid range:", range, {
1535
+ F: __dxlog_file5,
1432
1536
  L: 132,
1433
1537
  S: void 0,
1434
1538
  C: (f, a) => f(...a)
@@ -1749,8 +1853,8 @@ var useComments = (view, id, comments2 = []) => {
1749
1853
  // packages/ui/react-ui-editor/src/extensions/cursor-line-margin.ts
1750
1854
  import { Transaction } from "@codemirror/state";
1751
1855
  import { EditorView as EditorView8 } from "@codemirror/view";
1752
- import { log as log4 } from "@dxos/log";
1753
- var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/cursor-line-margin.ts";
1856
+ import { log as log5 } from "@dxos/log";
1857
+ var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/cursor-line-margin.ts";
1754
1858
  var annotation = "cursorLineMargin";
1755
1859
  var lineAtPos = (s, pos) => s.doc.lineAt(pos).number;
1756
1860
  var cursorLineMargin = (options = {
@@ -1777,8 +1881,8 @@ var cursorLineMargin = (options = {
1777
1881
  const needsScrollTop = false;
1778
1882
  const needsScrollBot = mainLine >= visBotLine - lines;
1779
1883
  if (needsScrollTop && needsScrollBot) {
1780
- log4.warn("is cursorScrollMargin too large for the editor size?", void 0, {
1781
- F: __dxlog_file5,
1884
+ log5.warn("is cursorScrollMargin too large for the editor size?", void 0, {
1885
+ F: __dxlog_file6,
1782
1886
  L: 65,
1783
1887
  S: void 0,
1784
1888
  C: (f, a) => f(...a)
@@ -1810,12 +1914,12 @@ var cursorLineMargin = (options = {
1810
1914
 
1811
1915
  // packages/ui/react-ui-editor/src/extensions/doc.ts
1812
1916
  import { Facet as Facet5 } from "@codemirror/state";
1813
- import { invariant as invariant2 } from "@dxos/invariant";
1814
- var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/doc.ts";
1917
+ import { invariant as invariant3 } from "@dxos/invariant";
1918
+ var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/doc.ts";
1815
1919
  var documentId2 = Facet5.define({
1816
1920
  combine: (providers) => {
1817
- invariant2(providers.length <= 1, void 0, {
1818
- F: __dxlog_file6,
1921
+ invariant3(providers.length <= 1, void 0, {
1922
+ F: __dxlog_file7,
1819
1923
  L: 11,
1820
1924
  S: void 0,
1821
1925
  A: [
@@ -1829,15 +1933,15 @@ var documentId2 = Facet5.define({
1829
1933
 
1830
1934
  // packages/ui/react-ui-editor/src/extensions/dnd.ts
1831
1935
  import { EditorView as EditorView9 } from "@codemirror/view";
1832
- import { log as log5 } from "@dxos/log";
1833
- var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/dnd.ts";
1936
+ import { log as log6 } from "@dxos/log";
1937
+ var __dxlog_file8 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/dnd.ts";
1834
1938
  var dnd = () => {
1835
1939
  return EditorView9.domEventHandlers({
1836
1940
  drop: (event, view) => {
1837
- log5.info("domEventHandlersDrop", {
1941
+ log6.info("domEventHandlersDrop", {
1838
1942
  event
1839
1943
  }, {
1840
- F: __dxlog_file7,
1944
+ F: __dxlog_file8,
1841
1945
  L: 14,
1842
1946
  S: void 0,
1843
1947
  C: (f, a) => f(...a)
@@ -1846,137 +1950,461 @@ var dnd = () => {
1846
1950
  });
1847
1951
  };
1848
1952
 
1849
- // packages/ui/react-ui-editor/src/extensions/listener.ts
1850
- import { EditorView as EditorView10 } from "@codemirror/view";
1851
- var listener = ({ onFocus, onChange }) => {
1852
- const extensions = [];
1853
- onFocus && extensions.push(EditorView10.focusChangeEffect.of((_, focusing) => {
1854
- onFocus(focusing);
1855
- return null;
1856
- }));
1857
- onChange && extensions.push(EditorView10.updateListener.of((update2) => {
1858
- onChange(update2.state.doc.toString());
1859
- }));
1860
- return extensions;
1861
- };
1862
-
1863
- // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
1864
- import { closeBracketsKeymap } from "@codemirror/autocomplete";
1865
- import { historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
1866
- import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
1867
- import { defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
1868
- import { languages } from "@codemirror/language-data";
1869
- import { searchKeymap } from "@codemirror/search";
1870
- import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
1871
- import { keymap as keymap5 } from "@codemirror/view";
1953
+ // packages/ui/react-ui-editor/src/extensions/factories.ts
1954
+ import { closeBrackets } from "@codemirror/autocomplete";
1955
+ import { history } from "@codemirror/commands";
1956
+ import { bracketMatching } from "@codemirror/language";
1957
+ import { EditorState } from "@codemirror/state";
1958
+ import { EditorView as EditorView10, crosshairCursor, drawSelection, dropCursor, highlightActiveLine, lineNumbers, placeholder, scrollPastEnd } from "@codemirror/view";
1959
+ import defaultsDeep2 from "lodash.defaultsdeep";
1960
+ import { generateName } from "@dxos/display-name";
1961
+ import { log as log7 } from "@dxos/log";
1962
+ import { hueTokens } from "@dxos/react-ui-theme";
1963
+ import { hexToHue, isNotFalsy as isNotFalsy2 } from "@dxos/util";
1872
1964
 
1873
- // packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
1874
- import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
1875
- import { HighlightStyle } from "@codemirror/language";
1876
- import { tags, styleTags, Tag } from "@lezer/highlight";
1877
- import { Table } from "@lezer/markdown";
1878
- var markdownTags = {
1879
- Blockquote: Tag.define(),
1880
- CodeMark: Tag.define(),
1881
- CodeText: Tag.define(),
1882
- EmphasisMark: Tag.define(),
1883
- HeaderMark: Tag.define(),
1884
- InlineCode: Tag.define(),
1885
- LinkLabel: Tag.define(),
1886
- LinkReference: Tag.define(),
1887
- ListMark: Tag.define(),
1888
- QuoteMark: Tag.define(),
1889
- URL: Tag.define(),
1890
- // Custom.
1891
- TableCell: Tag.define()
1892
- };
1893
- Table.defineNodes?.forEach((node) => {
1894
- switch (node?.name) {
1895
- case "TableCell": {
1896
- node.style = markdownTags.TableCell;
1897
- break;
1898
- }
1899
- }
1900
- });
1901
- var markdownTagsExtensions = [
1902
- Table,
1903
- {
1904
- props: [
1905
- styleTags(markdownTags)
1906
- ]
1907
- }
1908
- ];
1909
- var markdownHighlightStyle = (readonly) => {
1910
- return HighlightStyle.define([
1911
- {
1912
- tag: [
1913
- tags.keyword,
1914
- tags.name,
1915
- tags.deleted,
1916
- tags.character,
1917
- tags.propertyName,
1918
- tags.macroName,
1919
- tags.color,
1920
- tags.constant(tags.name),
1921
- tags.standard(tags.name),
1922
- tags.definition(tags.name),
1923
- tags.separator,
1924
- tags.typeName,
1925
- tags.className,
1926
- tags.number,
1927
- tags.changed,
1928
- tags.annotation,
1929
- tags.modifier,
1930
- tags.self,
1931
- tags.namespace,
1932
- tags.operator,
1933
- tags.operatorKeyword,
1934
- tags.escape,
1935
- tags.regexp,
1936
- tags.special(tags.string),
1937
- tags.meta,
1938
- tags.comment,
1939
- tags.atom,
1940
- tags.bool,
1941
- tags.special(tags.variableName),
1942
- tags.processingInstruction,
1943
- tags.string,
1944
- tags.inserted,
1945
- tags.invalid
1946
- ],
1947
- color: "inherit !important"
1948
- },
1949
- // Markdown marks.
1950
- {
1951
- tag: [
1952
- tags.meta,
1953
- tags.processingInstruction,
1954
- markdownTags.LinkLabel,
1955
- markdownTags.LinkReference,
1956
- markdownTags.ListMark
1957
- ],
1958
- class: mark
1959
- },
1960
- // Markdown marks.
1961
- {
1962
- tag: [
1963
- markdownTags.CodeMark,
1964
- markdownTags.HeaderMark,
1965
- markdownTags.QuoteMark,
1966
- markdownTags.EmphasisMark
1967
- ],
1968
- class: mark
1969
- },
1970
- // E.g., code block language (after ```).
1971
- {
1972
- tag: [
1973
- tags.function(tags.variableName),
1974
- tags.labelName
1975
- ],
1976
- class: codeMark
1977
- },
1978
- {
1979
- tag: [
1965
+ // packages/ui/react-ui-editor/src/themes/default.ts
1966
+ import get3 from "lodash.get";
1967
+ var defaultTheme = {
1968
+ //
1969
+ // Main layout:
1970
+ // https://codemirror.net/examples/styling
1971
+ //
1972
+ // <div class="cm-editor [cm-focused] [generated classes]">
1973
+ // <div class="cm-scroller">
1974
+ // <div class="cm-gutters">
1975
+ // <div class="cm-gutter [...]">
1976
+ // <div class="cm-gutterElement">...</div>
1977
+ // </div>
1978
+ // </div>
1979
+ // <div class="cm-content" role="textbox" contenteditable="true">
1980
+ // <div class="cm-line"></div>
1981
+ // </div>
1982
+ // <div class="cm-selectionLayer">
1983
+ // <div class="cm-selectionBackground"></div>
1984
+ // </div>
1985
+ // <div class="cm-cursorLayer">
1986
+ // <div class="cm-cursor"></div>
1987
+ // </div>
1988
+ // </div>
1989
+ // </div>
1990
+ //
1991
+ "&": {},
1992
+ "&.cm-focused": {
1993
+ outline: "none"
1994
+ },
1995
+ // NOTE: See https://codemirror.net/docs/guide (DOM Structure).
1996
+ ".cm-scroller": {
1997
+ // TODO(burdon): Reconcile with docs: https://codemirror.net/docs/guide
1998
+ // Inside of that is the scroller element. If the editor has its own scrollbar, this one should be styled with overflow: auto. But it doesn't have to—the editor also supports growing to accomodate its content, or growing up to a certain max-height and then scrolling.
1999
+ overflowY: "auto",
2000
+ fontFamily: get3(tokens, "fontFamily.body", []).join(","),
2001
+ lineHeight: 1.5
2002
+ },
2003
+ ".cm-content": {
2004
+ // TODO(burdon): Is it possible to remove the padding value from CM's default theme?
2005
+ // padding: 'unset',
2006
+ // NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
2007
+ fontSize: "16px"
2008
+ },
2009
+ "&light .cm-content": {
2010
+ color: get3(tokens, "extend.semanticColors.base.fg.light", "black"),
2011
+ caretColor: "black"
2012
+ },
2013
+ "&dark .cm-content": {
2014
+ color: get3(tokens, "extend.semanticColors.base.fg.dark", "white"),
2015
+ caretColor: "white"
2016
+ },
2017
+ //
2018
+ // Cursor
2019
+ //
2020
+ "&light .cm-cursor, &light .cm-dropCursor": {
2021
+ borderLeft: "2px solid black"
2022
+ },
2023
+ "&dark .cm-cursor, &dark .cm-dropCursor": {
2024
+ borderLeft: "2px solid white"
2025
+ },
2026
+ "&light .cm-placeholder": {
2027
+ color: get3(tokens, "extend.semanticColors.description.light", "rgba(0,0,0,.2)")
2028
+ },
2029
+ "&dark .cm-placeholder": {
2030
+ color: get3(tokens, "extend.semanticColors.description.dark", "rgba(255,255,255,.2)")
2031
+ },
2032
+ //
2033
+ // line
2034
+ //
2035
+ ".cm-line": {
2036
+ paddingInline: 0
2037
+ },
2038
+ ".cm-activeLine": {
2039
+ background: "transparent"
2040
+ },
2041
+ //
2042
+ // gutter
2043
+ //
2044
+ ".cm-gutterElement": {
2045
+ width: "48px"
2046
+ },
2047
+ //
2048
+ // Selection
2049
+ //
2050
+ "&light .cm-selectionBackground": {
2051
+ background: get3(tokens, "extend.colors.primary.100")
2052
+ },
2053
+ "&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
2054
+ background: get3(tokens, "extend.colors.primary.200")
2055
+ },
2056
+ "&dark .cm-selectionBackground": {
2057
+ background: get3(tokens, "extend.colors.primary.700")
2058
+ },
2059
+ "&dark.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
2060
+ background: get3(tokens, "extend.colors.primary.600")
2061
+ },
2062
+ //
2063
+ // Search
2064
+ //
2065
+ "&light .cm-searchMatch": {
2066
+ backgroundColor: get3(tokens, "extend.colors.yellow.100")
2067
+ },
2068
+ "&dark .cm-searchMatch": {
2069
+ backgroundColor: get3(tokens, "extend.colors.yellow.700")
2070
+ },
2071
+ //
2072
+ // link
2073
+ //
2074
+ ".cm-link": {
2075
+ color: get3(tokens, "extend.colors.primary.500"),
2076
+ textDecorationLine: "underline",
2077
+ textDecorationThickness: "1px",
2078
+ textUnderlineOffset: "2px",
2079
+ borderRadius: ".125rem",
2080
+ fontFamily: get3(tokens, "fontFamily.body", []).join(",")
2081
+ },
2082
+ //
2083
+ // tooltip
2084
+ //
2085
+ ".cm-tooltip": {
2086
+ border: "none",
2087
+ background: "unset"
2088
+ },
2089
+ ".cm-tooltip-below": {},
2090
+ //
2091
+ // autocomplete
2092
+ //
2093
+ ".cm-tooltip-autocomplete": {
2094
+ marginTop: "4px",
2095
+ marginLeft: "-3px"
2096
+ },
2097
+ ".cm-tooltip-autocomplete ul li": {},
2098
+ ".cm-tooltip-autocomplete ul li[aria-selected]": {},
2099
+ ".cm-completionIcon": {
2100
+ display: "none"
2101
+ },
2102
+ ".cm-completionLabel": {
2103
+ fontFamily: get3(tokens, "fontFamily.body", []).join(",")
2104
+ },
2105
+ ".cm-completionMatchedText": {
2106
+ textDecoration: "none"
2107
+ },
2108
+ //
2109
+ // table
2110
+ //
2111
+ ".cm-table *": {
2112
+ fontFamily: `${get3(tokens, "fontFamily.mono", []).join(",")} !important`,
2113
+ textDecoration: "none !important"
2114
+ },
2115
+ ".cm-table-head": {
2116
+ padding: "2px 16px 2px 0px",
2117
+ borderBottom: `1px solid ${get3(tokens, "extend.colors.neutral.500")}`,
2118
+ fontWeight: 100,
2119
+ textAlign: "left",
2120
+ color: get3(tokens, "extend.colors.neutral.500")
2121
+ },
2122
+ ".cm-table-cell": {
2123
+ padding: "2px 16px 2px 0px"
2124
+ },
2125
+ //
2126
+ // image
2127
+ //
2128
+ ".cm-image": {
2129
+ display: "block",
2130
+ height: "0"
2131
+ },
2132
+ ".cm-image.cm-loaded-image": {
2133
+ height: "auto",
2134
+ borderTop: "0.5rem solid transparent",
2135
+ borderBottom: "0.5rem solid transparent"
2136
+ },
2137
+ //
2138
+ // font size
2139
+ // TODO(thure): This appears to be the best or only way to set selection caret heights,
2140
+ // but it's far more verbose than it needs to be.
2141
+ //
2142
+ // ...Object.keys(get(tokens, 'extend.fontSize', {})).reduce((acc: Record<string, any>, fontSize) => {
2143
+ // const height = get(tokens, ['extend', 'fontSize', fontSize, 1, 'lineHeight']);
2144
+ //
2145
+ // acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = { height };
2146
+ // acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = { height };
2147
+ // acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = { height };
2148
+ // return acc;
2149
+ // }, {}),
2150
+ /**
2151
+ * Panels
2152
+ * TODO(burdon): Needs styling attention (esp. dark mode).
2153
+ * https://github.com/codemirror/search/blob/main/src/search.ts#L745
2154
+ *
2155
+ * Find/replace panel.
2156
+ * <div class="cm-announced">...</div>
2157
+ * <div class="cm-scroller">...</div>
2158
+ * <div class="cm-panels cm-panels-bottom">
2159
+ * <div class="cm-search cm-panel">
2160
+ * <input class="cm-textfield" />
2161
+ * <button class="cm-button">...</button>
2162
+ * <label><input type="checkbox" />...</label>
2163
+ * </div>
2164
+ * </div
2165
+ */
2166
+ ".cm-panels": {
2167
+ border: `1px solid ${get3(tokens, "extend.colors.neutral.200")}`
2168
+ },
2169
+ ".cm-panel": {
2170
+ background: get3(tokens, "extend.colors.neutral.50"),
2171
+ fontFamily: get3(tokens, "fontFamily.body", []).join(",")
2172
+ },
2173
+ ".cm-button": {
2174
+ margin: "4px",
2175
+ fontFamily: get3(tokens, "fontFamily.body", []).join(","),
2176
+ background: get3(tokens, "extend.colors.neutral.100"),
2177
+ backgroundImage: "none",
2178
+ border: "none",
2179
+ "&:hover": {
2180
+ background: get3(tokens, "extend.colors.neutral.200")
2181
+ },
2182
+ "&:active": {
2183
+ background: get3(tokens, "extend.colors.neutral.300"),
2184
+ backgroundImage: "none"
2185
+ }
2186
+ },
2187
+ ".cm-panel input[type=checkbox]": {
2188
+ marginRight: "0.4rem !important"
2189
+ }
2190
+ };
2191
+
2192
+ // packages/ui/react-ui-editor/src/extensions/factories.ts
2193
+ var __dxlog_file9 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/factories.ts";
2194
+ var defaults = {
2195
+ bracketMatching: true,
2196
+ closeBrackets: true,
2197
+ drawSelection: true,
2198
+ editable: true,
2199
+ history: true,
2200
+ lineWrapping: true
2201
+ };
2202
+ var createBasicExtensions = (_props) => {
2203
+ const props = defaultsDeep2({}, _props, defaults);
2204
+ return [
2205
+ // TODO(burdon): Doesn't catch errors in keymap functions.
2206
+ EditorView10.exceptionSink.of((err) => {
2207
+ log7.catch(err, void 0, {
2208
+ F: __dxlog_file9,
2209
+ L: 78,
2210
+ S: void 0,
2211
+ C: (f, a) => f(...a)
2212
+ });
2213
+ }),
2214
+ props.allowMultipleSelections && EditorState.allowMultipleSelections.of(true),
2215
+ props.bracketMatching && bracketMatching(),
2216
+ props.closeBrackets && closeBrackets(),
2217
+ props.crosshairCursor && crosshairCursor(),
2218
+ props.dropCursor && dropCursor(),
2219
+ props.drawSelection && drawSelection(),
2220
+ props.highlightActiveLine && highlightActiveLine(),
2221
+ props.history && history(),
2222
+ props.lineNumbers && lineNumbers(),
2223
+ props.lineWrapping && EditorView10.lineWrapping,
2224
+ props.placeholder && placeholder(props.placeholder),
2225
+ props.readonly && [
2226
+ EditorState.readOnly.of(true),
2227
+ EditorView10.editable.of(false)
2228
+ ],
2229
+ props.scrollPastEnd && scrollPastEnd(),
2230
+ props.tabSize && EditorState.tabSize.of(props.tabSize)
2231
+ ].filter(isNotFalsy2);
2232
+ };
2233
+ var defaultSlots = {
2234
+ editor: {
2235
+ className: "w-full bs-full"
2236
+ },
2237
+ content: {
2238
+ className: "!p-2"
2239
+ }
2240
+ };
2241
+ var createThemeExtensions = ({ theme, themeMode, slots: _slots } = {}) => {
2242
+ const slots = defaultsDeep2({}, _slots, defaultSlots);
2243
+ return [
2244
+ EditorView10.baseTheme(defaultTheme),
2245
+ EditorView10.darkTheme.of(themeMode === "dark"),
2246
+ theme && EditorView10.theme(theme),
2247
+ slots.editor?.className && EditorView10.editorAttributes.of({
2248
+ class: slots.editor.className
2249
+ }),
2250
+ slots.content?.className && EditorView10.contentAttributes.of({
2251
+ class: slots.content.className
2252
+ })
2253
+ ].filter(isNotFalsy2);
2254
+ };
2255
+ var createDataExtensions = ({ id, text, space, identity }) => {
2256
+ const extensions = [
2257
+ automerge(text)
2258
+ ];
2259
+ if (space && identity) {
2260
+ const peerId = identity?.identityKey.toHex();
2261
+ const { cursorLightValue, cursorDarkValue } = hueTokens[identity?.profile?.data?.hue ?? hexToHue(peerId ?? "0")];
2262
+ const awarenessProvider2 = new SpaceAwarenessProvider({
2263
+ space,
2264
+ channel: `awareness.${id}`,
2265
+ peerId: identity.identityKey.toHex(),
2266
+ info: {
2267
+ displayName: identity.profile?.displayName ?? generateName(identity.identityKey.toHex()),
2268
+ color: cursorDarkValue,
2269
+ lightColor: cursorLightValue
2270
+ }
2271
+ });
2272
+ extensions.push(awareness(awarenessProvider2));
2273
+ }
2274
+ return extensions;
2275
+ };
2276
+
2277
+ // packages/ui/react-ui-editor/src/extensions/listener.ts
2278
+ import { EditorView as EditorView11 } from "@codemirror/view";
2279
+ var listener = ({ onFocus, onChange }) => {
2280
+ const extensions = [];
2281
+ onFocus && extensions.push(EditorView11.focusChangeEffect.of((_, focusing) => {
2282
+ onFocus(focusing);
2283
+ return null;
2284
+ }));
2285
+ onChange && extensions.push(EditorView11.updateListener.of((update2) => {
2286
+ onChange(update2.state.doc.toString());
2287
+ }));
2288
+ return extensions;
2289
+ };
2290
+
2291
+ // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
2292
+ import { closeBracketsKeymap } from "@codemirror/autocomplete";
2293
+ import { historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
2294
+ import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
2295
+ import { defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
2296
+ import { languages } from "@codemirror/language-data";
2297
+ import { searchKeymap } from "@codemirror/search";
2298
+ import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
2299
+ import { keymap as keymap5 } from "@codemirror/view";
2300
+
2301
+ // packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
2302
+ import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
2303
+ import { HighlightStyle } from "@codemirror/language";
2304
+ import { tags, styleTags, Tag } from "@lezer/highlight";
2305
+ import { Table } from "@lezer/markdown";
2306
+ var markdownTags = {
2307
+ Blockquote: Tag.define(),
2308
+ CodeMark: Tag.define(),
2309
+ CodeText: Tag.define(),
2310
+ EmphasisMark: Tag.define(),
2311
+ HeaderMark: Tag.define(),
2312
+ InlineCode: Tag.define(),
2313
+ LinkLabel: Tag.define(),
2314
+ LinkReference: Tag.define(),
2315
+ ListMark: Tag.define(),
2316
+ QuoteMark: Tag.define(),
2317
+ URL: Tag.define(),
2318
+ // Custom.
2319
+ TableCell: Tag.define()
2320
+ };
2321
+ Table.defineNodes?.forEach((node) => {
2322
+ switch (node?.name) {
2323
+ case "TableCell": {
2324
+ node.style = markdownTags.TableCell;
2325
+ break;
2326
+ }
2327
+ }
2328
+ });
2329
+ var markdownTagsExtensions = [
2330
+ Table,
2331
+ {
2332
+ props: [
2333
+ styleTags(markdownTags)
2334
+ ]
2335
+ }
2336
+ ];
2337
+ var markdownHighlightStyle = (readonly) => {
2338
+ return HighlightStyle.define([
2339
+ {
2340
+ tag: [
2341
+ tags.keyword,
2342
+ tags.name,
2343
+ tags.deleted,
2344
+ tags.character,
2345
+ tags.propertyName,
2346
+ tags.macroName,
2347
+ tags.color,
2348
+ tags.constant(tags.name),
2349
+ tags.standard(tags.name),
2350
+ tags.definition(tags.name),
2351
+ tags.separator,
2352
+ tags.typeName,
2353
+ tags.className,
2354
+ tags.number,
2355
+ tags.changed,
2356
+ tags.annotation,
2357
+ tags.modifier,
2358
+ tags.self,
2359
+ tags.namespace,
2360
+ tags.operator,
2361
+ tags.operatorKeyword,
2362
+ tags.escape,
2363
+ tags.regexp,
2364
+ tags.special(tags.string),
2365
+ tags.meta,
2366
+ tags.comment,
2367
+ tags.atom,
2368
+ tags.bool,
2369
+ tags.special(tags.variableName),
2370
+ tags.processingInstruction,
2371
+ tags.string,
2372
+ tags.inserted,
2373
+ tags.invalid
2374
+ ],
2375
+ color: "inherit !important"
2376
+ },
2377
+ // Markdown marks.
2378
+ {
2379
+ tag: [
2380
+ tags.meta,
2381
+ tags.processingInstruction,
2382
+ markdownTags.LinkLabel,
2383
+ markdownTags.LinkReference,
2384
+ markdownTags.ListMark
2385
+ ],
2386
+ class: mark
2387
+ },
2388
+ // Markdown marks.
2389
+ {
2390
+ tag: [
2391
+ markdownTags.CodeMark,
2392
+ markdownTags.HeaderMark,
2393
+ markdownTags.QuoteMark,
2394
+ markdownTags.EmphasisMark
2395
+ ],
2396
+ class: mark
2397
+ },
2398
+ // E.g., code block language (after ```).
2399
+ {
2400
+ tag: [
2401
+ tags.function(tags.variableName),
2402
+ tags.labelName
2403
+ ],
2404
+ class: codeMark
2405
+ },
2406
+ {
2407
+ tag: [
1980
2408
  tags.monospace
1981
2409
  ],
1982
2410
  class: "font-mono"
@@ -2101,7 +2529,7 @@ var createMarkdownExtensions = ({ themeMode } = {}) => {
2101
2529
  // packages/ui/react-ui-editor/src/extensions/markdown/decorate.ts
2102
2530
  import { syntaxTree } from "@codemirror/language";
2103
2531
  import { RangeSetBuilder as RangeSetBuilder2, StateEffect as StateEffect4 } from "@codemirror/state";
2104
- import { EditorView as EditorView11, Decoration as Decoration5, WidgetType as WidgetType3, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
2532
+ import { EditorView as EditorView12, Decoration as Decoration5, WidgetType as WidgetType3, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
2105
2533
  import { mx as mx2 } from "@dxos/react-ui-theme";
2106
2534
  var HorizontalRuleWidget = class extends WidgetType3 {
2107
2535
  toDOM() {
@@ -2309,15 +2737,15 @@ var decorateMarkdown = (options = {}) => {
2309
2737
  }
2310
2738
  }, {
2311
2739
  provide: (plugin) => [
2312
- EditorView11.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration5.none),
2313
- EditorView11.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration5.none),
2314
- EditorView11.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration5.none)
2740
+ EditorView12.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration5.none),
2741
+ EditorView12.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration5.none),
2742
+ EditorView12.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration5.none)
2315
2743
  ]
2316
2744
  }),
2317
2745
  formattingStyles
2318
2746
  ];
2319
2747
  };
2320
- var formattingStyles = EditorView11.baseTheme({
2748
+ var formattingStyles = EditorView12.baseTheme({
2321
2749
  "& .cm-code": {
2322
2750
  fontFamily: getToken("fontFamily.mono", []).join(",")
2323
2751
  },
@@ -2370,7 +2798,7 @@ var formattingStyles = EditorView11.baseTheme({
2370
2798
  import { snippet } from "@codemirror/autocomplete";
2371
2799
  import { syntaxTree as syntaxTree2 } from "@codemirror/language";
2372
2800
  import { EditorSelection } from "@codemirror/state";
2373
- import { EditorView as EditorView12, keymap as keymap6 } from "@codemirror/view";
2801
+ import { EditorView as EditorView13, keymap as keymap6 } from "@codemirror/view";
2374
2802
  import { useState, useMemo } from "react";
2375
2803
  var compareFormatting = (a, b) => a.blockType === b.blockType && a.strong === b.strong && a.emphasis === b.emphasis && a.strikethrough === b.strikethrough && a.code === b.code && a.link === b.link && a.listStyle === b.listStyle && a.blockQuote === b.blockQuote;
2376
2804
  var Inline;
@@ -3440,7 +3868,7 @@ var getFormatting = (state) => {
3440
3868
  };
3441
3869
  var useFormattingState = () => {
3442
3870
  const [state, setState] = useState(null);
3443
- const observer = useMemo(() => EditorView12.updateListener.of((update2) => {
3871
+ const observer = useMemo(() => EditorView13.updateListener.of((update2) => {
3444
3872
  if (update2.docChanged || update2.selectionSet) {
3445
3873
  const newState = getFormatting(update2.state);
3446
3874
  if (!state || !compareFormatting(state, newState)) {
@@ -3457,7 +3885,7 @@ var useFormattingState = () => {
3457
3885
  // packages/ui/react-ui-editor/src/extensions/markdown/image.ts
3458
3886
  import { syntaxTree as syntaxTree3 } from "@codemirror/language";
3459
3887
  import { StateField as StateField5 } from "@codemirror/state";
3460
- import { Decoration as Decoration6, EditorView as EditorView13, WidgetType as WidgetType4 } from "@codemirror/view";
3888
+ import { Decoration as Decoration6, EditorView as EditorView14, WidgetType as WidgetType4 } from "@codemirror/view";
3461
3889
  var image = (options = {}) => {
3462
3890
  return StateField5.define({
3463
3891
  create: (state) => {
@@ -3484,7 +3912,7 @@ var image = (options = {}) => {
3484
3912
  add: buildDecorations2(from, to, tr.state)
3485
3913
  });
3486
3914
  },
3487
- provide: (field) => EditorView13.decorations.from(field)
3915
+ provide: (field) => EditorView14.decorations.from(field)
3488
3916
  });
3489
3917
  };
3490
3918
  var preloaded = /* @__PURE__ */ new Set();
@@ -3572,12 +4000,12 @@ var linkTooltip = (render) => hoverTooltip2((view, pos, side) => {
3572
4000
  // packages/ui/react-ui-editor/src/extensions/markdown/table.ts
3573
4001
  import { syntaxTree as syntaxTree5 } from "@codemirror/language";
3574
4002
  import { RangeSetBuilder as RangeSetBuilder3, StateField as StateField6 } from "@codemirror/state";
3575
- import { Decoration as Decoration7, EditorView as EditorView14, WidgetType as WidgetType5 } from "@codemirror/view";
4003
+ import { Decoration as Decoration7, EditorView as EditorView15, WidgetType as WidgetType5 } from "@codemirror/view";
3576
4004
  var table = (options = {}) => {
3577
4005
  return StateField6.define({
3578
4006
  create: (state) => update(state, options),
3579
4007
  update: (_, tr) => update(tr.state, options),
3580
- provide: (field) => EditorView14.decorations.from(field)
4008
+ provide: (field) => EditorView15.decorations.from(field)
3581
4009
  });
3582
4010
  };
3583
4011
  var update = (state, options) => {
@@ -3671,8 +4099,8 @@ var TableWidget = class extends WidgetType5 {
3671
4099
 
3672
4100
  // packages/ui/react-ui-editor/src/extensions/mention.ts
3673
4101
  import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
3674
- import { log as log6 } from "@dxos/log";
3675
- var __dxlog_file8 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/mention.ts";
4102
+ import { log as log8 } from "@dxos/log";
4103
+ var __dxlog_file10 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/mention.ts";
3676
4104
  var mention = ({ onSearch }) => {
3677
4105
  return autocompletion2({
3678
4106
  // TODO(burdon): Not working.
@@ -3684,10 +4112,10 @@ var mention = ({ onSearch }) => {
3684
4112
  icons: false,
3685
4113
  override: [
3686
4114
  (context) => {
3687
- log6.info("completion context", {
4115
+ log8.info("completion context", {
3688
4116
  context
3689
4117
  }, {
3690
- F: __dxlog_file8,
4118
+ F: __dxlog_file10,
3691
4119
  L: 26,
3692
4120
  S: void 0,
3693
4121
  C: (f, a) => f(...a)
@@ -3794,9 +4222,9 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
3794
4222
  };
3795
4223
 
3796
4224
  // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
3797
- var __dxlog_file9 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
4225
+ var __dxlog_file11 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
3798
4226
  var instanceCount = 0;
3799
- var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, className, autoFocus, scrollTo = EditorView15.scrollIntoView(0), moveToEndOfLine, debug, dataTestId }, forwardedRef) => {
4227
+ var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, className, autoFocus, scrollTo = EditorView16.scrollIntoView(0), moveToEndOfLine, debug, dataTestId }, forwardedRef) => {
3800
4228
  const [instanceId] = useState2(() => `text-editor-${++instanceCount}`);
3801
4229
  const tabsterDOMAttribute = useFocusableGroup({
3802
4230
  tabBehavior: "limited"
@@ -3815,31 +4243,31 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, c
3815
4243
  autoFocus
3816
4244
  ]);
3817
4245
  useEffect2(() => {
3818
- log7("updating", {
4246
+ log9("updating", {
3819
4247
  id,
3820
4248
  instanceId
3821
4249
  }, {
3822
- F: __dxlog_file9,
4250
+ F: __dxlog_file11,
3823
4251
  L: 88,
3824
4252
  S: void 0,
3825
4253
  C: (f, a) => f(...a)
3826
4254
  });
3827
- const state = EditorState.create({
4255
+ const state = EditorState2.create({
3828
4256
  doc,
3829
4257
  selection,
3830
4258
  extensions: [
3831
4259
  id && documentId2.of(id),
3832
4260
  // TODO(burdon): NOTE: Doesn't catch errors in keymap functions.
3833
- EditorView15.exceptionSink.of((err) => {
3834
- log7.catch(err, void 0, {
3835
- F: __dxlog_file9,
4261
+ EditorView16.exceptionSink.of((err) => {
4262
+ log9.catch(err, void 0, {
4263
+ F: __dxlog_file11,
3836
4264
  L: 101,
3837
4265
  S: void 0,
3838
4266
  C: (f, a) => f(...a)
3839
4267
  });
3840
4268
  }),
3841
4269
  // Focus.
3842
- EditorView15.updateListener.of((update2) => {
4270
+ EditorView16.updateListener.of((update2) => {
3843
4271
  update2.transactions.forEach((transaction) => {
3844
4272
  if (transaction.isUserEvent("focus.container")) {
3845
4273
  rootRef.current?.focus();
@@ -3847,9 +4275,9 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, c
3847
4275
  });
3848
4276
  }),
3849
4277
  extensions
3850
- ].filter(isNotFalsy2)
4278
+ ].filter(isNotFalsy3)
3851
4279
  });
3852
- const view2 = new EditorView15({
4280
+ const view2 = new EditorView16({
3853
4281
  state,
3854
4282
  parent: rootRef.current,
3855
4283
  scrollTo,
@@ -3869,746 +4297,307 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, c
3869
4297
  selection: {
3870
4298
  anchor: to
3871
4299
  }
3872
- });
3873
- }
3874
- if (state.facet(editorMode).noTabster) {
3875
- rootRef.current?.removeAttribute("data-tabster");
3876
- }
3877
- return () => {
3878
- view2?.destroy();
3879
- setView(null);
3880
- };
3881
- }, [
3882
- doc,
3883
- selection,
3884
- extensions
3885
- ]);
3886
- const handleKeyUp = useCallback((event) => {
3887
- const { key } = event;
3888
- switch (key) {
3889
- case "Enter": {
3890
- view?.focus();
3891
- break;
3892
- }
3893
- }
3894
- }, [
3895
- view
3896
- ]);
3897
- return /* @__PURE__ */ React.createElement("div", {
3898
- role: "none",
3899
- ref: rootRef,
3900
- tabIndex: 0,
3901
- className,
3902
- "data-testid": dataTestId,
3903
- ...tabsterDOMAttribute,
3904
- onKeyUp: handleKeyUp
3905
- });
3906
- });
3907
-
3908
- // packages/ui/react-ui-editor/src/components/Toolbar/Toolbar.tsx
3909
- import { ChatText, Code, CodeBlock, Link, ListBullets, ListChecks, ListNumbers, Paragraph, TextStrikethrough, Table as Table2, TextB, TextHOne, TextHTwo, TextHThree, TextHFour, TextHFive, TextHSix, TextItalic, Quotes } from "@phosphor-icons/react";
3910
- import { createContext } from "@radix-ui/react-context";
3911
- import React2, { useRef as useRef2, useState as useState3 } from "react";
3912
- import { DensityProvider, ElevationProvider, Select, Toolbar as NaturalToolbar, Tooltip, useTranslation } from "@dxos/react-ui";
3913
- import { getSize } from "@dxos/react-ui-theme";
3914
- var tooltipProps = {
3915
- side: "top",
3916
- classNames: "z-10"
3917
- };
3918
- var HeadingIcons = {
3919
- "0": Paragraph,
3920
- "1": TextHOne,
3921
- "2": TextHTwo,
3922
- "3": TextHThree,
3923
- "4": TextHFour,
3924
- "5": TextHFive,
3925
- "6": TextHSix
3926
- };
3927
- var [ToolbarContextProvider, useToolbarContext] = createContext("Toolbar");
3928
- var ToolbarRoot = ({ children, onAction, classNames, state }) => {
3929
- return /* @__PURE__ */ React2.createElement(ToolbarContextProvider, {
3930
- onAction,
3931
- state
3932
- }, /* @__PURE__ */ React2.createElement(DensityProvider, {
3933
- density: "fine"
3934
- }, /* @__PURE__ */ React2.createElement(ElevationProvider, {
3935
- elevation: "chrome"
3936
- }, /* @__PURE__ */ React2.createElement(NaturalToolbar.Root, {
3937
- classNames: [
3938
- "is-full shrink-0 overflow-x-auto p-1",
3939
- classNames
3940
- ]
3941
- }, children))));
3942
- };
3943
- var buttonStyles = "min-bs-0 p-2";
3944
- var iconStyles = getSize(5);
3945
- var ToolbarButton = ({ Icon, children, ...props }) => {
3946
- return /* @__PURE__ */ React2.createElement(Tooltip.Root, null, /* @__PURE__ */ React2.createElement(Tooltip.Trigger, {
3947
- asChild: true
3948
- }, /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroupItem, {
3949
- variant: "ghost",
3950
- ...props,
3951
- classNames: buttonStyles
3952
- }, /* @__PURE__ */ React2.createElement(Icon, {
3953
- className: iconStyles
3954
- }), /* @__PURE__ */ React2.createElement("span", {
3955
- className: "sr-only"
3956
- }, children))), /* @__PURE__ */ React2.createElement(Tooltip.Portal, null, /* @__PURE__ */ React2.createElement(Tooltip.Content, tooltipProps, children, /* @__PURE__ */ React2.createElement(Tooltip.Arrow, null))));
3957
- };
3958
- var ToolbarSeparator = () => /* @__PURE__ */ React2.createElement("div", {
3959
- role: "separator",
3960
- className: "grow"
3961
- });
3962
- var MarkdownHeading = () => {
3963
- const { t } = useTranslation(translationKey);
3964
- const { onAction, state } = useToolbarContext("MarkdownFormatting");
3965
- const blockType = state ? state.blockType : "paragraph";
3966
- const header = blockType && /heading(\d)/.exec(blockType);
3967
- const value = header ? header[1] : blockType === "paragraph" || !blockType ? "0" : void 0;
3968
- const HeadingIcon = HeadingIcons[value ?? "0"];
3969
- const suppressNextTooltip = useRef2(false);
3970
- const [tooltipOpen, setTooltipOpen] = useState3(false);
3971
- const [selectOpen, setSelectOpen] = useState3(false);
3972
- return /* @__PURE__ */ React2.createElement(Tooltip.Root, {
3973
- open: tooltipOpen,
3974
- onOpenChange: (nextOpen) => {
3975
- if (nextOpen && suppressNextTooltip.current) {
3976
- suppressNextTooltip.current = false;
3977
- return setTooltipOpen(false);
3978
- } else {
3979
- return setTooltipOpen(nextOpen);
3980
- }
3981
- }
3982
- }, /* @__PURE__ */ React2.createElement(Select.Root, {
3983
- disabled: value === null,
3984
- value: value ?? "0",
3985
- open: selectOpen,
3986
- onOpenChange: (nextOpen) => {
3987
- if (!nextOpen) {
3988
- suppressNextTooltip.current = true;
3989
- }
3990
- return setSelectOpen(nextOpen);
3991
- },
3992
- onValueChange: (value2) => onAction?.({
3993
- type: "heading",
3994
- data: parseInt(value2)
3995
- })
3996
- }, /* @__PURE__ */ React2.createElement(Tooltip.Trigger, {
3997
- asChild: true
3998
- }, /* @__PURE__ */ React2.createElement(NaturalToolbar.Button, {
3999
- asChild: true
4000
- }, /* @__PURE__ */ React2.createElement(Select.TriggerButton, {
4001
- variant: "ghost",
4002
- classNames: buttonStyles
4003
- }, /* @__PURE__ */ React2.createElement("span", {
4004
- className: "sr-only"
4005
- }, t("heading label")), /* @__PURE__ */ React2.createElement(HeadingIcon, {
4006
- className: iconStyles
4007
- })))), /* @__PURE__ */ React2.createElement(Select.Portal, null, /* @__PURE__ */ React2.createElement(Select.Content, null, /* @__PURE__ */ React2.createElement(Select.ScrollUpButton, null), /* @__PURE__ */ React2.createElement(Select.Viewport, null, /* @__PURE__ */ React2.createElement(Select.Option, {
4008
- value: "0"
4009
- }, /* @__PURE__ */ React2.createElement(Paragraph, {
4010
- className: iconStyles
4011
- })), [
4012
- 1,
4013
- 2,
4014
- 3,
4015
- 4,
4016
- 5,
4017
- 6
4018
- ].map((level) => /* @__PURE__ */ React2.createElement(Select.Option, {
4019
- key: level,
4020
- value: String(level)
4021
- }, level === 1 && /* @__PURE__ */ React2.createElement(TextHOne, {
4022
- className: iconStyles
4023
- }), level === 2 && /* @__PURE__ */ React2.createElement(TextHTwo, {
4024
- className: iconStyles
4025
- }), level === 3 && /* @__PURE__ */ React2.createElement(TextHThree, {
4026
- className: iconStyles
4027
- }), level === 4 && /* @__PURE__ */ React2.createElement(TextHFour, {
4028
- className: iconStyles
4029
- }), level === 5 && /* @__PURE__ */ React2.createElement(TextHFive, {
4030
- className: iconStyles
4031
- }), level === 6 && /* @__PURE__ */ React2.createElement(TextHSix, {
4032
- className: iconStyles
4033
- })))), /* @__PURE__ */ React2.createElement(Select.ScrollDownButton, null), /* @__PURE__ */ React2.createElement(Select.Arrow, null)))), /* @__PURE__ */ React2.createElement(Tooltip.Portal, null, /* @__PURE__ */ React2.createElement(Tooltip.Content, tooltipProps, t("heading label"), /* @__PURE__ */ React2.createElement(Tooltip.Arrow, null))));
4034
- };
4035
- var markdownStyles = [
4036
- {
4037
- type: "strong",
4038
- Icon: TextB,
4039
- getState: (state) => state.strong
4040
- },
4041
- {
4042
- type: "emphasis",
4043
- Icon: TextItalic,
4044
- getState: (state) => state.emphasis
4045
- },
4046
- {
4047
- type: "strikethrough",
4048
- Icon: TextStrikethrough,
4049
- getState: (state) => state.strikethrough
4050
- },
4051
- {
4052
- type: "code",
4053
- Icon: Code,
4054
- getState: (state) => state.code
4055
- },
4056
- {
4057
- type: "link",
4058
- Icon: Link,
4059
- getState: (state) => state.link
4060
- }
4061
- ];
4062
- var MarkdownStyles = () => {
4063
- const { onAction, state } = useToolbarContext("MarkdownStyles");
4064
- const { t } = useTranslation(translationKey);
4065
- return /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroup, {
4066
- type: "multiple",
4067
- value: markdownStyles.filter(({ getState }) => state && getState(state)).map(({ type }) => type)
4068
- }, markdownStyles.map(({ type, getState, Icon }) => /* @__PURE__ */ React2.createElement(ToolbarButton, {
4069
- key: type,
4070
- value: type,
4071
- Icon,
4072
- disabled: state?.blockType === "codeblock",
4073
- onClick: state ? () => onAction?.({
4074
- type,
4075
- data: !getState(state)
4076
- }) : void 0
4077
- }, t(`${type} label`))));
4300
+ });
4301
+ }
4302
+ if (state.facet(editorMode).noTabster) {
4303
+ rootRef.current?.removeAttribute("data-tabster");
4304
+ }
4305
+ return () => {
4306
+ view2?.destroy();
4307
+ setView(null);
4308
+ };
4309
+ }, [
4310
+ doc,
4311
+ selection,
4312
+ extensions
4313
+ ]);
4314
+ const handleKeyUp = useCallback((event) => {
4315
+ const { key } = event;
4316
+ switch (key) {
4317
+ case "Enter": {
4318
+ view?.focus();
4319
+ break;
4320
+ }
4321
+ }
4322
+ }, [
4323
+ view
4324
+ ]);
4325
+ return /* @__PURE__ */ React.createElement("div", {
4326
+ role: "none",
4327
+ ref: rootRef,
4328
+ tabIndex: 0,
4329
+ className,
4330
+ "data-testid": dataTestId,
4331
+ ...tabsterDOMAttribute,
4332
+ onKeyUp: handleKeyUp
4333
+ });
4334
+ });
4335
+
4336
+ // packages/ui/react-ui-editor/src/components/Toolbar/Toolbar.tsx
4337
+ import { ChatText, Code, CodeBlock, Link, ListBullets, ListChecks, ListNumbers, Paragraph, TextStrikethrough, Table as Table2, TextB, TextHOne, TextHTwo, TextHThree, TextHFour, TextHFive, TextHSix, TextItalic, Quotes } from "@phosphor-icons/react";
4338
+ import { createContext } from "@radix-ui/react-context";
4339
+ import React2, { useRef as useRef2, useState as useState3 } from "react";
4340
+ import { DensityProvider, ElevationProvider, Select, Toolbar as NaturalToolbar, Tooltip, useTranslation } from "@dxos/react-ui";
4341
+ import { getSize } from "@dxos/react-ui-theme";
4342
+ var tooltipProps = {
4343
+ side: "top",
4344
+ classNames: "z-10"
4078
4345
  };
4079
- var markdownLists = [
4080
- {
4081
- type: "list-bullet",
4082
- Icon: ListBullets,
4083
- getState: (state) => state.listStyle === "bullet"
4084
- },
4085
- {
4086
- type: "list-ordered",
4087
- Icon: ListNumbers,
4088
- getState: (state) => state.listStyle === "ordered"
4089
- },
4090
- {
4091
- type: "list-task",
4092
- Icon: ListChecks,
4093
- getState: (state) => state.listStyle === "task"
4094
- }
4095
- ];
4096
- var MarkdownLists = () => {
4097
- const { onAction, state } = useToolbarContext("MarkdownStyles");
4098
- const { t } = useTranslation(translationKey);
4099
- return /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroup, {
4100
- type: "single",
4101
- value: state?.listStyle ? `list-${state.listStyle}` : ""
4102
- }, markdownLists.map(({ type, getState, Icon }) => /* @__PURE__ */ React2.createElement(ToolbarButton, {
4103
- key: type,
4104
- value: type,
4105
- Icon,
4106
- onClick: state ? () => onAction?.({
4107
- type,
4108
- data: !getState(state)
4109
- }) : void 0
4110
- }, t(`${type} label`))));
4346
+ var HeadingIcons = {
4347
+ "0": Paragraph,
4348
+ "1": TextHOne,
4349
+ "2": TextHTwo,
4350
+ "3": TextHThree,
4351
+ "4": TextHFour,
4352
+ "5": TextHFive,
4353
+ "6": TextHSix
4111
4354
  };
4112
- var markdownBlocks = [
4113
- {
4114
- type: "blockquote",
4115
- Icon: Quotes,
4116
- getState: (state) => state.blockQuote
4117
- },
4118
- {
4119
- type: "codeblock",
4120
- Icon: CodeBlock,
4121
- getState: (state) => state.blockType === "codeblock"
4122
- },
4123
- {
4124
- type: "table",
4125
- Icon: Table2,
4126
- getState: (state) => state.blockType === "tablecell",
4127
- disabled: (state) => !state.blankLine
4128
- }
4129
- ];
4130
- var MarkdownBlocks = () => {
4131
- const { onAction, state } = useToolbarContext("MarkdownStyles");
4132
- const { t } = useTranslation(translationKey);
4133
- const value = markdownBlocks.find(({ getState }) => state && getState(state));
4134
- return /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroup, {
4135
- type: "single",
4136
- value: value?.type ?? ""
4137
- }, markdownBlocks.map(({ type, disabled, getState, Icon }) => /* @__PURE__ */ React2.createElement(ToolbarButton, {
4138
- key: type,
4139
- value: type,
4140
- Icon,
4141
- disabled: !state || disabled?.(state),
4142
- onClick: state ? () => onAction?.({
4143
- type,
4144
- data: !getState(state)
4145
- }) : void 0
4146
- }, t(`${type} label`))));
4355
+ var [ToolbarContextProvider, useToolbarContext] = createContext("Toolbar");
4356
+ var ToolbarRoot = ({ children, onAction, classNames, state }) => {
4357
+ return /* @__PURE__ */ React2.createElement(ToolbarContextProvider, {
4358
+ onAction,
4359
+ state
4360
+ }, /* @__PURE__ */ React2.createElement(DensityProvider, {
4361
+ density: "fine"
4362
+ }, /* @__PURE__ */ React2.createElement(ElevationProvider, {
4363
+ elevation: "chrome"
4364
+ }, /* @__PURE__ */ React2.createElement(NaturalToolbar.Root, {
4365
+ classNames: [
4366
+ "is-full shrink-0 overflow-x-auto p-1",
4367
+ classNames
4368
+ ]
4369
+ }, children))));
4147
4370
  };
4148
- var MarkdownStandard = () => /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(MarkdownHeading, null), /* @__PURE__ */ React2.createElement(MarkdownStyles, null), /* @__PURE__ */ React2.createElement(MarkdownLists, null), /* @__PURE__ */ React2.createElement(MarkdownBlocks, null));
4149
- var MarkdownExtended = () => {
4150
- const { onAction } = useToolbarContext("MarkdownStyles");
4151
- const { t } = useTranslation(translationKey);
4371
+ var buttonStyles = "min-bs-0 p-2";
4372
+ var iconStyles = getSize(5);
4373
+ var ToolbarButton = ({ Icon, children, ...props }) => {
4152
4374
  return /* @__PURE__ */ React2.createElement(Tooltip.Root, null, /* @__PURE__ */ React2.createElement(Tooltip.Trigger, {
4153
4375
  asChild: true
4154
- }, /* @__PURE__ */ React2.createElement(NaturalToolbar.Button, {
4376
+ }, /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroupItem, {
4155
4377
  variant: "ghost",
4156
- "data-testid": "editor.toolbar.comment",
4157
- onClick: () => onAction?.({
4158
- type: "comment"
4159
- }),
4378
+ ...props,
4160
4379
  classNames: buttonStyles
4161
- }, /* @__PURE__ */ React2.createElement(ChatText, {
4380
+ }, /* @__PURE__ */ React2.createElement(Icon, {
4162
4381
  className: iconStyles
4163
4382
  }), /* @__PURE__ */ React2.createElement("span", {
4164
4383
  className: "sr-only"
4165
- }, t("comment label")))), /* @__PURE__ */ React2.createElement(Tooltip.Portal, null, /* @__PURE__ */ React2.createElement(Tooltip.Content, tooltipProps, t("comment label"), /* @__PURE__ */ React2.createElement(Tooltip.Arrow, null))));
4166
- };
4167
- var Toolbar = {
4168
- Root: ToolbarRoot,
4169
- Button: ToolbarButton,
4170
- Separator: ToolbarSeparator,
4171
- Markdown: MarkdownStandard,
4172
- Extended: MarkdownExtended
4384
+ }, children))), /* @__PURE__ */ React2.createElement(Tooltip.Portal, null, /* @__PURE__ */ React2.createElement(Tooltip.Content, tooltipProps, children, /* @__PURE__ */ React2.createElement(Tooltip.Arrow, null))));
4173
4385
  };
4174
-
4175
- // packages/ui/react-ui-editor/src/hooks/awareness-provider.ts
4176
- import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
4177
- import { Context as Context2 } from "@dxos/context";
4178
- import { invariant as invariant3 } from "@dxos/invariant";
4179
- import { log as log8 } from "@dxos/log";
4180
- var __dxlog_file10 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
4181
- var DEBOUNCE_INTERVAL = 100;
4182
- var SpaceAwarenessProvider = class {
4183
- constructor(params) {
4184
- this._remoteStates = /* @__PURE__ */ new Map();
4185
- this.remoteStateChange = new Event2();
4186
- this._space = params.space;
4187
- this._channel = params.channel;
4188
- this._peerId = params.peerId;
4189
- this._info = params.info;
4190
- }
4191
- open() {
4192
- this._ctx = new Context2();
4193
- this._postTask = new DeferredTask(this._ctx, async () => {
4194
- if (this._localState) {
4195
- await this._space.postMessage(this._channel, {
4196
- kind: "post",
4197
- state: this._localState
4198
- });
4199
- await sleep(DEBOUNCE_INTERVAL);
4200
- }
4201
- });
4202
- this._ctx.onDispose(this._space.listen(this._channel, (message) => {
4203
- switch (message.payload.kind) {
4204
- case "query": {
4205
- this._handleQueryMessage();
4206
- break;
4207
- }
4208
- case "post": {
4209
- this._handlePostMessage(message.payload);
4210
- break;
4211
- }
4212
- }
4213
- }));
4214
- void this._space.postMessage(this._channel, {
4215
- kind: "query"
4216
- }).catch((err) => {
4217
- log8.debug("failed to query awareness", {
4218
- err
4219
- }, {
4220
- F: __dxlog_file10,
4221
- L: 89,
4222
- S: this,
4223
- C: (f, a) => f(...a)
4224
- });
4225
- });
4226
- }
4227
- close() {
4228
- void this._ctx?.dispose();
4229
- this._ctx = void 0;
4230
- this._postTask = void 0;
4231
- }
4232
- getRemoteStates() {
4233
- return Array.from(this._remoteStates.values());
4234
- }
4235
- update(position) {
4236
- invariant3(this._postTask, void 0, {
4237
- F: __dxlog_file10,
4238
- L: 104,
4239
- S: this,
4240
- A: [
4241
- "this._postTask",
4242
- ""
4243
- ]
4244
- });
4245
- this._localState = {
4246
- peerId: this._peerId,
4247
- position,
4248
- info: this._info
4249
- };
4250
- this._postTask.schedule();
4251
- }
4252
- _handleQueryMessage() {
4253
- invariant3(this._postTask, void 0, {
4254
- F: __dxlog_file10,
4255
- L: 115,
4256
- S: this,
4257
- A: [
4258
- "this._postTask",
4259
- ""
4260
- ]
4261
- });
4262
- this._postTask.schedule();
4263
- }
4264
- _handlePostMessage(message) {
4265
- invariant3(message.kind === "post", void 0, {
4266
- F: __dxlog_file10,
4267
- L: 120,
4268
- S: this,
4269
- A: [
4270
- "message.kind === 'post'",
4271
- ""
4272
- ]
4273
- });
4274
- this._remoteStates.set(message.state.peerId, message.state);
4275
- this.remoteStateChange.emit();
4276
- }
4386
+ var ToolbarSeparator = () => /* @__PURE__ */ React2.createElement("div", {
4387
+ role: "separator",
4388
+ className: "grow"
4389
+ });
4390
+ var MarkdownHeading = () => {
4391
+ const { t } = useTranslation(translationKey);
4392
+ const { onAction, state } = useToolbarContext("MarkdownFormatting");
4393
+ const blockType = state ? state.blockType : "paragraph";
4394
+ const header = blockType && /heading(\d)/.exec(blockType);
4395
+ const value = header ? header[1] : blockType === "paragraph" || !blockType ? "0" : void 0;
4396
+ const HeadingIcon = HeadingIcons[value ?? "0"];
4397
+ const suppressNextTooltip = useRef2(false);
4398
+ const [tooltipOpen, setTooltipOpen] = useState3(false);
4399
+ const [selectOpen, setSelectOpen] = useState3(false);
4400
+ return /* @__PURE__ */ React2.createElement(Tooltip.Root, {
4401
+ open: tooltipOpen,
4402
+ onOpenChange: (nextOpen) => {
4403
+ if (nextOpen && suppressNextTooltip.current) {
4404
+ suppressNextTooltip.current = false;
4405
+ return setTooltipOpen(false);
4406
+ } else {
4407
+ return setTooltipOpen(nextOpen);
4408
+ }
4409
+ }
4410
+ }, /* @__PURE__ */ React2.createElement(Select.Root, {
4411
+ disabled: value === null,
4412
+ value: value ?? "0",
4413
+ open: selectOpen,
4414
+ onOpenChange: (nextOpen) => {
4415
+ if (!nextOpen) {
4416
+ suppressNextTooltip.current = true;
4417
+ }
4418
+ return setSelectOpen(nextOpen);
4419
+ },
4420
+ onValueChange: (value2) => onAction?.({
4421
+ type: "heading",
4422
+ data: parseInt(value2)
4423
+ })
4424
+ }, /* @__PURE__ */ React2.createElement(Tooltip.Trigger, {
4425
+ asChild: true
4426
+ }, /* @__PURE__ */ React2.createElement(NaturalToolbar.Button, {
4427
+ asChild: true
4428
+ }, /* @__PURE__ */ React2.createElement(Select.TriggerButton, {
4429
+ variant: "ghost",
4430
+ classNames: buttonStyles
4431
+ }, /* @__PURE__ */ React2.createElement("span", {
4432
+ className: "sr-only"
4433
+ }, t("heading label")), /* @__PURE__ */ React2.createElement(HeadingIcon, {
4434
+ className: iconStyles
4435
+ })))), /* @__PURE__ */ React2.createElement(Select.Portal, null, /* @__PURE__ */ React2.createElement(Select.Content, null, /* @__PURE__ */ React2.createElement(Select.ScrollUpButton, null), /* @__PURE__ */ React2.createElement(Select.Viewport, null, /* @__PURE__ */ React2.createElement(Select.Option, {
4436
+ value: "0"
4437
+ }, /* @__PURE__ */ React2.createElement(Paragraph, {
4438
+ className: iconStyles
4439
+ })), [
4440
+ 1,
4441
+ 2,
4442
+ 3,
4443
+ 4,
4444
+ 5,
4445
+ 6
4446
+ ].map((level) => /* @__PURE__ */ React2.createElement(Select.Option, {
4447
+ key: level,
4448
+ value: String(level)
4449
+ }, level === 1 && /* @__PURE__ */ React2.createElement(TextHOne, {
4450
+ className: iconStyles
4451
+ }), level === 2 && /* @__PURE__ */ React2.createElement(TextHTwo, {
4452
+ className: iconStyles
4453
+ }), level === 3 && /* @__PURE__ */ React2.createElement(TextHThree, {
4454
+ className: iconStyles
4455
+ }), level === 4 && /* @__PURE__ */ React2.createElement(TextHFour, {
4456
+ className: iconStyles
4457
+ }), level === 5 && /* @__PURE__ */ React2.createElement(TextHFive, {
4458
+ className: iconStyles
4459
+ }), level === 6 && /* @__PURE__ */ React2.createElement(TextHSix, {
4460
+ className: iconStyles
4461
+ })))), /* @__PURE__ */ React2.createElement(Select.ScrollDownButton, null), /* @__PURE__ */ React2.createElement(Select.Arrow, null)))), /* @__PURE__ */ React2.createElement(Tooltip.Portal, null, /* @__PURE__ */ React2.createElement(Tooltip.Content, tooltipProps, t("heading label"), /* @__PURE__ */ React2.createElement(Tooltip.Arrow, null))));
4277
4462
  };
4278
-
4279
- // packages/ui/react-ui-editor/src/hooks/extension-utils.ts
4280
- import { closeBrackets } from "@codemirror/autocomplete";
4281
- import { history } from "@codemirror/commands";
4282
- import { bracketMatching } from "@codemirror/language";
4283
- import { EditorState as EditorState2 } from "@codemirror/state";
4284
- import { EditorView as EditorView16, crosshairCursor, drawSelection, dropCursor, highlightActiveLine, lineNumbers, placeholder, scrollPastEnd } from "@codemirror/view";
4285
- import defaultsDeep2 from "lodash.defaultsdeep";
4286
- import { useMemo as useMemo2 } from "react";
4287
- import { generateName } from "@dxos/display-name";
4288
- import { createDocAccessor, getTextContent } from "@dxos/echo-schema";
4289
- import { log as log9 } from "@dxos/log";
4290
- import { hueTokens } from "@dxos/react-ui-theme";
4291
- import { hexToHue, isNotFalsy as isNotFalsy3 } from "@dxos/util";
4292
-
4293
- // packages/ui/react-ui-editor/src/themes/default.ts
4294
- import get3 from "lodash.get";
4295
- var defaultTheme = {
4296
- //
4297
- // Main layout:
4298
- // https://codemirror.net/examples/styling
4299
- //
4300
- // <div class="cm-editor [cm-focused] [generated classes]">
4301
- // <div class="cm-scroller">
4302
- // <div class="cm-gutters">
4303
- // <div class="cm-gutter [...]">
4304
- // <div class="cm-gutterElement">...</div>
4305
- // </div>
4306
- // </div>
4307
- // <div class="cm-content" role="textbox" contenteditable="true">
4308
- // <div class="cm-line"></div>
4309
- // </div>
4310
- // <div class="cm-selectionLayer">
4311
- // <div class="cm-selectionBackground"></div>
4312
- // </div>
4313
- // <div class="cm-cursorLayer">
4314
- // <div class="cm-cursor"></div>
4315
- // </div>
4316
- // </div>
4317
- // </div>
4318
- //
4319
- "&": {},
4320
- "&.cm-focused": {
4321
- outline: "none"
4322
- },
4323
- // NOTE: See https://codemirror.net/docs/guide (DOM Structure).
4324
- ".cm-scroller": {
4325
- // TODO(burdon): Reconcile with docs: https://codemirror.net/docs/guide
4326
- // Inside of that is the scroller element. If the editor has its own scrollbar, this one should be styled with overflow: auto. But it doesn't have to—the editor also supports growing to accomodate its content, or growing up to a certain max-height and then scrolling.
4327
- overflowY: "auto",
4328
- fontFamily: get3(tokens, "fontFamily.body", []).join(","),
4329
- lineHeight: 1.5
4330
- },
4331
- ".cm-content": {
4332
- // TODO(burdon): Is it possible to remove the padding value from CM's default theme?
4333
- // padding: 'unset',
4334
- // NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
4335
- fontSize: "16px"
4336
- },
4337
- "&light .cm-content": {
4338
- color: get3(tokens, "extend.semanticColors.base.fg.light", "black"),
4339
- caretColor: "black"
4340
- },
4341
- "&dark .cm-content": {
4342
- color: get3(tokens, "extend.semanticColors.base.fg.dark", "white"),
4343
- caretColor: "white"
4344
- },
4345
- //
4346
- // Cursor
4347
- //
4348
- "&light .cm-cursor, &light .cm-dropCursor": {
4349
- borderLeft: "2px solid black"
4350
- },
4351
- "&dark .cm-cursor, &dark .cm-dropCursor": {
4352
- borderLeft: "2px solid white"
4353
- },
4354
- "&light .cm-placeholder": {
4355
- color: get3(tokens, "extend.semanticColors.description.light", "rgba(0,0,0,.2)")
4356
- },
4357
- "&dark .cm-placeholder": {
4358
- color: get3(tokens, "extend.semanticColors.description.dark", "rgba(255,255,255,.2)")
4359
- },
4360
- //
4361
- // line
4362
- //
4363
- ".cm-line": {
4364
- paddingInline: 0
4365
- },
4366
- ".cm-activeLine": {
4367
- background: "transparent"
4368
- },
4369
- //
4370
- // gutter
4371
- //
4372
- ".cm-gutterElement": {
4373
- width: "48px"
4374
- },
4375
- //
4376
- // Selection
4377
- //
4378
- "&light .cm-selectionBackground": {
4379
- background: get3(tokens, "extend.colors.primary.100")
4380
- },
4381
- "&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
4382
- background: get3(tokens, "extend.colors.primary.200")
4383
- },
4384
- "&dark .cm-selectionBackground": {
4385
- background: get3(tokens, "extend.colors.primary.700")
4386
- },
4387
- "&dark.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
4388
- background: get3(tokens, "extend.colors.primary.600")
4389
- },
4390
- //
4391
- // Search
4392
- //
4393
- "&light .cm-searchMatch": {
4394
- backgroundColor: get3(tokens, "extend.colors.yellow.100")
4395
- },
4396
- "&dark .cm-searchMatch": {
4397
- backgroundColor: get3(tokens, "extend.colors.yellow.700")
4398
- },
4399
- //
4400
- // link
4401
- //
4402
- ".cm-link": {
4403
- color: get3(tokens, "extend.colors.primary.500"),
4404
- textDecorationLine: "underline",
4405
- textDecorationThickness: "1px",
4406
- textUnderlineOffset: "2px",
4407
- borderRadius: ".125rem",
4408
- fontFamily: get3(tokens, "fontFamily.body", []).join(",")
4409
- },
4410
- //
4411
- // tooltip
4412
- //
4413
- ".cm-tooltip": {
4414
- border: "none",
4415
- background: "unset"
4416
- },
4417
- ".cm-tooltip-below": {},
4418
- //
4419
- // autocomplete
4420
- //
4421
- ".cm-tooltip-autocomplete": {
4422
- marginTop: "4px",
4423
- marginLeft: "-3px"
4424
- },
4425
- ".cm-tooltip-autocomplete ul li": {},
4426
- ".cm-tooltip-autocomplete ul li[aria-selected]": {},
4427
- ".cm-completionIcon": {
4428
- display: "none"
4429
- },
4430
- ".cm-completionLabel": {
4431
- fontFamily: get3(tokens, "fontFamily.body", []).join(",")
4432
- },
4433
- ".cm-completionMatchedText": {
4434
- textDecoration: "none"
4435
- },
4436
- //
4437
- // table
4438
- //
4439
- ".cm-table *": {
4440
- fontFamily: `${get3(tokens, "fontFamily.mono", []).join(",")} !important`,
4441
- textDecoration: "none !important"
4442
- },
4443
- ".cm-table-head": {
4444
- padding: "2px 16px 2px 0px",
4445
- borderBottom: `1px solid ${get3(tokens, "extend.colors.neutral.500")}`,
4446
- fontWeight: 100,
4447
- textAlign: "left",
4448
- color: get3(tokens, "extend.colors.neutral.500")
4449
- },
4450
- ".cm-table-cell": {
4451
- padding: "2px 16px 2px 0px"
4452
- },
4453
- //
4454
- // image
4455
- //
4456
- ".cm-image": {
4457
- display: "block",
4458
- height: "0"
4459
- },
4460
- ".cm-image.cm-loaded-image": {
4461
- height: "auto",
4462
- borderTop: "0.5rem solid transparent",
4463
- borderBottom: "0.5rem solid transparent"
4463
+ var markdownStyles = [
4464
+ {
4465
+ type: "strong",
4466
+ Icon: TextB,
4467
+ getState: (state) => state.strong
4464
4468
  },
4465
- //
4466
- // font size
4467
- // TODO(thure): This appears to be the best or only way to set selection caret heights,
4468
- // but it's far more verbose than it needs to be.
4469
- //
4470
- // ...Object.keys(get(tokens, 'extend.fontSize', {})).reduce((acc: Record<string, any>, fontSize) => {
4471
- // const height = get(tokens, ['extend', 'fontSize', fontSize, 1, 'lineHeight']);
4472
- //
4473
- // acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = { height };
4474
- // acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = { height };
4475
- // acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = { height };
4476
- // return acc;
4477
- // }, {}),
4478
- /**
4479
- * Panels
4480
- * TODO(burdon): Needs styling attention (esp. dark mode).
4481
- * https://github.com/codemirror/search/blob/main/src/search.ts#L745
4482
- *
4483
- * Find/replace panel.
4484
- * <div class="cm-announced">...</div>
4485
- * <div class="cm-scroller">...</div>
4486
- * <div class="cm-panels cm-panels-bottom">
4487
- * <div class="cm-search cm-panel">
4488
- * <input class="cm-textfield" />
4489
- * <button class="cm-button">...</button>
4490
- * <label><input type="checkbox" />...</label>
4491
- * </div>
4492
- * </div
4493
- */
4494
- ".cm-panels": {
4495
- border: `1px solid ${get3(tokens, "extend.colors.neutral.200")}`
4469
+ {
4470
+ type: "emphasis",
4471
+ Icon: TextItalic,
4472
+ getState: (state) => state.emphasis
4496
4473
  },
4497
- ".cm-panel": {
4498
- background: get3(tokens, "extend.colors.neutral.50"),
4499
- fontFamily: get3(tokens, "fontFamily.body", []).join(",")
4474
+ {
4475
+ type: "strikethrough",
4476
+ Icon: TextStrikethrough,
4477
+ getState: (state) => state.strikethrough
4500
4478
  },
4501
- ".cm-button": {
4502
- margin: "4px",
4503
- fontFamily: get3(tokens, "fontFamily.body", []).join(","),
4504
- background: get3(tokens, "extend.colors.neutral.100"),
4505
- backgroundImage: "none",
4506
- border: "none",
4507
- "&:hover": {
4508
- background: get3(tokens, "extend.colors.neutral.200")
4509
- },
4510
- "&:active": {
4511
- background: get3(tokens, "extend.colors.neutral.300"),
4512
- backgroundImage: "none"
4513
- }
4479
+ {
4480
+ type: "code",
4481
+ Icon: Code,
4482
+ getState: (state) => state.code
4514
4483
  },
4515
- ".cm-panel input[type=checkbox]": {
4516
- marginRight: "0.4rem !important"
4484
+ {
4485
+ type: "link",
4486
+ Icon: Link,
4487
+ getState: (state) => state.link
4517
4488
  }
4489
+ ];
4490
+ var MarkdownStyles = () => {
4491
+ const { onAction, state } = useToolbarContext("MarkdownStyles");
4492
+ const { t } = useTranslation(translationKey);
4493
+ return /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroup, {
4494
+ type: "multiple",
4495
+ value: markdownStyles.filter(({ getState }) => state && getState(state)).map(({ type }) => type)
4496
+ }, markdownStyles.map(({ type, getState, Icon }) => /* @__PURE__ */ React2.createElement(ToolbarButton, {
4497
+ key: type,
4498
+ value: type,
4499
+ Icon,
4500
+ disabled: state?.blockType === "codeblock",
4501
+ onClick: state ? () => onAction?.({
4502
+ type,
4503
+ data: !getState(state)
4504
+ }) : void 0
4505
+ }, t(`${type} label`))));
4518
4506
  };
4519
-
4520
- // packages/ui/react-ui-editor/src/hooks/extension-utils.ts
4521
- var __dxlog_file11 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/extension-utils.ts";
4522
- var defaults = {
4523
- bracketMatching: true,
4524
- closeBrackets: true,
4525
- drawSelection: true,
4526
- editable: true,
4527
- history: true,
4528
- lineWrapping: true
4529
- };
4530
- var createBasicExtensions = (_props) => {
4531
- const props = defaultsDeep2({}, _props, defaults);
4532
- return [
4533
- // TODO(burdon): Doesn't catch errors in keymap functions.
4534
- EditorView16.exceptionSink.of((err) => {
4535
- log9.catch(err, void 0, {
4536
- F: __dxlog_file11,
4537
- L: 79,
4538
- S: void 0,
4539
- C: (f, a) => f(...a)
4540
- });
4541
- }),
4542
- props.allowMultipleSelections && EditorState2.allowMultipleSelections.of(true),
4543
- props.bracketMatching && bracketMatching(),
4544
- props.closeBrackets && closeBrackets(),
4545
- props.crosshairCursor && crosshairCursor(),
4546
- props.dropCursor && dropCursor(),
4547
- props.drawSelection && drawSelection(),
4548
- props.highlightActiveLine && highlightActiveLine(),
4549
- props.history && history(),
4550
- props.lineNumbers && lineNumbers(),
4551
- props.lineWrapping && EditorView16.lineWrapping,
4552
- props.placeholder && placeholder(props.placeholder),
4553
- props.readonly && [
4554
- EditorState2.readOnly.of(true),
4555
- EditorView16.editable.of(false)
4556
- ],
4557
- props.scrollPastEnd && scrollPastEnd(),
4558
- props.tabSize && EditorState2.tabSize.of(props.tabSize)
4559
- ].filter(isNotFalsy3);
4507
+ var markdownLists = [
4508
+ {
4509
+ type: "list-bullet",
4510
+ Icon: ListBullets,
4511
+ getState: (state) => state.listStyle === "bullet"
4512
+ },
4513
+ {
4514
+ type: "list-ordered",
4515
+ Icon: ListNumbers,
4516
+ getState: (state) => state.listStyle === "ordered"
4517
+ },
4518
+ {
4519
+ type: "list-task",
4520
+ Icon: ListChecks,
4521
+ getState: (state) => state.listStyle === "task"
4522
+ }
4523
+ ];
4524
+ var MarkdownLists = () => {
4525
+ const { onAction, state } = useToolbarContext("MarkdownStyles");
4526
+ const { t } = useTranslation(translationKey);
4527
+ return /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroup, {
4528
+ type: "single",
4529
+ value: state?.listStyle ? `list-${state.listStyle}` : ""
4530
+ }, markdownLists.map(({ type, getState, Icon }) => /* @__PURE__ */ React2.createElement(ToolbarButton, {
4531
+ key: type,
4532
+ value: type,
4533
+ Icon,
4534
+ onClick: state ? () => onAction?.({
4535
+ type,
4536
+ data: !getState(state)
4537
+ }) : void 0
4538
+ }, t(`${type} label`))));
4560
4539
  };
4561
- var defaultSlots = {
4562
- editor: {
4563
- className: "w-full bs-full"
4540
+ var markdownBlocks = [
4541
+ {
4542
+ type: "blockquote",
4543
+ Icon: Quotes,
4544
+ getState: (state) => state.blockQuote
4564
4545
  },
4565
- content: {
4566
- className: "!p-2"
4546
+ {
4547
+ type: "codeblock",
4548
+ Icon: CodeBlock,
4549
+ getState: (state) => state.blockType === "codeblock"
4550
+ },
4551
+ {
4552
+ type: "table",
4553
+ Icon: Table2,
4554
+ getState: (state) => state.blockType === "tablecell",
4555
+ disabled: (state) => !state.blankLine
4567
4556
  }
4557
+ ];
4558
+ var MarkdownBlocks = () => {
4559
+ const { onAction, state } = useToolbarContext("MarkdownStyles");
4560
+ const { t } = useTranslation(translationKey);
4561
+ const value = markdownBlocks.find(({ getState }) => state && getState(state));
4562
+ return /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroup, {
4563
+ type: "single",
4564
+ value: value?.type ?? ""
4565
+ }, markdownBlocks.map(({ type, disabled, getState, Icon }) => /* @__PURE__ */ React2.createElement(ToolbarButton, {
4566
+ key: type,
4567
+ value: type,
4568
+ Icon,
4569
+ disabled: !state || disabled?.(state),
4570
+ onClick: state ? () => onAction?.({
4571
+ type,
4572
+ data: !getState(state)
4573
+ }) : void 0
4574
+ }, t(`${type} label`))));
4568
4575
  };
4569
- var createThemeExtensions = ({ theme, themeMode, slots: _slots } = {}) => {
4570
- const slots = defaultsDeep2({}, _slots, defaultSlots);
4571
- return [
4572
- EditorView16.baseTheme(defaultTheme),
4573
- EditorView16.darkTheme.of(themeMode === "dark"),
4574
- theme && EditorView16.theme(theme),
4575
- slots.editor?.className && EditorView16.editorAttributes.of({
4576
- class: slots.editor.className
4576
+ var MarkdownStandard = () => /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(MarkdownHeading, null), /* @__PURE__ */ React2.createElement(MarkdownStyles, null), /* @__PURE__ */ React2.createElement(MarkdownLists, null), /* @__PURE__ */ React2.createElement(MarkdownBlocks, null));
4577
+ var MarkdownExtended = () => {
4578
+ const { onAction } = useToolbarContext("MarkdownStyles");
4579
+ const { t } = useTranslation(translationKey);
4580
+ return /* @__PURE__ */ React2.createElement(Tooltip.Root, null, /* @__PURE__ */ React2.createElement(Tooltip.Trigger, {
4581
+ asChild: true
4582
+ }, /* @__PURE__ */ React2.createElement(NaturalToolbar.Button, {
4583
+ variant: "ghost",
4584
+ "data-testid": "editor.toolbar.comment",
4585
+ onClick: () => onAction?.({
4586
+ type: "comment"
4577
4587
  }),
4578
- slots.content?.className && EditorView16.contentAttributes.of({
4579
- class: slots.content.className
4580
- })
4581
- ].filter(isNotFalsy3);
4582
- };
4583
- var createDataExtensions = ({ id, text, space, identity }) => {
4584
- const extensions = [
4585
- automerge(text)
4586
- ];
4587
- if (space && identity) {
4588
- const peerId = identity?.identityKey.toHex();
4589
- const { cursorLightValue, cursorDarkValue } = hueTokens[identity?.profile?.data?.hue ?? hexToHue(peerId ?? "0")];
4590
- const awarenessProvider2 = new SpaceAwarenessProvider({
4591
- space,
4592
- channel: `awareness.${id}`,
4593
- peerId: identity.identityKey.toHex(),
4594
- info: {
4595
- displayName: identity.profile?.displayName ?? generateName(identity.identityKey.toHex()),
4596
- color: cursorDarkValue,
4597
- lightColor: cursorLightValue
4598
- }
4599
- });
4600
- extensions.push(awareness(awarenessProvider2));
4601
- }
4602
- return extensions;
4588
+ classNames: buttonStyles
4589
+ }, /* @__PURE__ */ React2.createElement(ChatText, {
4590
+ className: iconStyles
4591
+ }), /* @__PURE__ */ React2.createElement("span", {
4592
+ className: "sr-only"
4593
+ }, t("comment label")))), /* @__PURE__ */ React2.createElement(Tooltip.Portal, null, /* @__PURE__ */ React2.createElement(Tooltip.Content, tooltipProps, t("comment label"), /* @__PURE__ */ React2.createElement(Tooltip.Arrow, null))));
4603
4594
  };
4604
- var useDocAccessor = (text) => {
4605
- return useMemo2(() => ({
4606
- id: text.id,
4607
- doc: getTextContent(text),
4608
- accessor: createDocAccessor(text)
4609
- }), [
4610
- text
4611
- ]);
4595
+ var Toolbar = {
4596
+ Root: ToolbarRoot,
4597
+ Button: ToolbarButton,
4598
+ Separator: ToolbarSeparator,
4599
+ Markdown: MarkdownStandard,
4600
+ Extended: MarkdownExtended
4612
4601
  };
4613
4602
 
4614
4603
  // packages/ui/react-ui-editor/src/hooks/useActionHandler.ts
@@ -4659,6 +4648,19 @@ var useActionHandler = (view) => {
4659
4648
  };
4660
4649
  };
4661
4650
 
4651
+ // packages/ui/react-ui-editor/src/hooks/useDocAccessor.ts
4652
+ import { useMemo as useMemo2 } from "react";
4653
+ import { createDocAccessor, getTextContent } from "@dxos/echo-schema";
4654
+ var useDocAccessor = (text) => {
4655
+ return useMemo2(() => ({
4656
+ id: text.id,
4657
+ doc: getTextContent(text),
4658
+ accessor: createDocAccessor(text)
4659
+ }), [
4660
+ text
4661
+ ]);
4662
+ };
4663
+
4662
4664
  // packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
4663
4665
  import { EditorSelection as EditorSelection2, EditorState as EditorState3 } from "@codemirror/state";
4664
4666
  import { EditorView as EditorView17 } from "@codemirror/view";