@dxos/react-ui-editor 0.8.2-main.fbd8ed0 → 0.8.2-staging.42af850

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 (180) hide show
  1. package/dist/lib/browser/index.mjs +1828 -961
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/browser/testing/index.mjs +3 -64
  5. package/dist/lib/browser/testing/index.mjs.map +4 -4
  6. package/dist/lib/node/index.cjs +2008 -1138
  7. package/dist/lib/node/index.cjs.map +4 -4
  8. package/dist/lib/node/meta.json +1 -1
  9. package/dist/lib/node/testing/index.cjs +3 -75
  10. package/dist/lib/node/testing/index.cjs.map +4 -4
  11. package/dist/lib/node-esm/index.mjs +1828 -961
  12. package/dist/lib/node-esm/index.mjs.map +4 -4
  13. package/dist/lib/node-esm/meta.json +1 -1
  14. package/dist/lib/node-esm/testing/index.mjs +3 -64
  15. package/dist/lib/node-esm/testing/index.mjs.map +4 -4
  16. package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts.map +1 -1
  17. package/dist/types/src/components/EditorToolbar/index.d.ts +1 -1
  18. package/dist/types/src/components/EditorToolbar/index.d.ts.map +1 -1
  19. package/dist/types/src/components/EditorToolbar/util.d.ts +4 -6
  20. package/dist/types/src/components/EditorToolbar/util.d.ts.map +1 -1
  21. package/dist/types/src/components/Popover/RefDropdownMenu.d.ts +21 -0
  22. package/dist/types/src/components/Popover/RefDropdownMenu.d.ts.map +1 -0
  23. package/dist/types/src/{testing → components/Popover}/RefPopover.d.ts +1 -1
  24. package/dist/types/src/components/Popover/RefPopover.d.ts.map +1 -0
  25. package/dist/types/src/components/Popover/index.d.ts +3 -0
  26. package/dist/types/src/components/Popover/index.d.ts.map +1 -0
  27. package/dist/types/src/components/index.d.ts +1 -0
  28. package/dist/types/src/components/index.d.ts.map +1 -1
  29. package/dist/types/src/defaults.d.ts +2 -5
  30. package/dist/types/src/defaults.d.ts.map +1 -1
  31. package/dist/types/src/extensions/annotations.d.ts +4 -1
  32. package/dist/types/src/extensions/annotations.d.ts.map +1 -1
  33. package/dist/types/src/extensions/autocomplete.d.ts +1 -2
  34. package/dist/types/src/extensions/autocomplete.d.ts.map +1 -1
  35. package/dist/types/src/extensions/automerge/automerge.stories.d.ts.map +1 -1
  36. package/dist/types/src/extensions/automerge/sync.d.ts.map +1 -1
  37. package/dist/types/src/extensions/awareness/awareness-provider.d.ts.map +1 -1
  38. package/dist/types/src/extensions/awareness/awareness.d.ts.map +1 -1
  39. package/dist/types/src/extensions/command/command.d.ts +1 -2
  40. package/dist/types/src/extensions/command/command.d.ts.map +1 -1
  41. package/dist/types/src/extensions/command/hint.d.ts +14 -2
  42. package/dist/types/src/extensions/command/hint.d.ts.map +1 -1
  43. package/dist/types/src/extensions/command/index.d.ts +2 -0
  44. package/dist/types/src/extensions/command/index.d.ts.map +1 -1
  45. package/dist/types/src/extensions/command/menu.d.ts +4 -14
  46. package/dist/types/src/extensions/command/menu.d.ts.map +1 -1
  47. package/dist/types/src/extensions/command/state.d.ts +1 -1
  48. package/dist/types/src/extensions/command/state.d.ts.map +1 -1
  49. package/dist/types/src/extensions/command/typeahead.d.ts +17 -0
  50. package/dist/types/src/extensions/command/typeahead.d.ts.map +1 -0
  51. package/dist/types/src/extensions/comments.d.ts +2 -12
  52. package/dist/types/src/extensions/comments.d.ts.map +1 -1
  53. package/dist/types/src/extensions/factories.d.ts +4 -0
  54. package/dist/types/src/extensions/factories.d.ts.map +1 -1
  55. package/dist/types/src/extensions/index.d.ts +2 -0
  56. package/dist/types/src/extensions/index.d.ts.map +1 -1
  57. package/dist/types/src/extensions/json.d.ts +7 -0
  58. package/dist/types/src/extensions/json.d.ts.map +1 -0
  59. package/dist/types/src/extensions/markdown/{editorAction.d.ts → action.d.ts} +1 -1
  60. package/dist/types/src/extensions/markdown/action.d.ts.map +1 -0
  61. package/dist/types/src/extensions/markdown/bundle.d.ts +2 -1
  62. package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
  63. package/dist/types/src/extensions/markdown/index.d.ts +1 -2
  64. package/dist/types/src/extensions/markdown/index.d.ts.map +1 -1
  65. package/dist/types/src/extensions/markdown/styles.d.ts.map +1 -1
  66. package/dist/types/src/extensions/outliner/commands.d.ts +10 -0
  67. package/dist/types/src/extensions/outliner/commands.d.ts.map +1 -0
  68. package/dist/types/src/extensions/outliner/editor.d.ts +5 -0
  69. package/dist/types/src/extensions/outliner/editor.d.ts.map +1 -0
  70. package/dist/types/src/extensions/outliner/editor.test.d.ts +2 -0
  71. package/dist/types/src/extensions/outliner/editor.test.d.ts.map +1 -0
  72. package/dist/types/src/extensions/outliner/index.d.ts +4 -0
  73. package/dist/types/src/extensions/outliner/index.d.ts.map +1 -0
  74. package/dist/types/src/extensions/outliner/outliner.d.ts +13 -0
  75. package/dist/types/src/extensions/outliner/outliner.d.ts.map +1 -0
  76. package/dist/types/src/extensions/outliner/outliner.test.d.ts +2 -0
  77. package/dist/types/src/extensions/outliner/outliner.test.d.ts.map +1 -0
  78. package/dist/types/src/extensions/outliner/selection.d.ts +12 -0
  79. package/dist/types/src/extensions/outliner/selection.d.ts.map +1 -0
  80. package/dist/types/src/extensions/outliner/tree.d.ts +79 -0
  81. package/dist/types/src/extensions/outliner/tree.d.ts.map +1 -0
  82. package/dist/types/src/extensions/outliner/tree.test.d.ts +2 -0
  83. package/dist/types/src/extensions/outliner/tree.test.d.ts.map +1 -0
  84. package/dist/types/src/stories/Command.stories.d.ts +7 -0
  85. package/dist/types/src/stories/Command.stories.d.ts.map +1 -0
  86. package/dist/types/src/stories/{TextEditorComments.stories.d.ts → Comments.stories.d.ts} +3 -3
  87. package/dist/types/src/stories/Comments.stories.d.ts.map +1 -0
  88. package/dist/types/src/stories/EditorToolbar.stories.d.ts +12 -0
  89. package/dist/types/src/stories/EditorToolbar.stories.d.ts.map +1 -0
  90. package/dist/types/src/stories/{TextEditorSpecial.stories.d.ts → Experimental.stories.d.ts} +3 -6
  91. package/dist/types/src/stories/Experimental.stories.d.ts.map +1 -0
  92. package/dist/types/src/stories/Markdown.stories.d.ts +46 -0
  93. package/dist/types/src/stories/Markdown.stories.d.ts.map +1 -0
  94. package/dist/types/src/stories/Outliner.stories.d.ts +26 -0
  95. package/dist/types/src/stories/Outliner.stories.d.ts.map +1 -0
  96. package/dist/types/src/stories/Preview.stories.d.ts +10 -0
  97. package/dist/types/src/stories/Preview.stories.d.ts.map +1 -0
  98. package/dist/types/src/stories/{TextEditorBasic.stories.d.ts → TextEditor.stories.d.ts} +9 -39
  99. package/dist/types/src/stories/TextEditor.stories.d.ts.map +1 -0
  100. package/dist/types/src/stories/{story-utils.d.ts → util.d.ts} +6 -6
  101. package/dist/types/src/stories/util.d.ts.map +1 -0
  102. package/dist/types/src/styles/theme.d.ts.map +1 -1
  103. package/dist/types/src/styles/tokens.d.ts.map +1 -1
  104. package/dist/types/src/testing/index.d.ts +1 -1
  105. package/dist/types/src/testing/index.d.ts.map +1 -1
  106. package/dist/types/src/testing/util.d.ts +2 -0
  107. package/dist/types/src/testing/util.d.ts.map +1 -0
  108. package/package.json +40 -34
  109. package/src/components/EditorToolbar/EditorToolbar.tsx +81 -57
  110. package/src/components/EditorToolbar/index.ts +7 -1
  111. package/src/components/EditorToolbar/util.ts +3 -4
  112. package/src/components/Popover/RefDropdownMenu.tsx +77 -0
  113. package/src/{testing → components/Popover}/RefPopover.tsx +5 -4
  114. package/src/components/Popover/index.ts +6 -0
  115. package/src/components/index.ts +1 -0
  116. package/src/defaults.ts +10 -13
  117. package/src/extensions/annotations.ts +41 -64
  118. package/src/extensions/autocomplete.ts +5 -6
  119. package/src/extensions/automerge/automerge.stories.tsx +2 -7
  120. package/src/extensions/automerge/automerge.test.tsx +3 -2
  121. package/src/extensions/automerge/sync.ts +3 -3
  122. package/src/extensions/awareness/awareness-provider.ts +4 -4
  123. package/src/extensions/awareness/awareness.ts +7 -7
  124. package/src/extensions/blast.ts +9 -9
  125. package/src/extensions/command/command.ts +1 -3
  126. package/src/extensions/command/hint.ts +7 -7
  127. package/src/extensions/command/index.ts +2 -0
  128. package/src/extensions/command/menu.ts +75 -50
  129. package/src/extensions/command/typeahead.ts +116 -0
  130. package/src/extensions/comments.ts +4 -69
  131. package/src/extensions/factories.ts +13 -0
  132. package/src/extensions/index.ts +2 -0
  133. package/src/extensions/json.ts +56 -0
  134. package/src/extensions/markdown/bundle.ts +13 -9
  135. package/src/extensions/markdown/decorate.ts +7 -7
  136. package/src/extensions/markdown/image.ts +2 -2
  137. package/src/extensions/markdown/index.ts +1 -2
  138. package/src/extensions/markdown/styles.ts +2 -1
  139. package/src/extensions/markdown/table.ts +3 -3
  140. package/src/extensions/outliner/commands.ts +270 -0
  141. package/src/extensions/outliner/editor.test.ts +33 -0
  142. package/src/extensions/outliner/editor.ts +184 -0
  143. package/src/extensions/outliner/index.ts +7 -0
  144. package/src/extensions/outliner/outliner.test.ts +99 -0
  145. package/src/extensions/outliner/outliner.ts +168 -0
  146. package/src/extensions/outliner/selection.ts +50 -0
  147. package/src/extensions/outliner/tree.test.ts +164 -0
  148. package/src/extensions/outliner/tree.ts +315 -0
  149. package/src/extensions/preview/preview.ts +5 -5
  150. package/src/stories/Command.stories.tsx +97 -0
  151. package/src/stories/{TextEditorComments.stories.tsx → Comments.stories.tsx} +13 -14
  152. package/src/{components/EditorToolbar → stories}/EditorToolbar.stories.tsx +26 -20
  153. package/src/stories/{TextEditorSpecial.stories.tsx → Experimental.stories.tsx} +9 -30
  154. package/src/stories/Markdown.stories.tsx +121 -0
  155. package/src/stories/Outliner.stories.tsx +108 -0
  156. package/src/stories/{TextEditorPreview.stories.tsx → Preview.stories.tsx} +46 -136
  157. package/src/stories/TextEditor.stories.tsx +256 -0
  158. package/src/stories/{story-utils.tsx → util.tsx} +21 -22
  159. package/src/styles/theme.ts +12 -5
  160. package/src/styles/tokens.ts +1 -2
  161. package/src/testing/index.ts +1 -1
  162. package/src/testing/util.ts +5 -0
  163. package/dist/types/src/components/EditorToolbar/EditorToolbar.stories.d.ts +0 -53
  164. package/dist/types/src/components/EditorToolbar/EditorToolbar.stories.d.ts.map +0 -1
  165. package/dist/types/src/components/EditorToolbar/comment.d.ts +0 -18
  166. package/dist/types/src/components/EditorToolbar/comment.d.ts.map +0 -1
  167. package/dist/types/src/extensions/markdown/editorAction.d.ts.map +0 -1
  168. package/dist/types/src/extensions/markdown/outliner.d.ts +0 -12
  169. package/dist/types/src/extensions/markdown/outliner.d.ts.map +0 -1
  170. package/dist/types/src/stories/TextEditorBasic.stories.d.ts.map +0 -1
  171. package/dist/types/src/stories/TextEditorComments.stories.d.ts.map +0 -1
  172. package/dist/types/src/stories/TextEditorPreview.stories.d.ts +0 -13
  173. package/dist/types/src/stories/TextEditorPreview.stories.d.ts.map +0 -1
  174. package/dist/types/src/stories/TextEditorSpecial.stories.d.ts.map +0 -1
  175. package/dist/types/src/stories/story-utils.d.ts.map +0 -1
  176. package/dist/types/src/testing/RefPopover.d.ts.map +0 -1
  177. package/src/components/EditorToolbar/comment.ts +0 -30
  178. package/src/extensions/markdown/outliner.ts +0 -235
  179. package/src/stories/TextEditorBasic.stories.tsx +0 -333
  180. /package/src/extensions/markdown/{editorAction.ts → action.ts} +0 -0
@@ -35,12 +35,15 @@ var translations_default = [
35
35
 
36
36
  // packages/ui/react-ui-editor/src/index.ts
37
37
  import { EditorState as EditorState4 } from "@codemirror/state";
38
- import { EditorView as EditorView23, keymap as keymap11 } from "@codemirror/view";
38
+ import { EditorView as EditorView24, keymap as keymap13 } from "@codemirror/view";
39
39
  import { tags as tags2 } from "@lezer/highlight";
40
40
  import { TextKind } from "@dxos/protocols/proto/dxos/echo/model/text";
41
41
 
42
42
  // packages/ui/react-ui-editor/src/components/EditorToolbar/EditorToolbar.tsx
43
- import React3, { memo, useCallback } from "react";
43
+ import { useSignals as _useSignals } from "@preact-signals/safe-react/tracking";
44
+ import { Rx } from "@effect-rx/rx-react";
45
+ import React3, { memo, useMemo as useMemo3 } from "react";
46
+ import { rxFromSignal } from "@dxos/app-graph";
44
47
  import { ElevationProvider } from "@dxos/react-ui";
45
48
  import { MenuProvider, ToolbarMenu, createGapSeparator, useMenuActions } from "@dxos/react-ui-menu";
46
49
  import { textBlockWidth } from "@dxos/react-ui-theme";
@@ -71,233 +74,51 @@ var createEditorActionGroup = (id, props, icon) => createMenuItemGroup(id, {
71
74
  });
72
75
 
73
76
  // packages/ui/react-ui-editor/src/extensions/annotations.ts
74
- import { StateField } from "@codemirror/state";
75
- import { Decoration, EditorView } from "@codemirror/view";
76
- import { isNotFalsy } from "@dxos/util";
77
-
78
- // packages/ui/react-ui-editor/src/util/facet.ts
79
- import { Facet } from "@codemirror/state";
80
- var singleValueFacet = (defaultValue) => Facet.define({
81
- // Called immediately.
82
- combine: (providers) => {
83
- return providers[0] ?? defaultValue;
84
- }
85
- });
86
-
87
- // packages/ui/react-ui-editor/src/util/cursor.ts
88
- var overlap = (a, b) => a.from <= b.to && a.to >= b.from;
89
- var defaultCursorConverter = {
90
- toCursor: (position) => position.toString(),
91
- fromCursor: (cursor) => parseInt(cursor)
92
- };
93
- var Cursor = class _Cursor {
94
- static {
95
- this.converter = singleValueFacet(defaultCursorConverter);
96
- }
97
- static {
98
- this.getCursorFromRange = (state, range) => {
99
- const cursorConverter2 = state.facet(_Cursor.converter);
100
- const from = cursorConverter2.toCursor(range.from);
101
- const to = cursorConverter2.toCursor(range.to, -1);
102
- return [
103
- from,
104
- to
105
- ].join(":");
106
- };
107
- }
108
- static {
109
- this.getRangeFromCursor = (state, cursor) => {
110
- const cursorConverter2 = state.facet(_Cursor.converter);
111
- const parts = cursor.split(":");
112
- const from = cursorConverter2.fromCursor(parts[0]);
113
- const to = cursorConverter2.fromCursor(parts[1]);
114
- return from !== void 0 && to !== void 0 ? {
115
- from,
116
- to
117
- } : void 0;
118
- };
119
- }
120
- };
121
-
122
- // packages/ui/react-ui-editor/src/util/debug.ts
123
- import { log } from "@dxos/log";
124
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util/debug.ts";
125
- var wrapWithCatch = (fn) => {
126
- return (...args) => {
127
- try {
128
- return fn(...args);
129
- } catch (err) {
130
- log.catch(err, void 0, {
131
- F: __dxlog_file,
132
- L: 15,
133
- S: void 0,
134
- C: (f, a) => f(...a)
135
- });
136
- }
137
- };
138
- };
139
- var callbackWrapper = (fn) => (...args) => {
140
- try {
141
- return fn(...args);
142
- } catch (err) {
143
- log.catch(err, void 0, {
144
- F: __dxlog_file,
145
- L: 29,
146
- S: void 0,
147
- C: (f, a) => f(...a)
148
- });
149
- }
150
- };
151
- var debugDispatcher = (trs, view) => {
152
- logChanges(trs);
153
- view.update(trs);
154
- };
155
- var logChanges = (trs) => {
156
- const changes = trs.flatMap((tr) => {
157
- if (tr.changes.empty) {
158
- return void 0;
159
- }
160
- const changes2 = [];
161
- tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => changes2.push(JSON.stringify({
162
- fromA,
163
- toA,
164
- fromB,
165
- toB,
166
- inserted: inserted.toString()
167
- })));
168
- return changes2;
169
- }).filter(Boolean);
170
- if (changes.length) {
171
- log("changes", {
172
- changes
173
- }, {
174
- F: __dxlog_file,
175
- L: 62,
176
- S: void 0,
177
- C: (f, a) => f(...a)
178
- });
179
- }
180
- };
181
-
182
- // packages/ui/react-ui-editor/src/util/dom.ts
183
- var flattenRect = (rect, left) => {
184
- const x = left ? rect.left : rect.right;
185
- return {
186
- left: x,
187
- right: x,
188
- top: rect.top,
189
- bottom: rect.bottom
190
- };
191
- };
192
- var scratchRange;
193
- var textRange = (node, from, to = from) => {
194
- const range = scratchRange || (scratchRange = document.createRange());
195
- range.setEnd(node, to);
196
- range.setStart(node, from);
197
- return range;
198
- };
199
- var clientRectsFor = (dom) => {
200
- if (dom.nodeType === 3) {
201
- return textRange(dom, 0, dom.nodeValue.length).getClientRects();
202
- } else if (dom.nodeType === 1) {
203
- return dom.getClientRects();
204
- } else {
205
- return [];
206
- }
207
- };
208
-
209
- // packages/ui/react-ui-editor/src/util/react.tsx
210
- import React from "react";
211
- import { createRoot } from "react-dom/client";
212
- import { ThemeProvider, Tooltip } from "@dxos/react-ui";
213
- import { defaultTx } from "@dxos/react-ui-theme";
214
- var createElement = (tag, options, children) => {
215
- const el = document.createElement(tag);
216
- if (options?.className) {
217
- el.className = options.className;
218
- }
219
- if (children) {
220
- el.append(...Array.isArray(children) ? children : [
221
- children
222
- ]);
223
- }
224
- return el;
225
- };
226
- var renderRoot = (root, node) => {
227
- createRoot(root).render(/* @__PURE__ */ React.createElement(ThemeProvider, {
228
- tx: defaultTx
229
- }, node));
230
- return root;
231
- };
232
- var createRenderer = (Component) => (el, props) => {
233
- renderRoot(el, /* @__PURE__ */ React.createElement(ThemeProvider, {
234
- tx: defaultTx
235
- }, /* @__PURE__ */ React.createElement(Tooltip.Provider, null, /* @__PURE__ */ React.createElement(Component, props))));
236
- };
237
-
238
- // packages/ui/react-ui-editor/src/extensions/annotations.ts
77
+ import { RangeSetBuilder } from "@codemirror/state";
78
+ import { Decoration, EditorView, ViewPlugin } from "@codemirror/view";
239
79
  var annotationMark = Decoration.mark({
240
80
  class: "cm-annotation"
241
81
  });
242
- var annotations = (options = {}) => {
243
- const match = (state) => {
244
- const annotations2 = [];
245
- const text = state.doc.toString();
246
- if (options.match) {
247
- const matches = text.matchAll(options.match);
248
- for (const match2 of matches) {
249
- const from = match2.index;
250
- const to = from + match2[0].length;
251
- const cursor = Cursor.getCursorFromRange(state, {
252
- from,
253
- to
254
- });
255
- annotations2.push({
256
- cursor
257
- });
82
+ var annotations = ({ match } = {}) => {
83
+ return [
84
+ ViewPlugin.fromClass(class {
85
+ constructor() {
86
+ this.decorations = Decoration.none;
258
87
  }
259
- }
260
- return annotations2;
261
- };
262
- const annotationsState = StateField.define({
263
- create: (state) => {
264
- return match(state);
265
- },
266
- update: (value, tr) => {
267
- if (!tr.changes.empty) {
268
- return match(tr.state);
88
+ update(update2) {
89
+ const builder = new RangeSetBuilder();
90
+ if (match) {
91
+ const { from, to } = update2.view.viewport;
92
+ const text = update2.state.doc.sliceString(from, to);
93
+ const matches = text.matchAll(match);
94
+ for (const m of matches) {
95
+ if (m.index !== void 0) {
96
+ const start = from + m.index;
97
+ const end = start + m[0].length;
98
+ builder.add(start, end, annotationMark);
99
+ }
100
+ }
101
+ }
102
+ this.decorations = builder.finish();
269
103
  }
270
- return value;
271
- }
272
- });
273
- return [
274
- annotationsState,
275
- EditorView.decorations.compute([
276
- annotationsState
277
- ], (state) => {
278
- const annotations2 = state.field(annotationsState);
279
- const decorations = annotations2.map((annotation) => {
280
- const range = Cursor.getRangeFromCursor(state, annotation.cursor);
281
- return range && annotationMark.range(range.from, range.to);
282
- }).filter(isNotFalsy);
283
- return Decoration.set(decorations);
104
+ }, {
105
+ decorations: (v) => v.decorations
284
106
  }),
285
- styles
107
+ EditorView.theme({
108
+ ".cm-annotation": {
109
+ textDecoration: "underline",
110
+ textDecorationStyle: "wavy",
111
+ textDecorationColor: "var(--dx-errorText)"
112
+ }
113
+ })
286
114
  ];
287
115
  };
288
- var styles = EditorView.theme({
289
- ".cm-annotation": {
290
- textDecoration: "underline",
291
- textDecorationStyle: "wavy",
292
- textDecorationColor: "var(--dx-error)"
293
- }
294
- });
295
116
 
296
117
  // packages/ui/react-ui-editor/src/extensions/autocomplete.ts
297
118
  import { autocompletion, completionKeymap } from "@codemirror/autocomplete";
298
119
  import { markdownLanguage } from "@codemirror/lang-markdown";
299
120
  import { keymap } from "@codemirror/view";
300
- var autocomplete = ({ debug, activateOnTyping, override, onSearch } = {}) => {
121
+ var autocomplete = ({ activateOnTyping, override, onSearch } = {}) => {
301
122
  const extensions = [
302
123
  // https://codemirror.net/docs/ref/#view.keymap
303
124
  // https://discuss.codemirror.net/t/how-can-i-replace-the-default-autocompletion-keymap-v6/3322
@@ -306,15 +127,13 @@ var autocomplete = ({ debug, activateOnTyping, override, onSearch } = {}) => {
306
127
  // https://codemirror.net/examples/autocompletion
307
128
  // https://codemirror.net/docs/ref/#autocomplete.autocompletion
308
129
  autocompletion({
309
- activateOnTyping,
310
130
  override,
311
- closeOnBlur: !debug,
312
- tooltipClass: () => "shadow rounded"
131
+ activateOnTyping
313
132
  })
314
133
  ];
315
134
  if (onSearch) {
316
135
  extensions.push(
317
- // TODO(burdon): Optional decoration via addToOptions
136
+ // TODO(burdon): Optional decoration via addToOptions.
318
137
  markdownLanguage.data.of({
319
138
  autocomplete: (context) => {
320
139
  const match = context.matchBefore(/\w*/);
@@ -334,20 +153,20 @@ var autocomplete = ({ debug, activateOnTyping, override, onSearch } = {}) => {
334
153
 
335
154
  // packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
336
155
  import { next as A3 } from "@automerge/automerge";
337
- import { StateField as StateField2 } from "@codemirror/state";
338
- import { EditorView as EditorView2, ViewPlugin } from "@codemirror/view";
156
+ import { StateField } from "@codemirror/state";
157
+ import { EditorView as EditorView2, ViewPlugin as ViewPlugin2 } from "@codemirror/view";
339
158
 
340
159
  // packages/ui/react-ui-editor/src/extensions/automerge/cursor.ts
341
- import { log as log2 } from "@dxos/log";
160
+ import { log } from "@dxos/log";
342
161
  import { fromCursor, toCursor } from "@dxos/react-client/echo";
343
- var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/automerge/cursor.ts";
162
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/automerge/cursor.ts";
344
163
  var cursorConverter = (accessor) => ({
345
164
  toCursor: (pos, assoc) => {
346
165
  try {
347
166
  return toCursor(accessor, pos, assoc);
348
167
  } catch (err) {
349
- log2.catch(err, void 0, {
350
- F: __dxlog_file2,
168
+ log.catch(err, void 0, {
169
+ F: __dxlog_file,
351
170
  L: 15,
352
171
  S: void 0,
353
172
  C: (f, a) => f(...a)
@@ -359,8 +178,8 @@ var cursorConverter = (accessor) => ({
359
178
  try {
360
179
  return fromCursor(accessor, cursor);
361
180
  } catch (err) {
362
- log2.catch(err, void 0, {
363
- F: __dxlog_file2,
181
+ log.catch(err, void 0, {
182
+ F: __dxlog_file,
364
183
  L: 24,
365
184
  S: void 0,
366
185
  C: (f, a) => f(...a)
@@ -532,12 +351,12 @@ var Syncer = class {
532
351
  this._state = _state;
533
352
  this._pending = false;
534
353
  }
535
- reconcile(view, editor) {
354
+ reconcile(view, editor2) {
536
355
  if (this._pending) {
537
356
  return;
538
357
  }
539
358
  this._pending = true;
540
- if (editor) {
359
+ if (editor2) {
541
360
  this.onEditorChange(view);
542
361
  } else {
543
362
  this.onAutomergeChange(view);
@@ -568,70 +387,230 @@ var Syncer = class {
568
387
  }
569
388
  };
570
389
 
571
- // packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
572
- var automerge = (accessor) => {
573
- const syncState = StateField2.define({
574
- create: () => ({
575
- path: accessor.path.slice(),
576
- lastHeads: A3.getHeads(accessor.handle.doc()),
577
- unreconciledTransactions: []
578
- }),
579
- update: (value, tr) => {
580
- const result = {
581
- path: accessor.path.slice(),
582
- lastHeads: value.lastHeads,
583
- unreconciledTransactions: value.unreconciledTransactions.slice()
584
- };
585
- let clearUnreconciled = false;
586
- for (const effect of tr.effects) {
587
- if (effect.is(updateHeadsEffect)) {
588
- result.lastHeads = effect.value.newHeads;
589
- clearUnreconciled = true;
590
- }
591
- }
592
- if (clearUnreconciled) {
593
- result.unreconciledTransactions = [];
594
- } else {
595
- if (!isReconcile(tr)) {
596
- result.unreconciledTransactions.push(tr);
597
- }
598
- }
599
- return result;
600
- }
601
- });
602
- const syncer = new Syncer(accessor.handle, syncState);
603
- return [
604
- Cursor.converter.of(cursorConverter(accessor)),
605
- // Track heads.
606
- syncState,
607
- // Reconcile external updates.
608
- ViewPlugin.fromClass(class {
609
- constructor(_view) {
610
- this._view = _view;
611
- this._handleChange = () => {
612
- syncer.reconcile(this._view, false);
613
- };
614
- accessor.handle.addListener("change", this._handleChange);
615
- }
616
- destroy() {
617
- accessor.handle.removeListener("change", this._handleChange);
618
- }
619
- }),
620
- // Reconcile local updates.
621
- EditorView2.updateListener.of(({ view, changes }) => {
622
- if (!changes.empty) {
623
- syncer.reconcile(view, true);
624
- }
625
- })
626
- ];
627
- };
628
-
629
- // packages/ui/react-ui-editor/src/extensions/awareness/awareness.ts
630
- import { Annotation as Annotation2, RangeSet } from "@codemirror/state";
631
- import { Decoration as Decoration2, EditorView as EditorView3, ViewPlugin as ViewPlugin2, WidgetType } from "@codemirror/view";
632
- import { Event } from "@dxos/async";
633
- import { Context } from "@dxos/context";
634
- var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/awareness/awareness.ts";
390
+ // packages/ui/react-ui-editor/src/util/facet.ts
391
+ import { Facet } from "@codemirror/state";
392
+ var singleValueFacet = (defaultValue) => Facet.define({
393
+ // Called immediately.
394
+ combine: (providers) => {
395
+ return providers[0] ?? defaultValue;
396
+ }
397
+ });
398
+
399
+ // packages/ui/react-ui-editor/src/util/cursor.ts
400
+ var overlap = (a, b) => a.from <= b.to && a.to >= b.from;
401
+ var defaultCursorConverter = {
402
+ toCursor: (position) => position.toString(),
403
+ fromCursor: (cursor) => parseInt(cursor)
404
+ };
405
+ var Cursor = class _Cursor {
406
+ static {
407
+ this.converter = singleValueFacet(defaultCursorConverter);
408
+ }
409
+ static {
410
+ this.getCursorFromRange = (state, range) => {
411
+ const cursorConverter2 = state.facet(_Cursor.converter);
412
+ const from = cursorConverter2.toCursor(range.from);
413
+ const to = cursorConverter2.toCursor(range.to, -1);
414
+ return [
415
+ from,
416
+ to
417
+ ].join(":");
418
+ };
419
+ }
420
+ static {
421
+ this.getRangeFromCursor = (state, cursor) => {
422
+ const cursorConverter2 = state.facet(_Cursor.converter);
423
+ const parts = cursor.split(":");
424
+ const from = cursorConverter2.fromCursor(parts[0]);
425
+ const to = cursorConverter2.fromCursor(parts[1]);
426
+ return from !== void 0 && to !== void 0 ? {
427
+ from,
428
+ to
429
+ } : void 0;
430
+ };
431
+ }
432
+ };
433
+
434
+ // packages/ui/react-ui-editor/src/util/debug.ts
435
+ import { log as log2 } from "@dxos/log";
436
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util/debug.ts";
437
+ var wrapWithCatch = (fn) => {
438
+ return (...args) => {
439
+ try {
440
+ return fn(...args);
441
+ } catch (err) {
442
+ log2.catch(err, void 0, {
443
+ F: __dxlog_file2,
444
+ L: 15,
445
+ S: void 0,
446
+ C: (f, a) => f(...a)
447
+ });
448
+ }
449
+ };
450
+ };
451
+ var callbackWrapper = (fn) => (...args) => {
452
+ try {
453
+ return fn(...args);
454
+ } catch (err) {
455
+ log2.catch(err, void 0, {
456
+ F: __dxlog_file2,
457
+ L: 29,
458
+ S: void 0,
459
+ C: (f, a) => f(...a)
460
+ });
461
+ }
462
+ };
463
+ var debugDispatcher = (trs, view) => {
464
+ logChanges(trs);
465
+ view.update(trs);
466
+ };
467
+ var logChanges = (trs) => {
468
+ const changes = trs.flatMap((tr) => {
469
+ if (tr.changes.empty) {
470
+ return void 0;
471
+ }
472
+ const changes2 = [];
473
+ tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => changes2.push(JSON.stringify({
474
+ fromA,
475
+ toA,
476
+ fromB,
477
+ toB,
478
+ inserted: inserted.toString()
479
+ })));
480
+ return changes2;
481
+ }).filter(Boolean);
482
+ if (changes.length) {
483
+ log2("changes", {
484
+ changes
485
+ }, {
486
+ F: __dxlog_file2,
487
+ L: 62,
488
+ S: void 0,
489
+ C: (f, a) => f(...a)
490
+ });
491
+ }
492
+ };
493
+
494
+ // packages/ui/react-ui-editor/src/util/dom.ts
495
+ var flattenRect = (rect, left) => {
496
+ const x = left ? rect.left : rect.right;
497
+ return {
498
+ left: x,
499
+ right: x,
500
+ top: rect.top,
501
+ bottom: rect.bottom
502
+ };
503
+ };
504
+ var scratchRange;
505
+ var textRange = (node, from, to = from) => {
506
+ const range = scratchRange || (scratchRange = document.createRange());
507
+ range.setEnd(node, to);
508
+ range.setStart(node, from);
509
+ return range;
510
+ };
511
+ var clientRectsFor = (dom) => {
512
+ if (dom.nodeType === 3) {
513
+ return textRange(dom, 0, dom.nodeValue.length).getClientRects();
514
+ } else if (dom.nodeType === 1) {
515
+ return dom.getClientRects();
516
+ } else {
517
+ return [];
518
+ }
519
+ };
520
+
521
+ // packages/ui/react-ui-editor/src/util/react.tsx
522
+ import React from "react";
523
+ import { createRoot } from "react-dom/client";
524
+ import { ThemeProvider, Tooltip } from "@dxos/react-ui";
525
+ import { defaultTx } from "@dxos/react-ui-theme";
526
+ var createElement = (tag, options, children) => {
527
+ const el = document.createElement(tag);
528
+ if (options?.className) {
529
+ el.className = options.className;
530
+ }
531
+ if (children) {
532
+ el.append(...Array.isArray(children) ? children : [
533
+ children
534
+ ]);
535
+ }
536
+ return el;
537
+ };
538
+ var renderRoot = (root, node) => {
539
+ createRoot(root).render(/* @__PURE__ */ React.createElement(ThemeProvider, {
540
+ tx: defaultTx
541
+ }, node));
542
+ return root;
543
+ };
544
+ var createRenderer = (Component) => (el, props) => {
545
+ renderRoot(el, /* @__PURE__ */ React.createElement(ThemeProvider, {
546
+ tx: defaultTx
547
+ }, /* @__PURE__ */ React.createElement(Tooltip.Provider, null, /* @__PURE__ */ React.createElement(Component, props))));
548
+ };
549
+
550
+ // packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
551
+ var automerge = (accessor) => {
552
+ const syncState = StateField.define({
553
+ create: () => ({
554
+ path: accessor.path.slice(),
555
+ lastHeads: A3.getHeads(accessor.handle.doc()),
556
+ unreconciledTransactions: []
557
+ }),
558
+ update: (value, tr) => {
559
+ const result = {
560
+ path: accessor.path.slice(),
561
+ lastHeads: value.lastHeads,
562
+ unreconciledTransactions: value.unreconciledTransactions.slice()
563
+ };
564
+ let clearUnreconciled = false;
565
+ for (const effect of tr.effects) {
566
+ if (effect.is(updateHeadsEffect)) {
567
+ result.lastHeads = effect.value.newHeads;
568
+ clearUnreconciled = true;
569
+ }
570
+ }
571
+ if (clearUnreconciled) {
572
+ result.unreconciledTransactions = [];
573
+ } else {
574
+ if (!isReconcile(tr)) {
575
+ result.unreconciledTransactions.push(tr);
576
+ }
577
+ }
578
+ return result;
579
+ }
580
+ });
581
+ const syncer = new Syncer(accessor.handle, syncState);
582
+ return [
583
+ Cursor.converter.of(cursorConverter(accessor)),
584
+ // Track heads.
585
+ syncState,
586
+ // Reconcile external updates.
587
+ ViewPlugin2.fromClass(class {
588
+ constructor(_view) {
589
+ this._view = _view;
590
+ this._handleChange = () => {
591
+ syncer.reconcile(this._view, false);
592
+ };
593
+ accessor.handle.addListener("change", this._handleChange);
594
+ }
595
+ destroy() {
596
+ accessor.handle.removeListener("change", this._handleChange);
597
+ }
598
+ }),
599
+ // Reconcile local updates.
600
+ EditorView2.updateListener.of(({ view, changes }) => {
601
+ if (!changes.empty) {
602
+ syncer.reconcile(view, true);
603
+ }
604
+ })
605
+ ];
606
+ };
607
+
608
+ // packages/ui/react-ui-editor/src/extensions/awareness/awareness.ts
609
+ import { Annotation as Annotation2, RangeSet } from "@codemirror/state";
610
+ import { Decoration as Decoration2, EditorView as EditorView3, ViewPlugin as ViewPlugin3, WidgetType } from "@codemirror/view";
611
+ import { Event } from "@dxos/async";
612
+ import { Context } from "@dxos/context";
613
+ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/awareness/awareness.ts";
635
614
  var dummyProvider = {
636
615
  remoteStateChange: new Event(),
637
616
  open: () => {
@@ -647,10 +626,10 @@ var RemoteSelectionChangedAnnotation = Annotation2.define();
647
626
  var awareness = (provider = dummyProvider) => {
648
627
  return [
649
628
  awarenessProvider.of(provider),
650
- ViewPlugin2.fromClass(RemoteSelectionsDecorator, {
629
+ ViewPlugin3.fromClass(RemoteSelectionsDecorator, {
651
630
  decorations: (value) => value.decorations
652
631
  }),
653
- styles2
632
+ styles
654
633
  ];
655
634
  };
656
635
  var RemoteSelectionsDecorator = class {
@@ -693,7 +672,7 @@ var RemoteSelectionsDecorator = class {
693
672
  } : void 0);
694
673
  }
695
674
  _updateRemoteSelections(view) {
696
- const decorations = [];
675
+ const decorations2 = [];
697
676
  const awarenessStates = this._provider.getRemoteStates();
698
677
  for (const state of awarenessStates) {
699
678
  const anchor = state.position?.anchor ? this._cursorConverter.fromCursor(state.position.anchor) : null;
@@ -708,7 +687,7 @@ var RemoteSelectionsDecorator = class {
708
687
  const darkColor = state.info.darkColor;
709
688
  const lightColor = state.info.lightColor;
710
689
  if (startLine.number === endLine.number) {
711
- decorations.push({
690
+ decorations2.push({
712
691
  from: start,
713
692
  to: end,
714
693
  value: Decoration2.mark({
@@ -719,7 +698,7 @@ var RemoteSelectionsDecorator = class {
719
698
  })
720
699
  });
721
700
  } else {
722
- decorations.push({
701
+ decorations2.push({
723
702
  from: start,
724
703
  to: startLine.from + startLine.length,
725
704
  value: Decoration2.mark({
@@ -729,7 +708,7 @@ var RemoteSelectionsDecorator = class {
729
708
  class: "cm-collab-selection"
730
709
  })
731
710
  });
732
- decorations.push({
711
+ decorations2.push({
733
712
  from: endLine.from,
734
713
  to: end,
735
714
  value: Decoration2.mark({
@@ -741,7 +720,7 @@ var RemoteSelectionsDecorator = class {
741
720
  });
742
721
  for (let i = startLine.number + 1; i < endLine.number; i++) {
743
722
  const linePos = view.state.doc.line(i).from;
744
- decorations.push({
723
+ decorations2.push({
745
724
  from: linePos,
746
725
  to: linePos,
747
726
  value: Decoration2.line({
@@ -753,7 +732,7 @@ var RemoteSelectionsDecorator = class {
753
732
  });
754
733
  }
755
734
  }
756
- decorations.push({
735
+ decorations2.push({
757
736
  from: head,
758
737
  to: head,
759
738
  value: Decoration2.widget({
@@ -763,14 +742,12 @@ var RemoteSelectionsDecorator = class {
763
742
  })
764
743
  });
765
744
  }
766
- this.decorations = Decoration2.set(decorations, true);
745
+ this.decorations = Decoration2.set(decorations2, true);
767
746
  }
768
747
  };
769
748
  var RemoteCaretWidget = class extends WidgetType {
770
749
  constructor(_name, _color) {
771
- super();
772
- this._name = _name;
773
- this._color = _color;
750
+ super(), this._name = _name, this._color = _color;
774
751
  }
775
752
  toDOM() {
776
753
  const span = document.createElement("span");
@@ -802,7 +779,7 @@ var RemoteCaretWidget = class extends WidgetType {
802
779
  return true;
803
780
  }
804
781
  };
805
- var styles2 = EditorView3.theme({
782
+ var styles = EditorView3.theme({
806
783
  ".cm-collab-selection": {},
807
784
  ".cm-collab-selectionLine": {
808
785
  padding: 0,
@@ -1281,10 +1258,10 @@ var random = (min, max) => {
1281
1258
  import { StateEffect as StateEffect2 } from "@codemirror/state";
1282
1259
 
1283
1260
  // packages/ui/react-ui-editor/src/extensions/command/state.ts
1284
- import { StateField as StateField3 } from "@codemirror/state";
1261
+ import { StateField as StateField2 } from "@codemirror/state";
1285
1262
  import { showTooltip } from "@codemirror/view";
1286
1263
  var commandConfig = singleValueFacet();
1287
- var commandState = StateField3.define({
1264
+ var commandState = StateField2.define({
1288
1265
  create: () => ({}),
1289
1266
  update: (state, tr) => {
1290
1267
  for (const effect of tr.effects) {
@@ -1393,14 +1370,14 @@ var commandKeyBindings = [
1393
1370
  import { EditorView as EditorView6, keymap as keymap3 } from "@codemirror/view";
1394
1371
 
1395
1372
  // packages/ui/react-ui-editor/src/extensions/command/hint.ts
1396
- import { RangeSetBuilder } from "@codemirror/state";
1397
- import { Decoration as Decoration3, EditorView as EditorView5, ViewPlugin as ViewPlugin3, WidgetType as WidgetType2 } from "@codemirror/view";
1398
- var hintViewPlugin = ({ onHint }) => ViewPlugin3.fromClass(class {
1373
+ import { RangeSetBuilder as RangeSetBuilder2 } from "@codemirror/state";
1374
+ import { Decoration as Decoration3, EditorView as EditorView5, ViewPlugin as ViewPlugin4, WidgetType as WidgetType2 } from "@codemirror/view";
1375
+ var hintViewPlugin = ({ onHint }) => ViewPlugin4.fromClass(class {
1399
1376
  constructor() {
1400
- this.deco = Decoration3.none;
1377
+ this.decorations = Decoration3.none;
1401
1378
  }
1402
1379
  update(update2) {
1403
- const builder = new RangeSetBuilder();
1380
+ const builder = new RangeSetBuilder2();
1404
1381
  const cState = update2.view.state.field(commandState, false);
1405
1382
  if (!cState?.tooltip) {
1406
1383
  const selection = update2.view.state.selection.main;
@@ -1409,22 +1386,21 @@ var hintViewPlugin = ({ onHint }) => ViewPlugin3.fromClass(class {
1409
1386
  const hint = onHint();
1410
1387
  if (hint) {
1411
1388
  builder.add(selection.from, selection.to, Decoration3.widget({
1412
- widget: new CommandHint(hint)
1389
+ widget: new Hint(hint)
1413
1390
  }));
1414
1391
  }
1415
1392
  }
1416
1393
  }
1417
- this.deco = builder.finish();
1394
+ this.decorations = builder.finish();
1418
1395
  }
1419
1396
  }, {
1420
1397
  provide: (plugin) => [
1421
- EditorView5.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration3.none)
1398
+ EditorView5.decorations.of((view) => view.plugin(plugin)?.decorations ?? Decoration3.none)
1422
1399
  ]
1423
1400
  });
1424
- var CommandHint = class extends WidgetType2 {
1401
+ var Hint = class extends WidgetType2 {
1425
1402
  constructor(content) {
1426
- super();
1427
- this.content = content;
1403
+ super(), this.content = content;
1428
1404
  }
1429
1405
  toDOM() {
1430
1406
  const wrap = document.createElement("span");
@@ -1461,79 +1437,12 @@ var CommandHint = class extends WidgetType2 {
1461
1437
  }
1462
1438
  };
1463
1439
 
1464
- // packages/ui/react-ui-editor/src/extensions/command/menu.ts
1465
- import { ViewPlugin as ViewPlugin4 } from "@codemirror/view";
1466
- var floatingMenu = (options) => ViewPlugin4.fromClass(class {
1467
- constructor(view) {
1468
- this.rafId = null;
1469
- this.view = view;
1470
- const container = view.scrollDOM;
1471
- if (getComputedStyle(container).position === "static") {
1472
- container.style.position = "relative";
1473
- }
1474
- this.button = document.createElement("div");
1475
- this.button.style.position = "absolute";
1476
- this.button.style.zIndex = "10";
1477
- this.button.style.display = "none";
1478
- options.renderMenu(this.button, {
1479
- onAction: () => openCommand(view)
1480
- }, view);
1481
- container.appendChild(this.button);
1482
- container.addEventListener("scroll", this.scheduleUpdate.bind(this));
1483
- this.scheduleUpdate();
1484
- }
1485
- update(update2) {
1486
- if (update2.transactions.some((tr) => tr.effects.some((effect) => effect.is(openEffect)))) {
1487
- this.button.style.display = "none";
1488
- } else if (update2.transactions.some((tr) => tr.effects.some((effect) => effect.is(closeEffect)))) {
1489
- this.button.style.display = "block";
1490
- } else if (update2.selectionSet || update2.viewportChanged || update2.docChanged || update2.geometryChanged) {
1491
- this.scheduleUpdate();
1492
- }
1493
- }
1494
- scheduleUpdate() {
1495
- if (this.rafId != null) {
1496
- cancelAnimationFrame(this.rafId);
1497
- }
1498
- this.rafId = requestAnimationFrame(this.updateButtonPosition.bind(this));
1499
- }
1500
- updateButtonPosition() {
1501
- const pos = this.view.state.selection.main.head;
1502
- const lineBlock = this.view.lineBlockAt(pos);
1503
- const domInfo = this.view.domAtPos(lineBlock.from);
1504
- let node = domInfo.node;
1505
- while (node && !(node instanceof HTMLElement)) {
1506
- node = node.parentNode;
1507
- }
1508
- if (!node) {
1509
- this.button.style.display = "none";
1510
- return;
1511
- }
1512
- const lineRect = node.getBoundingClientRect();
1513
- const containerRect = this.view.scrollDOM.getBoundingClientRect();
1514
- const offsetTop = lineRect.top - containerRect.top + this.view.scrollDOM.scrollTop;
1515
- const offsetLeft = this.view.scrollDOM.clientWidth + this.view.scrollDOM.scrollLeft - lineRect.x;
1516
- this.button.style.top = `${offsetTop}px`;
1517
- this.button.style.left = `${offsetLeft}px`;
1518
- this.button.style.display = "block";
1519
- }
1520
- destroy() {
1521
- this.button.remove();
1522
- if (this.rafId != null) {
1523
- cancelAnimationFrame(this.rafId);
1524
- }
1525
- }
1526
- });
1527
-
1528
1440
  // packages/ui/react-ui-editor/src/extensions/command/command.ts
1529
1441
  var command = (options = {}) => {
1530
1442
  return [
1531
1443
  keymap3.of(commandKeyBindings),
1532
1444
  commandConfig.of(options),
1533
1445
  commandState,
1534
- options.renderMenu ? floatingMenu({
1535
- renderMenu: options.renderMenu
1536
- }) : [],
1537
1446
  options.onHint ? hintViewPlugin({
1538
1447
  onHint: options.onHint
1539
1448
  }) : [],
@@ -1548,30 +1457,199 @@ var command = (options = {}) => {
1548
1457
  ];
1549
1458
  };
1550
1459
 
1551
- // packages/ui/react-ui-editor/src/extensions/comments.ts
1552
- import { invertedEffects } from "@codemirror/commands";
1553
- import { StateEffect as StateEffect3, StateField as StateField4 } from "@codemirror/state";
1554
- import { hoverTooltip, keymap as keymap5, Decoration as Decoration4, EditorView as EditorView8, ViewPlugin as ViewPlugin5 } from "@codemirror/view";
1555
- import sortBy from "lodash.sortby";
1556
- import { useEffect, useMemo as useMemo2 } from "react";
1557
- import { debounce as debounce2 } from "@dxos/async";
1558
- import { log as log4 } from "@dxos/log";
1559
- import { isNonNullable } from "@dxos/util";
1560
-
1561
- // packages/ui/react-ui-editor/src/extensions/selection.ts
1562
- import { Transaction } from "@codemirror/state";
1563
- import { EditorView as EditorView7, keymap as keymap4 } from "@codemirror/view";
1564
- import { debounce } from "@dxos/async";
1565
- import { invariant as invariant3 } from "@dxos/invariant";
1566
- import { isNotFalsy as isNotFalsy2 } from "@dxos/util";
1567
- var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/selection.ts";
1568
- var documentId = singleValueFacet();
1569
- var stateRestoreAnnotation = "dxos.org/cm/state-restore";
1570
- var createEditorStateTransaction = ({ scrollTo, selection }) => {
1571
- return {
1572
- selection,
1460
+ // packages/ui/react-ui-editor/src/extensions/command/menu.ts
1461
+ import { EditorView as EditorView7, ViewPlugin as ViewPlugin5 } from "@codemirror/view";
1462
+ var floatingMenu = (options = {}) => [
1463
+ ViewPlugin5.fromClass(class {
1464
+ constructor(view) {
1465
+ this.rafId = null;
1466
+ this.view = view;
1467
+ const container = view.scrollDOM;
1468
+ if (getComputedStyle(container).position === "static") {
1469
+ container.style.position = "relative";
1470
+ }
1471
+ const icon = document.createElement("dx-icon");
1472
+ icon.setAttribute("icon", options.icon ?? "ph--dots-three-outline--regular");
1473
+ const button = document.createElement("button");
1474
+ button.appendChild(icon);
1475
+ this.tag = document.createElement("dx-ref-tag");
1476
+ this.tag.classList.add("cm-ref-tag");
1477
+ this.tag.appendChild(button);
1478
+ container.appendChild(this.tag);
1479
+ container.addEventListener("scroll", this.scheduleUpdate.bind(this));
1480
+ this.scheduleUpdate();
1481
+ }
1482
+ update(update2) {
1483
+ this.tag.dataset.focused = update2.view.hasFocus ? "true" : "false";
1484
+ if (!update2.view.hasFocus) {
1485
+ return;
1486
+ }
1487
+ if (update2.transactions.some((tr) => tr.effects.some((effect) => effect.is(openEffect)))) {
1488
+ this.tag.style.display = "none";
1489
+ this.tag.classList.add("opacity-10");
1490
+ } else if (update2.transactions.some((tr) => tr.effects.some((effect) => effect.is(closeEffect)))) {
1491
+ this.tag.style.display = "block";
1492
+ } else if (update2.docChanged || update2.focusChanged || update2.geometryChanged || update2.selectionSet || update2.viewportChanged) {
1493
+ this.scheduleUpdate();
1494
+ }
1495
+ }
1496
+ updateButtonPosition() {
1497
+ const { x, width } = this.view.contentDOM.getBoundingClientRect();
1498
+ const pos = this.view.state.selection.main.head;
1499
+ const line = this.view.lineBlockAt(pos);
1500
+ const coords = this.view.coordsAtPos(line.from);
1501
+ if (!coords) {
1502
+ return;
1503
+ }
1504
+ const lineHeight = coords.bottom - coords.top;
1505
+ const dy = (lineHeight - (options.height ?? 32)) / 2;
1506
+ const offsetTop = coords.top + dy;
1507
+ const offsetLeft = x + width + (options.padding ?? 8);
1508
+ this.tag.style.top = `${offsetTop}px`;
1509
+ this.tag.style.left = `${offsetLeft}px`;
1510
+ this.tag.style.display = "block";
1511
+ }
1512
+ scheduleUpdate() {
1513
+ if (this.rafId != null) {
1514
+ cancelAnimationFrame(this.rafId);
1515
+ }
1516
+ this.rafId = requestAnimationFrame(this.updateButtonPosition.bind(this));
1517
+ }
1518
+ destroy() {
1519
+ this.tag.remove();
1520
+ if (this.rafId != null) {
1521
+ cancelAnimationFrame(this.rafId);
1522
+ }
1523
+ }
1524
+ }),
1525
+ EditorView7.theme({
1526
+ ".cm-ref-tag": {
1527
+ position: "fixed",
1528
+ padding: "0",
1529
+ border: "none",
1530
+ transition: "opacity 0.3s ease-in-out",
1531
+ opacity: 0.1
1532
+ },
1533
+ ".cm-ref-tag button": {
1534
+ display: "grid",
1535
+ alignItems: "center",
1536
+ justifyContent: "center",
1537
+ width: "2rem",
1538
+ height: "2rem"
1539
+ },
1540
+ '.cm-ref-tag[data-focused="true"]': {
1541
+ opacity: 1
1542
+ }
1543
+ })
1544
+ ];
1545
+
1546
+ // packages/ui/react-ui-editor/src/extensions/command/typeahead.ts
1547
+ import { EditorSelection, Prec, RangeSetBuilder as RangeSetBuilder3 } from "@codemirror/state";
1548
+ import { Decoration as Decoration4, keymap as keymap4, ViewPlugin as ViewPlugin6 } from "@codemirror/view";
1549
+ var typeahead = ({ onComplete } = {}) => {
1550
+ let hint;
1551
+ const complete = (view) => {
1552
+ if (!hint) {
1553
+ return false;
1554
+ }
1555
+ const selection = view.state.selection.main;
1556
+ view.dispatch({
1557
+ changes: [
1558
+ {
1559
+ from: selection.from,
1560
+ to: selection.to,
1561
+ insert: hint
1562
+ }
1563
+ ],
1564
+ selection: EditorSelection.cursor(selection.from + hint.length)
1565
+ });
1566
+ return true;
1567
+ };
1568
+ return [
1569
+ ViewPlugin6.fromClass(class {
1570
+ constructor() {
1571
+ this.decorations = Decoration4.none;
1572
+ }
1573
+ update(update2) {
1574
+ const builder = new RangeSetBuilder3();
1575
+ const selection = update2.view.state.selection.main;
1576
+ const line = update2.view.state.doc.lineAt(selection.from);
1577
+ if (selection.from === selection.to && selection.from === line.to) {
1578
+ const str = update2.state.sliceDoc(line.from, selection.from);
1579
+ hint = onComplete?.({
1580
+ line: str
1581
+ });
1582
+ if (hint) {
1583
+ builder.add(selection.from, selection.to, Decoration4.widget({
1584
+ widget: new Hint(hint)
1585
+ }));
1586
+ }
1587
+ }
1588
+ this.decorations = builder.finish();
1589
+ }
1590
+ }, {
1591
+ decorations: (v) => v.decorations
1592
+ }),
1593
+ // Keys.
1594
+ Prec.highest(keymap4.of([
1595
+ {
1596
+ key: "Tab",
1597
+ preventDefault: true,
1598
+ run: complete
1599
+ },
1600
+ {
1601
+ key: "ArrowRight",
1602
+ preventDefault: true,
1603
+ run: complete
1604
+ }
1605
+ ]))
1606
+ ];
1607
+ };
1608
+ var staticCompletion = (completions, defaultCompletion) => ({ line }) => {
1609
+ if (line.length === 0 && defaultCompletion) {
1610
+ return defaultCompletion;
1611
+ }
1612
+ const words = line.split(/\s+/).filter(Boolean);
1613
+ if (words.length) {
1614
+ const word = words.at(-1);
1615
+ for (const completion of completions) {
1616
+ const match = matchCompletion(completion, word);
1617
+ if (match) {
1618
+ return match;
1619
+ }
1620
+ }
1621
+ }
1622
+ };
1623
+ var matchCompletion = (completion, word) => {
1624
+ if (completion.length > word.length && completion.startsWith(word)) {
1625
+ return completion.slice(word.length);
1626
+ }
1627
+ };
1628
+
1629
+ // packages/ui/react-ui-editor/src/extensions/comments.ts
1630
+ import { invertedEffects } from "@codemirror/commands";
1631
+ import { StateEffect as StateEffect3, StateField as StateField3 } from "@codemirror/state";
1632
+ import { hoverTooltip, keymap as keymap6, Decoration as Decoration5, EditorView as EditorView9, ViewPlugin as ViewPlugin7 } from "@codemirror/view";
1633
+ import sortBy from "lodash.sortby";
1634
+ import { useEffect } from "react";
1635
+ import { debounce as debounce2 } from "@dxos/async";
1636
+ import { log as log4 } from "@dxos/log";
1637
+ import { isNonNullable } from "@dxos/util";
1638
+
1639
+ // packages/ui/react-ui-editor/src/extensions/selection.ts
1640
+ import { Transaction } from "@codemirror/state";
1641
+ import { EditorView as EditorView8, keymap as keymap5 } from "@codemirror/view";
1642
+ import { debounce } from "@dxos/async";
1643
+ import { invariant as invariant3 } from "@dxos/invariant";
1644
+ import { isNotFalsy } from "@dxos/util";
1645
+ var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/selection.ts";
1646
+ var documentId = singleValueFacet();
1647
+ var stateRestoreAnnotation = "dxos.org/cm/state-restore";
1648
+ var createEditorStateTransaction = ({ scrollTo, selection }) => {
1649
+ return {
1650
+ selection,
1573
1651
  scrollIntoView: !scrollTo,
1574
- effects: scrollTo ? EditorView7.scrollIntoView(scrollTo, {
1652
+ effects: scrollTo ? EditorView8.scrollIntoView(scrollTo, {
1575
1653
  yMargin: 96
1576
1654
  }) : void 0,
1577
1655
  annotations: Transaction.userEvent.of(stateRestoreAnnotation)
@@ -1613,7 +1691,7 @@ var selectionState = ({ getState, setState } = {}) => {
1613
1691
  // setStateDebounced(id, {});
1614
1692
  // },
1615
1693
  // }),
1616
- EditorView7.updateListener.of(({ view, transactions }) => {
1694
+ EditorView8.updateListener.of(({ view, transactions }) => {
1617
1695
  const id = view.state.facet(documentId);
1618
1696
  if (!id || transactions.some((tr) => tr.isUserEvent(stateRestoreAnnotation))) {
1619
1697
  return;
@@ -1636,7 +1714,7 @@ var selectionState = ({ getState, setState } = {}) => {
1636
1714
  }
1637
1715
  }
1638
1716
  }),
1639
- getState && keymap4.of([
1717
+ getState && keymap5.of([
1640
1718
  {
1641
1719
  key: "ctrl-r",
1642
1720
  run: (view) => {
@@ -1648,7 +1726,7 @@ var selectionState = ({ getState, setState } = {}) => {
1648
1726
  }
1649
1727
  }
1650
1728
  ])
1651
- ].filter(isNotFalsy2);
1729
+ ].filter(isNotFalsy);
1652
1730
  };
1653
1731
 
1654
1732
  // packages/ui/react-ui-editor/src/extensions/comments.ts
@@ -1656,7 +1734,7 @@ var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src
1656
1734
  var setComments = StateEffect3.define();
1657
1735
  var setSelection = StateEffect3.define();
1658
1736
  var setCommentState = StateEffect3.define();
1659
- var commentsState = StateField4.define({
1737
+ var commentsState = StateField3.define({
1660
1738
  create: (state) => ({
1661
1739
  id: state.facet(documentId),
1662
1740
  comments: [],
@@ -1694,7 +1772,7 @@ var commentsState = StateField4.define({
1694
1772
  return value;
1695
1773
  }
1696
1774
  });
1697
- var styles3 = EditorView8.theme({
1775
+ var styles2 = EditorView9.theme({
1698
1776
  ".cm-comment, .cm-comment-current": {
1699
1777
  margin: "0 -3px",
1700
1778
  padding: "3px",
@@ -1707,23 +1785,23 @@ var styles3 = EditorView8.theme({
1707
1785
  textDecoration: "underline"
1708
1786
  }
1709
1787
  });
1710
- var createCommentMark = (id, isCurrent) => Decoration4.mark({
1788
+ var createCommentMark = (id, isCurrent) => Decoration5.mark({
1711
1789
  class: isCurrent ? "cm-comment-current" : "cm-comment",
1712
1790
  attributes: {
1713
1791
  "data-testid": "cm-comment",
1714
1792
  "data-comment-id": id
1715
1793
  }
1716
1794
  });
1717
- var commentsDecorations = EditorView8.decorations.compute([
1795
+ var commentsDecorations = EditorView9.decorations.compute([
1718
1796
  commentsState
1719
1797
  ], (state) => {
1720
1798
  const { selection: { current }, comments: comments2 } = state.field(commentsState);
1721
- const decorations = sortBy(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
1799
+ const decorations2 = sortBy(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
1722
1800
  const range = comment.range;
1723
1801
  if (!range) {
1724
1802
  log4.warn("Invalid range:", range, {
1725
1803
  F: __dxlog_file7,
1726
- L: 144,
1804
+ L: 135,
1727
1805
  S: void 0,
1728
1806
  C: (f, a) => f(...a)
1729
1807
  });
@@ -1734,10 +1812,10 @@ var commentsDecorations = EditorView8.decorations.compute([
1734
1812
  const mark = createCommentMark(comment.comment.id, comment.comment.id === current);
1735
1813
  return mark.range(range.from, range.to);
1736
1814
  }).filter(isNonNullable);
1737
- return Decoration4.set(decorations);
1815
+ return Decoration5.set(decorations2);
1738
1816
  });
1739
1817
  var commentClickedEffect = StateEffect3.define();
1740
- var handleCommentClick = EditorView8.domEventHandlers({
1818
+ var handleCommentClick = EditorView9.domEventHandlers({
1741
1819
  click: (event, view) => {
1742
1820
  let target = event.target;
1743
1821
  const editorRoot = view.dom;
@@ -1776,7 +1854,7 @@ var trackPastedComments = (onUpdate) => {
1776
1854
  }
1777
1855
  };
1778
1856
  return [
1779
- EditorView8.domEventHandlers({
1857
+ EditorView9.domEventHandlers({
1780
1858
  cut: handleTrack,
1781
1859
  copy: handleTrack
1782
1860
  }),
@@ -1798,7 +1876,7 @@ var trackPastedComments = (onUpdate) => {
1798
1876
  return effects;
1799
1877
  }),
1800
1878
  // Handle paste or the undo of comment deletion.
1801
- EditorView8.updateListener.of((update2) => {
1879
+ EditorView9.updateListener.of((update2) => {
1802
1880
  const restore = [];
1803
1881
  for (let i = 0; i < update2.transactions.length; i++) {
1804
1882
  const tr = update2.transactions[i];
@@ -1895,11 +1973,11 @@ var comments = (options = {}) => {
1895
1973
  commentsState,
1896
1974
  commentsDecorations,
1897
1975
  handleCommentClick,
1898
- styles3,
1976
+ styles2,
1899
1977
  //
1900
1978
  // Keymap.
1901
1979
  //
1902
- options.onCreate && keymap5.of([
1980
+ options.onCreate && keymap6.of([
1903
1981
  {
1904
1982
  key: shortcut,
1905
1983
  run: callbackWrapper(createComment)
@@ -1940,7 +2018,7 @@ var comments = (options = {}) => {
1940
2018
  //
1941
2019
  // Track deleted ranges and update ranges for decorations.
1942
2020
  //
1943
- EditorView8.updateListener.of(({ view, state, changes }) => {
2021
+ EditorView9.updateListener.of(({ view, state, changes }) => {
1944
2022
  let mod = false;
1945
2023
  const { comments: comments2, ...value } = state.field(commentsState);
1946
2024
  changes.iterChanges((from, to, from2, to2) => {
@@ -1972,7 +2050,7 @@ var comments = (options = {}) => {
1972
2050
  //
1973
2051
  // Track selection/proximity.
1974
2052
  //
1975
- EditorView8.updateListener.of(({ view, state }) => {
2053
+ EditorView9.updateListener.of(({ view, state }) => {
1976
2054
  let min = Infinity;
1977
2055
  const { selection: { current, closest }, comments: comments2 } = state.field(commentsState);
1978
2056
  const { head } = state.selection.main;
@@ -2026,7 +2104,7 @@ var scrollThreadIntoView = (view, id, center = true) => {
2026
2104
  anchor: range.from
2027
2105
  } : void 0,
2028
2106
  effects: [
2029
- needsScroll ? EditorView8.scrollIntoView(range.from, center ? {
2107
+ needsScroll ? EditorView9.scrollIntoView(range.from, center ? {
2030
2108
  y: "center"
2031
2109
  } : void 0) : [],
2032
2110
  needsSelectionUpdate ? setSelection.of({
@@ -2037,22 +2115,6 @@ var scrollThreadIntoView = (view, id, center = true) => {
2037
2115
  }
2038
2116
  }
2039
2117
  };
2040
- var selectionOverlapsComment = (state) => {
2041
- const commentState = state.field(commentsState, false);
2042
- if (commentState === void 0) {
2043
- return false;
2044
- }
2045
- const { selection } = state;
2046
- for (const range of selection.ranges) {
2047
- if (commentState.comments.some(({ range: commentRange }) => overlap(commentRange, range))) {
2048
- return true;
2049
- }
2050
- }
2051
- return false;
2052
- };
2053
- var hasActiveSelection = (state) => {
2054
- return state.selection.ranges.some((range) => !range.empty);
2055
- };
2056
2118
  var ExternalCommentSync = class {
2057
2119
  constructor(view, id, subscribe, getComments) {
2058
2120
  this.destroy = () => {
@@ -2072,21 +2134,11 @@ var ExternalCommentSync = class {
2072
2134
  this.unsubscribe = subscribe(updateComments);
2073
2135
  }
2074
2136
  };
2075
- var createExternalCommentSync = (id, subscribe, getComments) => ViewPlugin5.fromClass(class {
2137
+ var createExternalCommentSync = (id, subscribe, getComments) => ViewPlugin7.fromClass(class {
2076
2138
  constructor(view) {
2077
2139
  return new ExternalCommentSync(view, id, subscribe, getComments);
2078
2140
  }
2079
2141
  });
2080
- var useCommentState = (state) => {
2081
- return useMemo2(() => EditorView8.updateListener.of((update2) => {
2082
- if (update2.docChanged || update2.selectionSet) {
2083
- state.comment = selectionOverlapsComment(update2.state);
2084
- state.selection = hasActiveSelection(update2.state);
2085
- }
2086
- }), [
2087
- state
2088
- ]);
2089
- };
2090
2142
  var useComments = (view, id, comments2) => {
2091
2143
  useEffect(() => {
2092
2144
  if (view) {
@@ -2101,36 +2153,23 @@ var useComments = (view, id, comments2) => {
2101
2153
  }
2102
2154
  });
2103
2155
  };
2104
- var useCommentClickListener = (onCommentClick) => {
2105
- return useMemo2(() => EditorView8.updateListener.of((update2) => {
2106
- update2.transactions.forEach((transaction) => {
2107
- transaction.effects.forEach((effect) => {
2108
- if (effect.is(commentClickedEffect)) {
2109
- onCommentClick(effect.value);
2110
- }
2111
- });
2112
- });
2113
- }), [
2114
- onCommentClick
2115
- ]);
2116
- };
2117
2156
 
2118
2157
  // packages/ui/react-ui-editor/src/extensions/debug.ts
2119
2158
  import { syntaxTree } from "@codemirror/language";
2120
- import { StateField as StateField5 } from "@codemirror/state";
2159
+ import { StateField as StateField4 } from "@codemirror/state";
2121
2160
  var debugNodeLogger = (log9 = console.log) => {
2122
2161
  const logTokens = (state) => syntaxTree(state).iterate({
2123
2162
  enter: (node) => log9(node.type)
2124
2163
  });
2125
- return StateField5.define({
2164
+ return StateField4.define({
2126
2165
  create: (state) => logTokens(state),
2127
2166
  update: (_, tr) => logTokens(tr.state)
2128
2167
  });
2129
2168
  };
2130
2169
 
2131
2170
  // packages/ui/react-ui-editor/src/extensions/dnd.ts
2132
- import { dropCursor, EditorView as EditorView9 } from "@codemirror/view";
2133
- var styles4 = EditorView9.theme({
2171
+ import { dropCursor, EditorView as EditorView10 } from "@codemirror/view";
2172
+ var styles3 = EditorView10.theme({
2134
2173
  ".cm-dropCursor": {
2135
2174
  borderLeft: "2px solid var(--dx-accentText)",
2136
2175
  color: "var(--dx-accentText)",
@@ -2142,9 +2181,9 @@ var styles4 = EditorView9.theme({
2142
2181
  });
2143
2182
  var dropFile = (options = {}) => {
2144
2183
  return [
2145
- styles4,
2184
+ styles3,
2146
2185
  dropCursor(),
2147
- EditorView9.domEventHandlers({
2186
+ EditorView10.domEventHandlers({
2148
2187
  drop: (event, view) => {
2149
2188
  event.preventDefault();
2150
2189
  const files = event.dataTransfer?.files;
@@ -2171,18 +2210,18 @@ import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@cod
2171
2210
  import { searchKeymap } from "@codemirror/search";
2172
2211
  import { EditorState } from "@codemirror/state";
2173
2212
  import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
2174
- import { EditorView as EditorView11, drawSelection, dropCursor as dropCursor2, highlightActiveLine, keymap as keymap6, lineNumbers, placeholder, scrollPastEnd } from "@codemirror/view";
2213
+ import { EditorView as EditorView12, ViewPlugin as ViewPlugin8, drawSelection, dropCursor as dropCursor2, highlightActiveLine, keymap as keymap7, lineNumbers, placeholder, scrollPastEnd } from "@codemirror/view";
2175
2214
  import defaultsDeep2 from "lodash.defaultsdeep";
2176
2215
  import merge from "lodash.merge";
2177
2216
  import { generateName } from "@dxos/display-name";
2178
2217
  import { log as log5 } from "@dxos/log";
2179
- import { hexToHue, isNotFalsy as isNotFalsy3 } from "@dxos/util";
2218
+ import { hexToHue, isNotFalsy as isNotFalsy2 } from "@dxos/util";
2180
2219
 
2181
2220
  // packages/ui/react-ui-editor/src/extensions/focus.ts
2182
- import { StateEffect as StateEffect4, StateField as StateField6 } from "@codemirror/state";
2183
- import { EditorView as EditorView10 } from "@codemirror/view";
2221
+ import { StateEffect as StateEffect4, StateField as StateField5 } from "@codemirror/state";
2222
+ import { EditorView as EditorView11 } from "@codemirror/view";
2184
2223
  var focusEffect = StateEffect4.define();
2185
- var focusField = StateField6.define({
2224
+ var focusField = StateField5.define({
2186
2225
  create: () => false,
2187
2226
  update: (value, tr) => {
2188
2227
  for (const effect of tr.effects) {
@@ -2195,7 +2234,7 @@ var focusField = StateField6.define({
2195
2234
  });
2196
2235
  var focus = [
2197
2236
  focusField,
2198
- EditorView10.domEventHandlers({
2237
+ EditorView11.domEventHandlers({
2199
2238
  focus: (event, view) => {
2200
2239
  setTimeout(() => view.dispatch({
2201
2240
  effects: focusEffect.of(true)
@@ -2229,8 +2268,8 @@ var theme = {
2229
2268
  };
2230
2269
 
2231
2270
  // packages/ui/react-ui-editor/src/styles/tokens.ts
2232
- import get from "lodash.get";
2233
2271
  import { tokens } from "@dxos/react-ui-theme";
2272
+ import { get } from "@dxos/util";
2234
2273
  var getToken = (path, defaultValue) => {
2235
2274
  const value = get(tokens, path, defaultValue);
2236
2275
  return value?.toString() ?? "";
@@ -2353,19 +2392,25 @@ var defaultTheme = {
2353
2392
  */
2354
2393
  ".cm-tooltip.cm-tooltip-autocomplete": {
2355
2394
  marginTop: "4px",
2356
- marginLeft: "-3px"
2395
+ marginLeft: "-3px",
2396
+ borderColor: "var(--dx-separator)",
2397
+ borderTop: "none"
2357
2398
  },
2358
2399
  ".cm-tooltip.cm-tooltip-autocomplete > ul": {
2359
2400
  maxHeight: "20em"
2360
2401
  },
2361
- ".cm-tooltip.cm-tooltip-autocomplete > ul > li": {},
2362
- ".cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected]": {},
2402
+ ".cm-tooltip.cm-tooltip-autocomplete > ul > li": {
2403
+ padding: "4px"
2404
+ },
2405
+ ".cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected]": {
2406
+ background: "var(--dx-hoverSurface)"
2407
+ },
2363
2408
  ".cm-tooltip.cm-tooltip-autocomplete > ul > completion-section": {
2364
2409
  paddingLeft: "4px !important",
2365
2410
  borderBottom: "none !important",
2366
2411
  color: "var(--dx-accentText)"
2367
2412
  },
2368
- ".cm-tooltip.cm-completionInfo": {
2413
+ ".cm-completionInfo": {
2369
2414
  width: "360px !important",
2370
2415
  margin: "-10px 1px 0 1px",
2371
2416
  padding: "8px !important",
@@ -2415,7 +2460,7 @@ var defaultTheme = {
2415
2460
  backgroundColor: "var(--dx-input)"
2416
2461
  },
2417
2462
  ".cm-panel input:focus, .cm-panel button:focus": {
2418
- outline: "1px solid var(--dx-accentFocusIndicator)"
2463
+ outline: "1px solid var(--dx-neutralFocusIndicator)"
2419
2464
  },
2420
2465
  ".cm-panel label": {
2421
2466
  display: "inline-flex",
@@ -2428,7 +2473,7 @@ var defaultTheme = {
2428
2473
  height: "8px",
2429
2474
  marginRight: "6px !important",
2430
2475
  padding: "2px !important",
2431
- color: "var(--dx-accentFocusIndicator)"
2476
+ color: "var(--dx-neutralFocusIndicator)"
2432
2477
  },
2433
2478
  ".cm-panel button": {
2434
2479
  "&:hover": {
@@ -2468,10 +2513,10 @@ var createBasicExtensions = (_props) => {
2468
2513
  const props = defaultsDeep2({}, _props, defaultBasicOptions);
2469
2514
  return [
2470
2515
  // NOTE: Doesn't catch errors in keymap functions.
2471
- EditorView11.exceptionSink.of((err) => {
2516
+ EditorView12.exceptionSink.of((err) => {
2472
2517
  log5.catch(err, void 0, {
2473
2518
  F: __dxlog_file8,
2474
- L: 96,
2519
+ L: 98,
2475
2520
  S: void 0,
2476
2521
  C: (f, a) => f(...a)
2477
2522
  });
@@ -2483,18 +2528,18 @@ var createBasicExtensions = (_props) => {
2483
2528
  props.drawSelection && drawSelection({
2484
2529
  cursorBlinkRate: 1200
2485
2530
  }),
2486
- props.editable !== void 0 && EditorView11.editable.of(props.editable),
2531
+ props.editable !== void 0 && EditorView12.editable.of(props.editable),
2487
2532
  props.focus && focus,
2488
2533
  props.highlightActiveLine && highlightActiveLine(),
2489
2534
  props.history && history(),
2490
2535
  props.lineNumbers && lineNumbers(),
2491
- props.lineWrapping && EditorView11.lineWrapping,
2536
+ props.lineWrapping && EditorView12.lineWrapping,
2492
2537
  props.placeholder && placeholder(props.placeholder),
2493
2538
  props.readOnly !== void 0 && EditorState.readOnly.of(props.readOnly),
2494
2539
  props.scrollPastEnd && scrollPastEnd(),
2495
2540
  props.tabSize && EditorState.tabSize.of(props.tabSize),
2496
2541
  // https://codemirror.net/docs/ref/#view.KeyBinding
2497
- keymap6.of([
2542
+ keymap7.of([
2498
2543
  ...(props.keymap && keymaps[props.keymap]) ?? [],
2499
2544
  // NOTE: Tabs are also configured by markdown extension.
2500
2545
  // https://codemirror.net/docs/ref/#commands.indentWithTab
@@ -2514,28 +2559,33 @@ var createBasicExtensions = (_props) => {
2514
2559
  preventDefault: true,
2515
2560
  run: () => true
2516
2561
  }
2517
- ].filter(isNotFalsy3))
2518
- ].filter(isNotFalsy3);
2562
+ ].filter(isNotFalsy2))
2563
+ ].filter(isNotFalsy2);
2519
2564
  };
2520
2565
  var defaultThemeSlots = {
2521
2566
  editor: {
2522
2567
  className: "w-full bs-full"
2523
2568
  }
2524
2569
  };
2525
- var createThemeExtensions = ({ themeMode, styles: styles5, syntaxHighlighting: _syntaxHighlighting, slots: _slots } = {}) => {
2570
+ var createThemeExtensions = ({ themeMode, styles: styles4, syntaxHighlighting: _syntaxHighlighting, slots: _slots } = {}) => {
2526
2571
  const slots = defaultsDeep2({}, _slots, defaultThemeSlots);
2527
2572
  return [
2528
- EditorView11.darkTheme.of(themeMode === "dark"),
2529
- EditorView11.baseTheme(styles5 ? merge({}, defaultTheme, styles5) : defaultTheme),
2573
+ EditorView12.darkTheme.of(themeMode === "dark"),
2574
+ EditorView12.baseTheme(styles4 ? merge({}, defaultTheme, styles4) : defaultTheme),
2530
2575
  // https://github.com/codemirror/theme-one-dark
2531
2576
  _syntaxHighlighting && (themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)),
2532
- slots.editor?.className && EditorView11.editorAttributes.of({
2577
+ slots.editor?.className && EditorView12.editorAttributes.of({
2533
2578
  class: slots.editor.className
2534
2579
  }),
2535
- slots.content?.className && EditorView11.contentAttributes.of({
2580
+ slots.content?.className && EditorView12.contentAttributes.of({
2536
2581
  class: slots.content.className
2582
+ }),
2583
+ slots.scroll?.className && ViewPlugin8.fromClass(class {
2584
+ constructor(view) {
2585
+ view.scrollDOM.classList.add(slots.scroll.className);
2586
+ }
2537
2587
  })
2538
- ].filter(isNotFalsy3);
2588
+ ].filter(isNotFalsy2);
2539
2589
  };
2540
2590
  var createDataExtensions = ({ id, text, space, identity }) => {
2541
2591
  const extensions = [];
@@ -2561,7 +2611,7 @@ var createDataExtensions = ({ id, text, space, identity }) => {
2561
2611
 
2562
2612
  // packages/ui/react-ui-editor/src/extensions/folding.tsx
2563
2613
  import { codeFolding, foldGutter } from "@codemirror/language";
2564
- import { EditorView as EditorView12 } from "@codemirror/view";
2614
+ import { EditorView as EditorView13 } from "@codemirror/view";
2565
2615
  import React2 from "react";
2566
2616
  import { Icon } from "@dxos/react-ui";
2567
2617
  var folding = (_props = {}) => [
@@ -2585,7 +2635,7 @@ var folding = (_props = {}) => [
2585
2635
  }));
2586
2636
  }
2587
2637
  }),
2588
- EditorView12.theme({
2638
+ EditorView13.theme({
2589
2639
  ".cm-foldGutter": {
2590
2640
  opacity: 0.3,
2591
2641
  transition: "opacity 0.3s",
@@ -2597,15 +2647,59 @@ var folding = (_props = {}) => [
2597
2647
  })
2598
2648
  ];
2599
2649
 
2650
+ // packages/ui/react-ui-editor/src/extensions/json.ts
2651
+ import { json, jsonParseLinter } from "@codemirror/lang-json";
2652
+ import { linter } from "@codemirror/lint";
2653
+ import Ajv from "ajv";
2654
+ var createJsonExtensions = ({ schema } = {}) => {
2655
+ let lintSource = jsonParseLinter();
2656
+ if (schema) {
2657
+ const ajv = new Ajv({
2658
+ allErrors: false
2659
+ });
2660
+ const validate = ajv.compile(schema);
2661
+ lintSource = schemaLinter(validate);
2662
+ }
2663
+ return [
2664
+ json(),
2665
+ linter(lintSource)
2666
+ ];
2667
+ };
2668
+ var schemaLinter = (validate) => (view) => {
2669
+ try {
2670
+ const jsonText = view.state.doc.toString();
2671
+ const jsonData = JSON.parse(jsonText);
2672
+ const valid = validate(jsonData);
2673
+ if (valid) {
2674
+ return [];
2675
+ }
2676
+ return validate.errors?.map((err) => ({
2677
+ from: 0,
2678
+ to: jsonText.length,
2679
+ severity: "error",
2680
+ message: `${err.instancePath || "(root)"} ${err.message}`
2681
+ })) ?? [];
2682
+ } catch (err) {
2683
+ return [
2684
+ {
2685
+ from: 0,
2686
+ to: view.state.doc.length,
2687
+ severity: "error",
2688
+ message: "Invalid JSON: " + err.message
2689
+ }
2690
+ ];
2691
+ }
2692
+ };
2693
+
2600
2694
  // packages/ui/react-ui-editor/src/extensions/listener.ts
2601
- import { EditorView as EditorView13 } from "@codemirror/view";
2695
+ import { EditorView as EditorView14 } from "@codemirror/view";
2602
2696
  var listener = ({ onFocus, onChange }) => {
2603
2697
  const extensions = [];
2604
- onFocus && extensions.push(EditorView13.focusChangeEffect.of((_, focusing) => {
2698
+ onFocus && extensions.push(EditorView14.focusChangeEffect.of((_, focusing) => {
2605
2699
  onFocus(focusing);
2606
2700
  return null;
2607
2701
  }));
2608
- onChange && extensions.push(EditorView13.updateListener.of((update2) => {
2702
+ onChange && extensions.push(EditorView14.updateListener.of((update2) => {
2609
2703
  onChange(update2.state.doc.toString(), update2.state.facet(documentId));
2610
2704
  }));
2611
2705
  return extensions;
@@ -2614,23 +2708,23 @@ var listener = ({ onFocus, onChange }) => {
2614
2708
  // packages/ui/react-ui-editor/src/extensions/markdown/formatting.ts
2615
2709
  import { snippet } from "@codemirror/autocomplete";
2616
2710
  import { syntaxTree as syntaxTree2 } from "@codemirror/language";
2617
- import { EditorSelection } from "@codemirror/state";
2618
- import { EditorView as EditorView14, keymap as keymap7 } from "@codemirror/view";
2619
- import { useMemo as useMemo3 } from "react";
2711
+ import { EditorSelection as EditorSelection2 } from "@codemirror/state";
2712
+ import { EditorView as EditorView15, keymap as keymap8 } from "@codemirror/view";
2713
+ import { useMemo as useMemo2 } from "react";
2620
2714
  var formattingEquals = (a, b) => a.blockType === b.blockType && a.strong === b.strong && a.emphasis === b.emphasis && a.strikethrough === b.strikethrough && a.code === b.code && a.link === b.link && a.listStyle === b.listStyle && a.blockQuote === b.blockQuote;
2621
- var Inline;
2622
- (function(Inline2) {
2715
+ var Inline = /* @__PURE__ */ function(Inline2) {
2623
2716
  Inline2[Inline2["Strong"] = 0] = "Strong";
2624
2717
  Inline2[Inline2["Emphasis"] = 1] = "Emphasis";
2625
2718
  Inline2[Inline2["Strikethrough"] = 2] = "Strikethrough";
2626
2719
  Inline2[Inline2["Code"] = 3] = "Code";
2627
- })(Inline || (Inline = {}));
2628
- var List;
2629
- (function(List2) {
2720
+ return Inline2;
2721
+ }({});
2722
+ var List = /* @__PURE__ */ function(List2) {
2630
2723
  List2[List2["Ordered"] = 0] = "Ordered";
2631
2724
  List2[List2["Bullet"] = 1] = "Bullet";
2632
2725
  List2[List2["Task"] = 2] = "Task";
2633
- })(List || (List = {}));
2726
+ return List2;
2727
+ }({});
2634
2728
  var setHeading = (level) => {
2635
2729
  return ({ state, dispatch }) => {
2636
2730
  const { selection: { ranges }, doc } = state;
@@ -2735,7 +2829,7 @@ var setStyle = (type, enable) => {
2735
2829
  to: range.head + found + marker.length
2736
2830
  }
2737
2831
  ],
2738
- range: EditorSelection.cursor(range.from - marker.length)
2832
+ range: EditorSelection2.cursor(range.from - marker.length)
2739
2833
  };
2740
2834
  }
2741
2835
  }
@@ -2863,13 +2957,13 @@ var setStyle = (type, enable) => {
2863
2957
  from: range.head,
2864
2958
  insert: marker + marker
2865
2959
  },
2866
- range: EditorSelection.cursor(range.head + marker.length)
2960
+ range: EditorSelection2.cursor(range.head + marker.length)
2867
2961
  };
2868
2962
  }
2869
2963
  const changeSet = state.changes(changes2.concat(changesAtEnd));
2870
2964
  return {
2871
2965
  changes: changeSet,
2872
- range: range.empty && !changeSet.empty ? EditorSelection.cursor(range.head + marker.length) : EditorSelection.range(changeSet.mapPos(range.from, 1), changeSet.mapPos(range.to, -1))
2966
+ range: range.empty && !changeSet.empty ? EditorSelection2.cursor(range.head + marker.length) : EditorSelection2.range(changeSet.mapPos(range.from, 1), changeSet.mapPos(range.to, -1))
2873
2967
  };
2874
2968
  });
2875
2969
  dispatch(state.update(changes, {
@@ -3069,7 +3163,7 @@ var addLink = ({ url, image: image2 } = {}) => {
3069
3163
  const changeSet = state.changes(changes2.concat(changesAfter));
3070
3164
  return {
3071
3165
  changes: changeSet,
3072
- range: EditorSelection.cursor(changeSet.mapPos(to, 1) - cursorOffset - (url ? url.length + 2 : 0))
3166
+ range: EditorSelection2.cursor(changeSet.mapPos(to, 1) - cursorOffset - (url ? url.length + 2 : 0))
3073
3167
  };
3074
3168
  });
3075
3169
  if (changes.changes.empty) {
@@ -3503,7 +3597,7 @@ var toggleCodeblock = (target) => {
3503
3597
  };
3504
3598
  var formattingKeymap = (_options = {}) => {
3505
3599
  return [
3506
- keymap7.of([
3600
+ keymap8.of([
3507
3601
  {
3508
3602
  key: "meta-b",
3509
3603
  run: toggleStrong
@@ -3704,7 +3798,7 @@ var getFormatting = (state) => {
3704
3798
  };
3705
3799
  };
3706
3800
  var useFormattingState = (state) => {
3707
- return useMemo3(() => EditorView14.updateListener.of((update2) => {
3801
+ return useMemo2(() => EditorView15.updateListener.of((update2) => {
3708
3802
  if (update2.docChanged || update2.selectionSet) {
3709
3803
  Object.entries(getFormatting(update2.state)).forEach(([key, active]) => {
3710
3804
  state[key] = active;
@@ -3713,7 +3807,7 @@ var useFormattingState = (state) => {
3713
3807
  }), []);
3714
3808
  };
3715
3809
 
3716
- // packages/ui/react-ui-editor/src/extensions/markdown/editorAction.ts
3810
+ // packages/ui/react-ui-editor/src/extensions/markdown/action.ts
3717
3811
  var processEditorPayload = (view, { type, data }) => {
3718
3812
  let inlineType, listType;
3719
3813
  switch (type) {
@@ -3769,7 +3863,8 @@ import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lan
3769
3863
  import { syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
3770
3864
  import { languages } from "@codemirror/language-data";
3771
3865
  import { lintKeymap } from "@codemirror/lint";
3772
- import { keymap as keymap8 } from "@codemirror/view";
3866
+ import { keymap as keymap9 } from "@codemirror/view";
3867
+ import { isNotFalsy as isNotFalsy3 } from "@dxos/util";
3773
3868
 
3774
3869
  // packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
3775
3870
  import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
@@ -3951,7 +4046,7 @@ var markdownHighlightStyle = (_options = {}) => {
3951
4046
  };
3952
4047
 
3953
4048
  // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
3954
- var createMarkdownExtensions = ({ themeMode } = {}) => {
4049
+ var createMarkdownExtensions = (options = {}) => {
3955
4050
  return [
3956
4051
  // Main extension.
3957
4052
  // https://github.com/codemirror/lang-markdown
@@ -3975,21 +4070,21 @@ var createMarkdownExtensions = ({ themeMode } = {}) => {
3975
4070
  }),
3976
4071
  // Custom styles.
3977
4072
  syntaxHighlighting2(markdownHighlightStyle()),
3978
- keymap8.of([
4073
+ keymap9.of([
3979
4074
  // https://codemirror.net/docs/ref/#commands.indentWithTab
3980
- indentWithTab2,
4075
+ options.indentWithTab !== false && indentWithTab2,
3981
4076
  // https://codemirror.net/docs/ref/#commands.defaultKeymap
3982
4077
  ...defaultKeymap2,
3983
4078
  ...completionKeymap2,
3984
4079
  ...lintKeymap
3985
- ])
4080
+ ].filter(isNotFalsy3))
3986
4081
  ];
3987
4082
  };
3988
4083
 
3989
4084
  // packages/ui/react-ui-editor/src/extensions/markdown/debug.ts
3990
4085
  import { syntaxTree as syntaxTree3 } from "@codemirror/language";
3991
- import { StateField as StateField7 } from "@codemirror/state";
3992
- var debugTree = (cb) => StateField7.define({
4086
+ import { StateField as StateField6 } from "@codemirror/state";
4087
+ var debugTree = (cb) => StateField6.define({
3993
4088
  create: (state) => cb(convertTreeToJson(state)),
3994
4089
  update: (value, tr) => cb(convertTreeToJson(tr.state))
3995
4090
  });
@@ -4015,17 +4110,17 @@ var convertTreeToJson = (state) => {
4015
4110
 
4016
4111
  // packages/ui/react-ui-editor/src/extensions/markdown/decorate.ts
4017
4112
  import { syntaxTree as syntaxTree7 } from "@codemirror/language";
4018
- import { RangeSetBuilder as RangeSetBuilder3, StateEffect as StateEffect5 } from "@codemirror/state";
4019
- import { EditorView as EditorView18, Decoration as Decoration7, WidgetType as WidgetType5, ViewPlugin as ViewPlugin7 } from "@codemirror/view";
4113
+ import { RangeSetBuilder as RangeSetBuilder5, StateEffect as StateEffect5 } from "@codemirror/state";
4114
+ import { EditorView as EditorView19, Decoration as Decoration8, WidgetType as WidgetType5, ViewPlugin as ViewPlugin10 } from "@codemirror/view";
4020
4115
  import { invariant as invariant4 } from "@dxos/invariant";
4021
4116
  import { mx as mx2 } from "@dxos/react-ui-theme";
4022
4117
 
4023
4118
  // packages/ui/react-ui-editor/src/extensions/markdown/changes.ts
4024
4119
  import { syntaxTree as syntaxTree4 } from "@codemirror/language";
4025
4120
  import { Transaction as Transaction2 } from "@codemirror/state";
4026
- import { ViewPlugin as ViewPlugin6 } from "@codemirror/view";
4121
+ import { ViewPlugin as ViewPlugin9 } from "@codemirror/view";
4027
4122
  var adjustChanges = () => {
4028
- return ViewPlugin6.fromClass(class {
4123
+ return ViewPlugin9.fromClass(class {
4029
4124
  update(update2) {
4030
4125
  const tree = syntaxTree4(update2.state);
4031
4126
  const adjustments = [];
@@ -4166,13 +4261,13 @@ var getValidUrl = (str) => {
4166
4261
 
4167
4262
  // packages/ui/react-ui-editor/src/extensions/markdown/image.ts
4168
4263
  import { syntaxTree as syntaxTree5 } from "@codemirror/language";
4169
- import { StateField as StateField8 } from "@codemirror/state";
4170
- import { Decoration as Decoration5, EditorView as EditorView15, WidgetType as WidgetType3 } from "@codemirror/view";
4264
+ import { StateField as StateField7 } from "@codemirror/state";
4265
+ import { Decoration as Decoration6, EditorView as EditorView16, WidgetType as WidgetType3 } from "@codemirror/view";
4171
4266
  var image = (_options = {}) => {
4172
4267
  return [
4173
- StateField8.define({
4268
+ StateField7.define({
4174
4269
  create: (state) => {
4175
- return Decoration5.set(buildDecorations(0, state.doc.length, state));
4270
+ return Decoration6.set(buildDecorations(0, state.doc.length, state));
4176
4271
  },
4177
4272
  update: (value, tr) => {
4178
4273
  if (!tr.docChanged && !tr.selection) {
@@ -4195,12 +4290,12 @@ var image = (_options = {}) => {
4195
4290
  add: buildDecorations(from, to, tr.state)
4196
4291
  });
4197
4292
  },
4198
- provide: (field) => EditorView15.decorations.from(field)
4293
+ provide: (field) => EditorView16.decorations.from(field)
4199
4294
  })
4200
4295
  ];
4201
4296
  };
4202
4297
  var buildDecorations = (from, to, state) => {
4203
- const decorations = [];
4298
+ const decorations2 = [];
4204
4299
  const cursor = state.selection.main.head;
4205
4300
  syntaxTree5(state).iterate({
4206
4301
  enter: (node) => {
@@ -4213,7 +4308,7 @@ var buildDecorations = (from, to, state) => {
4213
4308
  return;
4214
4309
  }
4215
4310
  preloadImage(url);
4216
- decorations.push(Decoration5.replace({
4311
+ decorations2.push(Decoration6.replace({
4217
4312
  block: true,
4218
4313
  widget: new ImageWidget(url)
4219
4314
  }).range(hide2 ? node.from : node.to, node.to));
@@ -4223,7 +4318,7 @@ var buildDecorations = (from, to, state) => {
4223
4318
  from,
4224
4319
  to
4225
4320
  });
4226
- return decorations;
4321
+ return decorations2;
4227
4322
  };
4228
4323
  var preloaded = /* @__PURE__ */ new Set();
4229
4324
  var preloadImage = (url) => {
@@ -4235,8 +4330,7 @@ var preloadImage = (url) => {
4235
4330
  };
4236
4331
  var ImageWidget = class extends WidgetType3 {
4237
4332
  constructor(_url) {
4238
- super();
4239
- this._url = _url;
4333
+ super(), this._url = _url;
4240
4334
  }
4241
4335
  eq(other) {
4242
4336
  return this._url === other._url;
@@ -4255,10 +4349,10 @@ var ImageWidget = class extends WidgetType3 {
4255
4349
  };
4256
4350
 
4257
4351
  // packages/ui/react-ui-editor/src/extensions/markdown/styles.ts
4258
- import { EditorView as EditorView16 } from "@codemirror/view";
4352
+ import { EditorView as EditorView17 } from "@codemirror/view";
4259
4353
  var bulletListIndentationWidth = 24;
4260
4354
  var orderedListIndentationWidth = 36;
4261
- var formattingStyles = EditorView16.theme({
4355
+ var formattingStyles = EditorView17.theme({
4262
4356
  /**
4263
4357
  * Horizontal rule.
4264
4358
  */
@@ -4317,8 +4411,9 @@ var formattingStyles = EditorView16.theme({
4317
4411
  * Task list.
4318
4412
  */
4319
4413
  "& .cm-task": {
4320
- display: "inline-block",
4321
- width: `${bulletListIndentationWidth}px`
4414
+ display: "inline-flex",
4415
+ width: `${bulletListIndentationWidth}px`,
4416
+ height: "20px"
4322
4417
  },
4323
4418
  "& .cm-task-checkbox": {
4324
4419
  display: "grid",
@@ -4378,17 +4473,17 @@ var formattingStyles = EditorView16.theme({
4378
4473
 
4379
4474
  // packages/ui/react-ui-editor/src/extensions/markdown/table.ts
4380
4475
  import { syntaxTree as syntaxTree6 } from "@codemirror/language";
4381
- import { RangeSetBuilder as RangeSetBuilder2, StateField as StateField9 } from "@codemirror/state";
4382
- import { Decoration as Decoration6, EditorView as EditorView17, WidgetType as WidgetType4 } from "@codemirror/view";
4476
+ import { RangeSetBuilder as RangeSetBuilder4, StateField as StateField8 } from "@codemirror/state";
4477
+ import { Decoration as Decoration7, EditorView as EditorView18, WidgetType as WidgetType4 } from "@codemirror/view";
4383
4478
  var table = (options = {}) => {
4384
- return StateField9.define({
4479
+ return StateField8.define({
4385
4480
  create: (state) => update(state, options),
4386
4481
  update: (_, tr) => update(tr.state, options),
4387
- provide: (field) => EditorView17.decorations.from(field)
4482
+ provide: (field) => EditorView18.decorations.from(field)
4388
4483
  });
4389
4484
  };
4390
4485
  var update = (state, _options) => {
4391
- const builder = new RangeSetBuilder2();
4486
+ const builder = new RangeSetBuilder4();
4392
4487
  const cursor = state.selection.main.head;
4393
4488
  const tables = [];
4394
4489
  const getTable = () => tables[tables.length - 1];
@@ -4429,12 +4524,12 @@ var update = (state, _options) => {
4429
4524
  tables.forEach((table2) => {
4430
4525
  const replace = state.readOnly || cursor < table2.from || cursor > table2.to;
4431
4526
  if (replace) {
4432
- builder.add(table2.from, table2.to, Decoration6.replace({
4527
+ builder.add(table2.from, table2.to, Decoration7.replace({
4433
4528
  block: true,
4434
4529
  widget: new TableWidget(table2)
4435
4530
  }));
4436
4531
  } else {
4437
- builder.add(table2.from, table2.to, Decoration6.mark({
4532
+ builder.add(table2.from, table2.to, Decoration7.mark({
4438
4533
  class: "cm-table"
4439
4534
  }));
4440
4535
  }
@@ -4443,8 +4538,7 @@ var update = (state, _options) => {
4443
4538
  };
4444
4539
  var TableWidget = class extends WidgetType4 {
4445
4540
  constructor(_table) {
4446
- super();
4447
- this._table = _table;
4541
+ super(), this._table = _table;
4448
4542
  }
4449
4543
  eq(other) {
4450
4544
  return this._table.header?.join() === other._table.header?.join() && this._table.rows?.join() === other._table.rows?.join();
@@ -4492,9 +4586,7 @@ var HorizontalRuleWidget = class extends WidgetType5 {
4492
4586
  };
4493
4587
  var LinkButton = class extends WidgetType5 {
4494
4588
  constructor(url, render) {
4495
- super();
4496
- this.url = url;
4497
- this.render = render;
4589
+ super(), this.url = url, this.render = render;
4498
4590
  }
4499
4591
  eq(other) {
4500
4592
  return this.url === other.url;
@@ -4510,8 +4602,7 @@ var LinkButton = class extends WidgetType5 {
4510
4602
  };
4511
4603
  var CheckboxWidget = class extends WidgetType5 {
4512
4604
  constructor(_checked) {
4513
- super();
4514
- this._checked = _checked;
4605
+ super(), this._checked = _checked;
4515
4606
  }
4516
4607
  eq(other) {
4517
4608
  return this._checked === other._checked;
@@ -4555,9 +4646,7 @@ var CheckboxWidget = class extends WidgetType5 {
4555
4646
  };
4556
4647
  var TextWidget = class extends WidgetType5 {
4557
4648
  constructor(text, className) {
4558
- super();
4559
- this.text = text;
4560
- this.className = className;
4649
+ super(), this.text = text, this.className = className;
4561
4650
  }
4562
4651
  toDOM() {
4563
4652
  const el = document.createElement("span");
@@ -4568,29 +4657,29 @@ var TextWidget = class extends WidgetType5 {
4568
4657
  return el;
4569
4658
  }
4570
4659
  };
4571
- var hide = Decoration7.replace({});
4572
- var blockQuote = Decoration7.line({
4660
+ var hide = Decoration8.replace({});
4661
+ var blockQuote = Decoration8.line({
4573
4662
  class: "cm-blockquote"
4574
4663
  });
4575
- var fencedCodeLine = Decoration7.line({
4664
+ var fencedCodeLine = Decoration8.line({
4576
4665
  class: "cm-code cm-codeblock-line"
4577
4666
  });
4578
- var fencedCodeLineFirst = Decoration7.line({
4667
+ var fencedCodeLineFirst = Decoration8.line({
4579
4668
  class: mx2("cm-code cm-codeblock-line", "cm-codeblock-start")
4580
4669
  });
4581
- var fencedCodeLineLast = Decoration7.line({
4670
+ var fencedCodeLineLast = Decoration8.line({
4582
4671
  class: mx2("cm-code cm-codeblock-line", "cm-codeblock-end")
4583
4672
  });
4584
4673
  var commentBlockLine = fencedCodeLine;
4585
4674
  var commentBlockLineFirst = fencedCodeLineFirst;
4586
4675
  var commentBlockLineLast = fencedCodeLineLast;
4587
- var horizontalRule = Decoration7.replace({
4676
+ var horizontalRule = Decoration8.replace({
4588
4677
  widget: new HorizontalRuleWidget()
4589
4678
  });
4590
- var checkedTask = Decoration7.replace({
4679
+ var checkedTask = Decoration8.replace({
4591
4680
  widget: new CheckboxWidget(true)
4592
4681
  });
4593
- var uncheckedTask = Decoration7.replace({
4682
+ var uncheckedTask = Decoration8.replace({
4594
4683
  widget: new CheckboxWidget(false)
4595
4684
  });
4596
4685
  var editingRange = (state, range, focus2) => {
@@ -4606,8 +4695,8 @@ var autoHideTags = /* @__PURE__ */ new Set([
4606
4695
  "SuperscriptMark"
4607
4696
  ]);
4608
4697
  var buildDecorations2 = (view, options, focus2) => {
4609
- const deco = new RangeSetBuilder3();
4610
- const atomicDeco = new RangeSetBuilder3();
4698
+ const deco = new RangeSetBuilder5();
4699
+ const atomicDeco = new RangeSetBuilder5();
4611
4700
  const { state } = view;
4612
4701
  const headerLevels = [];
4613
4702
  const getHeaderLevels = (node, level) => {
@@ -4694,7 +4783,7 @@ var buildDecorations2 = (view, options, focus2) => {
4694
4783
  } else {
4695
4784
  const num = headers.slice(from - 1).map((level2) => level2?.number ?? 0).join(".") + " ";
4696
4785
  if (num.length) {
4697
- atomicDeco.add(mark.from, mark.from + len, Decoration7.replace({
4786
+ atomicDeco.add(mark.from, mark.from + len, Decoration8.replace({
4698
4787
  widget: new TextWidget(num, theme.heading(level))
4699
4788
  }));
4700
4789
  }
@@ -4719,7 +4808,7 @@ var buildDecorations2 = (view, options, focus2) => {
4719
4808
  if (node.from === line.to - 1) {
4720
4809
  return false;
4721
4810
  }
4722
- deco.add(line.from, line.from, Decoration7.line({
4811
+ deco.add(line.from, line.from, Decoration8.line({
4723
4812
  class: "cm-list-item",
4724
4813
  attributes: {
4725
4814
  style: `padding-left: ${offset}px; text-indent: -${width}px;`
@@ -4736,7 +4825,7 @@ var buildDecorations2 = (view, options, focus2) => {
4736
4825
  const label = list.type === "OrderedList" ? `${++list.number}.` : Unicode.bulletSmall;
4737
4826
  const line = state.doc.lineAt(node.from);
4738
4827
  const to = state.doc.sliceString(node.to, node.to + 1) === " " ? node.to + 1 : node.to;
4739
- atomicDeco.add(line.from, to, Decoration7.replace({
4828
+ atomicDeco.add(line.from, to, Decoration8.replace({
4740
4829
  widget: new TextWidget(label, list.type === "OrderedList" ? "cm-list-mark cm-list-mark-ordered" : "cm-list-mark cm-list-mark-bullet")
4741
4830
  }));
4742
4831
  break;
@@ -4823,7 +4912,7 @@ var buildDecorations2 = (view, options, focus2) => {
4823
4912
  if (!editing) {
4824
4913
  atomicDeco.add(node.from, marks[0].to, hide);
4825
4914
  }
4826
- deco.add(marks[0].to, marks[1].from, Decoration7.mark({
4915
+ deco.add(marks[0].to, marks[1].from, Decoration8.mark({
4827
4916
  tagName: "a",
4828
4917
  attributes: {
4829
4918
  class: "cm-link",
@@ -4833,7 +4922,7 @@ var buildDecorations2 = (view, options, focus2) => {
4833
4922
  }
4834
4923
  }));
4835
4924
  if (!editing) {
4836
- atomicDeco.add(marks[1].from, node.to, options.renderLinkButton ? Decoration7.replace({
4925
+ atomicDeco.add(marks[1].from, node.to, options.renderLinkButton ? Decoration8.replace({
4837
4926
  widget: new LinkButton(url, options.renderLinkButton)
4838
4927
  }) : hide);
4839
4928
  }
@@ -4891,7 +4980,7 @@ var buildDecorations2 = (view, options, focus2) => {
4891
4980
  var forceUpdate = StateEffect5.define();
4892
4981
  var decorateMarkdown = (options = {}) => {
4893
4982
  return [
4894
- ViewPlugin7.fromClass(class {
4983
+ ViewPlugin10.fromClass(class {
4895
4984
  constructor(view) {
4896
4985
  ({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations2(view, options, view.hasFocus));
4897
4986
  }
@@ -4923,9 +5012,9 @@ var decorateMarkdown = (options = {}) => {
4923
5012
  }
4924
5013
  }, {
4925
5014
  provide: (plugin) => [
4926
- EditorView18.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration7.none),
4927
- EditorView18.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration7.none),
4928
- EditorView18.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration7.none)
5015
+ EditorView19.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration8.none),
5016
+ EditorView19.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration8.none),
5017
+ EditorView19.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration8.none)
4929
5018
  ]
4930
5019
  }),
4931
5020
  image(),
@@ -4977,58 +5066,773 @@ var linkTooltip = (renderTooltip) => {
4977
5066
  });
4978
5067
  };
4979
5068
 
4980
- // packages/ui/react-ui-editor/src/extensions/markdown/outliner.ts
4981
- import { syntaxTree as syntaxTree9 } from "@codemirror/language";
4982
- import { StateField as StateField10, EditorState as EditorState2 } from "@codemirror/state";
4983
- import { Decoration as Decoration8, EditorView as EditorView19 } from "@codemirror/view";
4984
- import { log as log6 } from "@dxos/log";
5069
+ // packages/ui/react-ui-editor/src/extensions/mention.ts
5070
+ import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
5071
+ import { log as log6 } from "@dxos/log";
5072
+ var __dxlog_file10 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/mention.ts";
5073
+ var mention = ({ debug, onSearch }) => {
5074
+ return autocompletion2({
5075
+ // TODO(burdon): Not working.
5076
+ activateOnTyping: true,
5077
+ // activateOnTypingDelay: 100,
5078
+ // selectOnOpen: true,
5079
+ closeOnBlur: !debug,
5080
+ // defaultKeymap: false,
5081
+ icons: false,
5082
+ override: [
5083
+ (context) => {
5084
+ log6.info("completion context", {
5085
+ context
5086
+ }, {
5087
+ F: __dxlog_file10,
5088
+ L: 27,
5089
+ S: void 0,
5090
+ C: (f, a) => f(...a)
5091
+ });
5092
+ const match = context.matchBefore(/@(\w+)?/);
5093
+ if (!match || match.from === match.to && !context.explicit) {
5094
+ return null;
5095
+ }
5096
+ return {
5097
+ from: match.from,
5098
+ options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
5099
+ label: `@${value}`
5100
+ }))
5101
+ };
5102
+ }
5103
+ ]
5104
+ });
5105
+ };
5106
+
5107
+ // packages/ui/react-ui-editor/src/extensions/modes.ts
5108
+ import { keymap as keymap10 } from "@codemirror/view";
5109
+ import { vim } from "@replit/codemirror-vim";
5110
+ import { vscodeKeymap } from "@replit/codemirror-vscode-keymap";
5111
+ import { Schema } from "effect";
5112
+ var EditorViewModes = [
5113
+ "preview",
5114
+ "readonly",
5115
+ "source"
5116
+ ];
5117
+ var EditorViewMode = Schema.Union(...EditorViewModes.map((mode) => Schema.Literal(mode)));
5118
+ var EditorInputModes = [
5119
+ "default",
5120
+ "vim",
5121
+ "vscode"
5122
+ ];
5123
+ var EditorInputMode = Schema.Union(...EditorInputModes.map((mode) => Schema.Literal(mode)));
5124
+ var editorInputMode = singleValueFacet({});
5125
+ var InputModeExtensions = {
5126
+ default: [],
5127
+ vscode: [
5128
+ // https://github.com/replit/codemirror-vscode-keymap
5129
+ editorInputMode.of({
5130
+ type: "vscode"
5131
+ }),
5132
+ keymap10.of(vscodeKeymap)
5133
+ ],
5134
+ vim: [
5135
+ // https://github.com/replit/codemirror-vim
5136
+ vim(),
5137
+ editorInputMode.of({
5138
+ type: "vim",
5139
+ noTabster: true
5140
+ }),
5141
+ keymap10.of([
5142
+ {
5143
+ key: "Alt-Escape",
5144
+ run: (view) => {
5145
+ view.dom.parentElement?.focus();
5146
+ return true;
5147
+ }
5148
+ }
5149
+ ])
5150
+ ]
5151
+ };
5152
+
5153
+ // packages/ui/react-ui-editor/src/extensions/outliner/commands.ts
5154
+ import { indentMore } from "@codemirror/commands";
5155
+ import { getIndentUnit } from "@codemirror/language";
5156
+ import { EditorSelection as EditorSelection3 } from "@codemirror/state";
5157
+ import { keymap as keymap11 } from "@codemirror/view";
5158
+
5159
+ // packages/ui/react-ui-editor/src/extensions/outliner/selection.ts
5160
+ import { Compartment, Facet as Facet3 } from "@codemirror/state";
5161
+
5162
+ // packages/ui/react-ui-editor/src/extensions/outliner/tree.ts
5163
+ import { syntaxTree as syntaxTree9 } from "@codemirror/language";
5164
+ import { StateField as StateField9 } from "@codemirror/state";
5165
+ import { Facet as Facet2 } from "@codemirror/state";
5166
+ import { invariant as invariant5 } from "@dxos/invariant";
5167
+ var __dxlog_file11 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/outliner/tree.ts";
5168
+ var itemToJSON = ({ type, index, level, lineRange, contentRange, children }) => {
5169
+ return {
5170
+ type,
5171
+ index,
5172
+ level,
5173
+ lineRange,
5174
+ contentRange,
5175
+ children: children.map(itemToJSON)
5176
+ };
5177
+ };
5178
+ var Tree = class {
5179
+ constructor(node) {
5180
+ this.type = "root";
5181
+ this.index = -1;
5182
+ this.level = -1;
5183
+ this.children = [];
5184
+ this.node = node;
5185
+ this.lineRange = {
5186
+ from: node.from,
5187
+ to: node.to
5188
+ };
5189
+ this.contentRange = this.lineRange;
5190
+ }
5191
+ toJSON() {
5192
+ return itemToJSON(this);
5193
+ }
5194
+ get root() {
5195
+ return this;
5196
+ }
5197
+ traverse(itemOrCb, maybeCb) {
5198
+ if (typeof itemOrCb === "function") {
5199
+ return traverse(this, itemOrCb);
5200
+ } else {
5201
+ return traverse(itemOrCb, maybeCb);
5202
+ }
5203
+ }
5204
+ /**
5205
+ * Return the closest item.
5206
+ */
5207
+ find(pos) {
5208
+ return this.traverse((item) => item.lineRange.from <= pos && item.lineRange.to >= pos ? item : void 0);
5209
+ }
5210
+ /**
5211
+ * Return the first child, next sibling, or parent's next sibling.
5212
+ */
5213
+ next(item, enter = true) {
5214
+ if (enter && item.children.length > 0) {
5215
+ return item.children[0];
5216
+ }
5217
+ if (item.nextSibling) {
5218
+ return item.nextSibling;
5219
+ }
5220
+ if (item.parent) {
5221
+ return this.next(item.parent, false);
5222
+ }
5223
+ return void 0;
5224
+ }
5225
+ /**
5226
+ * Return the previous sibling, or parent.
5227
+ */
5228
+ prev(item) {
5229
+ if (item.prevSibling) {
5230
+ return this.lastDescendant(item.prevSibling);
5231
+ }
5232
+ return item.parent?.type === "root" ? void 0 : item.parent;
5233
+ }
5234
+ /**
5235
+ * Return the last descendant of the item, or the item itself if it has no children.
5236
+ */
5237
+ lastDescendant(item) {
5238
+ return item.children.length > 0 ? this.lastDescendant(item.children.at(-1)) : item;
5239
+ }
5240
+ };
5241
+ var getRange = (tree, item) => {
5242
+ const lastDescendant = tree.lastDescendant(item);
5243
+ return [
5244
+ item.lineRange.from,
5245
+ lastDescendant.lineRange.to
5246
+ ];
5247
+ };
5248
+ var traverse = (root, cb) => {
5249
+ const t = (item, level) => {
5250
+ if (item.type !== "root") {
5251
+ const value = cb(item, level);
5252
+ if (value != null) {
5253
+ return value;
5254
+ }
5255
+ }
5256
+ for (const child of item.children) {
5257
+ const value = t(child, level + 1);
5258
+ if (value != null) {
5259
+ return value;
5260
+ }
5261
+ }
5262
+ };
5263
+ return t(root, root.type === "root" ? -1 : 0);
5264
+ };
5265
+ var getListItemContent = (state, item) => {
5266
+ return state.doc.sliceString(item.contentRange.from, item.contentRange.to);
5267
+ };
5268
+ var listItemToString = (item, level = 0) => {
5269
+ const indent = " ".repeat(level);
5270
+ const data = {
5271
+ i: item.index,
5272
+ n: item.nextSibling?.index ?? "\u2205",
5273
+ p: item.prevSibling?.index ?? "\u2205",
5274
+ level: item.level,
5275
+ node: format([
5276
+ item.node.from,
5277
+ item.node.to
5278
+ ]),
5279
+ line: format([
5280
+ item.lineRange.from,
5281
+ item.lineRange.to
5282
+ ]),
5283
+ content: format([
5284
+ item.contentRange.from,
5285
+ item.contentRange.to
5286
+ ])
5287
+ };
5288
+ return `${indent}${item.type[0].toUpperCase()}(${Object.entries(data).map(([k, v]) => `${k}=${v}`).join(", ")})`;
5289
+ };
5290
+ var format = (value) => JSON.stringify(value, (key, value2) => {
5291
+ if (typeof value2 === "number") {
5292
+ return value2.toString().padStart(3, " ");
5293
+ }
5294
+ return value2;
5295
+ }).replaceAll('"', "");
5296
+ var treeFacet = Facet2.define({
5297
+ combine: (values) => values[0]
5298
+ });
5299
+ var outlinerTree = (options = {}) => {
5300
+ const buildTree = (state) => {
5301
+ let tree;
5302
+ let parent;
5303
+ let current;
5304
+ let prev;
5305
+ let level = -1;
5306
+ let index = -1;
5307
+ const prevSiblings = [];
5308
+ syntaxTree9(state).iterate({
5309
+ enter: (node) => {
5310
+ switch (node.name) {
5311
+ case "Document": {
5312
+ tree = new Tree(node.node);
5313
+ current = tree;
5314
+ break;
5315
+ }
5316
+ case "BulletList": {
5317
+ invariant5(current, void 0, {
5318
+ F: __dxlog_file11,
5319
+ L: 217,
5320
+ S: void 0,
5321
+ A: [
5322
+ "current",
5323
+ ""
5324
+ ]
5325
+ });
5326
+ parent = current;
5327
+ if (current) {
5328
+ current.lineRange.to = current.node.from;
5329
+ }
5330
+ prevSiblings[++level] = void 0;
5331
+ break;
5332
+ }
5333
+ case "ListItem": {
5334
+ invariant5(parent, void 0, {
5335
+ F: __dxlog_file11,
5336
+ L: 226,
5337
+ S: void 0,
5338
+ A: [
5339
+ "parent",
5340
+ ""
5341
+ ]
5342
+ });
5343
+ const nextSibling = node.node.nextSibling ?? node.node.parent?.nextSibling;
5344
+ const docRange = {
5345
+ from: state.doc.lineAt(node.from).from,
5346
+ to: nextSibling ? nextSibling.from - 1 : state.doc.length
5347
+ };
5348
+ current = {
5349
+ type: "unknown",
5350
+ index: ++index,
5351
+ level,
5352
+ node: node.node,
5353
+ lineRange: docRange,
5354
+ contentRange: {
5355
+ ...docRange
5356
+ },
5357
+ parent,
5358
+ prevSibling: prevSiblings[level],
5359
+ children: []
5360
+ };
5361
+ if (current.prevSibling) {
5362
+ current.prevSibling.nextSibling = current;
5363
+ }
5364
+ prevSiblings[level] = current;
5365
+ if (prev) {
5366
+ prev.lineRange.to = prev.contentRange.to = current.lineRange.from - 1;
5367
+ }
5368
+ prev = current;
5369
+ parent.children.push(current);
5370
+ if (parent.lineRange.to === parent.node.from) {
5371
+ parent.lineRange.to = parent.contentRange.to = current.lineRange.from - 1;
5372
+ }
5373
+ break;
5374
+ }
5375
+ case "ListMark": {
5376
+ invariant5(current, void 0, {
5377
+ F: __dxlog_file11,
5378
+ L: 270,
5379
+ S: void 0,
5380
+ A: [
5381
+ "current",
5382
+ ""
5383
+ ]
5384
+ });
5385
+ current.type = "bullet";
5386
+ current.contentRange.from = node.from + "- ".length;
5387
+ break;
5388
+ }
5389
+ case "Task": {
5390
+ invariant5(current, void 0, {
5391
+ F: __dxlog_file11,
5392
+ L: 276,
5393
+ S: void 0,
5394
+ A: [
5395
+ "current",
5396
+ ""
5397
+ ]
5398
+ });
5399
+ current.type = "task";
5400
+ break;
5401
+ }
5402
+ case "TaskMarker": {
5403
+ invariant5(current, void 0, {
5404
+ F: __dxlog_file11,
5405
+ L: 281,
5406
+ S: void 0,
5407
+ A: [
5408
+ "current",
5409
+ ""
5410
+ ]
5411
+ });
5412
+ current.contentRange.from = node.from + "[ ] ".length;
5413
+ break;
5414
+ }
5415
+ }
5416
+ },
5417
+ leave: (node) => {
5418
+ if (node.name === "BulletList") {
5419
+ invariant5(parent, void 0, {
5420
+ F: __dxlog_file11,
5421
+ L: 289,
5422
+ S: void 0,
5423
+ A: [
5424
+ "parent",
5425
+ ""
5426
+ ]
5427
+ });
5428
+ prevSiblings[level--] = void 0;
5429
+ parent = parent.parent;
5430
+ }
5431
+ }
5432
+ });
5433
+ invariant5(tree, void 0, {
5434
+ F: __dxlog_file11,
5435
+ L: 296,
5436
+ S: void 0,
5437
+ A: [
5438
+ "tree",
5439
+ ""
5440
+ ]
5441
+ });
5442
+ return tree;
5443
+ };
5444
+ return [
5445
+ StateField9.define({
5446
+ create: (state) => {
5447
+ return buildTree(state);
5448
+ },
5449
+ update: (value, tr) => {
5450
+ if (!tr.docChanged) {
5451
+ return value;
5452
+ }
5453
+ return buildTree(tr.state);
5454
+ },
5455
+ provide: (field) => treeFacet.from(field)
5456
+ })
5457
+ ];
5458
+ };
5459
+
5460
+ // packages/ui/react-ui-editor/src/extensions/outliner/selection.ts
5461
+ var getSelection = (state) => state.selection.main;
5462
+ var selectionEquals = (a, b) => a.length === b.length && a.every((i) => b.includes(i));
5463
+ var selectionFacet = Facet3.define({
5464
+ combine: (values) => values[0]
5465
+ });
5466
+ var selectionCompartment = new Compartment();
5467
+ var selectNone = (view) => {
5468
+ view.dispatch({
5469
+ effects: selectionCompartment.reconfigure(selectionFacet.of([]))
5470
+ });
5471
+ return true;
5472
+ };
5473
+ var selectAll = (view) => {
5474
+ const tree = view.state.facet(treeFacet);
5475
+ const selection = view.state.facet(selectionFacet);
5476
+ const items = [];
5477
+ tree.traverse((item) => items.push(item.index));
5478
+ view.dispatch({
5479
+ effects: selectionCompartment.reconfigure(selectionFacet.of(selectionEquals(selection, items) ? [] : items))
5480
+ });
5481
+ return true;
5482
+ };
5483
+ var selectUp = (view) => {
5484
+ return true;
5485
+ };
5486
+ var selectDown = (view) => {
5487
+ return true;
5488
+ };
5489
+
5490
+ // packages/ui/react-ui-editor/src/extensions/outliner/commands.ts
5491
+ var indentItemMore = (view) => {
5492
+ const pos = getSelection(view.state).from;
5493
+ const tree = view.state.facet(treeFacet);
5494
+ const current = tree.find(pos);
5495
+ if (current) {
5496
+ const previous = tree.prev(current);
5497
+ if (previous && current.level <= previous.level) {
5498
+ indentMore(view);
5499
+ }
5500
+ }
5501
+ return true;
5502
+ };
5503
+ var indentItemLess = (view) => {
5504
+ const pos = getSelection(view.state).from;
5505
+ const tree = view.state.facet(treeFacet);
5506
+ const current = tree.find(pos);
5507
+ if (current) {
5508
+ if (current.level > 0) {
5509
+ const indentUnit = getIndentUnit(view.state);
5510
+ const changes = [];
5511
+ tree.traverse(current, (item) => {
5512
+ const line = view.state.doc.lineAt(item.lineRange.from);
5513
+ changes.push({
5514
+ from: line.from,
5515
+ to: line.from + indentUnit
5516
+ });
5517
+ });
5518
+ if (changes.length > 0) {
5519
+ view.dispatch({
5520
+ changes
5521
+ });
5522
+ }
5523
+ }
5524
+ }
5525
+ return true;
5526
+ };
5527
+ var moveItemDown = (view) => {
5528
+ const pos = getSelection(view.state)?.from;
5529
+ const tree = view.state.facet(treeFacet);
5530
+ const current = tree.find(pos);
5531
+ if (current && current.nextSibling) {
5532
+ const next = current.nextSibling;
5533
+ const currentContent = view.state.doc.sliceString(...getRange(tree, current));
5534
+ const nextContent = view.state.doc.sliceString(...getRange(tree, next));
5535
+ const changes = [
5536
+ {
5537
+ from: current.lineRange.from,
5538
+ to: current.lineRange.from + currentContent.length,
5539
+ insert: nextContent
5540
+ },
5541
+ {
5542
+ from: next.lineRange.from,
5543
+ to: next.lineRange.from + nextContent.length,
5544
+ insert: currentContent
5545
+ }
5546
+ ];
5547
+ view.dispatch({
5548
+ changes,
5549
+ selection: EditorSelection3.cursor(pos + nextContent.length + 1),
5550
+ scrollIntoView: true
5551
+ });
5552
+ }
5553
+ return true;
5554
+ };
5555
+ var moveItemUp = (view) => {
5556
+ const pos = getSelection(view.state)?.from;
5557
+ const tree = view.state.facet(treeFacet);
5558
+ const current = tree.find(pos);
5559
+ if (current && current.prevSibling) {
5560
+ const prev = current.prevSibling;
5561
+ const currentContent = view.state.doc.sliceString(...getRange(tree, current));
5562
+ const prevContent = view.state.doc.sliceString(...getRange(tree, prev));
5563
+ const changes = [
5564
+ {
5565
+ from: prev.lineRange.from,
5566
+ to: prev.lineRange.from + prevContent.length,
5567
+ insert: currentContent
5568
+ },
5569
+ {
5570
+ from: current.lineRange.from,
5571
+ to: current.lineRange.from + currentContent.length,
5572
+ insert: prevContent
5573
+ }
5574
+ ];
5575
+ view.dispatch({
5576
+ changes,
5577
+ selection: EditorSelection3.cursor(pos - prevContent.length - 1),
5578
+ scrollIntoView: true
5579
+ });
5580
+ }
5581
+ return true;
5582
+ };
5583
+ var deleteItem = (view) => {
5584
+ const tree = view.state.facet(treeFacet);
5585
+ const pos = getSelection(view.state).from;
5586
+ const current = tree.find(pos);
5587
+ if (current) {
5588
+ view.dispatch({
5589
+ selection: EditorSelection3.cursor(current.lineRange.from),
5590
+ changes: [
5591
+ {
5592
+ from: current.lineRange.from,
5593
+ to: Math.min(current.lineRange.to + 1, view.state.doc.length)
5594
+ }
5595
+ ]
5596
+ });
5597
+ }
5598
+ return true;
5599
+ };
5600
+ var toggleTask = (view) => {
5601
+ const tree = view.state.facet(treeFacet);
5602
+ const pos = getSelection(view.state)?.from;
5603
+ const current = tree.find(pos);
5604
+ if (current) {
5605
+ const type = current.type === "task" ? "bullet" : "task";
5606
+ const indent = " ".repeat(getIndentUnit(view.state) * current.level);
5607
+ view.dispatch({
5608
+ changes: [
5609
+ {
5610
+ from: current.lineRange.from,
5611
+ to: current.contentRange.from,
5612
+ insert: indent + (type === "task" ? "- [ ] " : "- ")
5613
+ }
5614
+ ]
5615
+ });
5616
+ }
5617
+ return true;
5618
+ };
5619
+ var commands = () => keymap11.of([
5620
+ //
5621
+ // Indentation.
5622
+ //
5623
+ {
5624
+ key: "Tab",
5625
+ preventDefault: true,
5626
+ run: indentItemMore,
5627
+ shift: indentItemLess
5628
+ },
5629
+ //
5630
+ // Continuation.
5631
+ //
5632
+ {
5633
+ key: "Enter",
5634
+ shift: (view) => {
5635
+ const pos = getSelection(view.state).from;
5636
+ const insert = "\n ";
5637
+ view.dispatch({
5638
+ changes: [
5639
+ {
5640
+ from: pos,
5641
+ to: pos,
5642
+ insert
5643
+ }
5644
+ ],
5645
+ selection: EditorSelection3.cursor(pos + insert.length)
5646
+ });
5647
+ return true;
5648
+ }
5649
+ },
5650
+ //
5651
+ // Navigation.
5652
+ //
5653
+ {
5654
+ key: "ArrowDown",
5655
+ // Jump to next item (default moves to end of currentline).
5656
+ run: (view) => {
5657
+ const tree = view.state.facet(treeFacet);
5658
+ const item = tree.find(getSelection(view.state).from);
5659
+ if (item && view.state.doc.lineAt(item.lineRange.to).number - view.state.doc.lineAt(item.lineRange.from).number === 0) {
5660
+ const next = tree.next(item);
5661
+ if (next) {
5662
+ view.dispatch({
5663
+ selection: EditorSelection3.cursor(next.contentRange.from)
5664
+ });
5665
+ return true;
5666
+ }
5667
+ }
5668
+ return false;
5669
+ }
5670
+ },
5671
+ //
5672
+ // Line selection.
5673
+ // TODO(burdon): Shortcut to select current item?
5674
+ //
5675
+ {
5676
+ key: "Mod-a",
5677
+ preventDefault: true,
5678
+ run: selectAll
5679
+ },
5680
+ {
5681
+ key: "Escape",
5682
+ preventDefault: true,
5683
+ run: selectNone
5684
+ },
5685
+ {
5686
+ key: "ArrowUp",
5687
+ shift: selectUp
5688
+ },
5689
+ {
5690
+ key: "ArrowDown",
5691
+ shift: selectDown
5692
+ },
5693
+ //
5694
+ // Move.
5695
+ //
5696
+ {
5697
+ key: "Alt-ArrowDown",
5698
+ preventDefault: true,
5699
+ run: moveItemDown
5700
+ },
5701
+ {
5702
+ key: "Alt-ArrowUp",
5703
+ preventDefault: true,
5704
+ run: moveItemUp
5705
+ },
5706
+ //
5707
+ // Delete.
5708
+ //
5709
+ {
5710
+ key: "Mod-Backspace",
5711
+ preventDefault: true,
5712
+ run: deleteItem
5713
+ },
5714
+ //
5715
+ // Misc.
5716
+ //
5717
+ {
5718
+ key: "Alt-t",
5719
+ preventDefault: true,
5720
+ run: toggleTask
5721
+ }
5722
+ ]);
5723
+
5724
+ // packages/ui/react-ui-editor/src/extensions/outliner/outliner.ts
5725
+ import { Prec as Prec2 } from "@codemirror/state";
5726
+ import { Decoration as Decoration9, EditorView as EditorView20, ViewPlugin as ViewPlugin12 } from "@codemirror/view";
4985
5727
  import { mx as mx3 } from "@dxos/react-ui-theme";
4986
- var __dxlog_file10 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/markdown/outliner.ts";
4987
- var indentLevel = 2;
4988
- var matchTaskMarker = /^\s*- (\[ \]|\[x\])? /;
4989
- var getLineInfo = (line) => {
4990
- const match = line.text.match(matchTaskMarker);
4991
- const start = line.from + (match?.[0]?.length ?? 0);
4992
- return {
4993
- match,
4994
- start
4995
- };
5728
+
5729
+ // packages/ui/react-ui-editor/src/extensions/outliner/editor.ts
5730
+ import { EditorSelection as EditorSelection4, EditorState as EditorState2 } from "@codemirror/state";
5731
+ import { ViewPlugin as ViewPlugin11 } from "@codemirror/view";
5732
+ import { log as log7 } from "@dxos/log";
5733
+ var __dxlog_file12 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/outliner/editor.ts";
5734
+ var LIST_ITEM_REGEX = /^\s*- (\[ \]|\[x\])? /;
5735
+ var initialize = () => {
5736
+ return ViewPlugin11.fromClass(class {
5737
+ constructor(view) {
5738
+ const first = view.state.doc.lineAt(0);
5739
+ const text = view.state.sliceDoc(first.from, first.to);
5740
+ const match = text.match(LIST_ITEM_REGEX);
5741
+ if (!match) {
5742
+ setTimeout(() => {
5743
+ const insert = "- [ ] ";
5744
+ view.dispatch({
5745
+ changes: [
5746
+ {
5747
+ from: 0,
5748
+ to: 0,
5749
+ insert
5750
+ }
5751
+ ],
5752
+ selection: EditorSelection4.cursor(insert.length)
5753
+ });
5754
+ });
5755
+ }
5756
+ }
5757
+ });
4996
5758
  };
4997
- var outliner = () => [
5759
+ var editor = () => [
5760
+ initialize(),
4998
5761
  EditorState2.transactionFilter.of((tr) => {
5762
+ const tree = tr.state.facet(treeFacet);
4999
5763
  if (!tr.docChanged) {
5000
- const pos = tr.selection?.ranges[tr.selection?.mainIndex]?.from;
5001
- if (pos != null) {
5002
- const { match, start } = getLineInfo(tr.startState.doc.lineAt(pos));
5003
- if (match) {
5004
- if (pos < start) {
5764
+ const current = getSelection(tr.state).from;
5765
+ if (current != null) {
5766
+ const currentItem = tree.find(current);
5767
+ if (!currentItem) {
5768
+ return [];
5769
+ }
5770
+ if (current < currentItem.contentRange.from || current > currentItem.contentRange.to) {
5771
+ const prev = getSelection(tr.startState).from;
5772
+ const prevItem = prev != null ? tree.find(prev) : void 0;
5773
+ if (!prevItem) {
5005
5774
  return [
5006
5775
  {
5007
- selection: {
5008
- anchor: start,
5009
- head: start
5010
- }
5776
+ selection: EditorSelection4.cursor(currentItem.contentRange.from)
5011
5777
  }
5012
5778
  ];
5779
+ } else {
5780
+ if (currentItem.index < prevItem.index) {
5781
+ return [
5782
+ {
5783
+ selection: EditorSelection4.cursor(currentItem.contentRange.to)
5784
+ }
5785
+ ];
5786
+ } else if (currentItem.index > prevItem.index) {
5787
+ return [
5788
+ {
5789
+ selection: EditorSelection4.cursor(currentItem.contentRange.from)
5790
+ }
5791
+ ];
5792
+ } else {
5793
+ if (current < prev) {
5794
+ if (currentItem.index === 0) {
5795
+ return [];
5796
+ } else {
5797
+ return [
5798
+ {
5799
+ selection: EditorSelection4.cursor(currentItem.lineRange.from - 1)
5800
+ }
5801
+ ];
5802
+ }
5803
+ } else {
5804
+ return [
5805
+ {
5806
+ selection: EditorSelection4.cursor(currentItem.contentRange.to)
5807
+ }
5808
+ ];
5809
+ }
5810
+ }
5013
5811
  }
5014
5812
  }
5015
5813
  }
5016
5814
  return tr;
5017
5815
  }
5816
+ let cancel = false;
5018
5817
  const changes = [];
5019
5818
  tr.changes.iterChanges((fromA, toA, fromB, toB, insert) => {
5020
5819
  const line = tr.startState.doc.lineAt(fromA);
5021
- const isTaskMarker = line.text.match(matchTaskMarker);
5022
- if (isTaskMarker) {
5023
- const { start } = getLineInfo(line);
5820
+ const match = line.text.match(LIST_ITEM_REGEX);
5821
+ if (match) {
5822
+ const startTree = tr.startState.facet(treeFacet);
5823
+ const startItem = startTree.find(tr.startState.selection.main.from);
5824
+ const deleteLine = fromA === startItem?.lineRange.from && toA === startItem?.lineRange.to + 1;
5825
+ if (deleteLine) {
5826
+ return;
5827
+ }
5828
+ const currentItem = tree.find(tr.state.selection.main.from);
5829
+ if (!currentItem?.contentRange) {
5830
+ cancel = true;
5831
+ return;
5832
+ }
5833
+ const start = line.from + (match?.[0]?.length ?? 0);
5024
5834
  const replace = start === toA && toA - fromA === insert.length;
5025
5835
  if (replace) {
5026
- log6.info("delete line", void 0, {
5027
- F: __dxlog_file10,
5028
- L: 82,
5029
- S: void 0,
5030
- C: (f, a) => f(...a)
5031
- });
5032
5836
  changes.push({
5033
5837
  from: line.from - 1,
5034
5838
  to: toA
@@ -5040,24 +5844,9 @@ var outliner = () => [
5040
5844
  const line2 = tr.state.doc.lineAt(fromA);
5041
5845
  if (line2.text.match(/^\s*$/)) {
5042
5846
  if (line2.from === 0) {
5043
- log6.info("skip", void 0, {
5044
- F: __dxlog_file10,
5045
- L: 94,
5046
- S: void 0,
5047
- C: (f, a) => f(...a)
5048
- });
5049
- changes.push({
5050
- from: 0,
5051
- to: 0
5052
- });
5847
+ cancel = true;
5053
5848
  return;
5054
5849
  } else {
5055
- log6.info("delete line", void 0, {
5056
- F: __dxlog_file10,
5057
- L: 99,
5058
- S: void 0,
5059
- C: (f, a) => f(...a)
5060
- });
5061
5850
  changes.push({
5062
5851
  from: line2.from - 1,
5063
5852
  to: toA
@@ -5068,44 +5857,17 @@ var outliner = () => [
5068
5857
  }
5069
5858
  return;
5070
5859
  }
5071
- if (insert.length === indentLevel) {
5072
- if (line.number === 1) {
5073
- log6.info("skip", void 0, {
5074
- F: __dxlog_file10,
5075
- L: 111,
5076
- S: void 0,
5077
- C: (f, a) => f(...a)
5078
- });
5079
- changes.push({
5080
- from: 0,
5081
- to: 0
5082
- });
5083
- return;
5084
- } else {
5085
- const getIndent = (text) => (text.match(/^\s*/)?.[0]?.length ?? 0) / indentLevel;
5086
- const currentIndent = getIndent(line.text);
5087
- const indentPrevious = getIndent(tr.state.doc.lineAt(fromA - 1).text);
5088
- if (currentIndent > indentPrevious) {
5089
- log6.info("skip", void 0, {
5090
- F: __dxlog_file10,
5091
- L: 119,
5092
- S: void 0,
5093
- C: (f, a) => f(...a)
5094
- });
5095
- changes.push({
5096
- from: 0,
5097
- to: 0
5098
- });
5099
- return;
5100
- }
5101
- }
5860
+ const item = tree.find(fromA);
5861
+ if (item?.contentRange.from === item?.contentRange.to && fromA === toA) {
5862
+ cancel = true;
5863
+ return;
5102
5864
  }
5103
- log6.info("change", {
5865
+ log7("change", {
5866
+ item,
5104
5867
  line: {
5105
5868
  from: line.from,
5106
5869
  to: line.to
5107
5870
  },
5108
- start,
5109
5871
  a: [
5110
5872
  fromA,
5111
5873
  toA
@@ -5119,200 +5881,150 @@ var outliner = () => [
5119
5881
  length: insert.length
5120
5882
  }
5121
5883
  }, {
5122
- F: __dxlog_file10,
5123
- L: 134,
5884
+ F: __dxlog_file12,
5885
+ L: 164,
5124
5886
  S: void 0,
5125
5887
  C: (f, a) => f(...a)
5126
5888
  });
5127
5889
  }
5128
5890
  });
5129
5891
  if (changes.length > 0) {
5892
+ log7("modified,", {
5893
+ changes
5894
+ }, {
5895
+ F: __dxlog_file12,
5896
+ L: 175,
5897
+ S: void 0,
5898
+ C: (f, a) => f(...a)
5899
+ });
5130
5900
  return [
5131
5901
  {
5132
5902
  changes
5133
5903
  }
5134
5904
  ];
5905
+ } else if (cancel) {
5906
+ log7("cancel", void 0, {
5907
+ F: __dxlog_file12,
5908
+ L: 178,
5909
+ S: void 0,
5910
+ C: (f, a) => f(...a)
5911
+ });
5912
+ return [];
5135
5913
  }
5136
5914
  return tr;
5915
+ })
5916
+ ];
5917
+
5918
+ // packages/ui/react-ui-editor/src/extensions/outliner/outliner.ts
5919
+ var outliner = (options = {}) => [
5920
+ // Commands.
5921
+ Prec2.highest(commands()),
5922
+ // Selection.
5923
+ selectionCompartment.of(selectionFacet.of([])),
5924
+ // State.
5925
+ outlinerTree(),
5926
+ // Filter and possibly modify changes.
5927
+ editor(),
5928
+ // Floating menu.
5929
+ floatingMenu(),
5930
+ // Line decorations.
5931
+ decorations(options),
5932
+ // Default markdown decorations.
5933
+ decorateMarkdown({
5934
+ listPaddingLeft: 8
5935
+ }),
5936
+ // Researve space for menu.
5937
+ EditorView20.contentAttributes.of({
5938
+ class: "is-full !mr-[3rem]"
5939
+ })
5940
+ ];
5941
+ var decorations = (options) => [
5942
+ ViewPlugin12.fromClass(class {
5943
+ constructor(view) {
5944
+ this.decorations = Decoration9.none;
5945
+ this.updateDecorations(view.state, view);
5946
+ }
5947
+ update(update2) {
5948
+ const selectionChanged = !selectionEquals(update2.state.facet(selectionFacet), update2.startState.facet(selectionFacet));
5949
+ if (update2.focusChanged || update2.docChanged || update2.viewportChanged || update2.selectionSet || selectionChanged) {
5950
+ this.updateDecorations(update2.state, update2.view);
5951
+ }
5952
+ }
5953
+ updateDecorations(state, { viewport: { from, to }, hasFocus }) {
5954
+ const selection = state.facet(selectionFacet);
5955
+ const tree = state.facet(treeFacet);
5956
+ const current = tree.find(state.selection.ranges[state.selection.mainIndex]?.from);
5957
+ const doc = state.doc;
5958
+ const decorations2 = [];
5959
+ for (let lineNum = doc.lineAt(from).number; lineNum <= doc.lineAt(to).number; lineNum++) {
5960
+ const line = doc.line(lineNum);
5961
+ const item = tree.find(line.from);
5962
+ if (item) {
5963
+ const lineFrom = doc.lineAt(item.contentRange.from);
5964
+ const lineTo = doc.lineAt(item.contentRange.to);
5965
+ const isSelected = selection.includes(item.index) || item === current;
5966
+ decorations2.push(Decoration9.line({
5967
+ class: mx3("cm-list-item", lineFrom.number === line.number && "cm-list-item-start", lineTo.number === line.number && "cm-list-item-end", isSelected && (hasFocus ? "cm-list-item-focused" : "cm-list-item-selected"))
5968
+ }).range(line.from, line.from));
5969
+ }
5970
+ }
5971
+ this.decorations = Decoration9.set(decorations2);
5972
+ }
5973
+ }, {
5974
+ decorations: (v) => v.decorations
5137
5975
  }),
5138
- StateField10.define({
5139
- create: (state) => {
5140
- return Decoration8.set(buildDecorations3(0, state.doc.length, state));
5976
+ // Theme.
5977
+ EditorView20.theme(Object.assign({
5978
+ ".cm-list-item": {
5979
+ borderLeftWidth: "1px",
5980
+ borderRightWidth: "1px",
5981
+ paddingLeft: "32px",
5982
+ borderColor: "transparent"
5141
5983
  },
5142
- update: (value, tr) => {
5143
- const from = 0;
5144
- const to = tr.state.doc.length;
5145
- return value.map(tr.changes).update({
5146
- filterFrom: 0,
5147
- filterTo: tr.state.doc.length,
5148
- filter: () => false,
5149
- add: buildDecorations3(from, to, tr.state)
5150
- });
5984
+ ".cm-list-item.cm-codeblock-start": {
5985
+ borderRadius: "0"
5151
5986
  },
5152
- provide: (field) => EditorView19.decorations.from(field)
5153
- }),
5154
- // TODO(burdon): Increase indent padding by configuring decorate extension.
5155
- // TODO(burdon): Hover to select entire group.
5156
- EditorView19.theme({
5157
5987
  ".cm-list-item-start": {
5158
- borderTop: "1px solid var(--dx-separator)",
5159
- borderLeft: "1px solid var(--dx-separator)",
5160
- borderRight: "1px solid var(--dx-separator)",
5988
+ borderTopWidth: "1px",
5161
5989
  borderTopLeftRadius: "4px",
5162
5990
  borderTopRightRadius: "4px",
5163
5991
  paddingTop: "4px",
5164
- marginTop: "8px"
5992
+ marginTop: "2px"
5165
5993
  },
5166
5994
  ".cm-list-item-end": {
5167
- borderLeft: "1px solid var(--dx-separator)",
5168
- borderRight: "1px solid var(--dx-separator)",
5169
- borderBottom: "1px solid var(--dx-separator)",
5995
+ borderBottomWidth: "1px",
5170
5996
  borderBottomLeftRadius: "4px",
5171
5997
  borderBottomRightRadius: "4px",
5172
5998
  paddingBottom: "4px",
5173
- marginBottom: "8px"
5999
+ marginBottom: "2px"
5174
6000
  },
5175
- ".cm-list-item-continuation": {
5176
- borderLeft: "1px solid var(--dx-separator)",
5177
- borderRight: "1px solid var(--dx-separator)",
5178
- // TODO(burdon): Should match parent indentation.
5179
- paddingLeft: "24px"
6001
+ ".cm-list-item-selected": {
6002
+ borderColor: options.showSelected ? "var(--dx-separator)" : void 0
5180
6003
  },
5181
- // TODO(burdon): Set via options to decorate extension.
5182
- ".cm-list-item-continuation.cm-codeblock-start": {
5183
- borderRadius: "0"
5184
- }
5185
- })
5186
- ];
5187
- var buildDecorations3 = (from, to, state) => {
5188
- const decorations = [];
5189
- syntaxTree9(state).iterate({
5190
- enter: (node) => {
5191
- if (node.name === "ListItem") {
5192
- const sub = node.node.getChild("BulletList");
5193
- const lineStart = state.doc.lineAt(node.from);
5194
- const lineEnd = sub ? state.doc.lineAt(state.doc.lineAt(sub.from).from - 1) : state.doc.lineAt(node.to);
5195
- decorations.push(Decoration8.line({
5196
- class: mx3("cm-list-item-start", lineStart.number === lineEnd.number && "cm-list-item-end")
5197
- }).range(lineStart.from, lineStart.from));
5198
- for (let i = lineStart.from + 1; i < lineEnd.from; i++) {
5199
- decorations.push(Decoration8.line({
5200
- class: mx3("cm-list-item-continuation")
5201
- }).range(i, i));
5202
- }
5203
- if (lineStart.number !== lineEnd.number) {
5204
- decorations.push(Decoration8.line({
5205
- class: mx3("cm-list-item-end")
5206
- }).range(lineEnd.from, lineEnd.from));
5207
- }
5208
- }
6004
+ ".cm-list-item-focused": {
6005
+ borderColor: "var(--dx-accentFocusIndicator)"
5209
6006
  }
5210
- });
5211
- return decorations;
5212
- };
5213
-
5214
- // packages/ui/react-ui-editor/src/extensions/mention.ts
5215
- import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
5216
- import { log as log7 } from "@dxos/log";
5217
- var __dxlog_file11 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/mention.ts";
5218
- var mention = ({ debug, onSearch }) => {
5219
- return autocompletion2({
5220
- // TODO(burdon): Not working.
5221
- activateOnTyping: true,
5222
- // activateOnTypingDelay: 100,
5223
- // selectOnOpen: true,
5224
- closeOnBlur: !debug,
5225
- // defaultKeymap: false,
5226
- icons: false,
5227
- override: [
5228
- (context) => {
5229
- log7.info("completion context", {
5230
- context
5231
- }, {
5232
- F: __dxlog_file11,
5233
- L: 27,
5234
- S: void 0,
5235
- C: (f, a) => f(...a)
5236
- });
5237
- const match = context.matchBefore(/@(\w+)?/);
5238
- if (!match || match.from === match.to && !context.explicit) {
5239
- return null;
5240
- }
5241
- return {
5242
- from: match.from,
5243
- options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
5244
- label: `@${value}`
5245
- }))
5246
- };
5247
- }
5248
- ]
5249
- });
5250
- };
5251
-
5252
- // packages/ui/react-ui-editor/src/extensions/modes.ts
5253
- import { keymap as keymap9 } from "@codemirror/view";
5254
- import { vim } from "@replit/codemirror-vim";
5255
- import { vscodeKeymap } from "@replit/codemirror-vscode-keymap";
5256
- import { Schema } from "effect";
5257
- var EditorViewModes = [
5258
- "preview",
5259
- "readonly",
5260
- "source"
5261
- ];
5262
- var EditorViewMode = Schema.Union(...EditorViewModes.map((mode) => Schema.Literal(mode)));
5263
- var EditorInputModes = [
5264
- "default",
5265
- "vim",
5266
- "vscode"
6007
+ }))
5267
6008
  ];
5268
- var EditorInputMode = Schema.Union(...EditorInputModes.map((mode) => Schema.Literal(mode)));
5269
- var editorInputMode = singleValueFacet({});
5270
- var InputModeExtensions = {
5271
- default: [],
5272
- vscode: [
5273
- // https://github.com/replit/codemirror-vscode-keymap
5274
- editorInputMode.of({
5275
- type: "vscode"
5276
- }),
5277
- keymap9.of(vscodeKeymap)
5278
- ],
5279
- vim: [
5280
- // https://github.com/replit/codemirror-vim
5281
- vim(),
5282
- editorInputMode.of({
5283
- type: "vim",
5284
- noTabster: true
5285
- }),
5286
- keymap9.of([
5287
- {
5288
- key: "Alt-Escape",
5289
- run: (view) => {
5290
- view.dom.parentElement?.focus();
5291
- return true;
5292
- }
5293
- }
5294
- ])
5295
- ]
5296
- };
5297
6009
 
5298
6010
  // packages/ui/react-ui-editor/src/extensions/preview/preview.ts
5299
6011
  import "@dxos/lit-ui/dx-ref-tag.pcss";
5300
6012
  import { syntaxTree as syntaxTree10 } from "@codemirror/language";
5301
- import { RangeSetBuilder as RangeSetBuilder4, StateField as StateField11 } from "@codemirror/state";
5302
- import { Decoration as Decoration9, EditorView as EditorView20, WidgetType as WidgetType6 } from "@codemirror/view";
6013
+ import { RangeSetBuilder as RangeSetBuilder6, StateField as StateField10 } from "@codemirror/state";
6014
+ import { Decoration as Decoration10, EditorView as EditorView21, WidgetType as WidgetType6 } from "@codemirror/view";
5303
6015
  var preview = (options = {}) => {
5304
6016
  return [
5305
6017
  // NOTE: Atomic block decorations must be created from a state field, now a widget, otherwise it results in the following error:
5306
6018
  // "Block decorations may not be specified via plugins"
5307
- StateField11.define({
5308
- create: (state) => buildDecorations4(state, options),
5309
- update: (_, tr) => buildDecorations4(tr.state, options),
6019
+ StateField10.define({
6020
+ create: (state) => buildDecorations3(state, options),
6021
+ update: (_, tr) => buildDecorations3(tr.state, options),
5310
6022
  provide: (field) => [
5311
- EditorView20.decorations.from(field),
5312
- EditorView20.atomicRanges.of((view) => view.state.field(field))
6023
+ EditorView21.decorations.from(field),
6024
+ EditorView21.atomicRanges.of((view) => view.state.field(field))
5313
6025
  ]
5314
6026
  }),
5315
- EditorView20.theme({
6027
+ EditorView21.theme({
5316
6028
  ".cm-preview-block": {
5317
6029
  marginLeft: "-1rem",
5318
6030
  marginRight: "-1rem",
@@ -5337,8 +6049,8 @@ var getLinkRef = (state, node) => {
5337
6049
  };
5338
6050
  }
5339
6051
  };
5340
- var buildDecorations4 = (state, options) => {
5341
- const builder = new RangeSetBuilder4();
6052
+ var buildDecorations3 = (state, options) => {
6053
+ const builder = new RangeSetBuilder6();
5342
6054
  syntaxTree10(state).iterate({
5343
6055
  enter: (node) => {
5344
6056
  switch (node.name) {
@@ -5349,7 +6061,7 @@ var buildDecorations4 = (state, options) => {
5349
6061
  case "Link": {
5350
6062
  const link = getLinkRef(state, node.node);
5351
6063
  if (link) {
5352
- builder.add(node.from, node.to, Decoration9.replace({
6064
+ builder.add(node.from, node.to, Decoration10.replace({
5353
6065
  widget: new PreviewInlineWidget(options, link)
5354
6066
  }));
5355
6067
  }
@@ -5362,7 +6074,7 @@ var buildDecorations4 = (state, options) => {
5362
6074
  case "Image": {
5363
6075
  const link = getLinkRef(state, node.node);
5364
6076
  if (options.renderBlock && link) {
5365
- builder.add(node.from, node.to, Decoration9.replace({
6077
+ builder.add(node.from, node.to, Decoration10.replace({
5366
6078
  block: true,
5367
6079
  // atomic: true,
5368
6080
  widget: new PreviewBlockWidget(options, link)
@@ -5377,9 +6089,7 @@ var buildDecorations4 = (state, options) => {
5377
6089
  };
5378
6090
  var PreviewInlineWidget = class extends WidgetType6 {
5379
6091
  constructor(_options, _link) {
5380
- super();
5381
- this._options = _options;
5382
- this._link = _link;
6092
+ super(), this._options = _options, this._link = _link;
5383
6093
  }
5384
6094
  // override ignoreEvent() {
5385
6095
  // return false;
@@ -5390,15 +6100,13 @@ var PreviewInlineWidget = class extends WidgetType6 {
5390
6100
  toDOM(view) {
5391
6101
  const root = document.createElement("dx-ref-tag");
5392
6102
  root.textContent = this._link.label;
5393
- root.setAttribute("ref", this._link.ref);
6103
+ root.setAttribute("refId", this._link.ref);
5394
6104
  return root;
5395
6105
  }
5396
6106
  };
5397
6107
  var PreviewBlockWidget = class extends WidgetType6 {
5398
6108
  constructor(_options, _link) {
5399
- super();
5400
- this._options = _options;
5401
- this._link = _link;
6109
+ super(), this._options = _options, this._link = _link;
5402
6110
  }
5403
6111
  // override ignoreEvent() {
5404
6112
  // return true;
@@ -5455,7 +6163,7 @@ var PreviewBlockWidget = class extends WidgetType6 {
5455
6163
  };
5456
6164
 
5457
6165
  // packages/ui/react-ui-editor/src/extensions/typewriter.ts
5458
- import { keymap as keymap10 } from "@codemirror/view";
6166
+ import { keymap as keymap12 } from "@codemirror/view";
5459
6167
  var defaultItems = [
5460
6168
  "hello world!",
5461
6169
  "this is a test.",
@@ -5465,7 +6173,7 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
5465
6173
  let t;
5466
6174
  let idx = 0;
5467
6175
  return [
5468
- keymap10.of([
6176
+ keymap12.of([
5469
6177
  {
5470
6178
  // Reset.
5471
6179
  key: "alt-meta-'",
@@ -5569,30 +6277,6 @@ var createBlocks = (state, getView) => {
5569
6277
  };
5570
6278
  };
5571
6279
 
5572
- // packages/ui/react-ui-editor/src/components/EditorToolbar/comment.ts
5573
- var commentLabel = (comment, selection) => comment ? "selection overlaps existing comment label" : selection === false ? "select text to comment label" : "comment label";
5574
- var createCommentAction = (label, getView) => createEditorAction("comment", () => createComment(getView()), {
5575
- testId: "editor.toolbar.comment",
5576
- icon: "ph--chat-text--regular",
5577
- label
5578
- });
5579
- var createComment2 = (state, getView) => ({
5580
- nodes: [
5581
- createCommentAction([
5582
- commentLabel(state.comment, state.selection),
5583
- {
5584
- ns: translationKey
5585
- }
5586
- ], getView)
5587
- ],
5588
- edges: [
5589
- {
5590
- source: "root",
5591
- target: "comment"
5592
- }
5593
- ]
5594
- });
5595
-
5596
6280
  // packages/ui/react-ui-editor/src/components/EditorToolbar/formatting.ts
5597
6281
  var formats = {
5598
6282
  strong: "ph--text-b--regular",
@@ -5833,125 +6517,287 @@ var createViewMode = (state, onViewModeChange) => {
5833
6517
  };
5834
6518
 
5835
6519
  // packages/ui/react-ui-editor/src/defaults.ts
5836
- import { EditorView as EditorView21 } from "@codemirror/view";
6520
+ import { EditorView as EditorView22 } from "@codemirror/view";
5837
6521
  import { mx as mx4 } from "@dxos/react-ui-theme";
5838
- var margin = "!mt-[1rem]";
5839
6522
  var editorWidth = "!mli-auto is-full max-is-[min(50rem,100%-4rem)]";
5840
- var editorContent = mx4(margin, editorWidth);
5841
- var editorFullWidth = mx4(margin);
5842
- var editorGutter = EditorView21.theme({
5843
- // Match margin from content.
5844
- // Gutter = 2rem + 1rem margin.
6523
+ var editorSlots = {
6524
+ scroll: {
6525
+ className: "pbs-2"
6526
+ },
6527
+ content: {
6528
+ className: editorWidth
6529
+ }
6530
+ };
6531
+ var editorGutter = EditorView22.theme({
5845
6532
  ".cm-gutters": {
5846
- marginTop: "1rem",
5847
6533
  paddingRight: "1rem"
5848
6534
  }
5849
6535
  });
5850
- var editorMonospace = EditorView21.theme({
6536
+ var editorMonospace = EditorView22.theme({
5851
6537
  ".cm-content": {
5852
6538
  fontFamily: fontMono
5853
6539
  }
5854
6540
  });
5855
6541
  var editorWithToolbarLayout = "grid grid-cols-1 grid-rows-[min-content_1fr] data-[toolbar=disabled]:grid-rows-[1fr] justify-center content-start overflow-hidden";
5856
6542
  var stackItemContentEditorClassNames = (role) => mx4("attention-surface dx-focus-ring-inset data-[toolbar=disabled]:pbs-2", role === "section" ? "[&_.cm-scroller]:overflow-hidden [&_.cm-scroller]:min-bs-24" : "min-bs-0");
5857
- var stackItemContentToolbarClassNames = (role) => mx4("relative z-[1] flex is-full bg-toolbarSurface border-be border-separator", role === "section" && "sticky block-start-0 -mbe-px min-is-0");
6543
+ var stackItemContentToolbarClassNames = (role) => mx4("relative z-[1] flex is-full bg-toolbarSurface border-be border-subduedSeparator", role === "section" && "sticky block-start-0 -mbe-px min-is-0");
5858
6544
 
5859
6545
  // packages/ui/react-ui-editor/src/components/EditorToolbar/EditorToolbar.tsx
5860
6546
  var createToolbar = ({ getView, state, customActions, ...features }) => {
5861
- const nodes = [];
5862
- const edges = [];
5863
- if (features.headings ?? true) {
5864
- const headings2 = createHeadings(state, getView);
5865
- nodes.push(...headings2.nodes);
5866
- edges.push(...headings2.edges);
5867
- }
5868
- if (features.formatting ?? true) {
5869
- const formatting = createFormatting(state, getView);
5870
- nodes.push(...formatting.nodes);
5871
- edges.push(...formatting.edges);
5872
- }
5873
- if (features.lists ?? true) {
5874
- const lists = createLists(state, getView);
5875
- nodes.push(...lists.nodes);
5876
- edges.push(...lists.edges);
5877
- }
5878
- if (features.blocks ?? true) {
5879
- const blocks = createBlocks(state, getView);
5880
- nodes.push(...blocks.nodes);
5881
- edges.push(...blocks.edges);
5882
- }
5883
- if (features.image) {
5884
- const image2 = createImageUpload(features.image);
5885
- nodes.push(...image2.nodes);
5886
- edges.push(...image2.edges);
5887
- }
5888
- if (customActions) {
5889
- const custom = customActions();
5890
- nodes.push(...custom.nodes);
5891
- edges.push(...custom.edges);
5892
- }
5893
- const editorToolbarGap = createGapSeparator();
5894
- nodes.push(...editorToolbarGap.nodes);
5895
- edges.push(...editorToolbarGap.edges);
5896
- if (features.comment) {
5897
- const comment = createComment2(state, getView);
5898
- nodes.push(...comment.nodes);
5899
- edges.push(...comment.edges);
5900
- }
5901
- if (features.search ?? true) {
5902
- const search = createSearch(getView);
5903
- nodes.push(...search.nodes);
5904
- edges.push(...search.edges);
5905
- }
5906
- if (features.viewMode) {
5907
- const viewMode = createViewMode(state, features.viewMode);
5908
- nodes.push(...viewMode.nodes);
5909
- edges.push(...viewMode.edges);
5910
- }
5911
- return {
5912
- nodes,
5913
- edges
5914
- };
6547
+ return Rx.make((get2) => {
6548
+ const nodes = [];
6549
+ const edges = [];
6550
+ if (features.headings ?? true) {
6551
+ const headings2 = get2(rxFromSignal(() => createHeadings(state, getView)));
6552
+ nodes.push(...headings2.nodes);
6553
+ edges.push(...headings2.edges);
6554
+ }
6555
+ if (features.formatting ?? true) {
6556
+ const formatting = get2(rxFromSignal(() => createFormatting(state, getView)));
6557
+ nodes.push(...formatting.nodes);
6558
+ edges.push(...formatting.edges);
6559
+ }
6560
+ if (features.lists ?? true) {
6561
+ const lists = get2(rxFromSignal(() => createLists(state, getView)));
6562
+ nodes.push(...lists.nodes);
6563
+ edges.push(...lists.edges);
6564
+ }
6565
+ if (features.blocks ?? true) {
6566
+ const blocks = get2(rxFromSignal(() => createBlocks(state, getView)));
6567
+ nodes.push(...blocks.nodes);
6568
+ edges.push(...blocks.edges);
6569
+ }
6570
+ if (features.image) {
6571
+ const image2 = get2(rxFromSignal(() => createImageUpload(features.image)));
6572
+ nodes.push(...image2.nodes);
6573
+ edges.push(...image2.edges);
6574
+ }
6575
+ const editorToolbarGap = createGapSeparator();
6576
+ nodes.push(...editorToolbarGap.nodes);
6577
+ edges.push(...editorToolbarGap.edges);
6578
+ if (customActions) {
6579
+ const custom = get2(customActions);
6580
+ nodes.push(...custom.nodes);
6581
+ edges.push(...custom.edges);
6582
+ }
6583
+ if (features.search ?? true) {
6584
+ const search = get2(rxFromSignal(() => createSearch(getView)));
6585
+ nodes.push(...search.nodes);
6586
+ edges.push(...search.edges);
6587
+ }
6588
+ if (features.viewMode) {
6589
+ const viewMode = get2(rxFromSignal(() => createViewMode(state, features.viewMode)));
6590
+ nodes.push(...viewMode.nodes);
6591
+ edges.push(...viewMode.edges);
6592
+ }
6593
+ return {
6594
+ nodes,
6595
+ edges
6596
+ };
6597
+ });
5915
6598
  };
5916
6599
  var useEditorToolbarActionGraph = (props) => {
5917
- const menuCreator = useCallback(() => createToolbar(props), [
5918
- props
6600
+ const menuCreator = useMemo3(() => createToolbar({
6601
+ getView: props.getView,
6602
+ state: props.state,
6603
+ customActions: props.customActions,
6604
+ headings: props.headings,
6605
+ formatting: props.formatting,
6606
+ lists: props.lists,
6607
+ blocks: props.blocks,
6608
+ image: props.image,
6609
+ search: props.search,
6610
+ viewMode: props.viewMode
6611
+ }), [
6612
+ props.getView,
6613
+ props.state,
6614
+ props.customActions,
6615
+ props.headings,
6616
+ props.formatting,
6617
+ props.lists,
6618
+ props.blocks,
6619
+ props.image,
6620
+ props.search,
6621
+ props.viewMode
5919
6622
  ]);
5920
6623
  return useMenuActions(menuCreator);
5921
6624
  };
5922
6625
  var EditorToolbar = /* @__PURE__ */ memo(({ classNames, attendableId, role, ...props }) => {
5923
- const menuProps = useEditorToolbarActionGraph(props);
5924
- return /* @__PURE__ */ React3.createElement("div", {
5925
- role: "none",
5926
- className: stackItemContentToolbarClassNames(role)
5927
- }, /* @__PURE__ */ React3.createElement(ElevationProvider, {
5928
- elevation: role === "section" ? "positioned" : "base"
5929
- }, /* @__PURE__ */ React3.createElement(MenuProvider, {
5930
- ...menuProps,
5931
- attendableId
5932
- }, /* @__PURE__ */ React3.createElement(ToolbarMenu, {
5933
- classNames: [
5934
- textBlockWidth,
5935
- classNames
5936
- ]
5937
- }))));
6626
+ var _effect = _useSignals();
6627
+ try {
6628
+ const menuProps = useEditorToolbarActionGraph(props);
6629
+ return /* @__PURE__ */ React3.createElement("div", {
6630
+ role: "none",
6631
+ className: stackItemContentToolbarClassNames(role)
6632
+ }, /* @__PURE__ */ React3.createElement(ElevationProvider, {
6633
+ elevation: role === "section" ? "positioned" : "base"
6634
+ }, /* @__PURE__ */ React3.createElement(MenuProvider, {
6635
+ ...menuProps,
6636
+ attendableId
6637
+ }, /* @__PURE__ */ React3.createElement(ToolbarMenu, {
6638
+ classNames: [
6639
+ textBlockWidth,
6640
+ classNames
6641
+ ]
6642
+ }))));
6643
+ } finally {
6644
+ _effect.f();
6645
+ }
5938
6646
  });
5939
6647
 
6648
+ // packages/ui/react-ui-editor/src/components/Popover/RefPopover.tsx
6649
+ import { useSignals as _useSignals2 } from "@preact-signals/safe-react/tracking";
6650
+ import { createContext } from "@radix-ui/react-context";
6651
+ import React4, { useRef, useState, useEffect as useEffect2, useCallback } from "react";
6652
+ import { addEventListener } from "@dxos/async";
6653
+ import { Popover } from "@dxos/react-ui";
6654
+ var customEventOptions = {
6655
+ capture: true,
6656
+ passive: false
6657
+ };
6658
+ var REF_POPOVER = "RefPopover";
6659
+ var [RefPopoverContextProvider, useRefPopover] = createContext(REF_POPOVER, {});
6660
+ var RefPopoverProvider = ({ children, onLookup }) => {
6661
+ var _effect = _useSignals2();
6662
+ try {
6663
+ const trigger = useRef(null);
6664
+ const [value, setValue] = useState({});
6665
+ const [rootRef, setRootRef] = useState(null);
6666
+ const [open, setOpen] = useState(false);
6667
+ const handleDxRefTagActivate = useCallback((event) => {
6668
+ const { refId, label, trigger: dxTrigger } = event;
6669
+ setValue((value2) => ({
6670
+ ...value2,
6671
+ link: {
6672
+ label,
6673
+ ref: refId
6674
+ },
6675
+ pending: true
6676
+ }));
6677
+ trigger.current = dxTrigger;
6678
+ queueMicrotask(() => setOpen(true));
6679
+ void onLookup?.({
6680
+ label,
6681
+ ref: refId
6682
+ }).then((target) => setValue((value2) => ({
6683
+ ...value2,
6684
+ target: target ?? void 0,
6685
+ pending: false
6686
+ })));
6687
+ }, [
6688
+ onLookup
6689
+ ]);
6690
+ useEffect2(() => {
6691
+ return rootRef ? addEventListener(rootRef, "dx-ref-tag-activate", handleDxRefTagActivate, customEventOptions) : void 0;
6692
+ }, [
6693
+ rootRef
6694
+ ]);
6695
+ return /* @__PURE__ */ React4.createElement(RefPopoverContextProvider, {
6696
+ pending: value.pending,
6697
+ link: value.link,
6698
+ target: value.target
6699
+ }, /* @__PURE__ */ React4.createElement(Popover.Root, {
6700
+ open,
6701
+ onOpenChange: setOpen
6702
+ }, /* @__PURE__ */ React4.createElement(Popover.VirtualTrigger, {
6703
+ virtualRef: trigger
6704
+ }), /* @__PURE__ */ React4.createElement("div", {
6705
+ role: "none",
6706
+ className: "contents",
6707
+ ref: setRootRef
6708
+ }, children)));
6709
+ } finally {
6710
+ _effect.f();
6711
+ }
6712
+ };
6713
+ var RefPopover = {
6714
+ Provider: RefPopoverProvider
6715
+ };
6716
+
6717
+ // packages/ui/react-ui-editor/src/components/Popover/RefDropdownMenu.tsx
6718
+ import { useSignals as _useSignals3 } from "@preact-signals/safe-react/tracking";
6719
+ import { createContext as createContext2 } from "@radix-ui/react-context";
6720
+ import React5, { useRef as useRef2, useState as useState2, useEffect as useEffect3, useCallback as useCallback2 } from "react";
6721
+ import { addEventListener as addEventListener2 } from "@dxos/async";
6722
+ import { DropdownMenu } from "@dxos/react-ui";
6723
+ var customEventOptions2 = {
6724
+ capture: true,
6725
+ passive: false
6726
+ };
6727
+ var REF_DROPDOWN_MENU = "RefDropdownMenu";
6728
+ var [RefDropdownMenuContextProvider, useRefDropdownMenu] = createContext2(REF_DROPDOWN_MENU, {});
6729
+ var RefDropdownMenuProvider = ({ children, onLookup }) => {
6730
+ var _effect = _useSignals3();
6731
+ try {
6732
+ const trigger = useRef2(null);
6733
+ const [value, setValue] = useState2({});
6734
+ const [rootRef, setRootRef] = useState2(null);
6735
+ const [open, setOpen] = useState2(false);
6736
+ const handleDxRefTagActivate = useCallback2((event) => {
6737
+ const { refId, label, trigger: dxTrigger } = event;
6738
+ setValue((value2) => ({
6739
+ ...value2,
6740
+ link: {
6741
+ label,
6742
+ ref: refId
6743
+ },
6744
+ pending: true
6745
+ }));
6746
+ trigger.current = dxTrigger;
6747
+ queueMicrotask(() => setOpen(true));
6748
+ void onLookup?.({
6749
+ label,
6750
+ ref: refId
6751
+ }).then((target) => setValue((value2) => ({
6752
+ ...value2,
6753
+ target: target ?? void 0,
6754
+ pending: false
6755
+ })));
6756
+ }, [
6757
+ onLookup
6758
+ ]);
6759
+ useEffect3(() => {
6760
+ return rootRef ? addEventListener2(rootRef, "dx-ref-tag-activate", handleDxRefTagActivate, customEventOptions2) : void 0;
6761
+ }, [
6762
+ rootRef
6763
+ ]);
6764
+ return /* @__PURE__ */ React5.createElement(RefDropdownMenuContextProvider, {
6765
+ pending: value.pending,
6766
+ link: value.link,
6767
+ target: value.target
6768
+ }, /* @__PURE__ */ React5.createElement(DropdownMenu.Root, {
6769
+ open,
6770
+ onOpenChange: setOpen
6771
+ }, /* @__PURE__ */ React5.createElement(DropdownMenu.VirtualTrigger, {
6772
+ virtualRef: trigger
6773
+ }), /* @__PURE__ */ React5.createElement("div", {
6774
+ role: "none",
6775
+ className: "contents",
6776
+ ref: setRootRef
6777
+ }, children)));
6778
+ } finally {
6779
+ _effect.f();
6780
+ }
6781
+ };
6782
+ var RefDropdownMenu = {
6783
+ Provider: RefDropdownMenuProvider
6784
+ };
6785
+
5940
6786
  // packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
5941
6787
  import { EditorState as EditorState3 } from "@codemirror/state";
5942
- import { EditorView as EditorView22 } from "@codemirror/view";
6788
+ import { EditorView as EditorView23 } from "@codemirror/view";
5943
6789
  import { useFocusableGroup } from "@fluentui/react-tabster";
5944
- import { useCallback as useCallback2, useEffect as useEffect2, useMemo as useMemo4, useRef, useState } from "react";
6790
+ import { useCallback as useCallback3, useEffect as useEffect4, useMemo as useMemo4, useRef as useRef3, useState as useState3 } from "react";
5945
6791
  import { log as log8 } from "@dxos/log";
5946
6792
  import { getProviderValue, isNotFalsy as isNotFalsy4 } from "@dxos/util";
5947
- var __dxlog_file12 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
6793
+ var __dxlog_file13 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
5948
6794
  var instanceCount = 0;
5949
6795
  var useTextEditor = (props = {}, deps = []) => {
5950
6796
  const { id, doc, initialValue, extensions, autoFocus, scrollTo, selection, moveToEndOfLine, debug } = useMemo4(() => getProviderValue(props), deps ?? []);
5951
- const [instanceId] = useState(() => `text-editor-${++instanceCount}`);
5952
- const [view, setView] = useState();
5953
- const parentRef = useRef(null);
5954
- useEffect2(() => {
6797
+ const [instanceId] = useState3(() => `text-editor-${++instanceCount}`);
6798
+ const [view, setView] = useState3();
6799
+ const parentRef = useRef3(null);
6800
+ useEffect4(() => {
5955
6801
  let view2;
5956
6802
  if (parentRef.current) {
5957
6803
  log8("create", {
@@ -5959,7 +6805,7 @@ var useTextEditor = (props = {}, deps = []) => {
5959
6805
  instanceId,
5960
6806
  doc: initialValue?.length ?? 0
5961
6807
  }, {
5962
- F: __dxlog_file12,
6808
+ F: __dxlog_file13,
5963
6809
  L: 76,
5964
6810
  S: void 0,
5965
6811
  C: (f, a) => f(...a)
@@ -5983,9 +6829,9 @@ var useTextEditor = (props = {}, deps = []) => {
5983
6829
  id && documentId.of(id),
5984
6830
  extensions,
5985
6831
  // NOTE: This doesn't catch errors in keymap functions.
5986
- EditorView22.exceptionSink.of((err) => {
6832
+ EditorView23.exceptionSink.of((err) => {
5987
6833
  log8.catch(err, void 0, {
5988
- F: __dxlog_file12,
6834
+ F: __dxlog_file13,
5989
6835
  L: 98,
5990
6836
  S: void 0,
5991
6837
  C: (f, a) => f(...a)
@@ -5993,10 +6839,10 @@ var useTextEditor = (props = {}, deps = []) => {
5993
6839
  })
5994
6840
  ].filter(isNotFalsy4)
5995
6841
  });
5996
- view2 = new EditorView22({
6842
+ view2 = new EditorView23({
5997
6843
  parent: parentRef.current,
5998
6844
  state,
5999
- scrollTo: scrollTo ? EditorView22.scrollIntoView(scrollTo, {
6845
+ scrollTo: scrollTo ? EditorView23.scrollIntoView(scrollTo, {
6000
6846
  yMargin: 96
6001
6847
  }) : void 0,
6002
6848
  dispatchTransactions: debug ? debugDispatcher : void 0
@@ -6017,7 +6863,7 @@ var useTextEditor = (props = {}, deps = []) => {
6017
6863
  log8("destroy", {
6018
6864
  id
6019
6865
  }, {
6020
- F: __dxlog_file12,
6866
+ F: __dxlog_file13,
6021
6867
  L: 135,
6022
6868
  S: void 0,
6023
6869
  C: (f, a) => f(...a)
@@ -6025,7 +6871,7 @@ var useTextEditor = (props = {}, deps = []) => {
6025
6871
  view2?.destroy();
6026
6872
  };
6027
6873
  }, deps);
6028
- useEffect2(() => {
6874
+ useEffect4(() => {
6029
6875
  if (view) {
6030
6876
  if (scrollTo || selection) {
6031
6877
  if (selection && selection.anchor > view.state.doc.length) {
@@ -6034,7 +6880,7 @@ var useTextEditor = (props = {}, deps = []) => {
6034
6880
  scrollTo,
6035
6881
  selection
6036
6882
  }, {
6037
- F: __dxlog_file12,
6883
+ F: __dxlog_file13,
6038
6884
  L: 144,
6039
6885
  S: void 0,
6040
6886
  C: (f, a) => f(...a)
@@ -6052,7 +6898,7 @@ var useTextEditor = (props = {}, deps = []) => {
6052
6898
  scrollTo,
6053
6899
  selection
6054
6900
  ]);
6055
- useEffect2(() => {
6901
+ useEffect4(() => {
6056
6902
  if (view && autoFocus) {
6057
6903
  view.focus();
6058
6904
  }
@@ -6066,7 +6912,7 @@ var useTextEditor = (props = {}, deps = []) => {
6066
6912
  Escape: view?.state.facet(editorInputMode).noTabster
6067
6913
  }
6068
6914
  });
6069
- const handleKeyUp = useCallback2((event) => {
6915
+ const handleKeyUp = useCallback3((event) => {
6070
6916
  const { key, target, currentTarget } = event;
6071
6917
  if (target === currentTarget) {
6072
6918
  switch (key) {
@@ -6095,15 +6941,18 @@ export {
6095
6941
  EditorInputModes,
6096
6942
  EditorState4 as EditorState,
6097
6943
  EditorToolbar,
6098
- EditorView23 as EditorView,
6944
+ EditorView24 as EditorView,
6099
6945
  EditorViewMode,
6100
6946
  EditorViewModes,
6101
6947
  Inline,
6102
6948
  InputModeExtensions,
6103
6949
  List,
6950
+ RefDropdownMenu,
6951
+ RefPopover,
6104
6952
  RemoteSelectionsDecorator,
6105
6953
  SpaceAwarenessProvider,
6106
6954
  TextKind,
6955
+ Tree,
6107
6956
  addBlockquote,
6108
6957
  addCodeblock,
6109
6958
  addLink,
@@ -6121,6 +6970,8 @@ export {
6121
6970
  closeEffect,
6122
6971
  command,
6123
6972
  commandKeyBindings,
6973
+ commands,
6974
+ commentClickedEffect,
6124
6975
  comments,
6125
6976
  commentsState,
6126
6977
  convertTreeToJson,
@@ -6133,6 +6984,7 @@ export {
6133
6984
  createEditorStateTransaction,
6134
6985
  createElement,
6135
6986
  createExternalCommentSync,
6987
+ createJsonExtensions,
6136
6988
  createMarkdownExtensions,
6137
6989
  createRenderer,
6138
6990
  createThemeExtensions,
@@ -6141,35 +6993,46 @@ export {
6141
6993
  debugTree,
6142
6994
  decorateMarkdown,
6143
6995
  defaultOptions,
6996
+ deleteItem,
6144
6997
  documentId,
6145
6998
  dropFile,
6146
- editorContent,
6147
- editorFullWidth,
6148
6999
  editorGutter,
6149
7000
  editorInputMode,
6150
7001
  editorMonospace,
7002
+ editorSlots,
6151
7003
  editorWidth,
6152
7004
  editorWithToolbarLayout,
6153
7005
  flattenRect,
7006
+ floatingMenu,
6154
7007
  focus,
6155
7008
  focusField,
6156
7009
  folding,
6157
7010
  formattingEquals,
6158
7011
  formattingKeymap,
6159
7012
  getFormatting,
7013
+ getListItemContent,
7014
+ getRange,
6160
7015
  image,
7016
+ indentItemLess,
7017
+ indentItemMore,
6161
7018
  insertTable,
6162
- keymap11 as keymap,
7019
+ itemToJSON,
7020
+ keymap13 as keymap,
6163
7021
  linkTooltip,
7022
+ listItemToString,
6164
7023
  listener,
6165
7024
  logChanges,
6166
7025
  markdownHighlightStyle,
6167
7026
  markdownTags,
6168
7027
  markdownTagsExtensions,
7028
+ matchCompletion,
6169
7029
  mention,
7030
+ moveItemDown,
7031
+ moveItemUp,
6170
7032
  openCommand,
6171
7033
  openEffect,
6172
7034
  outliner,
7035
+ outlinerTree,
6173
7036
  overlap,
6174
7037
  preventNewline,
6175
7038
  preview,
@@ -6181,7 +7044,6 @@ export {
6181
7044
  removeStyle,
6182
7045
  renderRoot,
6183
7046
  scrollThreadIntoView,
6184
- selectionOverlapsComment,
6185
7047
  selectionState,
6186
7048
  setBlockquote,
6187
7049
  setComments,
@@ -6191,6 +7053,7 @@ export {
6191
7053
  singleValueFacet,
6192
7054
  stackItemContentEditorClassNames,
6193
7055
  stackItemContentToolbarClassNames,
7056
+ staticCompletion,
6194
7057
  table,
6195
7058
  tags2 as tags,
6196
7059
  textRange,
@@ -6202,13 +7065,17 @@ export {
6202
7065
  toggleStrikethrough,
6203
7066
  toggleStrong,
6204
7067
  toggleStyle,
7068
+ toggleTask,
6205
7069
  translations_default as translations,
7070
+ traverse,
7071
+ treeFacet,
7072
+ typeahead,
6206
7073
  typewriter,
6207
- useCommentClickListener,
6208
- useCommentState,
6209
7074
  useComments,
6210
7075
  useEditorToolbarState,
6211
7076
  useFormattingState,
7077
+ useRefDropdownMenu,
7078
+ useRefPopover,
6212
7079
  useTextEditor,
6213
7080
  wrapWithCatch
6214
7081
  };