@dxos/react-ui-editor 0.7.5-main.9cb18ac → 0.7.5-main.9d2a38b

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 (74) hide show
  1. package/dist/lib/browser/index.mjs +1105 -1127
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node/index.cjs +1128 -1164
  5. package/dist/lib/node/index.cjs.map +4 -4
  6. package/dist/lib/node/meta.json +1 -1
  7. package/dist/lib/node-esm/index.mjs +1105 -1127
  8. package/dist/lib/node-esm/index.mjs.map +4 -4
  9. package/dist/lib/node-esm/meta.json +1 -1
  10. package/dist/types/src/InputMode.stories.d.ts.map +1 -1
  11. package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts +4 -0
  12. package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts.map +1 -0
  13. package/dist/types/src/components/EditorToolbar/blocks.d.ts +18 -0
  14. package/dist/types/src/components/EditorToolbar/blocks.d.ts.map +1 -0
  15. package/dist/types/src/components/EditorToolbar/comment.d.ts +17 -0
  16. package/dist/types/src/components/EditorToolbar/comment.d.ts.map +1 -0
  17. package/dist/types/src/components/EditorToolbar/formatting.d.ts +18 -0
  18. package/dist/types/src/components/EditorToolbar/formatting.d.ts.map +1 -0
  19. package/dist/types/src/components/EditorToolbar/headings.d.ts +18 -0
  20. package/dist/types/src/components/EditorToolbar/headings.d.ts.map +1 -0
  21. package/dist/types/src/components/EditorToolbar/index.d.ts +3 -0
  22. package/dist/types/src/components/EditorToolbar/index.d.ts.map +1 -0
  23. package/dist/types/src/components/EditorToolbar/lists.d.ts +18 -0
  24. package/dist/types/src/components/EditorToolbar/lists.d.ts.map +1 -0
  25. package/dist/types/src/components/EditorToolbar/util.d.ts +58 -0
  26. package/dist/types/src/components/EditorToolbar/util.d.ts.map +1 -0
  27. package/dist/types/src/components/EditorToolbar/viewMode.d.ts +18 -0
  28. package/dist/types/src/components/EditorToolbar/viewMode.d.ts.map +1 -0
  29. package/dist/types/src/components/index.d.ts +1 -1
  30. package/dist/types/src/components/index.d.ts.map +1 -1
  31. package/dist/types/src/extensions/comments.d.ts +3 -4
  32. package/dist/types/src/extensions/comments.d.ts.map +1 -1
  33. package/dist/types/src/extensions/markdown/editorAction.d.ts +12 -0
  34. package/dist/types/src/extensions/markdown/editorAction.d.ts.map +1 -0
  35. package/dist/types/src/extensions/markdown/formatting.d.ts +14 -12
  36. package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -1
  37. package/dist/types/src/extensions/markdown/index.d.ts +1 -1
  38. package/dist/types/src/extensions/markdown/index.d.ts.map +1 -1
  39. package/dist/types/src/extensions/markdown/styles.d.ts.map +1 -1
  40. package/dist/types/src/hooks/useActionHandler.d.ts +2 -2
  41. package/dist/types/src/hooks/useActionHandler.d.ts.map +1 -1
  42. package/dist/types/src/index.d.ts +1 -0
  43. package/dist/types/src/index.d.ts.map +1 -1
  44. package/dist/types/src/styles/stack-item-content-class-names.d.ts +3 -0
  45. package/dist/types/src/styles/stack-item-content-class-names.d.ts.map +1 -0
  46. package/dist/types/tsconfig.tsbuildinfo +1 -1
  47. package/package.json +28 -27
  48. package/src/InputMode.stories.tsx +7 -10
  49. package/src/components/EditorToolbar/EditorToolbar.tsx +106 -0
  50. package/src/components/EditorToolbar/blocks.ts +41 -0
  51. package/src/components/EditorToolbar/comment.ts +20 -0
  52. package/src/components/EditorToolbar/formatting.ts +41 -0
  53. package/src/components/EditorToolbar/headings.ts +59 -0
  54. package/src/components/EditorToolbar/index.ts +6 -0
  55. package/src/components/EditorToolbar/lists.ts +40 -0
  56. package/src/components/EditorToolbar/util.ts +65 -0
  57. package/src/components/EditorToolbar/viewMode.ts +48 -0
  58. package/src/components/index.ts +1 -1
  59. package/src/extensions/comments.ts +8 -15
  60. package/src/extensions/markdown/{action.ts → editorAction.ts} +22 -20
  61. package/src/extensions/markdown/formatting.ts +20 -24
  62. package/src/extensions/markdown/index.ts +1 -1
  63. package/src/extensions/markdown/styles.ts +21 -0
  64. package/src/hooks/useActionHandler.ts +4 -4
  65. package/src/index.ts +4 -0
  66. package/src/styles/stack-item-content-class-names.ts +17 -0
  67. package/dist/types/src/components/Toolbar/Toolbar.d.ts +0 -34
  68. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +0 -1
  69. package/dist/types/src/components/Toolbar/index.d.ts +0 -2
  70. package/dist/types/src/components/Toolbar/index.d.ts.map +0 -1
  71. package/dist/types/src/extensions/markdown/action.d.ts +0 -9
  72. package/dist/types/src/extensions/markdown/action.d.ts.map +0 -1
  73. package/src/components/Toolbar/Toolbar.tsx +0 -522
  74. package/src/components/Toolbar/index.ts +0 -5
@@ -32,6 +32,7 @@ __export(node_exports, {
32
32
  EditorInputMode: () => EditorInputMode,
33
33
  EditorInputModes: () => EditorInputModes,
34
34
  EditorState: () => import_state.EditorState,
35
+ EditorToolbar: () => EditorToolbar,
35
36
  EditorView: () => import_view.EditorView,
36
37
  EditorViewMode: () => EditorViewMode,
37
38
  EditorViewModes: () => EditorViewModes,
@@ -41,7 +42,6 @@ __export(node_exports, {
41
42
  RemoteSelectionsDecorator: () => RemoteSelectionsDecorator,
42
43
  SpaceAwarenessProvider: () => SpaceAwarenessProvider,
43
44
  TextKind: () => import_text.TextKind,
44
- Toolbar: () => Toolbar,
45
45
  addBlockquote: () => addBlockquote,
46
46
  addCodeblock: () => addCodeblock,
47
47
  addLink: () => addLink,
@@ -60,8 +60,10 @@ __export(node_exports, {
60
60
  commentsState: () => commentsState,
61
61
  convertTreeToJson: () => convertTreeToJson,
62
62
  createBasicExtensions: () => createBasicExtensions,
63
- createComment: () => createComment,
63
+ createComment: () => createComment2,
64
64
  createDataExtensions: () => createDataExtensions,
65
+ createEditorAction: () => createEditorAction,
66
+ createEditorActionGroup: () => createEditorActionGroup,
65
67
  createEditorStateStore: () => createEditorStateStore,
66
68
  createEditorStateTransaction: () => createEditorStateTransaction,
67
69
  createElement: () => createElement,
@@ -100,7 +102,7 @@ __export(node_exports, {
100
102
  mention: () => mention,
101
103
  overlap: () => overlap,
102
104
  preventNewline: () => preventNewline,
103
- processAction: () => processAction,
105
+ processEditorPayload: () => processEditorPayload,
104
106
  removeBlockquote: () => removeBlockquote,
105
107
  removeCodeblock: () => removeCodeblock,
106
108
  removeLink: () => removeLink,
@@ -116,6 +118,8 @@ __export(node_exports, {
116
118
  setSelection: () => setSelection,
117
119
  setStyle: () => setStyle,
118
120
  singleValueFacet: () => singleValueFacet,
121
+ stackItemContentEditorClassNames: () => stackItemContentEditorClassNames,
122
+ stackItemContentToolbarClassNames: () => stackItemContentToolbarClassNames,
119
123
  table: () => table,
120
124
  tags: () => import_highlight.tags,
121
125
  textRange: () => textRange,
@@ -133,9 +137,9 @@ __export(node_exports, {
133
137
  useCommentClickListener: () => useCommentClickListener,
134
138
  useCommentState: () => useCommentState,
135
139
  useComments: () => useComments,
140
+ useEditorToolbarState: () => useEditorToolbarState,
136
141
  useFormattingState: () => useFormattingState,
137
142
  useTextEditor: () => useTextEditor,
138
- useToolbarContext: () => useToolbarContext,
139
143
  wrapWithCatch: () => wrapWithCatch
140
144
  });
141
145
  module.exports = __toCommonJS(node_exports);
@@ -143,26 +147,33 @@ var import_state = require("@codemirror/state");
143
147
  var import_view = require("@codemirror/view");
144
148
  var import_highlight = require("@lezer/highlight");
145
149
  var import_text = require("@dxos/protocols/proto/dxos/echo/model/text");
146
- var import_react = require("@phosphor-icons/react");
147
- var import_react_context = require("@radix-ui/react-context");
148
- var import_react2 = __toESM(require("react"));
149
- var import_react_dropzone = require("react-dropzone");
150
+ var import_react = __toESM(require("react"));
150
151
  var import_react_ui = require("@dxos/react-ui");
152
+ var import_react_ui_menu = require("@dxos/react-ui-menu");
151
153
  var import_react_ui_theme = require("@dxos/react-ui-theme");
152
- var import_state2 = require("@codemirror/state");
154
+ var import_react2 = require("react");
155
+ var import_live_object = require("@dxos/live-object");
156
+ var import_react_ui_menu2 = require("@dxos/react-ui-menu");
157
+ var import_react_ui_theme2 = require("@dxos/react-ui-theme");
153
158
  var import_view2 = require("@codemirror/view");
159
+ var import_react_ui_theme3 = require("@dxos/react-ui-theme");
160
+ var import_react_ui_theme4 = require("@dxos/react-ui-theme");
161
+ var import_lodash = __toESM(require("lodash.get"));
162
+ var import_react_ui_theme5 = require("@dxos/react-ui-theme");
163
+ var import_state2 = require("@codemirror/state");
164
+ var import_view3 = require("@codemirror/view");
154
165
  var import_util = require("@dxos/util");
155
166
  var import_state3 = require("@codemirror/state");
156
167
  var import_log = require("@dxos/log");
157
168
  var import_react3 = __toESM(require("react"));
158
169
  var import_client = require("react-dom/client");
159
170
  var import_react_ui2 = require("@dxos/react-ui");
160
- var import_react_ui_theme2 = require("@dxos/react-ui-theme");
171
+ var import_react_ui_theme6 = require("@dxos/react-ui-theme");
161
172
  var import_autocomplete = require("@codemirror/autocomplete");
162
173
  var import_lang_markdown = require("@codemirror/lang-markdown");
163
- var import_view3 = require("@codemirror/view");
164
- var import_state4 = require("@codemirror/state");
165
174
  var import_view4 = require("@codemirror/view");
175
+ var import_state4 = require("@codemirror/state");
176
+ var import_view5 = require("@codemirror/view");
166
177
  var import_automerge = require("@dxos/automerge/automerge");
167
178
  var import_log2 = require("@dxos/log");
168
179
  var import_echo = require("@dxos/react-client/echo");
@@ -171,64 +182,61 @@ var import_automerge2 = require("@dxos/automerge/automerge");
171
182
  var import_automerge3 = require("@dxos/automerge/automerge");
172
183
  var import_state6 = require("@codemirror/state");
173
184
  var import_state7 = require("@codemirror/state");
174
- var import_view5 = require("@codemirror/view");
185
+ var import_view6 = require("@codemirror/view");
175
186
  var import_async = require("@dxos/async");
176
187
  var import_context = require("@dxos/context");
177
188
  var import_async2 = require("@dxos/async");
178
189
  var import_context2 = require("@dxos/context");
179
190
  var import_invariant = require("@dxos/invariant");
180
191
  var import_log3 = require("@dxos/log");
181
- var import_view6 = require("@codemirror/view");
182
- var import_lodash = __toESM(require("lodash.defaultsdeep"));
183
- var import_invariant2 = require("@dxos/invariant");
184
192
  var import_view7 = require("@codemirror/view");
185
- var import_state8 = require("@codemirror/state");
193
+ var import_lodash2 = __toESM(require("lodash.defaultsdeep"));
194
+ var import_invariant2 = require("@dxos/invariant");
186
195
  var import_view8 = require("@codemirror/view");
187
- var import_state9 = require("@codemirror/state");
196
+ var import_state8 = require("@codemirror/state");
188
197
  var import_view9 = require("@codemirror/view");
198
+ var import_state9 = require("@codemirror/state");
199
+ var import_view10 = require("@codemirror/view");
189
200
  var import_commands = require("@codemirror/commands");
190
201
  var import_state10 = require("@codemirror/state");
191
- var import_view10 = require("@codemirror/view");
192
- var import_lodash2 = __toESM(require("lodash.sortby"));
202
+ var import_view11 = require("@codemirror/view");
203
+ var import_lodash3 = __toESM(require("lodash.sortby"));
193
204
  var import_react4 = require("react");
194
205
  var import_async3 = require("@dxos/async");
195
206
  var import_log4 = require("@dxos/log");
196
207
  var import_util2 = require("@dxos/util");
197
208
  var import_state11 = require("@codemirror/state");
198
- var import_view11 = require("@codemirror/view");
209
+ var import_view12 = require("@codemirror/view");
199
210
  var import_async4 = require("@dxos/async");
200
211
  var import_invariant3 = require("@dxos/invariant");
201
212
  var import_util3 = require("@dxos/util");
202
213
  var import_language = require("@codemirror/language");
203
214
  var import_state12 = require("@codemirror/state");
204
- var import_view12 = require("@codemirror/view");
215
+ var import_view13 = require("@codemirror/view");
205
216
  var import_autocomplete2 = require("@codemirror/autocomplete");
206
217
  var import_commands2 = require("@codemirror/commands");
207
218
  var import_language2 = require("@codemirror/language");
208
219
  var import_search = require("@codemirror/search");
209
220
  var import_state13 = require("@codemirror/state");
210
221
  var import_theme_one_dark = require("@codemirror/theme-one-dark");
211
- var import_view13 = require("@codemirror/view");
212
- var import_lodash3 = __toESM(require("lodash.defaultsdeep"));
213
- var import_lodash4 = __toESM(require("lodash.merge"));
222
+ var import_view14 = require("@codemirror/view");
223
+ var import_lodash4 = __toESM(require("lodash.defaultsdeep"));
224
+ var import_lodash5 = __toESM(require("lodash.merge"));
214
225
  var import_display_name = require("@dxos/display-name");
215
226
  var import_log5 = require("@dxos/log");
216
- var import_react_ui_theme3 = require("@dxos/react-ui-theme");
227
+ var import_react_ui_theme7 = require("@dxos/react-ui-theme");
217
228
  var import_util4 = require("@dxos/util");
218
229
  var import_state14 = require("@codemirror/state");
219
- var import_view14 = require("@codemirror/view");
220
- var import_react_ui_theme4 = require("@dxos/react-ui-theme");
221
- var import_lodash5 = __toESM(require("lodash.get"));
222
- var import_react_ui_theme5 = require("@dxos/react-ui-theme");
223
- var import_language3 = require("@codemirror/language");
224
230
  var import_view15 = require("@codemirror/view");
231
+ var import_language3 = require("@codemirror/language");
232
+ var import_view16 = require("@codemirror/view");
225
233
  var import_react5 = __toESM(require("react"));
226
234
  var import_react_ui3 = require("@dxos/react-ui");
227
- var import_view16 = require("@codemirror/view");
235
+ var import_view17 = require("@codemirror/view");
228
236
  var import_autocomplete3 = require("@codemirror/autocomplete");
229
237
  var import_language4 = require("@codemirror/language");
230
238
  var import_state15 = require("@codemirror/state");
231
- var import_view17 = require("@codemirror/view");
239
+ var import_view18 = require("@codemirror/view");
232
240
  var import_react6 = require("react");
233
241
  var import_autocomplete4 = require("@codemirror/autocomplete");
234
242
  var import_commands3 = require("@codemirror/commands");
@@ -236,7 +244,7 @@ var import_lang_markdown2 = require("@codemirror/lang-markdown");
236
244
  var import_language5 = require("@codemirror/language");
237
245
  var import_language_data = require("@codemirror/language-data");
238
246
  var import_lint = require("@codemirror/lint");
239
- var import_view18 = require("@codemirror/view");
247
+ var import_view19 = require("@codemirror/view");
240
248
  var import_lang_markdown3 = require("@codemirror/lang-markdown");
241
249
  var import_language6 = require("@codemirror/language");
242
250
  var import_highlight2 = require("@lezer/highlight");
@@ -245,35 +253,34 @@ var import_language7 = require("@codemirror/language");
245
253
  var import_state16 = require("@codemirror/state");
246
254
  var import_language8 = require("@codemirror/language");
247
255
  var import_state17 = require("@codemirror/state");
248
- var import_view19 = require("@codemirror/view");
256
+ var import_view20 = require("@codemirror/view");
249
257
  var import_invariant4 = require("@dxos/invariant");
250
- var import_react_ui_theme6 = require("@dxos/react-ui-theme");
258
+ var import_react_ui_theme8 = require("@dxos/react-ui-theme");
251
259
  var import_language9 = require("@codemirror/language");
252
260
  var import_state18 = require("@codemirror/state");
253
- var import_view20 = require("@codemirror/view");
261
+ var import_view21 = require("@codemirror/view");
254
262
  var import_language10 = require("@codemirror/language");
255
263
  var import_state19 = require("@codemirror/state");
256
- var import_view21 = require("@codemirror/view");
257
264
  var import_view22 = require("@codemirror/view");
265
+ var import_view23 = require("@codemirror/view");
258
266
  var import_language11 = require("@codemirror/language");
259
267
  var import_state20 = require("@codemirror/state");
260
- var import_view23 = require("@codemirror/view");
261
- var import_language12 = require("@codemirror/language");
262
268
  var import_view24 = require("@codemirror/view");
263
- var import_react_ui_theme7 = require("@dxos/react-ui-theme");
269
+ var import_language12 = require("@codemirror/language");
270
+ var import_view25 = require("@codemirror/view");
271
+ var import_react_ui_theme9 = require("@dxos/react-ui-theme");
264
272
  var import_autocomplete5 = require("@codemirror/autocomplete");
265
273
  var import_log6 = require("@dxos/log");
266
- var import_view25 = require("@codemirror/view");
274
+ var import_view26 = require("@codemirror/view");
267
275
  var import_codemirror_vim = require("@replit/codemirror-vim");
268
276
  var import_codemirror_vscode_keymap = require("@replit/codemirror-vscode-keymap");
269
277
  var import_echo_schema = require("@dxos/echo-schema");
270
- var import_view26 = require("@codemirror/view");
271
278
  var import_view27 = require("@codemirror/view");
272
- var import_react_ui_theme8 = require("@dxos/react-ui-theme");
279
+ var import_react7 = require("react");
273
280
  var import_state21 = require("@codemirror/state");
274
281
  var import_view28 = require("@codemirror/view");
275
282
  var import_react_tabster = require("@fluentui/react-tabster");
276
- var import_react7 = require("react");
283
+ var import_react8 = require("react");
277
284
  var import_log7 = require("@dxos/log");
278
285
  var import_util5 = require("@dxos/util");
279
286
  var translationKey = "react-ui-editor";
@@ -309,212 +316,774 @@ var translations_default = [
309
316
  }
310
317
  }
311
318
  ];
312
- var singleValueFacet = (defaultValue) => import_state3.Facet.define({
313
- // Called immediately.
314
- combine: (providers) => {
315
- return providers[0] ?? defaultValue;
319
+ var useEditorToolbarState = (initialState = {}) => {
320
+ return (0, import_react2.useMemo)(() => (0, import_live_object.create)(initialState), []);
321
+ };
322
+ var createEditorAction = (payload, icon, label = [
323
+ `${payload.type} label`,
324
+ {
325
+ ns: translationKey
316
326
  }
327
+ ], id = payload.type) => (0, import_react_ui_menu2.createMenuAction)(id, {
328
+ icon,
329
+ label,
330
+ ...payload
317
331
  });
318
- var overlap = (a, b) => a.from <= b.to && a.to >= b.from;
319
- var defaultCursorConverter = {
320
- toCursor: (position) => position.toString(),
321
- fromCursor: (cursor) => parseInt(cursor)
332
+ var createEditorActionGroup = (id, props, icon) => (0, import_react_ui_menu2.createMenuItemGroup)(id, {
333
+ icon,
334
+ iconOnly: true,
335
+ ...props
336
+ });
337
+ var editorToolbarSearch = createEditorAction({
338
+ type: "search"
339
+ }, "ph--magnifying-glass--regular");
340
+ var createBlockGroupAction = (value) => createEditorActionGroup("block", {
341
+ variant: "toggleGroup",
342
+ selectCardinality: "single",
343
+ value
344
+ });
345
+ var createBlockActions = (value, blankLine) => Object.entries({
346
+ blockquote: "ph--quotes--regular",
347
+ codeblock: "ph--code-block--regular",
348
+ table: "ph--table--regular"
349
+ }).map(([type, icon]) => {
350
+ return createEditorAction({
351
+ type,
352
+ checked: type === value,
353
+ ...type === "table" && {
354
+ disabled: !!blankLine
355
+ }
356
+ }, icon);
357
+ });
358
+ var createBlocks = (state) => {
359
+ const value = state?.blockQuote ? "blockquote" : state.blockType ?? "";
360
+ const blockGroupAction = createBlockGroupAction(value);
361
+ const blockActions = createBlockActions(value, state.blankLine);
362
+ return {
363
+ nodes: [
364
+ blockGroupAction,
365
+ ...blockActions
366
+ ],
367
+ edges: [
368
+ {
369
+ source: "root",
370
+ target: "block"
371
+ },
372
+ ...blockActions.map(({ id }) => ({
373
+ source: blockGroupAction.id,
374
+ target: id
375
+ }))
376
+ ]
377
+ };
322
378
  };
323
- var Cursor = class _Cursor {
324
- static {
325
- this.converter = singleValueFacet(defaultCursorConverter);
326
- }
327
- static {
328
- this.getCursorFromRange = (state, range) => {
329
- const cursorConverter2 = state.facet(_Cursor.converter);
330
- const from = cursorConverter2.toCursor(range.from);
331
- const to = cursorConverter2.toCursor(range.to, -1);
332
- return [
333
- from,
334
- to
335
- ].join(":");
336
- };
337
- }
338
- static {
339
- this.getRangeFromCursor = (state, cursor) => {
340
- const cursorConverter2 = state.facet(_Cursor.converter);
341
- const parts = cursor.split(":");
342
- const from = cursorConverter2.fromCursor(parts[0]);
343
- const to = cursorConverter2.fromCursor(parts[1]);
344
- return from !== void 0 && to !== void 0 ? {
345
- from,
346
- to
347
- } : void 0;
348
- };
349
- }
379
+ var commentLabel = (comment, selection) => comment ? "selection overlaps existing comment label" : selection === false ? "select text to comment label" : "comment label";
380
+ var createCommentAction = (label) => createEditorAction({
381
+ type: "comment",
382
+ testId: "editor.toolbar.comment"
383
+ }, "ph--chat-text--regular", label);
384
+ var createComment = (state) => ({
385
+ nodes: [
386
+ createCommentAction(commentLabel(state.comment, state.selection))
387
+ ],
388
+ edges: [
389
+ {
390
+ source: "root",
391
+ target: "comment"
392
+ }
393
+ ]
394
+ });
395
+ var formats = {
396
+ strong: "ph--text-b--regular",
397
+ emphasis: "ph--text-italic--regular",
398
+ strikethrough: "ph--text-strikethrough--regular",
399
+ code: "ph--code--regular",
400
+ link: "ph--link--regular"
401
+ };
402
+ var createFormattingGroup = (formatting) => createEditorActionGroup("formatting", {
403
+ variant: "toggleGroup",
404
+ selectCardinality: "multiple",
405
+ value: Object.keys(formats).filter((key) => !!formatting[key])
406
+ });
407
+ var createFormattingActions = (formatting) => Object.entries(formats).map(([type, icon]) => createEditorAction({
408
+ type,
409
+ checked: !!formatting[type]
410
+ }, icon));
411
+ var createFormatting = (state) => {
412
+ const formattingGroupAction = createFormattingGroup(state);
413
+ const formattingActions = createFormattingActions(state);
414
+ return {
415
+ nodes: [
416
+ formattingGroupAction,
417
+ ...formattingActions
418
+ ],
419
+ edges: [
420
+ {
421
+ source: "root",
422
+ target: "formatting"
423
+ },
424
+ ...formattingActions.map(({ id }) => ({
425
+ source: formattingGroupAction.id,
426
+ target: id
427
+ }))
428
+ ]
429
+ };
350
430
  };
351
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util/debug.ts";
352
- var wrapWithCatch = (fn) => {
353
- return (...args) => {
354
- try {
355
- return fn(...args);
356
- } catch (err) {
357
- import_log.log.catch(err, void 0, {
358
- F: __dxlog_file,
359
- L: 15,
360
- S: void 0,
361
- C: (f, a) => f(...a)
362
- });
431
+ var createHeadingGroupAction = (value) => createEditorActionGroup("heading", {
432
+ variant: "dropdownMenu",
433
+ applyActive: true,
434
+ selectCardinality: "single",
435
+ value
436
+ }, "ph--text-h--regular");
437
+ var createHeadingActions = (value) => Object.entries({
438
+ "0": "ph--paragraph--regular",
439
+ "1": "ph--text-h-one--regular",
440
+ "2": "ph--text-h-two--regular",
441
+ "3": "ph--text-h-three--regular",
442
+ "4": "ph--text-h-four--regular",
443
+ "5": "ph--text-h-five--regular",
444
+ "6": "ph--text-h-six--regular"
445
+ }).map(([levelStr, icon]) => {
446
+ const level = parseInt(levelStr);
447
+ return createEditorAction({
448
+ type: "heading",
449
+ data: level,
450
+ checked: value === levelStr
451
+ }, icon, [
452
+ "heading level label",
453
+ {
454
+ count: level,
455
+ ns: translationKey
363
456
  }
457
+ ], `heading--${levelStr}`);
458
+ });
459
+ var computeHeadingValue = (state) => {
460
+ const blockType = state ? state.blockType : "paragraph";
461
+ const header = blockType && /heading(\d)/.exec(blockType);
462
+ return header ? header[1] : blockType === "paragraph" || !blockType ? "0" : "";
463
+ };
464
+ var createHeadings = (state) => {
465
+ const headingValue = computeHeadingValue(state);
466
+ const headingGroupAction = createHeadingGroupAction(headingValue);
467
+ const headingActions = createHeadingActions(headingValue);
468
+ return {
469
+ nodes: [
470
+ headingGroupAction,
471
+ ...headingActions
472
+ ],
473
+ edges: [
474
+ {
475
+ source: "root",
476
+ target: "heading"
477
+ },
478
+ ...headingActions.map(({ id }) => ({
479
+ source: headingGroupAction.id,
480
+ target: id
481
+ }))
482
+ ]
364
483
  };
365
484
  };
366
- var callbackWrapper = (fn) => (...args) => {
367
- try {
368
- return fn(...args);
369
- } catch (err) {
370
- import_log.log.catch(err, void 0, {
371
- F: __dxlog_file,
372
- L: 29,
373
- S: void 0,
374
- C: (f, a) => f(...a)
375
- });
376
- }
485
+ var listStyles = {
486
+ bullet: "ph--list-bullets--regular",
487
+ ordered: "ph--list-numbers--regular",
488
+ task: "ph--list-checks--regular"
377
489
  };
378
- var debugDispatcher = (trs, view) => {
379
- logChanges(trs);
380
- view.update(trs);
490
+ var createListGroupAction = (value) => createEditorActionGroup("list", {
491
+ variant: "toggleGroup",
492
+ selectCardinality: "single",
493
+ value
494
+ });
495
+ var createListActions = (value) => Object.entries(listStyles).map(([listStyle, icon]) => createEditorAction({
496
+ type: `list-${listStyle}`,
497
+ checked: value === listStyle
498
+ }, icon));
499
+ var createLists = (state) => {
500
+ const value = state.listStyle ?? "";
501
+ const listGroupAction = createListGroupAction(value);
502
+ const listActionsMap = createListActions(value);
503
+ return {
504
+ nodes: [
505
+ listGroupAction,
506
+ ...listActionsMap
507
+ ],
508
+ edges: [
509
+ {
510
+ source: "root",
511
+ target: "list"
512
+ },
513
+ ...listActionsMap.map(({ id }) => ({
514
+ source: listGroupAction.id,
515
+ target: id
516
+ }))
517
+ ]
518
+ };
381
519
  };
382
- var logChanges = (trs) => {
383
- const changes = trs.flatMap((tr) => {
384
- if (tr.changes.empty) {
385
- return void 0;
520
+ var createViewModeGroupAction = (value) => createEditorActionGroup("viewMode", {
521
+ variant: "dropdownMenu",
522
+ applyActive: true,
523
+ selectCardinality: "single",
524
+ value
525
+ }, "ph--eye--regular");
526
+ var createViewModeActions = (value) => Object.entries({
527
+ preview: "ph--eye--regular",
528
+ source: "ph--pencil-simple--regular",
529
+ readonly: "ph--pencil-slash--regular"
530
+ }).map(([viewMode, icon]) => {
531
+ return createEditorAction({
532
+ type: "view-mode",
533
+ data: viewMode,
534
+ checked: viewMode === value
535
+ }, icon, [
536
+ `${viewMode} mode label`,
537
+ {
538
+ ns: translationKey
386
539
  }
387
- const changes2 = [];
388
- tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => changes2.push(JSON.stringify({
389
- fromA,
390
- toA,
391
- fromB,
392
- toB,
393
- inserted: inserted.toString()
394
- })));
395
- return changes2;
396
- }).filter(Boolean);
397
- if (changes.length) {
398
- import_log.log.info("changes", {
399
- changes
400
- }, {
401
- F: __dxlog_file,
402
- L: 62,
403
- S: void 0,
404
- C: (f, a) => f(...a)
540
+ ], `view-mode--${viewMode}`);
541
+ });
542
+ var createViewMode = (state) => {
543
+ const value = state.viewMode ?? "source";
544
+ const viewModeGroupAction = createViewModeGroupAction(value);
545
+ const viewModeActions = createViewModeActions(value);
546
+ return {
547
+ nodes: [
548
+ viewModeGroupAction,
549
+ ...viewModeActions
550
+ ],
551
+ edges: [
552
+ {
553
+ source: "root",
554
+ target: "viewMode"
555
+ },
556
+ ...viewModeActions.map(({ id }) => ({
557
+ source: viewModeGroupAction.id,
558
+ target: id
559
+ }))
560
+ ]
561
+ };
562
+ };
563
+ var stackItemContentEditorClassNames = (role) => (0, import_react_ui_theme2.mx)("ch-focus-ring-inset data-[toolbar=disabled]:pbs-2 attention-surface", role === "article" ? "min-bs-0" : "[&_.cm-scroller]:overflow-hidden [&_.cm-scroller]:min-bs-24");
564
+ var stackItemContentToolbarClassNames = (role) => (0, import_react_ui_theme2.mx)("attention-surface is-full border-be !border-separator", role === "section" && "sticky block-start-0 z-[1] -mbe-px min-is-0");
565
+ var createToolbar = ({ state, customActions, ...features }) => {
566
+ const nodes = [];
567
+ const edges = [];
568
+ if (features.headings ?? true) {
569
+ const headings2 = createHeadings(state);
570
+ nodes.push(...headings2.nodes);
571
+ edges.push(...headings2.edges);
572
+ }
573
+ if (features.formatting ?? true) {
574
+ const formatting = createFormatting(state);
575
+ nodes.push(...formatting.nodes);
576
+ edges.push(...formatting.edges);
577
+ }
578
+ if (features.lists ?? true) {
579
+ const lists = createLists(state);
580
+ nodes.push(...lists.nodes);
581
+ edges.push(...lists.edges);
582
+ }
583
+ if (features.blocks ?? true) {
584
+ const blocks = createBlocks(state);
585
+ nodes.push(...blocks.nodes);
586
+ edges.push(...blocks.edges);
587
+ }
588
+ if (customActions) {
589
+ const custom = customActions();
590
+ nodes.push(...custom.nodes);
591
+ edges.push(...custom.edges);
592
+ }
593
+ const editorToolbarGap = (0, import_react_ui_menu.createGapSeparator)();
594
+ nodes.push(...editorToolbarGap.nodes);
595
+ edges.push(...editorToolbarGap.edges);
596
+ if (features.comment ?? true) {
597
+ const comment = createComment(state);
598
+ nodes.push(...comment.nodes);
599
+ edges.push(...comment.edges);
600
+ }
601
+ if (features.search ?? true) {
602
+ nodes.push(editorToolbarSearch);
603
+ edges.push({
604
+ source: "root",
605
+ target: editorToolbarSearch.id
405
606
  });
406
607
  }
608
+ if (features.viewMode ?? true) {
609
+ const viewMode = createViewMode(state);
610
+ nodes.push(...viewMode.nodes);
611
+ edges.push(...viewMode.edges);
612
+ }
613
+ return {
614
+ nodes,
615
+ edges
616
+ };
407
617
  };
408
- var flattenRect = (rect, left) => {
409
- const x = left ? rect.left : rect.right;
618
+ var useEditorToolbarActionGraph = ({ onAction, ...props }) => {
619
+ const menuCreator = (0, import_react.useCallback)(() => createToolbar(props), [
620
+ props
621
+ ]);
622
+ const { resolveGroupItems } = (0, import_react_ui_menu.useMenuActions)(menuCreator);
410
623
  return {
411
- left: x,
412
- right: x,
413
- top: rect.top,
414
- bottom: rect.bottom
624
+ resolveGroupItems,
625
+ onAction
415
626
  };
416
627
  };
417
- var scratchRange;
418
- var textRange = (node, from, to = from) => {
419
- const range = scratchRange || (scratchRange = document.createRange());
420
- range.setEnd(node, to);
421
- range.setStart(node, from);
422
- return range;
628
+ var EditorToolbar = ({ classNames, attendableId, role, ...props }) => {
629
+ const menuProps = useEditorToolbarActionGraph(props);
630
+ return /* @__PURE__ */ import_react.default.createElement("div", {
631
+ role: "none",
632
+ className: stackItemContentToolbarClassNames(role)
633
+ }, /* @__PURE__ */ import_react.default.createElement(import_react_ui.ElevationProvider, {
634
+ elevation: role === "section" ? "positioned" : "base"
635
+ }, /* @__PURE__ */ import_react.default.createElement(import_react_ui_menu.MenuProvider, {
636
+ ...menuProps,
637
+ attendableId
638
+ }, /* @__PURE__ */ import_react.default.createElement(import_react_ui_menu.ToolbarMenu, {
639
+ classNames: [
640
+ import_react_ui_theme.textBlockWidth,
641
+ "!bg-transparent",
642
+ classNames
643
+ ]
644
+ }))));
423
645
  };
424
- var clientRectsFor = (dom) => {
425
- if (dom.nodeType === 3) {
426
- return textRange(dom, 0, dom.nodeValue.length).getClientRects();
427
- } else if (dom.nodeType === 1) {
428
- return dom.getClientRects();
429
- } else {
430
- return [];
431
- }
646
+ var headings = {
647
+ 1: "text-4xl",
648
+ 2: "text-3xl",
649
+ 3: "text-2xl",
650
+ 4: "text-xl",
651
+ 5: "text-lg",
652
+ 6: "text-md"
432
653
  };
433
- var createElement = (tag, options, children) => {
434
- const el = document.createElement(tag);
435
- if (options?.className) {
436
- el.className = options.className;
437
- }
438
- if (children) {
439
- el.append(...Array.isArray(children) ? children : [
440
- children
441
- ]);
654
+ var theme = {
655
+ code: "font-mono !no-underline text-neutral-700 dark:text-neutral-300",
656
+ codeMark: "font-mono text-primary-500",
657
+ mark: "opacity-50",
658
+ heading: (level) => {
659
+ return (0, import_react_ui_theme4.mx)(headings[level], "dark:text-primary-400");
442
660
  }
443
- return el;
444
661
  };
445
- var renderRoot = (root, node) => {
446
- (0, import_client.createRoot)(root).render(/* @__PURE__ */ import_react3.default.createElement(import_react_ui2.ThemeProvider, {
447
- tx: import_react_ui_theme2.defaultTx
448
- }, node));
449
- return root;
662
+ var getToken = (path, defaultValue) => {
663
+ const value = (0, import_lodash.default)(import_react_ui_theme5.tokens, path, defaultValue);
664
+ return value?.toString() ?? "";
450
665
  };
451
- var annotationMark = import_view2.Decoration.mark({
452
- class: "cm-annotation"
453
- });
454
- var annotations = (options = {}) => {
455
- const match = (state) => {
456
- const annotations2 = [];
457
- const text = state.doc.toString();
458
- if (options.match) {
459
- const matches = text.matchAll(options.match);
460
- for (const match2 of matches) {
461
- const from = match2.index;
462
- const to = from + match2[0].length;
463
- const cursor = Cursor.getCursorFromRange(state, {
464
- from,
465
- to
466
- });
467
- annotations2.push({
468
- cursor
469
- });
470
- }
471
- }
472
- return annotations2;
473
- };
474
- const annotationsState = import_state2.StateField.define({
475
- create: (state) => {
476
- return match(state);
666
+ var fontBody = getToken("fontFamily.body");
667
+ var fontMono = getToken("fontFamily.mono");
668
+ var defaultTheme = {
669
+ "&": {},
670
+ "&.cm-focused": {
671
+ outline: "none"
672
+ },
673
+ /**
674
+ * Scroller
675
+ */
676
+ ".cm-scroller": {
677
+ overflowY: "auto"
678
+ },
679
+ /**
680
+ * Content
681
+ * NOTE: Apply margins to content so that scrollbar is at the edge of the container.
682
+ */
683
+ ".cm-content": {
684
+ padding: "unset",
685
+ fontFamily: fontBody,
686
+ // NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
687
+ fontSize: "16px",
688
+ lineHeight: 1.5,
689
+ color: "unset"
690
+ },
691
+ /**
692
+ * Gutters
693
+ * NOTE: Gutters should have the same top margin as the content.
694
+ * NOTE: They can't be transparent since the content needs to scroll below.
695
+ */
696
+ ".cm-gutters": {
697
+ background: "var(--surface-bg)",
698
+ borderRight: "none"
699
+ },
700
+ ".cm-gutter": {},
701
+ ".cm-gutter.cm-lineNumbers .cm-gutterElement": {
702
+ minWidth: "40px",
703
+ alignContent: "center"
704
+ },
705
+ /**
706
+ * Height is set to match the corresponding line.
707
+ */
708
+ ".cm-gutterElement": {
709
+ alignItems: "center",
710
+ fontSize: "16px"
711
+ },
712
+ /**
713
+ * Line.
714
+ */
715
+ ".cm-line": {
716
+ paddingInline: 0
717
+ },
718
+ ".cm-activeLine": {
719
+ background: "var(--dx-cmActiveLine)"
720
+ },
721
+ /**
722
+ * Cursor (layer).
723
+ */
724
+ ".cm-cursor, .cm-dropCursor": {
725
+ borderLeft: "2px solid var(--dx-cmCursor)"
726
+ },
727
+ ".cm-placeholder": {
728
+ color: "var(--dx-subdued)"
729
+ },
730
+ /**
731
+ * Selection (layer).
732
+ */
733
+ ".cm-selectionBackground": {
734
+ background: "var(--dx-cmSelection)"
735
+ },
736
+ /**
737
+ * Search.
738
+ * NOTE: Matches comment.
739
+ */
740
+ ".cm-searchMatch": {
741
+ margin: "0 -3px",
742
+ padding: "3px",
743
+ borderRadius: "3px",
744
+ background: "var(--dx-cmHighlightSurface)",
745
+ color: "var(--dx-cmHighlight)"
746
+ },
747
+ ".cm-searchMatch-selected": {
748
+ textDecoration: "underline"
749
+ },
750
+ /**
751
+ * Link.
752
+ */
753
+ ".cm-link": {
754
+ textDecorationLine: "underline",
755
+ textDecorationThickness: "1px",
756
+ textUnderlineOffset: "2px",
757
+ borderRadius: ".125rem"
758
+ },
759
+ ".cm-link > span": {
760
+ color: "var(--dx-accentText)"
761
+ },
762
+ /**
763
+ * Tooltip.
764
+ */
765
+ ".cm-tooltip": {
766
+ background: "var(--dx-base)"
767
+ },
768
+ ".cm-tooltip-below": {},
769
+ /**
770
+ * Autocomplete.
771
+ * https://github.com/codemirror/autocomplete/blob/main/src/completion.ts
772
+ */
773
+ ".cm-tooltip.cm-tooltip-autocomplete": {
774
+ marginTop: "4px",
775
+ marginLeft: "-3px"
776
+ },
777
+ ".cm-tooltip.cm-tooltip-autocomplete > ul": {
778
+ maxHeight: "20em"
779
+ },
780
+ ".cm-tooltip.cm-tooltip-autocomplete > ul > li": {},
781
+ ".cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected]": {},
782
+ ".cm-tooltip.cm-tooltip-autocomplete > ul > completion-section": {
783
+ paddingLeft: "4px !important",
784
+ borderBottom: "none !important",
785
+ color: "var(--dx-accentText)"
786
+ },
787
+ ".cm-tooltip.cm-completionInfo": {
788
+ width: "360px !important",
789
+ margin: "-10px 1px 0 1px",
790
+ padding: "8px !important",
791
+ borderColor: "var(--dx-separator)"
792
+ },
793
+ ".cm-completionIcon": {
794
+ display: "none"
795
+ },
796
+ ".cm-completionLabel": {
797
+ fontFamily: fontBody
798
+ },
799
+ ".cm-completionMatchedText": {
800
+ textDecoration: "none !important",
801
+ opacity: 0.5
802
+ },
803
+ /**
804
+ * Panels
805
+ * https://github.com/codemirror/search/blob/main/src/search.ts#L745
806
+ *
807
+ * Find/replace panel.
808
+ * <div class="cm-announced">...</div>
809
+ * <div class="cm-scroller">...</div>
810
+ * <div class="cm-panels cm-panels-bottom">
811
+ * <div class="cm-search cm-panel">
812
+ * <input class="cm-textfield" />
813
+ * <button class="cm-button">...</button>
814
+ * <label><input type="checkbox" />...</label>
815
+ * </div>
816
+ * </div
817
+ */
818
+ // TODO(burdon): Implement custom panel (with icon buttons).
819
+ ".cm-panels": {},
820
+ ".cm-panel": {
821
+ fontFamily: fontBody,
822
+ backgroundColor: "var(--surface-bg)"
823
+ },
824
+ ".cm-panel input, .cm-panel button, .cm-panel label": {
825
+ color: "var(--dx-subdued)",
826
+ fontFamily: fontBody,
827
+ fontSize: "14px",
828
+ all: "unset",
829
+ margin: "3px !important",
830
+ padding: "2px 6px !important",
831
+ outline: "1px solid transparent"
832
+ },
833
+ ".cm-panel input, .cm-panel button": {
834
+ backgroundColor: "var(--dx-input)"
835
+ },
836
+ ".cm-panel input:focus, .cm-panel button:focus": {
837
+ outline: "1px solid var(--dx-accentFocusIndicator)"
838
+ },
839
+ ".cm-panel label": {
840
+ display: "inline-flex",
841
+ alignItems: "center",
842
+ cursor: "pointer"
843
+ },
844
+ ".cm-panel input.cm-textfield": {},
845
+ ".cm-panel input[type=checkbox]": {
846
+ width: "8px",
847
+ height: "8px",
848
+ marginRight: "6px !important",
849
+ padding: "2px !important",
850
+ color: "var(--dx-accentFocusIndicator)"
851
+ },
852
+ ".cm-panel button": {
853
+ "&:hover": {
854
+ backgroundColor: "var(--dx-accentSurfaceHover) !important"
477
855
  },
478
- update: (value, tr) => {
479
- if (!tr.changes.empty) {
480
- return match(tr.state);
481
- }
482
- return value;
856
+ "&:active": {
857
+ backgroundColor: "var(--dx-accentSurfaceHover)"
483
858
  }
484
- });
485
- return [
486
- annotationsState,
487
- import_view2.EditorView.decorations.compute([
488
- annotationsState
489
- ], (state) => {
490
- const annotations2 = state.field(annotationsState);
491
- const decorations = annotations2.map((annotation) => {
492
- const range = Cursor.getRangeFromCursor(state, annotation.cursor);
493
- return range && annotationMark.range(range.from, range.to);
494
- }).filter(import_util.isNotFalsy);
495
- return import_view2.Decoration.set(decorations);
496
- }),
497
- styles
498
- ];
859
+ },
860
+ ".cm-panel.cm-search": {
861
+ padding: "4px",
862
+ borderTop: "1px solid var(--dx-separator)"
863
+ }
499
864
  };
500
- var styles = import_view2.EditorView.theme({
501
- ".cm-annotation": {
502
- textDecoration: "underline",
503
- textDecorationStyle: "wavy",
504
- textDecorationColor: "var(--dx-error)"
865
+ var margin = "!mt-[1rem]";
866
+ var editorContent = (0, import_react_ui_theme3.mx)(margin, "!mli-auto w-full max-w-[min(50rem,100%-2rem)]");
867
+ var editorFullWidth = (0, import_react_ui_theme3.mx)(margin);
868
+ var editorWithToolbarLayout = "grid grid-cols-1 grid-rows-[min-content_1fr] data-[toolbar=disabled]:grid-rows-[1fr] justify-center content-start overflow-hidden";
869
+ var editorGutter = import_view2.EditorView.theme({
870
+ // Match margin from content.
871
+ ".cm-gutters": {
872
+ marginTop: "16px",
873
+ paddingRight: "1rem"
505
874
  }
506
875
  });
507
- var autocomplete = ({ debug, activateOnTyping, override, onSearch } = {}) => {
508
- const extensions = [
509
- // https://codemirror.net/docs/ref/#view.keymap
510
- // https://discuss.codemirror.net/t/how-can-i-replace-the-default-autocompletion-keymap-v6/3322
511
- // TODO(burdon): Set custom keymap.
512
- import_view3.keymap.of(import_autocomplete.completionKeymap),
513
- // https://codemirror.net/examples/autocompletion
514
- // https://codemirror.net/docs/ref/#autocomplete.autocompletion
515
- (0, import_autocomplete.autocompletion)({
516
- activateOnTyping,
517
- override,
876
+ var editorMonospace = import_view2.EditorView.theme({
877
+ ".cm-content": {
878
+ fontFamily: fontMono
879
+ }
880
+ });
881
+ var singleValueFacet = (defaultValue) => import_state3.Facet.define({
882
+ // Called immediately.
883
+ combine: (providers) => {
884
+ return providers[0] ?? defaultValue;
885
+ }
886
+ });
887
+ var overlap = (a, b) => a.from <= b.to && a.to >= b.from;
888
+ var defaultCursorConverter = {
889
+ toCursor: (position) => position.toString(),
890
+ fromCursor: (cursor) => parseInt(cursor)
891
+ };
892
+ var Cursor = class _Cursor {
893
+ static {
894
+ this.converter = singleValueFacet(defaultCursorConverter);
895
+ }
896
+ static {
897
+ this.getCursorFromRange = (state, range) => {
898
+ const cursorConverter2 = state.facet(_Cursor.converter);
899
+ const from = cursorConverter2.toCursor(range.from);
900
+ const to = cursorConverter2.toCursor(range.to, -1);
901
+ return [
902
+ from,
903
+ to
904
+ ].join(":");
905
+ };
906
+ }
907
+ static {
908
+ this.getRangeFromCursor = (state, cursor) => {
909
+ const cursorConverter2 = state.facet(_Cursor.converter);
910
+ const parts = cursor.split(":");
911
+ const from = cursorConverter2.fromCursor(parts[0]);
912
+ const to = cursorConverter2.fromCursor(parts[1]);
913
+ return from !== void 0 && to !== void 0 ? {
914
+ from,
915
+ to
916
+ } : void 0;
917
+ };
918
+ }
919
+ };
920
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util/debug.ts";
921
+ var wrapWithCatch = (fn) => {
922
+ return (...args) => {
923
+ try {
924
+ return fn(...args);
925
+ } catch (err) {
926
+ import_log.log.catch(err, void 0, {
927
+ F: __dxlog_file,
928
+ L: 15,
929
+ S: void 0,
930
+ C: (f, a) => f(...a)
931
+ });
932
+ }
933
+ };
934
+ };
935
+ var callbackWrapper = (fn) => (...args) => {
936
+ try {
937
+ return fn(...args);
938
+ } catch (err) {
939
+ import_log.log.catch(err, void 0, {
940
+ F: __dxlog_file,
941
+ L: 29,
942
+ S: void 0,
943
+ C: (f, a) => f(...a)
944
+ });
945
+ }
946
+ };
947
+ var debugDispatcher = (trs, view) => {
948
+ logChanges(trs);
949
+ view.update(trs);
950
+ };
951
+ var logChanges = (trs) => {
952
+ const changes = trs.flatMap((tr) => {
953
+ if (tr.changes.empty) {
954
+ return void 0;
955
+ }
956
+ const changes2 = [];
957
+ tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => changes2.push(JSON.stringify({
958
+ fromA,
959
+ toA,
960
+ fromB,
961
+ toB,
962
+ inserted: inserted.toString()
963
+ })));
964
+ return changes2;
965
+ }).filter(Boolean);
966
+ if (changes.length) {
967
+ import_log.log.info("changes", {
968
+ changes
969
+ }, {
970
+ F: __dxlog_file,
971
+ L: 62,
972
+ S: void 0,
973
+ C: (f, a) => f(...a)
974
+ });
975
+ }
976
+ };
977
+ var flattenRect = (rect, left) => {
978
+ const x = left ? rect.left : rect.right;
979
+ return {
980
+ left: x,
981
+ right: x,
982
+ top: rect.top,
983
+ bottom: rect.bottom
984
+ };
985
+ };
986
+ var scratchRange;
987
+ var textRange = (node, from, to = from) => {
988
+ const range = scratchRange || (scratchRange = document.createRange());
989
+ range.setEnd(node, to);
990
+ range.setStart(node, from);
991
+ return range;
992
+ };
993
+ var clientRectsFor = (dom) => {
994
+ if (dom.nodeType === 3) {
995
+ return textRange(dom, 0, dom.nodeValue.length).getClientRects();
996
+ } else if (dom.nodeType === 1) {
997
+ return dom.getClientRects();
998
+ } else {
999
+ return [];
1000
+ }
1001
+ };
1002
+ var createElement = (tag, options, children) => {
1003
+ const el = document.createElement(tag);
1004
+ if (options?.className) {
1005
+ el.className = options.className;
1006
+ }
1007
+ if (children) {
1008
+ el.append(...Array.isArray(children) ? children : [
1009
+ children
1010
+ ]);
1011
+ }
1012
+ return el;
1013
+ };
1014
+ var renderRoot = (root, node) => {
1015
+ (0, import_client.createRoot)(root).render(/* @__PURE__ */ import_react3.default.createElement(import_react_ui2.ThemeProvider, {
1016
+ tx: import_react_ui_theme6.defaultTx
1017
+ }, node));
1018
+ return root;
1019
+ };
1020
+ var annotationMark = import_view3.Decoration.mark({
1021
+ class: "cm-annotation"
1022
+ });
1023
+ var annotations = (options = {}) => {
1024
+ const match = (state) => {
1025
+ const annotations2 = [];
1026
+ const text = state.doc.toString();
1027
+ if (options.match) {
1028
+ const matches = text.matchAll(options.match);
1029
+ for (const match2 of matches) {
1030
+ const from = match2.index;
1031
+ const to = from + match2[0].length;
1032
+ const cursor = Cursor.getCursorFromRange(state, {
1033
+ from,
1034
+ to
1035
+ });
1036
+ annotations2.push({
1037
+ cursor
1038
+ });
1039
+ }
1040
+ }
1041
+ return annotations2;
1042
+ };
1043
+ const annotationsState = import_state2.StateField.define({
1044
+ create: (state) => {
1045
+ return match(state);
1046
+ },
1047
+ update: (value, tr) => {
1048
+ if (!tr.changes.empty) {
1049
+ return match(tr.state);
1050
+ }
1051
+ return value;
1052
+ }
1053
+ });
1054
+ return [
1055
+ annotationsState,
1056
+ import_view3.EditorView.decorations.compute([
1057
+ annotationsState
1058
+ ], (state) => {
1059
+ const annotations2 = state.field(annotationsState);
1060
+ const decorations = annotations2.map((annotation) => {
1061
+ const range = Cursor.getRangeFromCursor(state, annotation.cursor);
1062
+ return range && annotationMark.range(range.from, range.to);
1063
+ }).filter(import_util.isNotFalsy);
1064
+ return import_view3.Decoration.set(decorations);
1065
+ }),
1066
+ styles
1067
+ ];
1068
+ };
1069
+ var styles = import_view3.EditorView.theme({
1070
+ ".cm-annotation": {
1071
+ textDecoration: "underline",
1072
+ textDecorationStyle: "wavy",
1073
+ textDecorationColor: "var(--dx-error)"
1074
+ }
1075
+ });
1076
+ var autocomplete = ({ debug, activateOnTyping, override, onSearch } = {}) => {
1077
+ const extensions = [
1078
+ // https://codemirror.net/docs/ref/#view.keymap
1079
+ // https://discuss.codemirror.net/t/how-can-i-replace-the-default-autocompletion-keymap-v6/3322
1080
+ // TODO(burdon): Set custom keymap.
1081
+ import_view4.keymap.of(import_autocomplete.completionKeymap),
1082
+ // https://codemirror.net/examples/autocompletion
1083
+ // https://codemirror.net/docs/ref/#autocomplete.autocompletion
1084
+ (0, import_autocomplete.autocompletion)({
1085
+ activateOnTyping,
1086
+ override,
518
1087
  closeOnBlur: !debug,
519
1088
  tooltipClass: () => "shadow rounded"
520
1089
  })
@@ -787,7 +1356,7 @@ var automerge = (accessor) => {
787
1356
  // Track heads.
788
1357
  syncState,
789
1358
  // Reconcile external updates.
790
- import_view4.ViewPlugin.fromClass(class {
1359
+ import_view5.ViewPlugin.fromClass(class {
791
1360
  constructor(_view) {
792
1361
  this._view = _view;
793
1362
  this._handleChange = () => {
@@ -800,7 +1369,7 @@ var automerge = (accessor) => {
800
1369
  }
801
1370
  }),
802
1371
  // Reconcile local updates.
803
- import_view4.EditorView.updateListener.of(({ view, changes }) => {
1372
+ import_view5.EditorView.updateListener.of(({ view, changes }) => {
804
1373
  if (!changes.empty) {
805
1374
  syncer.reconcile(view, true);
806
1375
  }
@@ -823,7 +1392,7 @@ var RemoteSelectionChangedAnnotation = import_state7.Annotation.define();
823
1392
  var awareness = (provider = dummyProvider) => {
824
1393
  return [
825
1394
  awarenessProvider.of(provider),
826
- import_view5.ViewPlugin.fromClass(RemoteSelectionsDecorator, {
1395
+ import_view6.ViewPlugin.fromClass(RemoteSelectionsDecorator, {
827
1396
  decorations: (value) => value.decorations
828
1397
  }),
829
1398
  styles2
@@ -887,7 +1456,7 @@ var RemoteSelectionsDecorator = class {
887
1456
  decorations.push({
888
1457
  from: start,
889
1458
  to: end,
890
- value: import_view5.Decoration.mark({
1459
+ value: import_view6.Decoration.mark({
891
1460
  attributes: {
892
1461
  style: `background-color: ${lightColor}`
893
1462
  },
@@ -898,7 +1467,7 @@ var RemoteSelectionsDecorator = class {
898
1467
  decorations.push({
899
1468
  from: start,
900
1469
  to: startLine.from + startLine.length,
901
- value: import_view5.Decoration.mark({
1470
+ value: import_view6.Decoration.mark({
902
1471
  attributes: {
903
1472
  style: `background-color: ${lightColor}`
904
1473
  },
@@ -908,7 +1477,7 @@ var RemoteSelectionsDecorator = class {
908
1477
  decorations.push({
909
1478
  from: endLine.from,
910
1479
  to: end,
911
- value: import_view5.Decoration.mark({
1480
+ value: import_view6.Decoration.mark({
912
1481
  attributes: {
913
1482
  style: `background-color: ${lightColor}`
914
1483
  },
@@ -920,7 +1489,7 @@ var RemoteSelectionsDecorator = class {
920
1489
  decorations.push({
921
1490
  from: linePos,
922
1491
  to: linePos,
923
- value: import_view5.Decoration.line({
1492
+ value: import_view6.Decoration.line({
924
1493
  attributes: {
925
1494
  style: `background-color: ${lightColor}`,
926
1495
  class: "cm-collab-selectionLine"
@@ -932,17 +1501,17 @@ var RemoteSelectionsDecorator = class {
932
1501
  decorations.push({
933
1502
  from: head,
934
1503
  to: head,
935
- value: import_view5.Decoration.widget({
1504
+ value: import_view6.Decoration.widget({
936
1505
  side: head - anchor > 0 ? -1 : 1,
937
1506
  block: false,
938
1507
  widget: new RemoteCaretWidget(state.info.displayName ?? "Anonymous", darkColor)
939
1508
  })
940
1509
  });
941
1510
  }
942
- this.decorations = import_view5.Decoration.set(decorations, true);
1511
+ this.decorations = import_view6.Decoration.set(decorations, true);
943
1512
  }
944
1513
  };
945
- var RemoteCaretWidget = class extends import_view5.WidgetType {
1514
+ var RemoteCaretWidget = class extends import_view6.WidgetType {
946
1515
  constructor(_name, _color) {
947
1516
  super();
948
1517
  this._name = _name;
@@ -978,7 +1547,7 @@ var RemoteCaretWidget = class extends import_view5.WidgetType {
978
1547
  return true;
979
1548
  }
980
1549
  };
981
- var styles2 = import_view5.EditorView.theme({
1550
+ var styles2 = import_view6.EditorView.theme({
982
1551
  ".cm-collab-selection": {},
983
1552
  ".cm-collab-selectionLine": {
984
1553
  padding: 0,
@@ -1181,12 +1750,12 @@ var blast = (options = defaultOptions) => {
1181
1750
  };
1182
1751
  return [
1183
1752
  // Cursor moved.
1184
- import_view6.EditorView.updateListener.of((update2) => {
1753
+ import_view7.EditorView.updateListener.of((update2) => {
1185
1754
  if (blaster?.node !== update2.view.scrollDOM) {
1186
1755
  if (blaster) {
1187
1756
  blaster.destroy();
1188
1757
  }
1189
- blaster = new Blaster(update2.view.scrollDOM, (0, import_lodash.default)({
1758
+ blaster = new Blaster(update2.view.scrollDOM, (0, import_lodash2.default)({
1190
1759
  particleGravity: 0.2,
1191
1760
  particleShrinkRate: 0.995,
1192
1761
  color: () => [
@@ -1212,7 +1781,7 @@ var blast = (options = defaultOptions) => {
1212
1781
  }
1213
1782
  }
1214
1783
  }),
1215
- import_view6.keymap.of([
1784
+ import_view7.keymap.of([
1216
1785
  {
1217
1786
  any: (_, event) => {
1218
1787
  if (blaster) {
@@ -1498,7 +2067,7 @@ var commandState = import_state9.StateField.define({
1498
2067
  return state;
1499
2068
  },
1500
2069
  provide: (field) => [
1501
- import_view9.showTooltip.from(field, (value) => value.tooltip ?? null)
2070
+ import_view10.showTooltip.from(field, (value) => value.tooltip ?? null)
1502
2071
  ]
1503
2072
  });
1504
2073
  var openEffect = import_state9.StateEffect.define();
@@ -1538,7 +2107,7 @@ var commandKeyBindings = [
1538
2107
  run: closeCommand
1539
2108
  }
1540
2109
  ];
1541
- var CommandHint = class extends import_view8.WidgetType {
2110
+ var CommandHint = class extends import_view9.WidgetType {
1542
2111
  constructor(content) {
1543
2112
  super();
1544
2113
  this.content = content;
@@ -1577,9 +2146,9 @@ var CommandHint = class extends import_view8.WidgetType {
1577
2146
  return false;
1578
2147
  }
1579
2148
  };
1580
- var hintViewPlugin = ({ onHint }) => import_view8.ViewPlugin.fromClass(class {
2149
+ var hintViewPlugin = ({ onHint }) => import_view9.ViewPlugin.fromClass(class {
1581
2150
  constructor() {
1582
- this.deco = import_view8.Decoration.none;
2151
+ this.deco = import_view9.Decoration.none;
1583
2152
  }
1584
2153
  update(update2) {
1585
2154
  const builder = new import_state8.RangeSetBuilder();
@@ -1590,7 +2159,7 @@ var hintViewPlugin = ({ onHint }) => import_view8.ViewPlugin.fromClass(class {
1590
2159
  if (selection.from === selection.to && line.from === line.to) {
1591
2160
  const hint = onHint();
1592
2161
  if (hint) {
1593
- builder.add(selection.from, selection.to, import_view8.Decoration.widget({
2162
+ builder.add(selection.from, selection.to, import_view9.Decoration.widget({
1594
2163
  widget: new CommandHint(hint)
1595
2164
  }));
1596
2165
  }
@@ -1600,16 +2169,16 @@ var hintViewPlugin = ({ onHint }) => import_view8.ViewPlugin.fromClass(class {
1600
2169
  }
1601
2170
  }, {
1602
2171
  provide: (plugin) => [
1603
- import_view8.EditorView.decorations.of((view) => view.plugin(plugin)?.deco ?? import_view8.Decoration.none)
2172
+ import_view9.EditorView.decorations.of((view) => view.plugin(plugin)?.deco ?? import_view9.Decoration.none)
1604
2173
  ]
1605
2174
  });
1606
2175
  var command = (options) => {
1607
2176
  return [
1608
2177
  commandConfig.of(options),
1609
2178
  commandState,
1610
- import_view7.keymap.of(commandKeyBindings),
2179
+ import_view8.keymap.of(commandKeyBindings),
1611
2180
  hintViewPlugin(options),
1612
- import_view7.EditorView.focusChangeEffect.of((_, focusing) => {
2181
+ import_view8.EditorView.focusChangeEffect.of((_, focusing) => {
1613
2182
  return focusing ? closeEffect.of(null) : null;
1614
2183
  })
1615
2184
  ];
@@ -1621,7 +2190,7 @@ var createEditorStateTransaction = ({ scrollTo, selection }) => {
1621
2190
  return {
1622
2191
  selection,
1623
2192
  scrollIntoView: !scrollTo,
1624
- effects: scrollTo ? import_view11.EditorView.scrollIntoView(scrollTo, {
2193
+ effects: scrollTo ? import_view12.EditorView.scrollIntoView(scrollTo, {
1625
2194
  yMargin: 96
1626
2195
  }) : void 0,
1627
2196
  annotations: import_state11.Transaction.userEvent.of(stateRestoreAnnotation)
@@ -1663,7 +2232,7 @@ var selectionState = ({ getState, setState } = {}) => {
1663
2232
  // setStateDebounced(id, {});
1664
2233
  // },
1665
2234
  // }),
1666
- import_view11.EditorView.updateListener.of(({ view, transactions }) => {
2235
+ import_view12.EditorView.updateListener.of(({ view, transactions }) => {
1667
2236
  const id = view.state.facet(documentId);
1668
2237
  if (!id || transactions.some((tr) => tr.isUserEvent(stateRestoreAnnotation))) {
1669
2238
  return;
@@ -1686,7 +2255,7 @@ var selectionState = ({ getState, setState } = {}) => {
1686
2255
  }
1687
2256
  }
1688
2257
  }),
1689
- getState && import_view11.keymap.of([
2258
+ getState && import_view12.keymap.of([
1690
2259
  {
1691
2260
  key: "ctrl-r",
1692
2261
  run: (view) => {
@@ -1742,7 +2311,7 @@ var commentsState = import_state10.StateField.define({
1742
2311
  return value;
1743
2312
  }
1744
2313
  });
1745
- var styles3 = import_view10.EditorView.theme({
2314
+ var styles3 = import_view11.EditorView.theme({
1746
2315
  ".cm-comment, .cm-comment-current": {
1747
2316
  margin: "0 -3px",
1748
2317
  padding: "3px",
@@ -1755,23 +2324,23 @@ var styles3 = import_view10.EditorView.theme({
1755
2324
  textDecoration: "underline"
1756
2325
  }
1757
2326
  });
1758
- var createCommentMark = (id, isCurrent) => import_view10.Decoration.mark({
2327
+ var createCommentMark = (id, isCurrent) => import_view11.Decoration.mark({
1759
2328
  class: isCurrent ? "cm-comment-current" : "cm-comment",
1760
2329
  attributes: {
1761
2330
  "data-testid": "cm-comment",
1762
2331
  "data-comment-id": id
1763
2332
  }
1764
2333
  });
1765
- var commentsDecorations = import_view10.EditorView.decorations.compute([
2334
+ var commentsDecorations = import_view11.EditorView.decorations.compute([
1766
2335
  commentsState
1767
2336
  ], (state) => {
1768
2337
  const { selection: { current }, comments: comments2 } = state.field(commentsState);
1769
- const decorations = (0, import_lodash2.default)(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
2338
+ const decorations = (0, import_lodash3.default)(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
1770
2339
  const range = comment.range;
1771
2340
  if (!range) {
1772
2341
  import_log4.log.warn("Invalid range:", range, {
1773
2342
  F: __dxlog_file7,
1774
- L: 142,
2343
+ L: 144,
1775
2344
  S: void 0,
1776
2345
  C: (f, a) => f(...a)
1777
2346
  });
@@ -1782,10 +2351,10 @@ var commentsDecorations = import_view10.EditorView.decorations.compute([
1782
2351
  const mark = createCommentMark(comment.comment.id, comment.comment.id === current);
1783
2352
  return mark.range(range.from, range.to);
1784
2353
  }).filter(import_util2.nonNullable);
1785
- return import_view10.Decoration.set(decorations);
2354
+ return import_view11.Decoration.set(decorations);
1786
2355
  });
1787
2356
  var commentClickedEffect = import_state10.StateEffect.define();
1788
- var handleCommentClick = import_view10.EditorView.domEventHandlers({
2357
+ var handleCommentClick = import_view11.EditorView.domEventHandlers({
1789
2358
  click: (event, view) => {
1790
2359
  let target = event.target;
1791
2360
  const editorRoot = view.dom;
@@ -1824,7 +2393,7 @@ var trackPastedComments = (onUpdate) => {
1824
2393
  }
1825
2394
  };
1826
2395
  return [
1827
- import_view10.EditorView.domEventHandlers({
2396
+ import_view11.EditorView.domEventHandlers({
1828
2397
  cut: handleTrack,
1829
2398
  copy: handleTrack
1830
2399
  }),
@@ -1846,7 +2415,7 @@ var trackPastedComments = (onUpdate) => {
1846
2415
  return effects;
1847
2416
  }),
1848
2417
  // Handle paste or the undo of comment deletion.
1849
- import_view10.EditorView.updateListener.of((update2) => {
2418
+ import_view11.EditorView.updateListener.of((update2) => {
1850
2419
  const restore = [];
1851
2420
  for (let i = 0; i < update2.transactions.length; i++) {
1852
2421
  const tr = update2.transactions[i];
@@ -1905,7 +2474,7 @@ var mapTrackedComment = (comment, changes) => ({
1905
2474
  var restoreCommentEffect = import_state10.StateEffect.define({
1906
2475
  map: mapTrackedComment
1907
2476
  });
1908
- var createComment = (view) => {
2477
+ var createComment2 = (view) => {
1909
2478
  const options = view.state.facet(optionsFacet);
1910
2479
  const { from, to } = view.state.selection.main;
1911
2480
  if (from === to) {
@@ -1947,17 +2516,17 @@ var comments = (options = {}) => {
1947
2516
  //
1948
2517
  // Keymap.
1949
2518
  //
1950
- options.onCreate && import_view10.keymap.of([
2519
+ options.onCreate && import_view11.keymap.of([
1951
2520
  {
1952
2521
  key: shortcut,
1953
- run: callbackWrapper(createComment)
2522
+ run: callbackWrapper(createComment2)
1954
2523
  }
1955
2524
  ]),
1956
2525
  //
1957
2526
  // Hover tooltip (for key shortcut hints, etc.)
1958
2527
  // TODO(burdon): Factor out to generic hints extension for current selection/line.
1959
2528
  //
1960
- options.onHover && (0, import_view10.hoverTooltip)((view, pos) => {
2529
+ options.onHover && (0, import_view11.hoverTooltip)((view, pos) => {
1961
2530
  const selection = view.state.selection.main;
1962
2531
  if (selection && pos >= selection.from && pos <= selection.to) {
1963
2532
  return {
@@ -1986,7 +2555,7 @@ var comments = (options = {}) => {
1986
2555
  //
1987
2556
  // Track deleted ranges and update ranges for decorations.
1988
2557
  //
1989
- import_view10.EditorView.updateListener.of(({ view, state, changes }) => {
2558
+ import_view11.EditorView.updateListener.of(({ view, state, changes }) => {
1990
2559
  let mod = false;
1991
2560
  const { comments: comments2, ...value } = state.field(commentsState);
1992
2561
  changes.iterChanges((from, to, from2, to2) => {
@@ -2018,7 +2587,7 @@ var comments = (options = {}) => {
2018
2587
  //
2019
2588
  // Track selection/proximity.
2020
2589
  //
2021
- import_view10.EditorView.updateListener.of(({ view, state }) => {
2590
+ import_view11.EditorView.updateListener.of(({ view, state }) => {
2022
2591
  let min = Infinity;
2023
2592
  const { selection: { current, closest }, comments: comments2 } = state.field(commentsState);
2024
2593
  const { head } = state.selection.main;
@@ -2048,414 +2617,187 @@ var comments = (options = {}) => {
2048
2617
  range,
2049
2618
  location: view.coordsAtPos(range.from)
2050
2619
  }))
2051
- });
2052
- }
2053
- }),
2054
- options.onUpdate && trackPastedComments(options.onUpdate)
2055
- ].filter(import_util2.nonNullable);
2056
- };
2057
- var scrollThreadIntoView = (view, id, center = true) => {
2058
- const comment = view.state.field(commentsState).comments.find((range2) => range2.comment.id === id);
2059
- if (!comment?.comment.cursor) {
2060
- return;
2061
- }
2062
- const range = Cursor.getRangeFromCursor(view.state, comment.comment.cursor);
2063
- if (range) {
2064
- const currentSelection = view.state.selection.main;
2065
- const currentScrollPosition = view.scrollDOM.scrollTop;
2066
- const targetScrollPosition = view.coordsAtPos(range.from)?.top;
2067
- const needsScroll = targetScrollPosition !== void 0 && (targetScrollPosition < currentScrollPosition || targetScrollPosition > currentScrollPosition + view.scrollDOM.clientHeight);
2068
- const needsSelectionUpdate = currentSelection.from !== range.from || currentSelection.to !== range.from;
2069
- if (needsScroll || needsSelectionUpdate) {
2070
- view.dispatch({
2071
- selection: needsSelectionUpdate ? {
2072
- anchor: range.from
2073
- } : void 0,
2074
- effects: [
2075
- needsScroll ? import_view10.EditorView.scrollIntoView(range.from, center ? {
2076
- y: "center"
2077
- } : void 0) : [],
2078
- needsSelectionUpdate ? setSelection.of({
2079
- current: id
2080
- }) : []
2081
- ].flat()
2082
- });
2083
- }
2084
- }
2085
- };
2086
- var selectionOverlapsComment = (state) => {
2087
- const commentState = state.field(commentsState, false);
2088
- if (commentState === void 0) {
2089
- return false;
2090
- }
2091
- const { selection } = state;
2092
- for (const range of selection.ranges) {
2093
- if (commentState.comments.some(({ range: commentRange }) => overlap(commentRange, range))) {
2094
- return true;
2095
- }
2096
- }
2097
- return false;
2098
- };
2099
- var hasActiveSelection = (state) => {
2100
- return state.selection.ranges.some((range) => !range.empty);
2101
- };
2102
- var ExternalCommentSync = class {
2103
- constructor(view, id, subscribe, getComments) {
2104
- this.destroy = () => {
2105
- this.unsubscribe();
2106
- };
2107
- const updateComments = () => {
2108
- const comments2 = getComments();
2109
- if (id === view.state.facet(documentId)) {
2110
- queueMicrotask(() => view.dispatch({
2111
- effects: setComments.of({
2112
- id,
2113
- comments: comments2
2114
- })
2115
- }));
2116
- }
2117
- };
2118
- this.unsubscribe = subscribe(updateComments);
2119
- }
2120
- };
2121
- var createExternalCommentSync = (id, subscribe, getComments) => import_view10.ViewPlugin.fromClass(class {
2122
- constructor(view) {
2123
- return new ExternalCommentSync(view, id, subscribe, getComments);
2124
- }
2125
- });
2126
- var useCommentState = () => {
2127
- const [state, setState] = (0, import_react4.useState)({
2128
- comment: false,
2129
- selection: false
2130
- });
2131
- const observer = (0, import_react4.useMemo)(() => import_view10.EditorView.updateListener.of((update2) => {
2132
- if (update2.docChanged || update2.selectionSet) {
2133
- setState({
2134
- comment: selectionOverlapsComment(update2.state),
2135
- selection: hasActiveSelection(update2.state)
2136
- });
2137
- }
2138
- }), []);
2139
- return [
2140
- state,
2141
- observer
2142
- ];
2143
- };
2144
- var useComments = (view, id, comments2) => {
2145
- (0, import_react4.useEffect)(() => {
2146
- if (view) {
2147
- if (id === view.state.facet(documentId)) {
2148
- view.dispatch({
2149
- effects: setComments.of({
2150
- id,
2151
- comments: comments2 ?? []
2152
- })
2153
- });
2154
- }
2155
- }
2156
- });
2157
- };
2158
- var useCommentClickListener = (onCommentClick) => {
2159
- return (0, import_react4.useMemo)(() => import_view10.EditorView.updateListener.of((update2) => {
2160
- update2.transactions.forEach((transaction) => {
2161
- transaction.effects.forEach((effect) => {
2162
- if (effect.is(commentClickedEffect)) {
2163
- onCommentClick(effect.value);
2164
- }
2165
- });
2166
- });
2167
- }), [
2168
- onCommentClick
2169
- ]);
2170
- };
2171
- var debugNodeLogger = (log8 = console.log) => {
2172
- const logTokens = (state) => (0, import_language.syntaxTree)(state).iterate({
2173
- enter: (node) => log8(node.type)
2174
- });
2175
- return import_state12.StateField.define({
2176
- create: (state) => logTokens(state),
2177
- update: (_, tr) => logTokens(tr.state)
2178
- });
2179
- };
2180
- var styles4 = import_view12.EditorView.theme({
2181
- ".cm-dropCursor": {
2182
- borderLeft: "2px solid var(--dx-accentText)",
2183
- color: "var(--dx-accentText)",
2184
- padding: "0 4px"
2185
- },
2186
- ".cm-dropCursor:after": {
2187
- content: '"\u2190"'
2188
- }
2189
- });
2190
- var dropFile = (options = {}) => {
2191
- return [
2192
- styles4,
2193
- (0, import_view12.dropCursor)(),
2194
- import_view12.EditorView.domEventHandlers({
2195
- drop: (event, view) => {
2196
- event.preventDefault();
2197
- const files = event.dataTransfer?.files;
2198
- const pos = view.posAtCoords(event);
2199
- if (files?.length && pos !== null) {
2200
- view.dispatch({
2201
- selection: {
2202
- anchor: pos
2203
- }
2204
- });
2205
- options.onDrop?.(view, {
2206
- files
2207
- });
2208
- }
2209
- }
2210
- })
2211
- ];
2212
- };
2213
- var focusEffect = import_state14.StateEffect.define();
2214
- var focusField = import_state14.StateField.define({
2215
- create: () => false,
2216
- update: (value, tr) => {
2217
- for (const effect of tr.effects) {
2218
- if (effect.is(focusEffect)) {
2219
- return effect.value;
2220
- }
2221
- }
2222
- return value;
2223
- }
2224
- });
2225
- var focus = [
2226
- focusField,
2227
- import_view14.EditorView.domEventHandlers({
2228
- focus: (event, view) => {
2229
- setTimeout(() => view.dispatch({
2230
- effects: focusEffect.of(true)
2231
- }));
2232
- },
2233
- blur: (event, view) => {
2234
- setTimeout(() => view.dispatch({
2235
- effects: focusEffect.of(false)
2236
- }));
2237
- }
2238
- })
2239
- ];
2240
- var headings = {
2241
- 1: "text-4xl",
2242
- 2: "text-3xl",
2243
- 3: "text-2xl",
2244
- 4: "text-xl",
2245
- 5: "text-lg",
2246
- 6: "text-md"
2247
- };
2248
- var theme = {
2249
- code: "font-mono !no-underline text-neutral-700 dark:text-neutral-300",
2250
- codeMark: "font-mono text-primary-500",
2251
- mark: "opacity-50",
2252
- heading: (level) => {
2253
- return (0, import_react_ui_theme4.mx)(headings[level], "dark:text-primary-400");
2254
- }
2255
- };
2256
- var getToken = (path, defaultValue) => {
2257
- const value = (0, import_lodash5.default)(import_react_ui_theme5.tokens, path, defaultValue);
2258
- return value?.toString() ?? "";
2259
- };
2260
- var fontBody = getToken("fontFamily.body");
2261
- var fontMono = getToken("fontFamily.mono");
2262
- var defaultTheme = {
2263
- "&": {},
2264
- "&.cm-focused": {
2265
- outline: "none"
2266
- },
2267
- /**
2268
- * Scroller
2269
- */
2270
- ".cm-scroller": {
2271
- overflowY: "auto"
2272
- },
2273
- /**
2274
- * Content
2275
- * NOTE: Apply margins to content so that scrollbar is at the edge of the container.
2276
- */
2277
- ".cm-content": {
2278
- padding: "unset",
2279
- fontFamily: fontBody,
2280
- // NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
2281
- fontSize: "16px",
2282
- lineHeight: 1.5,
2283
- color: "unset"
2284
- },
2285
- /**
2286
- * Gutters
2287
- * NOTE: Gutters should have the same top margin as the content.
2288
- * NOTE: They can't be transparent since the content needs to scroll below.
2289
- */
2290
- ".cm-gutters": {
2291
- background: "var(--surface-bg)",
2292
- borderRight: "none"
2293
- },
2294
- ".cm-gutter": {},
2295
- ".cm-gutter.cm-lineNumbers .cm-gutterElement": {
2296
- minWidth: "40px",
2297
- alignContent: "center"
2298
- },
2299
- /**
2300
- * Height is set to match the corresponding line.
2301
- */
2302
- ".cm-gutterElement": {
2303
- alignItems: "center",
2304
- fontSize: "16px"
2305
- },
2306
- /**
2307
- * Line.
2308
- */
2309
- ".cm-line": {
2310
- paddingInline: 0
2311
- },
2312
- ".cm-activeLine": {
2313
- background: "var(--dx-cmActiveLine)"
2314
- },
2315
- /**
2316
- * Cursor (layer).
2317
- */
2318
- ".cm-cursor, .cm-dropCursor": {
2319
- borderLeft: "2px solid var(--dx-cmCursor)"
2320
- },
2321
- ".cm-placeholder": {
2322
- color: "var(--dx-subdued)"
2323
- },
2324
- /**
2325
- * Selection (layer).
2326
- */
2327
- ".cm-selectionBackground": {
2328
- background: "var(--dx-cmSelection)"
2329
- },
2330
- /**
2331
- * Search.
2332
- * NOTE: Matches comment.
2333
- */
2334
- ".cm-searchMatch": {
2335
- margin: "0 -3px",
2336
- padding: "3px",
2337
- borderRadius: "3px",
2338
- background: "var(--dx-cmHighlightSurface)",
2339
- color: "var(--dx-cmHighlight)"
2340
- },
2341
- ".cm-searchMatch-selected": {
2342
- textDecoration: "underline"
2343
- },
2344
- /**
2345
- * Link.
2346
- */
2347
- ".cm-link": {
2348
- textDecorationLine: "underline",
2349
- textDecorationThickness: "1px",
2350
- textUnderlineOffset: "2px",
2351
- borderRadius: ".125rem"
2352
- },
2353
- ".cm-link > span": {
2354
- color: "var(--dx-accentText)"
2355
- },
2356
- /**
2357
- * Tooltip.
2358
- */
2359
- ".cm-tooltip": {
2360
- background: "var(--dx-base)"
2361
- },
2362
- ".cm-tooltip-below": {},
2363
- /**
2364
- * Autocomplete.
2365
- * https://github.com/codemirror/autocomplete/blob/main/src/completion.ts
2366
- */
2367
- ".cm-tooltip.cm-tooltip-autocomplete": {
2368
- marginTop: "4px",
2369
- marginLeft: "-3px"
2370
- },
2371
- ".cm-tooltip.cm-tooltip-autocomplete > ul": {
2372
- maxHeight: "20em"
2373
- },
2374
- ".cm-tooltip.cm-tooltip-autocomplete > ul > li": {},
2375
- ".cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected]": {},
2376
- ".cm-tooltip.cm-tooltip-autocomplete > ul > completion-section": {
2377
- paddingLeft: "4px !important",
2378
- borderBottom: "none !important",
2379
- color: "var(--dx-accentText)"
2380
- },
2381
- ".cm-tooltip.cm-completionInfo": {
2382
- width: "360px !important",
2383
- margin: "-10px 1px 0 1px",
2384
- padding: "8px !important",
2385
- borderColor: "var(--dx-separator)"
2386
- },
2387
- ".cm-completionIcon": {
2388
- display: "none"
2389
- },
2390
- ".cm-completionLabel": {
2391
- fontFamily: fontBody
2392
- },
2393
- ".cm-completionMatchedText": {
2394
- textDecoration: "none !important",
2395
- opacity: 0.5
2396
- },
2397
- /**
2398
- * Panels
2399
- * https://github.com/codemirror/search/blob/main/src/search.ts#L745
2400
- *
2401
- * Find/replace panel.
2402
- * <div class="cm-announced">...</div>
2403
- * <div class="cm-scroller">...</div>
2404
- * <div class="cm-panels cm-panels-bottom">
2405
- * <div class="cm-search cm-panel">
2406
- * <input class="cm-textfield" />
2407
- * <button class="cm-button">...</button>
2408
- * <label><input type="checkbox" />...</label>
2409
- * </div>
2410
- * </div
2411
- */
2412
- // TODO(burdon): Implement custom panel (with icon buttons).
2413
- ".cm-panels": {},
2414
- ".cm-panel": {
2415
- fontFamily: fontBody,
2416
- backgroundColor: "var(--surface-bg)"
2417
- },
2418
- ".cm-panel input, .cm-panel button, .cm-panel label": {
2419
- color: "var(--dx-subdued)",
2420
- fontFamily: fontBody,
2421
- fontSize: "14px",
2422
- all: "unset",
2423
- margin: "3px !important",
2424
- padding: "2px 6px !important",
2425
- outline: "1px solid transparent"
2426
- },
2427
- ".cm-panel input, .cm-panel button": {
2428
- backgroundColor: "var(--dx-input)"
2429
- },
2430
- ".cm-panel input:focus, .cm-panel button:focus": {
2431
- outline: "1px solid var(--dx-accentFocusIndicator)"
2432
- },
2433
- ".cm-panel label": {
2434
- display: "inline-flex",
2435
- alignItems: "center",
2436
- cursor: "pointer"
2437
- },
2438
- ".cm-panel input.cm-textfield": {},
2439
- ".cm-panel input[type=checkbox]": {
2440
- width: "8px",
2441
- height: "8px",
2442
- marginRight: "6px !important",
2443
- padding: "2px !important",
2444
- color: "var(--dx-accentFocusIndicator)"
2445
- },
2446
- ".cm-panel button": {
2447
- "&:hover": {
2448
- backgroundColor: "var(--dx-accentSurfaceHover) !important"
2449
- },
2450
- "&:active": {
2451
- backgroundColor: "var(--dx-accentSurfaceHover)"
2620
+ });
2621
+ }
2622
+ }),
2623
+ options.onUpdate && trackPastedComments(options.onUpdate)
2624
+ ].filter(import_util2.nonNullable);
2625
+ };
2626
+ var scrollThreadIntoView = (view, id, center = true) => {
2627
+ const comment = view.state.field(commentsState).comments.find((range2) => range2.comment.id === id);
2628
+ if (!comment?.comment.cursor) {
2629
+ return;
2630
+ }
2631
+ const range = Cursor.getRangeFromCursor(view.state, comment.comment.cursor);
2632
+ if (range) {
2633
+ const currentSelection = view.state.selection.main;
2634
+ const currentScrollPosition = view.scrollDOM.scrollTop;
2635
+ const targetScrollPosition = view.coordsAtPos(range.from)?.top;
2636
+ const needsScroll = targetScrollPosition !== void 0 && (targetScrollPosition < currentScrollPosition || targetScrollPosition > currentScrollPosition + view.scrollDOM.clientHeight);
2637
+ const needsSelectionUpdate = currentSelection.from !== range.from || currentSelection.to !== range.from;
2638
+ if (needsScroll || needsSelectionUpdate) {
2639
+ view.dispatch({
2640
+ selection: needsSelectionUpdate ? {
2641
+ anchor: range.from
2642
+ } : void 0,
2643
+ effects: [
2644
+ needsScroll ? import_view11.EditorView.scrollIntoView(range.from, center ? {
2645
+ y: "center"
2646
+ } : void 0) : [],
2647
+ needsSelectionUpdate ? setSelection.of({
2648
+ current: id
2649
+ }) : []
2650
+ ].flat()
2651
+ });
2652
+ }
2653
+ }
2654
+ };
2655
+ var selectionOverlapsComment = (state) => {
2656
+ const commentState = state.field(commentsState, false);
2657
+ if (commentState === void 0) {
2658
+ return false;
2659
+ }
2660
+ const { selection } = state;
2661
+ for (const range of selection.ranges) {
2662
+ if (commentState.comments.some(({ range: commentRange }) => overlap(commentRange, range))) {
2663
+ return true;
2664
+ }
2665
+ }
2666
+ return false;
2667
+ };
2668
+ var hasActiveSelection = (state) => {
2669
+ return state.selection.ranges.some((range) => !range.empty);
2670
+ };
2671
+ var ExternalCommentSync = class {
2672
+ constructor(view, id, subscribe, getComments) {
2673
+ this.destroy = () => {
2674
+ this.unsubscribe();
2675
+ };
2676
+ const updateComments = () => {
2677
+ const comments2 = getComments();
2678
+ if (id === view.state.facet(documentId)) {
2679
+ queueMicrotask(() => view.dispatch({
2680
+ effects: setComments.of({
2681
+ id,
2682
+ comments: comments2
2683
+ })
2684
+ }));
2685
+ }
2686
+ };
2687
+ this.unsubscribe = subscribe(updateComments);
2688
+ }
2689
+ };
2690
+ var createExternalCommentSync = (id, subscribe, getComments) => import_view11.ViewPlugin.fromClass(class {
2691
+ constructor(view) {
2692
+ return new ExternalCommentSync(view, id, subscribe, getComments);
2693
+ }
2694
+ });
2695
+ var useCommentState = (state) => {
2696
+ return (0, import_react4.useMemo)(() => import_view11.EditorView.updateListener.of((update2) => {
2697
+ if (update2.docChanged || update2.selectionSet) {
2698
+ state.comment = selectionOverlapsComment(update2.state);
2699
+ state.selection = hasActiveSelection(update2.state);
2700
+ }
2701
+ }), [
2702
+ state
2703
+ ]);
2704
+ };
2705
+ var useComments = (view, id, comments2) => {
2706
+ (0, import_react4.useEffect)(() => {
2707
+ if (view) {
2708
+ if (id === view.state.facet(documentId)) {
2709
+ view.dispatch({
2710
+ effects: setComments.of({
2711
+ id,
2712
+ comments: comments2 ?? []
2713
+ })
2714
+ });
2715
+ }
2452
2716
  }
2717
+ });
2718
+ };
2719
+ var useCommentClickListener = (onCommentClick) => {
2720
+ return (0, import_react4.useMemo)(() => import_view11.EditorView.updateListener.of((update2) => {
2721
+ update2.transactions.forEach((transaction) => {
2722
+ transaction.effects.forEach((effect) => {
2723
+ if (effect.is(commentClickedEffect)) {
2724
+ onCommentClick(effect.value);
2725
+ }
2726
+ });
2727
+ });
2728
+ }), [
2729
+ onCommentClick
2730
+ ]);
2731
+ };
2732
+ var debugNodeLogger = (log8 = console.log) => {
2733
+ const logTokens = (state) => (0, import_language.syntaxTree)(state).iterate({
2734
+ enter: (node) => log8(node.type)
2735
+ });
2736
+ return import_state12.StateField.define({
2737
+ create: (state) => logTokens(state),
2738
+ update: (_, tr) => logTokens(tr.state)
2739
+ });
2740
+ };
2741
+ var styles4 = import_view13.EditorView.theme({
2742
+ ".cm-dropCursor": {
2743
+ borderLeft: "2px solid var(--dx-accentText)",
2744
+ color: "var(--dx-accentText)",
2745
+ padding: "0 4px"
2453
2746
  },
2454
- ".cm-panel.cm-search": {
2455
- padding: "4px",
2456
- borderTop: "1px solid var(--dx-separator)"
2747
+ ".cm-dropCursor:after": {
2748
+ content: '"\u2190"'
2457
2749
  }
2750
+ });
2751
+ var dropFile = (options = {}) => {
2752
+ return [
2753
+ styles4,
2754
+ (0, import_view13.dropCursor)(),
2755
+ import_view13.EditorView.domEventHandlers({
2756
+ drop: (event, view) => {
2757
+ event.preventDefault();
2758
+ const files = event.dataTransfer?.files;
2759
+ const pos = view.posAtCoords(event);
2760
+ if (files?.length && pos !== null) {
2761
+ view.dispatch({
2762
+ selection: {
2763
+ anchor: pos
2764
+ }
2765
+ });
2766
+ options.onDrop?.(view, {
2767
+ files
2768
+ });
2769
+ }
2770
+ }
2771
+ })
2772
+ ];
2458
2773
  };
2774
+ var focusEffect = import_state14.StateEffect.define();
2775
+ var focusField = import_state14.StateField.define({
2776
+ create: () => false,
2777
+ update: (value, tr) => {
2778
+ for (const effect of tr.effects) {
2779
+ if (effect.is(focusEffect)) {
2780
+ return effect.value;
2781
+ }
2782
+ }
2783
+ return value;
2784
+ }
2785
+ });
2786
+ var focus = [
2787
+ focusField,
2788
+ import_view15.EditorView.domEventHandlers({
2789
+ focus: (event, view) => {
2790
+ setTimeout(() => view.dispatch({
2791
+ effects: focusEffect.of(true)
2792
+ }));
2793
+ },
2794
+ blur: (event, view) => {
2795
+ setTimeout(() => view.dispatch({
2796
+ effects: focusEffect.of(false)
2797
+ }));
2798
+ }
2799
+ })
2800
+ ];
2459
2801
  var __dxlog_file8 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/factories.ts";
2460
2802
  var preventNewline = import_state13.EditorState.transactionFilter.of((tr) => tr.newDoc.lines > 1 ? [] : tr);
2461
2803
  var defaultBasicOptions = {
@@ -2477,10 +2819,10 @@ var keymaps = {
2477
2819
  default: import_commands2.defaultKeymap
2478
2820
  };
2479
2821
  var createBasicExtensions = (_props) => {
2480
- const props = (0, import_lodash3.default)({}, _props, defaultBasicOptions);
2822
+ const props = (0, import_lodash4.default)({}, _props, defaultBasicOptions);
2481
2823
  return [
2482
2824
  // NOTE: Doesn't catch errors in keymap functions.
2483
- import_view13.EditorView.exceptionSink.of((err) => {
2825
+ import_view14.EditorView.exceptionSink.of((err) => {
2484
2826
  import_log5.log.catch(err, void 0, {
2485
2827
  F: __dxlog_file8,
2486
2828
  L: 96,
@@ -2491,24 +2833,24 @@ var createBasicExtensions = (_props) => {
2491
2833
  props.allowMultipleSelections && import_state13.EditorState.allowMultipleSelections.of(true),
2492
2834
  props.bracketMatching && (0, import_language2.bracketMatching)(),
2493
2835
  props.closeBrackets && (0, import_autocomplete2.closeBrackets)(),
2494
- props.dropCursor && (0, import_view13.dropCursor)(),
2495
- props.drawSelection && (0, import_view13.drawSelection)({
2836
+ props.dropCursor && (0, import_view14.dropCursor)(),
2837
+ props.drawSelection && (0, import_view14.drawSelection)({
2496
2838
  cursorBlinkRate: 1200
2497
2839
  }),
2498
2840
  props.focus && focus,
2499
- props.highlightActiveLine && (0, import_view13.highlightActiveLine)(),
2841
+ props.highlightActiveLine && (0, import_view14.highlightActiveLine)(),
2500
2842
  props.history && (0, import_commands2.history)(),
2501
- props.lineNumbers && (0, import_view13.lineNumbers)(),
2502
- props.lineWrapping && import_view13.EditorView.lineWrapping,
2503
- props.placeholder && (0, import_view13.placeholder)(props.placeholder),
2843
+ props.lineNumbers && (0, import_view14.lineNumbers)(),
2844
+ props.lineWrapping && import_view14.EditorView.lineWrapping,
2845
+ props.placeholder && (0, import_view14.placeholder)(props.placeholder),
2504
2846
  props.readonly && [
2505
2847
  import_state13.EditorState.readOnly.of(true),
2506
- import_view13.EditorView.editable.of(false)
2848
+ import_view14.EditorView.editable.of(false)
2507
2849
  ],
2508
- props.scrollPastEnd && (0, import_view13.scrollPastEnd)(),
2850
+ props.scrollPastEnd && (0, import_view14.scrollPastEnd)(),
2509
2851
  props.tabSize && import_state13.EditorState.tabSize.of(props.tabSize),
2510
2852
  // https://codemirror.net/docs/ref/#view.KeyBinding
2511
- import_view13.keymap.of([
2853
+ import_view14.keymap.of([
2512
2854
  ...(props.keymap && keymaps[props.keymap]) ?? [],
2513
2855
  // NOTE: Tabs are also configured by markdown extension.
2514
2856
  // https://codemirror.net/docs/ref/#commands.indentWithTab
@@ -2530,16 +2872,16 @@ var defaultThemeSlots = {
2530
2872
  }
2531
2873
  };
2532
2874
  var createThemeExtensions = ({ themeMode, styles: styles5, syntaxHighlighting: _syntaxHighlighting, slots: _slots } = {}) => {
2533
- const slots = (0, import_lodash3.default)({}, _slots, defaultThemeSlots);
2875
+ const slots = (0, import_lodash4.default)({}, _slots, defaultThemeSlots);
2534
2876
  return [
2535
- import_view13.EditorView.darkTheme.of(themeMode === "dark"),
2536
- import_view13.EditorView.baseTheme(styles5 ? (0, import_lodash4.default)({}, defaultTheme, styles5) : defaultTheme),
2877
+ import_view14.EditorView.darkTheme.of(themeMode === "dark"),
2878
+ import_view14.EditorView.baseTheme(styles5 ? (0, import_lodash5.default)({}, defaultTheme, styles5) : defaultTheme),
2537
2879
  // https://github.com/codemirror/theme-one-dark
2538
2880
  _syntaxHighlighting && (themeMode === "dark" ? (0, import_language2.syntaxHighlighting)(import_theme_one_dark.oneDarkHighlightStyle) : (0, import_language2.syntaxHighlighting)(import_language2.defaultHighlightStyle)),
2539
- slots.editor?.className && import_view13.EditorView.editorAttributes.of({
2881
+ slots.editor?.className && import_view14.EditorView.editorAttributes.of({
2540
2882
  class: slots.editor.className
2541
2883
  }),
2542
- slots.content?.className && import_view13.EditorView.contentAttributes.of({
2884
+ slots.content?.className && import_view14.EditorView.contentAttributes.of({
2543
2885
  class: slots.content.className
2544
2886
  })
2545
2887
  ].filter(import_util4.isNotFalsy);
@@ -2551,7 +2893,7 @@ var createDataExtensions = ({ id, text, space, identity }) => {
2551
2893
  }
2552
2894
  if (space && identity) {
2553
2895
  const peerId = identity?.identityKey.toHex();
2554
- const { cursorLightValue, cursorDarkValue } = import_react_ui_theme3.hueTokens[identity?.profile?.data?.hue ?? (0, import_util4.hexToHue)(peerId ?? "0")];
2896
+ const { cursorLightValue, cursorDarkValue } = import_react_ui_theme7.hueTokens[identity?.profile?.data?.hue ?? (0, import_util4.hexToHue)(peerId ?? "0")];
2555
2897
  extensions.push(awareness(new SpaceAwarenessProvider({
2556
2898
  space,
2557
2899
  channel: `awareness.${id}`,
@@ -2586,7 +2928,7 @@ var folding = (_props = {}) => [
2586
2928
  }));
2587
2929
  }
2588
2930
  }),
2589
- import_view15.EditorView.theme({
2931
+ import_view16.EditorView.theme({
2590
2932
  ".cm-foldGutter": {
2591
2933
  opacity: 0.3,
2592
2934
  transition: "opacity 0.3s",
@@ -2599,11 +2941,11 @@ var folding = (_props = {}) => [
2599
2941
  ];
2600
2942
  var listener = ({ onFocus, onChange }) => {
2601
2943
  const extensions = [];
2602
- onFocus && extensions.push(import_view16.EditorView.focusChangeEffect.of((_, focusing) => {
2944
+ onFocus && extensions.push(import_view17.EditorView.focusChangeEffect.of((_, focusing) => {
2603
2945
  onFocus(focusing);
2604
2946
  return null;
2605
2947
  }));
2606
- onChange && extensions.push(import_view16.EditorView.updateListener.of((update2) => {
2948
+ onChange && extensions.push(import_view17.EditorView.updateListener.of((update2) => {
2607
2949
  onChange(update2.state.doc.toString(), update2.state.facet(documentId));
2608
2950
  }));
2609
2951
  return extensions;
@@ -3494,7 +3836,7 @@ var toggleCodeblock = (target) => {
3494
3836
  };
3495
3837
  var formattingKeymap = (_options = {}) => {
3496
3838
  return [
3497
- import_view17.keymap.of([
3839
+ import_view18.keymap.of([
3498
3840
  {
3499
3841
  key: "meta-b",
3500
3842
  run: toggleStrong
@@ -3694,63 +4036,54 @@ var getFormatting = (state) => {
3694
4036
  listStyle: listStyle || null
3695
4037
  };
3696
4038
  };
3697
- var useFormattingState = () => {
3698
- const [state, setState] = (0, import_react6.useState)();
3699
- const observer = (0, import_react6.useMemo)(() => import_view17.EditorView.updateListener.of((update2) => {
4039
+ var useFormattingState = (state) => {
4040
+ return (0, import_react6.useMemo)(() => import_view18.EditorView.updateListener.of((update2) => {
3700
4041
  if (update2.docChanged || update2.selectionSet) {
3701
- setState((prevState) => {
3702
- const newState = getFormatting(update2.state);
3703
- if (!prevState || !formattingEquals(prevState, newState)) {
3704
- return newState;
3705
- }
3706
- return prevState;
4042
+ Object.entries(getFormatting(update2.state)).forEach(([key, active]) => {
4043
+ state[key] = active;
3707
4044
  });
3708
4045
  }
3709
4046
  }), []);
3710
- return [
3711
- state,
3712
- observer
3713
- ];
3714
4047
  };
3715
- var processAction = (view, action) => {
4048
+ var processEditorPayload = (view, { type, data }) => {
3716
4049
  let inlineType, listType;
3717
- switch (action.type) {
4050
+ switch (type) {
3718
4051
  case "heading":
3719
- setHeading(parseInt(action.data))(view);
4052
+ setHeading(parseInt(data))(view);
3720
4053
  break;
3721
4054
  case "strong":
3722
4055
  case "emphasis":
3723
4056
  case "strikethrough":
3724
4057
  case "code":
3725
- inlineType = action.type === "strong" ? Inline.Strong : action.type === "emphasis" ? Inline.Emphasis : action.type === "strikethrough" ? Inline.Strikethrough : Inline.Code;
3726
- (typeof action.data === "boolean" ? setStyle(inlineType, action.data) : toggleStyle(inlineType))(view);
4058
+ inlineType = type === "strong" ? Inline.Strong : type === "emphasis" ? Inline.Emphasis : type === "strikethrough" ? Inline.Strikethrough : Inline.Code;
4059
+ (typeof data === "boolean" ? setStyle(inlineType, data) : toggleStyle(inlineType))(view);
3727
4060
  break;
3728
4061
  case "list-ordered":
3729
4062
  case "list-bullet":
3730
4063
  case "list-task":
3731
- listType = action.type === "list-ordered" ? List.Ordered : action.type === "list-bullet" ? List.Bullet : List.Task;
3732
- (action.data === false ? removeList(listType) : action.data === true ? addList(listType) : toggleList(listType))(view);
4064
+ listType = type === "list-ordered" ? List.Ordered : type === "list-bullet" ? List.Bullet : List.Task;
4065
+ (data === false ? removeList(listType) : data === true ? addList(listType) : toggleList(listType))(view);
3733
4066
  break;
3734
4067
  case "blockquote":
3735
- (action.data === false ? removeBlockquote : action.data === true ? addBlockquote : toggleBlockquote)(view);
4068
+ (data === false ? removeBlockquote : data === true ? addBlockquote : toggleBlockquote)(view);
3736
4069
  break;
3737
4070
  case "codeblock":
3738
- (action.data === false ? removeCodeblock : addCodeblock)(view);
4071
+ (data === false ? removeCodeblock : addCodeblock)(view);
3739
4072
  break;
3740
4073
  case "table":
3741
4074
  insertTable(view);
3742
4075
  break;
3743
4076
  case "link":
3744
- (action.data === false ? removeLink : addLink())(view);
4077
+ (data === false ? removeLink : addLink())(view);
3745
4078
  break;
3746
4079
  case "image":
3747
4080
  addLink({
3748
- url: action.data,
4081
+ url: data,
3749
4082
  image: true
3750
4083
  })(view);
3751
4084
  break;
3752
4085
  case "comment":
3753
- createComment(view);
4086
+ createComment2(view);
3754
4087
  break;
3755
4088
  }
3756
4089
  requestAnimationFrame(() => {
@@ -3956,7 +4289,7 @@ var createMarkdownExtensions = ({ themeMode } = {}) => {
3956
4289
  }),
3957
4290
  // Custom styles.
3958
4291
  (0, import_language5.syntaxHighlighting)(markdownHighlightStyle()),
3959
- import_view18.keymap.of([
4292
+ import_view19.keymap.of([
3960
4293
  // https://codemirror.net/docs/ref/#commands.indentWithTab
3961
4294
  import_commands3.indentWithTab,
3962
4295
  // https://codemirror.net/docs/ref/#commands.defaultKeymap
@@ -3990,7 +4323,7 @@ var convertTreeToJson = (state) => {
3990
4323
  return treeToJson((0, import_language7.syntaxTree)(state).cursor());
3991
4324
  };
3992
4325
  var adjustChanges = () => {
3993
- return import_view20.ViewPlugin.fromClass(class {
4326
+ return import_view21.ViewPlugin.fromClass(class {
3994
4327
  update(update2) {
3995
4328
  const tree = (0, import_language9.syntaxTree)(update2.state);
3996
4329
  const adjustments = [];
@@ -4132,7 +4465,7 @@ var image = (_options = {}) => {
4132
4465
  return [
4133
4466
  import_state19.StateField.define({
4134
4467
  create: (state) => {
4135
- return import_view21.Decoration.set(buildDecorations(0, state.doc.length, state));
4468
+ return import_view22.Decoration.set(buildDecorations(0, state.doc.length, state));
4136
4469
  },
4137
4470
  update: (value, tr) => {
4138
4471
  if (!tr.docChanged && !tr.selection) {
@@ -4155,7 +4488,7 @@ var image = (_options = {}) => {
4155
4488
  add: buildDecorations(from, to, tr.state)
4156
4489
  });
4157
4490
  },
4158
- provide: (field) => import_view21.EditorView.decorations.from(field)
4491
+ provide: (field) => import_view22.EditorView.decorations.from(field)
4159
4492
  })
4160
4493
  ];
4161
4494
  };
@@ -4181,7 +4514,7 @@ var buildDecorations = (from, to, state) => {
4181
4514
  return;
4182
4515
  }
4183
4516
  preloadImage(url);
4184
- decorations.push(import_view21.Decoration.replace({
4517
+ decorations.push(import_view22.Decoration.replace({
4185
4518
  block: true,
4186
4519
  widget: new ImageWidget(url)
4187
4520
  }).range(hide2 ? node.from : node.to, node.to));
@@ -4193,7 +4526,7 @@ var buildDecorations = (from, to, state) => {
4193
4526
  });
4194
4527
  return decorations;
4195
4528
  };
4196
- var ImageWidget = class extends import_view21.WidgetType {
4529
+ var ImageWidget = class extends import_view22.WidgetType {
4197
4530
  constructor(_url) {
4198
4531
  super();
4199
4532
  this._url = _url;
@@ -4215,7 +4548,7 @@ var ImageWidget = class extends import_view21.WidgetType {
4215
4548
  };
4216
4549
  var bulletListIndentationWidth = 24;
4217
4550
  var orderedListIndentationWidth = 36;
4218
- var formattingStyles = import_view22.EditorView.theme({
4551
+ var formattingStyles = import_view23.EditorView.theme({
4219
4552
  /**
4220
4553
  * Horizontal rule.
4221
4554
  */
@@ -4309,13 +4642,34 @@ var formattingStyles = import_view22.EditorView.theme({
4309
4642
  height: "auto",
4310
4643
  borderTop: "0.5rem solid transparent",
4311
4644
  borderBottom: "0.5rem solid transparent"
4645
+ },
4646
+ ".cm-image-with-loader": {
4647
+ display: "block",
4648
+ opacity: "0",
4649
+ transitionDuration: "350ms",
4650
+ transitionProperty: "opacity"
4651
+ },
4652
+ ".cm-image-with-loader.cm-loaded-image": {
4653
+ opacity: "1"
4654
+ },
4655
+ ".cm-image-wrapper": {
4656
+ "grid-template-columns": "1fr",
4657
+ display: "grid",
4658
+ margin: "0.5rem 0",
4659
+ overflow: "hidden",
4660
+ transitionDuration: "350ms",
4661
+ transitionProperty: "height",
4662
+ "& > *": {
4663
+ "grid-row-start": 1,
4664
+ "grid-column-start": 1
4665
+ }
4312
4666
  }
4313
4667
  });
4314
4668
  var table = (options = {}) => {
4315
4669
  return import_state20.StateField.define({
4316
4670
  create: (state) => update(state, options),
4317
4671
  update: (_, tr) => update(tr.state, options),
4318
- provide: (field) => import_view23.EditorView.decorations.from(field)
4672
+ provide: (field) => import_view24.EditorView.decorations.from(field)
4319
4673
  });
4320
4674
  };
4321
4675
  var update = (state, _options) => {
@@ -4360,19 +4714,19 @@ var update = (state, _options) => {
4360
4714
  tables.forEach((table2) => {
4361
4715
  const replace = state.readOnly || cursor < table2.from || cursor > table2.to;
4362
4716
  if (replace) {
4363
- builder.add(table2.from, table2.to, import_view23.Decoration.replace({
4717
+ builder.add(table2.from, table2.to, import_view24.Decoration.replace({
4364
4718
  block: true,
4365
4719
  widget: new TableWidget(table2)
4366
4720
  }));
4367
4721
  } else {
4368
- builder.add(table2.from, table2.to, import_view23.Decoration.mark({
4722
+ builder.add(table2.from, table2.to, import_view24.Decoration.mark({
4369
4723
  class: "cm-table"
4370
4724
  }));
4371
4725
  }
4372
4726
  });
4373
4727
  return builder.finish();
4374
4728
  };
4375
- var TableWidget = class extends import_view23.WidgetType {
4729
+ var TableWidget = class extends import_view24.WidgetType {
4376
4730
  constructor(_table) {
4377
4731
  super();
4378
4732
  this._table = _table;
@@ -4412,14 +4766,14 @@ var Unicode = {
4412
4766
  bulletSmall: "\u2219",
4413
4767
  bulletSquare: "\u2B1D"
4414
4768
  };
4415
- var HorizontalRuleWidget = class extends import_view19.WidgetType {
4769
+ var HorizontalRuleWidget = class extends import_view20.WidgetType {
4416
4770
  toDOM() {
4417
4771
  const el = document.createElement("span");
4418
4772
  el.className = "cm-hr";
4419
4773
  return el;
4420
4774
  }
4421
4775
  };
4422
- var LinkButton = class extends import_view19.WidgetType {
4776
+ var LinkButton = class extends import_view20.WidgetType {
4423
4777
  constructor(url, render) {
4424
4778
  super();
4425
4779
  this.url = url;
@@ -4435,7 +4789,7 @@ var LinkButton = class extends import_view19.WidgetType {
4435
4789
  return el;
4436
4790
  }
4437
4791
  };
4438
- var CheckboxWidget = class extends import_view19.WidgetType {
4792
+ var CheckboxWidget = class extends import_view20.WidgetType {
4439
4793
  constructor(_checked) {
4440
4794
  super();
4441
4795
  this._checked = _checked;
@@ -4480,7 +4834,7 @@ var CheckboxWidget = class extends import_view19.WidgetType {
4480
4834
  return false;
4481
4835
  }
4482
4836
  };
4483
- var TextWidget = class extends import_view19.WidgetType {
4837
+ var TextWidget = class extends import_view20.WidgetType {
4484
4838
  constructor(text, className) {
4485
4839
  super();
4486
4840
  this.text = text;
@@ -4495,29 +4849,29 @@ var TextWidget = class extends import_view19.WidgetType {
4495
4849
  return el;
4496
4850
  }
4497
4851
  };
4498
- var hide = import_view19.Decoration.replace({});
4499
- var blockQuote = import_view19.Decoration.line({
4500
- class: (0, import_react_ui_theme6.mx)("cm-blockquote")
4852
+ var hide = import_view20.Decoration.replace({});
4853
+ var blockQuote = import_view20.Decoration.line({
4854
+ class: (0, import_react_ui_theme8.mx)("cm-blockquote")
4501
4855
  });
4502
- var fencedCodeLine = import_view19.Decoration.line({
4503
- class: (0, import_react_ui_theme6.mx)("cm-code cm-codeblock-line")
4856
+ var fencedCodeLine = import_view20.Decoration.line({
4857
+ class: (0, import_react_ui_theme8.mx)("cm-code cm-codeblock-line")
4504
4858
  });
4505
- var fencedCodeLineFirst = import_view19.Decoration.line({
4506
- class: (0, import_react_ui_theme6.mx)("cm-code cm-codeblock-line", "cm-codeblock-first")
4859
+ var fencedCodeLineFirst = import_view20.Decoration.line({
4860
+ class: (0, import_react_ui_theme8.mx)("cm-code cm-codeblock-line", "cm-codeblock-first")
4507
4861
  });
4508
- var fencedCodeLineLast = import_view19.Decoration.line({
4509
- class: (0, import_react_ui_theme6.mx)("cm-code cm-codeblock-line", "cm-codeblock-last")
4862
+ var fencedCodeLineLast = import_view20.Decoration.line({
4863
+ class: (0, import_react_ui_theme8.mx)("cm-code cm-codeblock-line", "cm-codeblock-last")
4510
4864
  });
4511
4865
  var commentBlockLine = fencedCodeLine;
4512
4866
  var commentBlockLineFirst = fencedCodeLineFirst;
4513
4867
  var commentBlockLineLast = fencedCodeLineLast;
4514
- var horizontalRule = import_view19.Decoration.replace({
4868
+ var horizontalRule = import_view20.Decoration.replace({
4515
4869
  widget: new HorizontalRuleWidget()
4516
4870
  });
4517
- var checkedTask = import_view19.Decoration.replace({
4871
+ var checkedTask = import_view20.Decoration.replace({
4518
4872
  widget: new CheckboxWidget(true)
4519
4873
  });
4520
- var uncheckedTask = import_view19.Decoration.replace({
4874
+ var uncheckedTask = import_view20.Decoration.replace({
4521
4875
  widget: new CheckboxWidget(false)
4522
4876
  });
4523
4877
  var editingRange = (state, range, focus2) => {
@@ -4618,7 +4972,7 @@ var buildDecorations2 = (view, options, focus2) => {
4618
4972
  } else {
4619
4973
  const num = headers.slice(from - 1).map((level2) => level2?.number ?? 0).join(".") + " ";
4620
4974
  if (num.length) {
4621
- atomicDeco.add(mark.from, mark.from + len, import_view19.Decoration.replace({
4975
+ atomicDeco.add(mark.from, mark.from + len, import_view20.Decoration.replace({
4622
4976
  widget: new TextWidget(num, theme.heading(level))
4623
4977
  }));
4624
4978
  }
@@ -4643,7 +4997,7 @@ var buildDecorations2 = (view, options, focus2) => {
4643
4997
  if (node.from === line.to - 1) {
4644
4998
  return false;
4645
4999
  }
4646
- deco.add(line.from, line.from, import_view19.Decoration.line({
5000
+ deco.add(line.from, line.from, import_view20.Decoration.line({
4647
5001
  class: "cm-list-item",
4648
5002
  attributes: {
4649
5003
  style: `padding-left: ${offset}px; text-indent: -${width}px;`
@@ -4660,7 +5014,7 @@ var buildDecorations2 = (view, options, focus2) => {
4660
5014
  const label = list.type === "OrderedList" ? `${++list.number}.` : Unicode.bulletSmall;
4661
5015
  const line = state.doc.lineAt(node.from);
4662
5016
  const to = state.doc.sliceString(node.to, node.to + 1) === " " ? node.to + 1 : node.to;
4663
- atomicDeco.add(line.from, to, import_view19.Decoration.replace({
5017
+ atomicDeco.add(line.from, to, import_view20.Decoration.replace({
4664
5018
  widget: new TextWidget(label, list.type === "OrderedList" ? "cm-list-mark cm-list-mark-ordered" : "cm-list-mark cm-list-mark-bullet")
4665
5019
  }));
4666
5020
  break;
@@ -4747,7 +5101,7 @@ var buildDecorations2 = (view, options, focus2) => {
4747
5101
  if (!editing) {
4748
5102
  atomicDeco.add(node.from, marks[0].to, hide);
4749
5103
  }
4750
- deco.add(marks[0].to, marks[1].from, import_view19.Decoration.mark({
5104
+ deco.add(marks[0].to, marks[1].from, import_view20.Decoration.mark({
4751
5105
  tagName: "a",
4752
5106
  attributes: {
4753
5107
  class: "cm-link",
@@ -4757,7 +5111,7 @@ var buildDecorations2 = (view, options, focus2) => {
4757
5111
  }
4758
5112
  }));
4759
5113
  if (!editing) {
4760
- atomicDeco.add(marks[1].from, node.to, options.renderLinkButton ? import_view19.Decoration.replace({
5114
+ atomicDeco.add(marks[1].from, node.to, options.renderLinkButton ? import_view20.Decoration.replace({
4761
5115
  widget: new LinkButton(url, options.renderLinkButton)
4762
5116
  }) : hide);
4763
5117
  }
@@ -4815,7 +5169,7 @@ var buildDecorations2 = (view, options, focus2) => {
4815
5169
  var forceUpdate = import_state17.StateEffect.define();
4816
5170
  var decorateMarkdown = (options = {}) => {
4817
5171
  return [
4818
- import_view19.ViewPlugin.fromClass(class {
5172
+ import_view20.ViewPlugin.fromClass(class {
4819
5173
  constructor(view) {
4820
5174
  ({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations2(view, options, view.hasFocus));
4821
5175
  }
@@ -4847,9 +5201,9 @@ var decorateMarkdown = (options = {}) => {
4847
5201
  }
4848
5202
  }, {
4849
5203
  provide: (plugin) => [
4850
- import_view19.EditorView.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? import_view19.Decoration.none),
4851
- import_view19.EditorView.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? import_view19.Decoration.none),
4852
- import_view19.EditorView.decorations.of((view) => view.plugin(plugin)?.deco ?? import_view19.Decoration.none)
5204
+ import_view20.EditorView.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? import_view20.Decoration.none),
5205
+ import_view20.EditorView.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? import_view20.Decoration.none),
5206
+ import_view20.EditorView.decorations.of((view) => view.plugin(plugin)?.deco ?? import_view20.Decoration.none)
4853
5207
  ]
4854
5208
  }),
4855
5209
  image(),
@@ -4859,7 +5213,7 @@ var decorateMarkdown = (options = {}) => {
4859
5213
  ];
4860
5214
  };
4861
5215
  var linkTooltip = (render) => {
4862
- return (0, import_view24.hoverTooltip)((view, pos, side) => {
5216
+ return (0, import_view25.hoverTooltip)((view, pos, side) => {
4863
5217
  const syntax = (0, import_language12.syntaxTree)(view.state).resolveInner(pos, side);
4864
5218
  let link = null;
4865
5219
  for (let i = 0, node = syntax; !link && node && i < 5; node = node.parent, i++) {
@@ -4876,7 +5230,7 @@ var linkTooltip = (render) => {
4876
5230
  above: true,
4877
5231
  create: () => {
4878
5232
  const el = document.createElement("div");
4879
- el.className = (0, import_react_ui_theme7.tooltipContent)({}, "pli-2 plb-1");
5233
+ el.className = (0, import_react_ui_theme9.tooltipContent)({}, "pli-2 plb-1");
4880
5234
  render(el, urlText);
4881
5235
  return {
4882
5236
  dom: el,
@@ -4943,7 +5297,7 @@ var InputModeExtensions = {
4943
5297
  editorInputMode.of({
4944
5298
  type: "vscode"
4945
5299
  }),
4946
- import_view25.keymap.of(import_codemirror_vscode_keymap.vscodeKeymap)
5300
+ import_view26.keymap.of(import_codemirror_vscode_keymap.vscodeKeymap)
4947
5301
  ],
4948
5302
  vim: [
4949
5303
  // https://github.com/replit/codemirror-vim
@@ -4952,7 +5306,7 @@ var InputModeExtensions = {
4952
5306
  type: "vim",
4953
5307
  noTabster: true
4954
5308
  }),
4955
- import_view25.keymap.of([
5309
+ import_view26.keymap.of([
4956
5310
  {
4957
5311
  key: "Alt-Escape",
4958
5312
  run: (view) => {
@@ -4972,7 +5326,7 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
4972
5326
  let t;
4973
5327
  let idx = 0;
4974
5328
  return [
4975
- import_view26.keymap.of([
5329
+ import_view27.keymap.of([
4976
5330
  {
4977
5331
  // Reset.
4978
5332
  key: "alt-meta-'",
@@ -5017,413 +5371,19 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
5017
5371
  ])
5018
5372
  ];
5019
5373
  };
5020
- var iconStyles = (0, import_react_ui_theme.getSize)(5);
5021
- var buttonStyles = "min-bs-0 p-1";
5022
- var tooltipProps = {
5023
- side: "top",
5024
- classNames: "z-10"
5025
- };
5026
- var ToolbarSeparator = () => /* @__PURE__ */ import_react2.default.createElement("div", {
5027
- role: "separator",
5028
- className: "grow"
5029
- });
5030
- var [ToolbarContextProvider, useToolbarContext] = (0, import_react_context.createContext)("Toolbar");
5031
- var ToolbarRoot = ({ children, onAction, classNames, state }) => {
5032
- return /* @__PURE__ */ import_react2.default.createElement(ToolbarContextProvider, {
5033
- onAction,
5034
- state
5035
- }, /* @__PURE__ */ import_react2.default.createElement(import_react_ui.ElevationProvider, {
5036
- elevation: "positioned"
5037
- }, /* @__PURE__ */ import_react2.default.createElement(import_react_ui.Toolbar.Root, {
5038
- classNames: [
5039
- "p-1 is-full shrink-0 overflow-x-auto overflow-y-hidden",
5040
- classNames
5041
- ],
5042
- style: {
5043
- contain: "layout"
5044
- }
5045
- }, children)));
5046
- };
5047
- var ToolbarToggleButton = ({ Icon: Icon2, children, ...props }) => {
5048
- return /* @__PURE__ */ import_react2.default.createElement(import_react_ui.Tooltip.Root, null, /* @__PURE__ */ import_react2.default.createElement(import_react_ui.Tooltip.Trigger, {
5049
- asChild: true
5050
- }, /* @__PURE__ */ import_react2.default.createElement(import_react_ui.Toolbar.ToggleGroupItem, {
5051
- variant: "ghost",
5052
- ...props,
5053
- classNames: buttonStyles
5054
- }, /* @__PURE__ */ import_react2.default.createElement(Icon2, {
5055
- className: iconStyles
5056
- }), /* @__PURE__ */ import_react2.default.createElement("span", {
5057
- className: "sr-only"
5058
- }, children))), /* @__PURE__ */ import_react2.default.createElement(import_react_ui.Tooltip.Portal, null, /* @__PURE__ */ import_react2.default.createElement(import_react_ui.Tooltip.Content, tooltipProps, children, /* @__PURE__ */ import_react2.default.createElement(import_react_ui.Tooltip.Arrow, null))));
5059
- };
5060
- var ToolbarButton = ({ Icon: Icon2, children, ...props }) => {
5061
- return /* @__PURE__ */ import_react2.default.createElement(import_react_ui.Tooltip.Root, null, /* @__PURE__ */ import_react2.default.createElement(import_react_ui.Tooltip.Trigger, {
5062
- asChild: true
5063
- }, /* @__PURE__ */ import_react2.default.createElement(import_react_ui.Toolbar.Button, {
5064
- variant: "ghost",
5065
- ...props,
5066
- classNames: buttonStyles
5067
- }, /* @__PURE__ */ import_react2.default.createElement(Icon2, {
5068
- className: iconStyles
5069
- }), /* @__PURE__ */ import_react2.default.createElement("span", {
5070
- className: "sr-only"
5071
- }, children))), /* @__PURE__ */ import_react2.default.createElement(import_react_ui.Tooltip.Portal, null, /* @__PURE__ */ import_react2.default.createElement(import_react_ui.Tooltip.Content, tooltipProps, children, /* @__PURE__ */ import_react2.default.createElement(import_react_ui.Tooltip.Arrow, null))));
5072
- };
5073
- var HeadingIcons = {
5074
- "0": import_react.Paragraph,
5075
- "1": import_react.TextHOne,
5076
- "2": import_react.TextHTwo,
5077
- "3": import_react.TextHThree,
5078
- "4": import_react.TextHFour,
5079
- "5": import_react.TextHFive,
5080
- "6": import_react.TextHSix
5081
- };
5082
- var MarkdownHeading = () => {
5083
- const { t } = (0, import_react_ui.useTranslation)(translationKey);
5084
- const { onAction, state } = useToolbarContext("MarkdownFormatting");
5085
- const blockType = state ? state.blockType : "paragraph";
5086
- const header = blockType && /heading(\d)/.exec(blockType);
5087
- const value = header ? header[1] : blockType === "paragraph" || !blockType ? "0" : void 0;
5088
- const HeadingIcon = HeadingIcons[value ?? "0"];
5089
- const suppressNextTooltip = (0, import_react2.useRef)(false);
5090
- const [tooltipOpen, setTooltipOpen] = (0, import_react2.useState)(false);
5091
- const [selectOpen, setSelectOpen] = (0, import_react2.useState)(false);
5092
- return /* @__PURE__ */ import_react2.default.createElement(import_react_ui.Tooltip.Root, {
5093
- open: tooltipOpen,
5094
- onOpenChange: (nextOpen) => {
5095
- if (nextOpen && suppressNextTooltip.current) {
5096
- suppressNextTooltip.current = false;
5097
- return setTooltipOpen(false);
5098
- } else {
5099
- return setTooltipOpen(nextOpen);
5100
- }
5101
- }
5102
- }, /* @__PURE__ */ import_react2.default.createElement(import_react_ui.DropdownMenu.Root, {
5103
- open: selectOpen,
5104
- onOpenChange: (nextOpen) => {
5105
- if (!nextOpen) {
5106
- suppressNextTooltip.current = true;
5107
- }
5108
- return setSelectOpen(nextOpen);
5109
- }
5110
- }, /* @__PURE__ */ import_react2.default.createElement(import_react_ui.Tooltip.Trigger, {
5111
- asChild: true
5112
- }, /* @__PURE__ */ import_react2.default.createElement(import_react_ui.Toolbar.Button, {
5113
- asChild: true
5114
- }, /* @__PURE__ */ import_react2.default.createElement(import_react_ui.DropdownMenu.Trigger, {
5115
- asChild: true
5116
- }, /* @__PURE__ */ import_react2.default.createElement(import_react_ui.Button, {
5117
- variant: "ghost",
5118
- classNames: buttonStyles,
5119
- disabled: value === null
5120
- }, /* @__PURE__ */ import_react2.default.createElement("span", {
5121
- className: "sr-only"
5122
- }, t("heading label")), /* @__PURE__ */ import_react2.default.createElement(HeadingIcon, {
5123
- className: iconStyles
5124
- }), /* @__PURE__ */ import_react2.default.createElement(import_react.CaretDown, null))))), /* @__PURE__ */ import_react2.default.createElement(import_react_ui.DropdownMenu.Portal, null, /* @__PURE__ */ import_react2.default.createElement(import_react_ui.DropdownMenu.Content, {
5125
- classNames: "is-min md:is-min",
5126
- onCloseAutoFocus: (e) => e.preventDefault()
5127
- }, /* @__PURE__ */ import_react2.default.createElement(import_react_ui.DropdownMenu.Viewport, null, Object.keys(HeadingIcons).map((level) => {
5128
- const Icon2 = HeadingIcons[level];
5129
- return /* @__PURE__ */ import_react2.default.createElement(import_react_ui.DropdownMenu.CheckboxItem, {
5130
- key: level,
5131
- checked: value === level,
5132
- onClick: () => onAction?.({
5133
- type: "heading",
5134
- data: level
5135
- })
5136
- }, /* @__PURE__ */ import_react2.default.createElement("span", {
5137
- className: "sr-only"
5138
- }, t("heading level label", {
5139
- count: parseInt(level)
5140
- })), /* @__PURE__ */ import_react2.default.createElement(Icon2, {
5141
- className: iconStyles
5142
- }), /* @__PURE__ */ import_react2.default.createElement(import_react_ui.DropdownMenu.ItemIndicator, null, /* @__PURE__ */ import_react2.default.createElement(import_react.Check, null)));
5143
- })), /* @__PURE__ */ import_react2.default.createElement(import_react_ui.DropdownMenu.Arrow, null)))), /* @__PURE__ */ import_react2.default.createElement(import_react_ui.Tooltip.Portal, null, /* @__PURE__ */ import_react2.default.createElement(import_react_ui.Tooltip.Content, tooltipProps, t("heading label"), /* @__PURE__ */ import_react2.default.createElement(import_react_ui.Tooltip.Arrow, null))));
5144
- };
5145
- var markdownStyles = [
5146
- {
5147
- type: "strong",
5148
- Icon: import_react.TextB,
5149
- getState: (state) => !!state?.strong
5150
- },
5151
- {
5152
- type: "emphasis",
5153
- Icon: import_react.TextItalic,
5154
- getState: (state) => !!state?.emphasis
5155
- },
5156
- {
5157
- type: "strikethrough",
5158
- Icon: import_react.TextStrikethrough,
5159
- getState: (state) => !!state?.strikethrough
5160
- },
5161
- {
5162
- type: "code",
5163
- Icon: import_react.Code,
5164
- getState: (state) => !!state?.code
5165
- },
5166
- {
5167
- type: "link",
5168
- Icon: import_react.Link,
5169
- getState: (state) => !!state?.link
5170
- }
5171
- ];
5172
- var MarkdownStyles = () => {
5173
- const { onAction, state } = useToolbarContext("MarkdownStyles");
5174
- const { t } = (0, import_react_ui.useTranslation)(translationKey);
5175
- return /* @__PURE__ */ import_react2.default.createElement(import_react_ui.Toolbar.ToggleGroup, {
5176
- type: "multiple",
5177
- value: markdownStyles.filter(({ getState }) => state && getState(state)).map(({ type }) => type)
5178
- }, markdownStyles.map(({ type, getState, Icon: Icon2 }) => /* @__PURE__ */ import_react2.default.createElement(ToolbarToggleButton, {
5179
- key: type,
5180
- value: type,
5181
- Icon: Icon2,
5182
- disabled: state?.blockType === "codeblock",
5183
- onClick: state ? () => onAction?.({
5184
- type,
5185
- data: !getState(state)
5186
- }) : void 0
5187
- }, t(`${type} label`))));
5188
- };
5189
- var markdownLists = [
5190
- {
5191
- type: "list-bullet",
5192
- Icon: import_react.ListBullets,
5193
- getState: (state) => state.listStyle === "bullet"
5194
- },
5195
- {
5196
- type: "list-ordered",
5197
- Icon: import_react.ListNumbers,
5198
- getState: (state) => state.listStyle === "ordered"
5199
- },
5200
- {
5201
- type: "list-task",
5202
- Icon: import_react.ListChecks,
5203
- getState: (state) => state.listStyle === "task"
5204
- }
5205
- ];
5206
- var MarkdownLists = () => {
5207
- const { onAction, state } = useToolbarContext("MarkdownStyles");
5208
- const { t } = (0, import_react_ui.useTranslation)(translationKey);
5209
- return /* @__PURE__ */ import_react2.default.createElement(import_react_ui.Toolbar.ToggleGroup, {
5210
- type: "single",
5211
- value: state?.listStyle ? `list-${state.listStyle}` : ""
5212
- }, markdownLists.map(({ type, getState, Icon: Icon2 }) => /* @__PURE__ */ import_react2.default.createElement(ToolbarToggleButton, {
5213
- key: type,
5214
- value: type,
5215
- Icon: Icon2,
5216
- onClick: state ? () => onAction?.({
5217
- type,
5218
- data: !getState(state)
5219
- }) : void 0
5220
- }, t(`${type} label`))));
5221
- };
5222
- var markdownBlocks = [
5223
- {
5224
- type: "blockquote",
5225
- Icon: import_react.Quotes,
5226
- getState: (state) => !!state?.blockQuote
5227
- },
5228
- {
5229
- type: "codeblock",
5230
- Icon: import_react.CodeBlock,
5231
- getState: (state) => state.blockType === "codeblock"
5232
- },
5233
- {
5234
- type: "table",
5235
- Icon: import_react.Table,
5236
- getState: (state) => state.blockType === "tablecell",
5237
- disabled: (state) => !state.blankLine
5238
- }
5239
- ];
5240
- var MarkdownBlocks = () => {
5241
- const { onAction, state } = useToolbarContext("MarkdownStyles");
5242
- const { t } = (0, import_react_ui.useTranslation)(translationKey);
5243
- const value = markdownBlocks.find(({ getState }) => state && getState(state));
5244
- return /* @__PURE__ */ import_react2.default.createElement(import_react_ui.Toolbar.ToggleGroup, {
5245
- type: "single",
5246
- value: value?.type ?? ""
5247
- }, markdownBlocks.map(({ type, disabled, getState, Icon: Icon2 }) => /* @__PURE__ */ import_react2.default.createElement(ToolbarToggleButton, {
5248
- key: type,
5249
- value: type,
5250
- Icon: Icon2,
5251
- disabled: !state || disabled?.(state),
5252
- onClick: state ? () => onAction?.({
5253
- type,
5254
- data: !getState(state)
5255
- }) : void 0
5256
- }, t(`${type} label`))));
5257
- };
5258
- var MarkdownStandard = () => /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement(MarkdownHeading, null), /* @__PURE__ */ import_react2.default.createElement(MarkdownStyles, null), /* @__PURE__ */ import_react2.default.createElement(MarkdownLists, null), /* @__PURE__ */ import_react2.default.createElement(MarkdownBlocks, null));
5259
- var MarkdownCustom = ({ onUpload } = {}) => {
5260
- const { onAction } = useToolbarContext("MarkdownStyles");
5261
- const { t } = (0, import_react_ui.useTranslation)(translationKey);
5262
- const { acceptedFiles, getInputProps, open } = (0, import_react_dropzone.useDropzone)({
5263
- multiple: false,
5264
- noDrag: true,
5265
- accept: {
5266
- "image/*": [
5267
- ".jpg",
5268
- ".jpeg",
5269
- ".png",
5270
- ".gif"
5271
- ]
5272
- }
5273
- });
5274
- (0, import_react2.useEffect)(() => {
5275
- if (onUpload && acceptedFiles.length) {
5276
- requestAnimationFrame(async () => {
5277
- const f = acceptedFiles[0];
5278
- const file = new File([
5279
- f
5280
- ], f.name, {
5281
- type: f.type,
5282
- lastModified: f.lastModified
5283
- });
5284
- const info = await onUpload(file);
5285
- if (info) {
5286
- onAction?.({
5287
- type: "image",
5288
- data: info.url
5289
- });
5290
- }
5291
- });
5292
- }
5293
- }, [
5294
- acceptedFiles
5295
- ]);
5296
- return /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement("input", getInputProps()), /* @__PURE__ */ import_react2.default.createElement(ToolbarButton, {
5297
- value: "image",
5298
- Icon: import_react.Image,
5299
- onClick: () => open()
5300
- }, t("image label")));
5301
- };
5302
- var ViewModeIcons = {
5303
- preview: import_react.PencilSimple,
5304
- readonly: import_react.PencilSimpleSlash,
5305
- source: import_react.MarkdownLogo
5306
- };
5307
- var MarkdownView = ({ mode }) => {
5308
- const { t } = (0, import_react_ui.useTranslation)(translationKey);
5309
- const { onAction } = useToolbarContext("ViewMode");
5310
- const ModeIcon = ViewModeIcons[mode ?? "preview"];
5311
- const suppressNextTooltip = (0, import_react2.useRef)(false);
5312
- const [tooltipOpen, setTooltipOpen] = (0, import_react2.useState)(false);
5313
- const [selectOpen, setSelectOpen] = (0, import_react2.useState)(false);
5314
- return /* @__PURE__ */ import_react2.default.createElement(import_react_ui.Tooltip.Root, {
5315
- open: tooltipOpen,
5316
- onOpenChange: (nextOpen) => {
5317
- if (nextOpen && suppressNextTooltip.current) {
5318
- suppressNextTooltip.current = false;
5319
- return setTooltipOpen(false);
5320
- } else {
5321
- return setTooltipOpen(nextOpen);
5322
- }
5323
- }
5324
- }, /* @__PURE__ */ import_react2.default.createElement(import_react_ui.DropdownMenu.Root, {
5325
- open: selectOpen,
5326
- onOpenChange: (nextOpen) => {
5327
- if (!nextOpen) {
5328
- suppressNextTooltip.current = true;
5329
- }
5330
- return setSelectOpen(nextOpen);
5331
- }
5332
- }, /* @__PURE__ */ import_react2.default.createElement(import_react_ui.Tooltip.Trigger, {
5333
- asChild: true
5334
- }, /* @__PURE__ */ import_react2.default.createElement(import_react_ui.Toolbar.Button, {
5335
- asChild: true
5336
- }, /* @__PURE__ */ import_react2.default.createElement(import_react_ui.DropdownMenu.Trigger, {
5337
- asChild: true
5338
- }, /* @__PURE__ */ import_react2.default.createElement(import_react_ui.Button, {
5339
- variant: "ghost",
5340
- classNames: buttonStyles
5341
- }, /* @__PURE__ */ import_react2.default.createElement("span", {
5342
- className: "sr-only"
5343
- }, t("mode label")), /* @__PURE__ */ import_react2.default.createElement(ModeIcon, {
5344
- className: iconStyles
5345
- }), /* @__PURE__ */ import_react2.default.createElement(import_react.CaretDown, null))))), /* @__PURE__ */ import_react2.default.createElement(import_react_ui.DropdownMenu.Portal, null, /* @__PURE__ */ import_react2.default.createElement(import_react_ui.DropdownMenu.Content, {
5346
- classNames: "is-min md:is-min",
5347
- onCloseAutoFocus: (e) => e.preventDefault()
5348
- }, /* @__PURE__ */ import_react2.default.createElement(import_react_ui.DropdownMenu.Viewport, null, EditorViewModes.map((value) => {
5349
- const Icon2 = ViewModeIcons[value];
5350
- return /* @__PURE__ */ import_react2.default.createElement(import_react_ui.DropdownMenu.CheckboxItem, {
5351
- key: value,
5352
- checked: value === mode,
5353
- onClick: () => onAction?.({
5354
- type: "view-mode",
5355
- data: value
5356
- })
5357
- }, /* @__PURE__ */ import_react2.default.createElement(Icon2, {
5358
- className: iconStyles
5359
- }), /* @__PURE__ */ import_react2.default.createElement("span", {
5360
- className: "whitespace-nowrap grow"
5361
- }, t(`${value} mode label`)), /* @__PURE__ */ import_react2.default.createElement(import_react.Check, {
5362
- className: value === mode ? "visible" : "invisible"
5363
- }));
5364
- })), /* @__PURE__ */ import_react2.default.createElement(import_react_ui.DropdownMenu.Arrow, null)))), /* @__PURE__ */ import_react2.default.createElement(import_react_ui.Tooltip.Portal, null, /* @__PURE__ */ import_react2.default.createElement(import_react_ui.Tooltip.Content, tooltipProps, t("view mode label"), /* @__PURE__ */ import_react2.default.createElement(import_react_ui.Tooltip.Arrow, null))));
5365
- };
5366
- var MarkdownActions = () => {
5367
- const { onAction, state } = useToolbarContext("MarkdownActions");
5368
- const { t } = (0, import_react_ui.useTranslation)(translationKey);
5369
- let commentToolTipKey = "comment label";
5370
- if (state?.comment) {
5371
- commentToolTipKey = "selection overlaps existing comment label";
5372
- } else if (state?.selection === false) {
5373
- commentToolTipKey = "select text to comment label";
5374
- }
5375
- return /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement(ToolbarButton, {
5376
- value: "search",
5377
- Icon: import_react.MagnifyingGlass,
5378
- onClick: () => onAction?.({
5379
- type: "search"
5380
- })
5381
- }, t("search label")), /* @__PURE__ */ import_react2.default.createElement(ToolbarButton, {
5382
- value: "comment",
5383
- Icon: import_react.ChatText,
5384
- "data-testid": "editor.toolbar.comment",
5385
- onClick: () => onAction?.({
5386
- type: "comment"
5387
- }),
5388
- disabled: !state || state.comment || !state.selection
5389
- }, t(commentToolTipKey)));
5390
- };
5391
- var Toolbar = {
5392
- Root: ToolbarRoot,
5393
- Button: ToolbarToggleButton,
5394
- Separator: ToolbarSeparator,
5395
- View: MarkdownView,
5396
- Markdown: MarkdownStandard,
5397
- Custom: MarkdownCustom,
5398
- Actions: MarkdownActions
5399
- };
5400
- var margin = "!mt-[1rem]";
5401
- var editorContent = (0, import_react_ui_theme8.mx)(margin, "!mli-auto w-full max-w-[min(50rem,100%-2rem)]");
5402
- var editorFullWidth = (0, import_react_ui_theme8.mx)(margin);
5403
- var editorWithToolbarLayout = "grid grid-cols-1 grid-rows-[min-content_1fr] data-[toolbar=disabled]:grid-rows-[1fr] justify-center content-start overflow-hidden";
5404
- var editorGutter = import_view27.EditorView.theme({
5405
- // Match margin from content.
5406
- ".cm-gutters": {
5407
- marginTop: "16px",
5408
- paddingRight: "1rem"
5409
- }
5410
- });
5411
- var editorMonospace = import_view27.EditorView.theme({
5412
- ".cm-content": {
5413
- fontFamily: fontMono
5414
- }
5415
- });
5416
5374
  var useActionHandler = (view) => {
5417
- return (action) => view && processAction(view, action);
5375
+ return (0, import_react7.useCallback)((action) => view && processEditorPayload(view, action.properties), [
5376
+ view
5377
+ ]);
5418
5378
  };
5419
5379
  var __dxlog_file11 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
5420
5380
  var instanceCount = 0;
5421
5381
  var useTextEditor = (props = {}, deps = []) => {
5422
- const { id, initialValue, extensions, autoFocus, scrollTo, selection, moveToEndOfLine, debug } = (0, import_react7.useMemo)(() => (0, import_util5.getProviderValue)(props), deps ?? []);
5423
- const [instanceId] = (0, import_react7.useState)(() => `text-editor-${++instanceCount}`);
5424
- const [view, setView] = (0, import_react7.useState)();
5425
- const parentRef = (0, import_react7.useRef)(null);
5426
- (0, import_react7.useEffect)(() => {
5382
+ const { id, initialValue, extensions, autoFocus, scrollTo, selection, moveToEndOfLine, debug } = (0, import_react8.useMemo)(() => (0, import_util5.getProviderValue)(props), deps ?? []);
5383
+ const [instanceId] = (0, import_react8.useState)(() => `text-editor-${++instanceCount}`);
5384
+ const [view, setView] = (0, import_react8.useState)();
5385
+ const parentRef = (0, import_react8.useRef)(null);
5386
+ (0, import_react8.useEffect)(() => {
5427
5387
  let view2;
5428
5388
  if (parentRef.current) {
5429
5389
  (0, import_log7.log)("create", {
@@ -5497,7 +5457,7 @@ var useTextEditor = (props = {}, deps = []) => {
5497
5457
  view2?.destroy();
5498
5458
  };
5499
5459
  }, deps);
5500
- (0, import_react7.useEffect)(() => {
5460
+ (0, import_react8.useEffect)(() => {
5501
5461
  if (view) {
5502
5462
  if (scrollTo || selection) {
5503
5463
  if (selection && selection.anchor > view.state.doc.length) {
@@ -5524,7 +5484,7 @@ var useTextEditor = (props = {}, deps = []) => {
5524
5484
  scrollTo,
5525
5485
  selection
5526
5486
  ]);
5527
- (0, import_react7.useEffect)(() => {
5487
+ (0, import_react8.useEffect)(() => {
5528
5488
  if (view && autoFocus) {
5529
5489
  view.focus();
5530
5490
  }
@@ -5538,7 +5498,7 @@ var useTextEditor = (props = {}, deps = []) => {
5538
5498
  Escape: view?.state.facet(editorInputMode).noTabster
5539
5499
  }
5540
5500
  });
5541
- const handleKeyUp = (0, import_react7.useCallback)((event) => {
5501
+ const handleKeyUp = (0, import_react8.useCallback)((event) => {
5542
5502
  const { key, target, currentTarget } = event;
5543
5503
  if (target === currentTarget) {
5544
5504
  switch (key) {
@@ -5568,6 +5528,7 @@ var useTextEditor = (props = {}, deps = []) => {
5568
5528
  EditorInputMode,
5569
5529
  EditorInputModes,
5570
5530
  EditorState,
5531
+ EditorToolbar,
5571
5532
  EditorView,
5572
5533
  EditorViewMode,
5573
5534
  EditorViewModes,
@@ -5577,7 +5538,6 @@ var useTextEditor = (props = {}, deps = []) => {
5577
5538
  RemoteSelectionsDecorator,
5578
5539
  SpaceAwarenessProvider,
5579
5540
  TextKind,
5580
- Toolbar,
5581
5541
  addBlockquote,
5582
5542
  addCodeblock,
5583
5543
  addLink,
@@ -5598,6 +5558,8 @@ var useTextEditor = (props = {}, deps = []) => {
5598
5558
  createBasicExtensions,
5599
5559
  createComment,
5600
5560
  createDataExtensions,
5561
+ createEditorAction,
5562
+ createEditorActionGroup,
5601
5563
  createEditorStateStore,
5602
5564
  createEditorStateTransaction,
5603
5565
  createElement,
@@ -5636,7 +5598,7 @@ var useTextEditor = (props = {}, deps = []) => {
5636
5598
  mention,
5637
5599
  overlap,
5638
5600
  preventNewline,
5639
- processAction,
5601
+ processEditorPayload,
5640
5602
  removeBlockquote,
5641
5603
  removeCodeblock,
5642
5604
  removeLink,
@@ -5652,6 +5614,8 @@ var useTextEditor = (props = {}, deps = []) => {
5652
5614
  setSelection,
5653
5615
  setStyle,
5654
5616
  singleValueFacet,
5617
+ stackItemContentEditorClassNames,
5618
+ stackItemContentToolbarClassNames,
5655
5619
  table,
5656
5620
  tags,
5657
5621
  textRange,
@@ -5669,9 +5633,9 @@ var useTextEditor = (props = {}, deps = []) => {
5669
5633
  useCommentClickListener,
5670
5634
  useCommentState,
5671
5635
  useComments,
5636
+ useEditorToolbarState,
5672
5637
  useFormattingState,
5673
5638
  useTextEditor,
5674
- useToolbarContext,
5675
5639
  wrapWithCatch
5676
5640
  });
5677
5641
  //# sourceMappingURL=index.cjs.map