@dxos/react-ui-editor 0.4.8-main.27faba7 → 0.4.8-main.512e4c8

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 (89) hide show
  1. package/dist/lib/browser/index.mjs +920 -1084
  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.d.ts +18 -34
  5. package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
  6. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +79 -5
  7. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
  8. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -1
  9. package/dist/types/src/extensions/automerge/automerge.d.ts +1 -1
  10. package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
  11. package/dist/types/src/extensions/automerge/automerge.stories.d.ts +1 -1
  12. package/dist/types/src/extensions/automerge/automerge.stories.d.ts.map +1 -1
  13. package/dist/types/src/extensions/automerge/cursor.d.ts +1 -1
  14. package/dist/types/src/extensions/automerge/cursor.d.ts.map +1 -1
  15. package/dist/types/src/extensions/automerge/defs.d.ts +1 -15
  16. package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
  17. package/dist/types/src/extensions/automerge/index.d.ts +0 -1
  18. package/dist/types/src/extensions/automerge/index.d.ts.map +1 -1
  19. package/dist/types/src/extensions/automerge/sync.d.ts +2 -1
  20. package/dist/types/src/extensions/automerge/sync.d.ts.map +1 -1
  21. package/dist/types/src/extensions/automerge/update-automerge.d.ts +2 -1
  22. package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -1
  23. package/dist/types/src/extensions/comments.d.ts +1 -1
  24. package/dist/types/src/extensions/comments.d.ts.map +1 -1
  25. package/dist/types/src/extensions/cursor-line-margin.d.ts +6 -7
  26. package/dist/types/src/extensions/cursor-line-margin.d.ts.map +1 -1
  27. package/dist/types/src/extensions/doc.d.ts +3 -0
  28. package/dist/types/src/extensions/doc.d.ts.map +1 -0
  29. package/dist/types/src/extensions/index.d.ts +1 -1
  30. package/dist/types/src/extensions/index.d.ts.map +1 -1
  31. package/dist/types/src/extensions/markdown/bundle.d.ts +5 -4
  32. package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
  33. package/dist/types/src/extensions/markdown/decorate.d.ts.map +1 -1
  34. package/dist/types/src/extensions/markdown/formatting.d.ts +1 -1
  35. package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -1
  36. package/dist/types/src/extensions/markdown/table.d.ts +2 -2
  37. package/dist/types/src/extensions/markdown/table.d.ts.map +1 -1
  38. package/dist/types/src/hooks/defs.d.ts +0 -11
  39. package/dist/types/src/hooks/defs.d.ts.map +1 -1
  40. package/dist/types/src/hooks/extension-utils.d.ts +54 -0
  41. package/dist/types/src/hooks/extension-utils.d.ts.map +1 -0
  42. package/dist/types/src/hooks/index.d.ts +1 -2
  43. package/dist/types/src/hooks/index.d.ts.map +1 -1
  44. package/dist/types/src/hooks/useTextEditor.d.ts +3 -44
  45. package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
  46. package/dist/types/src/hooks/useTextEditor.stories.d.ts +6 -0
  47. package/dist/types/src/hooks/useTextEditor.stories.d.ts.map +1 -1
  48. package/dist/types/src/themes/default.d.ts +0 -3
  49. package/dist/types/src/themes/default.d.ts.map +1 -1
  50. package/package.json +24 -24
  51. package/src/components/TextEditor/TextEditor.stories.tsx +510 -23
  52. package/src/components/TextEditor/TextEditor.tsx +37 -149
  53. package/src/components/Toolbar/Toolbar.stories.tsx +46 -42
  54. package/src/extensions/automerge/automerge.stories.tsx +14 -16
  55. package/src/extensions/automerge/automerge.ts +2 -1
  56. package/src/extensions/automerge/cursor.ts +1 -1
  57. package/src/extensions/automerge/defs.ts +1 -22
  58. package/src/extensions/automerge/index.ts +0 -1
  59. package/src/extensions/automerge/sync.ts +2 -9
  60. package/src/extensions/automerge/update-automerge.ts +2 -1
  61. package/src/extensions/command/state.ts +1 -1
  62. package/src/extensions/comments.ts +8 -4
  63. package/src/extensions/cursor-line-margin.ts +17 -18
  64. package/src/extensions/doc.ts +14 -0
  65. package/src/extensions/index.ts +1 -1
  66. package/src/extensions/markdown/bundle.ts +11 -28
  67. package/src/extensions/markdown/decorate.ts +1 -3
  68. package/src/extensions/markdown/formatting.ts +15 -10
  69. package/src/extensions/markdown/image.ts +1 -0
  70. package/src/extensions/markdown/table.ts +11 -3
  71. package/src/hooks/defs.ts +0 -15
  72. package/src/hooks/extension-utils.ts +185 -0
  73. package/src/hooks/index.ts +1 -2
  74. package/src/hooks/useTextEditor.stories.tsx +39 -34
  75. package/src/hooks/useTextEditor.ts +11 -120
  76. package/src/index.ts +1 -1
  77. package/src/themes/default.ts +1 -28
  78. package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts +0 -103
  79. package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +0 -1
  80. package/dist/types/src/extensions/outliner.d.ts +0 -4
  81. package/dist/types/src/extensions/outliner.d.ts.map +0 -1
  82. package/dist/types/src/hooks/useEditorView.d.ts +0 -20
  83. package/dist/types/src/hooks/useEditorView.d.ts.map +0 -1
  84. package/dist/types/src/hooks/useTextModel.d.ts +0 -33
  85. package/dist/types/src/hooks/useTextModel.d.ts.map +0 -1
  86. package/src/components/TextEditor/MarkdownEditor.stories.tsx +0 -524
  87. package/src/extensions/outliner.ts +0 -12
  88. package/src/hooks/useEditorView.ts +0 -32
  89. package/src/hooks/useTextModel.ts +0 -121
@@ -29,16 +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 as EditorState3 } from "@codemirror/state";
33
- import { EditorView as EditorView17, scrollPastEnd as scrollPastEnd2 } from "@codemirror/view";
32
+ import { EditorState } from "@codemirror/state";
33
+ import { EditorView as EditorView15 } from "@codemirror/view";
34
34
  import { useFocusableGroup } from "@fluentui/react-tabster";
35
- import defaultsDeep3 from "lodash.defaultsdeep";
36
- import React, { forwardRef, useCallback, useEffect as useEffect3, useImperativeHandle, useRef as useRef3, useState as useState5, useMemo as useMemo3 } from "react";
37
- import { DocAccessor } from "@dxos/echo-schema";
38
- import { log as log9 } from "@dxos/log";
39
- import { useThemeContext } from "@dxos/react-ui";
40
- import { focusRing } from "@dxos/react-ui-theme";
41
- import { isNotFalsy as isNotFalsy4 } from "@dxos/util";
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";
42
38
 
43
39
  // packages/ui/react-ui-editor/src/extensions/annotations.ts
44
40
  import { StateField } from "@codemirror/state";
@@ -243,7 +239,6 @@ var cursorConverter = ({ handle, path }) => ({
243
239
 
244
240
  // packages/ui/react-ui-editor/src/extensions/automerge/defs.ts
245
241
  import { Annotation, StateEffect } from "@codemirror/state";
246
- import get2 from "lodash.get";
247
242
  var getPath = (state, field) => state.field(field).path;
248
243
  var getLastHeads = (state, field) => state.field(field).lastHeads;
249
244
  var updateHeadsEffect = StateEffect.define({});
@@ -1110,8 +1105,8 @@ var commandState = StateField3.define({
1110
1105
  }
1111
1106
  return state;
1112
1107
  },
1113
- provide: (f) => [
1114
- showTooltip.from(f, (value) => value.tooltip ?? null)
1108
+ provide: (field) => [
1109
+ showTooltip.from(field, (value) => value.tooltip ?? null)
1115
1110
  ]
1116
1111
  });
1117
1112
  var openEffect = StateEffect2.define();
@@ -1293,10 +1288,10 @@ var inlineUrl = mx(code, "px-1");
1293
1288
  var blockquote = mx("pl-1 mr-1 border-is-4 border-primary-500/70 dark:border-primary-500/30", light);
1294
1289
 
1295
1290
  // packages/ui/react-ui-editor/src/styles/tokens.ts
1296
- import get3 from "lodash.get";
1291
+ import get2 from "lodash.get";
1297
1292
  import { tailwindConfig } from "@dxos/react-ui-theme";
1298
1293
  var tokens = tailwindConfig({}).theme;
1299
- var getToken = (path, defaultValue = void 0) => get3(tokens, path, defaultValue);
1294
+ var getToken = (path, defaultValue = void 0) => get2(tokens, path, defaultValue);
1300
1295
 
1301
1296
  // packages/ui/react-ui-editor/src/styles/layout.ts
1302
1297
  var editorWithToolbarLayout = "grid grid-cols-1 grid-rows-[min-content_1fr] data-[toolbar=disabled]:grid-rows-[1fr] justify-center content-start overflow-hidden";
@@ -1735,12 +1730,14 @@ var focusComment = (view, id, center = true) => {
1735
1730
  var useComments = (view, id, comments2 = []) => {
1736
1731
  useEffect(() => {
1737
1732
  if (view) {
1738
- view.dispatch({
1739
- effects: setComments.of({
1740
- id,
1741
- comments: comments2
1742
- })
1743
- });
1733
+ if (id === view.state.facet(documentId)) {
1734
+ view.dispatch({
1735
+ effects: setComments.of({
1736
+ id,
1737
+ comments: comments2
1738
+ })
1739
+ });
1740
+ }
1744
1741
  }
1745
1742
  }, [
1746
1743
  id,
@@ -1750,74 +1747,97 @@ var useComments = (view, id, comments2 = []) => {
1750
1747
  };
1751
1748
 
1752
1749
  // packages/ui/react-ui-editor/src/extensions/cursor-line-margin.ts
1753
- import { Facet as Facet5, Transaction } from "@codemirror/state";
1750
+ import { Transaction } from "@codemirror/state";
1754
1751
  import { EditorView as EditorView8 } from "@codemirror/view";
1755
1752
  import { log as log4 } from "@dxos/log";
1756
1753
  var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/cursor-line-margin.ts";
1757
- var cursorLineMarginFacet = Facet5.define({
1758
- combine: (input) => input[0] ?? 3
1759
- });
1760
1754
  var annotation = "cursorLineMargin";
1761
1755
  var lineAtPos = (s, pos) => s.doc.lineAt(pos).number;
1762
- var cursorLineMargin = EditorView8.updateListener.of(({ transactions, state, selectionSet, startState, view }) => {
1763
- if (transactions.length < 1 || transactions.some((tr) => tr.isUserEvent(annotation))) {
1764
- return;
1765
- }
1766
- const s = state;
1767
- const { main } = s.selection;
1768
- const cursorLineMargin2 = s.facet(cursorLineMarginFacet);
1769
- const rect = view.dom.getBoundingClientRect();
1770
- const viewportTop = rect.top - view.documentTop;
1771
- const viewportBottom = rect.bottom - view.documentTop;
1772
- const mainLine = lineAtPos(s, main.head);
1773
- const _visTopLine = lineAtPos(s, view.lineBlockAtHeight(viewportTop).from);
1774
- const botLineBlk = view.lineBlockAtHeight(viewportBottom);
1775
- const visBotLineDoc = lineAtPos(s, Math.min(botLineBlk.to, s.doc.length));
1776
- const visBotLine = botLineBlk.bottom >= viewportBottom ? visBotLineDoc : visBotLineDoc + Math.floor((viewportBottom - botLineBlk.bottom) / view.defaultLineHeight);
1777
- const needsScrollTop = false;
1778
- const needsScrollBot = mainLine >= visBotLine - cursorLineMargin2;
1779
- if (needsScrollTop && needsScrollBot) {
1780
- log4.warn("is cursorScrollMargin too large for the editor size?", void 0, {
1781
- F: __dxlog_file5,
1782
- L: 66,
1783
- S: void 0,
1784
- C: (f, a) => f(...a)
1785
- });
1786
- return;
1787
- }
1788
- if (!needsScrollTop && !needsScrollBot) {
1789
- return;
1756
+ var cursorLineMargin = (options = {
1757
+ lines: 3
1758
+ }) => {
1759
+ const { lines } = options;
1760
+ if (!lines || lines <= 0) {
1761
+ return [];
1790
1762
  }
1791
- if (selectionSet) {
1792
- const { head } = startState.selection.main;
1793
- const oldMainLine = lineAtPos(startState, head);
1794
- if (needsScrollTop && oldMainLine < mainLine) {
1763
+ return EditorView8.updateListener.of(({ transactions, state, selectionSet, startState, view }) => {
1764
+ if (transactions.length < 1 || transactions.some((tr) => tr.isUserEvent(annotation))) {
1795
1765
  return;
1796
1766
  }
1797
- if (needsScrollBot && oldMainLine > mainLine) {
1767
+ const s = state;
1768
+ const { main } = s.selection;
1769
+ const rect = view.dom.getBoundingClientRect();
1770
+ const viewportTop = rect.top - view.documentTop;
1771
+ const viewportBottom = rect.bottom - view.documentTop;
1772
+ const mainLine = lineAtPos(s, main.head);
1773
+ const _visTopLine = lineAtPos(s, view.lineBlockAtHeight(viewportTop).from);
1774
+ const botLineBlk = view.lineBlockAtHeight(viewportBottom);
1775
+ const visBotLineDoc = lineAtPos(s, Math.min(botLineBlk.to, s.doc.length));
1776
+ const visBotLine = botLineBlk.bottom >= viewportBottom ? visBotLineDoc : visBotLineDoc + Math.floor((viewportBottom - botLineBlk.bottom) / view.defaultLineHeight);
1777
+ const needsScrollTop = false;
1778
+ const needsScrollBot = mainLine >= visBotLine - lines;
1779
+ if (needsScrollTop && needsScrollBot) {
1780
+ log4.warn("is cursorScrollMargin too large for the editor size?", void 0, {
1781
+ F: __dxlog_file5,
1782
+ L: 65,
1783
+ S: void 0,
1784
+ C: (f, a) => f(...a)
1785
+ });
1798
1786
  return;
1799
1787
  }
1800
- }
1801
- view.dispatch({
1802
- annotations: Transaction.userEvent.of(annotation),
1803
- effects: EditorView8.scrollIntoView(s.selection.main.head, {
1804
- y: needsScrollTop ? "start" : "end",
1805
- yMargin: view.defaultLineHeight * cursorLineMargin2
1806
- })
1788
+ if (!needsScrollTop && !needsScrollBot) {
1789
+ return;
1790
+ }
1791
+ if (selectionSet) {
1792
+ const { head } = startState.selection.main;
1793
+ const oldMainLine = lineAtPos(startState, head);
1794
+ if (needsScrollTop && oldMainLine < mainLine) {
1795
+ return;
1796
+ }
1797
+ if (needsScrollBot && oldMainLine > mainLine) {
1798
+ return;
1799
+ }
1800
+ }
1801
+ view.dispatch({
1802
+ annotations: Transaction.userEvent.of(annotation),
1803
+ effects: EditorView8.scrollIntoView(s.selection.main.head, {
1804
+ y: needsScrollTop ? "start" : "end",
1805
+ yMargin: view.defaultLineHeight * lines
1806
+ })
1807
+ });
1807
1808
  });
1809
+ };
1810
+
1811
+ // packages/ui/react-ui-editor/src/extensions/doc.ts
1812
+ 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";
1815
+ var documentId2 = Facet5.define({
1816
+ combine: (providers) => {
1817
+ invariant2(providers.length <= 1, void 0, {
1818
+ F: __dxlog_file6,
1819
+ L: 11,
1820
+ S: void 0,
1821
+ A: [
1822
+ "providers.length <= 1",
1823
+ ""
1824
+ ]
1825
+ });
1826
+ return providers[0];
1827
+ }
1808
1828
  });
1809
1829
 
1810
1830
  // packages/ui/react-ui-editor/src/extensions/dnd.ts
1811
1831
  import { EditorView as EditorView9 } from "@codemirror/view";
1812
1832
  import { log as log5 } from "@dxos/log";
1813
- var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/dnd.ts";
1833
+ var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/dnd.ts";
1814
1834
  var dnd = () => {
1815
1835
  return EditorView9.domEventHandlers({
1816
1836
  drop: (event, view) => {
1817
1837
  log5.info("domEventHandlersDrop", {
1818
1838
  event
1819
1839
  }, {
1820
- F: __dxlog_file6,
1840
+ F: __dxlog_file7,
1821
1841
  L: 14,
1822
1842
  S: void 0,
1823
1843
  C: (f, a) => f(...a)
@@ -1841,16 +1861,14 @@ var listener = ({ onFocus, onChange }) => {
1841
1861
  };
1842
1862
 
1843
1863
  // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
1844
- import { closeBrackets, closeBracketsKeymap } from "@codemirror/autocomplete";
1845
- import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
1864
+ import { closeBracketsKeymap } from "@codemirror/autocomplete";
1865
+ import { historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
1846
1866
  import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
1847
- import { bracketMatching, defaultHighlightStyle, indentOnInput, syntaxHighlighting } from "@codemirror/language";
1867
+ import { defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
1848
1868
  import { languages } from "@codemirror/language-data";
1849
1869
  import { searchKeymap } from "@codemirror/search";
1850
- import { EditorState } from "@codemirror/state";
1851
1870
  import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
1852
- import { EditorView as EditorView11, drawSelection, dropCursor, keymap as keymap5, placeholder } from "@codemirror/view";
1853
- import { isNotFalsy as isNotFalsy2 } from "@dxos/util";
1871
+ import { keymap as keymap5 } from "@codemirror/view";
1854
1872
 
1855
1873
  // packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
1856
1874
  import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
@@ -2041,19 +2059,8 @@ var markdownHighlightStyle = (readonly) => {
2041
2059
  };
2042
2060
 
2043
2061
  // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
2044
- var createMarkdownExtensions = ({ themeMode, placeholder: _placeholder, lineWrapping = true } = {}) => {
2062
+ var createMarkdownExtensions = ({ themeMode } = {}) => {
2045
2063
  return [
2046
- // TODO(burdon): Reconcile with createBasicExtensions.
2047
- lineWrapping && EditorView11.lineWrapping,
2048
- EditorState.allowMultipleSelections.of(true),
2049
- EditorState.tabSize.of(2),
2050
- bracketMatching(),
2051
- closeBrackets(),
2052
- dropCursor(),
2053
- drawSelection(),
2054
- history(),
2055
- indentOnInput(),
2056
- _placeholder && placeholder(_placeholder),
2057
2064
  // Main extension.
2058
2065
  // https://github.com/codemirror/lang-markdown
2059
2066
  // https://codemirror.net/5/mode/markdown/index.html (demo).
@@ -2088,13 +2095,13 @@ var createMarkdownExtensions = ({ themeMode, placeholder: _placeholder, lineWrap
2088
2095
  // https://codemirror.net/docs/ref/#commands.standardKeymap
2089
2096
  ...standardKeymap
2090
2097
  ])
2091
- ].filter(isNotFalsy2);
2098
+ ];
2092
2099
  };
2093
2100
 
2094
2101
  // packages/ui/react-ui-editor/src/extensions/markdown/decorate.ts
2095
2102
  import { syntaxTree } from "@codemirror/language";
2096
2103
  import { RangeSetBuilder as RangeSetBuilder2, StateEffect as StateEffect4 } from "@codemirror/state";
2097
- import { EditorView as EditorView12, Decoration as Decoration5, WidgetType as WidgetType3, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
2104
+ import { EditorView as EditorView11, Decoration as Decoration5, WidgetType as WidgetType3, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
2098
2105
  import { mx as mx2 } from "@dxos/react-ui-theme";
2099
2106
  var HorizontalRuleWidget = class extends WidgetType3 {
2100
2107
  toDOM() {
@@ -2302,15 +2309,15 @@ var decorateMarkdown = (options = {}) => {
2302
2309
  }
2303
2310
  }, {
2304
2311
  provide: (plugin) => [
2305
- EditorView12.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration5.none),
2306
- EditorView12.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration5.none),
2307
- EditorView12.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration5.none)
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)
2308
2315
  ]
2309
2316
  }),
2310
2317
  formattingStyles
2311
2318
  ];
2312
2319
  };
2313
- var formattingStyles = EditorView12.baseTheme({
2320
+ var formattingStyles = EditorView11.baseTheme({
2314
2321
  "& .cm-code": {
2315
2322
  fontFamily: getToken("fontFamily.mono", []).join(",")
2316
2323
  },
@@ -2363,7 +2370,7 @@ var formattingStyles = EditorView12.baseTheme({
2363
2370
  import { snippet } from "@codemirror/autocomplete";
2364
2371
  import { syntaxTree as syntaxTree2 } from "@codemirror/language";
2365
2372
  import { EditorSelection } from "@codemirror/state";
2366
- import { EditorView as EditorView13, keymap as keymap6 } from "@codemirror/view";
2373
+ import { EditorView as EditorView12, keymap as keymap6 } from "@codemirror/view";
2367
2374
  import { useState, useMemo } from "react";
2368
2375
  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;
2369
2376
  var Inline;
@@ -3018,8 +3025,8 @@ var removeList = (type) => ({ state, dispatch }) => {
3018
3025
  return true;
3019
3026
  };
3020
3027
  var toggleList = (type) => (target) => {
3021
- const formatting2 = getFormatting(target.state);
3022
- const active = formatting2.listStyle === (type === 1 ? "bullet" : type === 0 ? "ordered" : "task");
3028
+ const formatting = getFormatting(target.state);
3029
+ const active = formatting.listStyle === (type === 1 ? "bullet" : type === 0 ? "ordered" : "task");
3023
3030
  return (active ? removeList(type) : addList(type))(target);
3024
3031
  };
3025
3032
  var renumberListItems = (item, counter, changes, doc) => {
@@ -3233,7 +3240,7 @@ var removeCodeblock = ({ state, dispatch }) => {
3233
3240
  var toggleCodeblock = (target) => {
3234
3241
  return (getFormatting(target.state).blockType === "codeblock" ? removeCodeblock : addCodeblock)(target);
3235
3242
  };
3236
- var formatting = (options = {}) => {
3243
+ var formattingKeymap = (options = {}) => {
3237
3244
  return [
3238
3245
  keymap6.of([
3239
3246
  {
@@ -3433,7 +3440,7 @@ var getFormatting = (state) => {
3433
3440
  };
3434
3441
  var useFormattingState = () => {
3435
3442
  const [state, setState] = useState(null);
3436
- const observer = useMemo(() => EditorView13.updateListener.of((update2) => {
3443
+ const observer = useMemo(() => EditorView12.updateListener.of((update2) => {
3437
3444
  if (update2.docChanged || update2.selectionSet) {
3438
3445
  const newState = getFormatting(update2.state);
3439
3446
  if (!state || !compareFormatting(state, newState)) {
@@ -3450,7 +3457,7 @@ var useFormattingState = () => {
3450
3457
  // packages/ui/react-ui-editor/src/extensions/markdown/image.ts
3451
3458
  import { syntaxTree as syntaxTree3 } from "@codemirror/language";
3452
3459
  import { StateField as StateField5 } from "@codemirror/state";
3453
- import { Decoration as Decoration6, EditorView as EditorView14, WidgetType as WidgetType4 } from "@codemirror/view";
3460
+ import { Decoration as Decoration6, EditorView as EditorView13, WidgetType as WidgetType4 } from "@codemirror/view";
3454
3461
  var image = (options = {}) => {
3455
3462
  return StateField5.define({
3456
3463
  create: (state) => {
@@ -3477,7 +3484,7 @@ var image = (options = {}) => {
3477
3484
  add: buildDecorations2(from, to, tr.state)
3478
3485
  });
3479
3486
  },
3480
- provide: (field) => EditorView14.decorations.from(field)
3487
+ provide: (field) => EditorView13.decorations.from(field)
3481
3488
  });
3482
3489
  };
3483
3490
  var preloaded = /* @__PURE__ */ new Set();
@@ -3565,12 +3572,12 @@ var linkTooltip = (render) => hoverTooltip2((view, pos, side) => {
3565
3572
  // packages/ui/react-ui-editor/src/extensions/markdown/table.ts
3566
3573
  import { syntaxTree as syntaxTree5 } from "@codemirror/language";
3567
3574
  import { RangeSetBuilder as RangeSetBuilder3, StateField as StateField6 } from "@codemirror/state";
3568
- import { Decoration as Decoration7, EditorView as EditorView15, WidgetType as WidgetType5 } from "@codemirror/view";
3575
+ import { Decoration as Decoration7, EditorView as EditorView14, WidgetType as WidgetType5 } from "@codemirror/view";
3569
3576
  var table = (options = {}) => {
3570
3577
  return StateField6.define({
3571
3578
  create: (state) => update(state, options),
3572
3579
  update: (_, tr) => update(tr.state, options),
3573
- provide: (field) => EditorView15.decorations.from(field)
3580
+ provide: (field) => EditorView14.decorations.from(field)
3574
3581
  });
3575
3582
  };
3576
3583
  var update = (state, options) => {
@@ -3614,9 +3621,11 @@ var update = (state, options) => {
3614
3621
  });
3615
3622
  tables.forEach((table2) => {
3616
3623
  const hide2 = state.readOnly || cursor < table2.from || cursor > table2.to;
3617
- hide2 && builder.add(table2.from, table2.to, Decoration7.replace({
3618
- widget: new TableWidget(table2)
3619
- }));
3624
+ if (hide2) {
3625
+ builder.add(table2.from, table2.to, Decoration7.replace({
3626
+ widget: new TableWidget(table2)
3627
+ }));
3628
+ }
3620
3629
  builder.add(table2.from, table2.to, Decoration7.mark({
3621
3630
  class: "cm-table"
3622
3631
  }));
@@ -3663,7 +3672,7 @@ var TableWidget = class extends WidgetType5 {
3663
3672
  // packages/ui/react-ui-editor/src/extensions/mention.ts
3664
3673
  import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
3665
3674
  import { log as log6 } from "@dxos/log";
3666
- var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/mention.ts";
3675
+ var __dxlog_file8 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/mention.ts";
3667
3676
  var mention = ({ onSearch }) => {
3668
3677
  return autocompletion2({
3669
3678
  // TODO(burdon): Not working.
@@ -3678,7 +3687,7 @@ var mention = ({ onSearch }) => {
3678
3687
  log6.info("completion context", {
3679
3688
  context
3680
3689
  }, {
3681
- F: __dxlog_file7,
3690
+ F: __dxlog_file8,
3682
3691
  L: 26,
3683
3692
  S: void 0,
3684
3693
  C: (f, a) => f(...a)
@@ -3727,11 +3736,6 @@ var EditorModes = {
3727
3736
  ]
3728
3737
  };
3729
3738
 
3730
- // packages/ui/react-ui-editor/src/extensions/outliner.ts
3731
- var outliner = (options = {}) => {
3732
- return [];
3733
- };
3734
-
3735
3739
  // packages/ui/react-ui-editor/src/extensions/typewriter.ts
3736
3740
  import { keymap as keymap8 } from "@codemirror/view";
3737
3741
  var defaultItems = [
@@ -3789,263 +3793,577 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
3789
3793
  ];
3790
3794
  };
3791
3795
 
3792
- // packages/ui/react-ui-editor/src/hooks/awareness-provider.ts
3793
- import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
3794
- import { Context as Context2 } from "@dxos/context";
3795
- import { invariant as invariant2 } from "@dxos/invariant";
3796
- import { log as log7 } from "@dxos/log";
3797
- var __dxlog_file8 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
3798
- var DEBOUNCE_INTERVAL = 100;
3799
- var SpaceAwarenessProvider = class {
3800
- constructor(params) {
3801
- this._remoteStates = /* @__PURE__ */ new Map();
3802
- this.remoteStateChange = new Event2();
3803
- this._space = params.space;
3804
- this._channel = params.channel;
3805
- this._peerId = params.peerId;
3806
- this._info = params.info;
3807
- }
3808
- open() {
3809
- this._ctx = new Context2();
3810
- this._postTask = new DeferredTask(this._ctx, async () => {
3811
- if (this._localState) {
3812
- await this._space.postMessage(this._channel, {
3813
- kind: "post",
3814
- state: this._localState
3815
- });
3816
- await sleep(DEBOUNCE_INTERVAL);
3817
- }
3796
+ // 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";
3798
+ var instanceCount = 0;
3799
+ var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, className, autoFocus, scrollTo = EditorView15.scrollIntoView(0), moveToEndOfLine, debug, dataTestId }, forwardedRef) => {
3800
+ const [instanceId] = useState2(() => `text-editor-${++instanceCount}`);
3801
+ const tabsterDOMAttribute = useFocusableGroup({
3802
+ tabBehavior: "limited"
3803
+ });
3804
+ const rootRef = useRef(null);
3805
+ const [view, setView] = useState2(null);
3806
+ useImperativeHandle(forwardedRef, () => view, [
3807
+ view
3808
+ ]);
3809
+ useEffect2(() => {
3810
+ if (autoFocus) {
3811
+ view?.focus();
3812
+ }
3813
+ }, [
3814
+ view,
3815
+ autoFocus
3816
+ ]);
3817
+ useEffect2(() => {
3818
+ log7("updating", {
3819
+ id,
3820
+ instanceId
3821
+ }, {
3822
+ F: __dxlog_file9,
3823
+ L: 88,
3824
+ S: void 0,
3825
+ C: (f, a) => f(...a)
3818
3826
  });
3819
- this._ctx.onDispose(this._space.listen(this._channel, (message) => {
3820
- switch (message.payload.kind) {
3821
- case "query": {
3822
- this._handleQueryMessage();
3823
- break;
3824
- }
3825
- case "post": {
3826
- this._handlePostMessage(message.payload);
3827
- break;
3827
+ const state = EditorState.create({
3828
+ doc,
3829
+ selection,
3830
+ extensions: [
3831
+ id && documentId2.of(id),
3832
+ // 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,
3836
+ L: 101,
3837
+ S: void 0,
3838
+ C: (f, a) => f(...a)
3839
+ });
3840
+ }),
3841
+ // Focus.
3842
+ EditorView15.updateListener.of((update2) => {
3843
+ update2.transactions.forEach((transaction) => {
3844
+ if (transaction.isUserEvent("focus.container")) {
3845
+ rootRef.current?.focus();
3846
+ }
3847
+ });
3848
+ }),
3849
+ extensions
3850
+ ].filter(isNotFalsy2)
3851
+ });
3852
+ const view2 = new EditorView15({
3853
+ state,
3854
+ parent: rootRef.current,
3855
+ scrollTo,
3856
+ // NOTE: Uncomment to debug/monitor all transactions.
3857
+ // https://codemirror.net/docs/ref/#view.EditorView.dispatch
3858
+ dispatchTransactions: (trs, view3) => {
3859
+ if (debug) {
3860
+ logChanges(trs);
3828
3861
  }
3862
+ view3.update(trs);
3829
3863
  }
3830
- }));
3831
- void this._space.postMessage(this._channel, {
3832
- kind: "query"
3833
- }).catch((err) => {
3834
- log7.debug("failed to query awareness", {
3835
- err
3836
- }, {
3837
- F: __dxlog_file8,
3838
- L: 89,
3839
- S: this,
3840
- C: (f, a) => f(...a)
3841
- });
3842
- });
3843
- }
3844
- close() {
3845
- void this._ctx?.dispose();
3846
- this._ctx = void 0;
3847
- this._postTask = void 0;
3848
- }
3849
- getRemoteStates() {
3850
- return Array.from(this._remoteStates.values());
3851
- }
3852
- update(position) {
3853
- invariant2(this._postTask, void 0, {
3854
- F: __dxlog_file8,
3855
- L: 104,
3856
- S: this,
3857
- A: [
3858
- "this._postTask",
3859
- ""
3860
- ]
3861
3864
  });
3862
- this._localState = {
3863
- peerId: this._peerId,
3864
- position,
3865
- info: this._info
3866
- };
3867
- this._postTask.schedule();
3868
- }
3869
- _handleQueryMessage() {
3870
- invariant2(this._postTask, void 0, {
3871
- F: __dxlog_file8,
3872
- L: 115,
3873
- S: this,
3874
- A: [
3875
- "this._postTask",
3876
- ""
3877
- ]
3878
- });
3879
- this._postTask.schedule();
3880
- }
3881
- _handlePostMessage(message) {
3882
- invariant2(message.kind === "post", void 0, {
3883
- F: __dxlog_file8,
3884
- L: 120,
3885
- S: this,
3886
- A: [
3887
- "message.kind === 'post'",
3888
- ""
3889
- ]
3890
- });
3891
- this._remoteStates.set(message.state.peerId, message.state);
3892
- this.remoteStateChange.emit();
3893
- }
3894
- };
3895
-
3896
- // packages/ui/react-ui-editor/src/hooks/useActionHandler.ts
3897
- var useActionHandler = (view) => {
3898
- return (action) => {
3899
- if (!view) {
3900
- return;
3865
+ setView(view2);
3866
+ if (moveToEndOfLine) {
3867
+ const { to } = view2.state.doc.lineAt(0);
3868
+ view2?.dispatch({
3869
+ selection: {
3870
+ anchor: to
3871
+ }
3872
+ });
3901
3873
  }
3902
- let inlineType, listType;
3903
- switch (action.type) {
3904
- case "heading":
3905
- setHeading(parseInt(action.data))(view);
3906
- break;
3907
- case "strong":
3908
- case "emphasis":
3909
- case "strikethrough":
3910
- case "code":
3911
- inlineType = action.type === "strong" ? Inline.Strong : action.type === "emphasis" ? Inline.Emphasis : action.type === "strikethrough" ? Inline.Strikethrough : Inline.Code;
3912
- (typeof action.data === "boolean" ? setStyle(inlineType, action.data) : toggleStyle(inlineType))(view);
3913
- break;
3914
- case "list-ordered":
3915
- case "list-bullet":
3916
- case "list-task":
3917
- listType = action.type === "list-ordered" ? List.Ordered : action.type === "list-bullet" ? List.Bullet : List.Task;
3918
- (action.data === false ? removeList(listType) : action.data === true ? addList(listType) : toggleList(listType))(view);
3919
- break;
3920
- case "blockquote":
3921
- (action.data === false ? removeBlockquote : action.data === true ? addBlockquote : toggleBlockquote)(view);
3922
- break;
3923
- case "codeblock":
3924
- (action.data === false ? removeCodeblock : addCodeblock)(view);
3925
- break;
3926
- case "table":
3927
- insertTable(view);
3928
- break;
3929
- case "link":
3930
- (action.data === false ? removeLink : addLink)(view);
3931
- break;
3932
- case "comment":
3933
- createComment(view);
3934
- break;
3874
+ if (state.facet(editorMode).noTabster) {
3875
+ rootRef.current?.removeAttribute("data-tabster");
3935
3876
  }
3936
- setTimeout(() => {
3937
- if (!view.hasFocus) {
3938
- view.focus();
3939
- }
3940
- });
3941
- };
3942
- };
3943
-
3944
- // packages/ui/react-ui-editor/src/hooks/useEditorView.ts
3945
- import { useRef, useState as useState2 } from "react";
3946
- var useEditorView = (id) => {
3947
- const editorRef = useRef(null);
3948
- const [prev, setPrev] = useState2([
3949
- null,
3950
- ""
3877
+ return () => {
3878
+ view2?.destroy();
3879
+ setView(null);
3880
+ };
3881
+ }, [
3882
+ doc,
3883
+ selection,
3884
+ extensions
3951
3885
  ]);
3952
- if (prev[0] !== editorRef.current) {
3953
- setPrev([
3954
- editorRef.current,
3955
- id
3956
- ]);
3957
- }
3958
- return [
3959
- editorRef,
3960
- prev[1] !== id
3961
- ];
3962
- };
3963
-
3964
- // packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
3965
- import { closeBrackets as closeBrackets2 } from "@codemirror/autocomplete";
3966
- import { history as history2 } from "@codemirror/commands";
3967
- import { bracketMatching as bracketMatching2 } from "@codemirror/language";
3968
- import { EditorSelection as EditorSelection2, EditorState as EditorState2 } from "@codemirror/state";
3969
- import { crosshairCursor, drawSelection as drawSelection2, dropCursor as dropCursor2, EditorView as EditorView16, highlightActiveLine, lineNumbers, placeholder as placeholder2, scrollPastEnd } from "@codemirror/view";
3970
- import defaultsDeep2 from "lodash.defaultsdeep";
3971
- import { useEffect as useEffect2, useRef as useRef2, useState as useState3 } from "react";
3972
- import { log as log8 } from "@dxos/log";
3973
- import { isNotFalsy as isNotFalsy3 } from "@dxos/util";
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
+ });
3974
3907
 
3975
- // packages/ui/react-ui-editor/src/themes/default.ts
3976
- import get4 from "lodash.get";
3977
- var defaultTheme = {
3978
- //
3979
- // Main layout:
3980
- // https://codemirror.net/examples/styling
3981
- //
3982
- // <div class="cm-editor [cm-focused] [generated classes]">
3983
- // <div class="cm-scroller">
3984
- // <div class="cm-gutters">
3985
- // <div class="cm-gutter [...]">
3986
- // <div class="cm-gutterElement">...</div>
3987
- // </div>
3988
- // </div>
3989
- // <div class="cm-content" role="textbox" contenteditable="true">
3990
- // <div class="cm-line"></div>
3991
- // </div>
3992
- // <div class="cm-selectionLayer">
3993
- // <div class="cm-selectionBackground"></div>
3994
- // </div>
3995
- // <div class="cm-cursorLayer">
3996
- // <div class="cm-cursor"></div>
3997
- // </div>
3998
- // </div>
3999
- // </div>
4000
- //
4001
- "&": {},
4002
- "&.cm-focused": {
4003
- outline: "none"
4004
- },
4005
- // NOTE: See https://codemirror.net/docs/guide (DOM Structure).
4006
- ".cm-scroller": {
4007
- // TODO(burdon): Reconcile with docs: https://codemirror.net/docs/guide
4008
- // 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.
4009
- overflowY: "auto",
4010
- fontFamily: get4(tokens, "fontFamily.mono", []).join(","),
4011
- lineHeight: 1.5
4012
- },
4013
- ".cm-content": {
4014
- // TODO(burdon): Is it possible to remove the padding value from CM's default theme?
4015
- // padding: 'unset',
4016
- // NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
4017
- fontSize: "16px"
4018
- },
4019
- "&light .cm-content": {
4020
- color: get4(tokens, "extend.semanticColors.base.fg.light", "black"),
4021
- caretColor: "black"
4022
- },
4023
- "&dark .cm-content": {
4024
- color: get4(tokens, "extend.semanticColors.base.fg.dark", "white"),
4025
- caretColor: "white"
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
4026
4040
  },
4027
- //
4028
- // Cursor
4029
- //
4030
- "&light .cm-cursor, &light .cm-dropCursor": {
4031
- borderLeft: "2px solid black"
4041
+ {
4042
+ type: "emphasis",
4043
+ Icon: TextItalic,
4044
+ getState: (state) => state.emphasis
4032
4045
  },
4033
- "&dark .cm-cursor, &dark .cm-dropCursor": {
4034
- borderLeft: "2px solid white"
4046
+ {
4047
+ type: "strikethrough",
4048
+ Icon: TextStrikethrough,
4049
+ getState: (state) => state.strikethrough
4035
4050
  },
4036
- "&light .cm-placeholder": {
4037
- color: get4(tokens, "extend.semanticColors.description.light", "rgba(0,0,0,.2)")
4051
+ {
4052
+ type: "code",
4053
+ Icon: Code,
4054
+ getState: (state) => state.code
4038
4055
  },
4039
- "&dark .cm-placeholder": {
4040
- color: get4(tokens, "extend.semanticColors.description.dark", "rgba(255,255,255,.2)")
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`))));
4078
+ };
4079
+ var markdownLists = [
4080
+ {
4081
+ type: "list-bullet",
4082
+ Icon: ListBullets,
4083
+ getState: (state) => state.listStyle === "bullet"
4041
4084
  },
4042
- //
4043
- // line
4044
- //
4045
- ".cm-line": {
4046
- paddingInline: 0
4085
+ {
4086
+ type: "list-ordered",
4087
+ Icon: ListNumbers,
4088
+ getState: (state) => state.listStyle === "ordered"
4047
4089
  },
4048
- ".cm-activeLine": {
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`))));
4111
+ };
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`))));
4147
+ };
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);
4152
+ return /* @__PURE__ */ React2.createElement(Tooltip.Root, null, /* @__PURE__ */ React2.createElement(Tooltip.Trigger, {
4153
+ asChild: true
4154
+ }, /* @__PURE__ */ React2.createElement(NaturalToolbar.Button, {
4155
+ variant: "ghost",
4156
+ "data-testid": "editor.toolbar.comment",
4157
+ onClick: () => onAction?.({
4158
+ type: "comment"
4159
+ }),
4160
+ classNames: buttonStyles
4161
+ }, /* @__PURE__ */ React2.createElement(ChatText, {
4162
+ className: iconStyles
4163
+ }), /* @__PURE__ */ React2.createElement("span", {
4164
+ 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
4173
+ };
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
+ }
4277
+ };
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": {
4049
4367
  background: "transparent"
4050
4368
  },
4051
4369
  //
@@ -4058,36 +4376,36 @@ var defaultTheme = {
4058
4376
  // Selection
4059
4377
  //
4060
4378
  "&light .cm-selectionBackground": {
4061
- background: get4(tokens, "extend.colors.primary.100")
4379
+ background: get3(tokens, "extend.colors.primary.100")
4062
4380
  },
4063
4381
  "&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
4064
- background: get4(tokens, "extend.colors.primary.200")
4382
+ background: get3(tokens, "extend.colors.primary.200")
4065
4383
  },
4066
4384
  "&dark .cm-selectionBackground": {
4067
- background: get4(tokens, "extend.colors.primary.700")
4385
+ background: get3(tokens, "extend.colors.primary.700")
4068
4386
  },
4069
4387
  "&dark.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
4070
- background: get4(tokens, "extend.colors.primary.600")
4388
+ background: get3(tokens, "extend.colors.primary.600")
4071
4389
  },
4072
4390
  //
4073
4391
  // Search
4074
4392
  //
4075
4393
  "&light .cm-searchMatch": {
4076
- backgroundColor: get4(tokens, "extend.colors.yellow.100")
4394
+ backgroundColor: get3(tokens, "extend.colors.yellow.100")
4077
4395
  },
4078
4396
  "&dark .cm-searchMatch": {
4079
- backgroundColor: get4(tokens, "extend.colors.yellow.700")
4397
+ backgroundColor: get3(tokens, "extend.colors.yellow.700")
4080
4398
  },
4081
4399
  //
4082
4400
  // link
4083
4401
  //
4084
4402
  ".cm-link": {
4085
- color: get4(tokens, "extend.colors.primary.500"),
4403
+ color: get3(tokens, "extend.colors.primary.500"),
4086
4404
  textDecorationLine: "underline",
4087
4405
  textDecorationThickness: "1px",
4088
4406
  textUnderlineOffset: "2px",
4089
4407
  borderRadius: ".125rem",
4090
- fontFamily: get4(tokens, "fontFamily.body", []).join(",")
4408
+ fontFamily: get3(tokens, "fontFamily.body", []).join(",")
4091
4409
  },
4092
4410
  //
4093
4411
  // tooltip
@@ -4110,7 +4428,7 @@ var defaultTheme = {
4110
4428
  display: "none"
4111
4429
  },
4112
4430
  ".cm-completionLabel": {
4113
- fontFamily: get4(tokens, "fontFamily.body", []).join(",")
4431
+ fontFamily: get3(tokens, "fontFamily.body", []).join(",")
4114
4432
  },
4115
4433
  ".cm-completionMatchedText": {
4116
4434
  textDecoration: "none"
@@ -4119,15 +4437,15 @@ var defaultTheme = {
4119
4437
  // table
4120
4438
  //
4121
4439
  ".cm-table *": {
4122
- fontFamily: `${get4(tokens, "fontFamily.mono", []).join(",")} !important`,
4440
+ fontFamily: `${get3(tokens, "fontFamily.mono", []).join(",")} !important`,
4123
4441
  textDecoration: "none !important"
4124
4442
  },
4125
4443
  ".cm-table-head": {
4126
4444
  padding: "2px 16px 2px 0px",
4127
- borderBottom: `1px solid ${get4(tokens, "extend.colors.neutral.500")}`,
4445
+ borderBottom: `1px solid ${get3(tokens, "extend.colors.neutral.500")}`,
4128
4446
  fontWeight: 100,
4129
4447
  textAlign: "left",
4130
- color: get4(tokens, "extend.colors.neutral.500")
4448
+ color: get3(tokens, "extend.colors.neutral.500")
4131
4449
  },
4132
4450
  ".cm-table-cell": {
4133
4451
  padding: "2px 16px 2px 0px"
@@ -4174,738 +4492,265 @@ var defaultTheme = {
4174
4492
  * </div
4175
4493
  */
4176
4494
  ".cm-panels": {
4177
- border: `1px solid ${get4(tokens, "extend.colors.neutral.200")}`
4495
+ border: `1px solid ${get3(tokens, "extend.colors.neutral.200")}`
4178
4496
  },
4179
4497
  ".cm-panel": {
4180
- background: get4(tokens, "extend.colors.neutral.50"),
4181
- fontFamily: get4(tokens, "fontFamily.body", []).join(",")
4498
+ background: get3(tokens, "extend.colors.neutral.50"),
4499
+ fontFamily: get3(tokens, "fontFamily.body", []).join(",")
4182
4500
  },
4183
4501
  ".cm-button": {
4184
4502
  margin: "4px",
4185
- fontFamily: get4(tokens, "fontFamily.body", []).join(","),
4186
- background: get4(tokens, "extend.colors.neutral.100"),
4503
+ fontFamily: get3(tokens, "fontFamily.body", []).join(","),
4504
+ background: get3(tokens, "extend.colors.neutral.100"),
4187
4505
  backgroundImage: "none",
4188
4506
  border: "none",
4189
4507
  "&:hover": {
4190
- background: get4(tokens, "extend.colors.neutral.200")
4508
+ background: get3(tokens, "extend.colors.neutral.200")
4191
4509
  },
4192
4510
  "&:active": {
4193
- background: get4(tokens, "extend.colors.neutral.300"),
4194
- backgroundImage: "none"
4195
- }
4196
- },
4197
- ".cm-panel input[type=checkbox]": {
4198
- marginRight: "0.4rem !important"
4199
- }
4200
- };
4201
- var textTheme = {
4202
- ".cm-scroller": {
4203
- fontFamily: get4(tokens, "fontFamily.body", []).join(",")
4204
- },
4205
- ".cm-placeholder": {
4206
- fontFamily: get4(tokens, "fontFamily.body", []).join(",")
4207
- }
4208
- };
4209
- var markdownTheme = {
4210
- ".cm-scroller": {
4211
- fontFamily: get4(tokens, "fontFamily.body", []).join(",")
4212
- },
4213
- ".cm-placeholder": {
4214
- fontFamily: get4(tokens, "fontFamily.body", []).join(",")
4215
- }
4216
- };
4217
- var codeTheme = {
4218
- ".cm-scroller": {
4219
- fontFamily: get4(tokens, "fontFamily.mono", []).join(",")
4220
- },
4221
- ".cm-placeholder": {
4222
- fontFamily: get4(tokens, "fontFamily.mono", []).join(",")
4223
- }
4224
- };
4225
-
4226
- // packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
4227
- var __dxlog_file9 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
4228
- var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions } = {}, deps = []) => {
4229
- const onUpdate = useRef2();
4230
- const [view, setView] = useState3();
4231
- const parentRef = useRef2(null);
4232
- useEffect2(() => {
4233
- let view2;
4234
- if (parentRef.current) {
4235
- const state = EditorState2.create({
4236
- doc,
4237
- selection,
4238
- extensions: [
4239
- // TODO(burdon): Doesn't catch errors in keymap functions.
4240
- EditorView16.exceptionSink.of((err) => {
4241
- log8.catch(err, void 0, {
4242
- F: __dxlog_file9,
4243
- L: 70,
4244
- S: void 0,
4245
- C: (f, a) => f(...a)
4246
- });
4247
- }),
4248
- extensions,
4249
- EditorView16.updateListener.of(() => {
4250
- onUpdate.current?.();
4251
- })
4252
- ].filter(isNotFalsy3)
4253
- });
4254
- view2 = new EditorView16({
4255
- parent: parentRef.current,
4256
- scrollTo,
4257
- state,
4258
- // NOTE: Uncomment to debug/monitor all transactions.
4259
- // https://codemirror.net/docs/ref/#view.EditorView.dispatch
4260
- dispatchTransactions: (trs, view3) => {
4261
- if (debug) {
4262
- logChanges(trs);
4263
- }
4264
- view3.update(trs);
4265
- }
4266
- });
4267
- setView(view2);
4268
- }
4269
- return () => {
4270
- view2?.destroy();
4271
- };
4272
- }, deps);
4273
- useEffect2(() => {
4274
- if (view) {
4275
- if (!selection && !view.state.selection.main.anchor) {
4276
- selection = EditorSelection2.single(view.state.doc.line(1).to);
4277
- }
4278
- if (selection || scrollTo) {
4279
- onUpdate.current = () => {
4280
- onUpdate.current = void 0;
4281
- view.dispatch({
4282
- selection,
4283
- effects: scrollTo && [
4284
- scrollTo
4285
- ],
4286
- scrollIntoView: !scrollTo
4287
- });
4288
- };
4289
- }
4290
- if (autoFocus) {
4291
- view.focus();
4292
- }
4293
- }
4294
- }, [
4295
- view,
4296
- autoFocus,
4297
- selection,
4298
- scrollTo
4299
- ]);
4300
- return {
4301
- parentRef,
4302
- view
4303
- };
4304
- };
4305
- var defaults = {
4306
- bracketMatching: true,
4307
- closeBrackets: true,
4308
- drawSelection: true,
4309
- editable: true,
4310
- history: true,
4311
- lineWrapping: true
4312
- };
4313
- var createBasicExtensions = (_props) => {
4314
- const props = defaultsDeep2({}, _props, defaults);
4315
- return [
4316
- // TODO(burdon): Doesn't catch errors in keymap functions.
4317
- EditorView16.exceptionSink.of((err) => {
4318
- log8.catch(err, void 0, {
4319
- F: __dxlog_file9,
4320
- L: 167,
4321
- S: void 0,
4322
- C: (f, a) => f(...a)
4323
- });
4324
- }),
4325
- props.allowMultipleSelections && EditorState2.allowMultipleSelections.of(true),
4326
- props.bracketMatching && bracketMatching2(),
4327
- props.closeBrackets && closeBrackets2(),
4328
- props.crosshairCursor && crosshairCursor(),
4329
- props.dropCursor && dropCursor2(),
4330
- props.drawSelection && drawSelection2(),
4331
- props.highlightActiveLine && highlightActiveLine(),
4332
- props.history && history2(),
4333
- props.lineNumbers && lineNumbers(),
4334
- props.lineWrapping && EditorView16.lineWrapping,
4335
- props.placeholder && placeholder2(props.placeholder),
4336
- props.readonly && [
4337
- EditorState2.readOnly.of(true),
4338
- EditorView16.editable.of(false)
4339
- ],
4340
- props.scrollPastEnd && scrollPastEnd(),
4341
- props.tabSize && EditorState2.tabSize.of(props.tabSize)
4342
- ].filter(isNotFalsy3);
4343
- };
4344
- var createThemeExtensions = ({ theme, themeMode, slots } = {}) => {
4345
- return [
4346
- EditorView16.baseTheme(defaultTheme),
4347
- EditorView16.darkTheme.of(themeMode === "dark"),
4348
- theme && EditorView16.theme(theme),
4349
- slots?.editor?.className && EditorView16.editorAttributes.of({
4350
- class: slots.editor.className
4351
- }),
4352
- slots?.content?.className && EditorView16.contentAttributes.of({
4353
- class: slots.content.className
4354
- })
4355
- ].filter(isNotFalsy3);
4356
- };
4357
-
4358
- // packages/ui/react-ui-editor/src/hooks/useTextModel.ts
4359
- import get5 from "lodash.get";
4360
- import { useState as useState4, useMemo as useMemo2 } from "react";
4361
- import { generateName } from "@dxos/display-name";
4362
- import { getRawDoc } from "@dxos/echo-schema";
4363
- import { invariant as invariant3 } from "@dxos/invariant";
4364
- import { isAutomergeObject } from "@dxos/react-client/echo";
4365
- import { hueTokens } from "@dxos/react-ui-theme";
4366
- import { hexToHue } from "@dxos/util";
4367
- var __dxlog_file10 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
4368
- var useTextExtensions = ({ id, text, space, identity }) => {
4369
- const extensions = [
4370
- automerge(text)
4371
- ];
4372
- const peerId = identity?.identityKey.toHex();
4373
- const { cursorLightValue, cursorDarkValue } = hueTokens[identity?.profile?.data?.hue ?? hexToHue(peerId ?? "0")];
4374
- if (space && identity) {
4375
- const awarenessProvider2 = new SpaceAwarenessProvider({
4376
- space,
4377
- channel: `awareness.${id}`,
4378
- peerId: identity.identityKey.toHex(),
4379
- info: {
4380
- displayName: identity.profile?.displayName ?? generateName(identity.identityKey.toHex()),
4381
- color: cursorDarkValue,
4382
- lightColor: cursorLightValue
4383
- }
4384
- });
4385
- extensions.push(awareness(awarenessProvider2));
4386
- }
4387
- return extensions;
4388
- };
4389
- var useTextModel = (props) => useMemo2(() => createModel(props), Object.values(props));
4390
- var useInMemoryTextModel = ({ id, defaultContent }) => {
4391
- const [content, setContent] = useState4(defaultContent ?? "");
4392
- return {
4393
- id,
4394
- content,
4395
- text: () => content,
4396
- setContent
4397
- };
4398
- };
4399
- var createModel = ({ space, identity, text }) => {
4400
- if (!text) {
4401
- return void 0;
4402
- }
4403
- invariant3(isAutomergeObject(text), void 0, {
4404
- F: __dxlog_file10,
4405
- L: 89,
4406
- S: void 0,
4407
- A: [
4408
- "isAutomergeObject(text)",
4409
- ""
4410
- ]
4411
- });
4412
- const obj = text;
4413
- const doc = getRawDoc(obj, [
4414
- obj.field
4415
- ]);
4416
- const peerId = identity?.identityKey.toHex();
4417
- const { cursorLightValue, cursorDarkValue } = hueTokens[identity?.profile?.data?.hue ?? hexToHue(peerId ?? "0")];
4418
- const awarenessProvider2 = space && new SpaceAwarenessProvider({
4419
- space,
4420
- channel: `automerge.awareness.${obj.id}`,
4421
- info: {
4422
- displayName: identity ? identity.profile?.displayName ?? generateName(identity.identityKey.toHex()) : void 0,
4423
- color: cursorLightValue,
4424
- lightColor: cursorDarkValue
4425
- },
4426
- peerId: identity?.identityKey.toHex() ?? "Anonymous"
4427
- });
4428
- const extensions = [
4429
- automerge({
4430
- handle: doc.handle,
4431
- path: doc.path
4432
- })
4433
- ];
4434
- if (awarenessProvider2) {
4435
- extensions.push(awareness(awarenessProvider2));
4436
- }
4437
- return {
4438
- id: obj.id,
4439
- content: doc,
4440
- text: () => get5(doc.handle.docSync(), doc.path),
4441
- extension: extensions
4442
- };
4443
- };
4444
-
4445
- // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
4446
- var __dxlog_file11 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
4447
- var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo = EditorView17.scrollIntoView(0), moveToEndOfLine, selection, theme, slots = defaultSlots, extensions = [], scrollPastEnd: _scrollPastEnd, debug }, forwardedRef) => {
4448
- const tabsterDOMAttribute = useFocusableGroup({
4449
- tabBehavior: "limited"
4450
- });
4451
- const { themeMode } = useThemeContext();
4452
- const rootRef = useRef3(null);
4453
- const [view, setView] = useState5(null);
4454
- useImperativeHandle(forwardedRef, () => view, [
4455
- view
4456
- ]);
4457
- useEffect3(() => {
4458
- if (autoFocus) {
4459
- view?.focus();
4460
- }
4461
- }, [
4462
- view,
4463
- autoFocus
4464
- ]);
4465
- useEffect3(() => {
4466
- if (!model || !rootRef.current) {
4467
- return;
4468
- }
4469
- const state = EditorState3.create({
4470
- doc: typeof model.content === "string" ? model.content : DocAccessor.getValue(model.content),
4471
- selection,
4472
- extensions: [
4473
- // TODO(burdon): Doesn't catch errors in keymap functions.
4474
- EditorView17.exceptionSink.of((err) => {
4475
- log9.catch(err, void 0, {
4476
- F: __dxlog_file11,
4477
- L: 123,
4478
- S: void 0,
4479
- C: (f, a) => f(...a)
4480
- });
4481
- }),
4482
- // Theme.
4483
- // TODO(burdon): Make base theme configurable.
4484
- EditorView17.baseTheme(defaultTheme),
4485
- theme && EditorView17.theme(theme),
4486
- EditorView17.darkTheme.of(themeMode === "dark"),
4487
- slots.editor?.className && EditorView17.editorAttributes.of({
4488
- class: slots.editor.className
4489
- }),
4490
- slots.content?.className && EditorView17.contentAttributes.of({
4491
- class: slots.content.className
4492
- }),
4493
- // NOTE: Assumes default line height.
4494
- _scrollPastEnd && scrollPastEnd2(),
4495
- // Focus.
4496
- EditorView17.updateListener.of((update2) => {
4497
- update2.transactions.forEach((transaction) => {
4498
- if (transaction.isUserEvent("focus.container")) {
4499
- rootRef.current?.focus();
4500
- }
4501
- });
4502
- }),
4503
- // State.
4504
- EditorView17.editable.of(!readonly),
4505
- EditorState3.readOnly.of(!!readonly),
4506
- // Storage and replication.
4507
- // NOTE: This must come before user extensions.
4508
- model.extension,
4509
- // Custom.
4510
- ...extensions
4511
- ].filter(isNotFalsy4)
4512
- });
4513
- const view2 = new EditorView17({
4514
- state,
4515
- parent: rootRef.current,
4516
- scrollTo,
4517
- // NOTE: Uncomment to debug/monitor all transactions.
4518
- // https://codemirror.net/docs/ref/#view.EditorView.dispatch
4519
- dispatchTransactions: (trs, view3) => {
4520
- if (debug) {
4521
- logChanges(trs);
4522
- }
4523
- view3.update(trs);
4524
- }
4525
- });
4526
- setView(view2);
4527
- if (moveToEndOfLine) {
4528
- const { to } = view2.state.doc.lineAt(0);
4529
- view2?.dispatch({
4530
- selection: {
4531
- anchor: to
4532
- }
4533
- });
4534
- }
4535
- if (state.facet(editorMode).noTabster) {
4536
- rootRef.current.removeAttribute("data-tabster");
4537
- }
4538
- return () => {
4539
- view2?.destroy();
4540
- setView(null);
4541
- };
4542
- }, [
4543
- rootRef,
4544
- extensions,
4545
- model,
4546
- readonly,
4547
- themeMode
4548
- ]);
4549
- const handleKeyUp = useCallback((event) => {
4550
- const { key } = event;
4551
- switch (key) {
4552
- case "Enter": {
4553
- view?.focus();
4554
- break;
4555
- }
4556
- }
4557
- }, [
4558
- view
4559
- ]);
4560
- return /* @__PURE__ */ React.createElement("div", {
4561
- role: "none",
4562
- ref: rootRef,
4563
- key: model.id,
4564
- tabIndex: 0,
4565
- onKeyUp: handleKeyUp,
4566
- ...slots.root,
4567
- ...tabsterDOMAttribute
4568
- });
4569
- });
4570
- var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, lineWrapping = true, theme = textTheme, slots, extensions: _extensions, ...props }, forwardedRef) => {
4571
- const { themeMode } = useThemeContext();
4572
- const updatedSlots = defaultsDeep3({}, slots, defaultTextSlots);
4573
- const extensions = useMemo3(() => [
4574
- createBasicExtensions({
4575
- lineWrapping,
4576
- placeholder: placeholder3
4577
- }),
4578
- createThemeExtensions({
4579
- themeMode
4580
- }),
4581
- ..._extensions ?? []
4582
- ], [
4583
- themeMode,
4584
- placeholder3,
4585
- lineWrapping,
4586
- _extensions
4587
- ]);
4588
- return /* @__PURE__ */ React.createElement(BaseTextEditor, {
4589
- ref: forwardedRef,
4590
- readonly,
4591
- extensions,
4592
- theme,
4593
- slots: updatedSlots,
4594
- ...props
4595
- });
4596
- });
4597
- var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, theme = markdownTheme, slots, extensions: _extensions, ...props }, forwardedRef) => {
4598
- const { themeMode } = useThemeContext();
4599
- const updatedSlots = defaultsDeep3({}, slots, defaultMarkdownSlots);
4600
- const extensions = useMemo3(() => [
4601
- createMarkdownExtensions({
4602
- themeMode,
4603
- placeholder: placeholder3
4604
- }),
4605
- ..._extensions ?? []
4606
- ], [
4607
- themeMode,
4608
- placeholder3,
4609
- _extensions
4610
- ]);
4611
- return /* @__PURE__ */ React.createElement(BaseTextEditor, {
4612
- ref: forwardedRef,
4613
- readonly,
4614
- extensions,
4615
- theme,
4616
- slots: updatedSlots,
4617
- ...props
4618
- });
4619
- });
4620
- var defaultSlots = {
4621
- root: {
4622
- className: focusRing
4623
- },
4624
- editor: {
4625
- className: "bs-full"
4626
- }
4627
- };
4628
- var defaultTextSlots = {
4629
- ...defaultSlots
4630
- };
4631
- var defaultMarkdownSlots = {
4632
- ...defaultSlots
4633
- };
4634
-
4635
- // packages/ui/react-ui-editor/src/components/Toolbar/Toolbar.tsx
4636
- 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";
4637
- import { createContext } from "@radix-ui/react-context";
4638
- import React2, { useRef as useRef4, useState as useState6 } from "react";
4639
- import { DensityProvider, ElevationProvider, Select, Toolbar as NaturalToolbar, Tooltip, useTranslation } from "@dxos/react-ui";
4640
- import { getSize } from "@dxos/react-ui-theme";
4641
- var tooltipProps = {
4642
- side: "top",
4643
- classNames: "z-10"
4644
- };
4645
- var HeadingIcons = {
4646
- "0": Paragraph,
4647
- "1": TextHOne,
4648
- "2": TextHTwo,
4649
- "3": TextHThree,
4650
- "4": TextHFour,
4651
- "5": TextHFive,
4652
- "6": TextHSix
4653
- };
4654
- var [ToolbarContextProvider, useToolbarContext] = createContext("Toolbar");
4655
- var ToolbarRoot = ({ children, onAction, classNames, state }) => {
4656
- return /* @__PURE__ */ React2.createElement(ToolbarContextProvider, {
4657
- onAction,
4658
- state
4659
- }, /* @__PURE__ */ React2.createElement(DensityProvider, {
4660
- density: "fine"
4661
- }, /* @__PURE__ */ React2.createElement(ElevationProvider, {
4662
- elevation: "chrome"
4663
- }, /* @__PURE__ */ React2.createElement(NaturalToolbar.Root, {
4664
- classNames: [
4665
- "is-full shrink-0 overflow-x-auto p-1",
4666
- classNames
4667
- ]
4668
- }, children))));
4669
- };
4670
- var buttonStyles = "min-bs-0 p-2";
4671
- var iconStyles = getSize(5);
4672
- var ToolbarButton = ({ Icon, children, ...props }) => {
4673
- return /* @__PURE__ */ React2.createElement(Tooltip.Root, null, /* @__PURE__ */ React2.createElement(Tooltip.Trigger, {
4674
- asChild: true
4675
- }, /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroupItem, {
4676
- variant: "ghost",
4677
- ...props,
4678
- classNames: buttonStyles
4679
- }, /* @__PURE__ */ React2.createElement(Icon, {
4680
- className: iconStyles
4681
- }), /* @__PURE__ */ React2.createElement("span", {
4682
- className: "sr-only"
4683
- }, children))), /* @__PURE__ */ React2.createElement(Tooltip.Portal, null, /* @__PURE__ */ React2.createElement(Tooltip.Content, tooltipProps, children, /* @__PURE__ */ React2.createElement(Tooltip.Arrow, null))));
4684
- };
4685
- var ToolbarSeparator = () => /* @__PURE__ */ React2.createElement("div", {
4686
- role: "separator",
4687
- className: "grow"
4688
- });
4689
- var MarkdownHeading = () => {
4690
- const { t } = useTranslation(translationKey);
4691
- const { onAction, state } = useToolbarContext("MarkdownFormatting");
4692
- const blockType = state ? state.blockType : "paragraph";
4693
- const header = blockType && /heading(\d)/.exec(blockType);
4694
- const value = header ? header[1] : blockType === "paragraph" || !blockType ? "0" : void 0;
4695
- const HeadingIcon = HeadingIcons[value ?? "0"];
4696
- const suppressNextTooltip = useRef4(false);
4697
- const [tooltipOpen, setTooltipOpen] = useState6(false);
4698
- const [selectOpen, setSelectOpen] = useState6(false);
4699
- return /* @__PURE__ */ React2.createElement(Tooltip.Root, {
4700
- open: tooltipOpen,
4701
- onOpenChange: (nextOpen) => {
4702
- if (nextOpen && suppressNextTooltip.current) {
4703
- suppressNextTooltip.current = false;
4704
- return setTooltipOpen(false);
4705
- } else {
4706
- return setTooltipOpen(nextOpen);
4707
- }
4708
- }
4709
- }, /* @__PURE__ */ React2.createElement(Select.Root, {
4710
- disabled: value === null,
4711
- value: value ?? "0",
4712
- open: selectOpen,
4713
- onOpenChange: (nextOpen) => {
4714
- if (!nextOpen) {
4715
- suppressNextTooltip.current = true;
4716
- }
4717
- return setSelectOpen(nextOpen);
4718
- },
4719
- onValueChange: (value2) => onAction?.({
4720
- type: "heading",
4721
- data: parseInt(value2)
4722
- })
4723
- }, /* @__PURE__ */ React2.createElement(Tooltip.Trigger, {
4724
- asChild: true
4725
- }, /* @__PURE__ */ React2.createElement(NaturalToolbar.Button, {
4726
- asChild: true
4727
- }, /* @__PURE__ */ React2.createElement(Select.TriggerButton, {
4728
- variant: "ghost",
4729
- classNames: buttonStyles
4730
- }, /* @__PURE__ */ React2.createElement("span", {
4731
- className: "sr-only"
4732
- }, t("heading label")), /* @__PURE__ */ React2.createElement(HeadingIcon, {
4733
- className: iconStyles
4734
- })))), /* @__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, {
4735
- value: "0"
4736
- }, /* @__PURE__ */ React2.createElement(Paragraph, {
4737
- className: iconStyles
4738
- })), [
4739
- 1,
4740
- 2,
4741
- 3,
4742
- 4,
4743
- 5,
4744
- 6
4745
- ].map((level) => /* @__PURE__ */ React2.createElement(Select.Option, {
4746
- key: level,
4747
- value: String(level)
4748
- }, level === 1 && /* @__PURE__ */ React2.createElement(TextHOne, {
4749
- className: iconStyles
4750
- }), level === 2 && /* @__PURE__ */ React2.createElement(TextHTwo, {
4751
- className: iconStyles
4752
- }), level === 3 && /* @__PURE__ */ React2.createElement(TextHThree, {
4753
- className: iconStyles
4754
- }), level === 4 && /* @__PURE__ */ React2.createElement(TextHFour, {
4755
- className: iconStyles
4756
- }), level === 5 && /* @__PURE__ */ React2.createElement(TextHFive, {
4757
- className: iconStyles
4758
- }), level === 6 && /* @__PURE__ */ React2.createElement(TextHSix, {
4759
- className: iconStyles
4760
- })))), /* @__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))));
4761
- };
4762
- var markdownStyles = [
4763
- {
4764
- type: "strong",
4765
- Icon: TextB,
4766
- getState: (state) => state.strong
4767
- },
4768
- {
4769
- type: "emphasis",
4770
- Icon: TextItalic,
4771
- getState: (state) => state.emphasis
4772
- },
4773
- {
4774
- type: "strikethrough",
4775
- Icon: TextStrikethrough,
4776
- getState: (state) => state.strikethrough
4777
- },
4778
- {
4779
- type: "code",
4780
- Icon: Code,
4781
- getState: (state) => state.code
4782
- },
4783
- {
4784
- type: "link",
4785
- Icon: Link,
4786
- getState: (state) => state.link
4787
- }
4788
- ];
4789
- var MarkdownStyles = () => {
4790
- const { onAction, state } = useToolbarContext("MarkdownStyles");
4791
- const { t } = useTranslation(translationKey);
4792
- return /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroup, {
4793
- type: "multiple",
4794
- value: markdownStyles.filter(({ getState }) => state && getState(state)).map(({ type }) => type)
4795
- }, markdownStyles.map(({ type, getState, Icon }) => /* @__PURE__ */ React2.createElement(ToolbarButton, {
4796
- key: type,
4797
- value: type,
4798
- Icon,
4799
- disabled: state?.blockType === "codeblock",
4800
- onClick: state ? () => onAction?.({
4801
- type,
4802
- data: !getState(state)
4803
- }) : void 0
4804
- }, t(`${type} label`))));
4805
- };
4806
- var markdownLists = [
4807
- {
4808
- type: "list-bullet",
4809
- Icon: ListBullets,
4810
- getState: (state) => state.listStyle === "bullet"
4811
- },
4812
- {
4813
- type: "list-ordered",
4814
- Icon: ListNumbers,
4815
- getState: (state) => state.listStyle === "ordered"
4511
+ background: get3(tokens, "extend.colors.neutral.300"),
4512
+ backgroundImage: "none"
4513
+ }
4816
4514
  },
4817
- {
4818
- type: "list-task",
4819
- Icon: ListChecks,
4820
- getState: (state) => state.listStyle === "task"
4515
+ ".cm-panel input[type=checkbox]": {
4516
+ marginRight: "0.4rem !important"
4821
4517
  }
4822
- ];
4823
- var MarkdownLists = () => {
4824
- const { onAction, state } = useToolbarContext("MarkdownStyles");
4825
- const { t } = useTranslation(translationKey);
4826
- return /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroup, {
4827
- type: "single",
4828
- value: state?.listStyle ? `list-${state.listStyle}` : ""
4829
- }, markdownLists.map(({ type, getState, Icon }) => /* @__PURE__ */ React2.createElement(ToolbarButton, {
4830
- key: type,
4831
- value: type,
4832
- Icon,
4833
- onClick: state ? () => onAction?.({
4834
- type,
4835
- data: !getState(state)
4836
- }) : void 0
4837
- }, t(`${type} label`))));
4838
4518
  };
4839
- var markdownBlocks = [
4840
- {
4841
- type: "blockquote",
4842
- Icon: Quotes,
4843
- getState: (state) => state.blockQuote
4844
- },
4845
- {
4846
- type: "codeblock",
4847
- Icon: CodeBlock,
4848
- getState: (state) => state.blockType === "codeblock"
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);
4560
+ };
4561
+ var defaultSlots = {
4562
+ editor: {
4563
+ className: "w-full bs-full"
4849
4564
  },
4850
- {
4851
- type: "table",
4852
- Icon: Table2,
4853
- getState: (state) => state.blockType === "tablecell",
4854
- disabled: (state) => !state.blankLine
4565
+ content: {
4566
+ className: "!p-2"
4855
4567
  }
4856
- ];
4857
- var MarkdownBlocks = () => {
4858
- const { onAction, state } = useToolbarContext("MarkdownStyles");
4859
- const { t } = useTranslation(translationKey);
4860
- const value = markdownBlocks.find(({ getState }) => state && getState(state));
4861
- return /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroup, {
4862
- type: "single",
4863
- value: value?.type ?? ""
4864
- }, markdownBlocks.map(({ type, disabled, getState, Icon }) => /* @__PURE__ */ React2.createElement(ToolbarButton, {
4865
- key: type,
4866
- value: type,
4867
- Icon,
4868
- disabled: !state || disabled?.(state),
4869
- onClick: state ? () => onAction?.({
4870
- type,
4871
- data: !getState(state)
4872
- }) : void 0
4873
- }, t(`${type} label`))));
4874
4568
  };
4875
- 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));
4876
- var MarkdownExtended = () => {
4877
- const { onAction } = useToolbarContext("MarkdownStyles");
4878
- const { t } = useTranslation(translationKey);
4879
- return /* @__PURE__ */ React2.createElement(Tooltip.Root, null, /* @__PURE__ */ React2.createElement(Tooltip.Trigger, {
4880
- asChild: true
4881
- }, /* @__PURE__ */ React2.createElement(NaturalToolbar.Button, {
4882
- variant: "ghost",
4883
- "data-testid": "editor.toolbar.comment",
4884
- onClick: () => onAction?.({
4885
- type: "comment"
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
4886
4577
  }),
4887
- classNames: buttonStyles
4888
- }, /* @__PURE__ */ React2.createElement(ChatText, {
4889
- className: iconStyles
4890
- }), /* @__PURE__ */ React2.createElement("span", {
4891
- className: "sr-only"
4892
- }, t("comment label")))), /* @__PURE__ */ React2.createElement(Tooltip.Portal, null, /* @__PURE__ */ React2.createElement(Tooltip.Content, tooltipProps, t("comment label"), /* @__PURE__ */ React2.createElement(Tooltip.Arrow, null))));
4578
+ slots.content?.className && EditorView16.contentAttributes.of({
4579
+ class: slots.content.className
4580
+ })
4581
+ ].filter(isNotFalsy3);
4893
4582
  };
4894
- var Toolbar = {
4895
- Root: ToolbarRoot,
4896
- Button: ToolbarButton,
4897
- Separator: ToolbarSeparator,
4898
- Markdown: MarkdownStandard,
4899
- Extended: MarkdownExtended
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;
4603
+ };
4604
+ var useDocAccessor = (text) => {
4605
+ return useMemo2(() => ({
4606
+ id: text.id,
4607
+ doc: getTextContent(text),
4608
+ accessor: createDocAccessor(text)
4609
+ }), [
4610
+ text
4611
+ ]);
4612
+ };
4613
+
4614
+ // packages/ui/react-ui-editor/src/hooks/useActionHandler.ts
4615
+ var useActionHandler = (view) => {
4616
+ return (action) => {
4617
+ if (!view) {
4618
+ return;
4619
+ }
4620
+ let inlineType, listType;
4621
+ switch (action.type) {
4622
+ case "heading":
4623
+ setHeading(parseInt(action.data))(view);
4624
+ break;
4625
+ case "strong":
4626
+ case "emphasis":
4627
+ case "strikethrough":
4628
+ case "code":
4629
+ inlineType = action.type === "strong" ? Inline.Strong : action.type === "emphasis" ? Inline.Emphasis : action.type === "strikethrough" ? Inline.Strikethrough : Inline.Code;
4630
+ (typeof action.data === "boolean" ? setStyle(inlineType, action.data) : toggleStyle(inlineType))(view);
4631
+ break;
4632
+ case "list-ordered":
4633
+ case "list-bullet":
4634
+ case "list-task":
4635
+ listType = action.type === "list-ordered" ? List.Ordered : action.type === "list-bullet" ? List.Bullet : List.Task;
4636
+ (action.data === false ? removeList(listType) : action.data === true ? addList(listType) : toggleList(listType))(view);
4637
+ break;
4638
+ case "blockquote":
4639
+ (action.data === false ? removeBlockquote : action.data === true ? addBlockquote : toggleBlockquote)(view);
4640
+ break;
4641
+ case "codeblock":
4642
+ (action.data === false ? removeCodeblock : addCodeblock)(view);
4643
+ break;
4644
+ case "table":
4645
+ insertTable(view);
4646
+ break;
4647
+ case "link":
4648
+ (action.data === false ? removeLink : addLink)(view);
4649
+ break;
4650
+ case "comment":
4651
+ createComment(view);
4652
+ break;
4653
+ }
4654
+ setTimeout(() => {
4655
+ if (!view.hasFocus) {
4656
+ view.focus();
4657
+ }
4658
+ });
4659
+ };
4660
+ };
4661
+
4662
+ // packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
4663
+ import { EditorSelection as EditorSelection2, EditorState as EditorState3 } from "@codemirror/state";
4664
+ import { EditorView as EditorView17 } from "@codemirror/view";
4665
+ import { useEffect as useEffect3, useMemo as useMemo3, useRef as useRef3, useState as useState4 } from "react";
4666
+ import { log as log10 } from "@dxos/log";
4667
+ import { isNotFalsy as isNotFalsy4 } from "@dxos/util";
4668
+ var __dxlog_file12 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
4669
+ var useTextEditor = (cb = () => ({}), deps = []) => {
4670
+ let { id, doc, selection, extensions, autoFocus, scrollTo, debug } = useMemo3(cb, deps ?? []);
4671
+ const onUpdate = useRef3();
4672
+ const [view, setView] = useState4();
4673
+ const parentRef = useRef3(null);
4674
+ useEffect3(() => {
4675
+ let view2;
4676
+ if (parentRef.current) {
4677
+ const state = EditorState3.create({
4678
+ doc,
4679
+ selection,
4680
+ extensions: [
4681
+ id && documentId2.of(id),
4682
+ // TODO(burdon): Doesn't catch errors in keymap functions.
4683
+ EditorView17.exceptionSink.of((err) => {
4684
+ log10.catch(err, void 0, {
4685
+ F: __dxlog_file12,
4686
+ L: 44,
4687
+ S: void 0,
4688
+ C: (f, a) => f(...a)
4689
+ });
4690
+ }),
4691
+ extensions,
4692
+ EditorView17.updateListener.of(() => {
4693
+ onUpdate.current?.();
4694
+ })
4695
+ ].filter(isNotFalsy4)
4696
+ });
4697
+ view2 = new EditorView17({
4698
+ parent: parentRef.current,
4699
+ scrollTo,
4700
+ state,
4701
+ // NOTE: Uncomment to debug/monitor all transactions.
4702
+ // https://codemirror.net/docs/ref/#view.EditorView.dispatch
4703
+ dispatchTransactions: (trs, view3) => {
4704
+ if (debug) {
4705
+ logChanges(trs);
4706
+ }
4707
+ view3.update(trs);
4708
+ }
4709
+ });
4710
+ setView(view2);
4711
+ }
4712
+ return () => {
4713
+ view2?.destroy();
4714
+ };
4715
+ }, deps);
4716
+ useEffect3(() => {
4717
+ if (view) {
4718
+ if (!selection && !view.state.selection.main.anchor) {
4719
+ selection = EditorSelection2.single(view.state.doc.line(1).to);
4720
+ }
4721
+ if (selection || scrollTo) {
4722
+ onUpdate.current = () => {
4723
+ onUpdate.current = void 0;
4724
+ view.dispatch({
4725
+ selection,
4726
+ effects: scrollTo && [
4727
+ scrollTo
4728
+ ],
4729
+ scrollIntoView: !scrollTo
4730
+ });
4731
+ };
4732
+ }
4733
+ if (autoFocus) {
4734
+ view.focus();
4735
+ }
4736
+ }
4737
+ }, [
4738
+ view,
4739
+ autoFocus,
4740
+ selection,
4741
+ scrollTo
4742
+ ]);
4743
+ return {
4744
+ parentRef,
4745
+ view
4746
+ };
4900
4747
  };
4901
4748
  export {
4902
- BaseTextEditor,
4903
4749
  Cursor,
4904
4750
  Doc,
4905
4751
  EditorModes,
4906
4752
  Inline,
4907
4753
  List,
4908
- MarkdownEditor,
4909
4754
  RemoteSelectionsDecorator,
4910
4755
  SpaceAwarenessProvider,
4911
4756
  TextEditor,
@@ -4925,29 +4770,26 @@ export {
4925
4770
  awarenessProvider,
4926
4771
  blast,
4927
4772
  callbackWrapper,
4928
- codeTheme,
4929
4773
  command,
4930
4774
  comments,
4931
4775
  compareFormatting,
4932
4776
  createBasicExtensions,
4933
4777
  createComment,
4778
+ createDataExtensions,
4934
4779
  createMarkdownExtensions,
4935
4780
  createThemeExtensions,
4936
4781
  cursorLineMargin,
4937
- cursorLineMarginFacet,
4938
4782
  decorateMarkdown,
4939
- defaultMarkdownSlots,
4940
4783
  defaultOptions,
4941
- defaultSlots,
4942
- defaultTextSlots,
4943
4784
  defaultTheme,
4944
4785
  dnd,
4786
+ documentId2 as documentId,
4945
4787
  editorFillLayoutEditor,
4946
4788
  editorFillLayoutRoot,
4947
4789
  editorMode,
4948
4790
  editorWithToolbarLayout,
4949
4791
  focusComment,
4950
- formatting,
4792
+ formattingKeymap,
4951
4793
  getFormatting,
4952
4794
  getToken,
4953
4795
  image,
@@ -4959,9 +4801,7 @@ export {
4959
4801
  markdownHighlightStyle,
4960
4802
  markdownTags,
4961
4803
  markdownTagsExtensions,
4962
- markdownTheme,
4963
4804
  mention,
4964
- outliner,
4965
4805
  removeBlockquote,
4966
4806
  removeCodeblock,
4967
4807
  removeLink,
@@ -4974,7 +4814,6 @@ export {
4974
4814
  setStyle,
4975
4815
  table,
4976
4816
  tags2 as tags,
4977
- textTheme,
4978
4817
  toggleBlockquote,
4979
4818
  toggleCodeblock,
4980
4819
  toggleEmphasis,
@@ -4987,12 +4826,9 @@ export {
4987
4826
  typewriter,
4988
4827
  useActionHandler,
4989
4828
  useComments,
4990
- useEditorView,
4829
+ useDocAccessor,
4991
4830
  useFormattingState,
4992
- useInMemoryTextModel,
4993
4831
  useTextEditor,
4994
- useTextExtensions,
4995
- useTextModel,
4996
4832
  useToolbarContext
4997
4833
  };
4998
4834
  //# sourceMappingURL=index.mjs.map