@dxos/react-ui-editor 0.8.2-main.f081794 → 0.8.2-main.fbd8ed0

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 (131) hide show
  1. package/dist/lib/browser/index.mjs +1664 -1359
  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.map +2 -2
  5. package/dist/lib/node/index.cjs +2122 -1819
  6. package/dist/lib/node/index.cjs.map +4 -4
  7. package/dist/lib/node/meta.json +1 -1
  8. package/dist/lib/node/testing/index.cjs.map +2 -2
  9. package/dist/lib/node-esm/index.mjs +1664 -1359
  10. package/dist/lib/node-esm/index.mjs.map +4 -4
  11. package/dist/lib/node-esm/meta.json +1 -1
  12. package/dist/lib/node-esm/testing/index.mjs.map +2 -2
  13. package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts +1 -1
  14. package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts.map +1 -1
  15. package/dist/types/src/{stories/InputMode.stories.d.ts → components/EditorToolbar/EditorToolbar.stories.d.ts} +3 -7
  16. package/dist/types/src/components/EditorToolbar/EditorToolbar.stories.d.ts.map +1 -0
  17. package/dist/types/src/components/EditorToolbar/blocks.d.ts +4 -3
  18. package/dist/types/src/components/EditorToolbar/blocks.d.ts.map +1 -1
  19. package/dist/types/src/components/EditorToolbar/comment.d.ts +4 -3
  20. package/dist/types/src/components/EditorToolbar/comment.d.ts.map +1 -1
  21. package/dist/types/src/components/EditorToolbar/formatting.d.ts +4 -3
  22. package/dist/types/src/components/EditorToolbar/formatting.d.ts.map +1 -1
  23. package/dist/types/src/components/EditorToolbar/headings.d.ts +4 -3
  24. package/dist/types/src/components/EditorToolbar/headings.d.ts.map +1 -1
  25. package/dist/types/src/components/EditorToolbar/image.d.ts +16 -0
  26. package/dist/types/src/components/EditorToolbar/image.d.ts.map +1 -0
  27. package/dist/types/src/components/EditorToolbar/lists.d.ts +4 -3
  28. package/dist/types/src/components/EditorToolbar/lists.d.ts.map +1 -1
  29. package/dist/types/src/components/EditorToolbar/search.d.ts +17 -0
  30. package/dist/types/src/components/EditorToolbar/search.d.ts.map +1 -0
  31. package/dist/types/src/components/EditorToolbar/util.d.ts +11 -17
  32. package/dist/types/src/components/EditorToolbar/util.d.ts.map +1 -1
  33. package/dist/types/src/components/EditorToolbar/view-mode.d.ts +4 -3
  34. package/dist/types/src/components/EditorToolbar/view-mode.d.ts.map +1 -1
  35. package/dist/types/src/defaults.d.ts.map +1 -1
  36. package/dist/types/src/extensions/annotations.d.ts.map +1 -1
  37. package/dist/types/src/extensions/autocomplete.d.ts.map +1 -1
  38. package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
  39. package/dist/types/src/extensions/automerge/automerge.stories.d.ts.map +1 -1
  40. package/dist/types/src/extensions/automerge/cursor.d.ts.map +1 -1
  41. package/dist/types/src/extensions/automerge/defs.d.ts +1 -1
  42. package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
  43. package/dist/types/src/extensions/automerge/sync.d.ts.map +1 -1
  44. package/dist/types/src/extensions/automerge/update-automerge.d.ts +1 -1
  45. package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -1
  46. package/dist/types/src/extensions/automerge/update-codemirror.d.ts +1 -1
  47. package/dist/types/src/extensions/automerge/update-codemirror.d.ts.map +1 -1
  48. package/dist/types/src/extensions/awareness/awareness.d.ts.map +1 -1
  49. package/dist/types/src/extensions/blast.d.ts.map +1 -1
  50. package/dist/types/src/extensions/command/command.d.ts.map +1 -1
  51. package/dist/types/src/extensions/command/hint.d.ts.map +1 -1
  52. package/dist/types/src/extensions/command/menu.d.ts.map +1 -1
  53. package/dist/types/src/extensions/comments.d.ts.map +1 -1
  54. package/dist/types/src/extensions/debug.d.ts.map +1 -1
  55. package/dist/types/src/extensions/dnd.d.ts.map +1 -1
  56. package/dist/types/src/extensions/factories.d.ts.map +1 -1
  57. package/dist/types/src/extensions/folding.d.ts.map +1 -1
  58. package/dist/types/src/extensions/listener.d.ts.map +1 -1
  59. package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
  60. package/dist/types/src/extensions/markdown/changes.d.ts.map +1 -1
  61. package/dist/types/src/extensions/markdown/debug.d.ts.map +1 -1
  62. package/dist/types/src/extensions/markdown/decorate.d.ts +1 -0
  63. package/dist/types/src/extensions/markdown/decorate.d.ts.map +1 -1
  64. package/dist/types/src/extensions/markdown/formatting.d.ts +1 -1
  65. package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -1
  66. package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
  67. package/dist/types/src/extensions/markdown/image.d.ts.map +1 -1
  68. package/dist/types/src/extensions/markdown/index.d.ts +1 -0
  69. package/dist/types/src/extensions/markdown/index.d.ts.map +1 -1
  70. package/dist/types/src/extensions/markdown/link.d.ts.map +1 -1
  71. package/dist/types/src/extensions/markdown/outliner.d.ts +12 -0
  72. package/dist/types/src/extensions/markdown/outliner.d.ts.map +1 -0
  73. package/dist/types/src/extensions/markdown/table.d.ts.map +1 -1
  74. package/dist/types/src/extensions/mention.d.ts.map +1 -1
  75. package/dist/types/src/extensions/modes.d.ts +5 -5
  76. package/dist/types/src/extensions/modes.d.ts.map +1 -1
  77. package/dist/types/src/extensions/preview/preview.d.ts.map +1 -1
  78. package/dist/types/src/extensions/selection.d.ts.map +1 -1
  79. package/dist/types/src/extensions/typewriter.d.ts.map +1 -1
  80. package/dist/types/src/hooks/index.d.ts +0 -1
  81. package/dist/types/src/hooks/index.d.ts.map +1 -1
  82. package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
  83. package/dist/types/src/stories/TextEditorBasic.stories.d.ts +3 -0
  84. package/dist/types/src/stories/TextEditorBasic.stories.d.ts.map +1 -1
  85. package/dist/types/src/stories/story-utils.d.ts.map +1 -1
  86. package/dist/types/src/styles/theme.d.ts.map +1 -1
  87. package/dist/types/src/testing/RefPopover.d.ts.map +1 -1
  88. package/dist/types/src/util/cursor.d.ts.map +1 -1
  89. package/dist/types/src/util/debug.d.ts.map +1 -1
  90. package/dist/types/src/util/dom.d.ts.map +1 -1
  91. package/dist/types/src/util/facet.d.ts.map +1 -1
  92. package/dist/types/src/util/react.d.ts.map +1 -1
  93. package/dist/types/tsconfig.tsbuildinfo +1 -1
  94. package/package.json +32 -28
  95. package/src/components/EditorToolbar/EditorToolbar.stories.tsx +90 -0
  96. package/src/components/EditorToolbar/EditorToolbar.tsx +31 -32
  97. package/src/components/EditorToolbar/blocks.ts +27 -6
  98. package/src/components/EditorToolbar/comment.ts +11 -4
  99. package/src/components/EditorToolbar/formatting.ts +34 -7
  100. package/src/components/EditorToolbar/headings.ts +9 -8
  101. package/src/components/EditorToolbar/image.ts +16 -0
  102. package/src/components/EditorToolbar/lists.ts +26 -7
  103. package/src/components/EditorToolbar/search.ts +19 -0
  104. package/src/components/EditorToolbar/util.ts +14 -14
  105. package/src/components/EditorToolbar/view-mode.ts +9 -8
  106. package/src/defaults.ts +1 -1
  107. package/src/extensions/automerge/automerge.stories.tsx +9 -7
  108. package/src/extensions/automerge/automerge.test.tsx +4 -4
  109. package/src/extensions/automerge/automerge.ts +2 -2
  110. package/src/extensions/automerge/defs.ts +1 -2
  111. package/src/extensions/automerge/sync.ts +4 -4
  112. package/src/extensions/automerge/update-automerge.ts +1 -1
  113. package/src/extensions/automerge/update-codemirror.ts +3 -4
  114. package/src/extensions/markdown/changes.ts +3 -2
  115. package/src/extensions/markdown/decorate.ts +8 -7
  116. package/src/extensions/markdown/formatting.ts +4 -4
  117. package/src/extensions/markdown/index.ts +1 -0
  118. package/src/extensions/markdown/outliner.ts +235 -0
  119. package/src/extensions/markdown/styles.ts +2 -2
  120. package/src/extensions/modes.ts +5 -6
  121. package/src/extensions/preview/preview.ts +1 -1
  122. package/src/hooks/index.ts +0 -1
  123. package/src/stories/TextEditorBasic.stories.tsx +44 -0
  124. package/src/stories/story-utils.tsx +7 -9
  125. package/src/styles/theme.ts +3 -0
  126. package/src/testing/RefPopover.tsx +4 -4
  127. package/dist/types/src/hooks/useActionHandler.d.ts +0 -4
  128. package/dist/types/src/hooks/useActionHandler.d.ts.map +0 -1
  129. package/dist/types/src/stories/InputMode.stories.d.ts.map +0 -1
  130. package/src/hooks/useActionHandler.ts +0 -12
  131. package/src/stories/InputMode.stories.tsx +0 -124
@@ -63,7 +63,7 @@ __export(node_exports, {
63
63
  commentsState: () => commentsState,
64
64
  convertTreeToJson: () => convertTreeToJson,
65
65
  createBasicExtensions: () => createBasicExtensions,
66
- createComment: () => createComment2,
66
+ createComment: () => createComment,
67
67
  createDataExtensions: () => createDataExtensions,
68
68
  createEditorAction: () => createEditorAction,
69
69
  createEditorActionGroup: () => createEditorActionGroup,
@@ -107,6 +107,7 @@ __export(node_exports, {
107
107
  mention: () => mention,
108
108
  openCommand: () => openCommand,
109
109
  openEffect: () => openEffect,
110
+ outliner: () => outliner,
110
111
  overlap: () => overlap,
111
112
  preventNewline: () => preventNewline,
112
113
  preview: () => preview,
@@ -141,7 +142,6 @@ __export(node_exports, {
141
142
  toggleStyle: () => toggleStyle,
142
143
  translations: () => translations_default,
143
144
  typewriter: () => typewriter,
144
- useActionHandler: () => useActionHandler,
145
145
  useCommentClickListener: () => useCommentClickListener,
146
146
  useCommentState: () => useCommentState,
147
147
  useComments: () => useComments,
@@ -162,89 +162,87 @@ var import_react_ui_theme = require("@dxos/react-ui-theme");
162
162
  var import_react2 = require("react");
163
163
  var import_live_object = require("@dxos/live-object");
164
164
  var import_react_ui_menu2 = require("@dxos/react-ui-menu");
165
- var import_view2 = require("@codemirror/view");
166
- var import_react_ui_theme2 = require("@dxos/react-ui-theme");
167
- var import_react_ui_theme3 = require("@dxos/react-ui-theme");
168
- var import_lodash = __toESM(require("lodash.get"));
169
- var import_react_ui_theme4 = require("@dxos/react-ui-theme");
170
165
  var import_state2 = require("@codemirror/state");
171
- var import_view3 = require("@codemirror/view");
166
+ var import_view2 = require("@codemirror/view");
172
167
  var import_util = require("@dxos/util");
173
168
  var import_state3 = require("@codemirror/state");
174
169
  var import_log = require("@dxos/log");
175
170
  var import_react3 = __toESM(require("react"));
176
171
  var import_client = require("react-dom/client");
177
172
  var import_react_ui2 = require("@dxos/react-ui");
178
- var import_react_ui_theme5 = require("@dxos/react-ui-theme");
173
+ var import_react_ui_theme2 = require("@dxos/react-ui-theme");
179
174
  var import_autocomplete = require("@codemirror/autocomplete");
180
175
  var import_lang_markdown = require("@codemirror/lang-markdown");
181
- var import_view4 = require("@codemirror/view");
176
+ var import_view3 = require("@codemirror/view");
177
+ var import_automerge = require("@automerge/automerge");
182
178
  var import_state4 = require("@codemirror/state");
183
- var import_view5 = require("@codemirror/view");
184
- var import_automerge = require("@dxos/automerge/automerge");
179
+ var import_view4 = require("@codemirror/view");
185
180
  var import_log2 = require("@dxos/log");
186
181
  var import_echo = require("@dxos/react-client/echo");
187
182
  var import_state5 = require("@codemirror/state");
188
- var import_automerge2 = require("@dxos/automerge/automerge");
189
- var import_automerge3 = require("@dxos/automerge/automerge");
183
+ var import_automerge2 = require("@automerge/automerge");
184
+ var import_automerge3 = require("@automerge/automerge");
190
185
  var import_state6 = require("@codemirror/state");
191
186
  var import_state7 = require("@codemirror/state");
192
- var import_view6 = require("@codemirror/view");
187
+ var import_view5 = require("@codemirror/view");
193
188
  var import_async = require("@dxos/async");
194
189
  var import_context = require("@dxos/context");
195
190
  var import_async2 = require("@dxos/async");
196
191
  var import_context2 = require("@dxos/context");
197
192
  var import_invariant = require("@dxos/invariant");
198
193
  var import_log3 = require("@dxos/log");
199
- var import_view7 = require("@codemirror/view");
200
- var import_lodash2 = __toESM(require("lodash.defaultsdeep"));
194
+ var import_view6 = require("@codemirror/view");
195
+ var import_lodash = __toESM(require("lodash.defaultsdeep"));
201
196
  var import_invariant2 = require("@dxos/invariant");
202
197
  var import_state8 = require("@codemirror/state");
203
198
  var import_state9 = require("@codemirror/state");
199
+ var import_view7 = require("@codemirror/view");
204
200
  var import_view8 = require("@codemirror/view");
205
- var import_view9 = require("@codemirror/view");
206
201
  var import_state10 = require("@codemirror/state");
202
+ var import_view9 = require("@codemirror/view");
207
203
  var import_view10 = require("@codemirror/view");
208
- var import_view11 = require("@codemirror/view");
209
204
  var import_commands = require("@codemirror/commands");
210
205
  var import_state11 = require("@codemirror/state");
211
- var import_view12 = require("@codemirror/view");
212
- var import_lodash3 = __toESM(require("lodash.sortby"));
206
+ var import_view11 = require("@codemirror/view");
207
+ var import_lodash2 = __toESM(require("lodash.sortby"));
213
208
  var import_react4 = require("react");
214
209
  var import_async3 = require("@dxos/async");
215
210
  var import_log4 = require("@dxos/log");
216
211
  var import_util2 = require("@dxos/util");
217
212
  var import_state12 = require("@codemirror/state");
218
- var import_view13 = require("@codemirror/view");
213
+ var import_view12 = require("@codemirror/view");
219
214
  var import_async4 = require("@dxos/async");
220
215
  var import_invariant3 = require("@dxos/invariant");
221
216
  var import_util3 = require("@dxos/util");
222
217
  var import_language = require("@codemirror/language");
223
218
  var import_state13 = require("@codemirror/state");
224
- var import_view14 = require("@codemirror/view");
219
+ var import_view13 = require("@codemirror/view");
225
220
  var import_autocomplete2 = require("@codemirror/autocomplete");
226
221
  var import_commands2 = require("@codemirror/commands");
227
222
  var import_language2 = require("@codemirror/language");
228
223
  var import_search = require("@codemirror/search");
229
224
  var import_state14 = require("@codemirror/state");
230
225
  var import_theme_one_dark = require("@codemirror/theme-one-dark");
231
- var import_view15 = require("@codemirror/view");
232
- var import_lodash4 = __toESM(require("lodash.defaultsdeep"));
233
- var import_lodash5 = __toESM(require("lodash.merge"));
226
+ var import_view14 = require("@codemirror/view");
227
+ var import_lodash3 = __toESM(require("lodash.defaultsdeep"));
228
+ var import_lodash4 = __toESM(require("lodash.merge"));
234
229
  var import_display_name = require("@dxos/display-name");
235
230
  var import_log5 = require("@dxos/log");
236
231
  var import_util4 = require("@dxos/util");
237
232
  var import_state15 = require("@codemirror/state");
238
- var import_view16 = require("@codemirror/view");
233
+ var import_view15 = require("@codemirror/view");
234
+ var import_react_ui_theme3 = require("@dxos/react-ui-theme");
235
+ var import_lodash5 = __toESM(require("lodash.get"));
236
+ var import_react_ui_theme4 = require("@dxos/react-ui-theme");
239
237
  var import_language3 = require("@codemirror/language");
240
- var import_view17 = require("@codemirror/view");
238
+ var import_view16 = require("@codemirror/view");
241
239
  var import_react5 = __toESM(require("react"));
242
240
  var import_react_ui3 = require("@dxos/react-ui");
243
- var import_view18 = require("@codemirror/view");
241
+ var import_view17 = require("@codemirror/view");
244
242
  var import_autocomplete3 = require("@codemirror/autocomplete");
245
243
  var import_language4 = require("@codemirror/language");
246
244
  var import_state16 = require("@codemirror/state");
247
- var import_view19 = require("@codemirror/view");
245
+ var import_view18 = require("@codemirror/view");
248
246
  var import_react6 = require("react");
249
247
  var import_autocomplete4 = require("@codemirror/autocomplete");
250
248
  var import_commands3 = require("@codemirror/commands");
@@ -252,7 +250,7 @@ var import_lang_markdown2 = require("@codemirror/lang-markdown");
252
250
  var import_language5 = require("@codemirror/language");
253
251
  var import_language_data = require("@codemirror/language-data");
254
252
  var import_lint = require("@codemirror/lint");
255
- var import_view20 = require("@codemirror/view");
253
+ var import_view19 = require("@codemirror/view");
256
254
  var import_lang_markdown3 = require("@codemirror/lang-markdown");
257
255
  var import_language6 = require("@codemirror/language");
258
256
  var import_highlight2 = require("@lezer/highlight");
@@ -261,39 +259,46 @@ var import_language7 = require("@codemirror/language");
261
259
  var import_state17 = require("@codemirror/state");
262
260
  var import_language8 = require("@codemirror/language");
263
261
  var import_state18 = require("@codemirror/state");
264
- var import_view21 = require("@codemirror/view");
262
+ var import_view20 = require("@codemirror/view");
265
263
  var import_invariant4 = require("@dxos/invariant");
266
- var import_react_ui_theme6 = require("@dxos/react-ui-theme");
264
+ var import_react_ui_theme5 = require("@dxos/react-ui-theme");
267
265
  var import_language9 = require("@codemirror/language");
268
266
  var import_state19 = require("@codemirror/state");
269
- var import_view22 = require("@codemirror/view");
267
+ var import_view21 = require("@codemirror/view");
270
268
  var import_language10 = require("@codemirror/language");
271
269
  var import_state20 = require("@codemirror/state");
270
+ var import_view22 = require("@codemirror/view");
272
271
  var import_view23 = require("@codemirror/view");
273
- var import_view24 = require("@codemirror/view");
274
272
  var import_language11 = require("@codemirror/language");
275
273
  var import_state21 = require("@codemirror/state");
276
- var import_view25 = require("@codemirror/view");
274
+ var import_view24 = require("@codemirror/view");
277
275
  var import_language12 = require("@codemirror/language");
276
+ var import_view25 = require("@codemirror/view");
277
+ var import_react_ui_theme6 = require("@dxos/react-ui-theme");
278
+ var import_language13 = require("@codemirror/language");
279
+ var import_state22 = require("@codemirror/state");
278
280
  var import_view26 = require("@codemirror/view");
281
+ var import_log6 = require("@dxos/log");
279
282
  var import_react_ui_theme7 = require("@dxos/react-ui-theme");
280
283
  var import_autocomplete5 = require("@codemirror/autocomplete");
281
- var import_log6 = require("@dxos/log");
284
+ var import_log7 = require("@dxos/log");
282
285
  var import_view27 = require("@codemirror/view");
283
286
  var import_codemirror_vim = require("@replit/codemirror-vim");
284
287
  var import_codemirror_vscode_keymap = require("@replit/codemirror-vscode-keymap");
285
- var import_echo_schema = require("@dxos/echo-schema");
288
+ var import_effect = require("effect");
286
289
  var import_dx_ref_tag = require("@dxos/lit-ui/dx-ref-tag.pcss");
287
- var import_language13 = require("@codemirror/language");
288
- var import_state22 = require("@codemirror/state");
290
+ var import_language14 = require("@codemirror/language");
291
+ var import_state23 = require("@codemirror/state");
289
292
  var import_view28 = require("@codemirror/view");
290
293
  var import_view29 = require("@codemirror/view");
291
- var import_react7 = require("react");
292
- var import_state23 = require("@codemirror/state");
294
+ var import_search2 = require("@codemirror/search");
293
295
  var import_view30 = require("@codemirror/view");
296
+ var import_react_ui_theme8 = require("@dxos/react-ui-theme");
297
+ var import_state24 = require("@codemirror/state");
298
+ var import_view31 = require("@codemirror/view");
294
299
  var import_react_tabster = require("@fluentui/react-tabster");
295
- var import_react8 = require("react");
296
- var import_log7 = require("@dxos/log");
300
+ var import_react7 = require("react");
301
+ var import_log8 = require("@dxos/log");
297
302
  var import_util5 = require("@dxos/util");
298
303
  var translationKey = "react-ui-editor";
299
304
  var translations_default = [
@@ -331,824 +336,271 @@ var translations_default = [
331
336
  var useEditorToolbarState = (initialState = {}) => {
332
337
  return (0, import_react2.useMemo)(() => (0, import_live_object.live)(initialState), []);
333
338
  };
334
- var createEditorAction = (payload, icon, label = [
335
- `${payload.type} label`,
336
- {
337
- ns: translationKey
338
- }
339
- ], id = payload.type) => (0, import_react_ui_menu2.createMenuAction)(id, {
340
- icon,
341
- label,
342
- ...payload
343
- });
339
+ var createEditorAction = (id, invoke, properties) => {
340
+ const { label = [
341
+ `${id} label`,
342
+ {
343
+ ns: translationKey
344
+ }
345
+ ], ...rest } = properties;
346
+ return (0, import_react_ui_menu2.createMenuAction)(id, invoke, {
347
+ label,
348
+ ...rest
349
+ });
350
+ };
344
351
  var createEditorActionGroup = (id, props, icon) => (0, import_react_ui_menu2.createMenuItemGroup)(id, {
345
352
  icon,
346
353
  iconOnly: true,
347
354
  ...props
348
355
  });
349
- var editorToolbarSearch = createEditorAction({
350
- type: "search"
351
- }, "ph--magnifying-glass--regular");
352
- var createBlockGroupAction = (value) => createEditorActionGroup("block", {
353
- variant: "toggleGroup",
354
- selectCardinality: "single",
355
- value
356
+ var singleValueFacet = (defaultValue) => import_state3.Facet.define({
357
+ // Called immediately.
358
+ combine: (providers) => {
359
+ return providers[0] ?? defaultValue;
360
+ }
356
361
  });
357
- var createBlockActions = (value, blankLine) => Object.entries({
358
- blockquote: "ph--quotes--regular",
359
- codeblock: "ph--code-block--regular",
360
- table: "ph--table--regular"
361
- }).map(([type, icon]) => {
362
- return createEditorAction({
363
- type,
364
- checked: type === value,
365
- ...type === "table" && {
366
- disabled: !!blankLine
362
+ var overlap = (a, b) => a.from <= b.to && a.to >= b.from;
363
+ var defaultCursorConverter = {
364
+ toCursor: (position) => position.toString(),
365
+ fromCursor: (cursor) => parseInt(cursor)
366
+ };
367
+ var Cursor = class _Cursor {
368
+ static {
369
+ this.converter = singleValueFacet(defaultCursorConverter);
370
+ }
371
+ static {
372
+ this.getCursorFromRange = (state, range) => {
373
+ const cursorConverter2 = state.facet(_Cursor.converter);
374
+ const from = cursorConverter2.toCursor(range.from);
375
+ const to = cursorConverter2.toCursor(range.to, -1);
376
+ return [
377
+ from,
378
+ to
379
+ ].join(":");
380
+ };
381
+ }
382
+ static {
383
+ this.getRangeFromCursor = (state, cursor) => {
384
+ const cursorConverter2 = state.facet(_Cursor.converter);
385
+ const parts = cursor.split(":");
386
+ const from = cursorConverter2.fromCursor(parts[0]);
387
+ const to = cursorConverter2.fromCursor(parts[1]);
388
+ return from !== void 0 && to !== void 0 ? {
389
+ from,
390
+ to
391
+ } : void 0;
392
+ };
393
+ }
394
+ };
395
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util/debug.ts";
396
+ var wrapWithCatch = (fn) => {
397
+ return (...args) => {
398
+ try {
399
+ return fn(...args);
400
+ } catch (err) {
401
+ import_log.log.catch(err, void 0, {
402
+ F: __dxlog_file,
403
+ L: 15,
404
+ S: void 0,
405
+ C: (f, a) => f(...a)
406
+ });
367
407
  }
368
- }, icon);
369
- });
370
- var createBlocks = (state) => {
371
- const value = state?.blockQuote ? "blockquote" : state.blockType ?? "";
372
- const blockGroupAction = createBlockGroupAction(value);
373
- const blockActions = createBlockActions(value, state.blankLine);
374
- return {
375
- nodes: [
376
- blockGroupAction,
377
- ...blockActions
378
- ],
379
- edges: [
380
- {
381
- source: "root",
382
- target: "block"
383
- },
384
- ...blockActions.map(({ id }) => ({
385
- source: blockGroupAction.id,
386
- target: id
387
- }))
388
- ]
389
408
  };
390
409
  };
391
- var commentLabel = (comment, selection) => comment ? "selection overlaps existing comment label" : selection === false ? "select text to comment label" : "comment label";
392
- var createCommentAction = (label) => createEditorAction({
393
- type: "comment",
394
- testId: "editor.toolbar.comment"
395
- }, "ph--chat-text--regular", label);
396
- var createComment = (state) => ({
397
- nodes: [
398
- createCommentAction([
399
- commentLabel(state.comment, state.selection),
400
- {
401
- ns: translationKey
402
- }
403
- ])
404
- ],
405
- edges: [
406
- {
407
- source: "root",
408
- target: "comment"
410
+ var callbackWrapper = (fn) => (...args) => {
411
+ try {
412
+ return fn(...args);
413
+ } catch (err) {
414
+ import_log.log.catch(err, void 0, {
415
+ F: __dxlog_file,
416
+ L: 29,
417
+ S: void 0,
418
+ C: (f, a) => f(...a)
419
+ });
420
+ }
421
+ };
422
+ var debugDispatcher = (trs, view) => {
423
+ logChanges(trs);
424
+ view.update(trs);
425
+ };
426
+ var logChanges = (trs) => {
427
+ const changes = trs.flatMap((tr) => {
428
+ if (tr.changes.empty) {
429
+ return void 0;
409
430
  }
410
- ]
411
- });
412
- var formats = {
413
- strong: "ph--text-b--regular",
414
- emphasis: "ph--text-italic--regular",
415
- strikethrough: "ph--text-strikethrough--regular",
416
- code: "ph--code--regular",
417
- link: "ph--link--regular"
431
+ const changes2 = [];
432
+ tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => changes2.push(JSON.stringify({
433
+ fromA,
434
+ toA,
435
+ fromB,
436
+ toB,
437
+ inserted: inserted.toString()
438
+ })));
439
+ return changes2;
440
+ }).filter(Boolean);
441
+ if (changes.length) {
442
+ (0, import_log.log)("changes", {
443
+ changes
444
+ }, {
445
+ F: __dxlog_file,
446
+ L: 62,
447
+ S: void 0,
448
+ C: (f, a) => f(...a)
449
+ });
450
+ }
418
451
  };
419
- var createFormattingGroup = (formatting) => createEditorActionGroup("formatting", {
420
- variant: "toggleGroup",
421
- selectCardinality: "multiple",
422
- value: Object.keys(formats).filter((key) => !!formatting[key])
423
- });
424
- var createFormattingActions = (formatting) => Object.entries(formats).map(([type, icon]) => createEditorAction({
425
- type,
426
- checked: !!formatting[type]
427
- }, icon));
428
- var createFormatting = (state) => {
429
- const formattingGroupAction = createFormattingGroup(state);
430
- const formattingActions = createFormattingActions(state);
452
+ var flattenRect = (rect, left) => {
453
+ const x = left ? rect.left : rect.right;
431
454
  return {
432
- nodes: [
433
- formattingGroupAction,
434
- ...formattingActions
435
- ],
436
- edges: [
437
- {
438
- source: "root",
439
- target: "formatting"
440
- },
441
- ...formattingActions.map(({ id }) => ({
442
- source: formattingGroupAction.id,
443
- target: id
444
- }))
445
- ]
455
+ left: x,
456
+ right: x,
457
+ top: rect.top,
458
+ bottom: rect.bottom
446
459
  };
447
460
  };
448
- var createHeadingGroupAction = (value) => createEditorActionGroup("heading", {
449
- variant: "dropdownMenu",
450
- applyActive: true,
451
- selectCardinality: "single",
452
- value
453
- }, "ph--text-h--regular");
454
- var createHeadingActions = (value) => Object.entries({
455
- "0": "ph--paragraph--regular",
456
- "1": "ph--text-h-one--regular",
457
- "2": "ph--text-h-two--regular",
458
- "3": "ph--text-h-three--regular",
459
- "4": "ph--text-h-four--regular",
460
- "5": "ph--text-h-five--regular",
461
- "6": "ph--text-h-six--regular"
462
- }).map(([levelStr, icon]) => {
463
- const level = parseInt(levelStr);
464
- return createEditorAction({
465
- type: "heading",
466
- data: level,
467
- checked: value === levelStr
468
- }, icon, [
469
- "heading level label",
470
- {
471
- count: level,
472
- ns: translationKey
473
- }
474
- ], `heading--${levelStr}`);
475
- });
476
- var computeHeadingValue = (state) => {
477
- const blockType = state ? state.blockType : "paragraph";
478
- const header = blockType && /heading(\d)/.exec(blockType);
479
- return header ? header[1] : blockType === "paragraph" || !blockType ? "0" : "";
461
+ var scratchRange;
462
+ var textRange = (node, from, to = from) => {
463
+ const range = scratchRange || (scratchRange = document.createRange());
464
+ range.setEnd(node, to);
465
+ range.setStart(node, from);
466
+ return range;
480
467
  };
481
- var createHeadings = (state) => {
482
- const headingValue = computeHeadingValue(state);
483
- const headingGroupAction = createHeadingGroupAction(headingValue);
484
- const headingActions = createHeadingActions(headingValue);
485
- return {
486
- nodes: [
487
- headingGroupAction,
488
- ...headingActions
489
- ],
490
- edges: [
491
- {
492
- source: "root",
493
- target: "heading"
494
- },
495
- ...headingActions.map(({ id }) => ({
496
- source: headingGroupAction.id,
497
- target: id
498
- }))
499
- ]
500
- };
468
+ var clientRectsFor = (dom) => {
469
+ if (dom.nodeType === 3) {
470
+ return textRange(dom, 0, dom.nodeValue.length).getClientRects();
471
+ } else if (dom.nodeType === 1) {
472
+ return dom.getClientRects();
473
+ } else {
474
+ return [];
475
+ }
501
476
  };
502
- var listStyles = {
503
- bullet: "ph--list-bullets--regular",
504
- ordered: "ph--list-numbers--regular",
505
- task: "ph--list-checks--regular"
477
+ var createElement = (tag, options, children) => {
478
+ const el = document.createElement(tag);
479
+ if (options?.className) {
480
+ el.className = options.className;
481
+ }
482
+ if (children) {
483
+ el.append(...Array.isArray(children) ? children : [
484
+ children
485
+ ]);
486
+ }
487
+ return el;
506
488
  };
507
- var createListGroupAction = (value) => createEditorActionGroup("list", {
508
- variant: "toggleGroup",
509
- selectCardinality: "single",
510
- value
511
- });
512
- var createListActions = (value) => Object.entries(listStyles).map(([listStyle, icon]) => createEditorAction({
513
- type: `list-${listStyle}`,
514
- checked: value === listStyle
515
- }, icon));
516
- var createLists = (state) => {
517
- const value = state.listStyle ?? "";
518
- const listGroupAction = createListGroupAction(value);
519
- const listActionsMap = createListActions(value);
520
- return {
521
- nodes: [
522
- listGroupAction,
523
- ...listActionsMap
524
- ],
525
- edges: [
526
- {
527
- source: "root",
528
- target: "list"
529
- },
530
- ...listActionsMap.map(({ id }) => ({
531
- source: listGroupAction.id,
532
- target: id
533
- }))
534
- ]
535
- };
489
+ var renderRoot = (root, node) => {
490
+ (0, import_client.createRoot)(root).render(/* @__PURE__ */ import_react3.default.createElement(import_react_ui2.ThemeProvider, {
491
+ tx: import_react_ui_theme2.defaultTx
492
+ }, node));
493
+ return root;
536
494
  };
537
- var createViewModeGroupAction = (value) => createEditorActionGroup("viewMode", {
538
- variant: "dropdownMenu",
539
- applyActive: true,
540
- selectCardinality: "single",
541
- value
542
- }, "ph--eye--regular");
543
- var createViewModeActions = (value) => Object.entries({
544
- preview: "ph--eye--regular",
545
- source: "ph--pencil-simple--regular",
546
- readonly: "ph--pencil-slash--regular"
547
- }).map(([viewMode, icon]) => {
548
- return createEditorAction({
549
- type: "view-mode",
550
- data: viewMode,
551
- checked: viewMode === value
552
- }, icon, [
553
- `${viewMode} mode label`,
554
- {
555
- ns: translationKey
556
- }
557
- ], `view-mode--${viewMode}`);
495
+ var createRenderer = (Component) => (el, props) => {
496
+ renderRoot(el, /* @__PURE__ */ import_react3.default.createElement(import_react_ui2.ThemeProvider, {
497
+ tx: import_react_ui_theme2.defaultTx
498
+ }, /* @__PURE__ */ import_react3.default.createElement(import_react_ui2.Tooltip.Provider, null, /* @__PURE__ */ import_react3.default.createElement(Component, props))));
499
+ };
500
+ var annotationMark = import_view2.Decoration.mark({
501
+ class: "cm-annotation"
558
502
  });
559
- var createViewMode = (state) => {
560
- const value = state.viewMode ?? "source";
561
- const viewModeGroupAction = createViewModeGroupAction(value);
562
- const viewModeActions = createViewModeActions(value);
563
- return {
564
- nodes: [
565
- viewModeGroupAction,
566
- ...viewModeActions
567
- ],
568
- edges: [
569
- {
570
- source: "root",
571
- target: "viewMode"
572
- },
573
- ...viewModeActions.map(({ id }) => ({
574
- source: viewModeGroupAction.id,
575
- target: id
576
- }))
577
- ]
503
+ var annotations = (options = {}) => {
504
+ const match = (state) => {
505
+ const annotations2 = [];
506
+ const text = state.doc.toString();
507
+ if (options.match) {
508
+ const matches = text.matchAll(options.match);
509
+ for (const match2 of matches) {
510
+ const from = match2.index;
511
+ const to = from + match2[0].length;
512
+ const cursor = Cursor.getCursorFromRange(state, {
513
+ from,
514
+ to
515
+ });
516
+ annotations2.push({
517
+ cursor
518
+ });
519
+ }
520
+ }
521
+ return annotations2;
578
522
  };
523
+ const annotationsState = import_state2.StateField.define({
524
+ create: (state) => {
525
+ return match(state);
526
+ },
527
+ update: (value, tr) => {
528
+ if (!tr.changes.empty) {
529
+ return match(tr.state);
530
+ }
531
+ return value;
532
+ }
533
+ });
534
+ return [
535
+ annotationsState,
536
+ import_view2.EditorView.decorations.compute([
537
+ annotationsState
538
+ ], (state) => {
539
+ const annotations2 = state.field(annotationsState);
540
+ const decorations = annotations2.map((annotation) => {
541
+ const range = Cursor.getRangeFromCursor(state, annotation.cursor);
542
+ return range && annotationMark.range(range.from, range.to);
543
+ }).filter(import_util.isNotFalsy);
544
+ return import_view2.Decoration.set(decorations);
545
+ }),
546
+ styles
547
+ ];
579
548
  };
580
- var headings = {
581
- 1: "text-4xl",
582
- 2: "text-3xl",
583
- 3: "text-2xl",
584
- 4: "text-xl",
585
- 5: "text-lg",
586
- 6: ""
587
- };
588
- var theme = {
589
- code: "font-mono !no-underline text-neutral-700 dark:text-neutral-300",
590
- codeMark: "font-mono text-primary-500",
591
- mark: "opacity-50",
592
- heading: (level) => {
593
- return (0, import_react_ui_theme3.mx)(headings[level], "dark:text-primary-400");
549
+ var styles = import_view2.EditorView.theme({
550
+ ".cm-annotation": {
551
+ textDecoration: "underline",
552
+ textDecorationStyle: "wavy",
553
+ textDecorationColor: "var(--dx-error)"
594
554
  }
555
+ });
556
+ var autocomplete = ({ debug, activateOnTyping, override, onSearch } = {}) => {
557
+ const extensions = [
558
+ // https://codemirror.net/docs/ref/#view.keymap
559
+ // https://discuss.codemirror.net/t/how-can-i-replace-the-default-autocompletion-keymap-v6/3322
560
+ // TODO(burdon): Set custom keymap.
561
+ import_view3.keymap.of(import_autocomplete.completionKeymap),
562
+ // https://codemirror.net/examples/autocompletion
563
+ // https://codemirror.net/docs/ref/#autocomplete.autocompletion
564
+ (0, import_autocomplete.autocompletion)({
565
+ activateOnTyping,
566
+ override,
567
+ closeOnBlur: !debug,
568
+ tooltipClass: () => "shadow rounded"
569
+ })
570
+ ];
571
+ if (onSearch) {
572
+ extensions.push(
573
+ // TODO(burdon): Optional decoration via addToOptions
574
+ import_lang_markdown.markdownLanguage.data.of({
575
+ autocomplete: (context) => {
576
+ const match = context.matchBefore(/\w*/);
577
+ if (!match || match.from === match.to && !context.explicit) {
578
+ return null;
579
+ }
580
+ return {
581
+ from: match.from,
582
+ options: onSearch(match.text.toLowerCase())
583
+ };
584
+ }
585
+ })
586
+ );
587
+ }
588
+ return extensions;
595
589
  };
596
- var getToken = (path, defaultValue) => {
597
- const value = (0, import_lodash.default)(import_react_ui_theme4.tokens, path, defaultValue);
598
- return value?.toString() ?? "";
599
- };
600
- var fontBody = getToken("fontFamily.body");
601
- var fontMono = getToken("fontFamily.mono");
602
- var defaultTheme = {
603
- "&": {},
604
- "&.cm-focused": {
605
- outline: "none"
606
- },
607
- /**
608
- * Scroller
609
- */
610
- ".cm-scroller": {
611
- overflowY: "auto"
612
- },
613
- /**
614
- * Content
615
- * NOTE: Apply margins to content so that scrollbar is at the edge of the container.
616
- */
617
- ".cm-content": {
618
- padding: "unset",
619
- fontFamily: fontBody,
620
- // NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
621
- fontSize: "16px",
622
- lineHeight: 1.5,
623
- color: "unset"
624
- },
625
- /**
626
- * Gutters
627
- * NOTE: Gutters should have the same top margin as the content.
628
- */
629
- ".cm-gutters": {
630
- borderRight: "none",
631
- background: "transparent"
632
- },
633
- ".cm-gutter": {},
634
- ".cm-gutter.cm-lineNumbers": {
635
- paddingRight: "4px",
636
- borderRight: "1px solid var(--dx-separator)"
637
- },
638
- ".cm-gutter.cm-lineNumbers .cm-gutterElement": {
639
- minWidth: "40px",
640
- alignContent: "center"
641
- },
642
- /**
643
- * Height is set to match the corresponding line.
644
- */
645
- ".cm-gutterElement": {
646
- alignItems: "center",
647
- fontSize: "12px"
648
- },
649
- /**
650
- * Line.
651
- */
652
- ".cm-line": {
653
- paddingInline: 0
654
- },
655
- ".cm-activeLine": {
656
- background: "var(--dx-cmActiveLine)"
657
- },
658
- /**
659
- * Cursor (layer).
660
- */
661
- ".cm-cursor, .cm-dropCursor": {
662
- borderLeft: "2px solid var(--dx-cmCursor)"
663
- },
664
- ".cm-placeholder": {
665
- color: "var(--dx-subdued)"
666
- },
667
- /**
668
- * Selection (layer).
669
- */
670
- ".cm-selectionBackground": {
671
- background: "var(--dx-cmSelection)"
672
- },
673
- /**
674
- * Search.
675
- * NOTE: Matches comment.
676
- */
677
- ".cm-searchMatch": {
678
- margin: "0 -3px",
679
- padding: "3px",
680
- borderRadius: "3px",
681
- background: "var(--dx-cmHighlightSurface)",
682
- color: "var(--dx-cmHighlight)"
683
- },
684
- ".cm-searchMatch-selected": {
685
- textDecoration: "underline"
686
- },
687
- /**
688
- * Link.
689
- */
690
- ".cm-link": {
691
- textDecorationLine: "underline",
692
- textDecorationThickness: "1px",
693
- textDecorationColor: "var(--dx-separator)",
694
- textUnderlineOffset: "2px",
695
- borderRadius: ".125rem"
696
- },
697
- ".cm-link > span": {
698
- color: "var(--dx-accentText)"
699
- },
700
- /**
701
- * Tooltip.
702
- */
703
- ".cm-tooltip": {
704
- background: "var(--dx-baseSurface)"
705
- },
706
- ".cm-tooltip-below": {},
707
- /**
708
- * Autocomplete.
709
- * https://github.com/codemirror/autocomplete/blob/main/src/completion.ts
710
- */
711
- ".cm-tooltip.cm-tooltip-autocomplete": {
712
- marginTop: "4px",
713
- marginLeft: "-3px"
714
- },
715
- ".cm-tooltip.cm-tooltip-autocomplete > ul": {
716
- maxHeight: "20em"
717
- },
718
- ".cm-tooltip.cm-tooltip-autocomplete > ul > li": {},
719
- ".cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected]": {},
720
- ".cm-tooltip.cm-tooltip-autocomplete > ul > completion-section": {
721
- paddingLeft: "4px !important",
722
- borderBottom: "none !important",
723
- color: "var(--dx-accentText)"
724
- },
725
- ".cm-tooltip.cm-completionInfo": {
726
- width: "360px !important",
727
- margin: "-10px 1px 0 1px",
728
- padding: "8px !important",
729
- borderColor: "var(--dx-separator)"
730
- },
731
- ".cm-completionIcon": {
732
- display: "none"
733
- },
734
- ".cm-completionLabel": {
735
- fontFamily: fontBody
736
- },
737
- ".cm-completionMatchedText": {
738
- textDecoration: "none !important",
739
- opacity: 0.5
740
- },
741
- /**
742
- * Panels
743
- * https://github.com/codemirror/search/blob/main/src/search.ts#L745
744
- *
745
- * Find/replace panel.
746
- * <div class="cm-announced">...</div>
747
- * <div class="cm-scroller">...</div>
748
- * <div class="cm-panels cm-panels-bottom">
749
- * <div class="cm-search cm-panel">
750
- * <input class="cm-textfield" />
751
- * <button class="cm-button">...</button>
752
- * <label><input type="checkbox" />...</label>
753
- * </div>
754
- * </div
755
- */
756
- // TODO(burdon): Implement custom panel (with icon buttons).
757
- ".cm-panels": {},
758
- ".cm-panel": {
759
- fontFamily: fontBody,
760
- backgroundColor: "var(--surface-bg)"
761
- },
762
- ".cm-panel input, .cm-panel button, .cm-panel label": {
763
- color: "var(--dx-subdued)",
764
- fontFamily: fontBody,
765
- fontSize: "14px",
766
- all: "unset",
767
- margin: "3px !important",
768
- padding: "2px 6px !important",
769
- outline: "1px solid transparent"
770
- },
771
- ".cm-panel input, .cm-panel button": {
772
- backgroundColor: "var(--dx-input)"
773
- },
774
- ".cm-panel input:focus, .cm-panel button:focus": {
775
- outline: "1px solid var(--dx-accentFocusIndicator)"
776
- },
777
- ".cm-panel label": {
778
- display: "inline-flex",
779
- alignItems: "center",
780
- cursor: "pointer"
781
- },
782
- ".cm-panel input.cm-textfield": {},
783
- ".cm-panel input[type=checkbox]": {
784
- width: "8px",
785
- height: "8px",
786
- marginRight: "6px !important",
787
- padding: "2px !important",
788
- color: "var(--dx-accentFocusIndicator)"
789
- },
790
- ".cm-panel button": {
791
- "&:hover": {
792
- backgroundColor: "var(--dx-accentSurfaceHover) !important"
793
- },
794
- "&:active": {
795
- backgroundColor: "var(--dx-accentSurfaceHover)"
796
- }
797
- },
798
- ".cm-panel.cm-search": {
799
- padding: "4px",
800
- borderTop: "1px solid var(--dx-separator)"
801
- }
802
- };
803
- var margin = "!mt-[1rem]";
804
- var editorWidth = "!mli-auto is-full max-is-[min(50rem,100%-4rem)]";
805
- var editorContent = (0, import_react_ui_theme2.mx)(margin, editorWidth);
806
- var editorFullWidth = (0, import_react_ui_theme2.mx)(margin);
807
- var editorGutter = import_view2.EditorView.theme({
808
- // Match margin from content.
809
- // Gutter = 2rem + 1rem margin.
810
- ".cm-gutters": {
811
- marginTop: "1rem",
812
- paddingRight: "1rem"
813
- }
814
- });
815
- var editorMonospace = import_view2.EditorView.theme({
816
- ".cm-content": {
817
- fontFamily: fontMono
818
- }
819
- });
820
- var editorWithToolbarLayout = "grid grid-cols-1 grid-rows-[min-content_1fr] data-[toolbar=disabled]:grid-rows-[1fr] justify-center content-start overflow-hidden";
821
- var stackItemContentEditorClassNames = (role) => (0, import_react_ui_theme2.mx)("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");
822
- var stackItemContentToolbarClassNames = (role) => (0, import_react_ui_theme2.mx)("attention-surface is-full border-be !border-separator relative z-[1]", role === "section" && "sticky block-start-0 -mbe-px min-is-0");
823
- var createToolbar = ({ state, customActions, ...features }) => {
824
- const nodes = [];
825
- const edges = [];
826
- if (features.headings ?? true) {
827
- const headings2 = createHeadings(state);
828
- nodes.push(...headings2.nodes);
829
- edges.push(...headings2.edges);
830
- }
831
- if (features.formatting ?? true) {
832
- const formatting = createFormatting(state);
833
- nodes.push(...formatting.nodes);
834
- edges.push(...formatting.edges);
835
- }
836
- if (features.lists ?? true) {
837
- const lists = createLists(state);
838
- nodes.push(...lists.nodes);
839
- edges.push(...lists.edges);
840
- }
841
- if (features.blocks ?? true) {
842
- const blocks = createBlocks(state);
843
- nodes.push(...blocks.nodes);
844
- edges.push(...blocks.edges);
845
- }
846
- if (customActions) {
847
- const custom = customActions();
848
- nodes.push(...custom.nodes);
849
- edges.push(...custom.edges);
850
- }
851
- const editorToolbarGap = (0, import_react_ui_menu.createGapSeparator)();
852
- nodes.push(...editorToolbarGap.nodes);
853
- edges.push(...editorToolbarGap.edges);
854
- if (features.comment ?? true) {
855
- const comment = createComment(state);
856
- nodes.push(...comment.nodes);
857
- edges.push(...comment.edges);
858
- }
859
- if (features.search ?? true) {
860
- nodes.push(editorToolbarSearch);
861
- edges.push({
862
- source: "root",
863
- target: editorToolbarSearch.id
864
- });
865
- }
866
- if (features.viewMode ?? true) {
867
- const viewMode = createViewMode(state);
868
- nodes.push(...viewMode.nodes);
869
- edges.push(...viewMode.edges);
870
- }
871
- return {
872
- nodes,
873
- edges
874
- };
875
- };
876
- var useEditorToolbarActionGraph = ({ onAction, ...props }) => {
877
- const menuCreator = (0, import_react.useCallback)(() => createToolbar(props), [
878
- props
879
- ]);
880
- const { resolveGroupItems } = (0, import_react_ui_menu.useMenuActions)(menuCreator);
881
- return {
882
- resolveGroupItems,
883
- onAction
884
- };
885
- };
886
- var EditorToolbar = ({ classNames, attendableId, role, ...props }) => {
887
- const menuProps = useEditorToolbarActionGraph(props);
888
- return /* @__PURE__ */ import_react.default.createElement("div", {
889
- role: "none",
890
- className: stackItemContentToolbarClassNames(role)
891
- }, /* @__PURE__ */ import_react.default.createElement(import_react_ui.ElevationProvider, {
892
- elevation: role === "section" ? "positioned" : "base"
893
- }, /* @__PURE__ */ import_react.default.createElement(import_react_ui_menu.MenuProvider, {
894
- ...menuProps,
895
- attendableId
896
- }, /* @__PURE__ */ import_react.default.createElement(import_react_ui_menu.ToolbarMenu, {
897
- classNames: [
898
- import_react_ui_theme.textBlockWidth,
899
- "!bg-transparent",
900
- classNames
901
- ]
902
- }))));
903
- };
904
- var singleValueFacet = (defaultValue) => import_state3.Facet.define({
905
- // Called immediately.
906
- combine: (providers) => {
907
- return providers[0] ?? defaultValue;
908
- }
909
- });
910
- var overlap = (a, b) => a.from <= b.to && a.to >= b.from;
911
- var defaultCursorConverter = {
912
- toCursor: (position) => position.toString(),
913
- fromCursor: (cursor) => parseInt(cursor)
914
- };
915
- var Cursor = class _Cursor {
916
- static {
917
- this.converter = singleValueFacet(defaultCursorConverter);
918
- }
919
- static {
920
- this.getCursorFromRange = (state, range) => {
921
- const cursorConverter2 = state.facet(_Cursor.converter);
922
- const from = cursorConverter2.toCursor(range.from);
923
- const to = cursorConverter2.toCursor(range.to, -1);
924
- return [
925
- from,
926
- to
927
- ].join(":");
928
- };
929
- }
930
- static {
931
- this.getRangeFromCursor = (state, cursor) => {
932
- const cursorConverter2 = state.facet(_Cursor.converter);
933
- const parts = cursor.split(":");
934
- const from = cursorConverter2.fromCursor(parts[0]);
935
- const to = cursorConverter2.fromCursor(parts[1]);
936
- return from !== void 0 && to !== void 0 ? {
937
- from,
938
- to
939
- } : void 0;
940
- };
941
- }
942
- };
943
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util/debug.ts";
944
- var wrapWithCatch = (fn) => {
945
- return (...args) => {
946
- try {
947
- return fn(...args);
948
- } catch (err) {
949
- import_log.log.catch(err, void 0, {
950
- F: __dxlog_file,
951
- L: 15,
952
- S: void 0,
953
- C: (f, a) => f(...a)
954
- });
955
- }
956
- };
957
- };
958
- var callbackWrapper = (fn) => (...args) => {
959
- try {
960
- return fn(...args);
961
- } catch (err) {
962
- import_log.log.catch(err, void 0, {
963
- F: __dxlog_file,
964
- L: 29,
965
- S: void 0,
966
- C: (f, a) => f(...a)
967
- });
968
- }
969
- };
970
- var debugDispatcher = (trs, view) => {
971
- logChanges(trs);
972
- view.update(trs);
973
- };
974
- var logChanges = (trs) => {
975
- const changes = trs.flatMap((tr) => {
976
- if (tr.changes.empty) {
977
- return void 0;
978
- }
979
- const changes2 = [];
980
- tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => changes2.push(JSON.stringify({
981
- fromA,
982
- toA,
983
- fromB,
984
- toB,
985
- inserted: inserted.toString()
986
- })));
987
- return changes2;
988
- }).filter(Boolean);
989
- if (changes.length) {
990
- (0, import_log.log)("changes", {
991
- changes
992
- }, {
993
- F: __dxlog_file,
994
- L: 62,
995
- S: void 0,
996
- C: (f, a) => f(...a)
997
- });
998
- }
999
- };
1000
- var flattenRect = (rect, left) => {
1001
- const x = left ? rect.left : rect.right;
1002
- return {
1003
- left: x,
1004
- right: x,
1005
- top: rect.top,
1006
- bottom: rect.bottom
1007
- };
1008
- };
1009
- var scratchRange;
1010
- var textRange = (node, from, to = from) => {
1011
- const range = scratchRange || (scratchRange = document.createRange());
1012
- range.setEnd(node, to);
1013
- range.setStart(node, from);
1014
- return range;
1015
- };
1016
- var clientRectsFor = (dom) => {
1017
- if (dom.nodeType === 3) {
1018
- return textRange(dom, 0, dom.nodeValue.length).getClientRects();
1019
- } else if (dom.nodeType === 1) {
1020
- return dom.getClientRects();
1021
- } else {
1022
- return [];
1023
- }
1024
- };
1025
- var createElement = (tag, options, children) => {
1026
- const el = document.createElement(tag);
1027
- if (options?.className) {
1028
- el.className = options.className;
1029
- }
1030
- if (children) {
1031
- el.append(...Array.isArray(children) ? children : [
1032
- children
1033
- ]);
1034
- }
1035
- return el;
1036
- };
1037
- var renderRoot = (root, node) => {
1038
- (0, import_client.createRoot)(root).render(/* @__PURE__ */ import_react3.default.createElement(import_react_ui2.ThemeProvider, {
1039
- tx: import_react_ui_theme5.defaultTx
1040
- }, node));
1041
- return root;
1042
- };
1043
- var createRenderer = (Component) => (el, props) => {
1044
- renderRoot(el, /* @__PURE__ */ import_react3.default.createElement(import_react_ui2.ThemeProvider, {
1045
- tx: import_react_ui_theme5.defaultTx
1046
- }, /* @__PURE__ */ import_react3.default.createElement(import_react_ui2.Tooltip.Provider, null, /* @__PURE__ */ import_react3.default.createElement(Component, props))));
1047
- };
1048
- var annotationMark = import_view3.Decoration.mark({
1049
- class: "cm-annotation"
1050
- });
1051
- var annotations = (options = {}) => {
1052
- const match = (state) => {
1053
- const annotations2 = [];
1054
- const text = state.doc.toString();
1055
- if (options.match) {
1056
- const matches = text.matchAll(options.match);
1057
- for (const match2 of matches) {
1058
- const from = match2.index;
1059
- const to = from + match2[0].length;
1060
- const cursor = Cursor.getCursorFromRange(state, {
1061
- from,
1062
- to
1063
- });
1064
- annotations2.push({
1065
- cursor
1066
- });
1067
- }
1068
- }
1069
- return annotations2;
1070
- };
1071
- const annotationsState = import_state2.StateField.define({
1072
- create: (state) => {
1073
- return match(state);
1074
- },
1075
- update: (value, tr) => {
1076
- if (!tr.changes.empty) {
1077
- return match(tr.state);
1078
- }
1079
- return value;
1080
- }
1081
- });
1082
- return [
1083
- annotationsState,
1084
- import_view3.EditorView.decorations.compute([
1085
- annotationsState
1086
- ], (state) => {
1087
- const annotations2 = state.field(annotationsState);
1088
- const decorations = annotations2.map((annotation) => {
1089
- const range = Cursor.getRangeFromCursor(state, annotation.cursor);
1090
- return range && annotationMark.range(range.from, range.to);
1091
- }).filter(import_util.isNotFalsy);
1092
- return import_view3.Decoration.set(decorations);
1093
- }),
1094
- styles
1095
- ];
1096
- };
1097
- var styles = import_view3.EditorView.theme({
1098
- ".cm-annotation": {
1099
- textDecoration: "underline",
1100
- textDecorationStyle: "wavy",
1101
- textDecorationColor: "var(--dx-error)"
1102
- }
1103
- });
1104
- var autocomplete = ({ debug, activateOnTyping, override, onSearch } = {}) => {
1105
- const extensions = [
1106
- // https://codemirror.net/docs/ref/#view.keymap
1107
- // https://discuss.codemirror.net/t/how-can-i-replace-the-default-autocompletion-keymap-v6/3322
1108
- // TODO(burdon): Set custom keymap.
1109
- import_view4.keymap.of(import_autocomplete.completionKeymap),
1110
- // https://codemirror.net/examples/autocompletion
1111
- // https://codemirror.net/docs/ref/#autocomplete.autocompletion
1112
- (0, import_autocomplete.autocompletion)({
1113
- activateOnTyping,
1114
- override,
1115
- closeOnBlur: !debug,
1116
- tooltipClass: () => "shadow rounded"
1117
- })
1118
- ];
1119
- if (onSearch) {
1120
- extensions.push(
1121
- // TODO(burdon): Optional decoration via addToOptions
1122
- import_lang_markdown.markdownLanguage.data.of({
1123
- autocomplete: (context) => {
1124
- const match = context.matchBefore(/\w*/);
1125
- if (!match || match.from === match.to && !context.explicit) {
1126
- return null;
1127
- }
1128
- return {
1129
- from: match.from,
1130
- options: onSearch(match.text.toLowerCase())
1131
- };
1132
- }
1133
- })
1134
- );
1135
- }
1136
- return extensions;
1137
- };
1138
- var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/automerge/cursor.ts";
1139
- var cursorConverter = (accessor) => ({
1140
- toCursor: (pos, assoc) => {
1141
- try {
1142
- return (0, import_echo.toCursor)(accessor, pos, assoc);
1143
- } catch (err) {
1144
- import_log2.log.catch(err, void 0, {
1145
- F: __dxlog_file2,
1146
- L: 15,
1147
- S: void 0,
1148
- C: (f, a) => f(...a)
1149
- });
1150
- return "";
1151
- }
590
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/automerge/cursor.ts";
591
+ var cursorConverter = (accessor) => ({
592
+ toCursor: (pos, assoc) => {
593
+ try {
594
+ return (0, import_echo.toCursor)(accessor, pos, assoc);
595
+ } catch (err) {
596
+ import_log2.log.catch(err, void 0, {
597
+ F: __dxlog_file2,
598
+ L: 15,
599
+ S: void 0,
600
+ C: (f, a) => f(...a)
601
+ });
602
+ return "";
603
+ }
1152
604
  },
1153
605
  fromCursor: (cursor) => {
1154
606
  try {
@@ -1337,8 +789,8 @@ var Syncer = class {
1337
789
  }
1338
790
  onAutomergeChange(view) {
1339
791
  const oldHeads = getLastHeads(view.state, this._state);
1340
- const newHeads = import_automerge2.next.getHeads(this._handle.docSync());
1341
- const diff = import_automerge2.next.equals(oldHeads, newHeads) ? [] : import_automerge2.next.diff(this._handle.docSync(), oldHeads, newHeads);
792
+ const newHeads = import_automerge2.next.getHeads(this._handle.doc());
793
+ const diff = import_automerge2.next.equals(oldHeads, newHeads) ? [] : import_automerge2.next.diff(this._handle.doc(), oldHeads, newHeads);
1342
794
  const selection = view.state.selection;
1343
795
  const path = getPath(view.state, this._state);
1344
796
  updateCodeMirror(view, selection, path, diff);
@@ -1352,7 +804,7 @@ var automerge = (accessor) => {
1352
804
  const syncState = import_state4.StateField.define({
1353
805
  create: () => ({
1354
806
  path: accessor.path.slice(),
1355
- lastHeads: import_automerge.next.getHeads(accessor.handle.docSync()),
807
+ lastHeads: import_automerge.next.getHeads(accessor.handle.doc()),
1356
808
  unreconciledTransactions: []
1357
809
  }),
1358
810
  update: (value, tr) => {
@@ -1384,7 +836,7 @@ var automerge = (accessor) => {
1384
836
  // Track heads.
1385
837
  syncState,
1386
838
  // Reconcile external updates.
1387
- import_view5.ViewPlugin.fromClass(class {
839
+ import_view4.ViewPlugin.fromClass(class {
1388
840
  constructor(_view) {
1389
841
  this._view = _view;
1390
842
  this._handleChange = () => {
@@ -1397,7 +849,7 @@ var automerge = (accessor) => {
1397
849
  }
1398
850
  }),
1399
851
  // Reconcile local updates.
1400
- import_view5.EditorView.updateListener.of(({ view, changes }) => {
852
+ import_view4.EditorView.updateListener.of(({ view, changes }) => {
1401
853
  if (!changes.empty) {
1402
854
  syncer.reconcile(view, true);
1403
855
  }
@@ -1420,7 +872,7 @@ var RemoteSelectionChangedAnnotation = import_state7.Annotation.define();
1420
872
  var awareness = (provider = dummyProvider) => {
1421
873
  return [
1422
874
  awarenessProvider.of(provider),
1423
- import_view6.ViewPlugin.fromClass(RemoteSelectionsDecorator, {
875
+ import_view5.ViewPlugin.fromClass(RemoteSelectionsDecorator, {
1424
876
  decorations: (value) => value.decorations
1425
877
  }),
1426
878
  styles2
@@ -1484,7 +936,7 @@ var RemoteSelectionsDecorator = class {
1484
936
  decorations.push({
1485
937
  from: start,
1486
938
  to: end,
1487
- value: import_view6.Decoration.mark({
939
+ value: import_view5.Decoration.mark({
1488
940
  attributes: {
1489
941
  style: `background-color: ${lightColor}`
1490
942
  },
@@ -1495,7 +947,7 @@ var RemoteSelectionsDecorator = class {
1495
947
  decorations.push({
1496
948
  from: start,
1497
949
  to: startLine.from + startLine.length,
1498
- value: import_view6.Decoration.mark({
950
+ value: import_view5.Decoration.mark({
1499
951
  attributes: {
1500
952
  style: `background-color: ${lightColor}`
1501
953
  },
@@ -1505,7 +957,7 @@ var RemoteSelectionsDecorator = class {
1505
957
  decorations.push({
1506
958
  from: endLine.from,
1507
959
  to: end,
1508
- value: import_view6.Decoration.mark({
960
+ value: import_view5.Decoration.mark({
1509
961
  attributes: {
1510
962
  style: `background-color: ${lightColor}`
1511
963
  },
@@ -1517,7 +969,7 @@ var RemoteSelectionsDecorator = class {
1517
969
  decorations.push({
1518
970
  from: linePos,
1519
971
  to: linePos,
1520
- value: import_view6.Decoration.line({
972
+ value: import_view5.Decoration.line({
1521
973
  attributes: {
1522
974
  style: `background-color: ${lightColor}`,
1523
975
  class: "cm-collab-selectionLine"
@@ -1529,17 +981,17 @@ var RemoteSelectionsDecorator = class {
1529
981
  decorations.push({
1530
982
  from: head,
1531
983
  to: head,
1532
- value: import_view6.Decoration.widget({
984
+ value: import_view5.Decoration.widget({
1533
985
  side: head - anchor > 0 ? -1 : 1,
1534
986
  block: false,
1535
987
  widget: new RemoteCaretWidget(state.info.displayName ?? "Anonymous", darkColor)
1536
988
  })
1537
989
  });
1538
990
  }
1539
- this.decorations = import_view6.Decoration.set(decorations, true);
991
+ this.decorations = import_view5.Decoration.set(decorations, true);
1540
992
  }
1541
993
  };
1542
- var RemoteCaretWidget = class extends import_view6.WidgetType {
994
+ var RemoteCaretWidget = class extends import_view5.WidgetType {
1543
995
  constructor(_name, _color) {
1544
996
  super();
1545
997
  this._name = _name;
@@ -1575,7 +1027,7 @@ var RemoteCaretWidget = class extends import_view6.WidgetType {
1575
1027
  return true;
1576
1028
  }
1577
1029
  };
1578
- var styles2 = import_view6.EditorView.theme({
1030
+ var styles2 = import_view5.EditorView.theme({
1579
1031
  ".cm-collab-selection": {},
1580
1032
  ".cm-collab-selectionLine": {
1581
1033
  padding: 0,
@@ -1778,12 +1230,12 @@ var blast = (options = defaultOptions) => {
1778
1230
  };
1779
1231
  return [
1780
1232
  // Cursor moved.
1781
- import_view7.EditorView.updateListener.of((update2) => {
1233
+ import_view6.EditorView.updateListener.of((update2) => {
1782
1234
  if (blaster?.node !== update2.view.scrollDOM) {
1783
1235
  if (blaster) {
1784
1236
  blaster.destroy();
1785
1237
  }
1786
- blaster = new Blaster(update2.view.scrollDOM, (0, import_lodash2.default)({
1238
+ blaster = new Blaster(update2.view.scrollDOM, (0, import_lodash.default)({
1787
1239
  particleGravity: 0.2,
1788
1240
  particleShrinkRate: 0.995,
1789
1241
  color: () => [
@@ -1809,7 +1261,7 @@ var blast = (options = defaultOptions) => {
1809
1261
  }
1810
1262
  }
1811
1263
  }),
1812
- import_view7.keymap.of([
1264
+ import_view6.keymap.of([
1813
1265
  {
1814
1266
  any: (_, event) => {
1815
1267
  if (blaster) {
@@ -2101,7 +1553,7 @@ var commandState = import_state9.StateField.define({
2101
1553
  return state;
2102
1554
  },
2103
1555
  provide: (field) => [
2104
- import_view8.showTooltip.from(field, (value) => value.tooltip ?? null)
1556
+ import_view7.showTooltip.from(field, (value) => value.tooltip ?? null)
2105
1557
  ]
2106
1558
  });
2107
1559
  var openEffect = import_state8.StateEffect.define();
@@ -2141,9 +1593,9 @@ var commandKeyBindings = [
2141
1593
  run: closeCommand
2142
1594
  }
2143
1595
  ];
2144
- var hintViewPlugin = ({ onHint }) => import_view10.ViewPlugin.fromClass(class {
1596
+ var hintViewPlugin = ({ onHint }) => import_view9.ViewPlugin.fromClass(class {
2145
1597
  constructor() {
2146
- this.deco = import_view10.Decoration.none;
1598
+ this.deco = import_view9.Decoration.none;
2147
1599
  }
2148
1600
  update(update2) {
2149
1601
  const builder = new import_state10.RangeSetBuilder();
@@ -2154,7 +1606,7 @@ var hintViewPlugin = ({ onHint }) => import_view10.ViewPlugin.fromClass(class {
2154
1606
  if (selection.from === selection.to && line.from === line.to) {
2155
1607
  const hint = onHint();
2156
1608
  if (hint) {
2157
- builder.add(selection.from, selection.to, import_view10.Decoration.widget({
1609
+ builder.add(selection.from, selection.to, import_view9.Decoration.widget({
2158
1610
  widget: new CommandHint(hint)
2159
1611
  }));
2160
1612
  }
@@ -2164,10 +1616,10 @@ var hintViewPlugin = ({ onHint }) => import_view10.ViewPlugin.fromClass(class {
2164
1616
  }
2165
1617
  }, {
2166
1618
  provide: (plugin) => [
2167
- import_view10.EditorView.decorations.of((view) => view.plugin(plugin)?.deco ?? import_view10.Decoration.none)
1619
+ import_view9.EditorView.decorations.of((view) => view.plugin(plugin)?.deco ?? import_view9.Decoration.none)
2168
1620
  ]
2169
1621
  });
2170
- var CommandHint = class extends import_view10.WidgetType {
1622
+ var CommandHint = class extends import_view9.WidgetType {
2171
1623
  constructor(content) {
2172
1624
  super();
2173
1625
  this.content = content;
@@ -2206,7 +1658,7 @@ var CommandHint = class extends import_view10.WidgetType {
2206
1658
  return false;
2207
1659
  }
2208
1660
  };
2209
- var floatingMenu = (options) => import_view11.ViewPlugin.fromClass(class {
1661
+ var floatingMenu = (options) => import_view10.ViewPlugin.fromClass(class {
2210
1662
  constructor(view) {
2211
1663
  this.rafId = null;
2212
1664
  this.view = view;
@@ -2269,7 +1721,7 @@ var floatingMenu = (options) => import_view11.ViewPlugin.fromClass(class {
2269
1721
  });
2270
1722
  var command = (options = {}) => {
2271
1723
  return [
2272
- import_view9.keymap.of(commandKeyBindings),
1724
+ import_view8.keymap.of(commandKeyBindings),
2273
1725
  commandConfig.of(options),
2274
1726
  commandState,
2275
1727
  options.renderMenu ? floatingMenu({
@@ -2278,10 +1730,10 @@ var command = (options = {}) => {
2278
1730
  options.onHint ? hintViewPlugin({
2279
1731
  onHint: options.onHint
2280
1732
  }) : [],
2281
- import_view9.EditorView.focusChangeEffect.of((_, focusing) => {
1733
+ import_view8.EditorView.focusChangeEffect.of((_, focusing) => {
2282
1734
  return focusing ? closeEffect.of(null) : null;
2283
1735
  }),
2284
- import_view9.EditorView.theme({
1736
+ import_view8.EditorView.theme({
2285
1737
  ".cm-tooltip": {
2286
1738
  background: "transparent"
2287
1739
  }
@@ -2295,7 +1747,7 @@ var createEditorStateTransaction = ({ scrollTo, selection }) => {
2295
1747
  return {
2296
1748
  selection,
2297
1749
  scrollIntoView: !scrollTo,
2298
- effects: scrollTo ? import_view13.EditorView.scrollIntoView(scrollTo, {
1750
+ effects: scrollTo ? import_view12.EditorView.scrollIntoView(scrollTo, {
2299
1751
  yMargin: 96
2300
1752
  }) : void 0,
2301
1753
  annotations: import_state12.Transaction.userEvent.of(stateRestoreAnnotation)
@@ -2337,7 +1789,7 @@ var selectionState = ({ getState, setState } = {}) => {
2337
1789
  // setStateDebounced(id, {});
2338
1790
  // },
2339
1791
  // }),
2340
- import_view13.EditorView.updateListener.of(({ view, transactions }) => {
1792
+ import_view12.EditorView.updateListener.of(({ view, transactions }) => {
2341
1793
  const id = view.state.facet(documentId);
2342
1794
  if (!id || transactions.some((tr) => tr.isUserEvent(stateRestoreAnnotation))) {
2343
1795
  return;
@@ -2360,7 +1812,7 @@ var selectionState = ({ getState, setState } = {}) => {
2360
1812
  }
2361
1813
  }
2362
1814
  }),
2363
- getState && import_view13.keymap.of([
1815
+ getState && import_view12.keymap.of([
2364
1816
  {
2365
1817
  key: "ctrl-r",
2366
1818
  run: (view) => {
@@ -2416,7 +1868,7 @@ var commentsState = import_state11.StateField.define({
2416
1868
  return value;
2417
1869
  }
2418
1870
  });
2419
- var styles3 = import_view12.EditorView.theme({
1871
+ var styles3 = import_view11.EditorView.theme({
2420
1872
  ".cm-comment, .cm-comment-current": {
2421
1873
  margin: "0 -3px",
2422
1874
  padding: "3px",
@@ -2429,18 +1881,18 @@ var styles3 = import_view12.EditorView.theme({
2429
1881
  textDecoration: "underline"
2430
1882
  }
2431
1883
  });
2432
- var createCommentMark = (id, isCurrent) => import_view12.Decoration.mark({
1884
+ var createCommentMark = (id, isCurrent) => import_view11.Decoration.mark({
2433
1885
  class: isCurrent ? "cm-comment-current" : "cm-comment",
2434
1886
  attributes: {
2435
1887
  "data-testid": "cm-comment",
2436
1888
  "data-comment-id": id
2437
1889
  }
2438
1890
  });
2439
- var commentsDecorations = import_view12.EditorView.decorations.compute([
1891
+ var commentsDecorations = import_view11.EditorView.decorations.compute([
2440
1892
  commentsState
2441
1893
  ], (state) => {
2442
1894
  const { selection: { current }, comments: comments2 } = state.field(commentsState);
2443
- const decorations = (0, import_lodash3.default)(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
1895
+ const decorations = (0, import_lodash2.default)(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
2444
1896
  const range = comment.range;
2445
1897
  if (!range) {
2446
1898
  import_log4.log.warn("Invalid range:", range, {
@@ -2456,10 +1908,10 @@ var commentsDecorations = import_view12.EditorView.decorations.compute([
2456
1908
  const mark = createCommentMark(comment.comment.id, comment.comment.id === current);
2457
1909
  return mark.range(range.from, range.to);
2458
1910
  }).filter(import_util2.isNonNullable);
2459
- return import_view12.Decoration.set(decorations);
1911
+ return import_view11.Decoration.set(decorations);
2460
1912
  });
2461
1913
  var commentClickedEffect = import_state11.StateEffect.define();
2462
- var handleCommentClick = import_view12.EditorView.domEventHandlers({
1914
+ var handleCommentClick = import_view11.EditorView.domEventHandlers({
2463
1915
  click: (event, view) => {
2464
1916
  let target = event.target;
2465
1917
  const editorRoot = view.dom;
@@ -2498,7 +1950,7 @@ var trackPastedComments = (onUpdate) => {
2498
1950
  }
2499
1951
  };
2500
1952
  return [
2501
- import_view12.EditorView.domEventHandlers({
1953
+ import_view11.EditorView.domEventHandlers({
2502
1954
  cut: handleTrack,
2503
1955
  copy: handleTrack
2504
1956
  }),
@@ -2520,7 +1972,7 @@ var trackPastedComments = (onUpdate) => {
2520
1972
  return effects;
2521
1973
  }),
2522
1974
  // Handle paste or the undo of comment deletion.
2523
- import_view12.EditorView.updateListener.of((update2) => {
1975
+ import_view11.EditorView.updateListener.of((update2) => {
2524
1976
  const restore = [];
2525
1977
  for (let i = 0; i < update2.transactions.length; i++) {
2526
1978
  const tr = update2.transactions[i];
@@ -2579,7 +2031,7 @@ var mapTrackedComment = (comment, changes) => ({
2579
2031
  var restoreCommentEffect = import_state11.StateEffect.define({
2580
2032
  map: mapTrackedComment
2581
2033
  });
2582
- var createComment2 = (view) => {
2034
+ var createComment = (view) => {
2583
2035
  const options = view.state.facet(optionsFacet);
2584
2036
  const { from, to } = view.state.selection.main;
2585
2037
  if (from === to) {
@@ -2621,17 +2073,17 @@ var comments = (options = {}) => {
2621
2073
  //
2622
2074
  // Keymap.
2623
2075
  //
2624
- options.onCreate && import_view12.keymap.of([
2076
+ options.onCreate && import_view11.keymap.of([
2625
2077
  {
2626
2078
  key: shortcut,
2627
- run: callbackWrapper(createComment2)
2079
+ run: callbackWrapper(createComment)
2628
2080
  }
2629
2081
  ]),
2630
2082
  //
2631
2083
  // Hover tooltip (for key shortcut hints, etc.)
2632
2084
  // TODO(burdon): Factor out to generic hints extension for current selection/line.
2633
2085
  //
2634
- options.renderTooltip && (0, import_view12.hoverTooltip)((view, pos) => {
2086
+ options.renderTooltip && (0, import_view11.hoverTooltip)((view, pos) => {
2635
2087
  const selection = view.state.selection.main;
2636
2088
  if (selection && pos >= selection.from && pos <= selection.to) {
2637
2089
  return {
@@ -2662,7 +2114,7 @@ var comments = (options = {}) => {
2662
2114
  //
2663
2115
  // Track deleted ranges and update ranges for decorations.
2664
2116
  //
2665
- import_view12.EditorView.updateListener.of(({ view, state, changes }) => {
2117
+ import_view11.EditorView.updateListener.of(({ view, state, changes }) => {
2666
2118
  let mod = false;
2667
2119
  const { comments: comments2, ...value } = state.field(commentsState);
2668
2120
  changes.iterChanges((from, to, from2, to2) => {
@@ -2694,7 +2146,7 @@ var comments = (options = {}) => {
2694
2146
  //
2695
2147
  // Track selection/proximity.
2696
2148
  //
2697
- import_view12.EditorView.updateListener.of(({ view, state }) => {
2149
+ import_view11.EditorView.updateListener.of(({ view, state }) => {
2698
2150
  let min = Infinity;
2699
2151
  const { selection: { current, closest }, comments: comments2 } = state.field(commentsState);
2700
2152
  const { head } = state.selection.main;
@@ -2748,7 +2200,7 @@ var scrollThreadIntoView = (view, id, center = true) => {
2748
2200
  anchor: range.from
2749
2201
  } : void 0,
2750
2202
  effects: [
2751
- needsScroll ? import_view12.EditorView.scrollIntoView(range.from, center ? {
2203
+ needsScroll ? import_view11.EditorView.scrollIntoView(range.from, center ? {
2752
2204
  y: "center"
2753
2205
  } : void 0) : [],
2754
2206
  needsSelectionUpdate ? setSelection.of({
@@ -2794,13 +2246,13 @@ var ExternalCommentSync = class {
2794
2246
  this.unsubscribe = subscribe(updateComments);
2795
2247
  }
2796
2248
  };
2797
- var createExternalCommentSync = (id, subscribe, getComments) => import_view12.ViewPlugin.fromClass(class {
2249
+ var createExternalCommentSync = (id, subscribe, getComments) => import_view11.ViewPlugin.fromClass(class {
2798
2250
  constructor(view) {
2799
2251
  return new ExternalCommentSync(view, id, subscribe, getComments);
2800
2252
  }
2801
2253
  });
2802
2254
  var useCommentState = (state) => {
2803
- return (0, import_react4.useMemo)(() => import_view12.EditorView.updateListener.of((update2) => {
2255
+ return (0, import_react4.useMemo)(() => import_view11.EditorView.updateListener.of((update2) => {
2804
2256
  if (update2.docChanged || update2.selectionSet) {
2805
2257
  state.comment = selectionOverlapsComment(update2.state);
2806
2258
  state.selection = hasActiveSelection(update2.state);
@@ -2821,90 +2273,316 @@ var useComments = (view, id, comments2) => {
2821
2273
  });
2822
2274
  }
2823
2275
  }
2824
- });
2825
- };
2826
- var useCommentClickListener = (onCommentClick) => {
2827
- return (0, import_react4.useMemo)(() => import_view12.EditorView.updateListener.of((update2) => {
2828
- update2.transactions.forEach((transaction) => {
2829
- transaction.effects.forEach((effect) => {
2830
- if (effect.is(commentClickedEffect)) {
2831
- onCommentClick(effect.value);
2832
- }
2833
- });
2834
- });
2835
- }), [
2836
- onCommentClick
2837
- ]);
2838
- };
2839
- var debugNodeLogger = (log8 = console.log) => {
2840
- const logTokens = (state) => (0, import_language.syntaxTree)(state).iterate({
2841
- enter: (node) => log8(node.type)
2842
- });
2843
- return import_state13.StateField.define({
2844
- create: (state) => logTokens(state),
2845
- update: (_, tr) => logTokens(tr.state)
2846
- });
2847
- };
2848
- var styles4 = import_view14.EditorView.theme({
2849
- ".cm-dropCursor": {
2850
- borderLeft: "2px solid var(--dx-accentText)",
2851
- color: "var(--dx-accentText)",
2852
- padding: "0 4px"
2276
+ });
2277
+ };
2278
+ var useCommentClickListener = (onCommentClick) => {
2279
+ return (0, import_react4.useMemo)(() => import_view11.EditorView.updateListener.of((update2) => {
2280
+ update2.transactions.forEach((transaction) => {
2281
+ transaction.effects.forEach((effect) => {
2282
+ if (effect.is(commentClickedEffect)) {
2283
+ onCommentClick(effect.value);
2284
+ }
2285
+ });
2286
+ });
2287
+ }), [
2288
+ onCommentClick
2289
+ ]);
2290
+ };
2291
+ var debugNodeLogger = (log9 = console.log) => {
2292
+ const logTokens = (state) => (0, import_language.syntaxTree)(state).iterate({
2293
+ enter: (node) => log9(node.type)
2294
+ });
2295
+ return import_state13.StateField.define({
2296
+ create: (state) => logTokens(state),
2297
+ update: (_, tr) => logTokens(tr.state)
2298
+ });
2299
+ };
2300
+ var styles4 = import_view13.EditorView.theme({
2301
+ ".cm-dropCursor": {
2302
+ borderLeft: "2px solid var(--dx-accentText)",
2303
+ color: "var(--dx-accentText)",
2304
+ padding: "0 4px"
2305
+ },
2306
+ ".cm-dropCursor:after": {
2307
+ content: '"\u2190"'
2308
+ }
2309
+ });
2310
+ var dropFile = (options = {}) => {
2311
+ return [
2312
+ styles4,
2313
+ (0, import_view13.dropCursor)(),
2314
+ import_view13.EditorView.domEventHandlers({
2315
+ drop: (event, view) => {
2316
+ event.preventDefault();
2317
+ const files = event.dataTransfer?.files;
2318
+ const pos = view.posAtCoords(event);
2319
+ if (files?.length && pos !== null) {
2320
+ view.dispatch({
2321
+ selection: {
2322
+ anchor: pos
2323
+ }
2324
+ });
2325
+ options.onDrop?.(view, {
2326
+ files
2327
+ });
2328
+ }
2329
+ }
2330
+ })
2331
+ ];
2332
+ };
2333
+ var focusEffect = import_state15.StateEffect.define();
2334
+ var focusField = import_state15.StateField.define({
2335
+ create: () => false,
2336
+ update: (value, tr) => {
2337
+ for (const effect of tr.effects) {
2338
+ if (effect.is(focusEffect)) {
2339
+ return effect.value;
2340
+ }
2341
+ }
2342
+ return value;
2343
+ }
2344
+ });
2345
+ var focus = [
2346
+ focusField,
2347
+ import_view15.EditorView.domEventHandlers({
2348
+ focus: (event, view) => {
2349
+ setTimeout(() => view.dispatch({
2350
+ effects: focusEffect.of(true)
2351
+ }));
2352
+ },
2353
+ blur: (event, view) => {
2354
+ setTimeout(() => view.dispatch({
2355
+ effects: focusEffect.of(false)
2356
+ }));
2357
+ }
2358
+ })
2359
+ ];
2360
+ var headings = {
2361
+ 1: "text-4xl",
2362
+ 2: "text-3xl",
2363
+ 3: "text-2xl",
2364
+ 4: "text-xl",
2365
+ 5: "text-lg",
2366
+ 6: ""
2367
+ };
2368
+ var theme = {
2369
+ code: "font-mono !no-underline text-neutral-700 dark:text-neutral-300",
2370
+ codeMark: "font-mono text-primary-500",
2371
+ mark: "opacity-50",
2372
+ heading: (level) => {
2373
+ return (0, import_react_ui_theme3.mx)(headings[level], "dark:text-primary-400");
2374
+ }
2375
+ };
2376
+ var getToken = (path, defaultValue) => {
2377
+ const value = (0, import_lodash5.default)(import_react_ui_theme4.tokens, path, defaultValue);
2378
+ return value?.toString() ?? "";
2379
+ };
2380
+ var fontBody = getToken("fontFamily.body");
2381
+ var fontMono = getToken("fontFamily.mono");
2382
+ var defaultTheme = {
2383
+ "&": {},
2384
+ "&.cm-focused": {
2385
+ outline: "none"
2386
+ },
2387
+ /**
2388
+ * Scroller
2389
+ */
2390
+ ".cm-scroller": {
2391
+ overflowY: "auto"
2392
+ },
2393
+ /**
2394
+ * Content
2395
+ * NOTE: Apply margins to content so that scrollbar is at the edge of the container.
2396
+ */
2397
+ ".cm-content": {
2398
+ padding: "unset",
2399
+ fontFamily: fontBody,
2400
+ // NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
2401
+ fontSize: "16px",
2402
+ lineHeight: 1.5,
2403
+ color: "unset"
2404
+ },
2405
+ /**
2406
+ * Gutters
2407
+ * NOTE: Gutters should have the same top margin as the content.
2408
+ */
2409
+ ".cm-gutters": {
2410
+ borderRight: "none",
2411
+ background: "transparent"
2412
+ },
2413
+ ".cm-gutter": {},
2414
+ ".cm-gutter.cm-lineNumbers": {
2415
+ paddingRight: "4px",
2416
+ borderRight: "1px solid var(--dx-separator)"
2417
+ },
2418
+ ".cm-gutter.cm-lineNumbers .cm-gutterElement": {
2419
+ minWidth: "40px",
2420
+ alignContent: "center"
2421
+ },
2422
+ /**
2423
+ * Height is set to match the corresponding line.
2424
+ */
2425
+ ".cm-gutterElement": {
2426
+ alignItems: "center",
2427
+ fontSize: "12px"
2428
+ },
2429
+ /**
2430
+ * Line.
2431
+ */
2432
+ ".cm-line": {
2433
+ paddingInline: 0
2434
+ },
2435
+ ".cm-activeLine": {
2436
+ background: "var(--dx-cmActiveLine)"
2437
+ },
2438
+ /**
2439
+ * Cursor (layer).
2440
+ */
2441
+ ".cm-cursor, .cm-dropCursor": {
2442
+ borderLeft: "2px solid var(--dx-cmCursor)"
2443
+ },
2444
+ ".cm-placeholder": {
2445
+ color: "var(--dx-subdued)"
2446
+ },
2447
+ /**
2448
+ * Selection (layer).
2449
+ */
2450
+ ".cm-selectionBackground": {
2451
+ background: "var(--dx-cmSelection)"
2452
+ },
2453
+ "&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
2454
+ background: "var(--dx-cmFocusedSelection)"
2455
+ },
2456
+ /**
2457
+ * Search.
2458
+ * NOTE: Matches comment.
2459
+ */
2460
+ ".cm-searchMatch": {
2461
+ margin: "0 -3px",
2462
+ padding: "3px",
2463
+ borderRadius: "3px",
2464
+ background: "var(--dx-cmHighlightSurface)",
2465
+ color: "var(--dx-cmHighlight)"
2466
+ },
2467
+ ".cm-searchMatch-selected": {
2468
+ textDecoration: "underline"
2469
+ },
2470
+ /**
2471
+ * Link.
2472
+ */
2473
+ ".cm-link": {
2474
+ textDecorationLine: "underline",
2475
+ textDecorationThickness: "1px",
2476
+ textDecorationColor: "var(--dx-separator)",
2477
+ textUnderlineOffset: "2px",
2478
+ borderRadius: ".125rem"
2479
+ },
2480
+ ".cm-link > span": {
2481
+ color: "var(--dx-accentText)"
2482
+ },
2483
+ /**
2484
+ * Tooltip.
2485
+ */
2486
+ ".cm-tooltip": {
2487
+ background: "var(--dx-baseSurface)"
2488
+ },
2489
+ ".cm-tooltip-below": {},
2490
+ /**
2491
+ * Autocomplete.
2492
+ * https://github.com/codemirror/autocomplete/blob/main/src/completion.ts
2493
+ */
2494
+ ".cm-tooltip.cm-tooltip-autocomplete": {
2495
+ marginTop: "4px",
2496
+ marginLeft: "-3px"
2497
+ },
2498
+ ".cm-tooltip.cm-tooltip-autocomplete > ul": {
2499
+ maxHeight: "20em"
2500
+ },
2501
+ ".cm-tooltip.cm-tooltip-autocomplete > ul > li": {},
2502
+ ".cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected]": {},
2503
+ ".cm-tooltip.cm-tooltip-autocomplete > ul > completion-section": {
2504
+ paddingLeft: "4px !important",
2505
+ borderBottom: "none !important",
2506
+ color: "var(--dx-accentText)"
2507
+ },
2508
+ ".cm-tooltip.cm-completionInfo": {
2509
+ width: "360px !important",
2510
+ margin: "-10px 1px 0 1px",
2511
+ padding: "8px !important",
2512
+ borderColor: "var(--dx-separator)"
2513
+ },
2514
+ ".cm-completionIcon": {
2515
+ display: "none"
2516
+ },
2517
+ ".cm-completionLabel": {
2518
+ fontFamily: fontBody
2519
+ },
2520
+ ".cm-completionMatchedText": {
2521
+ textDecoration: "none !important",
2522
+ opacity: 0.5
2523
+ },
2524
+ /**
2525
+ * Panels
2526
+ * https://github.com/codemirror/search/blob/main/src/search.ts#L745
2527
+ *
2528
+ * Find/replace panel.
2529
+ * <div class="cm-announced">...</div>
2530
+ * <div class="cm-scroller">...</div>
2531
+ * <div class="cm-panels cm-panels-bottom">
2532
+ * <div class="cm-search cm-panel">
2533
+ * <input class="cm-textfield" />
2534
+ * <button class="cm-button">...</button>
2535
+ * <label><input type="checkbox" />...</label>
2536
+ * </div>
2537
+ * </div
2538
+ */
2539
+ // TODO(burdon): Implement custom panel (with icon buttons).
2540
+ ".cm-panels": {},
2541
+ ".cm-panel": {
2542
+ fontFamily: fontBody,
2543
+ backgroundColor: "var(--surface-bg)"
2544
+ },
2545
+ ".cm-panel input, .cm-panel button, .cm-panel label": {
2546
+ color: "var(--dx-subdued)",
2547
+ fontFamily: fontBody,
2548
+ fontSize: "14px",
2549
+ all: "unset",
2550
+ margin: "3px !important",
2551
+ padding: "2px 6px !important",
2552
+ outline: "1px solid transparent"
2553
+ },
2554
+ ".cm-panel input, .cm-panel button": {
2555
+ backgroundColor: "var(--dx-input)"
2556
+ },
2557
+ ".cm-panel input:focus, .cm-panel button:focus": {
2558
+ outline: "1px solid var(--dx-accentFocusIndicator)"
2559
+ },
2560
+ ".cm-panel label": {
2561
+ display: "inline-flex",
2562
+ alignItems: "center",
2563
+ cursor: "pointer"
2564
+ },
2565
+ ".cm-panel input.cm-textfield": {},
2566
+ ".cm-panel input[type=checkbox]": {
2567
+ width: "8px",
2568
+ height: "8px",
2569
+ marginRight: "6px !important",
2570
+ padding: "2px !important",
2571
+ color: "var(--dx-accentFocusIndicator)"
2572
+ },
2573
+ ".cm-panel button": {
2574
+ "&:hover": {
2575
+ backgroundColor: "var(--dx-accentSurfaceHover) !important"
2576
+ },
2577
+ "&:active": {
2578
+ backgroundColor: "var(--dx-accentSurfaceHover)"
2579
+ }
2853
2580
  },
2854
- ".cm-dropCursor:after": {
2855
- content: '"\u2190"'
2581
+ ".cm-panel.cm-search": {
2582
+ padding: "4px",
2583
+ borderTop: "1px solid var(--dx-separator)"
2856
2584
  }
2857
- });
2858
- var dropFile = (options = {}) => {
2859
- return [
2860
- styles4,
2861
- (0, import_view14.dropCursor)(),
2862
- import_view14.EditorView.domEventHandlers({
2863
- drop: (event, view) => {
2864
- event.preventDefault();
2865
- const files = event.dataTransfer?.files;
2866
- const pos = view.posAtCoords(event);
2867
- if (files?.length && pos !== null) {
2868
- view.dispatch({
2869
- selection: {
2870
- anchor: pos
2871
- }
2872
- });
2873
- options.onDrop?.(view, {
2874
- files
2875
- });
2876
- }
2877
- }
2878
- })
2879
- ];
2880
2585
  };
2881
- var focusEffect = import_state15.StateEffect.define();
2882
- var focusField = import_state15.StateField.define({
2883
- create: () => false,
2884
- update: (value, tr) => {
2885
- for (const effect of tr.effects) {
2886
- if (effect.is(focusEffect)) {
2887
- return effect.value;
2888
- }
2889
- }
2890
- return value;
2891
- }
2892
- });
2893
- var focus = [
2894
- focusField,
2895
- import_view16.EditorView.domEventHandlers({
2896
- focus: (event, view) => {
2897
- setTimeout(() => view.dispatch({
2898
- effects: focusEffect.of(true)
2899
- }));
2900
- },
2901
- blur: (event, view) => {
2902
- setTimeout(() => view.dispatch({
2903
- effects: focusEffect.of(false)
2904
- }));
2905
- }
2906
- })
2907
- ];
2908
2586
  var __dxlog_file8 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/factories.ts";
2909
2587
  var preventNewline = import_state14.EditorState.transactionFilter.of((tr) => tr.newDoc.lines > 1 ? [] : tr);
2910
2588
  var defaultBasicOptions = {
@@ -2925,10 +2603,10 @@ var keymaps = {
2925
2603
  default: import_commands2.defaultKeymap
2926
2604
  };
2927
2605
  var createBasicExtensions = (_props) => {
2928
- const props = (0, import_lodash4.default)({}, _props, defaultBasicOptions);
2606
+ const props = (0, import_lodash3.default)({}, _props, defaultBasicOptions);
2929
2607
  return [
2930
2608
  // NOTE: Doesn't catch errors in keymap functions.
2931
- import_view15.EditorView.exceptionSink.of((err) => {
2609
+ import_view14.EditorView.exceptionSink.of((err) => {
2932
2610
  import_log5.log.catch(err, void 0, {
2933
2611
  F: __dxlog_file8,
2934
2612
  L: 96,
@@ -2939,22 +2617,22 @@ var createBasicExtensions = (_props) => {
2939
2617
  props.allowMultipleSelections && import_state14.EditorState.allowMultipleSelections.of(true),
2940
2618
  props.bracketMatching && (0, import_language2.bracketMatching)(),
2941
2619
  props.closeBrackets && (0, import_autocomplete2.closeBrackets)(),
2942
- props.dropCursor && (0, import_view15.dropCursor)(),
2943
- props.drawSelection && (0, import_view15.drawSelection)({
2620
+ props.dropCursor && (0, import_view14.dropCursor)(),
2621
+ props.drawSelection && (0, import_view14.drawSelection)({
2944
2622
  cursorBlinkRate: 1200
2945
2623
  }),
2946
- props.editable !== void 0 && import_view15.EditorView.editable.of(props.editable),
2624
+ props.editable !== void 0 && import_view14.EditorView.editable.of(props.editable),
2947
2625
  props.focus && focus,
2948
- props.highlightActiveLine && (0, import_view15.highlightActiveLine)(),
2626
+ props.highlightActiveLine && (0, import_view14.highlightActiveLine)(),
2949
2627
  props.history && (0, import_commands2.history)(),
2950
- props.lineNumbers && (0, import_view15.lineNumbers)(),
2951
- props.lineWrapping && import_view15.EditorView.lineWrapping,
2952
- props.placeholder && (0, import_view15.placeholder)(props.placeholder),
2628
+ props.lineNumbers && (0, import_view14.lineNumbers)(),
2629
+ props.lineWrapping && import_view14.EditorView.lineWrapping,
2630
+ props.placeholder && (0, import_view14.placeholder)(props.placeholder),
2953
2631
  props.readOnly !== void 0 && import_state14.EditorState.readOnly.of(props.readOnly),
2954
- props.scrollPastEnd && (0, import_view15.scrollPastEnd)(),
2632
+ props.scrollPastEnd && (0, import_view14.scrollPastEnd)(),
2955
2633
  props.tabSize && import_state14.EditorState.tabSize.of(props.tabSize),
2956
2634
  // https://codemirror.net/docs/ref/#view.KeyBinding
2957
- import_view15.keymap.of([
2635
+ import_view14.keymap.of([
2958
2636
  ...(props.keymap && keymaps[props.keymap]) ?? [],
2959
2637
  // NOTE: Tabs are also configured by markdown extension.
2960
2638
  // https://codemirror.net/docs/ref/#commands.indentWithTab
@@ -2983,16 +2661,16 @@ var defaultThemeSlots = {
2983
2661
  }
2984
2662
  };
2985
2663
  var createThemeExtensions = ({ themeMode, styles: styles5, syntaxHighlighting: _syntaxHighlighting, slots: _slots } = {}) => {
2986
- const slots = (0, import_lodash4.default)({}, _slots, defaultThemeSlots);
2664
+ const slots = (0, import_lodash3.default)({}, _slots, defaultThemeSlots);
2987
2665
  return [
2988
- import_view15.EditorView.darkTheme.of(themeMode === "dark"),
2989
- import_view15.EditorView.baseTheme(styles5 ? (0, import_lodash5.default)({}, defaultTheme, styles5) : defaultTheme),
2666
+ import_view14.EditorView.darkTheme.of(themeMode === "dark"),
2667
+ import_view14.EditorView.baseTheme(styles5 ? (0, import_lodash4.default)({}, defaultTheme, styles5) : defaultTheme),
2990
2668
  // https://github.com/codemirror/theme-one-dark
2991
2669
  _syntaxHighlighting && (themeMode === "dark" ? (0, import_language2.syntaxHighlighting)(import_theme_one_dark.oneDarkHighlightStyle) : (0, import_language2.syntaxHighlighting)(import_language2.defaultHighlightStyle)),
2992
- slots.editor?.className && import_view15.EditorView.editorAttributes.of({
2670
+ slots.editor?.className && import_view14.EditorView.editorAttributes.of({
2993
2671
  class: slots.editor.className
2994
2672
  }),
2995
- slots.content?.className && import_view15.EditorView.contentAttributes.of({
2673
+ slots.content?.className && import_view14.EditorView.contentAttributes.of({
2996
2674
  class: slots.content.className
2997
2675
  })
2998
2676
  ].filter(import_util4.isNotFalsy);
@@ -3039,7 +2717,7 @@ var folding = (_props = {}) => [
3039
2717
  }));
3040
2718
  }
3041
2719
  }),
3042
- import_view17.EditorView.theme({
2720
+ import_view16.EditorView.theme({
3043
2721
  ".cm-foldGutter": {
3044
2722
  opacity: 0.3,
3045
2723
  transition: "opacity 0.3s",
@@ -3052,11 +2730,11 @@ var folding = (_props = {}) => [
3052
2730
  ];
3053
2731
  var listener = ({ onFocus, onChange }) => {
3054
2732
  const extensions = [];
3055
- onFocus && extensions.push(import_view18.EditorView.focusChangeEffect.of((_, focusing) => {
2733
+ onFocus && extensions.push(import_view17.EditorView.focusChangeEffect.of((_, focusing) => {
3056
2734
  onFocus(focusing);
3057
2735
  return null;
3058
2736
  }));
3059
- onChange && extensions.push(import_view18.EditorView.updateListener.of((update2) => {
2737
+ onChange && extensions.push(import_view17.EditorView.updateListener.of((update2) => {
3060
2738
  onChange(update2.state.doc.toString(), update2.state.facet(documentId));
3061
2739
  }));
3062
2740
  return extensions;
@@ -3947,7 +3625,7 @@ var toggleCodeblock = (target) => {
3947
3625
  };
3948
3626
  var formattingKeymap = (_options = {}) => {
3949
3627
  return [
3950
- import_view19.keymap.of([
3628
+ import_view18.keymap.of([
3951
3629
  {
3952
3630
  key: "meta-b",
3953
3631
  run: toggleStrong
@@ -4148,7 +3826,7 @@ var getFormatting = (state) => {
4148
3826
  };
4149
3827
  };
4150
3828
  var useFormattingState = (state) => {
4151
- return (0, import_react6.useMemo)(() => import_view19.EditorView.updateListener.of((update2) => {
3829
+ return (0, import_react6.useMemo)(() => import_view18.EditorView.updateListener.of((update2) => {
4152
3830
  if (update2.docChanged || update2.selectionSet) {
4153
3831
  Object.entries(getFormatting(update2.state)).forEach(([key, active]) => {
4154
3832
  state[key] = active;
@@ -4194,7 +3872,7 @@ var processEditorPayload = (view, { type, data }) => {
4194
3872
  })(view);
4195
3873
  break;
4196
3874
  case "comment":
4197
- createComment2(view);
3875
+ createComment(view);
4198
3876
  break;
4199
3877
  }
4200
3878
  requestAnimationFrame(() => {
@@ -4400,7 +4078,7 @@ var createMarkdownExtensions = ({ themeMode } = {}) => {
4400
4078
  }),
4401
4079
  // Custom styles.
4402
4080
  (0, import_language5.syntaxHighlighting)(markdownHighlightStyle()),
4403
- import_view20.keymap.of([
4081
+ import_view19.keymap.of([
4404
4082
  // https://codemirror.net/docs/ref/#commands.indentWithTab
4405
4083
  import_commands3.indentWithTab,
4406
4084
  // https://codemirror.net/docs/ref/#commands.defaultKeymap
@@ -4434,7 +4112,7 @@ var convertTreeToJson = (state) => {
4434
4112
  return treeToJson((0, import_language7.syntaxTree)(state).cursor());
4435
4113
  };
4436
4114
  var adjustChanges = () => {
4437
- return import_view22.ViewPlugin.fromClass(class {
4115
+ return import_view21.ViewPlugin.fromClass(class {
4438
4116
  update(update2) {
4439
4117
  const tree = (0, import_language9.syntaxTree)(update2.state);
4440
4118
  const adjustments = [];
@@ -4477,11 +4155,11 @@ var adjustChanges = () => {
4477
4155
  if (url) {
4478
4156
  const node = tree.resolveInner(fromA, -1);
4479
4157
  const invalidPositions = /* @__PURE__ */ new Set([
4480
- "Link",
4481
- "LinkMark",
4482
4158
  "Code",
4483
4159
  "CodeText",
4484
4160
  "FencedCode",
4161
+ "Link",
4162
+ "LinkMark",
4485
4163
  "URL"
4486
4164
  ]);
4487
4165
  if (!invalidPositions.has(node?.name)) {
@@ -4576,7 +4254,7 @@ var image = (_options = {}) => {
4576
4254
  return [
4577
4255
  import_state20.StateField.define({
4578
4256
  create: (state) => {
4579
- return import_view23.Decoration.set(buildDecorations(0, state.doc.length, state));
4257
+ return import_view22.Decoration.set(buildDecorations(0, state.doc.length, state));
4580
4258
  },
4581
4259
  update: (value, tr) => {
4582
4260
  if (!tr.docChanged && !tr.selection) {
@@ -4599,7 +4277,7 @@ var image = (_options = {}) => {
4599
4277
  add: buildDecorations(from, to, tr.state)
4600
4278
  });
4601
4279
  },
4602
- provide: (field) => import_view23.EditorView.decorations.from(field)
4280
+ provide: (field) => import_view22.EditorView.decorations.from(field)
4603
4281
  })
4604
4282
  ];
4605
4283
  };
@@ -4617,7 +4295,7 @@ var buildDecorations = (from, to, state) => {
4617
4295
  return;
4618
4296
  }
4619
4297
  preloadImage(url);
4620
- decorations.push(import_view23.Decoration.replace({
4298
+ decorations.push(import_view22.Decoration.replace({
4621
4299
  block: true,
4622
4300
  widget: new ImageWidget(url)
4623
4301
  }).range(hide2 ? node.from : node.to, node.to));
@@ -4637,7 +4315,7 @@ var preloadImage = (url) => {
4637
4315
  preloaded.add(url);
4638
4316
  }
4639
4317
  };
4640
- var ImageWidget = class extends import_view23.WidgetType {
4318
+ var ImageWidget = class extends import_view22.WidgetType {
4641
4319
  constructor(_url) {
4642
4320
  super();
4643
4321
  this._url = _url;
@@ -4659,7 +4337,7 @@ var ImageWidget = class extends import_view23.WidgetType {
4659
4337
  };
4660
4338
  var bulletListIndentationWidth = 24;
4661
4339
  var orderedListIndentationWidth = 36;
4662
- var formattingStyles = import_view24.EditorView.theme({
4340
+ var formattingStyles = import_view23.EditorView.theme({
4663
4341
  /**
4664
4342
  * Horizontal rule.
4665
4343
  */
@@ -4706,11 +4384,11 @@ var formattingStyles = import_view24.EditorView.theme({
4706
4384
  background: "var(--dx-cmCodeblock)",
4707
4385
  paddingInline: "1rem !important"
4708
4386
  },
4709
- "& .cm-codeblock-first": {
4387
+ "& .cm-codeblock-start": {
4710
4388
  borderTopLeftRadius: ".25rem",
4711
4389
  borderTopRightRadius: ".25rem"
4712
4390
  },
4713
- "& .cm-codeblock-last": {
4391
+ "& .cm-codeblock-end": {
4714
4392
  borderBottomLeftRadius: ".25rem",
4715
4393
  borderBottomRightRadius: ".25rem"
4716
4394
  },
@@ -4776,897 +4454,1522 @@ var formattingStyles = import_view24.EditorView.theme({
4776
4454
  }
4777
4455
  }
4778
4456
  });
4779
- var table = (options = {}) => {
4780
- return import_state21.StateField.define({
4781
- create: (state) => update(state, options),
4782
- update: (_, tr) => update(tr.state, options),
4783
- provide: (field) => import_view25.EditorView.decorations.from(field)
4784
- });
4457
+ var table = (options = {}) => {
4458
+ return import_state21.StateField.define({
4459
+ create: (state) => update(state, options),
4460
+ update: (_, tr) => update(tr.state, options),
4461
+ provide: (field) => import_view24.EditorView.decorations.from(field)
4462
+ });
4463
+ };
4464
+ var update = (state, _options) => {
4465
+ const builder = new import_state21.RangeSetBuilder();
4466
+ const cursor = state.selection.main.head;
4467
+ const tables = [];
4468
+ const getTable = () => tables[tables.length - 1];
4469
+ const getRow = () => {
4470
+ const table2 = getTable();
4471
+ return table2.rows?.[table2.rows.length - 1];
4472
+ };
4473
+ (0, import_language11.syntaxTree)(state).iterate({
4474
+ enter: (node) => {
4475
+ switch (node.name) {
4476
+ case "Table": {
4477
+ tables.push({
4478
+ from: node.from,
4479
+ to: node.to
4480
+ });
4481
+ break;
4482
+ }
4483
+ case "TableHeader": {
4484
+ getTable().header = [];
4485
+ break;
4486
+ }
4487
+ case "TableRow": {
4488
+ (getTable().rows ??= []).push([]);
4489
+ break;
4490
+ }
4491
+ case "TableCell": {
4492
+ const row = getRow();
4493
+ if (row) {
4494
+ row.push(state.sliceDoc(node.from, node.to));
4495
+ } else {
4496
+ getTable().header?.push(state.sliceDoc(node.from, node.to));
4497
+ }
4498
+ break;
4499
+ }
4500
+ }
4501
+ }
4502
+ });
4503
+ tables.forEach((table2) => {
4504
+ const replace = state.readOnly || cursor < table2.from || cursor > table2.to;
4505
+ if (replace) {
4506
+ builder.add(table2.from, table2.to, import_view24.Decoration.replace({
4507
+ block: true,
4508
+ widget: new TableWidget(table2)
4509
+ }));
4510
+ } else {
4511
+ builder.add(table2.from, table2.to, import_view24.Decoration.mark({
4512
+ class: "cm-table"
4513
+ }));
4514
+ }
4515
+ });
4516
+ return builder.finish();
4517
+ };
4518
+ var TableWidget = class extends import_view24.WidgetType {
4519
+ constructor(_table) {
4520
+ super();
4521
+ this._table = _table;
4522
+ }
4523
+ eq(other) {
4524
+ return this._table.header?.join() === other._table.header?.join() && this._table.rows?.join() === other._table.rows?.join();
4525
+ }
4526
+ toDOM(view) {
4527
+ const div = document.createElement("div");
4528
+ const table2 = div.appendChild(document.createElement("table"));
4529
+ const header = table2.appendChild(document.createElement("thead"));
4530
+ const tr = header.appendChild(document.createElement("tr"));
4531
+ this._table.header?.forEach((cell) => {
4532
+ const th = document.createElement("th");
4533
+ th.setAttribute("class", "cm-table-head");
4534
+ tr.appendChild(th).textContent = cell;
4535
+ });
4536
+ const body = table2.appendChild(document.createElement("tbody"));
4537
+ this._table.rows?.forEach((row) => {
4538
+ const tr2 = body.appendChild(document.createElement("tr"));
4539
+ row.forEach((cell) => {
4540
+ const td = document.createElement("td");
4541
+ td.setAttribute("class", "cm-table-cell");
4542
+ tr2.appendChild(td).textContent = cell;
4543
+ });
4544
+ });
4545
+ return div;
4546
+ }
4547
+ ignoreEvent(e) {
4548
+ return !/^mouse/.test(e.type);
4549
+ }
4550
+ };
4551
+ var __dxlog_file9 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/markdown/decorate.ts";
4552
+ var Unicode = {
4553
+ emDash: "\u2014",
4554
+ bullet: "\u2022",
4555
+ bulletSmall: "\u2219",
4556
+ bulletSquare: "\u2B1D"
4557
+ };
4558
+ var HorizontalRuleWidget = class extends import_view20.WidgetType {
4559
+ toDOM() {
4560
+ const el = document.createElement("span");
4561
+ el.className = "cm-hr";
4562
+ return el;
4563
+ }
4564
+ };
4565
+ var LinkButton = class extends import_view20.WidgetType {
4566
+ constructor(url, render) {
4567
+ super();
4568
+ this.url = url;
4569
+ this.render = render;
4570
+ }
4571
+ eq(other) {
4572
+ return this.url === other.url;
4573
+ }
4574
+ // TODO(burdon): Create icon and link directly without react?
4575
+ toDOM(view) {
4576
+ const el = document.createElement("span");
4577
+ this.render(el, {
4578
+ url: this.url
4579
+ }, view);
4580
+ return el;
4581
+ }
4582
+ };
4583
+ var CheckboxWidget = class extends import_view20.WidgetType {
4584
+ constructor(_checked) {
4585
+ super();
4586
+ this._checked = _checked;
4587
+ }
4588
+ eq(other) {
4589
+ return this._checked === other._checked;
4590
+ }
4591
+ toDOM(view) {
4592
+ const input = document.createElement("input");
4593
+ input.className = "cm-task-checkbox dx-checkbox";
4594
+ input.type = "checkbox";
4595
+ input.tabIndex = -1;
4596
+ input.checked = this._checked;
4597
+ if (view.state.readOnly) {
4598
+ input.setAttribute("disabled", "true");
4599
+ } else {
4600
+ input.onmousedown = (event) => {
4601
+ const line = view.state.doc.lineAt(view.posAtDOM(span));
4602
+ const text = view.state.sliceDoc(line.from, line.to);
4603
+ const match = text.match(/^\s*- (\[[xX ]]).*/);
4604
+ if (match) {
4605
+ const [, checked] = match;
4606
+ const pos = line.from + text.indexOf(checked);
4607
+ this._checked = checked !== "[ ]";
4608
+ view.dispatch({
4609
+ changes: {
4610
+ from: pos + 1,
4611
+ to: pos + 2,
4612
+ insert: this._checked ? " " : "x"
4613
+ }
4614
+ });
4615
+ event.preventDefault();
4616
+ }
4617
+ };
4618
+ }
4619
+ const span = document.createElement("span");
4620
+ span.className = "cm-task";
4621
+ span.appendChild(input);
4622
+ return span;
4623
+ }
4624
+ ignoreEvent() {
4625
+ return false;
4626
+ }
4627
+ };
4628
+ var TextWidget = class extends import_view20.WidgetType {
4629
+ constructor(text, className) {
4630
+ super();
4631
+ this.text = text;
4632
+ this.className = className;
4633
+ }
4634
+ toDOM() {
4635
+ const el = document.createElement("span");
4636
+ if (this.className) {
4637
+ el.className = this.className;
4638
+ }
4639
+ el.innerText = this.text;
4640
+ return el;
4641
+ }
4642
+ };
4643
+ var hide = import_view20.Decoration.replace({});
4644
+ var blockQuote = import_view20.Decoration.line({
4645
+ class: "cm-blockquote"
4646
+ });
4647
+ var fencedCodeLine = import_view20.Decoration.line({
4648
+ class: "cm-code cm-codeblock-line"
4649
+ });
4650
+ var fencedCodeLineFirst = import_view20.Decoration.line({
4651
+ class: (0, import_react_ui_theme5.mx)("cm-code cm-codeblock-line", "cm-codeblock-start")
4652
+ });
4653
+ var fencedCodeLineLast = import_view20.Decoration.line({
4654
+ class: (0, import_react_ui_theme5.mx)("cm-code cm-codeblock-line", "cm-codeblock-end")
4655
+ });
4656
+ var commentBlockLine = fencedCodeLine;
4657
+ var commentBlockLineFirst = fencedCodeLineFirst;
4658
+ var commentBlockLineLast = fencedCodeLineLast;
4659
+ var horizontalRule = import_view20.Decoration.replace({
4660
+ widget: new HorizontalRuleWidget()
4661
+ });
4662
+ var checkedTask = import_view20.Decoration.replace({
4663
+ widget: new CheckboxWidget(true)
4664
+ });
4665
+ var uncheckedTask = import_view20.Decoration.replace({
4666
+ widget: new CheckboxWidget(false)
4667
+ });
4668
+ var editingRange = (state, range, focus2) => {
4669
+ const { readOnly, selection: { main: { head } } } = state;
4670
+ return focus2 && !readOnly && head >= range.from && head <= range.to;
4785
4671
  };
4786
- var update = (state, _options) => {
4787
- const builder = new import_state21.RangeSetBuilder();
4788
- const cursor = state.selection.main.head;
4789
- const tables = [];
4790
- const getTable = () => tables[tables.length - 1];
4791
- const getRow = () => {
4792
- const table2 = getTable();
4793
- return table2.rows?.[table2.rows.length - 1];
4672
+ var autoHideTags = /* @__PURE__ */ new Set([
4673
+ "CodeMark",
4674
+ "CodeInfo",
4675
+ "EmphasisMark",
4676
+ "StrikethroughMark",
4677
+ "SubscriptMark",
4678
+ "SuperscriptMark"
4679
+ ]);
4680
+ var buildDecorations2 = (view, options, focus2) => {
4681
+ const deco = new import_state18.RangeSetBuilder();
4682
+ const atomicDeco = new import_state18.RangeSetBuilder();
4683
+ const { state } = view;
4684
+ const headerLevels = [];
4685
+ const getHeaderLevels = (node, level) => {
4686
+ (0, import_invariant4.invariant)(level > 0, void 0, {
4687
+ F: __dxlog_file9,
4688
+ L: 179,
4689
+ S: void 0,
4690
+ A: [
4691
+ "level > 0",
4692
+ ""
4693
+ ]
4694
+ });
4695
+ if (level > headerLevels.length) {
4696
+ const len = headerLevels.length;
4697
+ headerLevels.length = level;
4698
+ headerLevels.fill(null, len);
4699
+ headerLevels[level - 1] = {
4700
+ type: node.name,
4701
+ from: node.from,
4702
+ to: node.to,
4703
+ level,
4704
+ number: 0
4705
+ };
4706
+ } else {
4707
+ headerLevels.splice(level);
4708
+ }
4709
+ return headerLevels.slice(0, level);
4794
4710
  };
4795
- (0, import_language11.syntaxTree)(state).iterate({
4796
- enter: (node) => {
4797
- switch (node.name) {
4798
- case "Table": {
4799
- tables.push({
4800
- from: node.from,
4801
- to: node.to
4802
- });
4711
+ const listLevels = [];
4712
+ const enterList = (node) => {
4713
+ listLevels.push({
4714
+ type: node.name,
4715
+ from: node.from,
4716
+ to: node.to,
4717
+ level: listLevels.length,
4718
+ number: 0
4719
+ });
4720
+ };
4721
+ const leaveList = () => {
4722
+ listLevels.pop();
4723
+ };
4724
+ const getCurrentListLevel = () => {
4725
+ (0, import_invariant4.invariant)(listLevels.length, void 0, {
4726
+ F: __dxlog_file9,
4727
+ L: 201,
4728
+ S: void 0,
4729
+ A: [
4730
+ "listLevels.length",
4731
+ ""
4732
+ ]
4733
+ });
4734
+ return listLevels[listLevels.length - 1];
4735
+ };
4736
+ const enterNode = (node) => {
4737
+ switch (node.name) {
4738
+ // ATXHeading > HeaderMark > Paragraph
4739
+ // NOTE: Numbering requires processing the entire document since otherwise only the visible range will be
4740
+ // processed and the numbering will be incorrect.
4741
+ case "ATXHeading1":
4742
+ case "ATXHeading2":
4743
+ case "ATXHeading3":
4744
+ case "ATXHeading4":
4745
+ case "ATXHeading5":
4746
+ case "ATXHeading6": {
4747
+ const level = parseInt(node.name["ATXHeading".length]);
4748
+ const headers = getHeaderLevels(node, level);
4749
+ if (options.numberedHeadings?.from !== void 0) {
4750
+ const header = headers[level - 1];
4751
+ if (header) {
4752
+ header.number++;
4753
+ }
4754
+ }
4755
+ const editing = editingRange(state, node, focus2);
4756
+ if (editing) {
4803
4757
  break;
4804
4758
  }
4805
- case "TableHeader": {
4806
- getTable().header = [];
4759
+ const mark = node.node.firstChild;
4760
+ if (mark?.name === "HeaderMark") {
4761
+ const { from, to = 6 } = options.numberedHeadings ?? {};
4762
+ const text = view.state.sliceDoc(node.from, node.to);
4763
+ const len = text.match(/[#\s]+/)[0].length;
4764
+ if (!from || level < from || level > to) {
4765
+ atomicDeco.add(mark.from, mark.from + len, hide);
4766
+ } else {
4767
+ const num = headers.slice(from - 1).map((level2) => level2?.number ?? 0).join(".") + " ";
4768
+ if (num.length) {
4769
+ atomicDeco.add(mark.from, mark.from + len, import_view20.Decoration.replace({
4770
+ widget: new TextWidget(num, theme.heading(level))
4771
+ }));
4772
+ }
4773
+ }
4774
+ }
4775
+ return false;
4776
+ }
4777
+ //
4778
+ // Lists.
4779
+ // [BulletList | OrderedList] > (ListItem > ListMark) > (Task > TaskMarker)?
4780
+ //
4781
+ case "BulletList":
4782
+ case "OrderedList": {
4783
+ enterList(node);
4784
+ break;
4785
+ }
4786
+ case "ListItem": {
4787
+ const line = state.doc.lineAt(node.from);
4788
+ const list = getCurrentListLevel();
4789
+ const width = list.type === "OrderedList" ? orderedListIndentationWidth : bulletListIndentationWidth;
4790
+ const offset = (options?.listPaddingLeft ?? 0) + ((list.level ?? 0) + 1) * width;
4791
+ if (node.from === line.to - 1) {
4792
+ return false;
4793
+ }
4794
+ deco.add(line.from, line.from, import_view20.Decoration.line({
4795
+ class: "cm-list-item",
4796
+ attributes: {
4797
+ style: `padding-left: ${offset}px; text-indent: -${width}px;`
4798
+ }
4799
+ }));
4800
+ break;
4801
+ }
4802
+ case "ListMark": {
4803
+ const list = getCurrentListLevel();
4804
+ const next = tree.resolve(node.to + 1, 1);
4805
+ if (next?.name === "TaskMarker") {
4807
4806
  break;
4808
4807
  }
4809
- case "TableRow": {
4810
- (getTable().rows ??= []).push([]);
4811
- break;
4808
+ const label = list.type === "OrderedList" ? `${++list.number}.` : Unicode.bulletSmall;
4809
+ const line = state.doc.lineAt(node.from);
4810
+ const to = state.doc.sliceString(node.to, node.to + 1) === " " ? node.to + 1 : node.to;
4811
+ atomicDeco.add(line.from, to, import_view20.Decoration.replace({
4812
+ widget: new TextWidget(label, list.type === "OrderedList" ? "cm-list-mark cm-list-mark-ordered" : "cm-list-mark cm-list-mark-bullet")
4813
+ }));
4814
+ break;
4815
+ }
4816
+ case "TaskMarker": {
4817
+ const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
4818
+ const line = state.doc.lineAt(node.from);
4819
+ const to = state.doc.sliceString(node.to, node.to + 1) === " " ? node.to + 1 : node.to;
4820
+ atomicDeco.add(line.from, to, checked ? checkedTask : uncheckedTask);
4821
+ break;
4822
+ }
4823
+ //
4824
+ // Blockquote > QuoteMark > Paragraph
4825
+ //
4826
+ case "Blockquote": {
4827
+ const editing = editingRange(state, node, focus2);
4828
+ const quoteMark = node.node.getChild("QuoteMark");
4829
+ const paragraph = node.node.getChild("Paragraph");
4830
+ if (!editing && quoteMark && paragraph) {
4831
+ atomicDeco.add(quoteMark.from, paragraph.from, hide);
4812
4832
  }
4813
- case "TableCell": {
4814
- const row = getRow();
4815
- if (row) {
4816
- row.push(state.sliceDoc(node.from, node.to));
4817
- } else {
4818
- getTable().header?.push(state.sliceDoc(node.from, node.to));
4833
+ for (const block of view.viewportLineBlocks) {
4834
+ if (block.to < node.from) {
4835
+ continue;
4836
+ }
4837
+ if (block.from > node.to) {
4838
+ break;
4839
+ }
4840
+ deco.add(block.from, block.from, blockQuote);
4841
+ }
4842
+ break;
4843
+ }
4844
+ //
4845
+ // CommentBlock
4846
+ //
4847
+ case "CommentBlock": {
4848
+ const editing = editingRange(state, node, focus2);
4849
+ for (const block of view.viewportLineBlocks) {
4850
+ if (block.to < node.from) {
4851
+ continue;
4852
+ }
4853
+ if (block.from > node.to) {
4854
+ break;
4855
+ }
4856
+ const isFirst = block.from <= node.from;
4857
+ const isLast = block.to >= node.to && /^(\s>)*-->$/.test(state.doc.sliceString(block.from, block.to));
4858
+ deco.add(block.from, block.from, isFirst ? commentBlockLineFirst : isLast ? commentBlockLineLast : commentBlockLine);
4859
+ if (!editing && (isFirst || isLast)) {
4860
+ atomicDeco.add(block.from, block.to, hide);
4861
+ }
4862
+ }
4863
+ break;
4864
+ }
4865
+ //
4866
+ // FencedCode > CodeMark > [CodeInfo] > CodeText > CodeMark
4867
+ //
4868
+ case "FencedCode": {
4869
+ for (const block of view.viewportLineBlocks) {
4870
+ if (block.to < node.from) {
4871
+ continue;
4872
+ }
4873
+ if (block.from > node.to) {
4874
+ break;
4875
+ }
4876
+ const first = block.from <= node.from;
4877
+ const last = block.to >= node.to && /```$/.test(state.doc.sliceString(block.from, block.to));
4878
+ deco.add(block.from, block.from, first ? fencedCodeLineFirst : last ? fencedCodeLineLast : fencedCodeLine);
4879
+ const editing = editingRange(state, node, focus2);
4880
+ if (!editing && (first || last)) {
4881
+ atomicDeco.add(block.from, block.to, hide);
4882
+ }
4883
+ }
4884
+ return false;
4885
+ }
4886
+ //
4887
+ // Link > [LinkMark, URL]
4888
+ //
4889
+ case "Link": {
4890
+ const marks = node.node.getChildren("LinkMark");
4891
+ const urlNode = node.node.getChild("URL");
4892
+ const editing = editingRange(state, node, focus2);
4893
+ if (urlNode && marks.length >= 2) {
4894
+ const url = state.sliceDoc(urlNode.from, urlNode.to);
4895
+ if (!editing) {
4896
+ atomicDeco.add(node.from, marks[0].to, hide);
4897
+ }
4898
+ deco.add(marks[0].to, marks[1].from, import_view20.Decoration.mark({
4899
+ tagName: "a",
4900
+ attributes: {
4901
+ class: "cm-link",
4902
+ href: url,
4903
+ rel: "noreferrer",
4904
+ target: "_blank"
4905
+ }
4906
+ }));
4907
+ if (!editing) {
4908
+ atomicDeco.add(marks[1].from, node.to, options.renderLinkButton ? import_view20.Decoration.replace({
4909
+ widget: new LinkButton(url, options.renderLinkButton)
4910
+ }) : hide);
4911
+ }
4912
+ }
4913
+ break;
4914
+ }
4915
+ //
4916
+ // HR
4917
+ //
4918
+ case "HorizontalRule": {
4919
+ if (!editingRange(state, node, focus2)) {
4920
+ deco.add(node.from, node.to, horizontalRule);
4921
+ }
4922
+ break;
4923
+ }
4924
+ default: {
4925
+ if (autoHideTags.has(node.name)) {
4926
+ if (!editingRange(state, node.node.parent, focus2)) {
4927
+ atomicDeco.add(node.from, node.to, hide);
4819
4928
  }
4820
- break;
4821
4929
  }
4822
4930
  }
4823
4931
  }
4824
- });
4825
- tables.forEach((table2) => {
4826
- const replace = state.readOnly || cursor < table2.from || cursor > table2.to;
4827
- if (replace) {
4828
- builder.add(table2.from, table2.to, import_view25.Decoration.replace({
4829
- block: true,
4830
- widget: new TableWidget(table2)
4831
- }));
4832
- } else {
4833
- builder.add(table2.from, table2.to, import_view25.Decoration.mark({
4834
- class: "cm-table"
4835
- }));
4932
+ };
4933
+ const leaveNode = (node) => {
4934
+ switch (node.name) {
4935
+ case "BulletList":
4936
+ case "OrderedList": {
4937
+ leaveList();
4938
+ break;
4939
+ }
4836
4940
  }
4837
- });
4838
- return builder.finish();
4839
- };
4840
- var TableWidget = class extends import_view25.WidgetType {
4841
- constructor(_table) {
4842
- super();
4843
- this._table = _table;
4844
- }
4845
- eq(other) {
4846
- return this._table.header?.join() === other._table.header?.join() && this._table.rows?.join() === other._table.rows?.join();
4847
- }
4848
- toDOM(view) {
4849
- const div = document.createElement("div");
4850
- const table2 = div.appendChild(document.createElement("table"));
4851
- const header = table2.appendChild(document.createElement("thead"));
4852
- const tr = header.appendChild(document.createElement("tr"));
4853
- this._table.header?.forEach((cell) => {
4854
- const th = document.createElement("th");
4855
- th.setAttribute("class", "cm-table-head");
4856
- tr.appendChild(th).textContent = cell;
4857
- });
4858
- const body = table2.appendChild(document.createElement("tbody"));
4859
- this._table.rows?.forEach((row) => {
4860
- const tr2 = body.appendChild(document.createElement("tr"));
4861
- row.forEach((cell) => {
4862
- const td = document.createElement("td");
4863
- td.setAttribute("class", "cm-table-cell");
4864
- tr2.appendChild(td).textContent = cell;
4941
+ };
4942
+ const tree = (0, import_language8.syntaxTree)(state);
4943
+ if (options.numberedHeadings?.from === void 0) {
4944
+ for (const { from, to } of view.visibleRanges) {
4945
+ tree.iterate({
4946
+ from,
4947
+ to,
4948
+ enter: wrapWithCatch(enterNode),
4949
+ leave: wrapWithCatch(leaveNode)
4865
4950
  });
4951
+ }
4952
+ } else {
4953
+ tree.iterate({
4954
+ enter: wrapWithCatch(enterNode),
4955
+ leave: wrapWithCatch(leaveNode)
4866
4956
  });
4867
- return div;
4868
- }
4869
- ignoreEvent(e) {
4870
- return !/^mouse/.test(e.type);
4871
- }
4872
- };
4873
- var __dxlog_file9 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/markdown/decorate.ts";
4874
- var Unicode = {
4875
- emDash: "\u2014",
4876
- bullet: "\u2022",
4877
- bulletSmall: "\u2219",
4878
- bulletSquare: "\u2B1D"
4879
- };
4880
- var HorizontalRuleWidget = class extends import_view21.WidgetType {
4881
- toDOM() {
4882
- const el = document.createElement("span");
4883
- el.className = "cm-hr";
4884
- return el;
4885
- }
4886
- };
4887
- var LinkButton = class extends import_view21.WidgetType {
4888
- constructor(url, render) {
4889
- super();
4890
- this.url = url;
4891
- this.render = render;
4892
- }
4893
- eq(other) {
4894
- return this.url === other.url;
4895
- }
4896
- // TODO(burdon): Create icon and link directly without react?
4897
- toDOM(view) {
4898
- const el = document.createElement("span");
4899
- this.render(el, {
4900
- url: this.url
4901
- }, view);
4902
- return el;
4903
4957
  }
4958
+ return {
4959
+ deco: deco.finish(),
4960
+ atomicDeco: atomicDeco.finish()
4961
+ };
4904
4962
  };
4905
- var CheckboxWidget = class extends import_view21.WidgetType {
4906
- constructor(_checked) {
4907
- super();
4908
- this._checked = _checked;
4909
- }
4910
- eq(other) {
4911
- return this._checked === other._checked;
4912
- }
4913
- toDOM(view) {
4914
- const input = document.createElement("input");
4915
- input.className = "cm-task-checkbox dx-checkbox";
4916
- input.type = "checkbox";
4917
- input.tabIndex = -1;
4918
- input.checked = this._checked;
4919
- if (view.state.readOnly) {
4920
- input.setAttribute("disabled", "true");
4921
- } else {
4922
- input.onmousedown = (event) => {
4923
- const line = view.state.doc.lineAt(view.posAtDOM(span));
4924
- const text = view.state.sliceDoc(line.from, line.to);
4925
- const match = text.match(/^\s*- (\[[xX ]]).*/);
4926
- if (match) {
4927
- const [, checked] = match;
4928
- const pos = line.from + text.indexOf(checked);
4929
- this._checked = checked !== "[ ]";
4963
+ var forceUpdate = import_state18.StateEffect.define();
4964
+ var decorateMarkdown = (options = {}) => {
4965
+ return [
4966
+ import_view20.ViewPlugin.fromClass(class {
4967
+ constructor(view) {
4968
+ ({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations2(view, options, view.hasFocus));
4969
+ }
4970
+ update(update2) {
4971
+ if (update2.docChanged || update2.viewportChanged || update2.focusChanged || update2.transactions.some((tr) => tr.effects.some((effect) => effect.is(forceUpdate))) || update2.selectionSet && !options.selectionChangeDelay) {
4972
+ ({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations2(update2.view, options, update2.view.hasFocus));
4973
+ this.clearUpdate();
4974
+ } else if (update2.selectionSet) {
4975
+ this.scheduleUpdate(update2.view);
4976
+ }
4977
+ }
4978
+ // Defer update in case moving through the document.
4979
+ scheduleUpdate(view) {
4980
+ this.clearUpdate();
4981
+ this.pendingUpdate = setTimeout(() => {
4930
4982
  view.dispatch({
4931
- changes: {
4932
- from: pos + 1,
4933
- to: pos + 2,
4934
- insert: this._checked ? " " : "x"
4935
- }
4983
+ effects: forceUpdate.of(null)
4936
4984
  });
4937
- event.preventDefault();
4985
+ }, options.selectionChangeDelay);
4986
+ }
4987
+ clearUpdate() {
4988
+ if (this.pendingUpdate) {
4989
+ clearTimeout(this.pendingUpdate);
4990
+ this.pendingUpdate = void 0;
4938
4991
  }
4939
- };
4940
- }
4941
- const span = document.createElement("span");
4942
- span.className = "cm-task";
4943
- span.appendChild(input);
4944
- return span;
4945
- }
4946
- ignoreEvent() {
4947
- return false;
4948
- }
4992
+ }
4993
+ destroy() {
4994
+ this.clearUpdate();
4995
+ }
4996
+ }, {
4997
+ provide: (plugin) => [
4998
+ import_view20.EditorView.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? import_view20.Decoration.none),
4999
+ import_view20.EditorView.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? import_view20.Decoration.none),
5000
+ import_view20.EditorView.decorations.of((view) => view.plugin(plugin)?.deco ?? import_view20.Decoration.none)
5001
+ ]
5002
+ }),
5003
+ image(),
5004
+ table(),
5005
+ adjustChanges(),
5006
+ formattingStyles
5007
+ ];
4949
5008
  };
4950
- var TextWidget = class extends import_view21.WidgetType {
4951
- constructor(text, className) {
4952
- super();
4953
- this.text = text;
4954
- this.className = className;
4955
- }
4956
- toDOM() {
4957
- const el = document.createElement("span");
4958
- if (this.className) {
4959
- el.className = this.className;
5009
+ var linkTooltip = (renderTooltip) => {
5010
+ return (0, import_view25.hoverTooltip)((view, pos, side) => {
5011
+ const syntax = (0, import_language12.syntaxTree)(view.state).resolveInner(pos, side);
5012
+ let link = null;
5013
+ for (let i = 0, node = syntax; !link && node && i < 5; node = node.parent, i++) {
5014
+ link = node.name === "Link" ? node : null;
4960
5015
  }
4961
- el.innerText = this.text;
4962
- return el;
4963
- }
5016
+ const url = link && link.getChild("URL");
5017
+ if (!url || !link) {
5018
+ return null;
5019
+ }
5020
+ const urlText = view.state.sliceDoc(url.from, url.to);
5021
+ return {
5022
+ pos: link.from,
5023
+ end: link.to,
5024
+ // NOTE: Forcing above causes the tooltip to flicker.
5025
+ // above: true,
5026
+ create: () => {
5027
+ const el = document.createElement("div");
5028
+ el.className = (0, import_react_ui_theme6.tooltipContent)({});
5029
+ renderTooltip(el, {
5030
+ url: urlText
5031
+ }, view);
5032
+ return {
5033
+ dom: el,
5034
+ offset: {
5035
+ x: 0,
5036
+ y: 4
5037
+ }
5038
+ };
5039
+ }
5040
+ };
5041
+ }, {
5042
+ // NOTE: 0 = default of 300ms.
5043
+ hoverTime: 1
5044
+ });
4964
5045
  };
4965
- var hide = import_view21.Decoration.replace({});
4966
- var blockQuote = import_view21.Decoration.line({
4967
- class: (0, import_react_ui_theme6.mx)("cm-blockquote")
4968
- });
4969
- var fencedCodeLine = import_view21.Decoration.line({
4970
- class: (0, import_react_ui_theme6.mx)("cm-code cm-codeblock-line")
4971
- });
4972
- var fencedCodeLineFirst = import_view21.Decoration.line({
4973
- class: (0, import_react_ui_theme6.mx)("cm-code cm-codeblock-line", "cm-codeblock-first")
4974
- });
4975
- var fencedCodeLineLast = import_view21.Decoration.line({
4976
- class: (0, import_react_ui_theme6.mx)("cm-code cm-codeblock-line", "cm-codeblock-last")
4977
- });
4978
- var commentBlockLine = fencedCodeLine;
4979
- var commentBlockLineFirst = fencedCodeLineFirst;
4980
- var commentBlockLineLast = fencedCodeLineLast;
4981
- var horizontalRule = import_view21.Decoration.replace({
4982
- widget: new HorizontalRuleWidget()
4983
- });
4984
- var checkedTask = import_view21.Decoration.replace({
4985
- widget: new CheckboxWidget(true)
4986
- });
4987
- var uncheckedTask = import_view21.Decoration.replace({
4988
- widget: new CheckboxWidget(false)
4989
- });
4990
- var editingRange = (state, range, focus2) => {
4991
- const { readOnly, selection: { main: { head } } } = state;
4992
- return focus2 && !readOnly && head >= range.from && head <= range.to;
5046
+ var __dxlog_file10 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/markdown/outliner.ts";
5047
+ var indentLevel = 2;
5048
+ var matchTaskMarker = /^\s*- (\[ \]|\[x\])? /;
5049
+ var getLineInfo = (line) => {
5050
+ const match = line.text.match(matchTaskMarker);
5051
+ const start = line.from + (match?.[0]?.length ?? 0);
5052
+ return {
5053
+ match,
5054
+ start
5055
+ };
4993
5056
  };
4994
- var autoHideTags = /* @__PURE__ */ new Set([
4995
- "CodeMark",
4996
- "CodeInfo",
4997
- "EmphasisMark",
4998
- "StrikethroughMark",
4999
- "SubscriptMark",
5000
- "SuperscriptMark"
5001
- ]);
5002
- var buildDecorations2 = (view, options, focus2) => {
5003
- const deco = new import_state18.RangeSetBuilder();
5004
- const atomicDeco = new import_state18.RangeSetBuilder();
5005
- const { state } = view;
5006
- const headerLevels = [];
5007
- const getHeaderLevels = (node, level) => {
5008
- (0, import_invariant4.invariant)(level > 0, void 0, {
5009
- F: __dxlog_file9,
5010
- L: 179,
5011
- S: void 0,
5012
- A: [
5013
- "level > 0",
5014
- ""
5015
- ]
5016
- });
5017
- if (level > headerLevels.length) {
5018
- const len = headerLevels.length;
5019
- headerLevels.length = level;
5020
- headerLevels.fill(null, len);
5021
- headerLevels[level - 1] = {
5022
- type: node.name,
5023
- from: node.from,
5024
- to: node.to,
5025
- level,
5026
- number: 0
5027
- };
5028
- } else {
5029
- headerLevels.splice(level);
5057
+ var outliner = () => [
5058
+ import_state22.EditorState.transactionFilter.of((tr) => {
5059
+ if (!tr.docChanged) {
5060
+ const pos = tr.selection?.ranges[tr.selection?.mainIndex]?.from;
5061
+ if (pos != null) {
5062
+ const { match, start } = getLineInfo(tr.startState.doc.lineAt(pos));
5063
+ if (match) {
5064
+ if (pos < start) {
5065
+ return [
5066
+ {
5067
+ selection: {
5068
+ anchor: start,
5069
+ head: start
5070
+ }
5071
+ }
5072
+ ];
5073
+ }
5074
+ }
5075
+ }
5076
+ return tr;
5030
5077
  }
5031
- return headerLevels.slice(0, level);
5032
- };
5033
- const listLevels = [];
5034
- const enterList = (node) => {
5035
- listLevels.push({
5036
- type: node.name,
5037
- from: node.from,
5038
- to: node.to,
5039
- level: listLevels.length,
5040
- number: 0
5041
- });
5042
- };
5043
- const leaveList = () => {
5044
- listLevels.pop();
5045
- };
5046
- const getCurrentListLevel = () => {
5047
- (0, import_invariant4.invariant)(listLevels.length, void 0, {
5048
- F: __dxlog_file9,
5049
- L: 201,
5050
- S: void 0,
5051
- A: [
5052
- "listLevels.length",
5053
- ""
5054
- ]
5055
- });
5056
- return listLevels[listLevels.length - 1];
5057
- };
5058
- const enterNode = (node) => {
5059
- switch (node.name) {
5060
- // ATXHeading > HeaderMark > Paragraph
5061
- // NOTE: Numbering requires processing the entire document since otherwise only the visible range will be
5062
- // processed and the numbering will be incorrect.
5063
- case "ATXHeading1":
5064
- case "ATXHeading2":
5065
- case "ATXHeading3":
5066
- case "ATXHeading4":
5067
- case "ATXHeading5":
5068
- case "ATXHeading6": {
5069
- const level = parseInt(node.name["ATXHeading".length]);
5070
- const headers = getHeaderLevels(node, level);
5071
- if (options.numberedHeadings?.from !== void 0) {
5072
- const header = headers[level - 1];
5073
- if (header) {
5074
- header.number++;
5078
+ const changes = [];
5079
+ tr.changes.iterChanges((fromA, toA, fromB, toB, insert) => {
5080
+ const line = tr.startState.doc.lineAt(fromA);
5081
+ const isTaskMarker = line.text.match(matchTaskMarker);
5082
+ if (isTaskMarker) {
5083
+ const { start } = getLineInfo(line);
5084
+ const replace = start === toA && toA - fromA === insert.length;
5085
+ if (replace) {
5086
+ import_log6.log.info("delete line", void 0, {
5087
+ F: __dxlog_file10,
5088
+ L: 82,
5089
+ S: void 0,
5090
+ C: (f, a) => f(...a)
5091
+ });
5092
+ changes.push({
5093
+ from: line.from - 1,
5094
+ to: toA
5095
+ });
5096
+ return;
5097
+ }
5098
+ if (fromB === toB) {
5099
+ if (toA === line.to) {
5100
+ const line2 = tr.state.doc.lineAt(fromA);
5101
+ if (line2.text.match(/^\s*$/)) {
5102
+ if (line2.from === 0) {
5103
+ import_log6.log.info("skip", void 0, {
5104
+ F: __dxlog_file10,
5105
+ L: 94,
5106
+ S: void 0,
5107
+ C: (f, a) => f(...a)
5108
+ });
5109
+ changes.push({
5110
+ from: 0,
5111
+ to: 0
5112
+ });
5113
+ return;
5114
+ } else {
5115
+ import_log6.log.info("delete line", void 0, {
5116
+ F: __dxlog_file10,
5117
+ L: 99,
5118
+ S: void 0,
5119
+ C: (f, a) => f(...a)
5120
+ });
5121
+ changes.push({
5122
+ from: line2.from - 1,
5123
+ to: toA
5124
+ });
5125
+ return;
5126
+ }
5127
+ }
5075
5128
  }
5129
+ return;
5076
5130
  }
5077
- const editing = editingRange(state, node, focus2);
5078
- if (editing) {
5079
- break;
5131
+ if (insert.length === indentLevel) {
5132
+ if (line.number === 1) {
5133
+ import_log6.log.info("skip", void 0, {
5134
+ F: __dxlog_file10,
5135
+ L: 111,
5136
+ S: void 0,
5137
+ C: (f, a) => f(...a)
5138
+ });
5139
+ changes.push({
5140
+ from: 0,
5141
+ to: 0
5142
+ });
5143
+ return;
5144
+ } else {
5145
+ const getIndent = (text) => (text.match(/^\s*/)?.[0]?.length ?? 0) / indentLevel;
5146
+ const currentIndent = getIndent(line.text);
5147
+ const indentPrevious = getIndent(tr.state.doc.lineAt(fromA - 1).text);
5148
+ if (currentIndent > indentPrevious) {
5149
+ import_log6.log.info("skip", void 0, {
5150
+ F: __dxlog_file10,
5151
+ L: 119,
5152
+ S: void 0,
5153
+ C: (f, a) => f(...a)
5154
+ });
5155
+ changes.push({
5156
+ from: 0,
5157
+ to: 0
5158
+ });
5159
+ return;
5160
+ }
5161
+ }
5162
+ }
5163
+ import_log6.log.info("change", {
5164
+ line: {
5165
+ from: line.from,
5166
+ to: line.to
5167
+ },
5168
+ start,
5169
+ a: [
5170
+ fromA,
5171
+ toA
5172
+ ],
5173
+ b: [
5174
+ fromB,
5175
+ toB
5176
+ ],
5177
+ insert: {
5178
+ text: insert.toString(),
5179
+ length: insert.length
5180
+ }
5181
+ }, {
5182
+ F: __dxlog_file10,
5183
+ L: 134,
5184
+ S: void 0,
5185
+ C: (f, a) => f(...a)
5186
+ });
5187
+ }
5188
+ });
5189
+ if (changes.length > 0) {
5190
+ return [
5191
+ {
5192
+ changes
5193
+ }
5194
+ ];
5195
+ }
5196
+ return tr;
5197
+ }),
5198
+ import_state22.StateField.define({
5199
+ create: (state) => {
5200
+ return import_view26.Decoration.set(buildDecorations3(0, state.doc.length, state));
5201
+ },
5202
+ update: (value, tr) => {
5203
+ const from = 0;
5204
+ const to = tr.state.doc.length;
5205
+ return value.map(tr.changes).update({
5206
+ filterFrom: 0,
5207
+ filterTo: tr.state.doc.length,
5208
+ filter: () => false,
5209
+ add: buildDecorations3(from, to, tr.state)
5210
+ });
5211
+ },
5212
+ provide: (field) => import_view26.EditorView.decorations.from(field)
5213
+ }),
5214
+ // TODO(burdon): Increase indent padding by configuring decorate extension.
5215
+ // TODO(burdon): Hover to select entire group.
5216
+ import_view26.EditorView.theme({
5217
+ ".cm-list-item-start": {
5218
+ borderTop: "1px solid var(--dx-separator)",
5219
+ borderLeft: "1px solid var(--dx-separator)",
5220
+ borderRight: "1px solid var(--dx-separator)",
5221
+ borderTopLeftRadius: "4px",
5222
+ borderTopRightRadius: "4px",
5223
+ paddingTop: "4px",
5224
+ marginTop: "8px"
5225
+ },
5226
+ ".cm-list-item-end": {
5227
+ borderLeft: "1px solid var(--dx-separator)",
5228
+ borderRight: "1px solid var(--dx-separator)",
5229
+ borderBottom: "1px solid var(--dx-separator)",
5230
+ borderBottomLeftRadius: "4px",
5231
+ borderBottomRightRadius: "4px",
5232
+ paddingBottom: "4px",
5233
+ marginBottom: "8px"
5234
+ },
5235
+ ".cm-list-item-continuation": {
5236
+ borderLeft: "1px solid var(--dx-separator)",
5237
+ borderRight: "1px solid var(--dx-separator)",
5238
+ // TODO(burdon): Should match parent indentation.
5239
+ paddingLeft: "24px"
5240
+ },
5241
+ // TODO(burdon): Set via options to decorate extension.
5242
+ ".cm-list-item-continuation.cm-codeblock-start": {
5243
+ borderRadius: "0"
5244
+ }
5245
+ })
5246
+ ];
5247
+ var buildDecorations3 = (from, to, state) => {
5248
+ const decorations = [];
5249
+ (0, import_language13.syntaxTree)(state).iterate({
5250
+ enter: (node) => {
5251
+ if (node.name === "ListItem") {
5252
+ const sub = node.node.getChild("BulletList");
5253
+ const lineStart = state.doc.lineAt(node.from);
5254
+ const lineEnd = sub ? state.doc.lineAt(state.doc.lineAt(sub.from).from - 1) : state.doc.lineAt(node.to);
5255
+ decorations.push(import_view26.Decoration.line({
5256
+ class: (0, import_react_ui_theme7.mx)("cm-list-item-start", lineStart.number === lineEnd.number && "cm-list-item-end")
5257
+ }).range(lineStart.from, lineStart.from));
5258
+ for (let i = lineStart.from + 1; i < lineEnd.from; i++) {
5259
+ decorations.push(import_view26.Decoration.line({
5260
+ class: (0, import_react_ui_theme7.mx)("cm-list-item-continuation")
5261
+ }).range(i, i));
5080
5262
  }
5081
- const mark = node.node.firstChild;
5082
- if (mark?.name === "HeaderMark") {
5083
- const { from, to = 6 } = options.numberedHeadings ?? {};
5084
- const text = view.state.sliceDoc(node.from, node.to);
5085
- const len = text.match(/[#\s]+/)[0].length;
5086
- if (!from || level < from || level > to) {
5087
- atomicDeco.add(mark.from, mark.from + len, hide);
5088
- } else {
5089
- const num = headers.slice(from - 1).map((level2) => level2?.number ?? 0).join(".") + " ";
5090
- if (num.length) {
5091
- atomicDeco.add(mark.from, mark.from + len, import_view21.Decoration.replace({
5092
- widget: new TextWidget(num, theme.heading(level))
5093
- }));
5094
- }
5095
- }
5263
+ if (lineStart.number !== lineEnd.number) {
5264
+ decorations.push(import_view26.Decoration.line({
5265
+ class: (0, import_react_ui_theme7.mx)("cm-list-item-end")
5266
+ }).range(lineEnd.from, lineEnd.from));
5096
5267
  }
5097
- return false;
5098
- }
5099
- //
5100
- // Lists.
5101
- // [BulletList | OrderedList] > (ListItem > ListMark) > (Task > TaskMarker)?
5102
- //
5103
- case "BulletList":
5104
- case "OrderedList": {
5105
- enterList(node);
5106
- break;
5107
5268
  }
5108
- case "ListItem": {
5109
- const line = state.doc.lineAt(node.from);
5110
- const list = getCurrentListLevel();
5111
- const width = list.type === "OrderedList" ? orderedListIndentationWidth : bulletListIndentationWidth;
5112
- const offset = ((list.level ?? 0) + 1) * width;
5113
- if (node.from === line.to - 1) {
5114
- return false;
5269
+ }
5270
+ });
5271
+ return decorations;
5272
+ };
5273
+ var __dxlog_file11 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/mention.ts";
5274
+ var mention = ({ debug, onSearch }) => {
5275
+ return (0, import_autocomplete5.autocompletion)({
5276
+ // TODO(burdon): Not working.
5277
+ activateOnTyping: true,
5278
+ // activateOnTypingDelay: 100,
5279
+ // selectOnOpen: true,
5280
+ closeOnBlur: !debug,
5281
+ // defaultKeymap: false,
5282
+ icons: false,
5283
+ override: [
5284
+ (context) => {
5285
+ import_log7.log.info("completion context", {
5286
+ context
5287
+ }, {
5288
+ F: __dxlog_file11,
5289
+ L: 27,
5290
+ S: void 0,
5291
+ C: (f, a) => f(...a)
5292
+ });
5293
+ const match = context.matchBefore(/@(\w+)?/);
5294
+ if (!match || match.from === match.to && !context.explicit) {
5295
+ return null;
5115
5296
  }
5116
- deco.add(line.from, line.from, import_view21.Decoration.line({
5117
- class: "cm-list-item",
5118
- attributes: {
5119
- style: `padding-left: ${offset}px; text-indent: -${width}px;`
5120
- }
5121
- }));
5122
- break;
5297
+ return {
5298
+ from: match.from,
5299
+ options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
5300
+ label: `@${value}`
5301
+ }))
5302
+ };
5123
5303
  }
5124
- case "ListMark": {
5125
- const list = getCurrentListLevel();
5126
- const next = tree.resolve(node.to + 1, 1);
5127
- if (next?.name === "TaskMarker") {
5128
- break;
5304
+ ]
5305
+ });
5306
+ };
5307
+ var EditorViewModes = [
5308
+ "preview",
5309
+ "readonly",
5310
+ "source"
5311
+ ];
5312
+ var EditorViewMode = import_effect.Schema.Union(...EditorViewModes.map((mode) => import_effect.Schema.Literal(mode)));
5313
+ var EditorInputModes = [
5314
+ "default",
5315
+ "vim",
5316
+ "vscode"
5317
+ ];
5318
+ var EditorInputMode = import_effect.Schema.Union(...EditorInputModes.map((mode) => import_effect.Schema.Literal(mode)));
5319
+ var editorInputMode = singleValueFacet({});
5320
+ var InputModeExtensions = {
5321
+ default: [],
5322
+ vscode: [
5323
+ // https://github.com/replit/codemirror-vscode-keymap
5324
+ editorInputMode.of({
5325
+ type: "vscode"
5326
+ }),
5327
+ import_view27.keymap.of(import_codemirror_vscode_keymap.vscodeKeymap)
5328
+ ],
5329
+ vim: [
5330
+ // https://github.com/replit/codemirror-vim
5331
+ (0, import_codemirror_vim.vim)(),
5332
+ editorInputMode.of({
5333
+ type: "vim",
5334
+ noTabster: true
5335
+ }),
5336
+ import_view27.keymap.of([
5337
+ {
5338
+ key: "Alt-Escape",
5339
+ run: (view) => {
5340
+ view.dom.parentElement?.focus();
5341
+ return true;
5129
5342
  }
5130
- const label = list.type === "OrderedList" ? `${++list.number}.` : Unicode.bulletSmall;
5131
- const line = state.doc.lineAt(node.from);
5132
- const to = state.doc.sliceString(node.to, node.to + 1) === " " ? node.to + 1 : node.to;
5133
- atomicDeco.add(line.from, to, import_view21.Decoration.replace({
5134
- widget: new TextWidget(label, list.type === "OrderedList" ? "cm-list-mark cm-list-mark-ordered" : "cm-list-mark cm-list-mark-bullet")
5135
- }));
5136
- break;
5137
5343
  }
5138
- case "TaskMarker": {
5139
- const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
5140
- const line = state.doc.lineAt(node.from);
5141
- const to = state.doc.sliceString(node.to, node.to + 1) === " " ? node.to + 1 : node.to;
5142
- atomicDeco.add(line.from, to, checked ? checkedTask : uncheckedTask);
5143
- break;
5344
+ ])
5345
+ ]
5346
+ };
5347
+ var preview = (options = {}) => {
5348
+ return [
5349
+ // NOTE: Atomic block decorations must be created from a state field, now a widget, otherwise it results in the following error:
5350
+ // "Block decorations may not be specified via plugins"
5351
+ import_state23.StateField.define({
5352
+ create: (state) => buildDecorations4(state, options),
5353
+ update: (_, tr) => buildDecorations4(tr.state, options),
5354
+ provide: (field) => [
5355
+ import_view28.EditorView.decorations.from(field),
5356
+ import_view28.EditorView.atomicRanges.of((view) => view.state.field(field))
5357
+ ]
5358
+ }),
5359
+ import_view28.EditorView.theme({
5360
+ ".cm-preview-block": {
5361
+ marginLeft: "-1rem",
5362
+ marginRight: "-1rem",
5363
+ padding: "1rem",
5364
+ borderRadius: "0.5rem",
5365
+ background: "var(--dx-modalSurface)",
5366
+ border: "1px solid var(--dx-separator)"
5144
5367
  }
5145
- //
5146
- // Blockquote > QuoteMark > Paragraph
5147
- //
5148
- case "Blockquote": {
5149
- const editing = editingRange(state, node, focus2);
5150
- const quoteMark = node.node.getChild("QuoteMark");
5151
- const paragraph = node.node.getChild("Paragraph");
5152
- if (!editing && quoteMark && paragraph) {
5153
- atomicDeco.add(quoteMark.from, paragraph.from, hide);
5154
- }
5155
- for (const block of view.viewportLineBlocks) {
5156
- if (block.to < node.from) {
5157
- continue;
5158
- }
5159
- if (block.from > node.to) {
5160
- break;
5368
+ })
5369
+ ];
5370
+ };
5371
+ var getLinkRef = (state, node) => {
5372
+ const mark = node.getChild("LinkMark");
5373
+ const label = node.getChild("LinkLabel");
5374
+ if (mark && label) {
5375
+ const ref = state.sliceDoc(label.from + 1, label.to - 1);
5376
+ return {
5377
+ suggest: ref.startsWith("?"),
5378
+ block: state.sliceDoc(mark.from, mark.from + 1) === "!",
5379
+ label: state.sliceDoc(mark.to, label.from - 1),
5380
+ ref: ref.startsWith("?") ? ref.slice(1) : ref
5381
+ };
5382
+ }
5383
+ };
5384
+ var buildDecorations4 = (state, options) => {
5385
+ const builder = new import_state23.RangeSetBuilder();
5386
+ (0, import_language14.syntaxTree)(state).iterate({
5387
+ enter: (node) => {
5388
+ switch (node.name) {
5389
+ //
5390
+ // Decoration.
5391
+ // [Label][dxn:echo:123]
5392
+ //
5393
+ case "Link": {
5394
+ const link = getLinkRef(state, node.node);
5395
+ if (link) {
5396
+ builder.add(node.from, node.to, import_view28.Decoration.replace({
5397
+ widget: new PreviewInlineWidget(options, link)
5398
+ }));
5161
5399
  }
5162
- deco.add(block.from, block.from, blockQuote);
5400
+ break;
5163
5401
  }
5164
- break;
5165
- }
5166
- //
5167
- // CommentBlock
5168
- //
5169
- case "CommentBlock": {
5170
- const editing = editingRange(state, node, focus2);
5171
- for (const block of view.viewportLineBlocks) {
5172
- if (block.to < node.from) {
5173
- continue;
5174
- }
5175
- if (block.from > node.to) {
5176
- break;
5177
- }
5178
- const isFirst = block.from <= node.from;
5179
- const isLast = block.to >= node.to && /^(\s>)*-->$/.test(state.doc.sliceString(block.from, block.to));
5180
- deco.add(block.from, block.from, isFirst ? commentBlockLineFirst : isLast ? commentBlockLineLast : commentBlockLine);
5181
- if (!editing && (isFirst || isLast)) {
5182
- atomicDeco.add(block.from, block.to, hide);
5402
+ //
5403
+ // Block widget.
5404
+ // ![Label][dxn:echo:123]
5405
+ //
5406
+ case "Image": {
5407
+ const link = getLinkRef(state, node.node);
5408
+ if (options.renderBlock && link) {
5409
+ builder.add(node.from, node.to, import_view28.Decoration.replace({
5410
+ block: true,
5411
+ // atomic: true,
5412
+ widget: new PreviewBlockWidget(options, link)
5413
+ }));
5183
5414
  }
5415
+ break;
5184
5416
  }
5185
- break;
5186
5417
  }
5187
- //
5188
- // FencedCode > CodeMark > [CodeInfo] > CodeText > CodeMark
5189
- //
5190
- case "FencedCode": {
5191
- for (const block of view.viewportLineBlocks) {
5192
- if (block.to < node.from) {
5193
- continue;
5194
- }
5195
- if (block.from > node.to) {
5196
- break;
5197
- }
5198
- const first = block.from <= node.from;
5199
- const last = block.to >= node.to && /^(\s>)*```$/.test(state.doc.sliceString(block.from, block.to));
5200
- deco.add(block.from, block.from, first ? fencedCodeLineFirst : last ? fencedCodeLineLast : fencedCodeLine);
5201
- const editing = editingRange(state, node, focus2);
5202
- if (!editing && (first || last)) {
5203
- atomicDeco.add(block.from, block.to, hide);
5204
- }
5205
- }
5206
- return false;
5418
+ }
5419
+ });
5420
+ return builder.finish();
5421
+ };
5422
+ var PreviewInlineWidget = class extends import_view28.WidgetType {
5423
+ constructor(_options, _link) {
5424
+ super();
5425
+ this._options = _options;
5426
+ this._link = _link;
5427
+ }
5428
+ // override ignoreEvent() {
5429
+ // return false;
5430
+ // }
5431
+ eq(other) {
5432
+ return this._link.ref === other._link.ref && this._link.label === other._link.label;
5433
+ }
5434
+ toDOM(view) {
5435
+ const root = document.createElement("dx-ref-tag");
5436
+ root.textContent = this._link.label;
5437
+ root.setAttribute("ref", this._link.ref);
5438
+ return root;
5439
+ }
5440
+ };
5441
+ var PreviewBlockWidget = class extends import_view28.WidgetType {
5442
+ constructor(_options, _link) {
5443
+ super();
5444
+ this._options = _options;
5445
+ this._link = _link;
5446
+ }
5447
+ // override ignoreEvent() {
5448
+ // return true;
5449
+ // }
5450
+ eq(other) {
5451
+ return this._link.ref === other._link.ref;
5452
+ }
5453
+ toDOM(view) {
5454
+ const root = document.createElement("div");
5455
+ root.classList.add("cm-preview-block");
5456
+ const handleAction = (action) => {
5457
+ const pos = view.posAtDOM(root);
5458
+ const node = (0, import_language14.syntaxTree)(view.state).resolve(pos + 1).node.parent;
5459
+ if (!node) {
5460
+ return;
5461
+ }
5462
+ const link = getLinkRef(view.state, node);
5463
+ if (link?.ref !== action.link.ref) {
5464
+ return;
5207
5465
  }
5208
- //
5209
- // Link > [LinkMark, URL]
5210
- //
5211
- case "Link": {
5212
- const marks = node.node.getChildren("LinkMark");
5213
- const urlNode = node.node.getChild("URL");
5214
- const editing = editingRange(state, node, focus2);
5215
- if (urlNode && marks.length >= 2) {
5216
- const url = state.sliceDoc(urlNode.from, urlNode.to);
5217
- if (!editing) {
5218
- atomicDeco.add(node.from, marks[0].to, hide);
5219
- }
5220
- deco.add(marks[0].to, marks[1].from, import_view21.Decoration.mark({
5221
- tagName: "a",
5222
- attributes: {
5223
- class: "cm-link",
5224
- href: url,
5225
- rel: "noreferrer",
5226
- target: "_blank"
5466
+ switch (action.type) {
5467
+ // TODO(burdon): Should we dispatch to the view or mutate the document? (i.e., handle externally?)
5468
+ // Insert ref text.
5469
+ case "insert": {
5470
+ view.dispatch({
5471
+ changes: {
5472
+ from: node.from,
5473
+ to: node.to,
5474
+ insert: action.target.text
5227
5475
  }
5228
- }));
5229
- if (!editing) {
5230
- atomicDeco.add(marks[1].from, node.to, options.renderLinkButton ? import_view21.Decoration.replace({
5231
- widget: new LinkButton(url, options.renderLinkButton)
5232
- }) : hide);
5233
- }
5476
+ });
5477
+ break;
5234
5478
  }
5235
- break;
5236
- }
5237
- //
5238
- // HR
5239
- //
5240
- case "HorizontalRule": {
5241
- if (!editingRange(state, node, focus2)) {
5242
- deco.add(node.from, node.to, horizontalRule);
5479
+ // Remove ref.
5480
+ case "delete": {
5481
+ view.dispatch({
5482
+ changes: {
5483
+ from: node.from,
5484
+ to: node.to
5485
+ }
5486
+ });
5487
+ break;
5243
5488
  }
5244
- break;
5245
5489
  }
5246
- default: {
5247
- if (autoHideTags.has(node.name)) {
5248
- if (!editingRange(state, node.node.parent, focus2)) {
5249
- atomicDeco.add(node.from, node.to, hide);
5490
+ };
5491
+ this._options.renderBlock(root, {
5492
+ readonly: view.state.readOnly,
5493
+ link: this._link,
5494
+ onAction: handleAction,
5495
+ onLookup: this._options.onLookup
5496
+ }, view);
5497
+ return root;
5498
+ }
5499
+ };
5500
+ var defaultItems = [
5501
+ "hello world!",
5502
+ "this is a test.",
5503
+ "this is [DXOS](https://dxos.org)"
5504
+ ];
5505
+ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
5506
+ let t;
5507
+ let idx = 0;
5508
+ return [
5509
+ import_view29.keymap.of([
5510
+ {
5511
+ // Reset.
5512
+ key: "alt-meta-'",
5513
+ run: (view) => {
5514
+ clearTimeout(t);
5515
+ idx = 0;
5516
+ return true;
5517
+ }
5518
+ },
5519
+ {
5520
+ // Next prompt.
5521
+ // TODO(burdon): Press 1-9 to select prompt?
5522
+ key: "shift-meta-'",
5523
+ run: (view) => {
5524
+ clearTimeout(t);
5525
+ const text = items[idx++];
5526
+ if (idx === items?.length) {
5527
+ idx = 0;
5250
5528
  }
5529
+ let i = 0;
5530
+ const insert = (d = 0) => {
5531
+ t = setTimeout(() => {
5532
+ const pos = view.state.selection.main.head;
5533
+ view.dispatch({
5534
+ changes: {
5535
+ from: pos,
5536
+ insert: text[i++]
5537
+ },
5538
+ selection: {
5539
+ anchor: pos + 1
5540
+ }
5541
+ });
5542
+ if (i < text.length) {
5543
+ insert(Math.random() * delay * (text[i] === " " ? 2 : 1));
5544
+ }
5545
+ }, d);
5546
+ };
5547
+ insert();
5548
+ return true;
5251
5549
  }
5252
5550
  }
5551
+ ])
5552
+ ];
5553
+ };
5554
+ var createBlockGroupAction = (value) => createEditorActionGroup("block", {
5555
+ variant: "toggleGroup",
5556
+ selectCardinality: "single",
5557
+ value
5558
+ });
5559
+ var createBlockActions = (value, getView, blankLine) => Object.entries({
5560
+ blockquote: "ph--quotes--regular",
5561
+ codeblock: "ph--code-block--regular",
5562
+ table: "ph--table--regular"
5563
+ }).map(([type, icon]) => {
5564
+ const checked = type === value;
5565
+ return createEditorAction(type, () => {
5566
+ const view = getView();
5567
+ if (!view) {
5568
+ return;
5253
5569
  }
5254
- };
5255
- const leaveNode = (node) => {
5256
- switch (node.name) {
5257
- case "BulletList":
5258
- case "OrderedList": {
5259
- leaveList();
5570
+ switch (type) {
5571
+ case "blockquote":
5572
+ checked ? removeBlockquote(view) : addBlockquote(view);
5573
+ break;
5574
+ case "codeblock":
5575
+ checked ? removeCodeblock(view) : addCodeblock(view);
5576
+ break;
5577
+ case "table":
5578
+ insertTable(view);
5260
5579
  break;
5261
- }
5262
- }
5263
- };
5264
- const tree = (0, import_language8.syntaxTree)(state);
5265
- if (options.numberedHeadings?.from === void 0) {
5266
- for (const { from, to } of view.visibleRanges) {
5267
- tree.iterate({
5268
- from,
5269
- to,
5270
- enter: wrapWithCatch(enterNode),
5271
- leave: wrapWithCatch(leaveNode)
5272
- });
5273
5580
  }
5274
- } else {
5275
- tree.iterate({
5276
- enter: wrapWithCatch(enterNode),
5277
- leave: wrapWithCatch(leaveNode)
5278
- });
5279
- }
5581
+ }, {
5582
+ checked,
5583
+ ...type === "table" && {
5584
+ disabled: !!blankLine
5585
+ },
5586
+ icon
5587
+ });
5588
+ });
5589
+ var createBlocks = (state, getView) => {
5590
+ const value = state?.blockQuote ? "blockquote" : state.blockType ?? "";
5591
+ const blockGroupAction = createBlockGroupAction(value);
5592
+ const blockActions = createBlockActions(value, getView, state.blankLine);
5280
5593
  return {
5281
- deco: deco.finish(),
5282
- atomicDeco: atomicDeco.finish()
5594
+ nodes: [
5595
+ blockGroupAction,
5596
+ ...blockActions
5597
+ ],
5598
+ edges: [
5599
+ {
5600
+ source: "root",
5601
+ target: "block"
5602
+ },
5603
+ ...blockActions.map(({ id }) => ({
5604
+ source: blockGroupAction.id,
5605
+ target: id
5606
+ }))
5607
+ ]
5283
5608
  };
5284
5609
  };
5285
- var forceUpdate = import_state18.StateEffect.define();
5286
- var decorateMarkdown = (options = {}) => {
5287
- return [
5288
- import_view21.ViewPlugin.fromClass(class {
5289
- constructor(view) {
5290
- ({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations2(view, options, view.hasFocus));
5291
- }
5292
- update(update2) {
5293
- if (update2.docChanged || update2.viewportChanged || update2.focusChanged || update2.transactions.some((tr) => tr.effects.some((effect) => effect.is(forceUpdate))) || update2.selectionSet && !options.selectionChangeDelay) {
5294
- ({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations2(update2.view, options, update2.view.hasFocus));
5295
- this.clearUpdate();
5296
- } else if (update2.selectionSet) {
5297
- this.scheduleUpdate(update2.view);
5298
- }
5299
- }
5300
- // Defer update in case moving through the document.
5301
- scheduleUpdate(view) {
5302
- this.clearUpdate();
5303
- this.pendingUpdate = setTimeout(() => {
5304
- view.dispatch({
5305
- effects: forceUpdate.of(null)
5306
- });
5307
- }, options.selectionChangeDelay);
5308
- }
5309
- clearUpdate() {
5310
- if (this.pendingUpdate) {
5311
- clearTimeout(this.pendingUpdate);
5312
- this.pendingUpdate = void 0;
5313
- }
5314
- }
5315
- destroy() {
5316
- this.clearUpdate();
5610
+ var commentLabel = (comment, selection) => comment ? "selection overlaps existing comment label" : selection === false ? "select text to comment label" : "comment label";
5611
+ var createCommentAction = (label, getView) => createEditorAction("comment", () => createComment(getView()), {
5612
+ testId: "editor.toolbar.comment",
5613
+ icon: "ph--chat-text--regular",
5614
+ label
5615
+ });
5616
+ var createComment2 = (state, getView) => ({
5617
+ nodes: [
5618
+ createCommentAction([
5619
+ commentLabel(state.comment, state.selection),
5620
+ {
5621
+ ns: translationKey
5317
5622
  }
5318
- }, {
5319
- provide: (plugin) => [
5320
- import_view21.EditorView.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? import_view21.Decoration.none),
5321
- import_view21.EditorView.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? import_view21.Decoration.none),
5322
- import_view21.EditorView.decorations.of((view) => view.plugin(plugin)?.deco ?? import_view21.Decoration.none)
5323
- ]
5324
- }),
5325
- image(),
5326
- table(),
5327
- adjustChanges(),
5328
- formattingStyles
5329
- ];
5623
+ ], getView)
5624
+ ],
5625
+ edges: [
5626
+ {
5627
+ source: "root",
5628
+ target: "comment"
5629
+ }
5630
+ ]
5631
+ });
5632
+ var formats = {
5633
+ strong: "ph--text-b--regular",
5634
+ emphasis: "ph--text-italic--regular",
5635
+ strikethrough: "ph--text-strikethrough--regular",
5636
+ code: "ph--code--regular",
5637
+ link: "ph--link--regular"
5330
5638
  };
5331
- var linkTooltip = (renderTooltip) => {
5332
- return (0, import_view26.hoverTooltip)((view, pos, side) => {
5333
- const syntax = (0, import_language12.syntaxTree)(view.state).resolveInner(pos, side);
5334
- let link = null;
5335
- for (let i = 0, node = syntax; !link && node && i < 5; node = node.parent, i++) {
5336
- link = node.name === "Link" ? node : null;
5639
+ var createFormattingGroup = (formatting) => createEditorActionGroup("formatting", {
5640
+ variant: "toggleGroup",
5641
+ selectCardinality: "multiple",
5642
+ value: Object.keys(formats).filter((key) => !!formatting[key])
5643
+ });
5644
+ var createFormattingActions = (formatting, getView) => Object.entries(formats).map(([type, icon]) => {
5645
+ const checked = !!formatting[type];
5646
+ return createEditorAction(type, () => {
5647
+ const view = getView();
5648
+ if (!view) {
5649
+ return;
5337
5650
  }
5338
- const url = link && link.getChild("URL");
5339
- if (!url || !link) {
5340
- return null;
5651
+ if (type === "link") {
5652
+ checked ? removeLink(view) : addLink()(view);
5653
+ return;
5341
5654
  }
5342
- const urlText = view.state.sliceDoc(url.from, url.to);
5343
- return {
5344
- pos: link.from,
5345
- end: link.to,
5346
- // NOTE: Forcing above causes the tooltip to flicker.
5347
- // above: true,
5348
- create: () => {
5349
- const el = document.createElement("div");
5350
- el.className = (0, import_react_ui_theme7.tooltipContent)({});
5351
- renderTooltip(el, {
5352
- url: urlText
5353
- }, view);
5354
- return {
5355
- dom: el,
5356
- offset: {
5357
- x: 0,
5358
- y: 4
5359
- }
5360
- };
5361
- }
5362
- };
5655
+ const inlineType = type === "strong" ? Inline.Strong : type === "emphasis" ? Inline.Emphasis : type === "strikethrough" ? Inline.Strikethrough : Inline.Code;
5656
+ setStyle(inlineType, !checked)(view);
5363
5657
  }, {
5364
- // NOTE: 0 = default of 300ms.
5365
- hoverTime: 1
5658
+ checked,
5659
+ icon
5366
5660
  });
5367
- };
5368
- var __dxlog_file10 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/mention.ts";
5369
- var mention = ({ debug, onSearch }) => {
5370
- return (0, import_autocomplete5.autocompletion)({
5371
- // TODO(burdon): Not working.
5372
- activateOnTyping: true,
5373
- // activateOnTypingDelay: 100,
5374
- // selectOnOpen: true,
5375
- closeOnBlur: !debug,
5376
- // defaultKeymap: false,
5377
- icons: false,
5378
- override: [
5379
- (context) => {
5380
- import_log6.log.info("completion context", {
5381
- context
5382
- }, {
5383
- F: __dxlog_file10,
5384
- L: 27,
5385
- S: void 0,
5386
- C: (f, a) => f(...a)
5387
- });
5388
- const match = context.matchBefore(/@(\w+)?/);
5389
- if (!match || match.from === match.to && !context.explicit) {
5390
- return null;
5391
- }
5392
- return {
5393
- from: match.from,
5394
- options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
5395
- label: `@${value}`
5396
- }))
5397
- };
5398
- }
5661
+ });
5662
+ var createFormatting = (state, getView) => {
5663
+ const formattingGroupAction = createFormattingGroup(state);
5664
+ const formattingActions = createFormattingActions(state, getView);
5665
+ return {
5666
+ nodes: [
5667
+ formattingGroupAction,
5668
+ ...formattingActions
5669
+ ],
5670
+ edges: [
5671
+ {
5672
+ source: "root",
5673
+ target: "formatting"
5674
+ },
5675
+ ...formattingActions.map(({ id }) => ({
5676
+ source: formattingGroupAction.id,
5677
+ target: id
5678
+ }))
5399
5679
  ]
5400
- });
5680
+ };
5401
5681
  };
5402
- var EditorViewModes = [
5403
- "preview",
5404
- "readonly",
5405
- "source"
5406
- ];
5407
- var EditorViewMode = import_echo_schema.S.Union(...EditorViewModes.map((mode) => import_echo_schema.S.Literal(mode)));
5408
- var EditorInputModes = [
5409
- "default",
5410
- "vim",
5411
- "vscode"
5412
- ];
5413
- var EditorInputMode = import_echo_schema.S.Union(...EditorInputModes.map((mode) => import_echo_schema.S.Literal(mode)));
5414
- var editorInputMode = singleValueFacet({});
5415
- var InputModeExtensions = {
5416
- default: [],
5417
- vscode: [
5418
- // https://github.com/replit/codemirror-vscode-keymap
5419
- editorInputMode.of({
5420
- type: "vscode"
5421
- }),
5422
- import_view27.keymap.of(import_codemirror_vscode_keymap.vscodeKeymap)
5423
- ],
5424
- vim: [
5425
- // https://github.com/replit/codemirror-vim
5426
- (0, import_codemirror_vim.vim)(),
5427
- editorInputMode.of({
5428
- type: "vim",
5429
- noTabster: true
5430
- }),
5431
- import_view27.keymap.of([
5682
+ var createHeadingGroupAction = (value) => createEditorActionGroup("heading", {
5683
+ variant: "dropdownMenu",
5684
+ applyActive: true,
5685
+ selectCardinality: "single",
5686
+ value
5687
+ }, "ph--text-h--regular");
5688
+ var createHeadingActions = (getView) => Object.entries({
5689
+ "0": "ph--paragraph--regular",
5690
+ "1": "ph--text-h-one--regular",
5691
+ "2": "ph--text-h-two--regular",
5692
+ "3": "ph--text-h-three--regular",
5693
+ "4": "ph--text-h-four--regular",
5694
+ "5": "ph--text-h-five--regular",
5695
+ "6": "ph--text-h-six--regular"
5696
+ }).map(([levelStr, icon]) => {
5697
+ const level = parseInt(levelStr);
5698
+ return createEditorAction(`heading--${levelStr}`, () => setHeading(level)(getView()), {
5699
+ label: [
5700
+ "heading level label",
5432
5701
  {
5433
- key: "Alt-Escape",
5434
- run: (view) => {
5435
- view.dom.parentElement?.focus();
5436
- return true;
5437
- }
5702
+ count: level,
5703
+ ns: translationKey
5438
5704
  }
5439
- ])
5440
- ]
5705
+ ],
5706
+ icon
5707
+ });
5708
+ });
5709
+ var computeHeadingValue = (state) => {
5710
+ const blockType = state ? state.blockType : "paragraph";
5711
+ const header = blockType && /heading(\d)/.exec(blockType);
5712
+ return header ? header[1] : blockType === "paragraph" || !blockType ? "0" : "";
5441
5713
  };
5442
- var preview = (options = {}) => {
5443
- return [
5444
- // NOTE: Atomic block decorations must be created from a state field, now a widget, otherwise it results in the following error:
5445
- // "Block decorations may not be specified via plugins"
5446
- import_state22.StateField.define({
5447
- create: (state) => buildDecorations3(state, options),
5448
- update: (_, tr) => buildDecorations3(tr.state, options),
5449
- provide: (field) => [
5450
- import_view28.EditorView.decorations.from(field),
5451
- import_view28.EditorView.atomicRanges.of((view) => view.state.field(field))
5452
- ]
5453
- }),
5454
- import_view28.EditorView.theme({
5455
- ".cm-preview-block": {
5456
- marginLeft: "-1rem",
5457
- marginRight: "-1rem",
5458
- padding: "1rem",
5459
- borderRadius: "0.5rem",
5460
- background: "var(--dx-modalSurface)",
5461
- border: "1px solid var(--dx-separator)"
5462
- }
5463
- })
5464
- ];
5714
+ var createHeadings = (state, getView) => {
5715
+ const headingValue = computeHeadingValue(state);
5716
+ const headingGroupAction = createHeadingGroupAction(headingValue);
5717
+ const headingActions = createHeadingActions(getView);
5718
+ return {
5719
+ nodes: [
5720
+ headingGroupAction,
5721
+ ...headingActions
5722
+ ],
5723
+ edges: [
5724
+ {
5725
+ source: "root",
5726
+ target: "heading"
5727
+ },
5728
+ ...headingActions.map(({ id }) => ({
5729
+ source: headingGroupAction.id,
5730
+ target: id
5731
+ }))
5732
+ ]
5733
+ };
5465
5734
  };
5466
- var getLinkRef = (state, node) => {
5467
- const mark = node.getChild("LinkMark");
5468
- const label = node.getChild("LinkLabel");
5469
- if (mark && label) {
5470
- const ref = state.sliceDoc(label.from + 1, label.to - 1);
5471
- return {
5472
- suggest: ref.startsWith("?"),
5473
- block: state.sliceDoc(mark.from, mark.from + 1) === "!",
5474
- label: state.sliceDoc(mark.to, label.from - 1),
5475
- ref: ref.startsWith("?") ? ref.slice(1) : ref
5476
- };
5477
- }
5735
+ var createImageUploadAction = (onImageUpload) => createEditorAction("image", onImageUpload, {
5736
+ testId: "editor.toolbar.image",
5737
+ icon: "ph--image-square--regular"
5738
+ });
5739
+ var createImageUpload = (onImageUpload) => ({
5740
+ nodes: [
5741
+ createImageUploadAction(onImageUpload)
5742
+ ],
5743
+ edges: [
5744
+ {
5745
+ source: "root",
5746
+ target: "image"
5747
+ }
5748
+ ]
5749
+ });
5750
+ var listStyles = {
5751
+ bullet: "ph--list-bullets--regular",
5752
+ ordered: "ph--list-numbers--regular",
5753
+ task: "ph--list-checks--regular"
5478
5754
  };
5479
- var buildDecorations3 = (state, options) => {
5480
- const builder = new import_state22.RangeSetBuilder();
5481
- (0, import_language13.syntaxTree)(state).iterate({
5482
- enter: (node) => {
5483
- switch (node.name) {
5484
- //
5485
- // Decoration.
5486
- // [Label][dxn:echo:123]
5487
- //
5488
- case "Link": {
5489
- const link = getLinkRef(state, node.node);
5490
- if (link) {
5491
- builder.add(node.from, node.to, import_view28.Decoration.replace({
5492
- widget: new PreviewInlineWidget(options, link)
5493
- }));
5494
- }
5495
- break;
5496
- }
5497
- //
5498
- // Block widget.
5499
- // ![Label][dxn:echo:123]
5500
- //
5501
- case "Image": {
5502
- const link = getLinkRef(state, node.node);
5503
- if (options.renderBlock && link) {
5504
- builder.add(node.from, node.to, import_view28.Decoration.replace({
5505
- block: true,
5506
- // atomic: true,
5507
- widget: new PreviewBlockWidget(options, link)
5508
- }));
5509
- }
5510
- break;
5511
- }
5512
- }
5755
+ var createListGroupAction = (value) => createEditorActionGroup("list", {
5756
+ variant: "toggleGroup",
5757
+ selectCardinality: "single",
5758
+ value
5759
+ });
5760
+ var createListActions = (value, getView) => Object.entries(listStyles).map(([listStyle, icon]) => {
5761
+ const checked = value === listStyle;
5762
+ return createEditorAction(`list-${listStyle}`, () => {
5763
+ const view = getView();
5764
+ if (!view) {
5765
+ return;
5513
5766
  }
5767
+ const listType = listStyle === "ordered" ? List.Ordered : listStyle === "bullet" ? List.Bullet : List.Task;
5768
+ if (checked) {
5769
+ removeList(listType)(view);
5770
+ } else {
5771
+ addList(listType)(view);
5772
+ }
5773
+ }, {
5774
+ checked,
5775
+ icon
5514
5776
  });
5515
- return builder.finish();
5777
+ });
5778
+ var createLists = (state, getView) => {
5779
+ const value = state.listStyle ?? "";
5780
+ const listGroupAction = createListGroupAction(value);
5781
+ const listActionsMap = createListActions(value, getView);
5782
+ return {
5783
+ nodes: [
5784
+ listGroupAction,
5785
+ ...listActionsMap
5786
+ ],
5787
+ edges: [
5788
+ {
5789
+ source: "root",
5790
+ target: "list"
5791
+ },
5792
+ ...listActionsMap.map(({ id }) => ({
5793
+ source: listGroupAction.id,
5794
+ target: id
5795
+ }))
5796
+ ]
5797
+ };
5516
5798
  };
5517
- var PreviewInlineWidget = class extends import_view28.WidgetType {
5518
- constructor(_options, _link) {
5519
- super();
5520
- this._options = _options;
5521
- this._link = _link;
5799
+ var createSearchAction = (getView) => createEditorAction("search", () => (0, import_search2.openSearchPanel)(getView()), {
5800
+ testId: "editor.toolbar.search",
5801
+ icon: "ph--magnifying-glass--regular"
5802
+ });
5803
+ var createSearch = (getView) => ({
5804
+ nodes: [
5805
+ createSearchAction(getView)
5806
+ ],
5807
+ edges: [
5808
+ {
5809
+ source: "root",
5810
+ target: "search"
5811
+ }
5812
+ ]
5813
+ });
5814
+ var createViewModeGroupAction = (value) => createEditorActionGroup("viewMode", {
5815
+ variant: "dropdownMenu",
5816
+ applyActive: true,
5817
+ selectCardinality: "single",
5818
+ value
5819
+ }, "ph--eye--regular");
5820
+ var createViewModeActions = (value, onViewModeChange) => Object.entries({
5821
+ preview: "ph--eye--regular",
5822
+ source: "ph--pencil-simple--regular",
5823
+ readonly: "ph--pencil-slash--regular"
5824
+ }).map(([viewMode, icon]) => {
5825
+ const checked = viewMode === value;
5826
+ return createEditorAction(`view-mode--${viewMode}`, () => onViewModeChange(viewMode), {
5827
+ label: [
5828
+ `${viewMode} mode label`,
5829
+ {
5830
+ ns: translationKey
5831
+ }
5832
+ ],
5833
+ checked,
5834
+ icon
5835
+ });
5836
+ });
5837
+ var createViewMode = (state, onViewModeChange) => {
5838
+ const value = state.viewMode ?? "source";
5839
+ const viewModeGroupAction = createViewModeGroupAction(value);
5840
+ const viewModeActions = createViewModeActions(value, onViewModeChange);
5841
+ return {
5842
+ nodes: [
5843
+ viewModeGroupAction,
5844
+ ...viewModeActions
5845
+ ],
5846
+ edges: [
5847
+ {
5848
+ source: "root",
5849
+ target: "viewMode"
5850
+ },
5851
+ ...viewModeActions.map(({ id }) => ({
5852
+ source: viewModeGroupAction.id,
5853
+ target: id
5854
+ }))
5855
+ ]
5856
+ };
5857
+ };
5858
+ var margin = "!mt-[1rem]";
5859
+ var editorWidth = "!mli-auto is-full max-is-[min(50rem,100%-4rem)]";
5860
+ var editorContent = (0, import_react_ui_theme8.mx)(margin, editorWidth);
5861
+ var editorFullWidth = (0, import_react_ui_theme8.mx)(margin);
5862
+ var editorGutter = import_view30.EditorView.theme({
5863
+ // Match margin from content.
5864
+ // Gutter = 2rem + 1rem margin.
5865
+ ".cm-gutters": {
5866
+ marginTop: "1rem",
5867
+ paddingRight: "1rem"
5522
5868
  }
5523
- // override ignoreEvent() {
5524
- // return false;
5525
- // }
5526
- eq(other) {
5527
- return this._link.ref === other._link.ref && this._link.label === other._link.label;
5869
+ });
5870
+ var editorMonospace = import_view30.EditorView.theme({
5871
+ ".cm-content": {
5872
+ fontFamily: fontMono
5528
5873
  }
5529
- toDOM(view) {
5530
- const root = document.createElement("dx-ref-tag");
5531
- root.setAttribute("label", this._link.label);
5532
- root.setAttribute("ref", this._link.ref);
5533
- return root;
5874
+ });
5875
+ var editorWithToolbarLayout = "grid grid-cols-1 grid-rows-[min-content_1fr] data-[toolbar=disabled]:grid-rows-[1fr] justify-center content-start overflow-hidden";
5876
+ var stackItemContentEditorClassNames = (role) => (0, import_react_ui_theme8.mx)("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");
5877
+ var stackItemContentToolbarClassNames = (role) => (0, import_react_ui_theme8.mx)("relative z-[1] flex is-full bg-toolbarSurface border-be border-separator", role === "section" && "sticky block-start-0 -mbe-px min-is-0");
5878
+ var createToolbar = ({ getView, state, customActions, ...features }) => {
5879
+ const nodes = [];
5880
+ const edges = [];
5881
+ if (features.headings ?? true) {
5882
+ const headings2 = createHeadings(state, getView);
5883
+ nodes.push(...headings2.nodes);
5884
+ edges.push(...headings2.edges);
5534
5885
  }
5535
- };
5536
- var PreviewBlockWidget = class extends import_view28.WidgetType {
5537
- constructor(_options, _link) {
5538
- super();
5539
- this._options = _options;
5540
- this._link = _link;
5886
+ if (features.formatting ?? true) {
5887
+ const formatting = createFormatting(state, getView);
5888
+ nodes.push(...formatting.nodes);
5889
+ edges.push(...formatting.edges);
5541
5890
  }
5542
- // override ignoreEvent() {
5543
- // return true;
5544
- // }
5545
- eq(other) {
5546
- return this._link.ref === other._link.ref;
5891
+ if (features.lists ?? true) {
5892
+ const lists = createLists(state, getView);
5893
+ nodes.push(...lists.nodes);
5894
+ edges.push(...lists.edges);
5547
5895
  }
5548
- toDOM(view) {
5549
- const root = document.createElement("div");
5550
- root.classList.add("cm-preview-block");
5551
- const handleAction = (action) => {
5552
- const pos = view.posAtDOM(root);
5553
- const node = (0, import_language13.syntaxTree)(view.state).resolve(pos + 1).node.parent;
5554
- if (!node) {
5555
- return;
5556
- }
5557
- const link = getLinkRef(view.state, node);
5558
- if (link?.ref !== action.link.ref) {
5559
- return;
5560
- }
5561
- switch (action.type) {
5562
- // TODO(burdon): Should we dispatch to the view or mutate the document? (i.e., handle externally?)
5563
- // Insert ref text.
5564
- case "insert": {
5565
- view.dispatch({
5566
- changes: {
5567
- from: node.from,
5568
- to: node.to,
5569
- insert: action.target.text
5570
- }
5571
- });
5572
- break;
5573
- }
5574
- // Remove ref.
5575
- case "delete": {
5576
- view.dispatch({
5577
- changes: {
5578
- from: node.from,
5579
- to: node.to
5580
- }
5581
- });
5582
- break;
5583
- }
5584
- }
5585
- };
5586
- this._options.renderBlock(root, {
5587
- readonly: view.state.readOnly,
5588
- link: this._link,
5589
- onAction: handleAction,
5590
- onLookup: this._options.onLookup
5591
- }, view);
5592
- return root;
5896
+ if (features.blocks ?? true) {
5897
+ const blocks = createBlocks(state, getView);
5898
+ nodes.push(...blocks.nodes);
5899
+ edges.push(...blocks.edges);
5593
5900
  }
5901
+ if (features.image) {
5902
+ const image2 = createImageUpload(features.image);
5903
+ nodes.push(...image2.nodes);
5904
+ edges.push(...image2.edges);
5905
+ }
5906
+ if (customActions) {
5907
+ const custom = customActions();
5908
+ nodes.push(...custom.nodes);
5909
+ edges.push(...custom.edges);
5910
+ }
5911
+ const editorToolbarGap = (0, import_react_ui_menu.createGapSeparator)();
5912
+ nodes.push(...editorToolbarGap.nodes);
5913
+ edges.push(...editorToolbarGap.edges);
5914
+ if (features.comment) {
5915
+ const comment = createComment2(state, getView);
5916
+ nodes.push(...comment.nodes);
5917
+ edges.push(...comment.edges);
5918
+ }
5919
+ if (features.search ?? true) {
5920
+ const search = createSearch(getView);
5921
+ nodes.push(...search.nodes);
5922
+ edges.push(...search.edges);
5923
+ }
5924
+ if (features.viewMode) {
5925
+ const viewMode = createViewMode(state, features.viewMode);
5926
+ nodes.push(...viewMode.nodes);
5927
+ edges.push(...viewMode.edges);
5928
+ }
5929
+ return {
5930
+ nodes,
5931
+ edges
5932
+ };
5594
5933
  };
5595
- var defaultItems = [
5596
- "hello world!",
5597
- "this is a test.",
5598
- "this is [DXOS](https://dxos.org)"
5599
- ];
5600
- var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
5601
- let t;
5602
- let idx = 0;
5603
- return [
5604
- import_view29.keymap.of([
5605
- {
5606
- // Reset.
5607
- key: "alt-meta-'",
5608
- run: (view) => {
5609
- clearTimeout(t);
5610
- idx = 0;
5611
- return true;
5612
- }
5613
- },
5614
- {
5615
- // Next prompt.
5616
- // TODO(burdon): Press 1-9 to select prompt?
5617
- key: "shift-meta-'",
5618
- run: (view) => {
5619
- clearTimeout(t);
5620
- const text = items[idx++];
5621
- if (idx === items?.length) {
5622
- idx = 0;
5623
- }
5624
- let i = 0;
5625
- const insert = (d = 0) => {
5626
- t = setTimeout(() => {
5627
- const pos = view.state.selection.main.head;
5628
- view.dispatch({
5629
- changes: {
5630
- from: pos,
5631
- insert: text[i++]
5632
- },
5633
- selection: {
5634
- anchor: pos + 1
5635
- }
5636
- });
5637
- if (i < text.length) {
5638
- insert(Math.random() * delay * (text[i] === " " ? 2 : 1));
5639
- }
5640
- }, d);
5641
- };
5642
- insert();
5643
- return true;
5644
- }
5645
- }
5646
- ])
5647
- ];
5648
- };
5649
- var useActionHandler = (view) => {
5650
- return (0, import_react7.useCallback)((action) => view && processEditorPayload(view, action.properties), [
5651
- view
5934
+ var useEditorToolbarActionGraph = (props) => {
5935
+ const menuCreator = (0, import_react.useCallback)(() => createToolbar(props), [
5936
+ props
5652
5937
  ]);
5938
+ return (0, import_react_ui_menu.useMenuActions)(menuCreator);
5653
5939
  };
5654
- var __dxlog_file11 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
5940
+ var EditorToolbar = /* @__PURE__ */ (0, import_react.memo)(({ classNames, attendableId, role, ...props }) => {
5941
+ const menuProps = useEditorToolbarActionGraph(props);
5942
+ return /* @__PURE__ */ import_react.default.createElement("div", {
5943
+ role: "none",
5944
+ className: stackItemContentToolbarClassNames(role)
5945
+ }, /* @__PURE__ */ import_react.default.createElement(import_react_ui.ElevationProvider, {
5946
+ elevation: role === "section" ? "positioned" : "base"
5947
+ }, /* @__PURE__ */ import_react.default.createElement(import_react_ui_menu.MenuProvider, {
5948
+ ...menuProps,
5949
+ attendableId
5950
+ }, /* @__PURE__ */ import_react.default.createElement(import_react_ui_menu.ToolbarMenu, {
5951
+ classNames: [
5952
+ import_react_ui_theme.textBlockWidth,
5953
+ classNames
5954
+ ]
5955
+ }))));
5956
+ });
5957
+ var __dxlog_file12 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
5655
5958
  var instanceCount = 0;
5656
5959
  var useTextEditor = (props = {}, deps = []) => {
5657
- const { id, doc, initialValue, extensions, autoFocus, scrollTo, selection, moveToEndOfLine, debug } = (0, import_react8.useMemo)(() => (0, import_util5.getProviderValue)(props), deps ?? []);
5658
- const [instanceId] = (0, import_react8.useState)(() => `text-editor-${++instanceCount}`);
5659
- const [view, setView] = (0, import_react8.useState)();
5660
- const parentRef = (0, import_react8.useRef)(null);
5661
- (0, import_react8.useEffect)(() => {
5960
+ const { id, doc, initialValue, extensions, autoFocus, scrollTo, selection, moveToEndOfLine, debug } = (0, import_react7.useMemo)(() => (0, import_util5.getProviderValue)(props), deps ?? []);
5961
+ const [instanceId] = (0, import_react7.useState)(() => `text-editor-${++instanceCount}`);
5962
+ const [view, setView] = (0, import_react7.useState)();
5963
+ const parentRef = (0, import_react7.useRef)(null);
5964
+ (0, import_react7.useEffect)(() => {
5662
5965
  let view2;
5663
5966
  if (parentRef.current) {
5664
- (0, import_log7.log)("create", {
5967
+ (0, import_log8.log)("create", {
5665
5968
  id,
5666
5969
  instanceId,
5667
5970
  doc: initialValue?.length ?? 0
5668
5971
  }, {
5669
- F: __dxlog_file11,
5972
+ F: __dxlog_file12,
5670
5973
  L: 76,
5671
5974
  S: void 0,
5672
5975
  C: (f, a) => f(...a)
@@ -5683,16 +5986,16 @@ var useTextEditor = (props = {}, deps = []) => {
5683
5986
  anchor
5684
5987
  };
5685
5988
  }
5686
- const state = import_state23.EditorState.create({
5989
+ const state = import_state24.EditorState.create({
5687
5990
  doc: doc ?? initialValue,
5688
5991
  // selection: initialSelection,
5689
5992
  extensions: [
5690
5993
  id && documentId.of(id),
5691
5994
  extensions,
5692
5995
  // NOTE: This doesn't catch errors in keymap functions.
5693
- import_view30.EditorView.exceptionSink.of((err) => {
5694
- import_log7.log.catch(err, void 0, {
5695
- F: __dxlog_file11,
5996
+ import_view31.EditorView.exceptionSink.of((err) => {
5997
+ import_log8.log.catch(err, void 0, {
5998
+ F: __dxlog_file12,
5696
5999
  L: 98,
5697
6000
  S: void 0,
5698
6001
  C: (f, a) => f(...a)
@@ -5700,10 +6003,10 @@ var useTextEditor = (props = {}, deps = []) => {
5700
6003
  })
5701
6004
  ].filter(import_util5.isNotFalsy)
5702
6005
  });
5703
- view2 = new import_view30.EditorView({
6006
+ view2 = new import_view31.EditorView({
5704
6007
  parent: parentRef.current,
5705
6008
  state,
5706
- scrollTo: scrollTo ? import_view30.EditorView.scrollIntoView(scrollTo, {
6009
+ scrollTo: scrollTo ? import_view31.EditorView.scrollIntoView(scrollTo, {
5707
6010
  yMargin: 96
5708
6011
  }) : void 0,
5709
6012
  dispatchTransactions: debug ? debugDispatcher : void 0
@@ -5721,10 +6024,10 @@ var useTextEditor = (props = {}, deps = []) => {
5721
6024
  setView(view2);
5722
6025
  }
5723
6026
  return () => {
5724
- (0, import_log7.log)("destroy", {
6027
+ (0, import_log8.log)("destroy", {
5725
6028
  id
5726
6029
  }, {
5727
- F: __dxlog_file11,
6030
+ F: __dxlog_file12,
5728
6031
  L: 135,
5729
6032
  S: void 0,
5730
6033
  C: (f, a) => f(...a)
@@ -5732,16 +6035,16 @@ var useTextEditor = (props = {}, deps = []) => {
5732
6035
  view2?.destroy();
5733
6036
  };
5734
6037
  }, deps);
5735
- (0, import_react8.useEffect)(() => {
6038
+ (0, import_react7.useEffect)(() => {
5736
6039
  if (view) {
5737
6040
  if (scrollTo || selection) {
5738
6041
  if (selection && selection.anchor > view.state.doc.length) {
5739
- import_log7.log.warn("invalid selection", {
6042
+ import_log8.log.warn("invalid selection", {
5740
6043
  length: view.state.doc.length,
5741
6044
  scrollTo,
5742
6045
  selection
5743
6046
  }, {
5744
- F: __dxlog_file11,
6047
+ F: __dxlog_file12,
5745
6048
  L: 144,
5746
6049
  S: void 0,
5747
6050
  C: (f, a) => f(...a)
@@ -5759,7 +6062,7 @@ var useTextEditor = (props = {}, deps = []) => {
5759
6062
  scrollTo,
5760
6063
  selection
5761
6064
  ]);
5762
- (0, import_react8.useEffect)(() => {
6065
+ (0, import_react7.useEffect)(() => {
5763
6066
  if (view && autoFocus) {
5764
6067
  view.focus();
5765
6068
  }
@@ -5773,7 +6076,7 @@ var useTextEditor = (props = {}, deps = []) => {
5773
6076
  Escape: view?.state.facet(editorInputMode).noTabster
5774
6077
  }
5775
6078
  });
5776
- const handleKeyUp = (0, import_react8.useCallback)((event) => {
6079
+ const handleKeyUp = (0, import_react7.useCallback)((event) => {
5777
6080
  const { key, target, currentTarget } = event;
5778
6081
  if (target === currentTarget) {
5779
6082
  switch (key) {
@@ -5877,6 +6180,7 @@ var useTextEditor = (props = {}, deps = []) => {
5877
6180
  mention,
5878
6181
  openCommand,
5879
6182
  openEffect,
6183
+ outliner,
5880
6184
  overlap,
5881
6185
  preventNewline,
5882
6186
  preview,
@@ -5911,7 +6215,6 @@ var useTextEditor = (props = {}, deps = []) => {
5911
6215
  toggleStyle,
5912
6216
  translations,
5913
6217
  typewriter,
5914
- useActionHandler,
5915
6218
  useCommentClickListener,
5916
6219
  useCommentState,
5917
6220
  useComments,