@dxos/react-ui-editor 0.3.10-main.a21ec31 → 0.3.10-next.3e4f36f

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 (121) hide show
  1. package/dist/lib/browser/index.mjs +737 -742
  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.map +1 -0
  5. package/dist/types/src/automerge/automerge-plugin/amToCodemirror.d.ts.map +1 -0
  6. package/dist/types/src/automerge/automerge-plugin/codeMirrorToAm.d.ts.map +1 -0
  7. package/dist/types/src/automerge/automerge-plugin/handle.d.ts.map +1 -0
  8. package/dist/types/src/automerge/automerge-plugin/index.d.ts.map +1 -0
  9. package/dist/types/src/automerge/automerge-plugin/plugin.d.ts.map +1 -0
  10. package/dist/types/src/automerge/automerge.stories.d.ts.map +1 -0
  11. package/dist/types/src/components/TextEditor/TextEditor.d.ts +2 -4
  12. package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
  13. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +4 -9
  14. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
  15. package/dist/types/src/components/TextEditor/extensions/{basic.d.ts → basic/bundle.d.ts} +1 -1
  16. package/dist/types/src/components/TextEditor/extensions/basic/bundle.d.ts.map +1 -0
  17. package/dist/types/src/components/TextEditor/extensions/basic/index.d.ts +3 -0
  18. package/dist/types/src/components/TextEditor/extensions/basic/index.d.ts.map +1 -0
  19. package/dist/types/src/components/TextEditor/extensions/basic/theme.d.ts +10 -0
  20. package/dist/types/src/components/TextEditor/extensions/basic/theme.d.ts.map +1 -0
  21. package/dist/types/src/components/TextEditor/extensions/change.d.ts +7 -0
  22. package/dist/types/src/components/TextEditor/extensions/change.d.ts.map +1 -0
  23. package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkDecoration.d.ts +11 -0
  24. package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkDecoration.d.ts.map +1 -0
  25. package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkTooltip.d.ts +8 -0
  26. package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkTooltip.d.ts.map +1 -0
  27. package/dist/types/src/components/TextEditor/extensions/{experimental.d.ts → hyperlink/hyperlinkWidget.d.ts} +2 -2
  28. package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkWidget.d.ts.map +1 -0
  29. package/dist/types/src/components/TextEditor/extensions/hyperlink/index.d.ts +4 -0
  30. package/dist/types/src/components/TextEditor/extensions/hyperlink/index.d.ts.map +1 -0
  31. package/dist/types/src/components/TextEditor/extensions/index.d.ts +2 -5
  32. package/dist/types/src/components/TextEditor/extensions/index.d.ts.map +1 -1
  33. package/dist/types/src/components/TextEditor/extensions/markdown/bundle.d.ts.map +1 -1
  34. package/dist/types/src/components/TextEditor/extensions/markdown/index.d.ts +1 -1
  35. package/dist/types/src/components/TextEditor/extensions/markdown/index.d.ts.map +1 -1
  36. package/dist/types/src/components/TextEditor/extensions/markdown/tags.d.ts +17 -0
  37. package/dist/types/src/components/TextEditor/extensions/markdown/tags.d.ts.map +1 -0
  38. package/dist/types/src/components/TextEditor/extensions/markdown/theme.d.ts +21 -0
  39. package/dist/types/src/components/TextEditor/extensions/markdown/theme.d.ts.map +1 -0
  40. package/dist/types/src/components/TextEditor/index.d.ts +0 -2
  41. package/dist/types/src/components/TextEditor/index.d.ts.map +1 -1
  42. package/dist/types/src/components/TextEditor/yjs.stories.d.ts +0 -1
  43. package/dist/types/src/components/TextEditor/yjs.stories.d.ts.map +1 -1
  44. package/dist/types/src/hooks/index.d.ts +1 -0
  45. package/dist/types/src/hooks/index.d.ts.map +1 -1
  46. package/dist/types/src/hooks/useCollaboration.d.ts +9 -0
  47. package/dist/types/src/hooks/useCollaboration.d.ts.map +1 -0
  48. package/dist/types/src/hooks/useTextModel.d.ts +4 -4
  49. package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
  50. package/dist/types/src/styles/markdown.d.ts +10 -12
  51. package/dist/types/src/styles/markdown.d.ts.map +1 -1
  52. package/package.json +32 -20
  53. package/src/{hooks/automerge → automerge}/automerge.stories.tsx +1 -2
  54. package/src/components/TextEditor/TextEditor.stories.tsx +43 -46
  55. package/src/components/TextEditor/TextEditor.tsx +45 -59
  56. package/src/components/TextEditor/extensions/{basic.ts → basic/bundle.ts} +2 -4
  57. package/src/components/TextEditor/extensions/basic/index.ts +6 -0
  58. package/src/components/TextEditor/extensions/basic/theme.ts +49 -0
  59. package/src/components/TextEditor/extensions/{listener.ts → change.ts} +3 -3
  60. package/src/components/TextEditor/extensions/{link.ts → hyperlink/hyperlinkDecoration.ts} +31 -68
  61. package/src/components/TextEditor/extensions/{tooltip.tsx → hyperlink/hyperlinkTooltip.tsx} +9 -9
  62. package/src/components/TextEditor/extensions/{experimental.tsx → hyperlink/hyperlinkWidget.tsx} +2 -17
  63. package/src/components/TextEditor/extensions/hyperlink/index.ts +7 -0
  64. package/src/components/TextEditor/extensions/index.ts +2 -5
  65. package/src/components/TextEditor/extensions/markdown/bundle.ts +11 -15
  66. package/src/components/TextEditor/extensions/markdown/index.ts +1 -1
  67. package/src/components/TextEditor/extensions/markdown/tags.ts +38 -0
  68. package/src/components/TextEditor/extensions/markdown/theme.ts +265 -0
  69. package/src/components/TextEditor/index.ts +0 -3
  70. package/src/components/TextEditor/yjs.stories.tsx +0 -1
  71. package/src/hooks/index.ts +1 -0
  72. package/src/hooks/useCollaboration.ts +45 -0
  73. package/src/hooks/useTextModel.ts +40 -51
  74. package/src/styles/markdown.ts +24 -26
  75. package/src/testing/replicator.ts +2 -2
  76. package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts +0 -35
  77. package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +0 -1
  78. package/dist/types/src/components/TextEditor/extensions/autocomplete.d.ts +0 -9
  79. package/dist/types/src/components/TextEditor/extensions/autocomplete.d.ts.map +0 -1
  80. package/dist/types/src/components/TextEditor/extensions/basic.d.ts.map +0 -1
  81. package/dist/types/src/components/TextEditor/extensions/experimental.d.ts.map +0 -1
  82. package/dist/types/src/components/TextEditor/extensions/link.d.ts +0 -11
  83. package/dist/types/src/components/TextEditor/extensions/link.d.ts.map +0 -1
  84. package/dist/types/src/components/TextEditor/extensions/listener.d.ts +0 -7
  85. package/dist/types/src/components/TextEditor/extensions/listener.d.ts.map +0 -1
  86. package/dist/types/src/components/TextEditor/extensions/markdown/highlight.d.ts +0 -31
  87. package/dist/types/src/components/TextEditor/extensions/markdown/highlight.d.ts.map +0 -1
  88. package/dist/types/src/components/TextEditor/extensions/tasklist.d.ts +0 -5
  89. package/dist/types/src/components/TextEditor/extensions/tasklist.d.ts.map +0 -1
  90. package/dist/types/src/components/TextEditor/extensions/tooltip.d.ts +0 -12
  91. package/dist/types/src/components/TextEditor/extensions/tooltip.d.ts.map +0 -1
  92. package/dist/types/src/components/TextEditor/themes/default.d.ts +0 -17
  93. package/dist/types/src/components/TextEditor/themes/default.d.ts.map +0 -1
  94. package/dist/types/src/components/TextEditor/themes/index.d.ts +0 -2
  95. package/dist/types/src/components/TextEditor/themes/index.d.ts.map +0 -1
  96. package/dist/types/src/hooks/automerge/PatchSemaphore.d.ts.map +0 -1
  97. package/dist/types/src/hooks/automerge/amToCodemirror.d.ts.map +0 -1
  98. package/dist/types/src/hooks/automerge/automerge.stories.d.ts.map +0 -1
  99. package/dist/types/src/hooks/automerge/codeMirrorToAm.d.ts.map +0 -1
  100. package/dist/types/src/hooks/automerge/handle.d.ts.map +0 -1
  101. package/dist/types/src/hooks/automerge/index.d.ts.map +0 -1
  102. package/dist/types/src/hooks/automerge/plugin.d.ts.map +0 -1
  103. package/src/components/TextEditor/MarkdownEditor.stories.tsx +0 -242
  104. package/src/components/TextEditor/extensions/autocomplete.ts +0 -72
  105. package/src/components/TextEditor/extensions/markdown/highlight.ts +0 -166
  106. package/src/components/TextEditor/extensions/tasklist.ts +0 -113
  107. package/src/components/TextEditor/themes/default.ts +0 -170
  108. package/src/components/TextEditor/themes/index.ts +0 -5
  109. /package/dist/types/src/{hooks/automerge → automerge/automerge-plugin}/PatchSemaphore.d.ts +0 -0
  110. /package/dist/types/src/{hooks/automerge → automerge/automerge-plugin}/amToCodemirror.d.ts +0 -0
  111. /package/dist/types/src/{hooks/automerge → automerge/automerge-plugin}/codeMirrorToAm.d.ts +0 -0
  112. /package/dist/types/src/{hooks/automerge → automerge/automerge-plugin}/handle.d.ts +0 -0
  113. /package/dist/types/src/{hooks/automerge → automerge/automerge-plugin}/index.d.ts +0 -0
  114. /package/dist/types/src/{hooks/automerge → automerge/automerge-plugin}/plugin.d.ts +0 -0
  115. /package/dist/types/src/{hooks/automerge → automerge}/automerge.stories.d.ts +0 -0
  116. /package/src/{hooks/automerge → automerge/automerge-plugin}/PatchSemaphore.ts +0 -0
  117. /package/src/{hooks/automerge → automerge/automerge-plugin}/amToCodemirror.ts +0 -0
  118. /package/src/{hooks/automerge → automerge/automerge-plugin}/codeMirrorToAm.ts +0 -0
  119. /package/src/{hooks/automerge → automerge/automerge-plugin}/handle.ts +0 -0
  120. /package/src/{hooks/automerge → automerge/automerge-plugin}/index.ts +0 -0
  121. /package/src/{hooks/automerge → automerge/automerge-plugin}/plugin.ts +0 -0
@@ -1,128 +1,149 @@
1
1
  // packages/ui/react-ui-editor/src/index.ts
2
2
  import { TextKind } from "@dxos/protocols/proto/dxos/echo/model/text";
3
- import { Doc, YText, YXmlFragment } from "@dxos/text-model";
3
+ import { Doc, YText as YText2, YXmlFragment } from "@dxos/text-model";
4
4
 
5
5
  // packages/ui/react-ui-editor/src/components/TextEditor/index.ts
6
6
  import { tags as tags2 } from "@lezer/highlight";
7
7
 
8
- // packages/ui/react-ui-editor/src/components/TextEditor/extensions/autocomplete.ts
9
- import { autocompletion, completionKeymap } from "@codemirror/autocomplete";
10
- import { keymap } from "@codemirror/view";
11
- var autocomplete = ({ getOptions }) => {
12
- return [
13
- // https://codemirror.net/docs/ref/#view.keymap
14
- // https://discuss.codemirror.net/t/how-can-i-replace-the-default-autocompletion-keymap-v6/3322
15
- keymap.of(completionKeymap),
16
- // https://codemirror.net/examples/autocompletion
17
- // https://codemirror.net/docs/ref/#autocomplete.autocompletion
18
- autocompletion({
19
- // TODO(burdon): Set custom keymap.
20
- // defaultKeymap: false,
21
- // Don't start unless key press.
22
- activateOnTyping: false,
23
- // TODO(burdon): Option to create new page?
24
- // TODO(burdon): Optional decoration via addToOptions
25
- override: [
26
- (context) => {
27
- const word = context.matchBefore(/\w*/);
28
- if (!word || word.from === word.to && !context.explicit) {
29
- return null;
30
- }
31
- return {
32
- from: word.from,
33
- options: getOptions(word.text.toLowerCase())
34
- };
35
- }
36
- ]
37
- })
38
- ];
39
- };
40
-
41
- // packages/ui/react-ui-editor/src/components/TextEditor/extensions/basic.ts
8
+ // packages/ui/react-ui-editor/src/components/TextEditor/extensions/basic/bundle.ts
42
9
  import { closeBrackets } from "@codemirror/autocomplete";
43
10
  import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
44
11
  import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
45
12
  import { EditorView, placeholder } from "@codemirror/view";
46
13
  var basicBundle = ({ themeMode, placeholder: _placeholder }) => [
47
- // TODO(burdon): Compare with minimalSetup.
48
- // https://codemirror.net/docs/ref/#codemirror.minimalSetup
49
14
  bracketMatching(),
50
15
  closeBrackets(),
51
- EditorView.lineWrapping,
52
16
  _placeholder && placeholder(_placeholder),
17
+ EditorView.lineWrapping,
53
18
  // TODO(burdon): Is this required?
54
19
  themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)
55
20
  ].filter(Boolean);
56
21
 
57
- // packages/ui/react-ui-editor/src/components/TextEditor/extensions/link.ts
58
- import { syntaxTree } from "@codemirror/language";
59
- import { RangeSetBuilder, StateField } from "@codemirror/state";
60
- import { Decoration, EditorView as EditorView2, WidgetType } from "@codemirror/view";
61
- var LinkButton = class extends WidgetType {
62
- constructor(_pos, _url, _onAttach) {
63
- super();
64
- this._pos = _pos;
65
- this._url = _url;
66
- this._onAttach = _onAttach;
67
- }
68
- eq(other) {
69
- return this._pos === other._pos && this._url === other._url;
70
- }
71
- toDOM(view) {
72
- const el = document.createElement("span");
73
- this._onAttach(el, this._url);
74
- return el;
22
+ // packages/ui/react-ui-editor/src/components/TextEditor/extensions/basic/theme.ts
23
+ import get from "lodash.get";
24
+
25
+ // packages/ui/react-ui-editor/src/styles/markdown.ts
26
+ import { mx } from "@dxos/react-ui-theme";
27
+ var heading = {
28
+ 1: "mbs-4 mbe-2 text-4xl font-semibold text-inherit no-underline",
29
+ 2: "mbs-4 mbe-2 text-3xl font-bold text-inherit no-underline",
30
+ 3: "mbs-4 mbe-2 text-2xl font-bold text-inherit no-underline",
31
+ 4: "mbs-4 mbe-2 text-xl font-extrabold text-inherit no-underline",
32
+ 5: "mbs-4 mbe-2 text-lg font-extrabold text-inherit no-underline",
33
+ 6: "mbs-4 mbe-2 font-black text-inherit no-underline"
34
+ };
35
+ var bold = "font-bold";
36
+ var code = "font-mono bg-neutral-500/10 rounded pli-0.5 plb-0.5 -mlb-0.5";
37
+ var codeWithoutMarks = mx(code, "pli-1.5 mli-0.5");
38
+ var italic = "italic";
39
+ var strikethrough = "line-through";
40
+ var mark = "!font-normal !no-underline !text-inherit opacity-40";
41
+
42
+ // packages/ui/react-ui-editor/src/styles/tokens.ts
43
+ import { tailwindConfig } from "@dxos/react-ui-theme";
44
+ var tokens = tailwindConfig({}).theme;
45
+
46
+ // packages/ui/react-ui-editor/src/components/TextEditor/extensions/basic/theme.ts
47
+ var basicTheme = {
48
+ "&.cm-focused": {
49
+ outline: "none"
50
+ },
51
+ "& .cm-line": {
52
+ paddingInline: 0,
53
+ lineHeight: 1.6,
54
+ minBlockSize: "1.6em"
55
+ },
56
+ "& .cm-line *": {
57
+ lineHeight: 1.6
58
+ },
59
+ "& .cm-scroller": {
60
+ fontFamily: get(tokens, "fontFamily.body", []).join(","),
61
+ overflow: "visible"
62
+ },
63
+ "& .cm-content": {
64
+ padding: 0,
65
+ caretColor: "black"
66
+ },
67
+ ".dark & .cm-content": {
68
+ caretColor: "white"
69
+ },
70
+ "& .cm-tooltip": {
71
+ backgroundColor: "transparent",
72
+ border: "none"
73
+ },
74
+ "& .cm-link": {
75
+ color: get(tokens, "extend.colors.primary.500"),
76
+ textDecoration: "underline"
75
77
  }
76
78
  };
77
- var LinkText = class extends WidgetType {
78
- constructor(_pos, _text, _url) {
79
+
80
+ // packages/ui/react-ui-editor/src/components/TextEditor/extensions/change.ts
81
+ import { StateField } from "@codemirror/state";
82
+ var onChangeExtension = (onChange) => StateField.define({
83
+ create: () => null,
84
+ update: (_value, transaction) => {
85
+ if (transaction.docChanged && onChange) {
86
+ onChange(transaction.newDoc.toString());
87
+ }
88
+ return null;
89
+ }
90
+ });
91
+
92
+ // packages/ui/react-ui-editor/src/components/TextEditor/extensions/hyperlink/hyperlinkDecoration.ts
93
+ import { syntaxTree } from "@codemirror/language";
94
+ import { RangeSetBuilder, StateField as StateField2 } from "@codemirror/state";
95
+ import { Decoration, EditorView as EditorView2, WidgetType } from "@codemirror/view";
96
+ var Link = class extends WidgetType {
97
+ constructor(_anchor, _text, _url) {
79
98
  super();
80
- this._pos = _pos;
99
+ this._anchor = _anchor;
81
100
  this._text = _text;
82
101
  this._url = _url;
83
102
  }
84
103
  eq(other) {
85
- return this._pos === other._pos && this._url === other._url;
104
+ return this._text === other.text && this._url === other.url;
86
105
  }
87
106
  toDOM(view) {
88
- const link2 = document.createElement("a");
89
- link2.setAttribute("class", "cm-link");
90
- link2.textContent = this._text;
107
+ const link = document.createElement("a");
108
+ link.setAttribute("class", "cm-link");
109
+ link.textContent = this._text;
91
110
  if (this._url) {
92
- link2.setAttribute("rel", "noreferrer");
93
- link2.setAttribute("target", "_blank");
94
- link2.href = this._url;
111
+ link.setAttribute("target", "_blank");
112
+ link.href = this._url;
95
113
  } else {
96
- link2.onclick = () => {
114
+ link.onclick = () => {
97
115
  view.dispatch({
98
116
  selection: {
99
- anchor: this._pos
117
+ anchor: this._anchor
100
118
  }
101
119
  });
102
120
  };
103
121
  }
104
- return link2;
122
+ return link;
105
123
  }
106
124
  };
107
- var update = (state, options) => {
125
+ var hyperlinkDecoration = ({ link } = {}) => {
126
+ return StateField2.define({
127
+ create: (state) => update(state, link),
128
+ update: (_, tr) => update(tr.state, link),
129
+ provide: (field) => EditorView2.decorations.from(field)
130
+ });
131
+ };
132
+ var update = (state, link) => {
108
133
  const builder = new RangeSetBuilder();
109
134
  const cursor = state.selection.main.head;
110
135
  syntaxTree(state).iterate({
111
136
  enter: (node) => {
112
- if (node.name === "Link") {
113
- const marks = node.node.getChildren("LinkMark");
114
- const text = marks.length >= 2 ? state.sliceDoc(marks[0].to, marks[1].from) : "";
115
- const urlNode = node.node.getChild("URL");
116
- const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
117
- if (cursor < node.from || cursor > node.to) {
137
+ if (cursor < node.from || cursor > node.to) {
138
+ if (node.name === "Link") {
139
+ const marks = node.node.getChildren("LinkMark");
140
+ const text = marks.length >= 2 ? state.sliceDoc(marks[0].to, marks[1].from) : "";
141
+ const urlNode = node.node.getChild("URL");
142
+ const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
118
143
  builder.add(node.from, node.to, Decoration.replace({
119
- widget: new LinkText(node.from, text, options.link ? url : void 0)
120
- }));
121
- }
122
- if (options.onRender) {
123
- builder.add(node.to, node.to, Decoration.replace({
124
- widget: new LinkButton(node.from, url, options.onRender)
144
+ widget: new Link(node.from, text, link ? url : void 0)
125
145
  }));
146
+ return false;
126
147
  }
127
148
  }
128
149
  return true;
@@ -130,26 +151,143 @@ var update = (state, options) => {
130
151
  });
131
152
  return builder.finish();
132
153
  };
133
- var link = (options = {}) => {
134
- return StateField.define({
135
- create: (state) => update(state, options),
136
- update: (_, tr) => update(tr.state, options),
137
- provide: (field) => EditorView2.decorations.from(field)
138
- });
139
- };
140
154
 
141
- // packages/ui/react-ui-editor/src/components/TextEditor/extensions/listener.ts
142
- import { StateField as StateField2 } from "@codemirror/state";
143
- var listener = (onChange) => StateField2.define({
144
- create: () => null,
145
- update: (_value, transaction) => {
146
- if (transaction.docChanged && onChange) {
147
- onChange(transaction.newDoc.toString());
155
+ // packages/ui/react-ui-editor/src/components/TextEditor/extensions/hyperlink/hyperlinkTooltip.tsx
156
+ import { hoverTooltip } from "@codemirror/view";
157
+ import { tooltipContent } from "@dxos/react-ui-theme";
158
+ var markdownLinkRegexp = /\[([^\]]+)]\(([^)]+)\)/;
159
+ var createHyperlinkTooltip = (onHover, regexp = markdownLinkRegexp) => hoverTooltip((view, pos) => {
160
+ const { from, text } = view.state.doc.lineAt(pos);
161
+ const p = pos - from;
162
+ let idx = 0;
163
+ let match;
164
+ do {
165
+ match = text.substring(idx).match(regexp);
166
+ if (!match) {
167
+ match = void 0;
168
+ break;
169
+ }
170
+ idx = text.indexOf(match[0]);
171
+ if (p >= idx && p < idx + match[0].length) {
172
+ break;
148
173
  }
174
+ idx += match[0].length;
175
+ } while (true);
176
+ if (!match) {
149
177
  return null;
150
178
  }
179
+ const [, , url] = match ?? [];
180
+ return {
181
+ pos: idx + from,
182
+ end: idx + from + match[0].length,
183
+ above: true,
184
+ create: () => {
185
+ const el = document.createElement("a");
186
+ el.innerText = "_";
187
+ el.className = tooltipContent({}, "mb-2 p-1");
188
+ el.setAttribute("target", "_blank");
189
+ el.setAttribute("href", url);
190
+ onHover(el, url);
191
+ return {
192
+ dom: el
193
+ };
194
+ }
195
+ };
151
196
  });
152
197
 
198
+ // packages/ui/react-ui-editor/src/components/TextEditor/extensions/hyperlink/hyperlinkWidget.tsx
199
+ import { Decoration as Decoration2, EditorView as EditorView3, MatchDecorator, ViewPlugin } from "@codemirror/view";
200
+ var markdownLinkRegexp2 = /\[([^\]]+)]\(([^)]+)\)(!?)/gi;
201
+ var linkDecorator = () => new MatchDecorator({
202
+ regexp: markdownLinkRegexp2,
203
+ decorate: (add, from, to, match, view) => {
204
+ const [_, label, url] = match;
205
+ const p0 = {
206
+ start: from,
207
+ end: from + 1
208
+ };
209
+ const p1 = {
210
+ start: from + 1,
211
+ end: from + 1 + label.length
212
+ };
213
+ const p2 = {
214
+ start: p1.end,
215
+ end: p1.end + 1
216
+ };
217
+ const p3 = {
218
+ start: p1.end + 1,
219
+ end: p1.end + 1 + url.length + 2
220
+ };
221
+ add(p0.start, p0.end, Decoration2.mark({
222
+ class: "cm-hyperlink-bracket",
223
+ _attributes: {
224
+ style: "display: none"
225
+ }
226
+ }));
227
+ add(p1.start, p1.end, Decoration2.mark({
228
+ class: "cm-hyperlink-label"
229
+ }));
230
+ add(p2.start, p2.end, Decoration2.mark({
231
+ class: "cm-hyperlink-bracket",
232
+ _attributes: {
233
+ style: "display: none"
234
+ }
235
+ }));
236
+ add(p3.start, p3.end, Decoration2.mark({
237
+ class: "cm-hyperlink-url",
238
+ _attributes: {
239
+ style: "display: none"
240
+ }
241
+ }));
242
+ }
243
+ });
244
+ function hyperLinkExtension() {
245
+ return ViewPlugin.fromClass(class HyperLinkView {
246
+ constructor(view) {
247
+ this.decorator = linkDecorator();
248
+ this.decorations = this.decorator.createDeco(view);
249
+ }
250
+ update(update2) {
251
+ if (update2.docChanged || update2.viewportChanged) {
252
+ this.decorations = this.decorator.updateDeco(update2, this.decorations);
253
+ }
254
+ }
255
+ }, {
256
+ decorations: (view) => view.decorations,
257
+ eventHandlers: {
258
+ // TODO(burdon): CLick to expand link.
259
+ // https://discuss.codemirror.net/t/decorator-iteration-on-click-event/4226/2
260
+ mousedown: function(event, view) {
261
+ const pos = view.posAtDOM(event.target);
262
+ if (pos !== 0) {
263
+ console.log(this);
264
+ }
265
+ },
266
+ // TODO(burdon): Hide when cursor moves away.
267
+ keydown: (event, view) => {
268
+ view.update([]);
269
+ }
270
+ }
271
+ });
272
+ }
273
+ var hyperlinkStyle = EditorView3.baseTheme({
274
+ ".cm-hyperlink-label": {
275
+ cursor: "pointer",
276
+ textDecoration: "underline"
277
+ },
278
+ ".cm-hyperlink-bracket": {
279
+ opacity: 0.2
280
+ },
281
+ ".cm-hyperlink-url": {
282
+ opacity: 0.5,
283
+ fontFamily: "monospace"
284
+ }
285
+ });
286
+ var hyperlinkWidget = [
287
+ hyperLinkExtension(),
288
+ hyperlinkStyle
289
+ ];
290
+
153
291
  // packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/bundle.ts
154
292
  import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
155
293
  import { defaultKeymap, history, historyKeymap, indentWithTab } from "@codemirror/commands";
@@ -160,59 +298,222 @@ import { lintKeymap } from "@codemirror/lint";
160
298
  import { highlightSelectionMatches, searchKeymap } from "@codemirror/search";
161
299
  import { EditorState } from "@codemirror/state";
162
300
  import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
163
- import { crosshairCursor, drawSelection, dropCursor, EditorView as EditorView3, highlightActiveLine, highlightActiveLineGutter, highlightSpecialChars, keymap as keymap2, placeholder as placeholder2, rectangularSelection } from "@codemirror/view";
301
+ import { crosshairCursor, drawSelection, dropCursor, EditorView as EditorView4, highlightActiveLine, highlightActiveLineGutter, highlightSpecialChars, keymap, placeholder as placeholder2, rectangularSelection } from "@codemirror/view";
164
302
 
165
- // packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/highlight.ts
166
- import { markdownLanguage } from "@codemirror/lang-markdown";
167
- import { HighlightStyle } from "@codemirror/language";
168
- import { tags, styleTags, Tag } from "@lezer/highlight";
169
- import get from "lodash.get";
170
-
171
- // packages/ui/react-ui-editor/src/styles/markdown.ts
172
- import { mx } from "@dxos/react-ui-theme";
173
- var heading = {
174
- 1: "mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
175
- 2: "mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
176
- 3: "mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
177
- 4: "mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
178
- 5: "mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
179
- 6: "mbs-4 mbe-2 font-medium text-inherit no-underline"
180
- };
181
- var light = "text-neutral-200 dark:text-neutral-800";
182
- var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
183
- var bold = "font-bold";
184
- var italic = "italic";
185
- var strikethrough = "line-through";
186
- var code = "font-mono !no-underline text-neutral-700 dark:text-neutral-300";
187
- var codeMark = "font-mono text-primary-500";
188
- var inlineUrl = mx(code, "px-1");
189
- var blockquote = mx("pl-1 mr-1 border-is-4 border-primary-500/70 dark:border-primary-500/30", light);
190
- var horizontalRule = "flex mlb-4 border-b text-neutral-100 dark:text-neutral-900 border-neutral-500/50";
191
-
192
- // packages/ui/react-ui-editor/src/styles/tokens.ts
193
- import { tailwindConfig } from "@dxos/react-ui-theme";
194
- var tokens = tailwindConfig({}).theme;
195
-
196
- // packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/highlight.ts
303
+ // packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/tags.ts
304
+ import { styleTags, Tag } from "@lezer/highlight";
197
305
  var markdownTags = {
198
- Blockquote: Tag.define(),
199
- CodeMark: Tag.define(),
200
- CodeText: Tag.define(),
201
- EmphasisMark: Tag.define(),
202
- HeaderMark: Tag.define(),
203
- HorizontalRule: Tag.define(),
204
- InlineCode: Tag.define(),
205
- LinkLabel: Tag.define(),
206
- LinkReference: Tag.define(),
207
- ListMark: Tag.define(),
208
- QuoteMark: Tag.define(),
209
- URL: Tag.define()
306
+ headingMark: Tag.define(),
307
+ quoteMark: Tag.define(),
308
+ listMark: Tag.define(),
309
+ linkMark: Tag.define(),
310
+ emphasisMark: Tag.define(),
311
+ codeMark: Tag.define(),
312
+ codeText: Tag.define(),
313
+ inlineCode: Tag.define(),
314
+ url: Tag.define(),
315
+ linkReference: Tag.define(),
316
+ linkLabel: Tag.define()
210
317
  };
211
318
  var markdownTagsExtension = {
212
319
  props: [
213
- styleTags(markdownTags)
320
+ styleTags({
321
+ HeaderMark: markdownTags.headingMark,
322
+ QuoteMark: markdownTags.quoteMark,
323
+ ListMark: markdownTags.listMark,
324
+ LinkMark: markdownTags.linkMark,
325
+ EmphasisMark: markdownTags.emphasisMark,
326
+ CodeMark: markdownTags.codeMark,
327
+ CodeText: markdownTags.codeText,
328
+ InlineCode: markdownTags.inlineCode,
329
+ URL: markdownTags.url,
330
+ LinkReference: markdownTags.linkReference,
331
+ LinkLabel: markdownTags.linkLabel
332
+ })
214
333
  ]
215
334
  };
335
+
336
+ // packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/theme.ts
337
+ import { markdownLanguage } from "@codemirror/lang-markdown";
338
+ import { HighlightStyle } from "@codemirror/language";
339
+ import { tags } from "@lezer/highlight";
340
+ import get2 from "lodash.get";
341
+ var chalky = "#e5c07b";
342
+ var coral = "#e06c75";
343
+ var cyan = "#56b6c2";
344
+ var invalid = "#ffffff";
345
+ var ivory = "#abb2bf";
346
+ var stone = "#7d8799";
347
+ var malibu = "#61afef";
348
+ var sage = "#98c379";
349
+ var whiskey = "#d19a66";
350
+ var violet = "#c678dd";
351
+ var highlightBackground = "#2c313a";
352
+ var tooltipBackground = "#353a42";
353
+ var monospace = get2(tokens, "fontFamily.mono", [
354
+ "monospace"
355
+ ]).join(",");
356
+ var markdownTheme = {
357
+ // TODO(thure): Consider whether these commented-out rules from one-dark-theme should be integrated.
358
+ // '&': {
359
+ // color: ivory,
360
+ // backgroundColor: background
361
+ // },
362
+ // '.cm-cursor, .cm-dropCursor': { borderLeftColor: cursor },
363
+ // '&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection': {
364
+ // backgroundColor: selection
365
+ // },
366
+ // '.cm-panels': { backgroundColor: darkBackground, color: ivory },
367
+ // '.cm-panels.cm-panels-top': { borderBottom: '2px solid black' },
368
+ // '.cm-panels.cm-panels-bottom': { borderTop: '2px solid black' },
369
+ // '.cm-searchMatch': {
370
+ // backgroundColor: '#72a1ff59',
371
+ // outline: '1px solid #457dff'
372
+ // },
373
+ // '.cm-searchMatch.cm-searchMatch-selected': {
374
+ // backgroundColor: '#6199ff2f'
375
+ // },
376
+ // '.cm-activeLine': { backgroundColor: '#6699ff0b' },
377
+ // '.cm-selectionMatch': { backgroundColor: '#aafe661a' },
378
+ // '&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket': {
379
+ // backgroundColor: '#bad0f847'
380
+ // },
381
+ // '.cm-gutters': {
382
+ // backgroundColor: background,
383
+ // color: stone,
384
+ // border: 'none'
385
+ // },
386
+ // '.cm-activeLineGutter': {
387
+ // backgroundColor: highlightBackground
388
+ // },
389
+ // '.cm-foldPlaceholder': {
390
+ // backgroundColor: 'transparent',
391
+ // border: 'none',
392
+ // color: '#ddd'
393
+ // },
394
+ "& .cm-tooltip": {
395
+ backgroundColor: "transparent",
396
+ border: "none"
397
+ },
398
+ // '.dark & .cm-tooltip': {
399
+ // border: 'none',
400
+ // backgroundColor: tooltipBackground,
401
+ // },
402
+ // '.dark & .cm-tooltip .cm-tooltip-arrow:before': {
403
+ // borderTopColor: 'transparent',
404
+ // borderBottomColor: 'transparent',
405
+ // },
406
+ // '.dark & .cm-tooltip .cm-tooltip-arrow:after': {
407
+ // borderTopColor: tooltipBackground,
408
+ // borderBottomColor: tooltipBackground,
409
+ // },
410
+ // '.dark & .cm-tooltip-autocomplete': {
411
+ // '& > ul > li[aria-selected]': {
412
+ // backgroundColor: highlightBackground,
413
+ // color: ivory,
414
+ // },
415
+ // },
416
+ "&.cm-focused": {
417
+ outline: "none"
418
+ },
419
+ "& .cm-line": {
420
+ paddingInline: 0,
421
+ lineHeight: 1.6,
422
+ minBlockSize: "1.6em"
423
+ },
424
+ "& .cm-line *": {
425
+ lineHeight: 1.6
426
+ },
427
+ "&.cm-focused .cm-selectionBackground, & .cm-selectionBackground": {
428
+ background: get2(tokens, "extend.colors.primary.150", "#00ffff")
429
+ },
430
+ ".dark & .cm-selectionBackground, .dark &.cm-focused .cm-selectionBackground": {
431
+ background: get2(tokens, "extend.colors.primary.850", "#00ffff")
432
+ },
433
+ "& .cm-selectionMatch": {
434
+ background: get2(tokens, "extend.colors.primary.250", "#00ffff") + "44"
435
+ },
436
+ ".dark & .cm-selectionMatch": {
437
+ background: get2(tokens, "extend.colors.primary.600", "#00ffff") + "44"
438
+ },
439
+ "& .cm-content": {
440
+ padding: 0,
441
+ caretColor: "black"
442
+ },
443
+ ".dark & .cm-content": {
444
+ caretColor: "white"
445
+ },
446
+ "& .cm-cursor": {
447
+ borderLeftColor: "black"
448
+ },
449
+ ".dark & .cm-cursor": {
450
+ borderLeftColor: "white"
451
+ },
452
+ ".cm-placeholder": {
453
+ fontFamily: get2(tokens, "fontFamily.body", []).join(",")
454
+ },
455
+ "& .cm-scroller": {
456
+ fontFamily: get2(tokens, "fontFamily.mono", []).join(","),
457
+ overflow: "visible"
458
+ },
459
+ "& .cm-activeLine": {
460
+ backgroundColor: "transparent"
461
+ },
462
+ ".dark & .cm-activeLine": {
463
+ backgroundColor: "transparent"
464
+ },
465
+ "& .cm-ySelectionInfo": {
466
+ fontFamily: get2(tokens, "fontFamily.body", []).join(","),
467
+ padding: "2px 4px",
468
+ marginBlockStart: "-4px"
469
+ },
470
+ "& .cm-ySelection, & .cm-selectionMatch": {
471
+ paddingBlockStart: ".15em",
472
+ paddingBlockEnd: ".15em"
473
+ },
474
+ "& .cm-ySelection, & .cm-yLineSelection": {
475
+ mixBlendMode: "multiply"
476
+ },
477
+ ".dark & .cm-ySelection, .dark & .cm-yLineSelection": {
478
+ mixBlendMode: "screen"
479
+ },
480
+ "& .cm-ySelectionCaret": {
481
+ display: "inline-block",
482
+ insetBlockStart: ".1em",
483
+ blockSize: "1.4em",
484
+ verticalAlign: "top"
485
+ },
486
+ "& .cm-yLineSelection": {
487
+ margin: "0"
488
+ },
489
+ ".cm-link": {
490
+ color: "rgb(20 89 208)",
491
+ textDecorationLine: "underline",
492
+ textDecorationThickness: "1px",
493
+ textUnderlineOffset: "2px",
494
+ borderRadius: ".125rem"
495
+ },
496
+ // TODO(burdon): Document.
497
+ ...Object.keys(get2(tokens, "extend.fontSize", {})).reduce((acc, fontSize) => {
498
+ const height = get2(tokens, [
499
+ "extend",
500
+ "fontSize",
501
+ fontSize,
502
+ 1,
503
+ "lineHeight"
504
+ ]);
505
+ acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = {
506
+ height
507
+ };
508
+ acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = {
509
+ height
510
+ };
511
+ acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = {
512
+ height
513
+ };
514
+ return acc;
515
+ }, {})
516
+ };
216
517
  var markdownHighlightStyle = HighlightStyle.define([
217
518
  {
218
519
  tag: [
@@ -252,22 +553,48 @@ var markdownHighlightStyle = HighlightStyle.define([
252
553
  ],
253
554
  color: "inherit !important"
254
555
  },
255
- // Markdown marks.
256
556
  {
257
557
  tag: [
558
+ tags.link,
559
+ tags.url
560
+ ],
561
+ color: "inherit !important",
562
+ textDecoration: "none !important"
563
+ },
564
+ {
565
+ tag: [
566
+ tags.function(tags.variableName),
567
+ tags.labelName
568
+ ],
569
+ color: malibu,
570
+ fontFamily: monospace
571
+ },
572
+ {
573
+ tag: [
574
+ markdownTags.codeMark,
575
+ markdownTags.emphasisMark,
576
+ markdownTags.headingMark,
577
+ markdownTags.linkLabel,
578
+ markdownTags.linkReference,
579
+ markdownTags.listMark,
580
+ markdownTags.quoteMark,
581
+ markdownTags.url,
258
582
  tags.meta,
259
- tags.processingInstruction,
260
- markdownTags.CodeMark,
261
- markdownTags.EmphasisMark,
262
- markdownTags.HeaderMark,
263
- markdownTags.LinkLabel,
264
- markdownTags.LinkReference,
265
- markdownTags.ListMark,
266
- markdownTags.QuoteMark
583
+ tags.processingInstruction
267
584
  ],
268
585
  class: mark
269
586
  },
270
- // Headings.
587
+ {
588
+ tag: [
589
+ markdownTags.codeText,
590
+ markdownTags.inlineCode
591
+ ],
592
+ class: "font-mono"
593
+ },
594
+ {
595
+ tag: tags.emphasis,
596
+ class: italic
597
+ },
271
598
  {
272
599
  tag: tags.heading1,
273
600
  class: heading[1]
@@ -292,61 +619,18 @@ var markdownHighlightStyle = HighlightStyle.define([
292
619
  tag: tags.heading6,
293
620
  class: heading[6]
294
621
  },
295
- // Emphasis.
296
- {
297
- tag: tags.emphasis,
298
- class: italic
299
- },
300
- {
301
- tag: tags.strong,
302
- class: bold
303
- },
304
622
  {
305
623
  tag: tags.strikethrough,
306
624
  class: strikethrough
307
625
  },
308
- // Naked URLs.
309
- {
310
- tag: [
311
- markdownTags.URL
312
- ],
313
- class: inlineUrl
314
- },
315
- // E.g., code block language (after ```).
316
- {
317
- tag: [
318
- tags.function(tags.variableName),
319
- tags.labelName
320
- ],
321
- class: codeMark
322
- },
323
- // The `markdown` extension configures extensions for `lezer` to parse markdown tokens (incl. below).
324
- // However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
325
- // when a language is specified. In this case, the syntax highlighting extensions will colorize
326
- // the code, but all other CSS properties will be inherited.
327
- {
328
- tag: [
329
- markdownTags.CodeText,
330
- markdownTags.InlineCode
331
- ],
332
- class: code
333
- },
334
- {
335
- tag: [
336
- markdownTags.QuoteMark
337
- ],
338
- class: blockquote
339
- },
340
626
  {
341
- tag: [
342
- markdownTags.HorizontalRule
343
- ],
344
- class: horizontalRule
627
+ tag: tags.strong,
628
+ class: bold
345
629
  }
346
630
  ], {
347
631
  scope: markdownLanguage,
348
632
  all: {
349
- fontFamily: get(tokens, "fontFamily.body", []).join(",")
633
+ fontFamily: get2(tokens, "fontFamily.body", []).join(",")
350
634
  }
351
635
  });
352
636
 
@@ -357,7 +641,7 @@ var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
357
641
  closeBrackets2(),
358
642
  _placeholder && placeholder2(_placeholder),
359
643
  EditorState.allowMultipleSelections.of(true),
360
- EditorView3.lineWrapping,
644
+ EditorView4.lineWrapping,
361
645
  // autocompletion(),
362
646
  crosshairCursor(),
363
647
  dropCursor(),
@@ -369,7 +653,7 @@ var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
369
653
  history(),
370
654
  indentOnInput(),
371
655
  rectangularSelection(),
372
- keymap2.of([
656
+ keymap.of([
373
657
  ...closeBracketsKeymap,
374
658
  // ...completionKeymap,
375
659
  ...defaultKeymap,
@@ -381,308 +665,23 @@ var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
381
665
  ]),
382
666
  // Main extension.
383
667
  // https://github.com/codemirror/lang-markdown
384
- // https://codemirror.net/5/mode/markdown/index.html (demo).
385
668
  markdown({
386
- // GRM by default (vs strict CommonMark):
387
- // Table, TaskList, Strikethrough, and Autolink.
388
- // NOTE: This extends the parser; it doesn't affect rendering.
389
- // https://github.github.com/gfm
390
- // https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
391
669
  base: markdownLanguage2,
392
- // Languages for syntax highlighting fenced code blocks.
393
670
  codeLanguages: languages,
394
- // Parser extensions.
395
671
  extensions: [
396
- // GFM, // TODO(burdon): Provided by default?
397
- markdownTagsExtension
398
- ]
399
- }),
400
- // Custom styles.
401
- syntaxHighlighting2(markdownHighlightStyle),
402
- // TODO(thure): All but one rule here apply to both themes; rename or refactor.
403
- themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2)
404
- ].filter(Boolean);
405
- };
406
-
407
- // packages/ui/react-ui-editor/src/components/TextEditor/extensions/tasklist.ts
408
- import { syntaxTree as syntaxTree2 } from "@codemirror/language";
409
- import { RangeSetBuilder as RangeSetBuilder2, StateField as StateField3 } from "@codemirror/state";
410
- import { EditorView as EditorView4, Decoration as Decoration2, WidgetType as WidgetType2 } from "@codemirror/view";
411
- var CheckboxWidget = class extends WidgetType2 {
412
- constructor(_pos, _getCursor, _checked) {
413
- super();
414
- this._pos = _pos;
415
- this._getCursor = _getCursor;
416
- this._checked = _checked;
417
- }
418
- eq(other) {
419
- return this._pos === other._pos && this._checked === other._checked;
420
- }
421
- toDOM(view) {
422
- const wrap = document.createElement("span");
423
- wrap.setAttribute("aria-hidden", "true");
424
- wrap.className = "cm-task-item";
425
- const box = wrap.appendChild(document.createElement("input"));
426
- box.type = "checkbox";
427
- box.checked = this._checked;
428
- box.onclick = (event) => {
429
- this._checked = !isChecked(view.state, this._pos);
430
- view.dispatch({
431
- changes: {
432
- from: this._pos + 1,
433
- to: this._pos + 2,
434
- insert: this._checked ? "x" : " "
435
- },
436
- // TODO(burdon): Restore cursor position? More useful to move to end of line (can indent).
437
- selection: {
438
- anchor: this._pos + 4
439
- }
440
- });
441
- return true;
442
- };
443
- return wrap;
444
- }
445
- // TODO(burdon): Remove listener?
446
- // override destroy() {
447
- // console.log('destroy', this._pos);
448
- // }
449
- ignoreEvent() {
450
- return false;
451
- }
452
- };
453
- var isChecked = (state, pos) => {
454
- return state.sliceDoc(pos, pos + 3).toLowerCase() === "[x]";
455
- };
456
- var statefield = () => {
457
- let lastPosition = 0;
458
- const listener2 = EditorView4.updateListener.of((update2) => {
459
- lastPosition = update2.startState.selection.main.head;
460
- });
461
- const checkbox = (state) => {
462
- const builder = new RangeSetBuilder2();
463
- syntaxTree2(state).iterate({
464
- enter: (node) => {
465
- if (node.name === "TaskMarker") {
466
- builder.add(node.from, node.to, Decoration2.replace({
467
- widget: new CheckboxWidget(node.from, () => lastPosition, isChecked(state, node.from))
468
- }));
469
- }
470
- }
471
- });
472
- return builder.finish();
473
- };
474
- return [
475
- listener2,
476
- StateField3.define({
477
- create: (state) => checkbox(state),
478
- update: (_, tr) => checkbox(tr.state),
479
- provide: (field) => EditorView4.decorations.from(field)
480
- })
481
- ];
482
- };
483
- var styles = EditorView4.baseTheme({
484
- "& .cm-task-item": {
485
- padding: "0 4px"
486
- }
487
- });
488
- var tasklist = () => [
489
- statefield(),
490
- styles
491
- ];
492
-
493
- // packages/ui/react-ui-editor/src/components/TextEditor/extensions/tooltip.tsx
494
- import { hoverTooltip } from "@codemirror/view";
495
- import { tooltipContent } from "@dxos/react-ui-theme";
496
- var markdownLinkRegexp = /\[([^\]]+)]\(([^)]+)\)/;
497
- var tooltip = ({ onHover, regexp = markdownLinkRegexp }) => hoverTooltip((view, pos) => {
498
- const { from, text } = view.state.doc.lineAt(pos);
499
- const p = pos - from;
500
- let idx = 0;
501
- let match;
502
- do {
503
- match = text.substring(idx).match(regexp);
504
- if (!match) {
505
- match = void 0;
506
- break;
507
- }
508
- idx = text.indexOf(match[0]);
509
- if (p >= idx && p < idx + match[0].length) {
510
- break;
511
- }
512
- idx += match[0].length;
513
- } while (true);
514
- if (!match) {
515
- return null;
516
- }
517
- const [, , url] = match ?? [];
518
- return {
519
- pos: idx + from,
520
- end: idx + from + match[0].length,
521
- above: true,
522
- create: () => {
523
- const el = document.createElement("div");
524
- el.className = tooltipContent({}, "pli-2 plb-1");
525
- onHover(el, url);
526
- return {
527
- dom: el,
528
- offset: {
529
- x: 0,
530
- y: 12
531
- }
532
- };
533
- }
534
- };
535
- });
536
-
537
- // packages/ui/react-ui-editor/src/components/TextEditor/themes/default.ts
538
- import get2 from "lodash.get";
539
- var defaultTheme = {
540
- //
541
- // Main layout:
542
- // <div class=".cm-editor .cm-focused">
543
- // <div class=".cm-scroller">
544
- // <div class=".cm-content" role="textbox" contenteditable="true">
545
- // <div class=".cm-line" />
546
- // </div>
547
- // </div>
548
- // </div>
549
- //
550
- "&": {},
551
- "&.cm-focused": {
552
- outline: "none"
553
- },
554
- "& .cm-scroller": {
555
- overflow: "visible"
556
- },
557
- "& .cm-content": {
558
- padding: 0,
559
- // Base font size (otherwise defined by HTML tag, which might be different for storybook).
560
- fontSize: "16px"
561
- },
562
- "&light .cm-content": {
563
- color: get2(tokens, "extend.colors.neutral.900", "black"),
564
- caretColor: "black"
565
- },
566
- "&dark .cm-content": {
567
- color: get2(tokens, "extend.colors.neutral.100", "white"),
568
- caretColor: "white"
569
- },
570
- //
571
- // Cursor
572
- //
573
- "&light .cm-cursor": {
574
- borderLeft: "2px solid black"
575
- },
576
- "&dark .cm-cursor": {
577
- borderLeft: "2px solid white"
578
- },
579
- "& .cm-placeholder": {
580
- fontWeight: 100
581
- },
582
- //
583
- // line
584
- //
585
- "& .cm-line": {
586
- paddingInline: 0
587
- },
588
- "& .cm-line *": {},
589
- "& .cm-activeLine": {
590
- backgroundColor: "transparent"
591
- },
592
- //
593
- // selection
594
- //
595
- "&light .cm-selectionBackground, &light.cm-focused .cm-selectionBackground": {
596
- background: get2(tokens, "extend.colors.primary.150", "#00ffff")
597
- },
598
- "&dark .cm-selectionBackground, &dark.cm-focused .cm-selectionBackground": {
599
- background: get2(tokens, "extend.colors.primary.850", "#00ffff")
600
- },
601
- "&light .cm-selectionMatch": {
602
- background: get2(tokens, "extend.colors.primary.250", "#00ffff") + "44"
603
- },
604
- "&dark .cm-selectionMatch": {
605
- background: get2(tokens, "extend.colors.primary.600", "#00ffff") + "44"
606
- },
607
- //
608
- // collaboration
609
- // TODO(burdon): Review classnames (YJS dependent?)
610
- //
611
- "&light .cm-ySelection, &light .cm-yLineSelection": {
612
- mixBlendMode: "multiply"
613
- },
614
- "&dark .cm-ySelection, &dark .cm-yLineSelection": {
615
- mixBlendMode: "screen"
616
- },
617
- "& .cm-ySelectionInfo": {
618
- padding: "2px 4px",
619
- marginBlockStart: "-4px"
620
- },
621
- "& .cm-ySelection, & .cm-selectionMatch": {
622
- paddingBlockStart: ".15em",
623
- paddingBlockEnd: ".15em"
624
- },
625
- "& .cm-ySelectionCaret": {
626
- display: "inline-block",
627
- insetBlockStart: ".1em",
628
- blockSize: "1.4em",
629
- verticalAlign: "top"
630
- },
631
- "& .cm-yLineSelection": {
632
- margin: 0
633
- },
634
- //
635
- // link
636
- //
637
- "& .cm-link": {
638
- color: get2(tokens, "extend.colors.primary.500"),
639
- textDecorationLine: "underline",
640
- textDecorationThickness: "1px",
641
- textUnderlineOffset: "2px",
642
- borderRadius: ".125rem",
643
- fontFamily: get2(tokens, "fontFamily.body", []).join(",")
644
- },
645
- //
646
- // tooltip
647
- //
648
- "& .cm-tooltip": {
649
- border: "none"
650
- },
651
- // '& .cm-tooltip-below': {},
652
- // '& .cm-tooltip-autocomplete': {},
653
- //
654
- // font size
655
- // TODO(thure): This appears to be the best or only way to set selection caret heights, but it's far more verbose than it needs to be.
656
- //
657
- ...Object.keys(get2(tokens, "extend.fontSize", {})).reduce((acc, fontSize) => {
658
- const height = get2(tokens, [
659
- "extend",
660
- "fontSize",
661
- fontSize,
662
- 1,
663
- "lineHeight"
664
- ]);
665
- acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = {
666
- height
667
- };
668
- acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = {
669
- height
670
- };
671
- acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = {
672
- height
673
- };
674
- return acc;
675
- }, {})
676
- };
677
- var textTheme = {
678
- "& .cm-scroller": {
679
- fontFamily: get2(tokens, "fontFamily.body", []).join(",")
680
- }
681
- };
682
- var codeTheme = {
683
- "& .cm-scroller": {
684
- fontFamily: get2(tokens, "fontFamily.mono", []).join(",")
685
- }
672
+ // TODO(burdon): This seems to upgrade the parser.
673
+ // GitHub flavored markdown bundle: Table, TaskList, Strikethrough, and Autolink.
674
+ // https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
675
+ // https://github.github.com/gfm
676
+ // GFM,
677
+ // Custom styling.
678
+ markdownTagsExtension
679
+ ]
680
+ }),
681
+ // TODO(thure): All but one rule here apply to both themes; rename or refactor.
682
+ syntaxHighlighting2(markdownHighlightStyle),
683
+ themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2)
684
+ ].filter(Boolean);
686
685
  };
687
686
 
688
687
  // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
@@ -691,174 +690,28 @@ import { EditorView as EditorView5 } from "@codemirror/view";
691
690
  import { useFocusableGroup } from "@fluentui/react-tabster";
692
691
  import { vim } from "@replit/codemirror-vim";
693
692
  import defaultsDeep from "lodash.defaultsdeep";
694
- import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useState } from "react";
695
- import { generateName } from "@dxos/display-name";
693
+ import get3 from "lodash.get";
694
+ import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useState } from "react";
695
+ import { isDocAccessor as isDocAccessor2 } from "@dxos/echo-schema";
696
696
  import { useThemeContext } from "@dxos/react-ui";
697
- import { getColorForValue, inputSurface, mx as mx2 } from "@dxos/react-ui-theme";
698
- var EditorModes = [
699
- "default",
700
- "vim"
701
- ];
702
- var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots = defaultSlots, editorMode }, forwardedRef) => {
703
- const { themeMode } = useThemeContext();
704
- const tabsterDOMAttribute = useFocusableGroup({
705
- tabBehavior: "limited"
706
- });
707
- const { awareness, peer } = model;
708
- useEffect(() => {
709
- if (awareness && peer) {
710
- awareness.setLocalStateField("user", {
711
- name: peer.name ?? generateName(peer.id),
712
- color: getColorForValue({
713
- value: peer.id,
714
- type: "color"
715
- }),
716
- colorLight: getColorForValue({
717
- value: peer.id,
718
- themeMode,
719
- type: "highlight"
720
- })
721
- });
722
- }
723
- }, [
724
- awareness,
725
- peer,
726
- themeMode
727
- ]);
728
- const [root, setRoot] = useState(null);
729
- const [state, setState] = useState();
730
- const [view, setView] = useState();
731
- useImperativeHandle(forwardedRef, () => ({
732
- root,
733
- state,
734
- view
735
- }), [
736
- view,
737
- state,
738
- root
739
- ]);
740
- useEffect(() => {
741
- if (!root) {
742
- return;
743
- }
744
- const state2 = EditorState2.create({
745
- doc: model.text(),
746
- extensions: [
747
- // TODO(burdon): Factor out VIM mode?
748
- editorMode === "vim" && vim(),
749
- // Theme.
750
- EditorView5.baseTheme(defaultTheme),
751
- EditorView5.theme(slots?.editor?.theme ?? {}),
752
- // TODO(burdon): themeMode doesn't change in storybooks.
753
- EditorView5.darkTheme.of(themeMode === "dark"),
754
- // Storage and replication.
755
- model.extension,
756
- // Custom.
757
- ...extensions
758
- ].filter(Boolean)
759
- });
760
- view?.destroy();
761
- setView(new EditorView5({
762
- state: state2,
763
- parent: root
764
- }));
765
- setState(state2);
766
- return () => {
767
- view?.destroy();
768
- setView(void 0);
769
- setState(void 0);
770
- };
771
- }, [
772
- root,
773
- model,
774
- themeMode,
775
- editorMode
776
- ]);
777
- const handleKeyUp = useCallback((event) => {
778
- const { key, altKey, shiftKey, metaKey, ctrlKey } = event;
779
- switch (key) {
780
- case "Enter": {
781
- view?.contentDOM.focus();
782
- break;
783
- }
784
- case "Escape": {
785
- editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey) && root?.focus();
786
- break;
787
- }
788
- }
789
- }, [
790
- view,
791
- editorMode
792
- ]);
793
- return /* @__PURE__ */ React.createElement("div", {
794
- key: model.id,
795
- ref: setRoot,
796
- tabIndex: 0,
797
- ...slots?.root,
798
- ...editorMode !== "vim" && tabsterDOMAttribute,
799
- onKeyUp: handleKeyUp
800
- });
801
- });
802
- var TextEditor = /* @__PURE__ */ forwardRef(({ extensions = [], slots: _slots, ...props }, forwardedRef) => {
803
- const { themeMode } = useThemeContext();
804
- const slots = defaultsDeep({}, _slots, defaultTextSlots);
805
- return /* @__PURE__ */ React.createElement(BaseTextEditor, {
806
- ref: forwardedRef,
807
- extensions: [
808
- basicBundle({
809
- themeMode,
810
- placeholder: slots?.editor?.placeholder
811
- }),
812
- ...extensions
813
- ],
814
- slots,
815
- ...props
816
- });
817
- });
818
- var MarkdownEditor = /* @__PURE__ */ forwardRef(({ extensions = [], slots: _slots, ...props }, forwardedRef) => {
819
- const { themeMode } = useThemeContext();
820
- const slots = defaultsDeep({}, _slots, defaultSlots);
821
- return /* @__PURE__ */ React.createElement(BaseTextEditor, {
822
- ref: forwardedRef,
823
- extensions: [
824
- markdownBundle({
825
- themeMode,
826
- placeholder: slots?.editor?.placeholder
827
- }),
828
- ...extensions
829
- ],
830
- slots,
831
- ...props
832
- });
833
- });
834
- var defaultSlots = {
835
- root: {
836
- className: mx2("p-2", inputSurface)
837
- }
838
- };
839
- var defaultTextSlots = {
840
- ...defaultSlots,
841
- editor: {
842
- theme: textTheme
843
- }
844
- };
845
697
 
846
- // packages/ui/react-ui-editor/src/hooks/useTextModel.ts
847
- import get3 from "lodash.get";
848
- import { useEffect as useEffect2, useState as useState2 } from "react";
698
+ // packages/ui/react-ui-editor/src/hooks/useCollaboration.ts
699
+ import { useEffect, useMemo } from "react";
849
700
  import { yCollab } from "y-codemirror.next";
850
- import { invariant } from "@dxos/invariant";
851
- import { getRawDoc, isActualAutomergeObject } from "@dxos/react-client/echo";
701
+ import { generateName } from "@dxos/display-name";
702
+ import { isDocAccessor } from "@dxos/echo-schema";
703
+ import { getColorForValue } from "@dxos/react-ui-theme";
704
+ import { YText } from "@dxos/text-model";
852
705
 
853
- // packages/ui/react-ui-editor/src/hooks/automerge/plugin.ts
854
- import { Annotation, Facet, StateEffect, StateField as StateField4 } from "@codemirror/state";
855
- import { ViewPlugin } from "@codemirror/view";
706
+ // packages/ui/react-ui-editor/src/automerge/automerge-plugin/plugin.ts
707
+ import { Annotation, Facet, StateEffect, StateField as StateField3 } from "@codemirror/state";
708
+ import { ViewPlugin as ViewPlugin2 } from "@codemirror/view";
856
709
  import * as automerge2 from "@dxos/automerge/automerge";
857
710
 
858
- // packages/ui/react-ui-editor/src/hooks/automerge/PatchSemaphore.ts
711
+ // packages/ui/react-ui-editor/src/automerge/automerge-plugin/PatchSemaphore.ts
859
712
  import { next as automerge } from "@dxos/automerge/automerge";
860
713
 
861
- // packages/ui/react-ui-editor/src/hooks/automerge/amToCodemirror.ts
714
+ // packages/ui/react-ui-editor/src/automerge/automerge-plugin/amToCodemirror.ts
862
715
  import { ChangeSet } from "@codemirror/state";
863
716
  var amToCodemirror_default = (view, selection, target, patches) => {
864
717
  for (const patch of patches) {
@@ -965,7 +818,7 @@ var charPath = (textPath, candidatePath) => {
965
818
  return null;
966
819
  };
967
820
 
968
- // packages/ui/react-ui-editor/src/hooks/automerge/codeMirrorToAm.ts
821
+ // packages/ui/react-ui-editor/src/automerge/automerge-plugin/codeMirrorToAm.ts
969
822
  import { next as am } from "@dxos/automerge/automerge";
970
823
  var codeMirrorToAm_default = (field, handle, transactions, state) => {
971
824
  const { lastHeads, path } = state.field(field);
@@ -988,7 +841,7 @@ var codeMirrorToAm_default = (field, handle, transactions, state) => {
988
841
  return newHeads ?? void 0;
989
842
  };
990
843
 
991
- // packages/ui/react-ui-editor/src/hooks/automerge/PatchSemaphore.ts
844
+ // packages/ui/react-ui-editor/src/automerge/automerge-plugin/PatchSemaphore.ts
992
845
  var PatchSemaphore = class {
993
846
  constructor(field) {
994
847
  this._inReconcile = false;
@@ -1029,7 +882,7 @@ var PatchSemaphore = class {
1029
882
  }
1030
883
  };
1031
884
 
1032
- // packages/ui/react-ui-editor/src/hooks/automerge/plugin.ts
885
+ // packages/ui/react-ui-editor/src/automerge/automerge-plugin/plugin.ts
1033
886
  var effectType = StateEffect.define({});
1034
887
  var updateHeads = (newHeads) => effectType.of({
1035
888
  newHeads
@@ -1040,7 +893,7 @@ var semaphoreFacet = Facet.define({
1040
893
  combine: (values) => values.at(-1)
1041
894
  });
1042
895
  var automergePlugin = (handle, path) => {
1043
- const stateField = StateField4.define({
896
+ const stateField = StateField3.define({
1044
897
  create: () => ({
1045
898
  lastHeads: automerge2.getHeads(handle.docSync()),
1046
899
  unreconciledTransactions: [],
@@ -1070,7 +923,7 @@ var automergePlugin = (handle, path) => {
1070
923
  }
1071
924
  });
1072
925
  const semaphore = new PatchSemaphore(stateField);
1073
- const viewPlugin = ViewPlugin.fromClass(class AutomergeCodemirrorViewPlugin {
926
+ const viewPlugin = ViewPlugin2.fromClass(class AutomergeCodemirrorViewPlugin {
1074
927
  constructor(view) {
1075
928
  this._handleChange = () => {
1076
929
  this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
@@ -1100,6 +953,45 @@ var automergePlugin = (handle, path) => {
1100
953
  var reconcileAnnotationType = Annotation.define();
1101
954
  var isReconcileTx = (tr) => !!tr.annotation(reconcileAnnotationType);
1102
955
 
956
+ // packages/ui/react-ui-editor/src/hooks/useCollaboration.ts
957
+ var useCollaboration = (model, themeMode) => {
958
+ const { provider, peer, content } = model;
959
+ const extension = useMemo(() => {
960
+ if (content instanceof YText) {
961
+ return yCollab(content, provider?.awareness);
962
+ } else if (isDocAccessor(content)) {
963
+ return automergePlugin(content.handle, content.path);
964
+ } else {
965
+ return void 0;
966
+ }
967
+ }, []);
968
+ useEffect(() => {
969
+ if (provider && peer) {
970
+ provider.awareness.setLocalStateField("user", {
971
+ name: peer.name ?? generateName(peer.id),
972
+ color: getColorForValue({
973
+ value: peer.id,
974
+ type: "color"
975
+ }),
976
+ colorLight: getColorForValue({
977
+ value: peer.id,
978
+ themeMode,
979
+ type: "highlight"
980
+ })
981
+ });
982
+ }
983
+ }, [
984
+ provider,
985
+ peer,
986
+ themeMode
987
+ ]);
988
+ return extension;
989
+ };
990
+
991
+ // packages/ui/react-ui-editor/src/hooks/useTextModel.ts
992
+ import { useMemo as useMemo2 } from "react";
993
+ import { getRawDoc, isActualAutomergeObject } from "@dxos/react-client/echo";
994
+
1103
995
  // packages/ui/react-ui-editor/src/hooks/yjs/cursors.ts
1104
996
  import * as random from "lib0/random";
1105
997
  var cursorColors = [
@@ -1239,89 +1131,185 @@ var SpaceAwarenessProvider = class extends Observable {
1239
1131
  };
1240
1132
 
1241
1133
  // packages/ui/react-ui-editor/src/hooks/useTextModel.ts
1242
- var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
1243
1134
  var useTextModel = ({ identity, space, text }) => {
1244
- const [model, setModel] = useState2(() => createModel({
1245
- identity,
1246
- space,
1247
- text
1248
- }));
1249
- useEffect2(() => {
1250
- setModel(createModel({
1251
- identity,
1135
+ const provider = useMemo2(() => {
1136
+ if (isActualAutomergeObject(text)) {
1137
+ return void 0;
1138
+ }
1139
+ if (!space || !text?.doc) {
1140
+ return void 0;
1141
+ }
1142
+ return new SpaceAwarenessProvider({
1252
1143
  space,
1253
- text
1254
- }));
1144
+ doc: text.doc,
1145
+ channel: `yjs.awareness.${text.id}`
1146
+ });
1255
1147
  }, [
1256
1148
  identity,
1257
1149
  space,
1150
+ text,
1151
+ text?.doc
1152
+ ]);
1153
+ const content = useMemo2(() => {
1154
+ if (isActualAutomergeObject(text)) {
1155
+ const obj = text;
1156
+ return getRawDoc(obj, [
1157
+ obj.field
1158
+ ]);
1159
+ } else {
1160
+ return text?.content;
1161
+ }
1162
+ }, [
1258
1163
  text
1259
1164
  ]);
1260
- return model;
1261
- };
1262
- var createModel = (options) => {
1263
- const { space, text } = options;
1264
- if (!space || !text?.doc || !text?.content) {
1265
- return void 0;
1266
- }
1267
1165
  if (isActualAutomergeObject(text)) {
1268
- return createAutomergeModel(options);
1269
- } else {
1270
- return createYjsModel(options);
1166
+ const obj = text;
1167
+ return {
1168
+ id: obj.id,
1169
+ content,
1170
+ provider: void 0,
1171
+ peer: identity ? {
1172
+ id: identity.identityKey.toHex(),
1173
+ name: identity.profile?.displayName
1174
+ } : void 0
1175
+ };
1176
+ }
1177
+ if (!text?.doc || !text?.content) {
1178
+ return void 0;
1271
1179
  }
1272
- };
1273
- var createYjsModel = ({ identity, space, text }) => {
1274
- invariant(space && text?.doc && text?.content, void 0, {
1275
- F: __dxlog_file2,
1276
- L: 73,
1277
- S: void 0,
1278
- A: [
1279
- "space && text?.doc && text?.content",
1280
- ""
1281
- ]
1282
- });
1283
- const provider = new SpaceAwarenessProvider({
1284
- space,
1285
- doc: text.doc,
1286
- channel: `yjs.awareness.${text.id}`
1287
- });
1288
1180
  return {
1289
1181
  id: text.doc.guid,
1290
1182
  content: text.content,
1291
- text: () => text.content.toString(),
1292
- extension: yCollab(text.content, provider.awareness),
1293
- awareness: provider.awareness,
1183
+ provider,
1294
1184
  peer: identity ? {
1295
1185
  id: identity.identityKey.toHex(),
1296
1186
  name: identity.profile?.displayName
1297
1187
  } : void 0
1298
1188
  };
1299
1189
  };
1300
- var createAutomergeModel = ({ identity, space, text }) => {
1301
- invariant(space && text?.doc && text?.content, void 0, {
1302
- F: __dxlog_file2,
1303
- L: 92,
1304
- S: void 0,
1305
- A: [
1306
- "space && text?.doc && text?.content",
1307
- ""
1308
- ]
1190
+
1191
+ // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
1192
+ var EditorModes = [
1193
+ "default",
1194
+ "vim"
1195
+ ];
1196
+ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots, editorMode }, forwardedRef) => {
1197
+ const { themeMode } = useThemeContext();
1198
+ const tabsterDOMAttribute = useFocusableGroup({
1199
+ tabBehavior: "limited"
1309
1200
  });
1310
- const obj = text;
1311
- const doc = getRawDoc(obj, [
1312
- obj.field
1201
+ const [parent, setParent] = useState(null);
1202
+ const [state, setState] = useState();
1203
+ const [view, setView] = useState();
1204
+ useImperativeHandle(forwardedRef, () => ({
1205
+ editor: parent,
1206
+ state,
1207
+ view
1208
+ }), [
1209
+ view,
1210
+ state,
1211
+ parent
1313
1212
  ]);
1314
- return {
1315
- id: obj.id,
1316
- content: doc,
1317
- text: () => get3(doc.handle.docSync(), doc.path),
1318
- extension: automergePlugin(doc.handle, doc.path),
1319
- peer: identity ? {
1320
- id: identity.identityKey.toHex(),
1321
- name: identity.profile?.displayName
1322
- } : void 0
1323
- };
1324
- };
1213
+ const collaboration = useCollaboration(model, themeMode);
1214
+ useEffect2(() => {
1215
+ if (!parent) {
1216
+ return;
1217
+ }
1218
+ const initialText = isDocAccessor2(model.content) ? get3(model.content.handle.docSync(), model.content.path) : model.content?.toString();
1219
+ const state2 = EditorState2.create({
1220
+ doc: initialText,
1221
+ extensions: [
1222
+ // TODO(burdon): Factor out VIM mode?
1223
+ editorMode === "vim" && vim(),
1224
+ // Replication.
1225
+ collaboration,
1226
+ // Theme.
1227
+ slots?.editor?.theme && EditorView5.theme(slots?.editor?.theme),
1228
+ // Custom.
1229
+ ...extensions
1230
+ ].filter(Boolean)
1231
+ });
1232
+ setState(state2);
1233
+ view?.destroy();
1234
+ setView(new EditorView5({
1235
+ state: state2,
1236
+ parent
1237
+ }));
1238
+ return () => {
1239
+ view?.destroy();
1240
+ setView(void 0);
1241
+ setState(void 0);
1242
+ };
1243
+ }, [
1244
+ parent,
1245
+ model.content,
1246
+ themeMode,
1247
+ editorMode
1248
+ ]);
1249
+ const handleKeyUp = useCallback((event) => {
1250
+ const { key, altKey, shiftKey, metaKey, ctrlKey } = event;
1251
+ switch (key) {
1252
+ case "Enter": {
1253
+ view?.contentDOM.focus();
1254
+ break;
1255
+ }
1256
+ case "Escape": {
1257
+ editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey) && parent?.focus();
1258
+ break;
1259
+ }
1260
+ }
1261
+ }, [
1262
+ view,
1263
+ editorMode
1264
+ ]);
1265
+ return /* @__PURE__ */ React.createElement("div", {
1266
+ key: model.id,
1267
+ ref: setParent,
1268
+ tabIndex: 0,
1269
+ ...slots?.root,
1270
+ ...editorMode !== "vim" && tabsterDOMAttribute,
1271
+ onKeyUp: handleKeyUp
1272
+ });
1273
+ });
1274
+ var TextEditor = /* @__PURE__ */ forwardRef(({ extensions: _extensions, slots, ...props }, forwardedRef) => {
1275
+ const { themeMode } = useThemeContext();
1276
+ const extensions = [
1277
+ ..._extensions ?? [],
1278
+ basicBundle({
1279
+ themeMode,
1280
+ placeholder: slots?.editor?.placeholder
1281
+ })
1282
+ ];
1283
+ return /* @__PURE__ */ React.createElement(BaseTextEditor, {
1284
+ ref: forwardedRef,
1285
+ extensions,
1286
+ slots: defaultsDeep({}, slots, {
1287
+ editor: {
1288
+ theme: basicTheme
1289
+ }
1290
+ }),
1291
+ ...props
1292
+ });
1293
+ });
1294
+ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ extensions: _extensions, slots, ...props }, forwardedRef) => {
1295
+ const { themeMode } = useThemeContext();
1296
+ const extensions = [
1297
+ ..._extensions ?? [],
1298
+ markdownBundle({
1299
+ themeMode
1300
+ })
1301
+ ];
1302
+ return /* @__PURE__ */ React.createElement(BaseTextEditor, {
1303
+ ref: forwardedRef,
1304
+ extensions,
1305
+ slots: defaultsDeep({}, slots, {
1306
+ editor: {
1307
+ theme: markdownTheme
1308
+ }
1309
+ }),
1310
+ ...props
1311
+ });
1312
+ });
1325
1313
  export {
1326
1314
  BaseTextEditor,
1327
1315
  Doc,
@@ -1330,27 +1318,34 @@ export {
1330
1318
  SpaceAwarenessProvider,
1331
1319
  TextEditor,
1332
1320
  TextKind,
1333
- YText,
1321
+ YText2 as YText,
1334
1322
  YXmlFragment,
1335
- autocomplete,
1336
1323
  basicBundle,
1337
- codeTheme,
1324
+ basicTheme,
1325
+ chalky,
1326
+ coral,
1327
+ createHyperlinkTooltip,
1338
1328
  cursorColor,
1339
- defaultSlots,
1340
- defaultTextSlots,
1341
- defaultTheme,
1342
- link,
1343
- listener,
1329
+ cyan,
1330
+ highlightBackground,
1331
+ hyperLinkExtension,
1332
+ hyperlinkDecoration,
1333
+ hyperlinkStyle,
1334
+ hyperlinkWidget,
1335
+ invalid,
1336
+ ivory,
1337
+ malibu,
1344
1338
  markdownBundle,
1345
1339
  markdownHighlightStyle,
1346
- markdownTags,
1347
- markdownTagsExtension,
1348
- statefield,
1349
- styles,
1340
+ markdownTheme,
1341
+ onChangeExtension,
1342
+ sage,
1343
+ stone,
1350
1344
  tags2 as tags,
1351
- tasklist,
1352
- textTheme,
1353
- tooltip,
1354
- useTextModel
1345
+ tooltipBackground,
1346
+ useCollaboration,
1347
+ useTextModel,
1348
+ violet,
1349
+ whiskey
1355
1350
  };
1356
1351
  //# sourceMappingURL=index.mjs.map