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