@dxos/react-ui-editor 0.3.9-main.9ca5eac → 0.3.9-main.9da1d41

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 (149) hide show
  1. package/dist/lib/browser/index.mjs +654 -734
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/types/src/automerge/automerge-plugin/PatchSemaphore.d.ts +2 -2
  5. package/dist/types/src/automerge/automerge-plugin/PatchSemaphore.d.ts.map +1 -1
  6. package/dist/types/src/automerge/automerge-plugin/codeMirrorToAm.d.ts +2 -2
  7. package/dist/types/src/automerge/automerge-plugin/codeMirrorToAm.d.ts.map +1 -1
  8. package/dist/types/src/automerge/automerge-plugin/handle.d.ts +9 -0
  9. package/dist/types/src/automerge/automerge-plugin/handle.d.ts.map +1 -0
  10. package/dist/types/src/automerge/automerge-plugin/index.d.ts +2 -2
  11. package/dist/types/src/automerge/automerge-plugin/index.d.ts.map +1 -1
  12. package/dist/types/src/automerge/automerge-plugin/plugin.d.ts +6 -5
  13. package/dist/types/src/automerge/automerge-plugin/plugin.d.ts.map +1 -1
  14. package/dist/types/src/automerge/automerge.stories.d.ts +1 -0
  15. package/dist/types/src/automerge/automerge.stories.d.ts.map +1 -1
  16. package/dist/types/src/components/TextEditor/TextEditor.d.ts +24 -20
  17. package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
  18. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +2 -25
  19. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
  20. package/dist/types/{stories/html/code-mirror.stories.d.ts → src/components/TextEditor/codemirror.stories.d.ts} +2 -2
  21. package/dist/types/src/components/TextEditor/codemirror.stories.d.ts.map +1 -0
  22. package/dist/types/src/components/TextEditor/extensions/basic/bundle.d.ts +8 -0
  23. package/dist/types/src/components/TextEditor/extensions/basic/bundle.d.ts.map +1 -0
  24. package/dist/types/src/components/TextEditor/extensions/basic/index.d.ts +3 -0
  25. package/dist/types/src/components/TextEditor/extensions/basic/index.d.ts.map +1 -0
  26. package/dist/types/src/components/TextEditor/extensions/basic/theme.d.ts +10 -0
  27. package/dist/types/src/components/TextEditor/extensions/basic/theme.d.ts.map +1 -0
  28. package/dist/types/src/components/TextEditor/extensions/change.d.ts +7 -0
  29. package/dist/types/src/components/TextEditor/extensions/change.d.ts.map +1 -0
  30. package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkDecoration.d.ts +11 -0
  31. package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkDecoration.d.ts.map +1 -0
  32. package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkTooltip.d.ts.map +1 -0
  33. package/dist/types/src/components/TextEditor/extensions/{hyperlink.d.ts → hyperlink/hyperlinkWidget.d.ts} +3 -3
  34. package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkWidget.d.ts.map +1 -0
  35. package/dist/types/src/components/TextEditor/extensions/hyperlink/index.d.ts +4 -0
  36. package/dist/types/src/components/TextEditor/extensions/hyperlink/index.d.ts.map +1 -0
  37. package/dist/types/src/components/TextEditor/extensions/index.d.ts +3 -1
  38. package/dist/types/src/components/TextEditor/extensions/index.d.ts.map +1 -1
  39. package/dist/types/src/components/TextEditor/extensions/markdown/bundle.d.ts +8 -0
  40. package/dist/types/src/components/TextEditor/extensions/markdown/bundle.d.ts.map +1 -0
  41. package/dist/types/src/components/TextEditor/extensions/markdown/index.d.ts +3 -0
  42. package/dist/types/src/components/TextEditor/extensions/markdown/index.d.ts.map +1 -0
  43. package/dist/types/src/components/{Markdown/markdownTags.d.ts → TextEditor/extensions/markdown/tags.d.ts} +1 -1
  44. package/dist/types/src/components/TextEditor/extensions/markdown/tags.d.ts.map +1 -0
  45. package/dist/types/src/components/TextEditor/extensions/markdown/theme.d.ts +21 -0
  46. package/dist/types/src/components/TextEditor/extensions/markdown/theme.d.ts.map +1 -0
  47. package/dist/types/src/components/TextEditor/index.d.ts +1 -3
  48. package/dist/types/src/components/TextEditor/index.d.ts.map +1 -1
  49. package/dist/types/src/components/TextEditor/yjs.stories.d.ts +11 -0
  50. package/dist/types/src/components/TextEditor/yjs.stories.d.ts.map +1 -0
  51. package/dist/types/src/components/index.d.ts +0 -3
  52. package/dist/types/src/components/index.d.ts.map +1 -1
  53. package/dist/types/src/hooks/index.d.ts +4 -0
  54. package/dist/types/src/hooks/index.d.ts.map +1 -0
  55. package/dist/types/src/hooks/useCollaboration.d.ts +9 -0
  56. package/dist/types/src/hooks/useCollaboration.d.ts.map +1 -0
  57. package/dist/types/src/{model.d.ts → hooks/useTextModel.d.ts} +1 -13
  58. package/dist/types/src/hooks/useTextModel.d.ts.map +1 -0
  59. package/dist/types/src/hooks/yjs/cursors.d.ts.map +1 -0
  60. package/dist/types/src/hooks/yjs/index.d.ts.map +1 -0
  61. package/dist/types/src/hooks/yjs/space-provider.d.ts.map +1 -0
  62. package/dist/types/src/index.d.ts +2 -2
  63. package/dist/types/src/index.d.ts.map +1 -1
  64. package/dist/types/src/styles/tokens.d.ts +4 -0
  65. package/dist/types/src/styles/tokens.d.ts.map +1 -1
  66. package/dist/types/src/testing/replicator.d.ts +1 -1
  67. package/dist/types/src/testing/replicator.d.ts.map +1 -1
  68. package/package.json +30 -27
  69. package/src/automerge/automerge-plugin/PatchSemaphore.ts +5 -5
  70. package/src/automerge/automerge-plugin/codeMirrorToAm.ts +10 -7
  71. package/src/automerge/automerge-plugin/handle.ts +14 -0
  72. package/src/automerge/automerge-plugin/index.ts +2 -2
  73. package/src/automerge/automerge-plugin/plugin.ts +39 -10
  74. package/src/automerge/automerge.stories.tsx +31 -46
  75. package/src/components/TextEditor/TextEditor.stories.tsx +43 -65
  76. package/src/components/TextEditor/TextEditor.tsx +108 -56
  77. package/src/components/TextEditor/codemirror.stories.ts +114 -0
  78. package/src/components/TextEditor/extensions/basic/bundle.ts +26 -0
  79. package/src/components/TextEditor/extensions/basic/index.ts +6 -0
  80. package/src/components/TextEditor/extensions/basic/theme.ts +49 -0
  81. package/src/components/TextEditor/extensions/change.ts +22 -0
  82. package/src/components/TextEditor/extensions/hyperlink/hyperlinkDecoration.ts +99 -0
  83. package/src/components/TextEditor/extensions/{hyperlinkTooltip.tsx → hyperlink/hyperlinkTooltip.tsx} +1 -0
  84. package/src/components/TextEditor/extensions/{hyperlink.tsx → hyperlink/hyperlinkWidget.tsx} +21 -10
  85. package/src/components/TextEditor/extensions/hyperlink/index.ts +7 -0
  86. package/src/components/TextEditor/extensions/index.ts +3 -1
  87. package/src/components/TextEditor/extensions/markdown/bundle.ts +99 -0
  88. package/src/components/TextEditor/extensions/markdown/index.ts +6 -0
  89. package/src/components/{Markdown/markdownTheme.ts → TextEditor/extensions/markdown/theme.ts} +23 -12
  90. package/src/components/TextEditor/index.ts +1 -4
  91. package/src/components/TextEditor/yjs.stories.tsx +55 -0
  92. package/src/components/index.ts +0 -3
  93. package/src/hooks/index.ts +7 -0
  94. package/src/hooks/useCollaboration.ts +35 -0
  95. package/src/{model.ts → hooks/useTextModel.ts} +4 -14
  96. package/src/index.ts +3 -3
  97. package/src/styles/tokens.ts +6 -0
  98. package/src/testing/replicator.ts +1 -2
  99. package/dist/types/src/automerge/demo.d.ts +0 -25
  100. package/dist/types/src/automerge/demo.d.ts.map +0 -1
  101. package/dist/types/src/components/Editor/Editor.d.ts +0 -15
  102. package/dist/types/src/components/Editor/Editor.d.ts.map +0 -1
  103. package/dist/types/src/components/Editor/Editor.stories.d.ts +0 -29
  104. package/dist/types/src/components/Editor/Editor.stories.d.ts.map +0 -1
  105. package/dist/types/src/components/Editor/index.d.ts +0 -2
  106. package/dist/types/src/components/Editor/index.d.ts.map +0 -1
  107. package/dist/types/src/components/Markdown/Markdown.d.ts +0 -20
  108. package/dist/types/src/components/Markdown/Markdown.d.ts.map +0 -1
  109. package/dist/types/src/components/Markdown/Markdown.stories.d.ts +0 -20
  110. package/dist/types/src/components/Markdown/Markdown.stories.d.ts.map +0 -1
  111. package/dist/types/src/components/Markdown/index.d.ts +0 -2
  112. package/dist/types/src/components/Markdown/index.d.ts.map +0 -1
  113. package/dist/types/src/components/Markdown/markdownTags.d.ts.map +0 -1
  114. package/dist/types/src/components/Markdown/markdownTheme.d.ts +0 -93
  115. package/dist/types/src/components/Markdown/markdownTheme.d.ts.map +0 -1
  116. package/dist/types/src/components/RichText/RichText.d.ts +0 -20
  117. package/dist/types/src/components/RichText/RichText.d.ts.map +0 -1
  118. package/dist/types/src/components/RichText/RichText.stories.d.ts +0 -27
  119. package/dist/types/src/components/RichText/RichText.stories.d.ts.map +0 -1
  120. package/dist/types/src/components/RichText/index.d.ts +0 -2
  121. package/dist/types/src/components/RichText/index.d.ts.map +0 -1
  122. package/dist/types/src/components/TextEditor/extensions/hyperlink.d.ts.map +0 -1
  123. package/dist/types/src/components/TextEditor/extensions/hyperlinkTooltip.d.ts.map +0 -1
  124. package/dist/types/src/components/TextEditor/theme.d.ts +0 -8
  125. package/dist/types/src/components/TextEditor/theme.d.ts.map +0 -1
  126. package/dist/types/src/model.d.ts.map +0 -1
  127. package/dist/types/src/yjs/cursors.d.ts.map +0 -1
  128. package/dist/types/src/yjs/index.d.ts.map +0 -1
  129. package/dist/types/src/yjs/space-provider.d.ts.map +0 -1
  130. package/dist/types/stories/html/code-mirror.stories.d.ts.map +0 -1
  131. package/src/automerge/demo.ts +0 -106
  132. package/src/components/Editor/Editor.stories.tsx +0 -82
  133. package/src/components/Editor/Editor.tsx +0 -33
  134. package/src/components/Editor/index.ts +0 -5
  135. package/src/components/Markdown/Markdown.stories.tsx +0 -59
  136. package/src/components/Markdown/Markdown.tsx +0 -214
  137. package/src/components/Markdown/index.ts +0 -5
  138. package/src/components/RichText/RichText.stories.tsx +0 -70
  139. package/src/components/RichText/RichText.tsx +0 -181
  140. package/src/components/RichText/index.ts +0 -5
  141. package/src/components/TextEditor/theme.ts +0 -33
  142. /package/dist/types/src/components/TextEditor/extensions/{hyperlinkTooltip.d.ts → hyperlink/hyperlinkTooltip.d.ts} +0 -0
  143. /package/dist/types/src/{yjs → hooks/yjs}/cursors.d.ts +0 -0
  144. /package/dist/types/src/{yjs → hooks/yjs}/index.d.ts +0 -0
  145. /package/dist/types/src/{yjs → hooks/yjs}/space-provider.d.ts +0 -0
  146. /package/src/components/{Markdown/markdownTags.ts → TextEditor/extensions/markdown/tags.ts} +0 -0
  147. /package/src/{yjs → hooks/yjs}/cursors.ts +0 -0
  148. /package/src/{yjs → hooks/yjs}/index.ts +0 -0
  149. /package/src/{yjs → hooks/yjs}/space-provider.ts +0 -0
@@ -1,199 +1,305 @@
1
- // packages/ui/react-ui-editor/src/components/Editor/Editor.tsx
2
- import React3, { forwardRef as forwardRef3, memo } from "react";
3
- import { YXmlFragment } from "@dxos/text-model";
1
+ // packages/ui/react-ui-editor/src/index.ts
2
+ import { TextKind } from "@dxos/protocols/proto/dxos/echo/model/text";
3
+ import { Doc, YText as YText2, YXmlFragment } from "@dxos/text-model";
4
4
 
5
- // packages/ui/react-ui-editor/src/model.ts
6
- import { useMemo } from "react";
5
+ // packages/ui/react-ui-editor/src/components/TextEditor/index.ts
6
+ import { tags as tags2 } from "@lezer/highlight";
7
7
 
8
- // packages/ui/react-ui-editor/src/yjs/cursors.ts
9
- import * as random from "lib0/random";
10
- var cursorColors = [
11
- {
12
- color: "#30bced",
13
- light: "#30bced33"
8
+ // packages/ui/react-ui-editor/src/components/TextEditor/extensions/basic/bundle.ts
9
+ import { closeBrackets } from "@codemirror/autocomplete";
10
+ import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
11
+ import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
12
+ import { placeholder } from "@codemirror/view";
13
+ var basicBundle = ({ themeMode, placeholder: _placeholder }) => [
14
+ bracketMatching(),
15
+ closeBrackets(),
16
+ _placeholder && placeholder(_placeholder),
17
+ // TODO(burdon): Is this required?
18
+ themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)
19
+ ].filter(Boolean);
20
+
21
+ // packages/ui/react-ui-editor/src/components/TextEditor/extensions/basic/theme.ts
22
+ import get from "lodash.get";
23
+
24
+ // packages/ui/react-ui-editor/src/styles/markdown.ts
25
+ import { mx } from "@dxos/react-ui-theme";
26
+ var heading = {
27
+ 1: "mbs-4 mbe-2 text-4xl font-semibold text-inherit no-underline",
28
+ 2: "mbs-4 mbe-2 text-3xl font-bold text-inherit no-underline",
29
+ 3: "mbs-4 mbe-2 text-2xl font-bold text-inherit no-underline",
30
+ 4: "mbs-4 mbe-2 text-xl font-extrabold text-inherit no-underline",
31
+ 5: "mbs-4 mbe-2 text-lg font-extrabold text-inherit no-underline",
32
+ 6: "mbs-4 mbe-2 font-black text-inherit no-underline"
33
+ };
34
+ var bold = "font-bold";
35
+ var code = "font-mono bg-neutral-500/10 rounded pli-0.5 plb-0.5 -mlb-0.5";
36
+ var codeWithoutMarks = mx(code, "pli-1.5 mli-0.5");
37
+ var italic = "italic";
38
+ var strikethrough = "line-through";
39
+ var mark = "!font-normal !no-underline !text-inherit opacity-40";
40
+
41
+ // packages/ui/react-ui-editor/src/styles/tokens.ts
42
+ import { tailwindConfig } from "@dxos/react-ui-theme";
43
+ var tokens = tailwindConfig({}).theme;
44
+
45
+ // packages/ui/react-ui-editor/src/components/TextEditor/extensions/basic/theme.ts
46
+ var basicTheme = {
47
+ "&.cm-focused": {
48
+ outline: "none"
14
49
  },
15
- {
16
- color: "#6eeb83",
17
- light: "#6eeb8333"
50
+ "& .cm-line": {
51
+ paddingInline: 0,
52
+ lineHeight: 1.6,
53
+ minBlockSize: "1.6em"
18
54
  },
19
- {
20
- color: "#ffbc42",
21
- light: "#ffbc4233"
55
+ "& .cm-line *": {
56
+ lineHeight: 1.6
22
57
  },
23
- {
24
- color: "#ecd444",
25
- light: "#ecd44433"
58
+ "& .cm-scroller": {
59
+ fontFamily: get(tokens, "fontFamily.body", []).join(","),
60
+ overflow: "visible"
26
61
  },
27
- {
28
- color: "#ee6352",
29
- light: "#ee635233"
62
+ "& .cm-content": {
63
+ padding: 0,
64
+ caretColor: "black"
30
65
  },
31
- {
32
- color: "#9ac2c9",
33
- light: "#9ac2c933"
66
+ ".dark & .cm-content": {
67
+ caretColor: "white"
34
68
  },
35
- {
36
- color: "#8acb88",
37
- light: "#8acb8833"
69
+ "& .cm-tooltip": {
70
+ backgroundColor: "transparent",
71
+ border: "none"
38
72
  },
39
- {
40
- color: "#1be7ff",
41
- light: "#1be7ff33"
73
+ "& .cm-link": {
74
+ color: get(tokens, "extend.colors.primary.500"),
75
+ textDecoration: "underline"
42
76
  }
43
- ];
44
- var cursorColor = cursorColors[random.uint32() % cursorColors.length];
77
+ };
45
78
 
46
- // packages/ui/react-ui-editor/src/yjs/space-provider.ts
47
- import * as decoding from "lib0/decoding";
48
- import * as encoding from "lib0/encoding";
49
- import { Observable } from "lib0/observable";
50
- import * as awarenessProtocol from "y-protocols/awareness";
51
- import { log } from "@dxos/log";
52
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/yjs/space-provider.ts";
53
- var messageAwareness = 1;
54
- var messageQueryAwareness = 3;
55
- var SpaceAwarenessProvider = class extends Observable {
56
- constructor({ space, doc, channel, awareness }) {
57
- super();
58
- this._space = space;
59
- this._awareness = awareness ?? new awarenessProtocol.Awareness(doc);
60
- this._channel = channel;
61
- this._clientId = doc.clientID;
62
- this._awareness.on("update", this._handleAwarenessUpdate.bind(this));
63
- this._space.listen(this._channel, this._handleSpaceMessage.bind(this));
64
- if (typeof window !== "undefined") {
65
- window.addEventListener("beforeunload", this._handleBeforeUnload.bind(this));
66
- } else if (typeof process !== "undefined") {
67
- process.on("exit", this._handleBeforeUnload.bind(this));
79
+ // packages/ui/react-ui-editor/src/components/TextEditor/extensions/change.ts
80
+ import { StateField } from "@codemirror/state";
81
+ var onChangeExtension = (onChange) => StateField.define({
82
+ create: () => null,
83
+ update: (_value, transaction) => {
84
+ if (transaction.docChanged && onChange) {
85
+ onChange(transaction.newDoc.toString());
68
86
  }
69
- const encoderAwarenessQuery = encoding.createEncoder();
70
- encoding.writeVarUint(encoderAwarenessQuery, messageQueryAwareness);
71
- void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessQuery));
72
- const encoderAwarenessState = encoding.createEncoder();
73
- encoding.writeVarUint(encoderAwarenessState, messageAwareness);
74
- encoding.writeVarUint8Array(encoderAwarenessState, awarenessProtocol.encodeAwarenessUpdate(this.awareness, [
75
- this._clientId
76
- ]));
77
- void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessState));
87
+ return null;
78
88
  }
79
- get awareness() {
80
- return this._awareness;
89
+ });
90
+
91
+ // packages/ui/react-ui-editor/src/components/TextEditor/extensions/hyperlink/hyperlinkDecoration.ts
92
+ import { syntaxTree } from "@codemirror/language";
93
+ import { RangeSetBuilder, StateField as StateField2 } from "@codemirror/state";
94
+ import { Decoration, EditorView, WidgetType } from "@codemirror/view";
95
+ var Link = class extends WidgetType {
96
+ constructor(_anchor, _text, _url) {
97
+ super();
98
+ this._anchor = _anchor;
99
+ this._text = _text;
100
+ this._url = _url;
81
101
  }
82
- _handleAwarenessUpdate({ added, updated, removed }, origin) {
83
- log("awareness update", {
84
- added,
85
- updated,
86
- removed,
87
- origin
88
- }, {
89
- F: __dxlog_file,
90
- L: 67,
91
- S: this,
92
- C: (f, a) => f(...a)
93
- });
94
- const changedClients = added.concat(updated).concat(removed);
95
- const encoderAwareness = encoding.createEncoder();
96
- encoding.writeVarUint(encoderAwareness, messageAwareness);
97
- encoding.writeVarUint8Array(encoderAwareness, awarenessProtocol.encodeAwarenessUpdate(this._awareness, changedClients));
98
- void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwareness));
102
+ eq(other) {
103
+ return this._text === other.text && this._url === other.url;
99
104
  }
100
- _handleSpaceMessage({ payload }) {
101
- log("space message", payload, {
102
- F: __dxlog_file,
103
- L: 79,
104
- S: this,
105
- C: (f, a) => f(...a)
106
- });
107
- const data = new Uint8Array(Array.from(Object.values(payload)));
108
- const encoder = this._readMessage(data);
109
- if (encoder) {
110
- void this._space.postMessage(this._channel, encoding.toUint8Array(encoder));
105
+ toDOM(view) {
106
+ const link = document.createElement("a");
107
+ link.setAttribute("class", "cm-link");
108
+ link.textContent = this._text;
109
+ if (this._url) {
110
+ link.setAttribute("target", "_blank");
111
+ link.href = this._url;
112
+ } else {
113
+ link.onclick = () => {
114
+ view.dispatch({
115
+ selection: {
116
+ anchor: this._anchor
117
+ }
118
+ });
119
+ };
111
120
  }
121
+ return link;
112
122
  }
113
- _readMessage(message) {
114
- const decoder = decoding.createDecoder(message);
115
- const encoder = encoding.createEncoder();
116
- const messageType = decoding.readVarUint(decoder);
117
- let sendReply = false;
118
- switch (messageType) {
119
- case messageAwareness: {
120
- awarenessProtocol.applyAwarenessUpdate(this._awareness, decoding.readVarUint8Array(decoder), this);
121
- break;
122
- }
123
- case messageQueryAwareness: {
124
- encoding.writeVarUint(encoder, messageAwareness);
125
- encoding.writeVarUint8Array(encoder, awarenessProtocol.encodeAwarenessUpdate(this._awareness, Array.from(this._awareness.getStates().keys())));
126
- sendReply = true;
127
- break;
128
- }
129
- default: {
130
- console.error("Invalid message:", messageType);
131
- return encoder;
123
+ };
124
+ var hyperlinkDecoration = ({ link } = {}) => {
125
+ return StateField2.define({
126
+ create: (state) => update(state, link),
127
+ update: (_, tr) => update(tr.state, link),
128
+ provide: (field) => EditorView.decorations.from(field)
129
+ });
130
+ };
131
+ var update = (state, link) => {
132
+ const builder = new RangeSetBuilder();
133
+ const cursor = state.selection.main.head;
134
+ syntaxTree(state).iterate({
135
+ enter: (node) => {
136
+ if (cursor < node.from || cursor > node.to) {
137
+ if (node.name === "Link") {
138
+ const marks = node.node.getChildren("LinkMark");
139
+ const text = marks.length >= 2 ? state.sliceDoc(marks[0].to, marks[1].from) : "";
140
+ const urlNode = node.node.getChild("URL");
141
+ const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
142
+ builder.add(node.from, node.to, Decoration.replace({
143
+ widget: new Link(node.from, text, link ? url : void 0)
144
+ }));
145
+ return false;
146
+ }
132
147
  }
148
+ return true;
133
149
  }
134
- if (!sendReply) {
135
- return null;
150
+ });
151
+ return builder.finish();
152
+ };
153
+
154
+ // packages/ui/react-ui-editor/src/components/TextEditor/extensions/hyperlink/hyperlinkTooltip.tsx
155
+ import { hoverTooltip } from "@codemirror/view";
156
+ import { tooltipContent } from "@dxos/react-ui-theme";
157
+ var markdownLinkRegexp = /\[([^\]]+)]\(([^)]+)\)/;
158
+ var createHyperlinkTooltip = (onHover, regexp = markdownLinkRegexp) => hoverTooltip((view, pos) => {
159
+ const { from, text } = view.state.doc.lineAt(pos);
160
+ const p = pos - from;
161
+ let idx = 0;
162
+ let match;
163
+ do {
164
+ match = text.substring(idx).match(regexp);
165
+ if (!match) {
166
+ match = void 0;
167
+ break;
136
168
  }
137
- return encoder;
138
- }
139
- _handleBeforeUnload() {
140
- awarenessProtocol.removeAwarenessStates(this._awareness, [
141
- this._clientId
142
- ], "window unload");
169
+ idx = text.indexOf(match[0]);
170
+ if (p >= idx && p < idx + match[0].length) {
171
+ break;
172
+ }
173
+ idx += match[0].length;
174
+ } while (true);
175
+ if (!match) {
176
+ return null;
143
177
  }
144
- };
178
+ const [, , url] = match ?? [];
179
+ return {
180
+ pos: idx + from,
181
+ end: idx + from + match[0].length,
182
+ above: true,
183
+ create: () => {
184
+ const el = document.createElement("a");
185
+ el.innerText = "_";
186
+ el.className = tooltipContent({}, "mb-2 p-1");
187
+ el.setAttribute("target", "_blank");
188
+ el.setAttribute("href", url);
189
+ onHover(el, url);
190
+ return {
191
+ dom: el
192
+ };
193
+ }
194
+ };
195
+ });
145
196
 
146
- // packages/ui/react-ui-editor/src/model.ts
147
- var useTextModel = ({ identity, space, text }) => {
148
- const provider = useMemo(() => {
149
- if (!space || !text?.doc) {
150
- return void 0;
197
+ // packages/ui/react-ui-editor/src/components/TextEditor/extensions/hyperlink/hyperlinkWidget.tsx
198
+ import { Decoration as Decoration2, EditorView as EditorView2, MatchDecorator, ViewPlugin } from "@codemirror/view";
199
+ var markdownLinkRegexp2 = /\[([^\]]+)]\(([^)]+)\)(!?)/gi;
200
+ var linkDecorator = () => new MatchDecorator({
201
+ regexp: markdownLinkRegexp2,
202
+ decorate: (add, from, to, match, view) => {
203
+ const [_, label, url] = match;
204
+ const p0 = {
205
+ start: from,
206
+ end: from + 1
207
+ };
208
+ const p1 = {
209
+ start: from + 1,
210
+ end: from + 1 + label.length
211
+ };
212
+ const p2 = {
213
+ start: p1.end,
214
+ end: p1.end + 1
215
+ };
216
+ const p3 = {
217
+ start: p1.end + 1,
218
+ end: p1.end + 1 + url.length + 2
219
+ };
220
+ add(p0.start, p0.end, Decoration2.mark({
221
+ class: "cm-hyperlink-bracket",
222
+ _attributes: {
223
+ style: "display: none"
224
+ }
225
+ }));
226
+ add(p1.start, p1.end, Decoration2.mark({
227
+ class: "cm-hyperlink-label"
228
+ }));
229
+ add(p2.start, p2.end, Decoration2.mark({
230
+ class: "cm-hyperlink-bracket",
231
+ _attributes: {
232
+ style: "display: none"
233
+ }
234
+ }));
235
+ add(p3.start, p3.end, Decoration2.mark({
236
+ class: "cm-hyperlink-url",
237
+ _attributes: {
238
+ style: "display: none"
239
+ }
240
+ }));
241
+ }
242
+ });
243
+ function hyperLinkExtension() {
244
+ return ViewPlugin.fromClass(class HyperLinkView {
245
+ constructor(view) {
246
+ this.decorator = linkDecorator();
247
+ this.decorations = this.decorator.createDeco(view);
151
248
  }
152
- return new SpaceAwarenessProvider({
153
- space,
154
- doc: text.doc,
155
- channel: `yjs.awareness.${text.id}`
156
- });
157
- }, [
158
- identity,
159
- space,
160
- text?.doc
161
- ]);
162
- if (!text?.doc || !text?.content) {
163
- return void 0;
249
+ update(update2) {
250
+ if (update2.docChanged || update2.viewportChanged) {
251
+ this.decorations = this.decorator.updateDeco(update2, this.decorations);
252
+ }
253
+ }
254
+ }, {
255
+ decorations: (view) => view.decorations,
256
+ eventHandlers: {
257
+ // TODO(burdon): CLick to expand link.
258
+ // https://discuss.codemirror.net/t/decorator-iteration-on-click-event/4226/2
259
+ mousedown: function(event, view) {
260
+ const pos = view.posAtDOM(event.target);
261
+ if (pos !== 0) {
262
+ console.log(this);
263
+ }
264
+ },
265
+ // TODO(burdon): Hide when cursor moves away.
266
+ keydown: (event, view) => {
267
+ view.update([]);
268
+ }
269
+ }
270
+ });
271
+ }
272
+ var hyperlinkStyle = EditorView2.baseTheme({
273
+ ".cm-hyperlink-label": {
274
+ cursor: "pointer",
275
+ textDecoration: "underline"
276
+ },
277
+ ".cm-hyperlink-bracket": {
278
+ opacity: 0.2
279
+ },
280
+ ".cm-hyperlink-url": {
281
+ opacity: 0.5,
282
+ fontFamily: "monospace"
164
283
  }
165
- return {
166
- id: text.doc.guid,
167
- content: text.content,
168
- provider,
169
- peer: identity ? {
170
- id: identity.identityKey.toHex(),
171
- name: identity.profile?.displayName
172
- } : void 0
173
- };
174
- };
284
+ });
285
+ var hyperlinkWidget = [
286
+ hyperLinkExtension(),
287
+ hyperlinkStyle
288
+ ];
175
289
 
176
- // packages/ui/react-ui-editor/src/components/Markdown/Markdown.tsx
177
- import { autocompletion, completionKeymap, closeBrackets, closeBracketsKeymap } from "@codemirror/autocomplete";
290
+ // packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/bundle.ts
291
+ import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
178
292
  import { defaultKeymap, history, historyKeymap, indentWithTab } from "@codemirror/commands";
179
- import { markdown, markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
180
- import { bracketMatching, defaultHighlightStyle, foldKeymap, indentOnInput, syntaxHighlighting } from "@codemirror/language";
293
+ import { markdownLanguage as markdownLanguage2, markdown } from "@codemirror/lang-markdown";
294
+ import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, foldKeymap, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
181
295
  import { languages } from "@codemirror/language-data";
182
296
  import { lintKeymap } from "@codemirror/lint";
183
- import { searchKeymap, highlightSelectionMatches } from "@codemirror/search";
184
- import { EditorState, StateField } from "@codemirror/state";
185
- import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
186
- import { keymap, crosshairCursor, drawSelection, dropCursor, highlightActiveLine, highlightActiveLineGutter, highlightSpecialChars, placeholder, rectangularSelection, EditorView } from "@codemirror/view";
187
- import { useFocusableGroup } from "@fluentui/react-tabster";
188
- import { vim } from "@replit/codemirror-vim";
189
- import React, { forwardRef, useEffect, useImperativeHandle, useState, useMemo as useMemo2, useCallback } from "react";
190
- import { yCollab } from "y-codemirror.next";
191
- import { generateName } from "@dxos/display-name";
192
- import { useThemeContext } from "@dxos/react-ui";
193
- import { getColorForValue } from "@dxos/react-ui-theme";
194
- import { YText } from "@dxos/text-model";
297
+ import { highlightSelectionMatches, searchKeymap } from "@codemirror/search";
298
+ import { EditorState } from "@codemirror/state";
299
+ import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
300
+ import { crosshairCursor, drawSelection, dropCursor, EditorView as EditorView3, highlightActiveLine, highlightActiveLineGutter, highlightSpecialChars, keymap, placeholder as placeholder2, rectangularSelection } from "@codemirror/view";
195
301
 
196
- // packages/ui/react-ui-editor/src/components/Markdown/markdownTags.ts
302
+ // packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/tags.ts
197
303
  import { styleTags, Tag } from "@lezer/highlight";
198
304
  var markdownTags = {
199
305
  headingMark: Tag.define(),
@@ -226,48 +332,28 @@ var markdownTagsExtension = {
226
332
  ]
227
333
  };
228
334
 
229
- // packages/ui/react-ui-editor/src/components/Markdown/markdownTheme.ts
335
+ // packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/theme.ts
230
336
  import { markdownLanguage } from "@codemirror/lang-markdown";
231
337
  import { HighlightStyle } from "@codemirror/language";
232
338
  import { tags } from "@lezer/highlight";
233
- import get from "lodash.get";
234
-
235
- // packages/ui/react-ui-editor/src/styles/markdown.ts
236
- import { mx } from "@dxos/react-ui-theme";
237
- var heading = {
238
- 1: "mbs-4 mbe-2 text-4xl font-semibold text-inherit no-underline",
239
- 2: "mbs-4 mbe-2 text-3xl font-bold text-inherit no-underline",
240
- 3: "mbs-4 mbe-2 text-2xl font-bold text-inherit no-underline",
241
- 4: "mbs-4 mbe-2 text-xl font-extrabold text-inherit no-underline",
242
- 5: "mbs-4 mbe-2 text-lg font-extrabold text-inherit no-underline",
243
- 6: "mbs-4 mbe-2 font-black text-inherit no-underline"
244
- };
245
- var blockquote = "mlb-2 border-is-4 border-neutral-500/50 pis-5";
246
- var unorderedList = "mlb-2 grid grid-cols-[min-content_1fr] [&>li:before]:content-[attr(marker)] [&>li:before]:mlb-1 [&>li:before]:mie-2";
247
- var orderedList = 'mlb-2 grid grid-cols-[min-content_1fr] [&>li:before]:content-[counters(section,_".")_"._"] [counter-reset:section] [&>li:before]:mlb-1';
248
- var listItem = "contents before:[counter-increment:section]";
249
- var codeBlock = "mlb-2 font-mono bg-neutral-500/10 p-3 rounded";
250
- var horizontalRule = "mlb-4 border-neutral-500/50";
251
- var paragraph = "mlb-1";
252
- var bold = "font-bold";
253
- var code = "font-mono bg-neutral-500/10 rounded pli-0.5 plb-0.5 -mlb-0.5";
254
- var codeWithoutMarks = mx(code, "pli-1.5 mli-0.5");
255
- var italic = "italic";
256
- var strikethrough = "line-through";
257
- var mark = "!font-normal !no-underline !text-inherit opacity-40";
258
-
259
- // packages/ui/react-ui-editor/src/styles/tokens.ts
260
- import { tailwindConfig } from "@dxos/react-ui-theme";
261
- var tokens = tailwindConfig({}).theme;
262
-
263
- // packages/ui/react-ui-editor/src/components/Markdown/markdownTheme.ts
339
+ import get2 from "lodash.get";
340
+ var chalky = "#e5c07b";
341
+ var coral = "#e06c75";
342
+ var cyan = "#56b6c2";
343
+ var invalid = "#ffffff";
344
+ var ivory = "#abb2bf";
345
+ var stone = "#7d8799";
264
346
  var malibu = "#61afef";
265
- var cursor = "#ffffff";
266
- var monospace = get(tokens, "fontFamily.mono", [
347
+ var sage = "#98c379";
348
+ var whiskey = "#d19a66";
349
+ var violet = "#c678dd";
350
+ var highlightBackground = "#2c313a";
351
+ var tooltipBackground = "#353a42";
352
+ var monospace = get2(tokens, "fontFamily.mono", [
267
353
  "monospace"
268
354
  ]).join(",");
269
355
  var markdownTheme = {
270
- // TODO(thure): consider whether these commented-out rules from one-dark-theme should be integrated.
356
+ // TODO(thure): Consider whether these commented-out rules from one-dark-theme should be integrated.
271
357
  // '&': {
272
358
  // color: ivory,
273
359
  // backgroundColor: background
@@ -304,7 +390,7 @@ var markdownTheme = {
304
390
  // border: 'none',
305
391
  // color: '#ddd'
306
392
  // },
307
- ".cm-tooltip": {
393
+ "& .cm-tooltip": {
308
394
  backgroundColor: "transparent",
309
395
  border: "none"
310
396
  },
@@ -331,40 +417,42 @@ var markdownTheme = {
331
417
  },
332
418
  "& .cm-line": {
333
419
  paddingInline: 0,
420
+ lineHeight: 1.6,
334
421
  minBlockSize: "1.6em"
335
422
  },
336
423
  "& .cm-line *": {
337
424
  lineHeight: 1.6
338
425
  },
339
426
  "&.cm-focused .cm-selectionBackground, & .cm-selectionBackground": {
340
- background: get(tokens, "extend.colors.primary.150", "#00ffff")
427
+ background: get2(tokens, "extend.colors.primary.150", "#00ffff")
341
428
  },
342
429
  ".dark & .cm-selectionBackground, .dark &.cm-focused .cm-selectionBackground": {
343
- background: get(tokens, "extend.colors.primary.850", "#00ffff")
430
+ background: get2(tokens, "extend.colors.primary.850", "#00ffff")
344
431
  },
345
432
  "& .cm-selectionMatch": {
346
- background: get(tokens, "extend.colors.primary.250", "#00ffff") + "44"
433
+ background: get2(tokens, "extend.colors.primary.250", "#00ffff") + "44"
347
434
  },
348
435
  ".dark & .cm-selectionMatch": {
349
- background: get(tokens, "extend.colors.primary.600", "#00ffff") + "44"
436
+ background: get2(tokens, "extend.colors.primary.600", "#00ffff") + "44"
350
437
  },
351
438
  "& .cm-content": {
439
+ padding: 0,
352
440
  caretColor: "black"
353
441
  },
354
442
  ".dark & .cm-content": {
355
- caretColor: cursor
443
+ caretColor: "white"
356
444
  },
357
445
  "& .cm-cursor": {
358
446
  borderLeftColor: "black"
359
447
  },
360
448
  ".dark & .cm-cursor": {
361
- borderLeftColor: cursor
449
+ borderLeftColor: "white"
362
450
  },
363
451
  ".cm-placeholder": {
364
- fontFamily: get(tokens, "fontFamily.body", []).join(",")
452
+ fontFamily: get2(tokens, "fontFamily.body", []).join(",")
365
453
  },
366
454
  "& .cm-scroller": {
367
- fontFamily: get(tokens, "fontFamily.mono", []).join(","),
455
+ fontFamily: get2(tokens, "fontFamily.mono", []).join(","),
368
456
  overflow: "visible"
369
457
  },
370
458
  "& .cm-activeLine": {
@@ -374,7 +462,7 @@ var markdownTheme = {
374
462
  backgroundColor: "transparent"
375
463
  },
376
464
  "& .cm-ySelectionInfo": {
377
- fontFamily: get(tokens, "fontFamily.body", []).join(","),
465
+ fontFamily: get2(tokens, "fontFamily.body", []).join(","),
378
466
  padding: "2px 4px",
379
467
  marginBlockStart: "-4px"
380
468
  },
@@ -397,8 +485,16 @@ var markdownTheme = {
397
485
  "& .cm-yLineSelection": {
398
486
  margin: "0"
399
487
  },
400
- ...Object.keys(get(tokens, "extend.fontSize", {})).reduce((acc, fontSize) => {
401
- const height = get(tokens, [
488
+ ".cm-link": {
489
+ color: "rgb(20 89 208)",
490
+ textDecorationLine: "underline",
491
+ textDecorationThickness: "1px",
492
+ textUnderlineOffset: "2px",
493
+ borderRadius: ".125rem"
494
+ },
495
+ // TODO(burdon): Document.
496
+ ...Object.keys(get2(tokens, "extend.fontSize", {})).reduce((acc, fontSize) => {
497
+ const height = get2(tokens, [
402
498
  "extend",
403
499
  "fontSize",
404
500
  fontSize,
@@ -417,7 +513,7 @@ var markdownTheme = {
417
513
  return acc;
418
514
  }, {})
419
515
  };
420
- var markdownDarkHighlighting = HighlightStyle.define([
516
+ var markdownHighlightStyle = HighlightStyle.define([
421
517
  {
422
518
  tag: [
423
519
  tags.keyword,
@@ -533,17 +629,278 @@ var markdownDarkHighlighting = HighlightStyle.define([
533
629
  ], {
534
630
  scope: markdownLanguage,
535
631
  all: {
536
- fontFamily: get(tokens, "fontFamily.body", []).join(",")
632
+ fontFamily: get2(tokens, "fontFamily.body", []).join(",")
537
633
  }
538
634
  });
539
635
 
540
- // packages/ui/react-ui-editor/src/components/Markdown/Markdown.tsx
636
+ // packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/bundle.ts
637
+ var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
638
+ return [
639
+ bracketMatching2(),
640
+ closeBrackets2(),
641
+ _placeholder && placeholder2(_placeholder),
642
+ EditorState.allowMultipleSelections.of(true),
643
+ EditorView3.lineWrapping,
644
+ // autocompletion(),
645
+ crosshairCursor(),
646
+ dropCursor(),
647
+ drawSelection(),
648
+ highlightActiveLine(),
649
+ highlightActiveLineGutter(),
650
+ highlightSelectionMatches(),
651
+ highlightSpecialChars(),
652
+ history(),
653
+ indentOnInput(),
654
+ rectangularSelection(),
655
+ keymap.of([
656
+ ...closeBracketsKeymap,
657
+ // ...completionKeymap,
658
+ ...defaultKeymap,
659
+ ...foldKeymap,
660
+ ...historyKeymap,
661
+ ...lintKeymap,
662
+ ...searchKeymap,
663
+ indentWithTab
664
+ ]),
665
+ // Main extension.
666
+ // https://github.com/codemirror/lang-markdown
667
+ markdown({
668
+ base: markdownLanguage2,
669
+ codeLanguages: languages,
670
+ extensions: [
671
+ // TODO(burdon): This seems to upgrade the parser.
672
+ // GitHub flavored markdown bundle: Table, TaskList, Strikethrough, and Autolink.
673
+ // https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
674
+ // https://github.github.com/gfm
675
+ // GFM,
676
+ // Custom styling.
677
+ markdownTagsExtension
678
+ ]
679
+ }),
680
+ // TODO(thure): All but one rule here apply to both themes; rename or refactor.
681
+ syntaxHighlighting2(markdownHighlightStyle),
682
+ themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2)
683
+ ].filter(Boolean);
684
+ };
685
+
686
+ // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
687
+ import { EditorState as EditorState2 } from "@codemirror/state";
688
+ import { EditorView as EditorView4 } from "@codemirror/view";
689
+ import { useFocusableGroup } from "@fluentui/react-tabster";
690
+ import { vim } from "@replit/codemirror-vim";
691
+ import defaultsDeep from "lodash.defaultsdeep";
692
+ import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useState } from "react";
693
+ import { useThemeContext } from "@dxos/react-ui";
694
+
695
+ // packages/ui/react-ui-editor/src/hooks/useCollaboration.ts
696
+ import { useEffect, useMemo } from "react";
697
+ import { yCollab } from "y-codemirror.next";
698
+ import { generateName } from "@dxos/display-name";
699
+ import { getColorForValue } from "@dxos/react-ui-theme";
700
+ import { YText } from "@dxos/text-model";
701
+ var useCollaboration = (model, themeMode) => {
702
+ const { provider, peer, content } = model;
703
+ const extension = useMemo(() => content instanceof YText ? yCollab(content, provider?.awareness) : void 0, []);
704
+ useEffect(() => {
705
+ if (provider && peer) {
706
+ provider.awareness.setLocalStateField("user", {
707
+ name: peer.name ?? generateName(peer.id),
708
+ color: getColorForValue({
709
+ value: peer.id,
710
+ type: "color"
711
+ }),
712
+ colorLight: getColorForValue({
713
+ value: peer.id,
714
+ themeMode,
715
+ type: "highlight"
716
+ })
717
+ });
718
+ }
719
+ }, [
720
+ provider,
721
+ peer,
722
+ themeMode
723
+ ]);
724
+ return extension;
725
+ };
726
+
727
+ // packages/ui/react-ui-editor/src/hooks/useTextModel.ts
728
+ import { useMemo as useMemo2 } from "react";
729
+
730
+ // packages/ui/react-ui-editor/src/hooks/yjs/cursors.ts
731
+ import * as random from "lib0/random";
732
+ var cursorColors = [
733
+ {
734
+ color: "#30bced",
735
+ light: "#30bced33"
736
+ },
737
+ {
738
+ color: "#6eeb83",
739
+ light: "#6eeb8333"
740
+ },
741
+ {
742
+ color: "#ffbc42",
743
+ light: "#ffbc4233"
744
+ },
745
+ {
746
+ color: "#ecd444",
747
+ light: "#ecd44433"
748
+ },
749
+ {
750
+ color: "#ee6352",
751
+ light: "#ee635233"
752
+ },
753
+ {
754
+ color: "#9ac2c9",
755
+ light: "#9ac2c933"
756
+ },
757
+ {
758
+ color: "#8acb88",
759
+ light: "#8acb8833"
760
+ },
761
+ {
762
+ color: "#1be7ff",
763
+ light: "#1be7ff33"
764
+ }
765
+ ];
766
+ var cursorColor = cursorColors[random.uint32() % cursorColors.length];
767
+
768
+ // packages/ui/react-ui-editor/src/hooks/yjs/space-provider.ts
769
+ import * as decoding from "lib0/decoding";
770
+ import * as encoding from "lib0/encoding";
771
+ import { Observable } from "lib0/observable";
772
+ import * as awarenessProtocol from "y-protocols/awareness";
773
+ import { log } from "@dxos/log";
774
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs/space-provider.ts";
775
+ var messageAwareness = 1;
776
+ var messageQueryAwareness = 3;
777
+ var SpaceAwarenessProvider = class extends Observable {
778
+ constructor({ space, doc, channel, awareness }) {
779
+ super();
780
+ this._space = space;
781
+ this._awareness = awareness ?? new awarenessProtocol.Awareness(doc);
782
+ this._channel = channel;
783
+ this._clientId = doc.clientID;
784
+ this._awareness.on("update", this._handleAwarenessUpdate.bind(this));
785
+ this._space.listen(this._channel, this._handleSpaceMessage.bind(this));
786
+ if (typeof window !== "undefined") {
787
+ window.addEventListener("beforeunload", this._handleBeforeUnload.bind(this));
788
+ } else if (typeof process !== "undefined") {
789
+ process.on("exit", this._handleBeforeUnload.bind(this));
790
+ }
791
+ const encoderAwarenessQuery = encoding.createEncoder();
792
+ encoding.writeVarUint(encoderAwarenessQuery, messageQueryAwareness);
793
+ void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessQuery));
794
+ const encoderAwarenessState = encoding.createEncoder();
795
+ encoding.writeVarUint(encoderAwarenessState, messageAwareness);
796
+ encoding.writeVarUint8Array(encoderAwarenessState, awarenessProtocol.encodeAwarenessUpdate(this.awareness, [
797
+ this._clientId
798
+ ]));
799
+ void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessState));
800
+ }
801
+ get awareness() {
802
+ return this._awareness;
803
+ }
804
+ _handleAwarenessUpdate({ added, updated, removed }, origin) {
805
+ log("awareness update", {
806
+ added,
807
+ updated,
808
+ removed,
809
+ origin
810
+ }, {
811
+ F: __dxlog_file,
812
+ L: 67,
813
+ S: this,
814
+ C: (f, a) => f(...a)
815
+ });
816
+ const changedClients = added.concat(updated).concat(removed);
817
+ const encoderAwareness = encoding.createEncoder();
818
+ encoding.writeVarUint(encoderAwareness, messageAwareness);
819
+ encoding.writeVarUint8Array(encoderAwareness, awarenessProtocol.encodeAwarenessUpdate(this._awareness, changedClients));
820
+ void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwareness));
821
+ }
822
+ _handleSpaceMessage({ payload }) {
823
+ log("space message", payload, {
824
+ F: __dxlog_file,
825
+ L: 79,
826
+ S: this,
827
+ C: (f, a) => f(...a)
828
+ });
829
+ const data = new Uint8Array(Array.from(Object.values(payload)));
830
+ const encoder = this._readMessage(data);
831
+ if (encoder) {
832
+ void this._space.postMessage(this._channel, encoding.toUint8Array(encoder));
833
+ }
834
+ }
835
+ _readMessage(message) {
836
+ const decoder = decoding.createDecoder(message);
837
+ const encoder = encoding.createEncoder();
838
+ const messageType = decoding.readVarUint(decoder);
839
+ let sendReply = false;
840
+ switch (messageType) {
841
+ case messageAwareness: {
842
+ awarenessProtocol.applyAwarenessUpdate(this._awareness, decoding.readVarUint8Array(decoder), this);
843
+ break;
844
+ }
845
+ case messageQueryAwareness: {
846
+ encoding.writeVarUint(encoder, messageAwareness);
847
+ encoding.writeVarUint8Array(encoder, awarenessProtocol.encodeAwarenessUpdate(this._awareness, Array.from(this._awareness.getStates().keys())));
848
+ sendReply = true;
849
+ break;
850
+ }
851
+ default: {
852
+ console.error("Invalid message:", messageType);
853
+ return encoder;
854
+ }
855
+ }
856
+ if (!sendReply) {
857
+ return null;
858
+ }
859
+ return encoder;
860
+ }
861
+ _handleBeforeUnload() {
862
+ awarenessProtocol.removeAwarenessStates(this._awareness, [
863
+ this._clientId
864
+ ], "window unload");
865
+ }
866
+ };
867
+
868
+ // packages/ui/react-ui-editor/src/hooks/useTextModel.ts
869
+ var useTextModel = ({ identity, space, text }) => {
870
+ const provider = useMemo2(() => {
871
+ if (!space || !text?.doc) {
872
+ return void 0;
873
+ }
874
+ return new SpaceAwarenessProvider({
875
+ space,
876
+ doc: text.doc,
877
+ channel: `yjs.awareness.${text.id}`
878
+ });
879
+ }, [
880
+ identity,
881
+ space,
882
+ text?.doc
883
+ ]);
884
+ if (!text?.doc || !text?.content) {
885
+ return void 0;
886
+ }
887
+ return {
888
+ id: text.doc.guid,
889
+ content: text.content,
890
+ provider,
891
+ peer: identity ? {
892
+ id: identity.identityKey.toHex(),
893
+ name: identity.profile?.displayName
894
+ } : void 0
895
+ };
896
+ };
897
+
898
+ // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
541
899
  var EditorModes = [
542
900
  "default",
543
901
  "vim"
544
902
  ];
545
- var MarkdownEditor = /* @__PURE__ */ forwardRef(({ model, slots = {}, editorMode, extensions = [], onChange }, forwardedRef) => {
546
- const { id, content, provider, peer } = model ?? {};
903
+ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots, editorMode }, forwardedRef) => {
547
904
  const { themeMode } = useThemeContext();
548
905
  const tabsterDOMAttribute = useFocusableGroup({
549
906
  tabBehavior: "limited"
@@ -555,110 +912,32 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ model, slots = {}, editorMode
555
912
  editor: parent,
556
913
  state,
557
914
  view
558
- }));
559
- const listenChangesExtension = useMemo2(() => StateField.define({
560
- create: () => null,
561
- update: (_value, transaction) => {
562
- if (transaction.docChanged && onChange) {
563
- onChange(transaction.newDoc);
564
- }
565
- return null;
566
- }
567
915
  }), [
568
- onChange
569
- ]);
570
- useEffect(() => {
571
- if (provider && peer) {
572
- provider.awareness.setLocalStateField("user", {
573
- name: peer.name ?? generateName(peer.id),
574
- color: getColorForValue({
575
- value: peer.id,
576
- type: "color"
577
- }),
578
- colorLight: getColorForValue({
579
- value: peer.id,
580
- themeMode,
581
- type: "highlight"
582
- })
583
- });
584
- }
585
- }, [
586
- provider,
587
- peer,
588
- themeMode
916
+ view,
917
+ state,
918
+ parent
589
919
  ]);
590
- useEffect(() => {
920
+ const collaboration = useCollaboration(model, themeMode);
921
+ useEffect2(() => {
591
922
  if (!parent) {
592
923
  return;
593
924
  }
594
- const state2 = EditorState.create({
595
- doc: content?.toString(),
925
+ const state2 = EditorState2.create({
926
+ doc: model.content?.toString(),
596
927
  extensions: [
597
- // Based on https://github.com/codemirror/dev/issues/44#issuecomment-789093799.
598
- listenChangesExtension,
599
- ...editorMode === "vim" ? [
600
- vim()
601
- ] : [],
602
- // All of https://github.com/codemirror/basic-setup minus line numbers and fold gutter.
603
- highlightActiveLineGutter(),
604
- highlightSpecialChars(),
605
- history(),
606
- drawSelection(),
607
- dropCursor(),
608
- EditorState.allowMultipleSelections.of(true),
609
- indentOnInput(),
610
- syntaxHighlighting(defaultHighlightStyle, {
611
- fallback: true
612
- }),
613
- bracketMatching(),
614
- closeBrackets(),
615
- autocompletion(),
616
- rectangularSelection(),
617
- crosshairCursor(),
618
- highlightActiveLine(),
619
- highlightSelectionMatches(),
620
- placeholder(slots.editor?.placeholder ?? ""),
621
- keymap.of([
622
- ...closeBracketsKeymap,
623
- ...defaultKeymap,
624
- ...searchKeymap,
625
- ...historyKeymap,
626
- ...foldKeymap,
627
- ...completionKeymap,
628
- ...lintKeymap,
629
- indentWithTab
630
- ]),
631
- EditorView.lineWrapping,
632
- // Themes.
633
- markdown({
634
- base: markdownLanguage2,
635
- codeLanguages: languages,
636
- extensions: [
637
- markdownTagsExtension
638
- ]
639
- }),
640
- EditorView.theme({
641
- ...markdownTheme,
642
- ...slots.editor?.markdownTheme
643
- }),
644
- ...themeMode === "dark" ? [
645
- syntaxHighlighting(oneDarkHighlightStyle)
646
- ] : [
647
- syntaxHighlighting(defaultHighlightStyle)
648
- ],
649
- // TODO(thure): All but one rule here apply to both themes; rename or refactor.
650
- syntaxHighlighting(markdownDarkHighlighting),
651
- // Replication and awareness (incl. remote selection).
652
- ...content instanceof YText ? [
653
- yCollab(content, provider?.awareness)
654
- ] : [],
928
+ // TODO(burdon): Factor out VIM mode?
929
+ editorMode === "vim" && vim(),
930
+ // Replication.
931
+ collaboration,
932
+ // Theme.
933
+ slots?.editor?.theme && EditorView4.theme(slots?.editor?.theme),
655
934
  // Custom.
656
935
  ...extensions
657
- ]
936
+ ].filter(Boolean)
658
937
  });
659
938
  setState(state2);
660
939
  view?.destroy();
661
- setView(new EditorView({
940
+ setView(new EditorView4({
662
941
  state: state2,
663
942
  parent
664
943
  }));
@@ -669,8 +948,7 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ model, slots = {}, editorMode
669
948
  };
670
949
  }, [
671
950
  parent,
672
- content,
673
- provider?.awareness,
951
+ model.content,
674
952
  themeMode,
675
953
  editorMode
676
954
  ]);
@@ -691,447 +969,89 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ model, slots = {}, editorMode
691
969
  editorMode
692
970
  ]);
693
971
  return /* @__PURE__ */ React.createElement("div", {
694
- tabIndex: 0,
972
+ key: model.id,
695
973
  ref: setParent,
696
- key: id,
697
- ...slots.root,
698
- ...editorMode !== "vim" ? tabsterDOMAttribute : {},
974
+ tabIndex: 0,
975
+ ...slots?.root,
976
+ ...editorMode !== "vim" && tabsterDOMAttribute,
699
977
  onKeyUp: handleKeyUp
700
978
  });
701
979
  });
702
-
703
- // packages/ui/react-ui-editor/src/components/RichText/RichText.tsx
704
- import { mergeAttributes } from "@tiptap/core";
705
- import Collaboration from "@tiptap/extension-collaboration";
706
- import CollaborationCursor from "@tiptap/extension-collaboration-cursor";
707
- import Heading from "@tiptap/extension-heading";
708
- import ListItem from "@tiptap/extension-list-item";
709
- import Placeholder from "@tiptap/extension-placeholder";
710
- import { EditorContent, useEditor as useNaturalEditor } from "@tiptap/react";
711
- import StarterKit from "@tiptap/starter-kit";
712
- import React2, { forwardRef as forwardRef2, useImperativeHandle as useImperativeHandle2, useMemo as useMemo3 } from "react";
713
- import { generateName as generateName2 } from "@dxos/display-name";
714
- import { mx as mx2 } from "@dxos/react-ui-theme";
715
- var useEditor = ({ model, placeholder: placeholder3 = "Enter text\u2026", slots = {} }) => {
716
- const extensions = useMemo3(() => [
717
- StarterKit.configure({
718
- // Extensions
719
- history: false,
720
- // Nodes
721
- blockquote: {
722
- HTMLAttributes: {
723
- class: blockquote
724
- }
725
- },
726
- bulletList: {
727
- HTMLAttributes: {
728
- class: unorderedList
729
- }
730
- },
731
- codeBlock: {
732
- HTMLAttributes: {
733
- class: codeBlock
734
- }
735
- },
736
- heading: false,
737
- horizontalRule: {
738
- HTMLAttributes: {
739
- class: horizontalRule
740
- }
741
- },
742
- listItem: false,
743
- orderedList: {
744
- HTMLAttributes: {
745
- class: orderedList
746
- }
747
- },
748
- paragraph: {
749
- HTMLAttributes: {
750
- class: paragraph
751
- }
752
- },
753
- // Marks
754
- bold: {
755
- HTMLAttributes: {
756
- class: bold
757
- }
758
- },
759
- code: {
760
- HTMLAttributes: {
761
- class: codeWithoutMarks
762
- }
763
- },
764
- italic: {
765
- HTMLAttributes: {
766
- class: italic
767
- }
768
- },
769
- strike: {
770
- HTMLAttributes: {
771
- class: strikethrough
772
- }
773
- }
774
- }),
775
- Heading.extend({
776
- renderHTML({ node, HTMLAttributes }) {
777
- const hasLevel = this.options.levels.includes(node.attrs.level);
778
- const level = hasLevel ? node.attrs.level : this.options.levels[0];
779
- return [
780
- `h${level}`,
781
- mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {
782
- class: heading[level]
783
- }),
784
- 0
785
- ];
786
- }
787
- }),
788
- ListItem.extend({
789
- renderHTML: ({ HTMLAttributes }) => [
790
- "li",
791
- mergeAttributes(HTMLAttributes, {
792
- marker: "\u2022 ",
793
- class: listItem
794
- }),
795
- [
796
- "div",
797
- {
798
- role: "none"
799
- },
800
- 0
801
- ]
802
- ]
803
- }),
804
- // https://github.com/ueberdosis/tiptap/tree/main/packages/extension-collaboration
805
- ...model && typeof model.content !== "string" ? [
806
- Collaboration.configure({
807
- fragment: model.content
808
- })
809
- ] : [],
810
- ...model?.provider ? [
811
- CollaborationCursor.configure({
812
- provider: model.provider,
813
- user: model.peer && {
814
- name: model.peer.name ?? generateName2(model.peer.id),
815
- color: cursorColor.color
816
- }
817
- })
818
- ] : [],
819
- Placeholder.configure({
820
- placeholder: placeholder3,
821
- emptyEditorClass: "before:content-[attr(data-placeholder)] before:absolute opacity-50 cursor-text"
980
+ var TextEditor = /* @__PURE__ */ forwardRef(({ extensions: _extensions, slots, ...props }, forwardedRef) => {
981
+ const { themeMode } = useThemeContext();
982
+ const extensions = [
983
+ ..._extensions ?? [],
984
+ basicBundle({
985
+ themeMode,
986
+ placeholder: slots?.editor?.placeholder
822
987
  })
823
- ], [
824
- model?.id
825
- ]);
826
- return useNaturalEditor({
988
+ ];
989
+ return /* @__PURE__ */ React.createElement(BaseTextEditor, {
990
+ ref: forwardedRef,
827
991
  extensions,
828
- editorProps: {
829
- attributes: {
830
- class: mx2("focus:outline-none focus-visible:outline-none", slots.editor?.className),
831
- spellcheck: slots.editor?.spellCheck === false ? "false" : "true",
832
- tabindex: slots.editor?.tabIndex ? String(slots.editor?.tabIndex) : "0"
992
+ slots: defaultsDeep({}, slots, {
993
+ editor: {
994
+ theme: basicTheme
833
995
  }
834
- }
835
- }, [
836
- extensions
837
- ]);
838
- };
839
- var RichTextEditor = /* @__PURE__ */ forwardRef2((props, ref) => {
840
- const editor = useEditor(props);
841
- useImperativeHandle2(ref, () => editor, [
842
- editor
843
- ]);
844
- return /* @__PURE__ */ React2.createElement(EditorContent, {
845
- ...props.slots?.root,
846
- editor
847
- });
848
- });
849
-
850
- // packages/ui/react-ui-editor/src/components/Editor/Editor.tsx
851
- var Editor = /* @__PURE__ */ memo(/* @__PURE__ */ forwardRef3(({ slots, ...params }, forwardedRef) => {
852
- const model = useTextModel(params);
853
- if (model?.content instanceof YXmlFragment) {
854
- return /* @__PURE__ */ React3.createElement(RichTextEditor, {
855
- ref: forwardedRef,
856
- model,
857
- slots
858
- });
859
- } else {
860
- return /* @__PURE__ */ React3.createElement(MarkdownEditor, {
861
- ref: forwardedRef,
862
- model,
863
- slots
864
- });
865
- }
866
- }));
867
-
868
- // packages/ui/react-ui-editor/src/components/TextEditor/index.ts
869
- import { tags as tags2 } from "@lezer/highlight";
870
-
871
- // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
872
- import { closeBrackets as closeBrackets2 } from "@codemirror/autocomplete";
873
- import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
874
- import { EditorState as EditorState2 } from "@codemirror/state";
875
- import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
876
- import { EditorView as EditorView2, placeholder as placeholder2 } from "@codemirror/view";
877
- import React4, { forwardRef as forwardRef4, useEffect as useEffect2, useImperativeHandle as useImperativeHandle3, useState as useState2, useCallback as useCallback2 } from "react";
878
- import { yCollab as yCollab2 } from "y-codemirror.next";
879
- import { useThemeContext as useThemeContext2 } from "@dxos/react-ui";
880
- import { YText as YText2 } from "@dxos/text-model";
881
-
882
- // packages/ui/react-ui-editor/src/components/TextEditor/theme.ts
883
- import get2 from "lodash.get";
884
- import { tailwindConfig as tailwindConfig2 } from "@dxos/react-ui-theme";
885
- var tokens2 = tailwindConfig2({}).theme;
886
- var defaultStyles = {
887
- "&.cm-focused": {
888
- outline: "none"
889
- },
890
- ".cm-placeholder": {
891
- fontFamily: get2(tokens2, "fontFamily.body", []).join(",")
892
- },
893
- "& .cm-scroller": {
894
- fontFamily: get2(tokens2, "fontFamily.body", []).join(","),
895
- overflow: "visible"
896
- },
897
- ".cm-tooltip": {
898
- backgroundColor: "transparent",
899
- border: "none"
900
- }
901
- };
902
-
903
- // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
904
- var TextEditor = /* @__PURE__ */ forwardRef4(({ model, extensions = [], theme = defaultStyles, slots = {}, onKeyDown, ...props }, forwardedRef) => {
905
- const { id, content } = model ?? {};
906
- const { themeMode } = useThemeContext2();
907
- const [parent, setParent] = useState2(null);
908
- const [state, setState] = useState2();
909
- const [view, setView] = useState2();
910
- useImperativeHandle3(forwardedRef, () => {
911
- return {
912
- editor: parent,
913
- state,
914
- view
915
- };
916
- }, [
917
- view
918
- ]);
919
- useEffect2(() => {
920
- if (!parent) {
921
- return;
922
- }
923
- view?.destroy();
924
- const state2 = EditorState2.create({
925
- doc: content?.toString(),
926
- extensions: [
927
- bracketMatching2(),
928
- closeBrackets2(),
929
- placeholder2(slots.editor?.placeholder ?? ""),
930
- EditorView2.lineWrapping,
931
- // Themes.
932
- EditorView2.theme(theme),
933
- ...themeMode === "dark" ? [
934
- syntaxHighlighting2(oneDarkHighlightStyle2)
935
- ] : [
936
- syntaxHighlighting2(defaultHighlightStyle2)
937
- ],
938
- // Replication.
939
- ...content instanceof YText2 ? [
940
- yCollab2(content, void 0)
941
- ] : [],
942
- // Custom.
943
- ...extensions
944
- ]
945
- });
946
- setState(state2);
947
- setView(new EditorView2({
948
- state: state2,
949
- parent
950
- }));
951
- return () => {
952
- view?.destroy();
953
- setView(void 0);
954
- setState(void 0);
955
- };
956
- }, [
957
- parent,
958
- content,
959
- themeMode
960
- ]);
961
- const handleKeyDown = useCallback2((event) => {
962
- if (view) {
963
- const { head, from, to } = view.state.selection.ranges[0];
964
- const { number } = view.state.doc.lineAt(head);
965
- const after = view.state.sliceDoc(from);
966
- onKeyDown?.(event, {
967
- from,
968
- to,
969
- line: number,
970
- lines: view.state.doc.lines,
971
- after
972
- });
973
- }
974
- }, [
975
- view
976
- ]);
977
- return /* @__PURE__ */ React4.createElement("div", {
978
- key: id,
979
- ref: setParent,
980
- ...slots.root,
981
- onKeyDown: handleKeyDown,
996
+ }),
982
997
  ...props
983
998
  });
984
999
  });
985
-
986
- // packages/ui/react-ui-editor/src/components/TextEditor/extensions/hyperlink.tsx
987
- import { Decoration, EditorView as EditorView3, MatchDecorator, ViewPlugin } from "@codemirror/view";
988
- var markdownLinkRegexp = /\[([^\]]+)]\(([^)]+)\)(!?)/gi;
989
- var linkDecorator = () => new MatchDecorator({
990
- regexp: markdownLinkRegexp,
991
- decorate: (add, from, to, match, view) => {
992
- const [_, label, url] = match;
993
- const p0 = {
994
- start: from,
995
- end: from + 1
996
- };
997
- const p1 = {
998
- start: from + 1,
999
- end: from + 1 + label.length
1000
- };
1001
- const p2 = {
1002
- start: p1.end,
1003
- end: p1.end + 1
1004
- };
1005
- const p3 = {
1006
- start: p1.end + 1,
1007
- end: p1.end + 1 + url.length + 2
1008
- };
1009
- add(p0.start, p0.end, Decoration.mark({
1010
- class: "cm-hyperlink-bracket"
1011
- }));
1012
- add(p1.start, p1.end, Decoration.mark({
1013
- class: "cm-hyperlink-label"
1014
- }));
1015
- add(p2.start, p2.end, Decoration.mark({
1016
- class: "cm-hyperlink-bracket"
1017
- }));
1018
- add(p3.start, p3.end, Decoration.mark({
1019
- class: "cm-hyperlink-url",
1020
- __attributes: {
1021
- style: "display: none"
1022
- }
1023
- }));
1024
- }
1025
- });
1026
- function hyperLinkExtension() {
1027
- return ViewPlugin.fromClass(class HyperLinkView {
1028
- constructor(view) {
1029
- this.decorator = linkDecorator();
1030
- this.decorations = this.decorator.createDeco(view);
1031
- }
1032
- update(update) {
1033
- if (update.docChanged || update.viewportChanged) {
1034
- this.decorations = this.decorator.updateDeco(update, this.decorations);
1035
- }
1036
- }
1037
- }, {
1038
- decorations: (view) => view.decorations,
1039
- eventHandlers: {
1040
- // TODO(burdon): CLick to expand link.
1041
- // https://discuss.codemirror.net/t/decorator-iteration-on-click-event/4226/2
1042
- mousedown: function(event, view) {
1043
- const pos = view.posAtDOM(event.target);
1044
- if (pos !== 0) {
1045
- console.log(this);
1046
- }
1047
- },
1048
- // TODO(burdon): Hide when cursor moves away.
1049
- keydown: (event, view) => {
1050
- view.update([]);
1000
+ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ extensions: _extensions, slots, ...props }, forwardedRef) => {
1001
+ const { themeMode } = useThemeContext();
1002
+ const extensions = [
1003
+ ..._extensions ?? [],
1004
+ markdownBundle({
1005
+ themeMode
1006
+ })
1007
+ ];
1008
+ return /* @__PURE__ */ React.createElement(BaseTextEditor, {
1009
+ ref: forwardedRef,
1010
+ extensions,
1011
+ slots: defaultsDeep({}, slots, {
1012
+ editor: {
1013
+ theme: markdownTheme
1051
1014
  }
1052
- }
1015
+ }),
1016
+ ...props
1053
1017
  });
1054
- }
1055
- var hyperLinkStyle = EditorView3.baseTheme({
1056
- ".cm-hyperlink-label": {
1057
- cursor: "pointer",
1058
- textDecoration: "underline"
1059
- },
1060
- ".cm-hyperlink-bracket": {
1061
- opacity: 0.2
1062
- },
1063
- ".cm-hyperlink-url": {
1064
- opacity: 0.5,
1065
- fontFamily: "monospace"
1066
- }
1067
- });
1068
- var hyperlink = [
1069
- hyperLinkExtension(),
1070
- hyperLinkStyle
1071
- ];
1072
-
1073
- // packages/ui/react-ui-editor/src/components/TextEditor/extensions/hyperlinkTooltip.tsx
1074
- import { hoverTooltip } from "@codemirror/view";
1075
- import { tooltipContent } from "@dxos/react-ui-theme";
1076
- var markdownLinkRegexp2 = /\[([^\]]+)]\(([^)]+)\)/;
1077
- var createHyperlinkTooltip = (onHover, regexp = markdownLinkRegexp2) => hoverTooltip((view, pos) => {
1078
- const { from, text } = view.state.doc.lineAt(pos);
1079
- const p = pos - from;
1080
- let idx = 0;
1081
- let match;
1082
- do {
1083
- match = text.substring(idx).match(regexp);
1084
- if (!match) {
1085
- match = void 0;
1086
- break;
1087
- }
1088
- idx = text.indexOf(match[0]);
1089
- if (p >= idx && p < idx + match[0].length) {
1090
- break;
1091
- }
1092
- idx += match[0].length;
1093
- } while (true);
1094
- if (!match) {
1095
- return null;
1096
- }
1097
- const [, , url] = match ?? [];
1098
- return {
1099
- pos: idx + from,
1100
- end: idx + from + match[0].length,
1101
- above: true,
1102
- create: () => {
1103
- const el = document.createElement("a");
1104
- el.innerText = "_";
1105
- el.className = tooltipContent({}, "mb-2 p-1");
1106
- el.setAttribute("target", "_blank");
1107
- el.setAttribute("href", url);
1108
- onHover(el, url);
1109
- return {
1110
- dom: el
1111
- };
1112
- }
1113
- };
1114
1018
  });
1115
-
1116
- // packages/ui/react-ui-editor/src/index.ts
1117
- import { TextKind } from "@dxos/protocols/proto/dxos/echo/model/text";
1118
- import { Doc, YText as YText3, YXmlFragment as YXmlFragment2 } from "@dxos/text-model";
1119
1019
  export {
1020
+ BaseTextEditor,
1120
1021
  Doc,
1121
- Editor,
1122
1022
  EditorModes,
1123
1023
  MarkdownEditor,
1124
- RichTextEditor,
1024
+ SpaceAwarenessProvider,
1125
1025
  TextEditor,
1126
1026
  TextKind,
1127
- YText3 as YText,
1128
- YXmlFragment2 as YXmlFragment,
1027
+ YText2 as YText,
1028
+ YXmlFragment,
1029
+ basicBundle,
1030
+ basicTheme,
1031
+ chalky,
1032
+ coral,
1129
1033
  createHyperlinkTooltip,
1130
- defaultStyles,
1034
+ cursorColor,
1035
+ cyan,
1036
+ highlightBackground,
1131
1037
  hyperLinkExtension,
1132
- hyperLinkStyle,
1133
- hyperlink,
1038
+ hyperlinkDecoration,
1039
+ hyperlinkStyle,
1040
+ hyperlinkWidget,
1041
+ invalid,
1042
+ ivory,
1043
+ malibu,
1044
+ markdownBundle,
1045
+ markdownHighlightStyle,
1046
+ markdownTheme,
1047
+ onChangeExtension,
1048
+ sage,
1049
+ stone,
1134
1050
  tags2 as tags,
1135
- useTextModel
1051
+ tooltipBackground,
1052
+ useCollaboration,
1053
+ useTextModel,
1054
+ violet,
1055
+ whiskey
1136
1056
  };
1137
1057
  //# sourceMappingURL=index.mjs.map