@dxos/react-ui-editor 0.4.8-main.05fda5d → 0.4.8-main.06fa7e4

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 (137) hide show
  1. package/dist/lib/browser/index.mjs +1938 -1920
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/types/src/components/TextEditor/TextEditor.d.ts +18 -34
  5. package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
  6. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +80 -5
  7. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
  8. package/dist/types/src/components/Toolbar/Toolbar.d.ts +12 -11
  9. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
  10. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts +4 -2
  11. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -1
  12. package/dist/types/src/extensions/automerge/automerge.d.ts +1 -1
  13. package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
  14. package/dist/types/src/extensions/automerge/automerge.stories.d.ts +2 -1
  15. package/dist/types/src/extensions/automerge/automerge.stories.d.ts.map +1 -1
  16. package/dist/types/src/extensions/automerge/cursor.d.ts +1 -1
  17. package/dist/types/src/extensions/automerge/cursor.d.ts.map +1 -1
  18. package/dist/types/src/extensions/automerge/defs.d.ts +1 -15
  19. package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
  20. package/dist/types/src/extensions/automerge/index.d.ts +0 -1
  21. package/dist/types/src/extensions/automerge/index.d.ts.map +1 -1
  22. package/dist/types/src/extensions/automerge/sync.d.ts +2 -1
  23. package/dist/types/src/extensions/automerge/sync.d.ts.map +1 -1
  24. package/dist/types/src/extensions/automerge/update-automerge.d.ts +2 -1
  25. package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -1
  26. package/dist/types/src/{hooks → extensions/awareness}/awareness-provider.d.ts +1 -1
  27. package/dist/types/src/extensions/awareness/awareness-provider.d.ts.map +1 -0
  28. package/dist/types/src/extensions/awareness/awareness.d.ts.map +1 -0
  29. package/dist/types/src/extensions/awareness/index.d.ts +3 -0
  30. package/dist/types/src/extensions/awareness/index.d.ts.map +1 -0
  31. package/dist/types/src/extensions/comments.d.ts +2 -2
  32. package/dist/types/src/extensions/comments.d.ts.map +1 -1
  33. package/dist/types/src/extensions/cursor.d.ts +1 -1
  34. package/dist/types/src/extensions/cursor.d.ts.map +1 -1
  35. package/dist/types/src/extensions/dnd.d.ts +7 -1
  36. package/dist/types/src/extensions/dnd.d.ts.map +1 -1
  37. package/dist/types/src/extensions/doc.d.ts +3 -0
  38. package/dist/types/src/extensions/doc.d.ts.map +1 -0
  39. package/dist/types/src/extensions/factories.d.ts +53 -0
  40. package/dist/types/src/extensions/factories.d.ts.map +1 -0
  41. package/dist/types/src/extensions/index.d.ts +4 -2
  42. package/dist/types/src/extensions/index.d.ts.map +1 -1
  43. package/dist/types/src/extensions/markdown/action.d.ts +9 -0
  44. package/dist/types/src/extensions/markdown/action.d.ts.map +1 -0
  45. package/dist/types/src/extensions/markdown/bundle.d.ts +5 -4
  46. package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
  47. package/dist/types/src/extensions/markdown/decorate.d.ts.map +1 -1
  48. package/dist/types/src/extensions/markdown/formatting.d.ts +8 -5
  49. package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -1
  50. package/dist/types/src/extensions/markdown/image.d.ts +6 -0
  51. package/dist/types/src/extensions/markdown/image.d.ts.map +1 -1
  52. package/dist/types/src/extensions/markdown/index.d.ts +1 -0
  53. package/dist/types/src/extensions/markdown/index.d.ts.map +1 -1
  54. package/dist/types/src/extensions/markdown/table.d.ts +2 -2
  55. package/dist/types/src/extensions/markdown/table.d.ts.map +1 -1
  56. package/dist/types/src/extensions/modes.d.ts +2 -1
  57. package/dist/types/src/extensions/modes.d.ts.map +1 -1
  58. package/dist/types/src/extensions/state.d.ts +20 -0
  59. package/dist/types/src/extensions/state.d.ts.map +1 -0
  60. package/dist/types/src/extensions/types.d.ts +9 -0
  61. package/dist/types/src/extensions/types.d.ts.map +1 -0
  62. package/dist/types/src/hooks/index.d.ts +1 -4
  63. package/dist/types/src/hooks/index.d.ts.map +1 -1
  64. package/dist/types/src/hooks/useActionHandler.d.ts +2 -2
  65. package/dist/types/src/hooks/useActionHandler.d.ts.map +1 -1
  66. package/dist/types/src/hooks/useDocAccessor.d.ts +9 -0
  67. package/dist/types/src/hooks/useDocAccessor.d.ts.map +1 -0
  68. package/dist/types/src/hooks/useTextEditor.d.ts +3 -44
  69. package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
  70. package/dist/types/src/hooks/useTextEditor.stories.d.ts +7 -0
  71. package/dist/types/src/hooks/useTextEditor.stories.d.ts.map +1 -1
  72. package/dist/types/src/themes/default.d.ts +0 -3
  73. package/dist/types/src/themes/default.d.ts.map +1 -1
  74. package/dist/types/src/translations.d.ts +1 -0
  75. package/dist/types/src/translations.d.ts.map +1 -1
  76. package/package.json +26 -27
  77. package/src/components/TextEditor/TextEditor.stories.tsx +532 -23
  78. package/src/components/TextEditor/TextEditor.tsx +45 -156
  79. package/src/components/Toolbar/Toolbar.stories.tsx +54 -55
  80. package/src/components/Toolbar/Toolbar.tsx +102 -60
  81. package/src/extensions/automerge/automerge.stories.tsx +16 -17
  82. package/src/extensions/automerge/automerge.ts +6 -5
  83. package/src/extensions/automerge/cursor.ts +1 -1
  84. package/src/extensions/automerge/defs.ts +1 -22
  85. package/src/extensions/automerge/index.ts +0 -1
  86. package/src/extensions/automerge/sync.ts +2 -9
  87. package/src/extensions/automerge/update-automerge.ts +2 -1
  88. package/src/{hooks → extensions/awareness}/awareness-provider.ts +1 -1
  89. package/src/extensions/{awareness.ts → awareness/awareness.ts} +1 -1
  90. package/src/extensions/awareness/index.ts +6 -0
  91. package/src/extensions/command/state.ts +3 -3
  92. package/src/extensions/comments.ts +9 -5
  93. package/src/extensions/cursor.ts +1 -1
  94. package/src/extensions/dnd.ts +31 -9
  95. package/src/extensions/doc.ts +14 -0
  96. package/src/extensions/factories.ts +193 -0
  97. package/src/extensions/index.ts +4 -2
  98. package/src/extensions/markdown/action.ts +112 -0
  99. package/src/extensions/markdown/bundle.ts +17 -37
  100. package/src/extensions/markdown/decorate.ts +2 -4
  101. package/src/extensions/markdown/formatting.test.ts +13 -13
  102. package/src/extensions/markdown/formatting.ts +110 -97
  103. package/src/extensions/markdown/image.ts +7 -0
  104. package/src/extensions/markdown/index.ts +1 -0
  105. package/src/extensions/markdown/table.ts +11 -3
  106. package/src/extensions/modes.ts +11 -2
  107. package/src/extensions/state.ts +90 -0
  108. package/src/extensions/types.ts +16 -0
  109. package/src/hooks/index.ts +1 -5
  110. package/src/hooks/useActionHandler.ts +4 -85
  111. package/src/hooks/useDocAccessor.ts +27 -0
  112. package/src/hooks/useTextEditor.stories.tsx +40 -35
  113. package/src/hooks/useTextEditor.ts +14 -120
  114. package/src/index.ts +1 -1
  115. package/src/themes/default.ts +25 -36
  116. package/src/translations.ts +1 -0
  117. package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts +0 -103
  118. package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +0 -1
  119. package/dist/types/src/extensions/awareness.d.ts.map +0 -1
  120. package/dist/types/src/extensions/cursor-line-margin.d.ts +0 -8
  121. package/dist/types/src/extensions/cursor-line-margin.d.ts.map +0 -1
  122. package/dist/types/src/extensions/outliner.d.ts +0 -4
  123. package/dist/types/src/extensions/outliner.d.ts.map +0 -1
  124. package/dist/types/src/hooks/awareness-provider.d.ts.map +0 -1
  125. package/dist/types/src/hooks/defs.d.ts +0 -20
  126. package/dist/types/src/hooks/defs.d.ts.map +0 -1
  127. package/dist/types/src/hooks/useEditorView.d.ts +0 -20
  128. package/dist/types/src/hooks/useEditorView.d.ts.map +0 -1
  129. package/dist/types/src/hooks/useTextModel.d.ts +0 -33
  130. package/dist/types/src/hooks/useTextModel.d.ts.map +0 -1
  131. package/src/components/TextEditor/MarkdownEditor.stories.tsx +0 -524
  132. package/src/extensions/cursor-line-margin.ts +0 -95
  133. package/src/extensions/outliner.ts +0 -12
  134. package/src/hooks/defs.ts +0 -30
  135. package/src/hooks/useEditorView.ts +0 -32
  136. package/src/hooks/useTextModel.ts +0 -121
  137. /package/dist/types/src/extensions/{awareness.d.ts → awareness/awareness.d.ts} +0 -0
@@ -15,6 +15,7 @@ var translations_default = [
15
15
  "blockquote label": "Block quote",
16
16
  "codeblock label": "Code block",
17
17
  "comment label": "Create comment",
18
+ "image label": "Insert image",
18
19
  "heading label": "Heading level",
19
20
  "table label": "Create table"
20
21
  }
@@ -23,21 +24,17 @@ var translations_default = [
23
24
  ];
24
25
 
25
26
  // packages/ui/react-ui-editor/src/index.ts
26
- import { keymap as keymap9 } from "@codemirror/view";
27
+ import { keymap as keymap11 } from "@codemirror/view";
27
28
  import { tags as tags2 } from "@lezer/highlight";
28
29
  import { TextKind } from "@dxos/protocols/proto/dxos/echo/model/text";
29
30
  import { Doc, YText, YXmlFragment } from "@dxos/text-model";
30
31
 
31
32
  // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
32
- import { EditorState as EditorState3 } from "@codemirror/state";
33
- import { EditorView as EditorView17, scrollPastEnd as scrollPastEnd2 } from "@codemirror/view";
33
+ import { EditorState as EditorState2 } from "@codemirror/state";
34
+ import { EditorView as EditorView16 } from "@codemirror/view";
34
35
  import { useFocusableGroup } from "@fluentui/react-tabster";
35
- import defaultsDeep3 from "lodash.defaultsdeep";
36
- import React, { forwardRef, useCallback, useEffect as useEffect3, useImperativeHandle, useRef as useRef3, useState as useState5, useMemo as useMemo3 } from "react";
37
- import { DocAccessor } from "@dxos/echo-schema";
38
- import { log as log9 } from "@dxos/log";
39
- import { useThemeContext } from "@dxos/react-ui";
40
- import { focusRing } from "@dxos/react-ui-theme";
36
+ import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useRef, useState as useState2 } from "react";
37
+ import { log as log7 } from "@dxos/log";
41
38
  import { isNotFalsy as isNotFalsy4 } from "@dxos/util";
42
39
 
43
40
  // packages/ui/react-ui-editor/src/extensions/annotations.ts
@@ -60,8 +57,8 @@ var Cursor = class _Cursor {
60
57
  });
61
58
  }
62
59
  static {
63
- this.getCursorFromRange = (state, range) => {
64
- const cursorConverter2 = state.facet(_Cursor.converter);
60
+ this.getCursorFromRange = (state2, range) => {
61
+ const cursorConverter2 = state2.facet(_Cursor.converter);
65
62
  const from = cursorConverter2.toCursor(range.from);
66
63
  const to = cursorConverter2.toCursor(range.to, -1);
67
64
  return [
@@ -71,8 +68,8 @@ var Cursor = class _Cursor {
71
68
  };
72
69
  }
73
70
  static {
74
- this.getRangeFromCursor = (state, cursor) => {
75
- const cursorConverter2 = state.facet(_Cursor.converter);
71
+ this.getRangeFromCursor = (state2, cursor) => {
72
+ const cursorConverter2 = state2.facet(_Cursor.converter);
76
73
  const parts = cursor.split(":");
77
74
  const from = cursorConverter2.fromCursor(parts[0]);
78
75
  const to = cursorConverter2.fromCursor(parts[1]);
@@ -89,15 +86,15 @@ var annotationMark = Decoration.mark({
89
86
  class: "cm-annotation"
90
87
  });
91
88
  var annotations = (options = {}) => {
92
- const match = (state) => {
89
+ const match = (state2) => {
93
90
  const annotations2 = [];
94
- const text = state.doc.toString();
91
+ const text = state2.doc.toString();
95
92
  if (options.match) {
96
93
  const matches = text.matchAll(options.match);
97
94
  for (const match2 of matches) {
98
95
  const from = match2.index;
99
96
  const to = from + match2[0].length;
100
- const cursor = Cursor.getCursorFromRange(state, {
97
+ const cursor = Cursor.getCursorFromRange(state2, {
101
98
  from,
102
99
  to
103
100
  });
@@ -109,8 +106,8 @@ var annotations = (options = {}) => {
109
106
  return annotations2;
110
107
  };
111
108
  const annotationsState = StateField.define({
112
- create: (state) => {
113
- return match(state);
109
+ create: (state2) => {
110
+ return match(state2);
114
111
  },
115
112
  update: (value, tr) => {
116
113
  if (!tr.changes.empty) {
@@ -123,10 +120,10 @@ var annotations = (options = {}) => {
123
120
  annotationsState,
124
121
  EditorView.decorations.compute([
125
122
  annotationsState
126
- ], (state) => {
127
- const annotations2 = state.field(annotationsState);
128
- const decorations = annotations2.map((annotation2) => {
129
- const range = Cursor.getRangeFromCursor(state, annotation2.cursor);
123
+ ], (state2) => {
124
+ const annotations2 = state2.field(annotationsState);
125
+ const decorations = annotations2.map((annotation) => {
126
+ const range = Cursor.getRangeFromCursor(state2, annotation.cursor);
130
127
  return range && annotationMark.range(range.from, range.to);
131
128
  }).filter(isNotFalsy);
132
129
  return Decoration.set(decorations);
@@ -243,9 +240,8 @@ var cursorConverter = ({ handle, path }) => ({
243
240
 
244
241
  // packages/ui/react-ui-editor/src/extensions/automerge/defs.ts
245
242
  import { Annotation, StateEffect } from "@codemirror/state";
246
- import get2 from "lodash.get";
247
- var getPath = (state, field) => state.field(field).path;
248
- var getLastHeads = (state, field) => state.field(field).lastHeads;
243
+ var getPath = (state2, field) => state2.field(field).path;
244
+ var getLastHeads = (state2, field) => state2.field(field).lastHeads;
249
245
  var updateHeadsEffect = StateEffect.define({});
250
246
  var updateHeads = (newHeads) => updateHeadsEffect.of({
251
247
  newHeads
@@ -260,8 +256,8 @@ import { next as A3 } from "@dxos/automerge/automerge";
260
256
 
261
257
  // packages/ui/react-ui-editor/src/extensions/automerge/update-automerge.ts
262
258
  import { next as A2 } from "@dxos/automerge/automerge";
263
- var updateAutomerge = (field, handle, transactions, state) => {
264
- const { lastHeads, path } = state.field(field);
259
+ var updateAutomerge = (field, handle, transactions, state2) => {
260
+ const { lastHeads, path } = state2.field(field);
265
261
  let hasChanges = false;
266
262
  for (const tr of transactions) {
267
263
  tr.changes.iterChanges(() => {
@@ -308,7 +304,7 @@ var updateCodeMirror = (view, selection, target, patches) => {
308
304
  annotations: reconcileAnnotation.of(false)
309
305
  });
310
306
  };
311
- var handlePatch = (patch, target, state) => {
307
+ var handlePatch = (patch, target, state2) => {
312
308
  if (patch.action === "insert") {
313
309
  return handleInsert(target, patch);
314
310
  } else if (patch.action === "splice") {
@@ -316,7 +312,7 @@ var handlePatch = (patch, target, state) => {
316
312
  } else if (patch.action === "del") {
317
313
  return handleDel(target, patch);
318
314
  } else if (patch.action === "put") {
319
- return handlePut(target, patch, state);
315
+ return handlePut(target, patch, state2);
320
316
  } else {
321
317
  return null;
322
318
  }
@@ -360,7 +356,7 @@ var handleDel = (target, patch) => {
360
356
  }
361
357
  ];
362
358
  };
363
- var handlePut = (target, patch, state) => {
359
+ var handlePut = (target, patch, state2) => {
364
360
  const index = charPath(target, [
365
361
  ...patch.path,
366
362
  0
@@ -368,7 +364,7 @@ var handlePut = (target, patch, state) => {
368
364
  if (index == null) {
369
365
  return [];
370
366
  }
371
- const length = state.doc.length;
367
+ const length = state2.doc.length;
372
368
  if (typeof patch.value !== "string") {
373
369
  return [];
374
370
  }
@@ -479,13 +475,13 @@ var automerge = (accessor) => {
479
475
  ViewPlugin.fromClass(class {
480
476
  constructor(_view) {
481
477
  this._view = _view;
482
- accessor.handle.addListener("change", this._handleChange.bind(this));
478
+ this._handleChange = () => {
479
+ syncer.reconcile(this._view, false);
480
+ };
481
+ accessor.handle.addListener("change", this._handleChange);
483
482
  }
484
483
  destroy() {
485
- accessor.handle.removeListener("change", this._handleChange.bind(this));
486
- }
487
- _handleChange() {
488
- syncer.reconcile(this._view, false);
484
+ accessor.handle.removeListener("change", this._handleChange);
489
485
  }
490
486
  }),
491
487
  // Reconcile local updates.
@@ -497,7 +493,7 @@ var automerge = (accessor) => {
497
493
  ];
498
494
  };
499
495
 
500
- // packages/ui/react-ui-editor/src/extensions/awareness.ts
496
+ // packages/ui/react-ui-editor/src/extensions/awareness/awareness.ts
501
497
  import { Annotation as Annotation2, Facet as Facet2, RangeSet } from "@codemirror/state";
502
498
  import { Decoration as Decoration2, EditorView as EditorView3, ViewPlugin as ViewPlugin2, WidgetType } from "@codemirror/view";
503
499
  import { Event } from "@dxos/async";
@@ -566,9 +562,9 @@ var RemoteSelectionsDecorator = class {
566
562
  _updateRemoteSelections(update2) {
567
563
  const decorations = [];
568
564
  const awarenessStates = this._provider.getRemoteStates();
569
- for (const state of awarenessStates) {
570
- const anchor = state.position?.anchor ? this._cursorConverter.fromCursor(state.position.anchor) : null;
571
- const head = state.position?.head ? this._cursorConverter.fromCursor(state.position.head) : null;
565
+ for (const state2 of awarenessStates) {
566
+ const anchor = state2.position?.anchor ? this._cursorConverter.fromCursor(state2.position.anchor) : null;
567
+ const head = state2.position?.head ? this._cursorConverter.fromCursor(state2.position.head) : null;
572
568
  if (anchor == null || head == null) {
573
569
  continue;
574
570
  }
@@ -576,8 +572,8 @@ var RemoteSelectionsDecorator = class {
576
572
  const end = Math.min(Math.max(anchor, head), update2.view.state.doc.length);
577
573
  const startLine = update2.view.state.doc.lineAt(start);
578
574
  const endLine = update2.view.state.doc.lineAt(end);
579
- const color = state.info.color ?? "#30bced";
580
- const lightColor = state.info.lightColor ?? color + "33";
575
+ const color = state2.info.color ?? "#30bced";
576
+ const lightColor = state2.info.lightColor ?? color + "33";
581
577
  if (startLine.number === endLine.number) {
582
578
  decorations.push({
583
579
  from: start,
@@ -630,7 +626,7 @@ var RemoteSelectionsDecorator = class {
630
626
  value: Decoration2.widget({
631
627
  side: head - anchor > 0 ? -1 : 1,
632
628
  block: false,
633
- widget: new RemoteCaretWidget(state.info.displayName ?? "Anonymous", color)
629
+ widget: new RemoteCaretWidget(state2.info.displayName ?? "Anonymous", color)
634
630
  })
635
631
  });
636
632
  }
@@ -732,11 +728,115 @@ var styles2 = EditorView3.baseTheme({
732
728
  }
733
729
  });
734
730
 
731
+ // packages/ui/react-ui-editor/src/extensions/awareness/awareness-provider.ts
732
+ import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
733
+ import { Context as Context2 } from "@dxos/context";
734
+ import { invariant } from "@dxos/invariant";
735
+ import { log as log2 } from "@dxos/log";
736
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/awareness/awareness-provider.ts";
737
+ var DEBOUNCE_INTERVAL = 100;
738
+ var SpaceAwarenessProvider = class {
739
+ constructor(params) {
740
+ this._remoteStates = /* @__PURE__ */ new Map();
741
+ this.remoteStateChange = new Event2();
742
+ this._space = params.space;
743
+ this._channel = params.channel;
744
+ this._peerId = params.peerId;
745
+ this._info = params.info;
746
+ }
747
+ open() {
748
+ this._ctx = new Context2();
749
+ this._postTask = new DeferredTask(this._ctx, async () => {
750
+ if (this._localState) {
751
+ await this._space.postMessage(this._channel, {
752
+ kind: "post",
753
+ state: this._localState
754
+ });
755
+ await sleep(DEBOUNCE_INTERVAL);
756
+ }
757
+ });
758
+ this._ctx.onDispose(this._space.listen(this._channel, (message) => {
759
+ switch (message.payload.kind) {
760
+ case "query": {
761
+ this._handleQueryMessage();
762
+ break;
763
+ }
764
+ case "post": {
765
+ this._handlePostMessage(message.payload);
766
+ break;
767
+ }
768
+ }
769
+ }));
770
+ void this._space.postMessage(this._channel, {
771
+ kind: "query"
772
+ }).catch((err) => {
773
+ log2.debug("failed to query awareness", {
774
+ err
775
+ }, {
776
+ F: __dxlog_file2,
777
+ L: 89,
778
+ S: this,
779
+ C: (f, a) => f(...a)
780
+ });
781
+ });
782
+ }
783
+ close() {
784
+ void this._ctx?.dispose();
785
+ this._ctx = void 0;
786
+ this._postTask = void 0;
787
+ }
788
+ getRemoteStates() {
789
+ return Array.from(this._remoteStates.values());
790
+ }
791
+ update(position) {
792
+ invariant(this._postTask, void 0, {
793
+ F: __dxlog_file2,
794
+ L: 104,
795
+ S: this,
796
+ A: [
797
+ "this._postTask",
798
+ ""
799
+ ]
800
+ });
801
+ this._localState = {
802
+ peerId: this._peerId,
803
+ position,
804
+ info: this._info
805
+ };
806
+ this._postTask.schedule();
807
+ }
808
+ _handleQueryMessage() {
809
+ invariant(this._postTask, void 0, {
810
+ F: __dxlog_file2,
811
+ L: 115,
812
+ S: this,
813
+ A: [
814
+ "this._postTask",
815
+ ""
816
+ ]
817
+ });
818
+ this._postTask.schedule();
819
+ }
820
+ _handlePostMessage(message) {
821
+ invariant(message.kind === "post", void 0, {
822
+ F: __dxlog_file2,
823
+ L: 120,
824
+ S: this,
825
+ A: [
826
+ "message.kind === 'post'",
827
+ ""
828
+ ]
829
+ });
830
+ this._remoteStates.set(message.state.peerId, message.state);
831
+ this.remoteStateChange.emit();
832
+ }
833
+ };
834
+
735
835
  // packages/ui/react-ui-editor/src/extensions/blast.ts
736
836
  import { EditorView as EditorView4, keymap as keymap2 } from "@codemirror/view";
737
837
  import defaultsDeep from "lodash.defaultsdeep";
738
- import { invariant } from "@dxos/invariant";
739
- var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
838
+ import { invariant as invariant2 } from "@dxos/invariant";
839
+ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
740
840
  var defaultOptions = {
741
841
  effect: 2,
742
842
  maxParticles: 200,
@@ -862,8 +962,8 @@ var Blaster = class {
862
962
  return this._node;
863
963
  }
864
964
  initialize() {
865
- invariant(!this._canvas && !this._ctx, void 0, {
866
- F: __dxlog_file2,
965
+ invariant2(!this._canvas && !this._ctx, void 0, {
966
+ F: __dxlog_file3,
867
967
  L: 141,
868
968
  S: this,
869
969
  A: [
@@ -899,8 +999,8 @@ var Blaster = class {
899
999
  }
900
1000
  }
901
1001
  start() {
902
- invariant(this._canvas && this._ctx, void 0, {
903
- F: __dxlog_file2,
1002
+ invariant2(this._canvas && this._ctx, void 0, {
1003
+ F: __dxlog_file3,
904
1004
  L: 180,
905
1005
  S: this,
906
1006
  A: [
@@ -1057,7 +1157,7 @@ var commandConfig = Facet3.define({
1057
1157
  });
1058
1158
  var commandState = StateField3.define({
1059
1159
  create: () => ({}),
1060
- update: (state, tr) => {
1160
+ update: (state2, tr) => {
1061
1161
  for (const effect of tr.effects) {
1062
1162
  if (effect.is(closeEffect)) {
1063
1163
  return {};
@@ -1096,7 +1196,7 @@ var commandState = StateField3.define({
1096
1196
  }
1097
1197
  });
1098
1198
  }
1099
- setTimeout(() => view2.focus());
1199
+ requestAnimationFrame(() => view2.focus());
1100
1200
  });
1101
1201
  }
1102
1202
  };
@@ -1108,10 +1208,10 @@ var commandState = StateField3.define({
1108
1208
  };
1109
1209
  }
1110
1210
  }
1111
- return state;
1211
+ return state2;
1112
1212
  },
1113
- provide: (f) => [
1114
- showTooltip.from(f, (value) => value.tooltip ?? null)
1213
+ provide: (field) => [
1214
+ showTooltip.from(field, (value) => value.tooltip ?? null)
1115
1215
  ]
1116
1216
  });
1117
1217
  var openEffect = StateEffect2.define();
@@ -1266,7 +1366,7 @@ import { hoverTooltip, keymap as keymap4, Decoration as Decoration4, EditorView
1266
1366
  import sortBy from "lodash.sortby";
1267
1367
  import { useEffect } from "react";
1268
1368
  import { debounce } from "@dxos/async";
1269
- import { log as log3 } from "@dxos/log";
1369
+ import { log as log4 } from "@dxos/log";
1270
1370
  import { nonNullable } from "@dxos/util";
1271
1371
 
1272
1372
  // packages/ui/react-ui-editor/src/styles/markdown.ts
@@ -1293,10 +1393,10 @@ var inlineUrl = mx(code, "px-1");
1293
1393
  var blockquote = mx("pl-1 mr-1 border-is-4 border-primary-500/70 dark:border-primary-500/30", light);
1294
1394
 
1295
1395
  // packages/ui/react-ui-editor/src/styles/tokens.ts
1296
- import get3 from "lodash.get";
1396
+ import get2 from "lodash.get";
1297
1397
  import { tailwindConfig } from "@dxos/react-ui-theme";
1298
1398
  var tokens = tailwindConfig({}).theme;
1299
- var getToken = (path, defaultValue = void 0) => get3(tokens, path, defaultValue);
1399
+ var getToken = (path, defaultValue = void 0) => get2(tokens, path, defaultValue);
1300
1400
 
1301
1401
  // packages/ui/react-ui-editor/src/styles/layout.ts
1302
1402
  var editorWithToolbarLayout = "grid grid-cols-1 grid-rows-[min-content_1fr] data-[toolbar=disabled]:grid-rows-[1fr] justify-center content-start overflow-hidden";
@@ -1304,14 +1404,14 @@ var editorFillLayoutRoot = "bs-full relative";
1304
1404
  var editorFillLayoutEditor = "!absolute inset-0";
1305
1405
 
1306
1406
  // packages/ui/react-ui-editor/src/util.ts
1307
- import { log as log2 } from "@dxos/log";
1308
- var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util.ts";
1407
+ import { log as log3 } from "@dxos/log";
1408
+ var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util.ts";
1309
1409
  var callbackWrapper = (fn) => (...args) => {
1310
1410
  try {
1311
1411
  return fn(...args);
1312
1412
  } catch (err) {
1313
- log2.catch(err, void 0, {
1314
- F: __dxlog_file3,
1413
+ log3.catch(err, void 0, {
1414
+ F: __dxlog_file4,
1315
1415
  L: 18,
1316
1416
  S: void 0,
1317
1417
  C: (f, a) => f(...a)
@@ -1334,10 +1434,10 @@ var logChanges = (trs) => {
1334
1434
  return changes2;
1335
1435
  }).filter(Boolean);
1336
1436
  if (changes.length) {
1337
- log2.info("changes", {
1437
+ log3.info("changes", {
1338
1438
  changes
1339
1439
  }, {
1340
- F: __dxlog_file3,
1440
+ F: __dxlog_file4,
1341
1441
  L: 39,
1342
1442
  S: void 0,
1343
1443
  C: (f, a) => f(...a)
@@ -1346,7 +1446,7 @@ var logChanges = (trs) => {
1346
1446
  };
1347
1447
 
1348
1448
  // packages/ui/react-ui-editor/src/extensions/comments.ts
1349
- var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/comments.ts";
1449
+ var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/comments.ts";
1350
1450
  var documentId = Facet4.define({
1351
1451
  combine: (values) => values[0]
1352
1452
  });
@@ -1354,8 +1454,8 @@ var setComments = StateEffect3.define();
1354
1454
  var setSelection = StateEffect3.define();
1355
1455
  var setCommentState = StateEffect3.define();
1356
1456
  var commentsState = StateField4.define({
1357
- create: (state) => ({
1358
- id: state.facet(documentId),
1457
+ create: (state2) => ({
1458
+ id: state2.facet(documentId),
1359
1459
  comments: [],
1360
1460
  selection: {}
1361
1461
  }),
@@ -1427,13 +1527,13 @@ var commentCurrentMark = Decoration4.mark({
1427
1527
  });
1428
1528
  var commentsDecorations = EditorView7.decorations.compute([
1429
1529
  commentsState
1430
- ], (state) => {
1431
- const { selection: { current }, comments: comments2 } = state.field(commentsState);
1530
+ ], (state2) => {
1531
+ const { selection: { current }, comments: comments2 } = state2.field(commentsState);
1432
1532
  const decorations = sortBy(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
1433
1533
  const range = comment.range;
1434
1534
  if (!range || range.from === range.to) {
1435
- log3.warn("Invalid range:", range, {
1436
- F: __dxlog_file4,
1535
+ log4.warn("Invalid range:", range, {
1536
+ F: __dxlog_file5,
1437
1537
  L: 132,
1438
1538
  S: void 0,
1439
1539
  C: (f, a) => f(...a)
@@ -1592,7 +1692,7 @@ var optionsFacet = Facet4.define({
1592
1692
  });
1593
1693
  var comments = (options = {}) => {
1594
1694
  const { key: shortcut = "meta-'" } = options;
1595
- const handleSelect = debounce((state) => options.onSelect?.(state), 200);
1695
+ const handleSelect = debounce((state2) => options.onSelect?.(state2), 200);
1596
1696
  return [
1597
1697
  optionsFacet.of(options),
1598
1698
  documentId.of(options.id),
@@ -1641,9 +1741,9 @@ var comments = (options = {}) => {
1641
1741
  //
1642
1742
  // Track deleted ranges and update ranges for decorations.
1643
1743
  //
1644
- EditorView7.updateListener.of(({ view, state, changes }) => {
1744
+ EditorView7.updateListener.of(({ view, state: state2, changes }) => {
1645
1745
  let mod = false;
1646
- const { comments: comments2, ...value } = state.field(commentsState);
1746
+ const { comments: comments2, ...value } = state2.field(commentsState);
1647
1747
  changes.iterChanges((from, to, from2, to2) => {
1648
1748
  comments2.forEach(({ comment, range }) => {
1649
1749
  if (from2 === to2) {
@@ -1673,10 +1773,10 @@ var comments = (options = {}) => {
1673
1773
  //
1674
1774
  // Track selection/proximity.
1675
1775
  //
1676
- EditorView7.updateListener.of(({ view, state }) => {
1776
+ EditorView7.updateListener.of(({ view, state: state2 }) => {
1677
1777
  let min = Infinity;
1678
- const { selection: { current, closest }, comments: comments2 } = state.field(commentsState);
1679
- const { head } = state.selection.main;
1778
+ const { selection: { current, closest }, comments: comments2 } = state2.field(commentsState);
1779
+ const { head } = state2.selection.main;
1680
1780
  const selection = {};
1681
1781
  comments2.forEach(({ comment, range }) => {
1682
1782
  if (head >= range.from && head <= range.to) {
@@ -1697,7 +1797,7 @@ var comments = (options = {}) => {
1697
1797
  });
1698
1798
  handleSelect({
1699
1799
  selection,
1700
- id: state.facet(documentId),
1800
+ id: state2.facet(documentId),
1701
1801
  comments: comments2.map(({ comment, range }) => ({
1702
1802
  comment,
1703
1803
  range,
@@ -1732,15 +1832,17 @@ var focusComment = (view, id, center = true) => {
1732
1832
  });
1733
1833
  }
1734
1834
  };
1735
- var useComments = (view, id, comments2 = []) => {
1835
+ var useComments = (view, id, comments2) => {
1736
1836
  useEffect(() => {
1737
1837
  if (view) {
1738
- view.dispatch({
1739
- effects: setComments.of({
1740
- id,
1741
- comments: comments2
1742
- })
1743
- });
1838
+ if (id === view.state.facet(documentId)) {
1839
+ view.dispatch({
1840
+ effects: setComments.of({
1841
+ id,
1842
+ comments: comments2 ?? []
1843
+ })
1844
+ });
1845
+ }
1744
1846
  }
1745
1847
  }, [
1746
1848
  id,
@@ -1749,623 +1851,442 @@ var useComments = (view, id, comments2 = []) => {
1749
1851
  ]);
1750
1852
  };
1751
1853
 
1752
- // packages/ui/react-ui-editor/src/extensions/cursor-line-margin.ts
1753
- import { Facet as Facet5, Transaction } from "@codemirror/state";
1754
- import { EditorView as EditorView8 } from "@codemirror/view";
1755
- import { log as log4 } from "@dxos/log";
1756
- var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/cursor-line-margin.ts";
1757
- var cursorLineMarginFacet = Facet5.define({
1758
- combine: (input) => input[0] ?? 3
1759
- });
1760
- var annotation = "cursorLineMargin";
1761
- var lineAtPos = (s, pos) => s.doc.lineAt(pos).number;
1762
- var cursorLineMargin = EditorView8.updateListener.of(({ transactions, state, selectionSet, startState, view }) => {
1763
- if (transactions.length < 1 || transactions.some((tr) => tr.isUserEvent(annotation))) {
1764
- return;
1765
- }
1766
- const s = state;
1767
- const { main } = s.selection;
1768
- const cursorLineMargin2 = s.facet(cursorLineMarginFacet);
1769
- const rect = view.dom.getBoundingClientRect();
1770
- const viewportTop = rect.top - view.documentTop;
1771
- const viewportBottom = rect.bottom - view.documentTop;
1772
- const mainLine = lineAtPos(s, main.head);
1773
- const _visTopLine = lineAtPos(s, view.lineBlockAtHeight(viewportTop).from);
1774
- const botLineBlk = view.lineBlockAtHeight(viewportBottom);
1775
- const visBotLineDoc = lineAtPos(s, Math.min(botLineBlk.to, s.doc.length));
1776
- const visBotLine = botLineBlk.bottom >= viewportBottom ? visBotLineDoc : visBotLineDoc + Math.floor((viewportBottom - botLineBlk.bottom) / view.defaultLineHeight);
1777
- const needsScrollTop = false;
1778
- const needsScrollBot = mainLine >= visBotLine - cursorLineMargin2;
1779
- if (needsScrollTop && needsScrollBot) {
1780
- log4.warn("is cursorScrollMargin too large for the editor size?", void 0, {
1781
- F: __dxlog_file5,
1782
- L: 66,
1854
+ // packages/ui/react-ui-editor/src/extensions/doc.ts
1855
+ import { Facet as Facet5 } from "@codemirror/state";
1856
+ import { invariant as invariant3 } from "@dxos/invariant";
1857
+ var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/doc.ts";
1858
+ var documentId2 = Facet5.define({
1859
+ combine: (providers) => {
1860
+ invariant3(providers.length <= 1, void 0, {
1861
+ F: __dxlog_file6,
1862
+ L: 11,
1783
1863
  S: void 0,
1784
- C: (f, a) => f(...a)
1864
+ A: [
1865
+ "providers.length <= 1",
1866
+ ""
1867
+ ]
1785
1868
  });
1786
- return;
1787
- }
1788
- if (!needsScrollTop && !needsScrollBot) {
1789
- return;
1790
- }
1791
- if (selectionSet) {
1792
- const { head } = startState.selection.main;
1793
- const oldMainLine = lineAtPos(startState, head);
1794
- if (needsScrollTop && oldMainLine < mainLine) {
1795
- return;
1796
- }
1797
- if (needsScrollBot && oldMainLine > mainLine) {
1798
- return;
1799
- }
1869
+ return providers[0];
1800
1870
  }
1801
- view.dispatch({
1802
- annotations: Transaction.userEvent.of(annotation),
1803
- effects: EditorView8.scrollIntoView(s.selection.main.head, {
1804
- y: needsScrollTop ? "start" : "end",
1805
- yMargin: view.defaultLineHeight * cursorLineMargin2
1806
- })
1807
- });
1808
1871
  });
1809
1872
 
1810
1873
  // packages/ui/react-ui-editor/src/extensions/dnd.ts
1811
- import { EditorView as EditorView9 } from "@codemirror/view";
1812
- import { log as log5 } from "@dxos/log";
1813
- var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/dnd.ts";
1814
- var dnd = () => {
1815
- return EditorView9.domEventHandlers({
1816
- drop: (event, view) => {
1817
- log5.info("domEventHandlersDrop", {
1818
- event
1819
- }, {
1820
- F: __dxlog_file6,
1821
- L: 14,
1822
- S: void 0,
1823
- C: (f, a) => f(...a)
1824
- });
1825
- }
1826
- });
1827
- };
1828
-
1829
- // packages/ui/react-ui-editor/src/extensions/listener.ts
1830
- import { EditorView as EditorView10 } from "@codemirror/view";
1831
- var listener = ({ onFocus, onChange }) => {
1832
- const extensions = [];
1833
- onFocus && extensions.push(EditorView10.focusChangeEffect.of((_, focusing) => {
1834
- onFocus(focusing);
1835
- return null;
1836
- }));
1837
- onChange && extensions.push(EditorView10.updateListener.of((update2) => {
1838
- onChange(update2.state.doc.toString());
1839
- }));
1840
- return extensions;
1874
+ import { dropCursor, EditorView as EditorView8 } from "@codemirror/view";
1875
+ var styles4 = EditorView8.baseTheme({
1876
+ ".cm-dropCursor": {
1877
+ borderLeft: `2px solid ${getToken("extend.colors.primary.500")}`,
1878
+ color: getToken("extend.colors.primary.500"),
1879
+ padding: "0 4px"
1880
+ },
1881
+ ".cm-dropCursor:after": {
1882
+ content: '"\u2190"'
1883
+ }
1884
+ });
1885
+ var dropFile = (options = {}) => {
1886
+ return [
1887
+ styles4,
1888
+ dropCursor(),
1889
+ EditorView8.domEventHandlers({
1890
+ drop: (event, view) => {
1891
+ event.preventDefault();
1892
+ const files = event.dataTransfer?.files;
1893
+ const pos = view.posAtCoords(event);
1894
+ if (files?.length && pos !== null) {
1895
+ view.dispatch({
1896
+ selection: {
1897
+ anchor: pos
1898
+ }
1899
+ });
1900
+ options.onDrop?.(view, {
1901
+ files
1902
+ });
1903
+ }
1904
+ }
1905
+ })
1906
+ ];
1841
1907
  };
1842
1908
 
1843
- // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
1909
+ // packages/ui/react-ui-editor/src/extensions/factories.ts
1844
1910
  import { closeBrackets, closeBracketsKeymap } from "@codemirror/autocomplete";
1845
- import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
1846
- import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
1847
- import { bracketMatching, defaultHighlightStyle, indentOnInput, syntaxHighlighting } from "@codemirror/language";
1848
- import { languages } from "@codemirror/language-data";
1911
+ import { defaultKeymap, history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
1912
+ import { bracketMatching } from "@codemirror/language";
1849
1913
  import { searchKeymap } from "@codemirror/search";
1850
1914
  import { EditorState } from "@codemirror/state";
1851
- import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
1852
- import { EditorView as EditorView11, drawSelection, dropCursor, keymap as keymap5, placeholder } from "@codemirror/view";
1853
- import { isNotFalsy as isNotFalsy2 } from "@dxos/util";
1915
+ import { EditorView as EditorView9, drawSelection, dropCursor as dropCursor2, highlightActiveLine, keymap as keymap5, lineNumbers, placeholder, scrollPastEnd } from "@codemirror/view";
1916
+ import defaultsDeep2 from "lodash.defaultsdeep";
1917
+ import { generateName } from "@dxos/display-name";
1918
+ import { log as log5 } from "@dxos/log";
1919
+ import { hueTokens } from "@dxos/react-ui-theme";
1920
+ import { hexToHue, isNotFalsy as isNotFalsy2 } from "@dxos/util";
1854
1921
 
1855
- // packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
1856
- import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
1857
- import { HighlightStyle } from "@codemirror/language";
1858
- import { tags, styleTags, Tag } from "@lezer/highlight";
1859
- import { Table } from "@lezer/markdown";
1860
- var markdownTags = {
1861
- Blockquote: Tag.define(),
1862
- CodeMark: Tag.define(),
1863
- CodeText: Tag.define(),
1864
- EmphasisMark: Tag.define(),
1865
- HeaderMark: Tag.define(),
1866
- InlineCode: Tag.define(),
1867
- LinkLabel: Tag.define(),
1868
- LinkReference: Tag.define(),
1869
- ListMark: Tag.define(),
1870
- QuoteMark: Tag.define(),
1871
- URL: Tag.define(),
1872
- // Custom.
1873
- TableCell: Tag.define()
1874
- };
1875
- Table.defineNodes?.forEach((node) => {
1876
- switch (node?.name) {
1877
- case "TableCell": {
1878
- node.style = markdownTags.TableCell;
1879
- break;
1880
- }
1881
- }
1882
- });
1883
- var markdownTagsExtensions = [
1884
- Table,
1885
- {
1886
- props: [
1887
- styleTags(markdownTags)
1888
- ]
1889
- }
1890
- ];
1891
- var markdownHighlightStyle = (readonly) => {
1892
- return HighlightStyle.define([
1893
- {
1894
- tag: [
1895
- tags.keyword,
1896
- tags.name,
1897
- tags.deleted,
1898
- tags.character,
1899
- tags.propertyName,
1900
- tags.macroName,
1901
- tags.color,
1902
- tags.constant(tags.name),
1903
- tags.standard(tags.name),
1904
- tags.definition(tags.name),
1905
- tags.separator,
1906
- tags.typeName,
1907
- tags.className,
1908
- tags.number,
1909
- tags.changed,
1910
- tags.annotation,
1911
- tags.modifier,
1912
- tags.self,
1913
- tags.namespace,
1914
- tags.operator,
1915
- tags.operatorKeyword,
1916
- tags.escape,
1917
- tags.regexp,
1918
- tags.special(tags.string),
1919
- tags.meta,
1920
- tags.comment,
1921
- tags.atom,
1922
- tags.bool,
1923
- tags.special(tags.variableName),
1924
- tags.processingInstruction,
1925
- tags.string,
1926
- tags.inserted,
1927
- tags.invalid
1928
- ],
1929
- color: "inherit !important"
1930
- },
1931
- // Markdown marks.
1932
- {
1933
- tag: [
1934
- tags.meta,
1935
- tags.processingInstruction,
1936
- markdownTags.LinkLabel,
1937
- markdownTags.LinkReference,
1938
- markdownTags.ListMark
1939
- ],
1940
- class: mark
1941
- },
1942
- // Markdown marks.
1943
- {
1944
- tag: [
1945
- markdownTags.CodeMark,
1946
- markdownTags.HeaderMark,
1947
- markdownTags.QuoteMark,
1948
- markdownTags.EmphasisMark
1949
- ],
1950
- class: mark
1951
- },
1952
- // E.g., code block language (after ```).
1953
- {
1954
- tag: [
1955
- tags.function(tags.variableName),
1956
- tags.labelName
1957
- ],
1958
- class: codeMark
1959
- },
1960
- {
1961
- tag: [
1962
- tags.monospace
1963
- ],
1964
- class: "font-mono"
1965
- },
1966
- // Headings.
1967
- {
1968
- tag: tags.heading1,
1969
- class: heading(1)
1970
- },
1971
- {
1972
- tag: tags.heading2,
1973
- class: heading(2)
1974
- },
1975
- {
1976
- tag: tags.heading3,
1977
- class: heading(3)
1978
- },
1979
- {
1980
- tag: tags.heading4,
1981
- class: heading(4)
1982
- },
1983
- {
1984
- tag: tags.heading5,
1985
- class: heading(5)
1986
- },
1987
- {
1988
- tag: tags.heading6,
1989
- class: heading(6)
1990
- },
1991
- // Emphasis.
1992
- {
1993
- tag: tags.emphasis,
1994
- class: italic
1995
- },
1996
- {
1997
- tag: tags.strong,
1998
- class: bold
1999
- },
2000
- {
2001
- tag: tags.strikethrough,
2002
- class: strikethrough
2003
- },
2004
- // Naked URLs.
2005
- {
2006
- tag: [
2007
- markdownTags.URL
2008
- ],
2009
- class: inlineUrl
2010
- },
2011
- // NOTE: The `markdown` extension configures extensions for `lezer` to parse markdown tokens (incl. below).
2012
- // However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
2013
- // when a language is specified. In this case, the syntax highlighting extensions will colorize
2014
- // the code, but all other CSS properties will be inherited.
2015
- // IMPORTANT: Therefore, the fenced code block will use the base editor font unless changed by an extension.
2016
- {
2017
- tag: [
2018
- markdownTags.CodeText,
2019
- markdownTags.InlineCode
2020
- ],
2021
- class: code
2022
- },
2023
- {
2024
- tag: [
2025
- markdownTags.QuoteMark
2026
- ],
2027
- class: blockquote
2028
- },
2029
- {
2030
- tag: [
2031
- markdownTags.TableCell
2032
- ],
2033
- class: "font-mono"
2034
- }
2035
- ], {
2036
- scope: markdownLanguage2,
2037
- all: {
2038
- fontFamily: getToken("fontFamily.body", []).join(",")
2039
- }
2040
- });
2041
- };
2042
-
2043
- // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
2044
- var createMarkdownExtensions = ({ themeMode, placeholder: _placeholder, lineWrapping = true } = {}) => {
2045
- return [
2046
- // TODO(burdon): Reconcile with createBasicExtensions.
2047
- lineWrapping && EditorView11.lineWrapping,
2048
- EditorState.allowMultipleSelections.of(true),
2049
- EditorState.tabSize.of(2),
2050
- bracketMatching(),
2051
- closeBrackets(),
2052
- dropCursor(),
2053
- drawSelection(),
2054
- history(),
2055
- indentOnInput(),
2056
- _placeholder && placeholder(_placeholder),
2057
- // Main extension.
2058
- // https://github.com/codemirror/lang-markdown
2059
- // https://codemirror.net/5/mode/markdown/index.html (demo).
2060
- markdown({
2061
- // GRM by default (vs strict CommonMark):
2062
- // Table, TaskList, Strikethrough, and Autolink.
2063
- // NOTE: This extends the parser; it doesn't affect rendering.
2064
- // https://github.github.com/gfm
2065
- // https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
2066
- base: markdownLanguage3,
2067
- // Languages for syntax highlighting fenced code blocks.
2068
- codeLanguages: languages,
2069
- // Parser extensions.
2070
- extensions: [
2071
- // GFM provided by default.
2072
- markdownTagsExtensions
2073
- ]
2074
- }),
2075
- // https://github.com/codemirror/theme-one-dark
2076
- themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle),
2077
- // Custom styles.
2078
- syntaxHighlighting(markdownHighlightStyle()),
2079
- keymap5.of([
2080
- // https://codemirror.net/docs/ref/#commands.indentWithTab
2081
- indentWithTab,
2082
- // https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
2083
- ...closeBracketsKeymap,
2084
- // https://codemirror.net/docs/ref/#commands.historyKeymap
2085
- ...historyKeymap,
2086
- // https://codemirror.net/docs/ref/#search.searchKeymap
2087
- ...searchKeymap,
2088
- // https://codemirror.net/docs/ref/#commands.standardKeymap
2089
- ...standardKeymap
2090
- ])
2091
- ].filter(isNotFalsy2);
2092
- };
2093
-
2094
- // packages/ui/react-ui-editor/src/extensions/markdown/decorate.ts
2095
- import { syntaxTree } from "@codemirror/language";
2096
- import { RangeSetBuilder as RangeSetBuilder2, StateEffect as StateEffect4 } from "@codemirror/state";
2097
- import { EditorView as EditorView12, Decoration as Decoration5, WidgetType as WidgetType3, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
2098
- import { mx as mx2 } from "@dxos/react-ui-theme";
2099
- var HorizontalRuleWidget = class extends WidgetType3 {
2100
- toDOM() {
2101
- const el = document.createElement("span");
2102
- el.className = "cm-hr";
2103
- return el;
2104
- }
2105
- };
2106
- var LinkButton = class extends WidgetType3 {
2107
- constructor(url, render) {
2108
- super();
2109
- this.url = url;
2110
- this.render = render;
2111
- }
2112
- eq(other) {
2113
- return this.url === other.url;
2114
- }
2115
- toDOM(view) {
2116
- const el = document.createElement("span");
2117
- this.render(el, this.url);
2118
- return el;
2119
- }
2120
- };
2121
- var CheckboxWidget = class extends WidgetType3 {
2122
- constructor(_checked) {
2123
- super();
2124
- this._checked = _checked;
2125
- }
2126
- eq(other) {
2127
- return this._checked === other._checked;
2128
- }
2129
- toDOM(view) {
2130
- const input = document.createElement("input");
2131
- input.className = "cm-task-checkbox";
2132
- input.type = "checkbox";
2133
- input.checked = this._checked;
2134
- if (view.state.readOnly) {
2135
- input.setAttribute("disabled", "true");
2136
- } else {
2137
- input.onmousedown = (event) => {
2138
- const pos = view.posAtDOM(input);
2139
- const text = view.state.sliceDoc(pos, pos + 3);
2140
- if (text === (this._checked ? "[x]" : "[ ]")) {
2141
- view.dispatch({
2142
- changes: {
2143
- from: pos + 1,
2144
- to: pos + 2,
2145
- insert: this._checked ? " " : "x"
2146
- }
2147
- });
2148
- event.preventDefault();
2149
- }
2150
- };
2151
- }
2152
- return input;
2153
- }
2154
- ignoreEvent() {
2155
- return false;
2156
- }
2157
- };
2158
- var hide = Decoration5.replace({});
2159
- var fencedCodeLine = Decoration5.line({
2160
- class: mx2("cm-code cm-codeblock-line")
2161
- });
2162
- var fencedCodeLineFirst = Decoration5.line({
2163
- class: mx2("cm-code cm-codeblock-line", "cm-codeblock-first")
2164
- });
2165
- var fencedCodeLineLast = Decoration5.line({
2166
- class: mx2("cm-code cm-codeblock-line", "cm-codeblock-last")
2167
- });
2168
- var horizontalRule = Decoration5.replace({
2169
- widget: new HorizontalRuleWidget()
2170
- });
2171
- var checkedTask = Decoration5.replace({
2172
- widget: new CheckboxWidget(true)
2173
- });
2174
- var uncheckedTask = Decoration5.replace({
2175
- widget: new CheckboxWidget(false)
2176
- });
2177
- var editingRange = (state, range, focus) => {
2178
- const { readOnly, selection: { main: { head } } } = state;
2179
- return focus && !readOnly && head >= range.from && head <= range.to;
2180
- };
2181
- var MarksByParent = /* @__PURE__ */ new Set([
2182
- "CodeMark",
2183
- "EmphasisMark",
2184
- "StrikethroughMark",
2185
- "SubscriptMark",
2186
- "SuperscriptMark"
2187
- ]);
2188
- var buildDecorations = (view, options, focus) => {
2189
- const deco = new RangeSetBuilder2();
2190
- const atomicDeco = new RangeSetBuilder2();
2191
- const { state } = view;
2192
- for (const { from, to } of view.visibleRanges) {
2193
- syntaxTree(state).iterate({
2194
- from,
2195
- to,
2196
- enter: (node) => {
2197
- if (node.name === "FencedCode") {
2198
- const editing = editingRange(state, node, focus);
2199
- for (const block of view.viewportLineBlocks) {
2200
- if (block.to < node.from) {
2201
- continue;
2202
- }
2203
- if (block.from > node.to) {
2204
- break;
2205
- }
2206
- const first = block.from <= node.from;
2207
- const last = block.to >= node.to && /^(\s>)*```$/.test(state.doc.sliceString(block.from, block.to));
2208
- deco.add(block.from, block.from, first ? fencedCodeLineFirst : last ? fencedCodeLineLast : fencedCodeLine);
2209
- if (!editing && (first || last)) {
2210
- atomicDeco.add(block.from, block.to, hide);
2211
- }
2212
- }
2213
- return false;
2214
- } else if (node.name === "Link") {
2215
- const marks = node.node.getChildren("LinkMark");
2216
- const urlNode = node.node.getChild("URL");
2217
- const editing = editingRange(state, node, focus);
2218
- if (urlNode && marks.length >= 2) {
2219
- const url = state.sliceDoc(urlNode.from, urlNode.to);
2220
- if (!editing) {
2221
- atomicDeco.add(node.from, marks[0].to, hide);
2222
- }
2223
- deco.add(marks[0].to, marks[1].from, Decoration5.mark({
2224
- tagName: "a",
2225
- attributes: {
2226
- class: "cm-link",
2227
- href: url,
2228
- rel: "noreferrer",
2229
- target: "_blank"
2230
- }
2231
- }));
2232
- if (!editing) {
2233
- atomicDeco.add(marks[1].from, node.to, options.renderLinkButton ? Decoration5.replace({
2234
- widget: new LinkButton(url, options.renderLinkButton)
2235
- }) : hide);
2236
- }
2237
- }
2238
- } else if (node.name === "HeaderMark") {
2239
- const parent = node.node.parent;
2240
- if (/^ATX/.test(parent.name) && !editingRange(state, state.doc.lineAt(node.from), focus)) {
2241
- const next = state.doc.sliceString(node.to, node.to + 1);
2242
- atomicDeco.add(node.from, node.to + (next === " " ? 1 : 0), hide);
2243
- }
2244
- } else if (node.name === "HorizontalRule") {
2245
- if (!editingRange(state, node, focus)) {
2246
- deco.add(node.from, node.to, horizontalRule);
2247
- }
2248
- } else if (node.name === "TaskMarker") {
2249
- if (!editingRange(state, node, focus)) {
2250
- const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
2251
- atomicDeco.add(node.from - 2, node.from - 1, Decoration5.mark({
2252
- class: "cm-task"
2253
- }));
2254
- atomicDeco.add(node.from, node.to, checked ? checkedTask : uncheckedTask);
2255
- }
2256
- } else if (MarksByParent.has(node.name)) {
2257
- if (!editingRange(state, node.node.parent, focus)) {
2258
- atomicDeco.add(node.from, node.to, hide);
2259
- }
2260
- }
2261
- }
2262
- });
2263
- }
2264
- return {
2265
- deco: deco.finish(),
2266
- atomicDeco: atomicDeco.finish()
2267
- };
2268
- };
2269
- var forceUpdate = StateEffect4.define();
2270
- var decorateMarkdown = (options = {}) => {
2271
- return [
2272
- ViewPlugin4.fromClass(class {
2273
- constructor(view) {
2274
- ({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations(view, options, view.hasFocus));
2275
- }
2276
- update(update2) {
2277
- if (update2.docChanged || update2.viewportChanged || update2.focusChanged || update2.transactions.some((tr) => tr.effects.some((e) => e.is(forceUpdate))) || update2.selectionSet && !options.selectionChangeDelay) {
2278
- ({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations(update2.view, options, update2.view.hasFocus));
2279
- this.clearUpdate();
2280
- } else if (update2.selectionSet) {
2281
- this.scheduleUpdate(update2.view);
2282
- }
2283
- }
2284
- // TODO(burdon): BUG: If the cursor is at the end of a link at the end of a line,
2285
- // the cursor will float in space or be in the wrong position after the decoration is applied.
2286
- scheduleUpdate(view) {
2287
- this.clearUpdate();
2288
- this.pendingUpdate = setTimeout(() => {
2289
- view.dispatch({
2290
- effects: forceUpdate.of(null)
2291
- });
2292
- }, options.selectionChangeDelay);
2293
- }
2294
- clearUpdate() {
2295
- if (this.pendingUpdate) {
2296
- clearTimeout(this.pendingUpdate);
2297
- this.pendingUpdate = void 0;
2298
- }
2299
- }
2300
- destroy() {
2301
- this.clearUpdate();
2302
- }
2303
- }, {
2304
- provide: (plugin) => [
2305
- EditorView12.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration5.none),
2306
- EditorView12.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration5.none),
2307
- EditorView12.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration5.none)
2308
- ]
2309
- }),
2310
- formattingStyles
2311
- ];
2312
- };
2313
- var formattingStyles = EditorView12.baseTheme({
2314
- "& .cm-code": {
2315
- fontFamily: getToken("fontFamily.mono", []).join(",")
1922
+ // packages/ui/react-ui-editor/src/themes/default.ts
1923
+ import get3 from "lodash.get";
1924
+ var defaultTheme = {
1925
+ //
1926
+ // Main layout:
1927
+ // https://codemirror.net/examples/styling
1928
+ //
1929
+ // <div class="cm-editor [cm-focused] [generated classes]">
1930
+ // <div class="cm-scroller">
1931
+ // <div class="cm-gutters">
1932
+ // <div class="cm-gutter [...]">
1933
+ // <div class="cm-gutterElement">...</div>
1934
+ // </div>
1935
+ // </div>
1936
+ // <div class="cm-content" role="textbox" contenteditable="true">
1937
+ // <div class="cm-line"></div>
1938
+ // </div>
1939
+ // <div class="cm-selectionLayer">
1940
+ // <div class="cm-selectionBackground"></div>
1941
+ // </div>
1942
+ // <div class="cm-cursorLayer">
1943
+ // <div class="cm-cursor"></div>
1944
+ // </div>
1945
+ // </div>
1946
+ // </div>
1947
+ //
1948
+ "&": {},
1949
+ "&.cm-focused": {
1950
+ outline: "none"
2316
1951
  },
2317
- "& .cm-codeblock-line": {
2318
- paddingInline: "1rem !important"
1952
+ // NOTE: See https://codemirror.net/docs/guide (DOM Structure).
1953
+ ".cm-scroller": {
1954
+ // TODO(burdon): Reconcile with docs: https://codemirror.net/docs/guide
1955
+ // Inside of that is the scroller element. If the editor has its own scrollbar, this one should be styled with overflow: auto. But it doesn't have to—the editor also supports growing to accomodate its content, or growing up to a certain max-height and then scrolling.
1956
+ overflowY: "auto",
1957
+ fontFamily: get3(tokens, "fontFamily.body", []).join(","),
1958
+ lineHeight: 1.5
2319
1959
  },
2320
- "& .cm-codeblock-end": {
2321
- display: "inline-block",
2322
- width: "100%",
2323
- position: "relative",
2324
- "&::after": {
2325
- position: "absolute",
2326
- inset: 0,
2327
- content: '""'
2328
- }
1960
+ ".cm-content": {
1961
+ // TODO(burdon): Is it possible to remove the padding value from CM's default theme?
1962
+ // padding: 'unset',
1963
+ // NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
1964
+ fontSize: "16px"
2329
1965
  },
2330
- "& .cm-codeblock-first": {
2331
- borderTopLeftRadius: ".5rem",
2332
- borderTopRightRadius: ".5rem"
1966
+ "&light .cm-content": {
1967
+ color: get3(tokens, "extend.semanticColors.base.fg.light", "black"),
1968
+ caretColor: "black"
2333
1969
  },
2334
- "& .cm-codeblock-last": {
2335
- borderBottomLeftRadius: ".5rem",
2336
- borderBottomRightRadius: ".5rem"
1970
+ "&dark .cm-content": {
1971
+ color: get3(tokens, "extend.semanticColors.base.fg.dark", "white"),
1972
+ caretColor: "white"
2337
1973
  },
2338
- "&light .cm-codeblock-line, &light .cm-activeLine.cm-codeblock-line": {
2339
- background: getToken("extend.semanticColors.input.light"),
2340
- mixBlendMode: "darken"
1974
+ //
1975
+ // Cursor
1976
+ //
1977
+ "&light .cm-cursor, &light .cm-dropCursor": {
1978
+ borderLeft: "2px solid black"
1979
+ },
1980
+ "&dark .cm-cursor, &dark .cm-dropCursor": {
1981
+ borderLeft: "2px solid white"
1982
+ },
1983
+ "&light .cm-placeholder": {
1984
+ color: get3(tokens, "extend.semanticColors.description.light", "rgba(0,0,0,.2)")
1985
+ },
1986
+ "&dark .cm-placeholder": {
1987
+ color: get3(tokens, "extend.semanticColors.description.dark", "rgba(255,255,255,.2)")
1988
+ },
1989
+ //
1990
+ // line
1991
+ //
1992
+ ".cm-line": {
1993
+ paddingInline: 0
1994
+ },
1995
+ ".cm-activeLine": {
1996
+ background: "transparent"
1997
+ },
1998
+ //
1999
+ // gutter
2000
+ //
2001
+ ".cm-gutterElement": {
2002
+ width: "48px"
2003
+ },
2004
+ //
2005
+ // Selection
2006
+ //
2007
+ "&light .cm-selectionBackground": {
2008
+ background: get3(tokens, "extend.colors.primary.100")
2009
+ },
2010
+ "&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
2011
+ background: get3(tokens, "extend.colors.primary.200")
2012
+ },
2013
+ "&dark .cm-selectionBackground": {
2014
+ background: get3(tokens, "extend.colors.primary.700")
2015
+ },
2016
+ "&dark.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
2017
+ background: get3(tokens, "extend.colors.primary.600")
2018
+ },
2019
+ //
2020
+ // Search
2021
+ //
2022
+ "&light .cm-searchMatch": {
2023
+ backgroundColor: get3(tokens, "extend.colors.yellow.100")
2024
+ },
2025
+ "&dark .cm-searchMatch": {
2026
+ backgroundColor: get3(tokens, "extend.colors.yellow.700")
2027
+ },
2028
+ //
2029
+ // link
2030
+ //
2031
+ ".cm-link": {
2032
+ color: get3(tokens, "extend.colors.primary.500"),
2033
+ textDecorationLine: "underline",
2034
+ textDecorationThickness: "1px",
2035
+ textUnderlineOffset: "2px",
2036
+ borderRadius: ".125rem",
2037
+ fontFamily: get3(tokens, "fontFamily.body", []).join(",")
2038
+ },
2039
+ //
2040
+ // tooltip
2041
+ //
2042
+ ".cm-tooltip": {
2043
+ border: "none",
2044
+ background: "unset"
2045
+ },
2046
+ ".cm-tooltip-below": {},
2047
+ //
2048
+ // autocomplete
2049
+ //
2050
+ ".cm-tooltip-autocomplete": {
2051
+ marginTop: "4px",
2052
+ marginLeft: "-3px"
2053
+ },
2054
+ ".cm-tooltip-autocomplete ul li": {},
2055
+ ".cm-tooltip-autocomplete ul li[aria-selected]": {},
2056
+ ".cm-completionIcon": {
2057
+ display: "none"
2058
+ },
2059
+ ".cm-completionLabel": {
2060
+ fontFamily: get3(tokens, "fontFamily.body", []).join(",")
2061
+ },
2062
+ ".cm-completionMatchedText": {
2063
+ textDecoration: "none"
2064
+ },
2065
+ //
2066
+ // table
2067
+ //
2068
+ ".cm-table *": {
2069
+ fontFamily: `${get3(tokens, "fontFamily.mono", []).join(",")} !important`,
2070
+ textDecoration: "none !important"
2071
+ },
2072
+ ".cm-table-head": {
2073
+ padding: "2px 16px 2px 0px",
2074
+ borderBottom: `1px solid ${get3(tokens, "extend.colors.neutral.500")}`,
2075
+ fontWeight: 100,
2076
+ textAlign: "left",
2077
+ color: get3(tokens, "extend.colors.neutral.500")
2078
+ },
2079
+ ".cm-table-cell": {
2080
+ padding: "2px 16px 2px 0px"
2081
+ },
2082
+ //
2083
+ // image
2084
+ //
2085
+ ".cm-image": {
2086
+ display: "block",
2087
+ height: "0"
2088
+ },
2089
+ ".cm-image.cm-loaded-image": {
2090
+ height: "auto",
2091
+ borderTop: "0.5rem solid transparent",
2092
+ borderBottom: "0.5rem solid transparent"
2093
+ },
2094
+ //
2095
+ // font size
2096
+ // TODO(thure): This appears to be the best or only way to set selection caret heights,
2097
+ // but it's far more verbose than it needs to be.
2098
+ //
2099
+ // ...Object.keys(get(tokens, 'extend.fontSize', {})).reduce((acc: Record<string, any>, fontSize) => {
2100
+ // const height = get(tokens, ['extend', 'fontSize', fontSize, 1, 'lineHeight']);
2101
+ //
2102
+ // acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = { height };
2103
+ // acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = { height };
2104
+ // acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = { height };
2105
+ // return acc;
2106
+ // }, {}),
2107
+ /**
2108
+ * Panels
2109
+ * TODO(burdon): Needs styling attention (esp. dark mode).
2110
+ * https://github.com/codemirror/search/blob/main/src/search.ts#L745
2111
+ *
2112
+ * Find/replace panel.
2113
+ * <div class="cm-announced">...</div>
2114
+ * <div class="cm-scroller">...</div>
2115
+ * <div class="cm-panels cm-panels-bottom">
2116
+ * <div class="cm-search cm-panel">
2117
+ * <input class="cm-textfield" />
2118
+ * <button class="cm-button">...</button>
2119
+ * <label><input type="checkbox" />...</label>
2120
+ * </div>
2121
+ * </div
2122
+ */
2123
+ ".cm-panels": {},
2124
+ ".cm-panel": {
2125
+ fontFamily: get3(tokens, "fontFamily.body", []).join(",")
2126
+ },
2127
+ ".cm-panel input[type=checkbox]": {
2128
+ marginRight: "0.4rem !important"
2129
+ },
2130
+ "&light .cm-panel": {
2131
+ background: get3(tokens, "extend.colors.neutral.50")
2341
2132
  },
2342
- "&dark .cm-codeblock-line, &dark .cm-activeLine.cm-codeblock-line": {
2343
- background: getToken("extend.semanticColors.input.dark"),
2344
- mixBlendMode: "lighten"
2133
+ "&dark .cm-panel": {
2134
+ background: get3(tokens, "extend.colors.neutral.850")
2345
2135
  },
2346
- "& .cm-hr": {
2347
- display: "inline-block",
2348
- width: "100%",
2349
- height: "0",
2350
- verticalAlign: "middle",
2351
- borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
2136
+ ".cm-button": {
2137
+ margin: "4px",
2138
+ fontFamily: get3(tokens, "fontFamily.body", []).join(","),
2139
+ backgroundImage: "none",
2140
+ border: "none",
2141
+ "&:active": {
2142
+ backgroundImage: "none"
2143
+ }
2352
2144
  },
2353
- "& .cm-task": {
2354
- color: getToken("extend.colors.blue.500")
2145
+ "&light .cm-button": {
2146
+ background: get3(tokens, "extend.colors.neutral.100"),
2147
+ "&:hover": {
2148
+ background: get3(tokens, "extend.colors.neutral.200")
2149
+ },
2150
+ "&:active": {
2151
+ background: get3(tokens, "extend.colors.neutral.300")
2152
+ }
2355
2153
  },
2356
- "& .cm-task-checkbox": {
2357
- marginLeft: "4px",
2358
- marginRight: "4px"
2154
+ "&dark .cm-button": {
2155
+ background: get3(tokens, "extend.colors.neutral.800"),
2156
+ "&:hover": {
2157
+ background: get3(tokens, "extend.colors.neutral.700")
2158
+ },
2159
+ "&:active": {
2160
+ background: get3(tokens, "extend.colors.neutral.600")
2161
+ }
2359
2162
  }
2360
- });
2163
+ };
2164
+
2165
+ // packages/ui/react-ui-editor/src/extensions/factories.ts
2166
+ var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/factories.ts";
2167
+ var defaultBasicOptions = {
2168
+ allowMultipleSelections: true,
2169
+ bracketMatching: true,
2170
+ closeBrackets: true,
2171
+ drawSelection: true,
2172
+ editable: true,
2173
+ history: true,
2174
+ keymap: "standard",
2175
+ lineWrapping: true,
2176
+ search: true
2177
+ };
2178
+ var keymaps = {
2179
+ // https://codemirror.net/docs/ref/#commands.standardKeymap
2180
+ standard: standardKeymap,
2181
+ // https://codemirror.net/docs/ref/#commands.defaultKeymap
2182
+ default: defaultKeymap
2183
+ };
2184
+ var createBasicExtensions = (_props) => {
2185
+ const props = defaultsDeep2({}, _props, defaultBasicOptions);
2186
+ return [
2187
+ // NOTE: Doesn't catch errors in keymap functions.
2188
+ EditorView9.exceptionSink.of((err) => {
2189
+ log5.catch(err, void 0, {
2190
+ F: __dxlog_file7,
2191
+ L: 91,
2192
+ S: void 0,
2193
+ C: (f, a) => f(...a)
2194
+ });
2195
+ }),
2196
+ props.allowMultipleSelections && EditorState.allowMultipleSelections.of(true),
2197
+ props.bracketMatching && bracketMatching(),
2198
+ props.closeBrackets && closeBrackets(),
2199
+ props.dropCursor && dropCursor2(),
2200
+ props.drawSelection && drawSelection(),
2201
+ props.highlightActiveLine && highlightActiveLine(),
2202
+ props.history && history(),
2203
+ props.lineNumbers && lineNumbers(),
2204
+ props.lineWrapping && EditorView9.lineWrapping,
2205
+ props.placeholder && placeholder(props.placeholder),
2206
+ props.readonly && [
2207
+ EditorState.readOnly.of(true),
2208
+ EditorView9.editable.of(false)
2209
+ ],
2210
+ props.scrollPastEnd && scrollPastEnd(),
2211
+ props.tabSize && EditorState.tabSize.of(props.tabSize),
2212
+ // https://codemirror.net/docs/ref/#view.KeyBinding
2213
+ keymap5.of([
2214
+ ...(props.keymap && keymaps[props.keymap]) ?? [],
2215
+ // https://codemirror.net/docs/ref/#commands.indentWithTab
2216
+ ...props.indentWithTab ? [
2217
+ indentWithTab
2218
+ ] : [],
2219
+ // https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
2220
+ ...props.closeBrackets ? closeBracketsKeymap : [],
2221
+ // https://codemirror.net/docs/ref/#commands.historyKeymap
2222
+ ...props.history ? historyKeymap : [],
2223
+ // https://codemirror.net/docs/ref/#search.searchKeymap
2224
+ ...props.search ? searchKeymap : []
2225
+ ].filter(isNotFalsy2))
2226
+ ].filter(isNotFalsy2);
2227
+ };
2228
+ var defaultThemeSlots = {
2229
+ editor: {
2230
+ className: "w-full bs-full"
2231
+ }
2232
+ };
2233
+ var createThemeExtensions = ({ theme, themeMode, slots: _slots } = {}) => {
2234
+ const slots = defaultsDeep2({}, _slots, defaultThemeSlots);
2235
+ return [
2236
+ EditorView9.baseTheme(defaultTheme),
2237
+ EditorView9.darkTheme.of(themeMode === "dark"),
2238
+ theme && EditorView9.theme(theme),
2239
+ slots.editor?.className && EditorView9.editorAttributes.of({
2240
+ class: slots.editor.className
2241
+ }),
2242
+ slots.content?.className && EditorView9.contentAttributes.of({
2243
+ class: slots.content.className
2244
+ })
2245
+ ].filter(isNotFalsy2);
2246
+ };
2247
+ var createDataExtensions = ({ id, text, space, identity }) => {
2248
+ const extensions = [
2249
+ automerge(text)
2250
+ ];
2251
+ if (space && identity) {
2252
+ const peerId = identity?.identityKey.toHex();
2253
+ const { cursorLightValue, cursorDarkValue } = hueTokens[identity?.profile?.data?.hue ?? hexToHue(peerId ?? "0")];
2254
+ const awarenessProvider2 = new SpaceAwarenessProvider({
2255
+ space,
2256
+ channel: `awareness.${id}`,
2257
+ peerId: identity.identityKey.toHex(),
2258
+ info: {
2259
+ displayName: identity.profile?.displayName ?? generateName(identity.identityKey.toHex()),
2260
+ color: cursorDarkValue,
2261
+ lightColor: cursorLightValue
2262
+ }
2263
+ });
2264
+ extensions.push(awareness(awarenessProvider2));
2265
+ }
2266
+ return extensions;
2267
+ };
2268
+
2269
+ // packages/ui/react-ui-editor/src/extensions/listener.ts
2270
+ import { EditorView as EditorView10 } from "@codemirror/view";
2271
+ var listener = ({ onFocus, onChange }) => {
2272
+ const extensions = [];
2273
+ onFocus && extensions.push(EditorView10.focusChangeEffect.of((_, focusing) => {
2274
+ onFocus(focusing);
2275
+ return null;
2276
+ }));
2277
+ onChange && extensions.push(EditorView10.updateListener.of((update2) => {
2278
+ onChange(update2.state.doc.toString());
2279
+ }));
2280
+ return extensions;
2281
+ };
2361
2282
 
2362
2283
  // packages/ui/react-ui-editor/src/extensions/markdown/formatting.ts
2363
2284
  import { snippet } from "@codemirror/autocomplete";
2364
- import { syntaxTree as syntaxTree2 } from "@codemirror/language";
2285
+ import { syntaxTree } from "@codemirror/language";
2365
2286
  import { EditorSelection } from "@codemirror/state";
2366
- import { EditorView as EditorView13, keymap as keymap6 } from "@codemirror/view";
2367
- import { useState, useMemo } from "react";
2368
- var compareFormatting = (a, b) => a.blockType === b.blockType && a.strong === b.strong && a.emphasis === b.emphasis && a.strikethrough === b.strikethrough && a.code === b.code && a.link === b.link && a.listStyle === b.listStyle && a.blockQuote === b.blockQuote;
2287
+ import { EditorView as EditorView11, keymap as keymap6 } from "@codemirror/view";
2288
+ import { useMemo, useState } from "react";
2289
+ var formattingEquals = (a, b) => a.blockType === b.blockType && a.strong === b.strong && a.emphasis === b.emphasis && a.strikethrough === b.strikethrough && a.code === b.code && a.link === b.link && a.listStyle === b.listStyle && a.blockQuote === b.blockQuote;
2369
2290
  var Inline;
2370
2291
  (function(Inline2) {
2371
2292
  Inline2[Inline2["Strong"] = 0] = "Strong";
@@ -2379,13 +2300,13 @@ var List;
2379
2300
  List2[List2["Bullet"] = 1] = "Bullet";
2380
2301
  List2[List2["Task"] = 2] = "Task";
2381
2302
  })(List || (List = {}));
2382
- var setHeading = (level) => ({ state, dispatch }) => {
2383
- const { selection: { ranges }, doc } = state;
2303
+ var setHeading = (level) => ({ state: state2, dispatch }) => {
2304
+ const { selection: { ranges }, doc } = state2;
2384
2305
  const changes = [];
2385
2306
  let prevBlock = -1;
2386
2307
  for (const range of ranges) {
2387
2308
  let sawBlock = false;
2388
- syntaxTree2(state).iterate({
2309
+ syntaxTree(state2).iterate({
2389
2310
  from: range.from,
2390
2311
  to: range.to,
2391
2312
  enter: (node) => {
@@ -2438,7 +2359,7 @@ var setHeading = (level) => ({ state, dispatch }) => {
2438
2359
  }
2439
2360
  });
2440
2361
  let line;
2441
- if (!sawBlock && range.empty && level > 0 && !/\S/.test((line = state.doc.lineAt(range.from)).text)) {
2362
+ if (!sawBlock && range.empty && level > 0 && !/\S/.test((line = state2.doc.lineAt(range.from)).text)) {
2442
2363
  changes.push({
2443
2364
  from: line.from,
2444
2365
  to: line.to,
@@ -2449,23 +2370,23 @@ var setHeading = (level) => ({ state, dispatch }) => {
2449
2370
  if (!changes.length) {
2450
2371
  return false;
2451
2372
  }
2452
- const changeSet = state.changes(changes);
2453
- dispatch(state.update({
2373
+ const changeSet = state2.changes(changes);
2374
+ dispatch(state2.update({
2454
2375
  changes: changeSet,
2455
- selection: state.selection.map(changeSet, 1),
2376
+ selection: state2.selection.map(changeSet, 1),
2456
2377
  userEvent: "format.setHeading",
2457
2378
  scrollIntoView: true
2458
2379
  }));
2459
2380
  return true;
2460
2381
  };
2461
- var setStyle = (type, enable) => ({ state, dispatch }) => {
2382
+ var setStyle = (type, enable) => ({ state: state2, dispatch }) => {
2462
2383
  const marker = inlineMarkerText(type);
2463
- const changes = state.changeByRange((range) => {
2384
+ const changes = state2.changeByRange((range) => {
2464
2385
  if (!enable && range.empty) {
2465
- const after = state.doc.sliceString(range.head, range.head + 6);
2386
+ const after = state2.doc.sliceString(range.head, range.head + 6);
2466
2387
  const found = after.indexOf(marker);
2467
2388
  if (found >= 0 && /^[*~`]*$/.test(after.slice(0, found))) {
2468
- const before = state.doc.sliceString(range.head - 6, range.head);
2389
+ const before = state2.doc.sliceString(range.head - 6, range.head);
2469
2390
  if (before.slice(before.length - found - marker.length, before.length - found) === marker && [
2470
2391
  ...before.slice(before.length - found)
2471
2392
  ].reverse().join("") === after.slice(0, found)) {
@@ -2492,14 +2413,14 @@ var setStyle = (type, enable) => ({ state, dispatch }) => {
2492
2413
  let startCovered = false;
2493
2414
  let endCovered = false;
2494
2415
  let { from, to } = range;
2495
- syntaxTree2(state).iterate({
2416
+ syntaxTree(state2).iterate({
2496
2417
  from,
2497
2418
  to,
2498
2419
  enter: (node) => {
2499
2420
  const { name } = node;
2500
2421
  if (Object.hasOwn(Textblocks, name) && Textblocks[name] !== "codeblock") {
2501
2422
  blockStart = blockContentStart(node);
2502
- blockEnd = blockContentEnd(node, state.doc);
2423
+ blockEnd = blockContentEnd(node, state2.doc);
2503
2424
  startCovered = endCovered = false;
2504
2425
  } else if (name === "Link" || name === "Image" && enable) {
2505
2426
  if (from < node.from && to > node.from && to <= node.to) {
@@ -2544,7 +2465,7 @@ var setStyle = (type, enable) => ({ state, dispatch }) => {
2544
2465
  });
2545
2466
  if (markType !== type && closeStart >= to) {
2546
2467
  changesAtEnd.push({
2547
- from: skipSpaces(Math.min(to, blockEnd), state.doc, 1, blockEnd),
2468
+ from: skipSpaces(Math.min(to, blockEnd), state2.doc, 1, blockEnd),
2548
2469
  insert: inlineMarkerText(markType)
2549
2470
  });
2550
2471
  }
@@ -2556,7 +2477,7 @@ var setStyle = (type, enable) => ({ state, dispatch }) => {
2556
2477
  });
2557
2478
  if (markType !== type && openEnd <= from) {
2558
2479
  changes2.push({
2559
- from: skipSpaces(Math.max(from, blockStart), state.doc, -1, blockStart),
2480
+ from: skipSpaces(Math.max(from, blockStart), state2.doc, -1, blockStart),
2560
2481
  insert: inlineMarkerText(markType)
2561
2482
  });
2562
2483
  }
@@ -2586,7 +2507,7 @@ var setStyle = (type, enable) => ({ state, dispatch }) => {
2586
2507
  changes2.push(startCovered);
2587
2508
  } else if (startCovered) {
2588
2509
  changes2.push({
2589
- from: skipSpaces(rangeStart, state.doc, -1, blockStart),
2510
+ from: skipSpaces(rangeStart, state2.doc, -1, blockStart),
2590
2511
  insert: marker
2591
2512
  });
2592
2513
  }
@@ -2594,7 +2515,7 @@ var setStyle = (type, enable) => ({ state, dispatch }) => {
2594
2515
  changes2.push(endCovered);
2595
2516
  } else if (endCovered) {
2596
2517
  changes2.push({
2597
- from: skipSpaces(rangeEnd, state.doc, 1, blockEnd),
2518
+ from: skipSpaces(rangeEnd, state2.doc, 1, blockEnd),
2598
2519
  insert: marker
2599
2520
  });
2600
2521
  }
@@ -2602,7 +2523,7 @@ var setStyle = (type, enable) => ({ state, dispatch }) => {
2602
2523
  }
2603
2524
  }
2604
2525
  });
2605
- if (blockStart < 0 && range.empty && enable && !/\S/.test(state.doc.lineAt(range.from).text)) {
2526
+ if (blockStart < 0 && range.empty && enable && !/\S/.test(state2.doc.lineAt(range.from).text)) {
2606
2527
  return {
2607
2528
  changes: {
2608
2529
  from: range.head,
@@ -2611,13 +2532,13 @@ var setStyle = (type, enable) => ({ state, dispatch }) => {
2611
2532
  range: EditorSelection.cursor(range.head + marker.length)
2612
2533
  };
2613
2534
  }
2614
- const changeSet = state.changes(changes2.concat(changesAtEnd));
2535
+ const changeSet = state2.changes(changes2.concat(changesAtEnd));
2615
2536
  return {
2616
2537
  changes: changeSet,
2617
2538
  range: range.empty && !changeSet.empty ? EditorSelection.cursor(range.head + marker.length) : EditorSelection.range(changeSet.mapPos(range.from, 1), changeSet.mapPos(range.to, -1))
2618
2539
  };
2619
2540
  });
2620
- dispatch(state.update(changes, {
2541
+ dispatch(state2.update(changes, {
2621
2542
  userEvent: enable ? "format.style.add" : "format.style.remove",
2622
2543
  scrollIntoView: true
2623
2544
  }));
@@ -2691,8 +2612,8 @@ var insertTable = (view) => {
2691
2612
  const { from } = doc.line(number);
2692
2613
  snippets.table(view, null, from, from);
2693
2614
  };
2694
- var removeLinkInner = (from, to, changes, state) => {
2695
- syntaxTree2(state).iterate({
2615
+ var removeLinkInner = (from, to, changes, state2) => {
2616
+ syntaxTree(state2).iterate({
2696
2617
  from,
2697
2618
  to,
2698
2619
  enter: (node) => {
@@ -2706,8 +2627,8 @@ var removeLinkInner = (from, to, changes, state) => {
2706
2627
  });
2707
2628
  } else if (name === "LinkTitle" || name === "URL") {
2708
2629
  changes.push({
2709
- from: skipSpaces(node2.from, state.doc, -1),
2710
- to: skipSpaces(node2.to, state.doc, 1)
2630
+ from: skipSpaces(node2.from, state2.doc, -1),
2631
+ to: skipSpaces(node2.to, state2.doc, 1)
2711
2632
  });
2712
2633
  }
2713
2634
  });
@@ -2716,32 +2637,32 @@ var removeLinkInner = (from, to, changes, state) => {
2716
2637
  }
2717
2638
  });
2718
2639
  };
2719
- var removeLink = ({ state, dispatch }) => {
2640
+ var removeLink = ({ state: state2, dispatch }) => {
2720
2641
  const changes = [];
2721
- for (const { from, to } of state.selection.ranges) {
2722
- removeLinkInner(from, to, changes, state);
2642
+ for (const { from, to } of state2.selection.ranges) {
2643
+ removeLinkInner(from, to, changes, state2);
2723
2644
  }
2724
2645
  if (!changes) {
2725
2646
  return false;
2726
2647
  }
2727
- dispatch(state.update({
2648
+ dispatch(state2.update({
2728
2649
  changes,
2729
2650
  userEvent: "format.link.remove",
2730
2651
  scrollIntoView: true
2731
2652
  }));
2732
2653
  return true;
2733
2654
  };
2734
- var addLink = ({ state, dispatch }) => {
2735
- const changes = state.changeByRange((range) => {
2655
+ var addLink = ({ url, image: image2 } = {}) => ({ state: state2, dispatch }) => {
2656
+ const changes = state2.changeByRange((range) => {
2736
2657
  let { from, to } = range;
2737
2658
  const cutStyles = [];
2738
2659
  let okay = null;
2739
- syntaxTree2(state).iterate({
2660
+ syntaxTree(state2).iterate({
2740
2661
  from,
2741
2662
  to,
2742
2663
  enter: (node) => {
2743
2664
  if (Object.hasOwn(Textblocks, node.name)) {
2744
- okay = Textblocks[node.name] !== "codeblock" && from >= blockContentStart(node) && to <= blockContentEnd(node, state.doc);
2665
+ okay = Textblocks[node.name] !== "codeblock" && from >= blockContentStart(node) && to <= blockContentEnd(node, state2.doc);
2745
2666
  } else if (Object.hasOwn(InlineMarker, node.name)) {
2746
2667
  const sNode = node.node;
2747
2668
  if (node.from < from && node.to <= to) {
@@ -2761,7 +2682,7 @@ var addLink = ({ state, dispatch }) => {
2761
2682
  }
2762
2683
  });
2763
2684
  if (okay === null) {
2764
- const line = state.doc.lineAt(from);
2685
+ const line = state2.doc.lineAt(from);
2765
2686
  okay = to <= line.to && !/\S/.test(line.text.slice(from - line.from));
2766
2687
  }
2767
2688
  if (!okay) {
@@ -2771,26 +2692,26 @@ var addLink = ({ state, dispatch }) => {
2771
2692
  }
2772
2693
  const changes2 = [];
2773
2694
  const changesAfter = [];
2774
- removeLinkInner(from, to, changesAfter, state);
2695
+ removeLinkInner(from, to, changesAfter, state2);
2775
2696
  let cursorOffset = 1;
2776
2697
  for (const style of cutStyles) {
2777
2698
  const type = InlineMarker[style.name];
2778
2699
  const mark2 = inlineMarkerText(type);
2779
2700
  if (style.from < from) {
2780
2701
  changes2.push({
2781
- from: skipSpaces(from, state.doc, -1),
2702
+ from: skipSpaces(from, state2.doc, -1),
2782
2703
  insert: mark2
2783
2704
  });
2784
2705
  changesAfter.push({
2785
- from: skipSpaces(from, state.doc, 1, to),
2706
+ from: skipSpaces(from, state2.doc, 1, to),
2786
2707
  insert: mark2
2787
2708
  });
2788
2709
  } else {
2789
2710
  changes2.push({
2790
- from: skipSpaces(to, state.doc, -1, from),
2711
+ from: skipSpaces(to, state2.doc, -1, from),
2791
2712
  insert: mark2
2792
2713
  });
2793
- const after = skipSpaces(to, state.doc, 1);
2714
+ const after = skipSpaces(to, state2.doc, 1);
2794
2715
  if (after === to) {
2795
2716
  cursorOffset += mark2.length;
2796
2717
  }
@@ -2802,34 +2723,34 @@ var addLink = ({ state, dispatch }) => {
2802
2723
  }
2803
2724
  changes2.push({
2804
2725
  from,
2805
- insert: "["
2726
+ insert: image2 ? "![" : "["
2806
2727
  }, {
2807
2728
  from: to,
2808
- insert: "]()"
2729
+ insert: `](${url ?? ""})`
2809
2730
  });
2810
- const changeSet = state.changes(changes2.concat(changesAfter));
2731
+ const changeSet = state2.changes(changes2.concat(changesAfter));
2811
2732
  return {
2812
2733
  changes: changeSet,
2813
- range: EditorSelection.cursor(changeSet.mapPos(to, 1) - cursorOffset)
2734
+ range: EditorSelection.cursor(changeSet.mapPos(to, 1) - cursorOffset - (url ? url.length + 2 : 0))
2814
2735
  };
2815
2736
  });
2816
2737
  if (changes.changes.empty) {
2817
2738
  return false;
2818
2739
  }
2819
- dispatch(state.update(changes, {
2740
+ dispatch(state2.update(changes, {
2820
2741
  userEvent: "format.link.add",
2821
2742
  scrollIntoView: true
2822
2743
  }));
2823
2744
  return true;
2824
2745
  };
2825
- var addList = (type) => ({ state, dispatch }) => {
2746
+ var addList = (type) => ({ state: state2, dispatch }) => {
2826
2747
  let lastBlock = -1;
2827
2748
  let counter = 1;
2828
2749
  let first = true;
2829
2750
  let parentColumn = null;
2830
2751
  const blocks = [];
2831
- for (const { from, to } of state.selection.ranges) {
2832
- syntaxTree2(state).iterate({
2752
+ for (const { from, to } of state2.selection.ranges) {
2753
+ syntaxTree(state2).iterate({
2833
2754
  from,
2834
2755
  to,
2835
2756
  enter: (node) => {
@@ -2841,7 +2762,7 @@ var addList = (type) => ({ state, dispatch }) => {
2841
2762
  }
2842
2763
  if (before?.name === (type === 0 ? "OrderedList" : "BulletList")) {
2843
2764
  const item = before.lastChild;
2844
- const itemLine = state.doc.lineAt(item.from);
2765
+ const itemLine = state2.doc.lineAt(item.from);
2845
2766
  const itemText = itemLine.text.slice(item.from - itemLine.from);
2846
2767
  parentColumn = item.from - itemLine.from + /^\s*/.exec(itemText)[0].length;
2847
2768
  if (type === 0) {
@@ -2876,10 +2797,10 @@ var addList = (type) => ({ state, dispatch }) => {
2876
2797
  });
2877
2798
  }
2878
2799
  if (!blocks.length) {
2879
- const { from, to } = state.doc.lineAt(state.selection.main.anchor);
2800
+ const { from, to } = state2.doc.lineAt(state2.selection.main.anchor);
2880
2801
  if (from === to) {
2881
2802
  const insert = type === 1 ? "- " : type === 0 ? "1. " : "- [ ] ";
2882
- dispatch(state.update({
2803
+ dispatch(state2.update({
2883
2804
  changes: [
2884
2805
  {
2885
2806
  from,
@@ -2900,11 +2821,11 @@ var addList = (type) => ({ state, dispatch }) => {
2900
2821
  for (let i = 0; i < blocks.length; i++) {
2901
2822
  const { node, counter: counter2, parentColumn: parentColumn2 } = blocks[i];
2902
2823
  const nodeFrom = node.name === "CodeBlock" ? node.from - 4 : node.from;
2903
- let padding = nodeFrom > 0 && !/\s/.test(state.doc.sliceString(nodeFrom - 1, nodeFrom)) ? 1 : 0;
2824
+ let padding = nodeFrom > 0 && !/\s/.test(state2.doc.sliceString(nodeFrom - 1, nodeFrom)) ? 1 : 0;
2904
2825
  if (type === 0) {
2905
2826
  padding += String(counter2).length;
2906
2827
  }
2907
- let line = state.doc.lineAt(nodeFrom);
2828
+ let line = state2.doc.lineAt(nodeFrom);
2908
2829
  const column = nodeFrom - line.from;
2909
2830
  if (parentColumn2 !== null && parentColumn2 > column) {
2910
2831
  padding = Math.max(padding, parentColumn2 - column);
@@ -2929,7 +2850,7 @@ var addList = (type) => ({ state, dispatch }) => {
2929
2850
  insert: mark2
2930
2851
  });
2931
2852
  while (line.to < node.to) {
2932
- line = state.doc.lineAt(line.to + 1);
2853
+ line = state2.doc.lineAt(line.to + 1);
2933
2854
  const open = /^[\s>]*/.exec(line.text)[0].length;
2934
2855
  changes.push({
2935
2856
  from: line.from + Math.min(open, column),
@@ -2944,25 +2865,25 @@ var addList = (type) => ({ state, dispatch }) => {
2944
2865
  next = next.nextSibling;
2945
2866
  }
2946
2867
  if (next?.name === "OrderedList") {
2947
- renumberListItems(next.firstChild, last.counter + 1, changes, state.doc);
2868
+ renumberListItems(next.firstChild, last.counter + 1, changes, state2.doc);
2948
2869
  }
2949
2870
  }
2950
- const changeSet = state.changes(changes);
2951
- dispatch(state.update({
2871
+ const changeSet = state2.changes(changes);
2872
+ dispatch(state2.update({
2952
2873
  changes: changeSet,
2953
- selection: state.selection.map(changeSet, 1),
2874
+ selection: state2.selection.map(changeSet, 1),
2954
2875
  userEvent: "format.list.add",
2955
2876
  scrollIntoView: true
2956
2877
  }));
2957
2878
  return true;
2958
2879
  };
2959
- var removeList = (type) => ({ state, dispatch }) => {
2880
+ var removeList = (type) => ({ state: state2, dispatch }) => {
2960
2881
  let lastBlock = -1;
2961
2882
  const changes = [];
2962
2883
  const stack = [];
2963
2884
  const targetNodeType = type === 0 ? "OrderedList" : type === 1 ? "BulletList" : "TaskList";
2964
- for (const { from, to } of state.selection.ranges) {
2965
- syntaxTree2(state).iterate({
2885
+ for (const { from, to } of state2.selection.ranges) {
2886
+ syntaxTree(state2).iterate({
2966
2887
  from,
2967
2888
  to,
2968
2889
  enter: (node) => {
@@ -2979,7 +2900,7 @@ var removeList = (type) => ({ state, dispatch }) => {
2979
2900
  stack.pop();
2980
2901
  } else if (name === "ListItem" && stack[stack.length - 1] === targetNodeType && node.from !== lastBlock) {
2981
2902
  lastBlock = node.from;
2982
- let line = state.doc.lineAt(node.from);
2903
+ let line = state2.doc.lineAt(node.from);
2983
2904
  const mark2 = /^\s*(\d+[.)] |[-*+] (\[[ x]\] )?)/.exec(line.text.slice(node.from - line.from));
2984
2905
  if (!mark2) {
2985
2906
  return false;
@@ -2990,7 +2911,7 @@ var removeList = (type) => ({ state, dispatch }) => {
2990
2911
  to: node.from + mark2[0].length
2991
2912
  });
2992
2913
  while (line.to < node.to) {
2993
- line = state.doc.lineAt(line.to + 1);
2914
+ line = state2.doc.lineAt(line.to + 1);
2994
2915
  const open = /^[\s>]*/.exec(line.text)[0].length;
2995
2916
  if (open > column) {
2996
2917
  changes.push({
@@ -3000,7 +2921,7 @@ var removeList = (type) => ({ state, dispatch }) => {
3000
2921
  }
3001
2922
  }
3002
2923
  if (node.to >= to) {
3003
- renumberListItems(node.node.nextSibling, 1, changes, state.doc);
2924
+ renumberListItems(node.node.nextSibling, 1, changes, state2.doc);
3004
2925
  }
3005
2926
  return false;
3006
2927
  }
@@ -3010,7 +2931,7 @@ var removeList = (type) => ({ state, dispatch }) => {
3010
2931
  if (!changes.length) {
3011
2932
  return false;
3012
2933
  }
3013
- dispatch(state.update({
2934
+ dispatch(state2.update({
3014
2935
  changes,
3015
2936
  userEvent: "format.list.remove",
3016
2937
  scrollIntoView: true
@@ -3018,8 +2939,8 @@ var removeList = (type) => ({ state, dispatch }) => {
3018
2939
  return true;
3019
2940
  };
3020
2941
  var toggleList = (type) => (target) => {
3021
- const formatting2 = getFormatting(target.state);
3022
- const active = formatting2.listStyle === (type === 1 ? "bullet" : type === 0 ? "ordered" : "task");
2942
+ const formatting = getFormatting(target.state);
2943
+ const active = formatting.listStyle === (type === 1 ? "bullet" : type === 0 ? "ordered" : "task");
3023
2944
  return (active ? removeList(type) : addList(type))(target);
3024
2945
  };
3025
2946
  var renumberListItems = (item, counter, changes, doc) => {
@@ -3040,12 +2961,12 @@ var renumberListItems = (item, counter, changes, doc) => {
3040
2961
  }
3041
2962
  }
3042
2963
  };
3043
- var setBlockquote = (enable) => ({ state, dispatch }) => {
2964
+ var setBlockquote = (enable) => ({ state: state2, dispatch }) => {
3044
2965
  const lines = [];
3045
2966
  let lastBlock = -1;
3046
- for (const { from, to } of state.selection.ranges) {
2967
+ for (const { from, to } of state2.selection.ranges) {
3047
2968
  const sawBlock = false;
3048
- syntaxTree2(state).iterate({
2969
+ syntaxTree(state2).iterate({
3049
2970
  from,
3050
2971
  to,
3051
2972
  enter: (node) => {
@@ -3054,9 +2975,9 @@ var setBlockquote = (enable) => ({ state, dispatch }) => {
3054
2975
  return false;
3055
2976
  }
3056
2977
  lastBlock = node.from;
3057
- let line2 = state.doc.lineAt(node.from);
2978
+ let line2 = state2.doc.lineAt(node.from);
3058
2979
  if (line2.number > 1) {
3059
- const prevLine = state.doc.line(line2.number - 1);
2980
+ const prevLine = state2.doc.line(line2.number - 1);
3060
2981
  if (/^[>\s]*$/.test(prevLine.text)) {
3061
2982
  if (!enable || lines.length && lines[lines.length - 1].number === prevLine.number - 1) {
3062
2983
  lines.push(prevLine);
@@ -3068,10 +2989,10 @@ var setBlockquote = (enable) => ({ state, dispatch }) => {
3068
2989
  if (line2.to >= node.to) {
3069
2990
  break;
3070
2991
  }
3071
- line2 = state.doc.line(line2.number + 1);
2992
+ line2 = state2.doc.line(line2.number + 1);
3072
2993
  }
3073
- if (!enable && line2.number < state.doc.lines) {
3074
- const nextLine = state.doc.line(line2.number + 1);
2994
+ if (!enable && line2.number < state2.doc.lines) {
2995
+ const nextLine = state2.doc.line(line2.number + 1);
3075
2996
  if (/^[>\s]*$/.test(nextLine.text)) {
3076
2997
  lines.push(nextLine);
3077
2998
  }
@@ -3081,7 +3002,7 @@ var setBlockquote = (enable) => ({ state, dispatch }) => {
3081
3002
  }
3082
3003
  });
3083
3004
  let line;
3084
- if (!sawBlock && enable && from === to && !/\S/.test((line = state.doc.lineAt(from)).text)) {
3005
+ if (!sawBlock && enable && from === to && !/\S/.test((line = state2.doc.lineAt(from)).text)) {
3085
3006
  lines.push(line);
3086
3007
  }
3087
3008
  }
@@ -3105,10 +3026,10 @@ var setBlockquote = (enable) => ({ state, dispatch }) => {
3105
3026
  if (!changes.length) {
3106
3027
  return false;
3107
3028
  }
3108
- const changeSet = state.changes(changes);
3109
- dispatch(state.update({
3029
+ const changeSet = state2.changes(changes);
3030
+ dispatch(state2.update({
3110
3031
  changes: changeSet,
3111
- selection: state.selection.map(changeSet, 1),
3032
+ selection: state2.selection.map(changeSet, 1),
3112
3033
  userEvent: enable ? "format.blockquote.add" : "format.blockquote.remove",
3113
3034
  scrollIntoView: true
3114
3035
  }));
@@ -3120,11 +3041,11 @@ var toggleBlockquote = (target) => {
3120
3041
  return (getFormatting(target.state).blockQuote ? removeBlockquote : addBlockquote)(target);
3121
3042
  };
3122
3043
  var addCodeblock = (target) => {
3123
- const { state, dispatch } = target;
3124
- const { selection } = state;
3044
+ const { state: state2, dispatch } = target;
3045
+ const { selection } = state2;
3125
3046
  if (selection.ranges.length === 1 && selection.main.empty) {
3126
3047
  const { head } = selection.main;
3127
- const line = state.doc.lineAt(head);
3048
+ const line = state2.doc.lineAt(head);
3128
3049
  if (!/\S/.test(line.text) && head === line.from) {
3129
3050
  snippets.codeblock(target, null, line.from, line.to);
3130
3051
  return true;
@@ -3134,7 +3055,7 @@ var addCodeblock = (target) => {
3134
3055
  for (const { from, to } of selection.ranges) {
3135
3056
  let blockFrom = from;
3136
3057
  let blockTo = to;
3137
- syntaxTree2(state).iterate({
3058
+ syntaxTree(state2).iterate({
3138
3059
  from,
3139
3060
  to,
3140
3061
  enter: (node) => {
@@ -3143,8 +3064,8 @@ var addCodeblock = (target) => {
3143
3064
  blockFrom = node.from;
3144
3065
  blockTo = node.to;
3145
3066
  } else {
3146
- blockFrom = Math.min(blockFrom, state.doc.lineAt(node.from).from);
3147
- blockTo = Math.max(blockTo, state.doc.lineAt(node.to).to);
3067
+ blockFrom = Math.min(blockFrom, state2.doc.lineAt(node.from).from);
3068
+ blockTo = Math.max(blockTo, state2.doc.lineAt(node.to).to);
3148
3069
  }
3149
3070
  }
3150
3071
  }
@@ -3162,7 +3083,7 @@ var addCodeblock = (target) => {
3162
3083
  return false;
3163
3084
  }
3164
3085
  const changes = ranges.map(({ from, to }) => {
3165
- const column = from - state.doc.lineAt(from).from;
3086
+ const column = from - state2.doc.lineAt(from).from;
3166
3087
  return [
3167
3088
  {
3168
3089
  from,
@@ -3174,30 +3095,30 @@ var addCodeblock = (target) => {
3174
3095
  }
3175
3096
  ];
3176
3097
  });
3177
- dispatch(state.update({
3098
+ dispatch(state2.update({
3178
3099
  changes,
3179
3100
  userEvent: "format.codeblock.add",
3180
3101
  scrollIntoView: true
3181
3102
  }));
3182
3103
  return true;
3183
3104
  };
3184
- var removeCodeblock = ({ state, dispatch }) => {
3105
+ var removeCodeblock = ({ state: state2, dispatch }) => {
3185
3106
  const changes = [];
3186
3107
  let lastBlock = -1;
3187
- for (const { from, to } of state.selection.ranges) {
3188
- syntaxTree2(state).iterate({
3108
+ for (const { from, to } of state2.selection.ranges) {
3109
+ syntaxTree(state2).iterate({
3189
3110
  from,
3190
3111
  to,
3191
3112
  enter: (node) => {
3192
3113
  if (Textblocks[node.name] === "codeblock" && lastBlock !== node.from) {
3193
3114
  lastBlock = node.from;
3194
- const firstLine = state.doc.lineAt(node.from);
3115
+ const firstLine = state2.doc.lineAt(node.from);
3195
3116
  if (node.name === "FencedCode") {
3196
3117
  changes.push({
3197
3118
  from: node.from,
3198
3119
  to: firstLine.to + 1 + node.from - firstLine.from
3199
3120
  });
3200
- const lastLine = state.doc.lineAt(node.to);
3121
+ const lastLine = state2.doc.lineAt(node.to);
3201
3122
  if (/^([\s>]|[-*+] |\d+[).])*`+$/.test(lastLine.text)) {
3202
3123
  changes.push({
3203
3124
  from: lastLine.from - (lastLine.number === firstLine.number + 1 ? 0 : 1),
@@ -3206,7 +3127,7 @@ var removeCodeblock = ({ state, dispatch }) => {
3206
3127
  }
3207
3128
  } else {
3208
3129
  const column = node.from - firstLine.from;
3209
- for (let line = firstLine; ; line = state.doc.line(line.number + 1)) {
3130
+ for (let line = firstLine; ; line = state2.doc.line(line.number + 1)) {
3210
3131
  changes.push({
3211
3132
  from: line.from + column - 4,
3212
3133
  to: line.from + column
@@ -3223,7 +3144,7 @@ var removeCodeblock = ({ state, dispatch }) => {
3223
3144
  if (!changes.length) {
3224
3145
  return false;
3225
3146
  }
3226
- dispatch(state.update({
3147
+ dispatch(state2.update({
3227
3148
  changes,
3228
3149
  userEvent: "format.codeblock.remove",
3229
3150
  scrollIntoView: true
@@ -3233,7 +3154,7 @@ var removeCodeblock = ({ state, dispatch }) => {
3233
3154
  var toggleCodeblock = (target) => {
3234
3155
  return (getFormatting(target.state).blockType === "codeblock" ? removeCodeblock : addCodeblock)(target);
3235
3156
  };
3236
- var formatting = (options = {}) => {
3157
+ var formattingKeymap = (options = {}) => {
3237
3158
  return [
3238
3159
  keymap6.of([
3239
3160
  {
@@ -3282,7 +3203,7 @@ var Textblocks = {
3282
3203
  TableCell: "tablecell",
3283
3204
  Task: "paragraph"
3284
3205
  };
3285
- var getFormatting = (state) => {
3206
+ var getFormatting = (state2) => {
3286
3207
  let blockType = null;
3287
3208
  const inline = [
3288
3209
  null,
@@ -3308,7 +3229,7 @@ var getFormatting = (state) => {
3308
3229
  continue;
3309
3230
  } else if (currentBlock.active[i]) {
3310
3231
  inline[i] = true;
3311
- } else if (/\S/.test(state.doc.sliceString(currentBlock.pos, upto))) {
3232
+ } else if (/\S/.test(state2.doc.sliceString(currentBlock.pos, upto))) {
3312
3233
  inline[i] = false;
3313
3234
  }
3314
3235
  }
@@ -3319,12 +3240,12 @@ var getFormatting = (state) => {
3319
3240
  currentBlock.pos = Math.min(upto, currentBlock.end);
3320
3241
  }
3321
3242
  };
3322
- const { selection } = state;
3243
+ const { selection } = state2;
3323
3244
  for (const range of selection.ranges) {
3324
3245
  if (range.empty && inline.some((v) => v === null)) {
3325
3246
  const contextSize = Math.min(range.head, 6);
3326
- const contextBefore = state.doc.sliceString(range.head - contextSize, range.head);
3327
- let contextAfter = state.doc.sliceString(range.head, range.head + contextSize);
3247
+ const contextBefore = state2.doc.sliceString(range.head - contextSize, range.head);
3248
+ let contextAfter = state2.doc.sliceString(range.head, range.head + contextSize);
3328
3249
  for (let i = 0; i < contextSize; i++) {
3329
3250
  const ch = contextAfter[i];
3330
3251
  if (ch !== contextBefore[contextBefore.length - 1 - i] || !/[~`*]/.test(ch)) {
@@ -3343,7 +3264,7 @@ var getFormatting = (state) => {
3343
3264
  }
3344
3265
  }
3345
3266
  }
3346
- syntaxTree2(state).iterate({
3267
+ syntaxTree(state2).iterate({
3347
3268
  from: range.from,
3348
3269
  to: range.to,
3349
3270
  enter: (node) => {
@@ -3417,7 +3338,7 @@ var getFormatting = (state) => {
3417
3338
  }
3418
3339
  });
3419
3340
  }
3420
- const { from, to } = state.doc.lineAt(selection.main.anchor);
3341
+ const { from, to } = state2.doc.lineAt(selection.main.anchor);
3421
3342
  const blankLine = from === to;
3422
3343
  return {
3423
3344
  blankLine,
@@ -3431,1030 +3352,1032 @@ var getFormatting = (state) => {
3431
3352
  listStyle: listStyle || null
3432
3353
  };
3433
3354
  };
3434
- var useFormattingState = () => {
3435
- const [state, setState] = useState(null);
3436
- const observer = useMemo(() => EditorView13.updateListener.of((update2) => {
3437
- if (update2.docChanged || update2.selectionSet) {
3438
- const newState = getFormatting(update2.state);
3439
- if (!state || !compareFormatting(state, newState)) {
3440
- setState(newState);
3441
- }
3442
- }
3443
- }), []);
3444
- return [
3445
- state,
3446
- observer
3447
- ];
3448
- };
3449
-
3450
- // packages/ui/react-ui-editor/src/extensions/markdown/image.ts
3451
- import { syntaxTree as syntaxTree3 } from "@codemirror/language";
3452
- import { StateField as StateField5 } from "@codemirror/state";
3453
- import { Decoration as Decoration6, EditorView as EditorView14, WidgetType as WidgetType4 } from "@codemirror/view";
3454
- var image = (options = {}) => {
3455
- return StateField5.define({
3456
- create: (state) => {
3457
- return Decoration6.set(buildDecorations2(0, state.doc.length, state));
3458
- },
3459
- update: (value, tr) => {
3460
- if (!tr.docChanged && !tr.selection) {
3461
- return value;
3462
- }
3463
- const cursor = tr.state.selection.main.head;
3464
- const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
3465
- let from = Math.min(cursor, oldCursor);
3466
- let to = Math.max(cursor, oldCursor);
3467
- tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
3468
- from = Math.min(from, fromB);
3469
- to = Math.max(to, toB);
3470
- });
3471
- from = tr.state.doc.lineAt(from).from;
3472
- to = tr.state.doc.lineAt(to).to;
3473
- return value.map(tr.changes).update({
3474
- filterFrom: from,
3475
- filterTo: to,
3476
- filter: () => false,
3477
- add: buildDecorations2(from, to, tr.state)
3478
- });
3479
- },
3480
- provide: (field) => EditorView14.decorations.from(field)
3481
- });
3482
- };
3483
- var preloaded = /* @__PURE__ */ new Set();
3484
- var preloadImage = (url) => {
3485
- if (!preloaded.has(url)) {
3486
- const img = document.createElement("img");
3487
- img.src = url;
3488
- preloaded.add(url);
3489
- }
3490
- };
3491
- var buildDecorations2 = (from, to, state) => {
3492
- const decorations = [];
3493
- const cursor = state.selection.main.head;
3494
- syntaxTree3(state).iterate({
3495
- enter: (node) => {
3496
- if (node.name === "Image") {
3497
- const urlNode = node.node.getChild("URL");
3498
- if (urlNode) {
3499
- const hide2 = state.readOnly || cursor < node.from || cursor > node.to;
3500
- const url = state.sliceDoc(urlNode.from, urlNode.to);
3501
- preloadImage(url);
3502
- decorations.push(Decoration6.replace({
3503
- block: true,
3504
- widget: new ImageWidget(url)
3505
- }).range(hide2 ? node.from : node.to, node.to));
3506
- }
3507
- }
3508
- },
3509
- from,
3510
- to
3511
- });
3512
- return decorations;
3513
- };
3514
- var ImageWidget = class extends WidgetType4 {
3515
- constructor(_url) {
3516
- super();
3517
- this._url = _url;
3518
- }
3519
- eq(other) {
3520
- return this._url === other._url;
3521
- }
3522
- toDOM(view) {
3523
- const img = document.createElement("img");
3524
- img.setAttribute("src", this._url);
3525
- img.setAttribute("class", "cm-image");
3526
- img.onload = () => img.classList.add("cm-loaded-image");
3527
- return img;
3528
- }
3529
- };
3530
-
3531
- // packages/ui/react-ui-editor/src/extensions/markdown/link.ts
3532
- import { syntaxTree as syntaxTree4 } from "@codemirror/language";
3533
- import { hoverTooltip as hoverTooltip2 } from "@codemirror/view";
3534
- import { tooltipContent } from "@dxos/react-ui-theme";
3535
- var linkTooltip = (render) => hoverTooltip2((view, pos, side) => {
3536
- const syntax = syntaxTree4(view.state).resolveInner(pos, side);
3537
- let link = null;
3538
- for (let i = 0, node = syntax; !link && node && i < 5; node = node.parent, i++) {
3539
- link = node.name === "Link" ? node : null;
3540
- }
3541
- const url = link && link.getChild("URL");
3542
- if (!url || !link) {
3543
- return null;
3544
- }
3545
- const urlText = view.state.sliceDoc(url.from, url.to);
3546
- return {
3547
- pos: link.from,
3548
- end: link.to,
3549
- above: true,
3550
- create: () => {
3551
- const el = document.createElement("div");
3552
- el.className = tooltipContent({}, "pli-2 plb-1");
3553
- render(el, urlText);
3554
- return {
3555
- dom: el,
3556
- offset: {
3557
- x: 0,
3558
- y: 4
3559
- }
3560
- };
3561
- }
3562
- };
3563
- });
3564
-
3565
- // packages/ui/react-ui-editor/src/extensions/markdown/table.ts
3566
- import { syntaxTree as syntaxTree5 } from "@codemirror/language";
3567
- import { RangeSetBuilder as RangeSetBuilder3, StateField as StateField6 } from "@codemirror/state";
3568
- import { Decoration as Decoration7, EditorView as EditorView15, WidgetType as WidgetType5 } from "@codemirror/view";
3569
- var table = (options = {}) => {
3570
- return StateField6.define({
3571
- create: (state) => update(state, options),
3572
- update: (_, tr) => update(tr.state, options),
3573
- provide: (field) => EditorView15.decorations.from(field)
3574
- });
3575
- };
3576
- var update = (state, options) => {
3577
- const builder = new RangeSetBuilder3();
3578
- const cursor = state.selection.main.head;
3579
- const tables = [];
3580
- const getTable = () => tables[tables.length - 1];
3581
- const getRow = () => {
3582
- const table2 = getTable();
3583
- return table2.rows?.[table2.rows.length - 1];
3584
- };
3585
- syntaxTree5(state).iterate({
3586
- enter: (node) => {
3587
- switch (node.name) {
3588
- case "Table": {
3589
- tables.push({
3590
- from: node.from,
3591
- to: node.to
3592
- });
3593
- break;
3594
- }
3595
- case "TableHeader": {
3596
- getTable().header = [];
3597
- break;
3598
- }
3599
- case "TableRow": {
3600
- (getTable().rows ??= []).push([]);
3601
- break;
3602
- }
3603
- case "TableCell": {
3604
- const row = getRow();
3605
- if (row) {
3606
- row.push(state.sliceDoc(node.from, node.to));
3607
- } else {
3608
- getTable().header?.push(state.sliceDoc(node.from, node.to));
3609
- }
3610
- break;
3355
+ var useFormattingState = () => {
3356
+ const [state2, setState] = useState();
3357
+ const observer = useMemo(() => EditorView11.updateListener.of((update2) => {
3358
+ if (update2.docChanged || update2.selectionSet) {
3359
+ setState((prevState) => {
3360
+ const newState = getFormatting(update2.state);
3361
+ if (!prevState || !formattingEquals(prevState, newState)) {
3362
+ return newState;
3611
3363
  }
3612
- }
3364
+ return prevState;
3365
+ });
3613
3366
  }
3614
- });
3615
- tables.forEach((table2) => {
3616
- const hide2 = state.readOnly || cursor < table2.from || cursor > table2.to;
3617
- hide2 && builder.add(table2.from, table2.to, Decoration7.replace({
3618
- widget: new TableWidget(table2)
3619
- }));
3620
- builder.add(table2.from, table2.to, Decoration7.mark({
3621
- class: "cm-table"
3622
- }));
3623
- });
3624
- return builder.finish();
3367
+ }), [
3368
+ setState
3369
+ ]);
3370
+ return [
3371
+ state2,
3372
+ observer
3373
+ ];
3625
3374
  };
3626
- var TableWidget = class extends WidgetType5 {
3627
- constructor(_table) {
3628
- super();
3629
- this._table = _table;
3630
- }
3631
- eq(other) {
3632
- return this._table.header?.join() === other._table.header?.join() && this._table.rows?.join() === other._table.rows?.join();
3375
+
3376
+ // packages/ui/react-ui-editor/src/extensions/markdown/action.ts
3377
+ var processAction = (view, action) => {
3378
+ let inlineType, listType;
3379
+ switch (action.type) {
3380
+ case "heading":
3381
+ setHeading(parseInt(action.data))(view);
3382
+ break;
3383
+ case "strong":
3384
+ case "emphasis":
3385
+ case "strikethrough":
3386
+ case "code":
3387
+ inlineType = action.type === "strong" ? Inline.Strong : action.type === "emphasis" ? Inline.Emphasis : action.type === "strikethrough" ? Inline.Strikethrough : Inline.Code;
3388
+ (typeof action.data === "boolean" ? setStyle(inlineType, action.data) : toggleStyle(inlineType))(view);
3389
+ break;
3390
+ case "list-ordered":
3391
+ case "list-bullet":
3392
+ case "list-task":
3393
+ listType = action.type === "list-ordered" ? List.Ordered : action.type === "list-bullet" ? List.Bullet : List.Task;
3394
+ (action.data === false ? removeList(listType) : action.data === true ? addList(listType) : toggleList(listType))(view);
3395
+ break;
3396
+ case "blockquote":
3397
+ (action.data === false ? removeBlockquote : action.data === true ? addBlockquote : toggleBlockquote)(view);
3398
+ break;
3399
+ case "codeblock":
3400
+ (action.data === false ? removeCodeblock : addCodeblock)(view);
3401
+ break;
3402
+ case "table":
3403
+ insertTable(view);
3404
+ break;
3405
+ case "link":
3406
+ (action.data === false ? removeLink : addLink())(view);
3407
+ break;
3408
+ case "image":
3409
+ addLink({
3410
+ url: action.data,
3411
+ image: true
3412
+ })(view);
3413
+ break;
3414
+ case "comment":
3415
+ createComment(view);
3416
+ break;
3633
3417
  }
3634
- toDOM(view) {
3635
- const table2 = document.createElement("table");
3636
- {
3637
- const header = table2.appendChild(document.createElement("thead"));
3638
- const tr = header.appendChild(document.createElement("tr"));
3639
- this._table.header?.forEach((cell) => {
3640
- const th = document.createElement("th");
3641
- th.setAttribute("class", "cm-table-head");
3642
- tr.appendChild(th).textContent = cell;
3643
- });
3644
- }
3645
- {
3646
- const body = table2.appendChild(document.createElement("tbody"));
3647
- this._table.rows?.forEach((row) => {
3648
- const tr = body.appendChild(document.createElement("tr"));
3649
- row.forEach((cell) => {
3650
- const td = document.createElement("td");
3651
- td.setAttribute("class", "cm-table-cell");
3652
- tr.appendChild(td).textContent = cell;
3653
- });
3654
- });
3418
+ requestAnimationFrame(() => {
3419
+ if (!view.hasFocus) {
3420
+ view.focus();
3655
3421
  }
3656
- return table2;
3657
- }
3658
- ignoreEvent(e) {
3659
- return !/^mouse/.test(e.type);
3660
- }
3422
+ });
3661
3423
  };
3662
3424
 
3663
- // packages/ui/react-ui-editor/src/extensions/mention.ts
3664
- import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
3665
- import { log as log6 } from "@dxos/log";
3666
- var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/mention.ts";
3667
- var mention = ({ onSearch }) => {
3668
- return autocompletion2({
3669
- // TODO(burdon): Not working.
3670
- activateOnTyping: true,
3671
- // activateOnTypingDelay: 100,
3672
- // selectOnOpen: true,
3673
- closeOnBlur: false,
3674
- // defaultKeymap: false,
3675
- icons: false,
3676
- override: [
3677
- (context) => {
3678
- log6.info("completion context", {
3679
- context
3680
- }, {
3681
- F: __dxlog_file7,
3682
- L: 26,
3683
- S: void 0,
3684
- C: (f, a) => f(...a)
3685
- });
3686
- const match = context.matchBefore(/@(\w+)?/);
3687
- if (!match || match.from === match.to && !context.explicit) {
3688
- return null;
3689
- }
3690
- return {
3691
- from: match.from,
3692
- options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
3693
- label: `@${value}`
3694
- }))
3695
- };
3696
- }
3425
+ // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
3426
+ import { completionKeymap as completionKeymap2 } from "@codemirror/autocomplete";
3427
+ import { defaultKeymap as defaultKeymap2, indentWithTab as indentWithTab2 } from "@codemirror/commands";
3428
+ import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
3429
+ import { defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
3430
+ import { languages } from "@codemirror/language-data";
3431
+ import { lintKeymap } from "@codemirror/lint";
3432
+ import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
3433
+ import { keymap as keymap7 } from "@codemirror/view";
3434
+
3435
+ // packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
3436
+ import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
3437
+ import { HighlightStyle } from "@codemirror/language";
3438
+ import { tags, styleTags, Tag } from "@lezer/highlight";
3439
+ import { Table } from "@lezer/markdown";
3440
+ var markdownTags = {
3441
+ Blockquote: Tag.define(),
3442
+ CodeMark: Tag.define(),
3443
+ CodeText: Tag.define(),
3444
+ EmphasisMark: Tag.define(),
3445
+ HeaderMark: Tag.define(),
3446
+ InlineCode: Tag.define(),
3447
+ LinkLabel: Tag.define(),
3448
+ LinkReference: Tag.define(),
3449
+ ListMark: Tag.define(),
3450
+ QuoteMark: Tag.define(),
3451
+ URL: Tag.define(),
3452
+ // Custom.
3453
+ TableCell: Tag.define()
3454
+ };
3455
+ Table.defineNodes?.forEach((node) => {
3456
+ switch (node?.name) {
3457
+ case "TableCell": {
3458
+ node.style = markdownTags.TableCell;
3459
+ break;
3460
+ }
3461
+ }
3462
+ });
3463
+ var markdownTagsExtensions = [
3464
+ Table,
3465
+ {
3466
+ props: [
3467
+ styleTags(markdownTags)
3697
3468
  ]
3469
+ }
3470
+ ];
3471
+ var markdownHighlightStyle = (readonly) => {
3472
+ return HighlightStyle.define([
3473
+ {
3474
+ tag: [
3475
+ tags.keyword,
3476
+ tags.name,
3477
+ tags.deleted,
3478
+ tags.character,
3479
+ tags.propertyName,
3480
+ tags.macroName,
3481
+ tags.color,
3482
+ tags.constant(tags.name),
3483
+ tags.standard(tags.name),
3484
+ tags.definition(tags.name),
3485
+ tags.separator,
3486
+ tags.typeName,
3487
+ tags.className,
3488
+ tags.number,
3489
+ tags.changed,
3490
+ tags.annotation,
3491
+ tags.modifier,
3492
+ tags.self,
3493
+ tags.namespace,
3494
+ tags.operator,
3495
+ tags.operatorKeyword,
3496
+ tags.escape,
3497
+ tags.regexp,
3498
+ tags.special(tags.string),
3499
+ tags.meta,
3500
+ tags.comment,
3501
+ tags.atom,
3502
+ tags.bool,
3503
+ tags.special(tags.variableName),
3504
+ tags.processingInstruction,
3505
+ tags.string,
3506
+ tags.inserted,
3507
+ tags.invalid
3508
+ ],
3509
+ color: "inherit !important"
3510
+ },
3511
+ // Markdown marks.
3512
+ {
3513
+ tag: [
3514
+ tags.meta,
3515
+ tags.processingInstruction,
3516
+ markdownTags.LinkLabel,
3517
+ markdownTags.LinkReference,
3518
+ markdownTags.ListMark
3519
+ ],
3520
+ class: mark
3521
+ },
3522
+ // Markdown marks.
3523
+ {
3524
+ tag: [
3525
+ markdownTags.CodeMark,
3526
+ markdownTags.HeaderMark,
3527
+ markdownTags.QuoteMark,
3528
+ markdownTags.EmphasisMark
3529
+ ],
3530
+ class: mark
3531
+ },
3532
+ // E.g., code block language (after ```).
3533
+ {
3534
+ tag: [
3535
+ tags.function(tags.variableName),
3536
+ tags.labelName
3537
+ ],
3538
+ class: codeMark
3539
+ },
3540
+ {
3541
+ tag: [
3542
+ tags.monospace
3543
+ ],
3544
+ class: "font-mono"
3545
+ },
3546
+ // Headings.
3547
+ {
3548
+ tag: tags.heading1,
3549
+ class: heading(1)
3550
+ },
3551
+ {
3552
+ tag: tags.heading2,
3553
+ class: heading(2)
3554
+ },
3555
+ {
3556
+ tag: tags.heading3,
3557
+ class: heading(3)
3558
+ },
3559
+ {
3560
+ tag: tags.heading4,
3561
+ class: heading(4)
3562
+ },
3563
+ {
3564
+ tag: tags.heading5,
3565
+ class: heading(5)
3566
+ },
3567
+ {
3568
+ tag: tags.heading6,
3569
+ class: heading(6)
3570
+ },
3571
+ // Emphasis.
3572
+ {
3573
+ tag: tags.emphasis,
3574
+ class: italic
3575
+ },
3576
+ {
3577
+ tag: tags.strong,
3578
+ class: bold
3579
+ },
3580
+ {
3581
+ tag: tags.strikethrough,
3582
+ class: strikethrough
3583
+ },
3584
+ // Naked URLs.
3585
+ {
3586
+ tag: [
3587
+ markdownTags.URL
3588
+ ],
3589
+ class: inlineUrl
3590
+ },
3591
+ // NOTE: The `markdown` extension configures extensions for `lezer` to parse markdown tokens (incl. below).
3592
+ // However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
3593
+ // when a language is specified. In this case, the syntax highlighting extensions will colorize
3594
+ // the code, but all other CSS properties will be inherited.
3595
+ // IMPORTANT: Therefore, the fenced code block will use the base editor font unless changed by an extension.
3596
+ {
3597
+ tag: [
3598
+ markdownTags.CodeText,
3599
+ markdownTags.InlineCode
3600
+ ],
3601
+ class: code
3602
+ },
3603
+ {
3604
+ tag: [
3605
+ markdownTags.QuoteMark
3606
+ ],
3607
+ class: blockquote
3608
+ },
3609
+ {
3610
+ tag: [
3611
+ markdownTags.TableCell
3612
+ ],
3613
+ class: "font-mono"
3614
+ }
3615
+ ], {
3616
+ scope: markdownLanguage2,
3617
+ all: {
3618
+ fontFamily: getToken("fontFamily.body", []).join(",")
3619
+ }
3698
3620
  });
3699
3621
  };
3700
3622
 
3701
- // packages/ui/react-ui-editor/src/extensions/modes.ts
3702
- import { Facet as Facet6 } from "@codemirror/state";
3703
- import { keymap as keymap7 } from "@codemirror/view";
3704
- import { vim } from "@replit/codemirror-vim";
3705
- var editorMode = Facet6.define({
3706
- combine: (modes) => modes[0] ?? {}
3707
- });
3708
- var EditorModes = {
3709
- default: [],
3710
- vim: [
3711
- vim(),
3712
- editorMode.of({
3713
- type: "vim",
3714
- noTabster: true
3623
+ // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
3624
+ var createMarkdownExtensions = ({ themeMode } = {}) => {
3625
+ return [
3626
+ // Main extension.
3627
+ // https://github.com/codemirror/lang-markdown
3628
+ // https://codemirror.net/5/mode/markdown/index.html (demo).
3629
+ markdown({
3630
+ // GRM by default (vs strict CommonMark):
3631
+ // Table, TaskList, Strikethrough, and Autolink.
3632
+ // NOTE: This extends the parser; it doesn't affect rendering.
3633
+ // https://github.github.com/gfm
3634
+ // https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
3635
+ base: markdownLanguage3,
3636
+ // Languages for syntax highlighting fenced code blocks.
3637
+ codeLanguages: languages,
3638
+ // Parser extensions.
3639
+ extensions: [
3640
+ // GFM provided by default.
3641
+ markdownTagsExtensions
3642
+ ]
3715
3643
  }),
3644
+ // https://github.com/codemirror/theme-one-dark
3645
+ themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle),
3646
+ // Custom styles.
3647
+ syntaxHighlighting(markdownHighlightStyle()),
3716
3648
  keymap7.of([
3717
- {
3718
- key: "Alt-Escape",
3719
- run: (view) => {
3720
- view.dispatch({
3721
- userEvent: "focus.container"
3722
- });
3723
- return true;
3724
- }
3725
- }
3726
- ])
3727
- ]
3728
- };
3729
-
3730
- // packages/ui/react-ui-editor/src/extensions/outliner.ts
3731
- var outliner = (options = {}) => {
3732
- return [];
3733
- };
3734
-
3735
- // packages/ui/react-ui-editor/src/extensions/typewriter.ts
3736
- import { keymap as keymap8 } from "@codemirror/view";
3737
- var defaultItems = [
3738
- "hello world!",
3739
- "this is a test.",
3740
- "this is [DXOS](https://dxos.org)"
3741
- ];
3742
- var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
3743
- let t;
3744
- let idx = 0;
3745
- return [
3746
- keymap8.of([
3747
- {
3748
- // Reset.
3749
- key: "alt-meta-'",
3750
- run: (view) => {
3751
- clearTimeout(t);
3752
- idx = 0;
3753
- return true;
3754
- }
3755
- },
3756
- {
3757
- // Next prompt.
3758
- // TODO(burdon): Press 1-9 to select prompt?
3759
- key: "shift-meta-'",
3760
- run: (view) => {
3761
- clearTimeout(t);
3762
- const text = items[idx++];
3763
- if (idx === items?.length) {
3764
- idx = 0;
3765
- }
3766
- let i = 0;
3767
- const insert = (d = 0) => {
3768
- t = setTimeout(() => {
3769
- const pos = view.state.selection.main.head;
3770
- view.dispatch({
3771
- changes: {
3772
- from: pos,
3773
- insert: text[i++]
3774
- },
3775
- selection: {
3776
- anchor: pos + 1
3777
- }
3778
- });
3779
- if (i < text.length) {
3780
- insert(Math.random() * delay * (text[i] === " " ? 2 : 1));
3781
- }
3782
- }, d);
3783
- };
3784
- insert();
3785
- return true;
3786
- }
3787
- }
3649
+ // https://codemirror.net/docs/ref/#commands.indentWithTab
3650
+ indentWithTab2,
3651
+ // https://codemirror.net/docs/ref/#commands.defaultKeymap
3652
+ ...defaultKeymap2,
3653
+ ...completionKeymap2,
3654
+ ...lintKeymap
3788
3655
  ])
3789
3656
  ];
3790
3657
  };
3791
3658
 
3792
- // packages/ui/react-ui-editor/src/hooks/awareness-provider.ts
3793
- import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
3794
- import { Context as Context2 } from "@dxos/context";
3795
- import { invariant as invariant2 } from "@dxos/invariant";
3796
- import { log as log7 } from "@dxos/log";
3797
- var __dxlog_file8 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
3798
- var DEBOUNCE_INTERVAL = 100;
3799
- var SpaceAwarenessProvider = class {
3800
- constructor(params) {
3801
- this._remoteStates = /* @__PURE__ */ new Map();
3802
- this.remoteStateChange = new Event2();
3803
- this._space = params.space;
3804
- this._channel = params.channel;
3805
- this._peerId = params.peerId;
3806
- this._info = params.info;
3659
+ // packages/ui/react-ui-editor/src/extensions/markdown/decorate.ts
3660
+ import { syntaxTree as syntaxTree2 } from "@codemirror/language";
3661
+ import { RangeSetBuilder as RangeSetBuilder2, StateEffect as StateEffect4 } from "@codemirror/state";
3662
+ import { EditorView as EditorView12, Decoration as Decoration5, WidgetType as WidgetType3, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
3663
+ import { mx as mx2 } from "@dxos/react-ui-theme";
3664
+ var HorizontalRuleWidget = class extends WidgetType3 {
3665
+ toDOM() {
3666
+ const el = document.createElement("span");
3667
+ el.className = "cm-hr";
3668
+ return el;
3807
3669
  }
3808
- open() {
3809
- this._ctx = new Context2();
3810
- this._postTask = new DeferredTask(this._ctx, async () => {
3811
- if (this._localState) {
3812
- await this._space.postMessage(this._channel, {
3813
- kind: "post",
3814
- state: this._localState
3815
- });
3816
- await sleep(DEBOUNCE_INTERVAL);
3817
- }
3818
- });
3819
- this._ctx.onDispose(this._space.listen(this._channel, (message) => {
3820
- switch (message.payload.kind) {
3821
- case "query": {
3822
- this._handleQueryMessage();
3823
- break;
3824
- }
3825
- case "post": {
3826
- this._handlePostMessage(message.payload);
3827
- break;
3828
- }
3829
- }
3830
- }));
3831
- void this._space.postMessage(this._channel, {
3832
- kind: "query"
3833
- }).catch((err) => {
3834
- log7.debug("failed to query awareness", {
3835
- err
3836
- }, {
3837
- F: __dxlog_file8,
3838
- L: 89,
3839
- S: this,
3840
- C: (f, a) => f(...a)
3841
- });
3842
- });
3670
+ };
3671
+ var LinkButton = class extends WidgetType3 {
3672
+ constructor(url, render) {
3673
+ super();
3674
+ this.url = url;
3675
+ this.render = render;
3843
3676
  }
3844
- close() {
3845
- void this._ctx?.dispose();
3846
- this._ctx = void 0;
3847
- this._postTask = void 0;
3677
+ eq(other) {
3678
+ return this.url === other.url;
3848
3679
  }
3849
- getRemoteStates() {
3850
- return Array.from(this._remoteStates.values());
3680
+ toDOM(view) {
3681
+ const el = document.createElement("span");
3682
+ this.render(el, this.url);
3683
+ return el;
3851
3684
  }
3852
- update(position) {
3853
- invariant2(this._postTask, void 0, {
3854
- F: __dxlog_file8,
3855
- L: 104,
3856
- S: this,
3857
- A: [
3858
- "this._postTask",
3859
- ""
3860
- ]
3861
- });
3862
- this._localState = {
3863
- peerId: this._peerId,
3864
- position,
3865
- info: this._info
3866
- };
3867
- this._postTask.schedule();
3685
+ };
3686
+ var CheckboxWidget = class extends WidgetType3 {
3687
+ constructor(_checked) {
3688
+ super();
3689
+ this._checked = _checked;
3868
3690
  }
3869
- _handleQueryMessage() {
3870
- invariant2(this._postTask, void 0, {
3871
- F: __dxlog_file8,
3872
- L: 115,
3873
- S: this,
3874
- A: [
3875
- "this._postTask",
3876
- ""
3877
- ]
3878
- });
3879
- this._postTask.schedule();
3691
+ eq(other) {
3692
+ return this._checked === other._checked;
3693
+ }
3694
+ toDOM(view) {
3695
+ const input = document.createElement("input");
3696
+ input.className = "cm-task-checkbox ch-checkbox ch-focus-ring -mbs-0.5";
3697
+ input.type = "checkbox";
3698
+ input.checked = this._checked;
3699
+ if (view.state.readOnly) {
3700
+ input.setAttribute("disabled", "true");
3701
+ } else {
3702
+ input.onmousedown = (event) => {
3703
+ const pos = view.posAtDOM(input);
3704
+ const text = view.state.sliceDoc(pos, pos + 3);
3705
+ if (text === (this._checked ? "[x]" : "[ ]")) {
3706
+ view.dispatch({
3707
+ changes: {
3708
+ from: pos + 1,
3709
+ to: pos + 2,
3710
+ insert: this._checked ? " " : "x"
3711
+ }
3712
+ });
3713
+ event.preventDefault();
3714
+ }
3715
+ };
3716
+ }
3717
+ return input;
3880
3718
  }
3881
- _handlePostMessage(message) {
3882
- invariant2(message.kind === "post", void 0, {
3883
- F: __dxlog_file8,
3884
- L: 120,
3885
- S: this,
3886
- A: [
3887
- "message.kind === 'post'",
3888
- ""
3889
- ]
3890
- });
3891
- this._remoteStates.set(message.state.peerId, message.state);
3892
- this.remoteStateChange.emit();
3719
+ ignoreEvent() {
3720
+ return false;
3893
3721
  }
3894
3722
  };
3895
-
3896
- // packages/ui/react-ui-editor/src/hooks/useActionHandler.ts
3897
- var useActionHandler = (view) => {
3898
- return (action) => {
3899
- if (!view) {
3900
- return;
3901
- }
3902
- let inlineType, listType;
3903
- switch (action.type) {
3904
- case "heading":
3905
- setHeading(parseInt(action.data))(view);
3906
- break;
3907
- case "strong":
3908
- case "emphasis":
3909
- case "strikethrough":
3910
- case "code":
3911
- inlineType = action.type === "strong" ? Inline.Strong : action.type === "emphasis" ? Inline.Emphasis : action.type === "strikethrough" ? Inline.Strikethrough : Inline.Code;
3912
- (typeof action.data === "boolean" ? setStyle(inlineType, action.data) : toggleStyle(inlineType))(view);
3913
- break;
3914
- case "list-ordered":
3915
- case "list-bullet":
3916
- case "list-task":
3917
- listType = action.type === "list-ordered" ? List.Ordered : action.type === "list-bullet" ? List.Bullet : List.Task;
3918
- (action.data === false ? removeList(listType) : action.data === true ? addList(listType) : toggleList(listType))(view);
3919
- break;
3920
- case "blockquote":
3921
- (action.data === false ? removeBlockquote : action.data === true ? addBlockquote : toggleBlockquote)(view);
3922
- break;
3923
- case "codeblock":
3924
- (action.data === false ? removeCodeblock : addCodeblock)(view);
3925
- break;
3926
- case "table":
3927
- insertTable(view);
3928
- break;
3929
- case "link":
3930
- (action.data === false ? removeLink : addLink)(view);
3931
- break;
3932
- case "comment":
3933
- createComment(view);
3934
- break;
3935
- }
3936
- setTimeout(() => {
3937
- if (!view.hasFocus) {
3938
- view.focus();
3939
- }
3940
- });
3941
- };
3942
- };
3943
-
3944
- // packages/ui/react-ui-editor/src/hooks/useEditorView.ts
3945
- import { useRef, useState as useState2 } from "react";
3946
- var useEditorView = (id) => {
3947
- const editorRef = useRef(null);
3948
- const [prev, setPrev] = useState2([
3949
- null,
3950
- ""
3951
- ]);
3952
- if (prev[0] !== editorRef.current) {
3953
- setPrev([
3954
- editorRef.current,
3955
- id
3956
- ]);
3957
- }
3958
- return [
3959
- editorRef,
3960
- prev[1] !== id
3961
- ];
3723
+ var hide = Decoration5.replace({});
3724
+ var fencedCodeLine = Decoration5.line({
3725
+ class: mx2("cm-code cm-codeblock-line")
3726
+ });
3727
+ var fencedCodeLineFirst = Decoration5.line({
3728
+ class: mx2("cm-code cm-codeblock-line", "cm-codeblock-first")
3729
+ });
3730
+ var fencedCodeLineLast = Decoration5.line({
3731
+ class: mx2("cm-code cm-codeblock-line", "cm-codeblock-last")
3732
+ });
3733
+ var horizontalRule = Decoration5.replace({
3734
+ widget: new HorizontalRuleWidget()
3735
+ });
3736
+ var checkedTask = Decoration5.replace({
3737
+ widget: new CheckboxWidget(true)
3738
+ });
3739
+ var uncheckedTask = Decoration5.replace({
3740
+ widget: new CheckboxWidget(false)
3741
+ });
3742
+ var editingRange = (state2, range, focus) => {
3743
+ const { readOnly, selection: { main: { head } } } = state2;
3744
+ return focus && !readOnly && head >= range.from && head <= range.to;
3962
3745
  };
3963
-
3964
- // packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
3965
- import { closeBrackets as closeBrackets2 } from "@codemirror/autocomplete";
3966
- import { history as history2 } from "@codemirror/commands";
3967
- import { bracketMatching as bracketMatching2 } from "@codemirror/language";
3968
- import { EditorSelection as EditorSelection2, EditorState as EditorState2 } from "@codemirror/state";
3969
- import { crosshairCursor, drawSelection as drawSelection2, dropCursor as dropCursor2, EditorView as EditorView16, highlightActiveLine, lineNumbers, placeholder as placeholder2, scrollPastEnd } from "@codemirror/view";
3970
- import defaultsDeep2 from "lodash.defaultsdeep";
3971
- import { useEffect as useEffect2, useRef as useRef2, useState as useState3 } from "react";
3972
- import { log as log8 } from "@dxos/log";
3973
- import { isNotFalsy as isNotFalsy3 } from "@dxos/util";
3974
-
3975
- // packages/ui/react-ui-editor/src/themes/default.ts
3976
- import get4 from "lodash.get";
3977
- var defaultTheme = {
3978
- //
3979
- // Main layout:
3980
- // https://codemirror.net/examples/styling
3981
- //
3982
- // <div class="cm-editor [cm-focused] [generated classes]">
3983
- // <div class="cm-scroller">
3984
- // <div class="cm-gutters">
3985
- // <div class="cm-gutter [...]">
3986
- // <div class="cm-gutterElement">...</div>
3987
- // </div>
3988
- // </div>
3989
- // <div class="cm-content" role="textbox" contenteditable="true">
3990
- // <div class="cm-line"></div>
3991
- // </div>
3992
- // <div class="cm-selectionLayer">
3993
- // <div class="cm-selectionBackground"></div>
3994
- // </div>
3995
- // <div class="cm-cursorLayer">
3996
- // <div class="cm-cursor"></div>
3997
- // </div>
3998
- // </div>
3999
- // </div>
4000
- //
4001
- "&": {},
4002
- "&.cm-focused": {
4003
- outline: "none"
4004
- },
4005
- // NOTE: See https://codemirror.net/docs/guide (DOM Structure).
4006
- ".cm-scroller": {
4007
- // TODO(burdon): Reconcile with docs: https://codemirror.net/docs/guide
4008
- // Inside of that is the scroller element. If the editor has its own scrollbar, this one should be styled with overflow: auto. But it doesn't have to—the editor also supports growing to accomodate its content, or growing up to a certain max-height and then scrolling.
4009
- overflowY: "auto",
4010
- fontFamily: get4(tokens, "fontFamily.mono", []).join(","),
4011
- lineHeight: 1.5
4012
- },
4013
- ".cm-content": {
4014
- // TODO(burdon): Is it possible to remove the padding value from CM's default theme?
4015
- // padding: 'unset',
4016
- // NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
4017
- fontSize: "16px"
4018
- },
4019
- "&light .cm-content": {
4020
- color: get4(tokens, "extend.semanticColors.base.fg.light", "black"),
4021
- caretColor: "black"
4022
- },
4023
- "&dark .cm-content": {
4024
- color: get4(tokens, "extend.semanticColors.base.fg.dark", "white"),
4025
- caretColor: "white"
4026
- },
4027
- //
4028
- // Cursor
4029
- //
4030
- "&light .cm-cursor, &light .cm-dropCursor": {
4031
- borderLeft: "2px solid black"
4032
- },
4033
- "&dark .cm-cursor, &dark .cm-dropCursor": {
4034
- borderLeft: "2px solid white"
4035
- },
4036
- "&light .cm-placeholder": {
4037
- color: get4(tokens, "extend.semanticColors.description.light", "rgba(0,0,0,.2)")
4038
- },
4039
- "&dark .cm-placeholder": {
4040
- color: get4(tokens, "extend.semanticColors.description.dark", "rgba(255,255,255,.2)")
4041
- },
4042
- //
4043
- // line
4044
- //
4045
- ".cm-line": {
4046
- paddingInline: 0
4047
- },
4048
- ".cm-activeLine": {
4049
- background: "transparent"
4050
- },
4051
- //
4052
- // gutter
4053
- //
4054
- ".cm-gutterElement": {
4055
- width: "48px"
4056
- },
4057
- //
4058
- // Selection
4059
- //
4060
- "&light .cm-selectionBackground": {
4061
- background: get4(tokens, "extend.colors.primary.100")
4062
- },
4063
- "&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
4064
- background: get4(tokens, "extend.colors.primary.200")
4065
- },
4066
- "&dark .cm-selectionBackground": {
4067
- background: get4(tokens, "extend.colors.primary.700")
4068
- },
4069
- "&dark.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
4070
- background: get4(tokens, "extend.colors.primary.600")
4071
- },
4072
- //
4073
- // Search
4074
- //
4075
- "&light .cm-searchMatch": {
4076
- backgroundColor: get4(tokens, "extend.colors.yellow.100")
4077
- },
4078
- "&dark .cm-searchMatch": {
4079
- backgroundColor: get4(tokens, "extend.colors.yellow.700")
4080
- },
4081
- //
4082
- // link
4083
- //
4084
- ".cm-link": {
4085
- color: get4(tokens, "extend.colors.primary.500"),
4086
- textDecorationLine: "underline",
4087
- textDecorationThickness: "1px",
4088
- textUnderlineOffset: "2px",
4089
- borderRadius: ".125rem",
4090
- fontFamily: get4(tokens, "fontFamily.body", []).join(",")
4091
- },
4092
- //
4093
- // tooltip
4094
- //
4095
- ".cm-tooltip": {
4096
- border: "none",
4097
- background: "unset"
4098
- },
4099
- ".cm-tooltip-below": {},
4100
- //
4101
- // autocomplete
4102
- //
4103
- ".cm-tooltip-autocomplete": {
4104
- marginTop: "4px",
4105
- marginLeft: "-3px"
4106
- },
4107
- ".cm-tooltip-autocomplete ul li": {},
4108
- ".cm-tooltip-autocomplete ul li[aria-selected]": {},
4109
- ".cm-completionIcon": {
4110
- display: "none"
4111
- },
4112
- ".cm-completionLabel": {
4113
- fontFamily: get4(tokens, "fontFamily.body", []).join(",")
3746
+ var MarksByParent = /* @__PURE__ */ new Set([
3747
+ "CodeMark",
3748
+ "EmphasisMark",
3749
+ "StrikethroughMark",
3750
+ "SubscriptMark",
3751
+ "SuperscriptMark"
3752
+ ]);
3753
+ var buildDecorations = (view, options, focus) => {
3754
+ const deco = new RangeSetBuilder2();
3755
+ const atomicDeco = new RangeSetBuilder2();
3756
+ const { state: state2 } = view;
3757
+ for (const { from, to } of view.visibleRanges) {
3758
+ syntaxTree2(state2).iterate({
3759
+ from,
3760
+ to,
3761
+ enter: (node) => {
3762
+ if (node.name === "FencedCode") {
3763
+ const editing = editingRange(state2, node, focus);
3764
+ for (const block of view.viewportLineBlocks) {
3765
+ if (block.to < node.from) {
3766
+ continue;
3767
+ }
3768
+ if (block.from > node.to) {
3769
+ break;
3770
+ }
3771
+ const first = block.from <= node.from;
3772
+ const last = block.to >= node.to && /^(\s>)*```$/.test(state2.doc.sliceString(block.from, block.to));
3773
+ deco.add(block.from, block.from, first ? fencedCodeLineFirst : last ? fencedCodeLineLast : fencedCodeLine);
3774
+ if (!editing && (first || last)) {
3775
+ atomicDeco.add(block.from, block.to, hide);
3776
+ }
3777
+ }
3778
+ return false;
3779
+ } else if (node.name === "Link") {
3780
+ const marks = node.node.getChildren("LinkMark");
3781
+ const urlNode = node.node.getChild("URL");
3782
+ const editing = editingRange(state2, node, focus);
3783
+ if (urlNode && marks.length >= 2) {
3784
+ const url = state2.sliceDoc(urlNode.from, urlNode.to);
3785
+ if (!editing) {
3786
+ atomicDeco.add(node.from, marks[0].to, hide);
3787
+ }
3788
+ deco.add(marks[0].to, marks[1].from, Decoration5.mark({
3789
+ tagName: "a",
3790
+ attributes: {
3791
+ class: "cm-link",
3792
+ href: url,
3793
+ rel: "noreferrer",
3794
+ target: "_blank"
3795
+ }
3796
+ }));
3797
+ if (!editing) {
3798
+ atomicDeco.add(marks[1].from, node.to, options.renderLinkButton ? Decoration5.replace({
3799
+ widget: new LinkButton(url, options.renderLinkButton)
3800
+ }) : hide);
3801
+ }
3802
+ }
3803
+ } else if (node.name === "HeaderMark") {
3804
+ const parent = node.node.parent;
3805
+ if (/^ATX/.test(parent.name) && !editingRange(state2, state2.doc.lineAt(node.from), focus)) {
3806
+ const next = state2.doc.sliceString(node.to, node.to + 1);
3807
+ atomicDeco.add(node.from, node.to + (next === " " ? 1 : 0), hide);
3808
+ }
3809
+ } else if (node.name === "HorizontalRule") {
3810
+ if (!editingRange(state2, node, focus)) {
3811
+ deco.add(node.from, node.to, horizontalRule);
3812
+ }
3813
+ } else if (node.name === "TaskMarker") {
3814
+ if (!editingRange(state2, node, focus)) {
3815
+ const checked = state2.doc.sliceString(node.from + 1, node.to - 1) === "x";
3816
+ atomicDeco.add(node.from - 2, node.from - 1, Decoration5.mark({
3817
+ class: "cm-task"
3818
+ }));
3819
+ atomicDeco.add(node.from, node.to, checked ? checkedTask : uncheckedTask);
3820
+ }
3821
+ } else if (MarksByParent.has(node.name)) {
3822
+ if (!editingRange(state2, node.node.parent, focus)) {
3823
+ atomicDeco.add(node.from, node.to, hide);
3824
+ }
3825
+ }
3826
+ }
3827
+ });
3828
+ }
3829
+ return {
3830
+ deco: deco.finish(),
3831
+ atomicDeco: atomicDeco.finish()
3832
+ };
3833
+ };
3834
+ var forceUpdate = StateEffect4.define();
3835
+ var decorateMarkdown = (options = {}) => {
3836
+ return [
3837
+ ViewPlugin4.fromClass(class {
3838
+ constructor(view) {
3839
+ ({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations(view, options, view.hasFocus));
3840
+ }
3841
+ update(update2) {
3842
+ if (update2.docChanged || update2.viewportChanged || update2.focusChanged || update2.transactions.some((tr) => tr.effects.some((e) => e.is(forceUpdate))) || update2.selectionSet && !options.selectionChangeDelay) {
3843
+ ({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations(update2.view, options, update2.view.hasFocus));
3844
+ this.clearUpdate();
3845
+ } else if (update2.selectionSet) {
3846
+ this.scheduleUpdate(update2.view);
3847
+ }
3848
+ }
3849
+ // TODO(burdon): BUG: If the cursor is at the end of a link at the end of a line,
3850
+ // the cursor will float in space or be in the wrong position after the decoration is applied.
3851
+ scheduleUpdate(view) {
3852
+ this.clearUpdate();
3853
+ this.pendingUpdate = setTimeout(() => {
3854
+ view.dispatch({
3855
+ effects: forceUpdate.of(null)
3856
+ });
3857
+ }, options.selectionChangeDelay);
3858
+ }
3859
+ clearUpdate() {
3860
+ if (this.pendingUpdate) {
3861
+ clearTimeout(this.pendingUpdate);
3862
+ this.pendingUpdate = void 0;
3863
+ }
3864
+ }
3865
+ destroy() {
3866
+ this.clearUpdate();
3867
+ }
3868
+ }, {
3869
+ provide: (plugin) => [
3870
+ EditorView12.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration5.none),
3871
+ EditorView12.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration5.none),
3872
+ EditorView12.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration5.none)
3873
+ ]
3874
+ }),
3875
+ formattingStyles
3876
+ ];
3877
+ };
3878
+ var formattingStyles = EditorView12.baseTheme({
3879
+ "& .cm-code": {
3880
+ fontFamily: getToken("fontFamily.mono", []).join(",")
4114
3881
  },
4115
- ".cm-completionMatchedText": {
4116
- textDecoration: "none"
3882
+ "& .cm-codeblock-line": {
3883
+ paddingInline: "1rem !important"
4117
3884
  },
4118
- //
4119
- // table
4120
- //
4121
- ".cm-table *": {
4122
- fontFamily: `${get4(tokens, "fontFamily.mono", []).join(",")} !important`,
4123
- textDecoration: "none !important"
3885
+ "& .cm-codeblock-end": {
3886
+ display: "inline-block",
3887
+ width: "100%",
3888
+ position: "relative",
3889
+ "&::after": {
3890
+ position: "absolute",
3891
+ inset: 0,
3892
+ content: '""'
3893
+ }
4124
3894
  },
4125
- ".cm-table-head": {
4126
- padding: "2px 16px 2px 0px",
4127
- borderBottom: `1px solid ${get4(tokens, "extend.colors.neutral.500")}`,
4128
- fontWeight: 100,
4129
- textAlign: "left",
4130
- color: get4(tokens, "extend.colors.neutral.500")
3895
+ "& .cm-codeblock-first": {
3896
+ borderTopLeftRadius: ".5rem",
3897
+ borderTopRightRadius: ".5rem"
4131
3898
  },
4132
- ".cm-table-cell": {
4133
- padding: "2px 16px 2px 0px"
3899
+ "& .cm-codeblock-last": {
3900
+ borderBottomLeftRadius: ".5rem",
3901
+ borderBottomRightRadius: ".5rem"
4134
3902
  },
4135
- //
4136
- // image
4137
- //
4138
- ".cm-image": {
4139
- display: "block",
4140
- height: "0"
3903
+ "&light .cm-codeblock-line, &light .cm-activeLine.cm-codeblock-line": {
3904
+ background: getToken("extend.semanticColors.input.light"),
3905
+ mixBlendMode: "darken"
4141
3906
  },
4142
- ".cm-image.cm-loaded-image": {
4143
- height: "auto",
4144
- borderTop: "0.5rem solid transparent",
4145
- borderBottom: "0.5rem solid transparent"
3907
+ "&dark .cm-codeblock-line, &dark .cm-activeLine.cm-codeblock-line": {
3908
+ background: getToken("extend.semanticColors.input.dark"),
3909
+ mixBlendMode: "lighten"
4146
3910
  },
4147
- //
4148
- // font size
4149
- // TODO(thure): This appears to be the best or only way to set selection caret heights,
4150
- // but it's far more verbose than it needs to be.
4151
- //
4152
- // ...Object.keys(get(tokens, 'extend.fontSize', {})).reduce((acc: Record<string, any>, fontSize) => {
4153
- // const height = get(tokens, ['extend', 'fontSize', fontSize, 1, 'lineHeight']);
4154
- //
4155
- // acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = { height };
4156
- // acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = { height };
4157
- // acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = { height };
4158
- // return acc;
4159
- // }, {}),
4160
- /**
4161
- * Panels
4162
- * TODO(burdon): Needs styling attention (esp. dark mode).
4163
- * https://github.com/codemirror/search/blob/main/src/search.ts#L745
4164
- *
4165
- * Find/replace panel.
4166
- * <div class="cm-announced">...</div>
4167
- * <div class="cm-scroller">...</div>
4168
- * <div class="cm-panels cm-panels-bottom">
4169
- * <div class="cm-search cm-panel">
4170
- * <input class="cm-textfield" />
4171
- * <button class="cm-button">...</button>
4172
- * <label><input type="checkbox" />...</label>
4173
- * </div>
4174
- * </div
4175
- */
4176
- ".cm-panels": {
4177
- border: `1px solid ${get4(tokens, "extend.colors.neutral.200")}`
3911
+ "& .cm-hr": {
3912
+ display: "inline-block",
3913
+ width: "100%",
3914
+ height: "0",
3915
+ verticalAlign: "middle",
3916
+ borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
4178
3917
  },
4179
- ".cm-panel": {
4180
- background: get4(tokens, "extend.colors.neutral.50"),
4181
- fontFamily: get4(tokens, "fontFamily.body", []).join(",")
3918
+ "& .cm-task": {
3919
+ color: getToken("extend.colors.blue.500")
4182
3920
  },
4183
- ".cm-button": {
4184
- margin: "4px",
4185
- fontFamily: get4(tokens, "fontFamily.body", []).join(","),
4186
- background: get4(tokens, "extend.colors.neutral.100"),
4187
- backgroundImage: "none",
4188
- border: "none",
4189
- "&:hover": {
4190
- background: get4(tokens, "extend.colors.neutral.200")
3921
+ "& .cm-task-checkbox": {
3922
+ marginLeft: "4px",
3923
+ marginRight: "4px"
3924
+ }
3925
+ });
3926
+
3927
+ // packages/ui/react-ui-editor/src/extensions/markdown/image.ts
3928
+ import { syntaxTree as syntaxTree3 } from "@codemirror/language";
3929
+ import { StateField as StateField5 } from "@codemirror/state";
3930
+ import { Decoration as Decoration6, EditorView as EditorView13, WidgetType as WidgetType4 } from "@codemirror/view";
3931
+ var image = (options = {}) => {
3932
+ return StateField5.define({
3933
+ create: (state2) => {
3934
+ return Decoration6.set(buildDecorations2(0, state2.doc.length, state2));
4191
3935
  },
4192
- "&:active": {
4193
- background: get4(tokens, "extend.colors.neutral.300"),
4194
- backgroundImage: "none"
3936
+ update: (value, tr) => {
3937
+ if (!tr.docChanged && !tr.selection) {
3938
+ return value;
3939
+ }
3940
+ const cursor = tr.state.selection.main.head;
3941
+ const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
3942
+ let from = Math.min(cursor, oldCursor);
3943
+ let to = Math.max(cursor, oldCursor);
3944
+ tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
3945
+ from = Math.min(from, fromB);
3946
+ to = Math.max(to, toB);
3947
+ });
3948
+ from = tr.state.doc.lineAt(from).from;
3949
+ to = tr.state.doc.lineAt(to).to;
3950
+ return value.map(tr.changes).update({
3951
+ filterFrom: from,
3952
+ filterTo: to,
3953
+ filter: () => false,
3954
+ add: buildDecorations2(from, to, tr.state)
3955
+ });
3956
+ },
3957
+ provide: (field) => EditorView13.decorations.from(field)
3958
+ });
3959
+ };
3960
+ var preloaded = /* @__PURE__ */ new Set();
3961
+ var preloadImage = (url) => {
3962
+ if (!preloaded.has(url)) {
3963
+ const img = document.createElement("img");
3964
+ img.src = url;
3965
+ preloaded.add(url);
3966
+ }
3967
+ };
3968
+ var buildDecorations2 = (from, to, state2) => {
3969
+ const decorations = [];
3970
+ const cursor = state2.selection.main.head;
3971
+ syntaxTree3(state2).iterate({
3972
+ enter: (node) => {
3973
+ if (node.name === "Image") {
3974
+ const urlNode = node.node.getChild("URL");
3975
+ if (urlNode) {
3976
+ const hide2 = state2.readOnly || cursor < node.from || cursor > node.to;
3977
+ const url = state2.sliceDoc(urlNode.from, urlNode.to);
3978
+ preloadImage(url);
3979
+ decorations.push(Decoration6.replace({
3980
+ block: true,
3981
+ widget: new ImageWidget(url)
3982
+ }).range(hide2 ? node.from : node.to, node.to));
3983
+ }
3984
+ }
3985
+ },
3986
+ from,
3987
+ to
3988
+ });
3989
+ return decorations;
3990
+ };
3991
+ var ImageWidget = class extends WidgetType4 {
3992
+ constructor(_url) {
3993
+ super();
3994
+ this._url = _url;
3995
+ }
3996
+ eq(other) {
3997
+ return this._url === other._url;
3998
+ }
3999
+ toDOM(view) {
4000
+ const img = document.createElement("img");
4001
+ img.setAttribute("src", this._url);
4002
+ img.setAttribute("class", "cm-image");
4003
+ img.onload = () => img.classList.add("cm-loaded-image");
4004
+ return img;
4005
+ }
4006
+ };
4007
+ var imageUpload = (options = {}) => {
4008
+ };
4009
+
4010
+ // packages/ui/react-ui-editor/src/extensions/markdown/link.ts
4011
+ import { syntaxTree as syntaxTree4 } from "@codemirror/language";
4012
+ import { hoverTooltip as hoverTooltip2 } from "@codemirror/view";
4013
+ import { tooltipContent } from "@dxos/react-ui-theme";
4014
+ var linkTooltip = (render) => hoverTooltip2((view, pos, side) => {
4015
+ const syntax = syntaxTree4(view.state).resolveInner(pos, side);
4016
+ let link = null;
4017
+ for (let i = 0, node = syntax; !link && node && i < 5; node = node.parent, i++) {
4018
+ link = node.name === "Link" ? node : null;
4019
+ }
4020
+ const url = link && link.getChild("URL");
4021
+ if (!url || !link) {
4022
+ return null;
4023
+ }
4024
+ const urlText = view.state.sliceDoc(url.from, url.to);
4025
+ return {
4026
+ pos: link.from,
4027
+ end: link.to,
4028
+ above: true,
4029
+ create: () => {
4030
+ const el = document.createElement("div");
4031
+ el.className = tooltipContent({}, "pli-2 plb-1");
4032
+ render(el, urlText);
4033
+ return {
4034
+ dom: el,
4035
+ offset: {
4036
+ x: 0,
4037
+ y: 4
4038
+ }
4039
+ };
4195
4040
  }
4196
- },
4197
- ".cm-panel input[type=checkbox]": {
4198
- marginRight: "0.4rem !important"
4199
- }
4041
+ };
4042
+ });
4043
+
4044
+ // packages/ui/react-ui-editor/src/extensions/markdown/table.ts
4045
+ import { syntaxTree as syntaxTree5 } from "@codemirror/language";
4046
+ import { RangeSetBuilder as RangeSetBuilder3, StateField as StateField6 } from "@codemirror/state";
4047
+ import { Decoration as Decoration7, EditorView as EditorView14, WidgetType as WidgetType5 } from "@codemirror/view";
4048
+ var table = (options = {}) => {
4049
+ return StateField6.define({
4050
+ create: (state2) => update(state2, options),
4051
+ update: (_, tr) => update(tr.state, options),
4052
+ provide: (field) => EditorView14.decorations.from(field)
4053
+ });
4200
4054
  };
4201
- var textTheme = {
4202
- ".cm-scroller": {
4203
- fontFamily: get4(tokens, "fontFamily.body", []).join(",")
4204
- },
4205
- ".cm-placeholder": {
4206
- fontFamily: get4(tokens, "fontFamily.body", []).join(",")
4207
- }
4055
+ var update = (state2, options) => {
4056
+ const builder = new RangeSetBuilder3();
4057
+ const cursor = state2.selection.main.head;
4058
+ const tables = [];
4059
+ const getTable = () => tables[tables.length - 1];
4060
+ const getRow = () => {
4061
+ const table2 = getTable();
4062
+ return table2.rows?.[table2.rows.length - 1];
4063
+ };
4064
+ syntaxTree5(state2).iterate({
4065
+ enter: (node) => {
4066
+ switch (node.name) {
4067
+ case "Table": {
4068
+ tables.push({
4069
+ from: node.from,
4070
+ to: node.to
4071
+ });
4072
+ break;
4073
+ }
4074
+ case "TableHeader": {
4075
+ getTable().header = [];
4076
+ break;
4077
+ }
4078
+ case "TableRow": {
4079
+ (getTable().rows ??= []).push([]);
4080
+ break;
4081
+ }
4082
+ case "TableCell": {
4083
+ const row = getRow();
4084
+ if (row) {
4085
+ row.push(state2.sliceDoc(node.from, node.to));
4086
+ } else {
4087
+ getTable().header?.push(state2.sliceDoc(node.from, node.to));
4088
+ }
4089
+ break;
4090
+ }
4091
+ }
4092
+ }
4093
+ });
4094
+ tables.forEach((table2) => {
4095
+ const hide2 = state2.readOnly || cursor < table2.from || cursor > table2.to;
4096
+ if (hide2) {
4097
+ builder.add(table2.from, table2.to, Decoration7.replace({
4098
+ widget: new TableWidget(table2)
4099
+ }));
4100
+ }
4101
+ builder.add(table2.from, table2.to, Decoration7.mark({
4102
+ class: "cm-table"
4103
+ }));
4104
+ });
4105
+ return builder.finish();
4208
4106
  };
4209
- var markdownTheme = {
4210
- ".cm-scroller": {
4211
- fontFamily: get4(tokens, "fontFamily.body", []).join(",")
4212
- },
4213
- ".cm-placeholder": {
4214
- fontFamily: get4(tokens, "fontFamily.body", []).join(",")
4107
+ var TableWidget = class extends WidgetType5 {
4108
+ constructor(_table) {
4109
+ super();
4110
+ this._table = _table;
4215
4111
  }
4216
- };
4217
- var codeTheme = {
4218
- ".cm-scroller": {
4219
- fontFamily: get4(tokens, "fontFamily.mono", []).join(",")
4220
- },
4221
- ".cm-placeholder": {
4222
- fontFamily: get4(tokens, "fontFamily.mono", []).join(",")
4112
+ eq(other) {
4113
+ return this._table.header?.join() === other._table.header?.join() && this._table.rows?.join() === other._table.rows?.join();
4223
4114
  }
4224
- };
4225
-
4226
- // packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
4227
- var __dxlog_file9 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
4228
- var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions } = {}, deps = []) => {
4229
- const onUpdate = useRef2();
4230
- const [view, setView] = useState3();
4231
- const parentRef = useRef2(null);
4232
- useEffect2(() => {
4233
- let view2;
4234
- if (parentRef.current) {
4235
- const state = EditorState2.create({
4236
- doc,
4237
- selection,
4238
- extensions: [
4239
- // TODO(burdon): Doesn't catch errors in keymap functions.
4240
- EditorView16.exceptionSink.of((err) => {
4241
- log8.catch(err, void 0, {
4242
- F: __dxlog_file9,
4243
- L: 70,
4244
- S: void 0,
4245
- C: (f, a) => f(...a)
4246
- });
4247
- }),
4248
- extensions,
4249
- EditorView16.updateListener.of(() => {
4250
- onUpdate.current?.();
4251
- })
4252
- ].filter(isNotFalsy3)
4115
+ toDOM(view) {
4116
+ const table2 = document.createElement("table");
4117
+ {
4118
+ const header = table2.appendChild(document.createElement("thead"));
4119
+ const tr = header.appendChild(document.createElement("tr"));
4120
+ this._table.header?.forEach((cell) => {
4121
+ const th = document.createElement("th");
4122
+ th.setAttribute("class", "cm-table-head");
4123
+ tr.appendChild(th).textContent = cell;
4253
4124
  });
4254
- view2 = new EditorView16({
4255
- parent: parentRef.current,
4256
- scrollTo,
4257
- state,
4258
- // NOTE: Uncomment to debug/monitor all transactions.
4259
- // https://codemirror.net/docs/ref/#view.EditorView.dispatch
4260
- dispatchTransactions: (trs, view3) => {
4261
- if (debug) {
4262
- logChanges(trs);
4263
- }
4264
- view3.update(trs);
4265
- }
4125
+ }
4126
+ {
4127
+ const body = table2.appendChild(document.createElement("tbody"));
4128
+ this._table.rows?.forEach((row) => {
4129
+ const tr = body.appendChild(document.createElement("tr"));
4130
+ row.forEach((cell) => {
4131
+ const td = document.createElement("td");
4132
+ td.setAttribute("class", "cm-table-cell");
4133
+ tr.appendChild(td).textContent = cell;
4134
+ });
4266
4135
  });
4267
- setView(view2);
4268
4136
  }
4269
- return () => {
4270
- view2?.destroy();
4271
- };
4272
- }, deps);
4273
- useEffect2(() => {
4274
- if (view) {
4275
- if (!selection && !view.state.selection.main.anchor) {
4276
- selection = EditorSelection2.single(view.state.doc.line(1).to);
4137
+ return table2;
4138
+ }
4139
+ ignoreEvent(e) {
4140
+ return !/^mouse/.test(e.type);
4141
+ }
4142
+ };
4143
+
4144
+ // packages/ui/react-ui-editor/src/extensions/mention.ts
4145
+ import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
4146
+ import { log as log6 } from "@dxos/log";
4147
+ var __dxlog_file8 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/mention.ts";
4148
+ var mention = ({ onSearch }) => {
4149
+ return autocompletion2({
4150
+ // TODO(burdon): Not working.
4151
+ activateOnTyping: true,
4152
+ // activateOnTypingDelay: 100,
4153
+ // selectOnOpen: true,
4154
+ closeOnBlur: false,
4155
+ // defaultKeymap: false,
4156
+ icons: false,
4157
+ override: [
4158
+ (context) => {
4159
+ log6.info("completion context", {
4160
+ context
4161
+ }, {
4162
+ F: __dxlog_file8,
4163
+ L: 26,
4164
+ S: void 0,
4165
+ C: (f, a) => f(...a)
4166
+ });
4167
+ const match = context.matchBefore(/@(\w+)?/);
4168
+ if (!match || match.from === match.to && !context.explicit) {
4169
+ return null;
4170
+ }
4171
+ return {
4172
+ from: match.from,
4173
+ options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
4174
+ label: `@${value}`
4175
+ }))
4176
+ };
4277
4177
  }
4278
- if (selection || scrollTo) {
4279
- onUpdate.current = () => {
4280
- onUpdate.current = void 0;
4178
+ ]
4179
+ });
4180
+ };
4181
+
4182
+ // packages/ui/react-ui-editor/src/extensions/modes.ts
4183
+ import { Facet as Facet6 } from "@codemirror/state";
4184
+ import { keymap as keymap8 } from "@codemirror/view";
4185
+ import { vim } from "@replit/codemirror-vim";
4186
+ import { vscodeKeymap } from "@replit/codemirror-vscode-keymap";
4187
+ var focusEvent = "focus.container";
4188
+ var editorMode = Facet6.define({
4189
+ combine: (modes) => modes[0] ?? {}
4190
+ });
4191
+ var EditorModes = {
4192
+ default: [],
4193
+ vscode: [
4194
+ // https://github.com/replit/codemirror-vscode-keymap
4195
+ editorMode.of({
4196
+ type: "vscode"
4197
+ }),
4198
+ keymap8.of(vscodeKeymap)
4199
+ ],
4200
+ vim: [
4201
+ // https://github.com/replit/codemirror-vim
4202
+ vim(),
4203
+ editorMode.of({
4204
+ type: "vim",
4205
+ noTabster: true
4206
+ }),
4207
+ keymap8.of([
4208
+ {
4209
+ key: "Alt-Escape",
4210
+ run: (view) => {
4281
4211
  view.dispatch({
4282
- selection,
4283
- effects: scrollTo && [
4284
- scrollTo
4285
- ],
4286
- scrollIntoView: !scrollTo
4212
+ userEvent: focusEvent
4287
4213
  });
4288
- };
4289
- }
4290
- if (autoFocus) {
4291
- view.focus();
4214
+ return true;
4215
+ }
4292
4216
  }
4293
- }
4294
- }, [
4295
- view,
4296
- autoFocus,
4297
- selection,
4298
- scrollTo
4299
- ]);
4300
- return {
4301
- parentRef,
4302
- view
4303
- };
4304
- };
4305
- var defaults = {
4306
- bracketMatching: true,
4307
- closeBrackets: true,
4308
- drawSelection: true,
4309
- editable: true,
4310
- history: true,
4311
- lineWrapping: true
4217
+ ])
4218
+ ]
4312
4219
  };
4313
- var createBasicExtensions = (_props) => {
4314
- const props = defaultsDeep2({}, _props, defaults);
4315
- return [
4316
- // TODO(burdon): Doesn't catch errors in keymap functions.
4317
- EditorView16.exceptionSink.of((err) => {
4318
- log8.catch(err, void 0, {
4319
- F: __dxlog_file9,
4320
- L: 167,
4321
- S: void 0,
4322
- C: (f, a) => f(...a)
4323
- });
4324
- }),
4325
- props.allowMultipleSelections && EditorState2.allowMultipleSelections.of(true),
4326
- props.bracketMatching && bracketMatching2(),
4327
- props.closeBrackets && closeBrackets2(),
4328
- props.crosshairCursor && crosshairCursor(),
4329
- props.dropCursor && dropCursor2(),
4330
- props.drawSelection && drawSelection2(),
4331
- props.highlightActiveLine && highlightActiveLine(),
4332
- props.history && history2(),
4333
- props.lineNumbers && lineNumbers(),
4334
- props.lineWrapping && EditorView16.lineWrapping,
4335
- props.placeholder && placeholder2(props.placeholder),
4336
- props.readonly && [
4337
- EditorState2.readOnly.of(true),
4338
- EditorView16.editable.of(false)
4339
- ],
4340
- props.scrollPastEnd && scrollPastEnd(),
4341
- props.tabSize && EditorState2.tabSize.of(props.tabSize)
4342
- ].filter(isNotFalsy3);
4220
+
4221
+ // packages/ui/react-ui-editor/src/extensions/state.ts
4222
+ import { Transaction } from "@codemirror/state";
4223
+ import { EditorView as EditorView15, keymap as keymap9 } from "@codemirror/view";
4224
+ import { debounce as debounce2 } from "@dxos/async";
4225
+ import { invariant as invariant4 } from "@dxos/invariant";
4226
+ import { isNotFalsy as isNotFalsy3 } from "@dxos/util";
4227
+ var __dxlog_file9 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/state.ts";
4228
+ var scrollAnnotation = "dxos.org/cm/scrolling";
4229
+ var keyPrefix = "dxos.org/react-ui-editor/state";
4230
+ var localStorageStateStoreAdapter = {
4231
+ setState: (id, state2) => {
4232
+ invariant4(id, void 0, {
4233
+ F: __dxlog_file9,
4234
+ L: 35,
4235
+ S: void 0,
4236
+ A: [
4237
+ "id",
4238
+ ""
4239
+ ]
4240
+ });
4241
+ localStorage.setItem(`${keyPrefix}/${id}`, JSON.stringify(state2));
4242
+ },
4243
+ getState: (id) => {
4244
+ invariant4(id, void 0, {
4245
+ F: __dxlog_file9,
4246
+ L: 39,
4247
+ S: void 0,
4248
+ A: [
4249
+ "id",
4250
+ ""
4251
+ ]
4252
+ });
4253
+ const state2 = localStorage.getItem(`${keyPrefix}/${id}`);
4254
+ return state2 ? JSON.parse(state2) : void 0;
4255
+ }
4343
4256
  };
4344
- var createThemeExtensions = ({ theme, themeMode, slots } = {}) => {
4257
+ var state = ({ getState, setState } = {}) => {
4258
+ const setStateDebounced = debounce2(setState, 1e3);
4345
4259
  return [
4346
- EditorView16.baseTheme(defaultTheme),
4347
- EditorView16.darkTheme.of(themeMode === "dark"),
4348
- theme && EditorView16.theme(theme),
4349
- slots?.editor?.className && EditorView16.editorAttributes.of({
4350
- class: slots.editor.className
4260
+ // TODO(burdon): Track scrolling (currently only updates when cursor moves).
4261
+ EditorView15.updateListener.of(({ view, changes, transactions }) => {
4262
+ const id = view.state.facet(documentId2);
4263
+ if (!id || transactions.some((tr) => tr.isUserEvent(scrollAnnotation))) {
4264
+ return;
4265
+ }
4266
+ if (setState) {
4267
+ const { top } = view.dom.getBoundingClientRect();
4268
+ const pos = view.posAtCoords({
4269
+ x: 0,
4270
+ y: top
4271
+ });
4272
+ if (pos !== null) {
4273
+ const { anchor, head } = view.state.selection.main;
4274
+ setStateDebounced(id, {
4275
+ scrollTo: {
4276
+ from: pos,
4277
+ yMargin: 0
4278
+ },
4279
+ selection: {
4280
+ anchor,
4281
+ head
4282
+ }
4283
+ });
4284
+ }
4285
+ }
4351
4286
  }),
4352
- slots?.content?.className && EditorView16.contentAttributes.of({
4353
- class: slots.content.className
4354
- })
4287
+ getState && keymap9.of([
4288
+ {
4289
+ key: "ctrl-r",
4290
+ run: (view) => {
4291
+ const state2 = getState(view.state.facet(documentId2));
4292
+ if (state2) {
4293
+ view.dispatch({
4294
+ effects: EditorView15.scrollIntoView(state2.scrollTo.from, {
4295
+ yMargin: 0
4296
+ }),
4297
+ selection: state2.selection,
4298
+ annotations: Transaction.userEvent.of(scrollAnnotation)
4299
+ });
4300
+ }
4301
+ return true;
4302
+ }
4303
+ }
4304
+ ])
4355
4305
  ].filter(isNotFalsy3);
4356
4306
  };
4357
4307
 
4358
- // packages/ui/react-ui-editor/src/hooks/useTextModel.ts
4359
- import get5 from "lodash.get";
4360
- import { useState as useState4, useMemo as useMemo2 } from "react";
4361
- import { generateName } from "@dxos/display-name";
4362
- import { getRawDoc } from "@dxos/echo-schema";
4363
- import { invariant as invariant3 } from "@dxos/invariant";
4364
- import { isAutomergeObject } from "@dxos/react-client/echo";
4365
- import { hueTokens } from "@dxos/react-ui-theme";
4366
- import { hexToHue } from "@dxos/util";
4367
- var __dxlog_file10 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
4368
- var useTextExtensions = ({ id, text, space, identity }) => {
4369
- const extensions = [
4370
- automerge(text)
4371
- ];
4372
- const peerId = identity?.identityKey.toHex();
4373
- const { cursorLightValue, cursorDarkValue } = hueTokens[identity?.profile?.data?.hue ?? hexToHue(peerId ?? "0")];
4374
- if (space && identity) {
4375
- const awarenessProvider2 = new SpaceAwarenessProvider({
4376
- space,
4377
- channel: `awareness.${id}`,
4378
- peerId: identity.identityKey.toHex(),
4379
- info: {
4380
- displayName: identity.profile?.displayName ?? generateName(identity.identityKey.toHex()),
4381
- color: cursorDarkValue,
4382
- lightColor: cursorLightValue
4308
+ // packages/ui/react-ui-editor/src/extensions/typewriter.ts
4309
+ import { keymap as keymap10 } from "@codemirror/view";
4310
+ var defaultItems = [
4311
+ "hello world!",
4312
+ "this is a test.",
4313
+ "this is [DXOS](https://dxos.org)"
4314
+ ];
4315
+ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
4316
+ let t;
4317
+ let idx = 0;
4318
+ return [
4319
+ keymap10.of([
4320
+ {
4321
+ // Reset.
4322
+ key: "alt-meta-'",
4323
+ run: (view) => {
4324
+ clearTimeout(t);
4325
+ idx = 0;
4326
+ return true;
4327
+ }
4328
+ },
4329
+ {
4330
+ // Next prompt.
4331
+ // TODO(burdon): Press 1-9 to select prompt?
4332
+ key: "shift-meta-'",
4333
+ run: (view) => {
4334
+ clearTimeout(t);
4335
+ const text = items[idx++];
4336
+ if (idx === items?.length) {
4337
+ idx = 0;
4338
+ }
4339
+ let i = 0;
4340
+ const insert = (d = 0) => {
4341
+ t = setTimeout(() => {
4342
+ const pos = view.state.selection.main.head;
4343
+ view.dispatch({
4344
+ changes: {
4345
+ from: pos,
4346
+ insert: text[i++]
4347
+ },
4348
+ selection: {
4349
+ anchor: pos + 1
4350
+ }
4351
+ });
4352
+ if (i < text.length) {
4353
+ insert(Math.random() * delay * (text[i] === " " ? 2 : 1));
4354
+ }
4355
+ }, d);
4356
+ };
4357
+ insert();
4358
+ return true;
4359
+ }
4383
4360
  }
4384
- });
4385
- extensions.push(awareness(awarenessProvider2));
4386
- }
4387
- return extensions;
4388
- };
4389
- var useTextModel = (props) => useMemo2(() => createModel(props), Object.values(props));
4390
- var useInMemoryTextModel = ({ id, defaultContent }) => {
4391
- const [content, setContent] = useState4(defaultContent ?? "");
4392
- return {
4393
- id,
4394
- content,
4395
- text: () => content,
4396
- setContent
4397
- };
4398
- };
4399
- var createModel = ({ space, identity, text }) => {
4400
- if (!text) {
4401
- return void 0;
4402
- }
4403
- invariant3(isAutomergeObject(text), void 0, {
4404
- F: __dxlog_file10,
4405
- L: 89,
4406
- S: void 0,
4407
- A: [
4408
- "isAutomergeObject(text)",
4409
- ""
4410
- ]
4411
- });
4412
- const obj = text;
4413
- const doc = getRawDoc(obj, [
4414
- obj.field
4415
- ]);
4416
- const peerId = identity?.identityKey.toHex();
4417
- const { cursorLightValue, cursorDarkValue } = hueTokens[identity?.profile?.data?.hue ?? hexToHue(peerId ?? "0")];
4418
- const awarenessProvider2 = space && new SpaceAwarenessProvider({
4419
- space,
4420
- channel: `automerge.awareness.${obj.id}`,
4421
- info: {
4422
- displayName: identity ? identity.profile?.displayName ?? generateName(identity.identityKey.toHex()) : void 0,
4423
- color: cursorLightValue,
4424
- lightColor: cursorDarkValue
4425
- },
4426
- peerId: identity?.identityKey.toHex() ?? "Anonymous"
4427
- });
4428
- const extensions = [
4429
- automerge({
4430
- handle: doc.handle,
4431
- path: doc.path
4432
- })
4361
+ ])
4433
4362
  ];
4434
- if (awarenessProvider2) {
4435
- extensions.push(awareness(awarenessProvider2));
4436
- }
4437
- return {
4438
- id: obj.id,
4439
- content: doc,
4440
- text: () => get5(doc.handle.docSync(), doc.path),
4441
- extension: extensions
4442
- };
4443
4363
  };
4444
4364
 
4445
4365
  // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
4446
- var __dxlog_file11 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
4447
- var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo = EditorView17.scrollIntoView(0), moveToEndOfLine, selection, theme, slots = defaultSlots, extensions = [], scrollPastEnd: _scrollPastEnd, debug }, forwardedRef) => {
4366
+ var __dxlog_file10 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
4367
+ var instanceCount = 0;
4368
+ var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, className, autoFocus, scrollTo = EditorView16.scrollIntoView(0, {
4369
+ yMargin: 0
4370
+ }), moveToEndOfLine, debug, dataTestId }, forwardedRef) => {
4371
+ const [instanceId] = useState2(() => `text-editor-${++instanceCount}`);
4448
4372
  const tabsterDOMAttribute = useFocusableGroup({
4449
4373
  tabBehavior: "limited"
4450
4374
  });
4451
- const { themeMode } = useThemeContext();
4452
- const rootRef = useRef3(null);
4453
- const [view, setView] = useState5(null);
4375
+ const rootRef = useRef(null);
4376
+ const [view, setView] = useState2(null);
4454
4377
  useImperativeHandle(forwardedRef, () => view, [
4455
4378
  view
4456
4379
  ]);
4457
- useEffect3(() => {
4380
+ useEffect2(() => {
4458
4381
  if (autoFocus) {
4459
4382
  view?.focus();
4460
4383
  }
@@ -4462,56 +4385,43 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
4462
4385
  view,
4463
4386
  autoFocus
4464
4387
  ]);
4465
- useEffect3(() => {
4466
- if (!model || !rootRef.current) {
4467
- return;
4468
- }
4469
- const state = EditorState3.create({
4470
- doc: typeof model.content === "string" ? model.content : DocAccessor.getValue(model.content),
4388
+ useEffect2(() => {
4389
+ log7("create", {
4390
+ id,
4391
+ instanceId
4392
+ }, {
4393
+ F: __dxlog_file10,
4394
+ L: 88,
4395
+ S: void 0,
4396
+ C: (f, a) => f(...a)
4397
+ });
4398
+ const state2 = EditorState2.create({
4399
+ doc,
4471
4400
  selection,
4472
4401
  extensions: [
4473
- // TODO(burdon): Doesn't catch errors in keymap functions.
4474
- EditorView17.exceptionSink.of((err) => {
4475
- log9.catch(err, void 0, {
4476
- F: __dxlog_file11,
4477
- L: 123,
4402
+ id && documentId2.of(id),
4403
+ // TODO(burdon): NOTE: Doesn't catch errors in keymap functions.
4404
+ EditorView16.exceptionSink.of((err) => {
4405
+ log7.catch(err, void 0, {
4406
+ F: __dxlog_file10,
4407
+ L: 101,
4478
4408
  S: void 0,
4479
4409
  C: (f, a) => f(...a)
4480
4410
  });
4481
4411
  }),
4482
- // Theme.
4483
- // TODO(burdon): Make base theme configurable.
4484
- EditorView17.baseTheme(defaultTheme),
4485
- theme && EditorView17.theme(theme),
4486
- EditorView17.darkTheme.of(themeMode === "dark"),
4487
- slots.editor?.className && EditorView17.editorAttributes.of({
4488
- class: slots.editor.className
4489
- }),
4490
- slots.content?.className && EditorView17.contentAttributes.of({
4491
- class: slots.content.className
4492
- }),
4493
- // NOTE: Assumes default line height.
4494
- _scrollPastEnd && scrollPastEnd2(),
4495
4412
  // Focus.
4496
- EditorView17.updateListener.of((update2) => {
4413
+ EditorView16.updateListener.of((update2) => {
4497
4414
  update2.transactions.forEach((transaction) => {
4498
- if (transaction.isUserEvent("focus.container")) {
4415
+ if (transaction.isUserEvent(focusEvent)) {
4499
4416
  rootRef.current?.focus();
4500
4417
  }
4501
4418
  });
4502
4419
  }),
4503
- // State.
4504
- EditorView17.editable.of(!readonly),
4505
- EditorState3.readOnly.of(!!readonly),
4506
- // Storage and replication.
4507
- // NOTE: This must come before user extensions.
4508
- model.extension,
4509
- // Custom.
4510
- ...extensions
4420
+ extensions
4511
4421
  ].filter(isNotFalsy4)
4512
4422
  });
4513
- const view2 = new EditorView17({
4514
- state,
4423
+ const view2 = new EditorView16({
4424
+ state: state2,
4515
4425
  parent: rootRef.current,
4516
4426
  scrollTo,
4517
4427
  // NOTE: Uncomment to debug/monitor all transactions.
@@ -4523,28 +4433,34 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
4523
4433
  view3.update(trs);
4524
4434
  }
4525
4435
  });
4526
- setView(view2);
4527
- if (moveToEndOfLine) {
4436
+ if (moveToEndOfLine && !(scrollTo || selection)) {
4528
4437
  const { to } = view2.state.doc.lineAt(0);
4529
- view2?.dispatch({
4438
+ view2.dispatch({
4530
4439
  selection: {
4531
4440
  anchor: to
4532
4441
  }
4533
4442
  });
4534
4443
  }
4535
- if (state.facet(editorMode).noTabster) {
4536
- rootRef.current.removeAttribute("data-tabster");
4444
+ if (state2.facet(editorMode).noTabster) {
4445
+ rootRef.current?.removeAttribute("data-tabster");
4537
4446
  }
4447
+ setView(view2);
4538
4448
  return () => {
4449
+ log7("destroy", {
4450
+ id,
4451
+ instanceId
4452
+ }, {
4453
+ F: __dxlog_file10,
4454
+ L: 150,
4455
+ S: void 0,
4456
+ C: (f, a) => f(...a)
4457
+ });
4539
4458
  view2?.destroy();
4540
- setView(null);
4541
4459
  };
4542
4460
  }, [
4543
- rootRef,
4544
- extensions,
4545
- model,
4546
- readonly,
4547
- themeMode
4461
+ doc,
4462
+ selection,
4463
+ extensions
4548
4464
  ]);
4549
4465
  const handleKeyUp = useCallback((event) => {
4550
4466
  const { key } = event;
@@ -4560,82 +4476,19 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
4560
4476
  return /* @__PURE__ */ React.createElement("div", {
4561
4477
  role: "none",
4562
4478
  ref: rootRef,
4563
- key: model.id,
4564
4479
  tabIndex: 0,
4565
- onKeyUp: handleKeyUp,
4566
- ...slots.root,
4567
- ...tabsterDOMAttribute
4568
- });
4569
- });
4570
- var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, lineWrapping = true, theme = textTheme, slots, extensions: _extensions, ...props }, forwardedRef) => {
4571
- const { themeMode } = useThemeContext();
4572
- const updatedSlots = defaultsDeep3({}, slots, defaultTextSlots);
4573
- const extensions = useMemo3(() => [
4574
- createBasicExtensions({
4575
- lineWrapping,
4576
- placeholder: placeholder3
4577
- }),
4578
- createThemeExtensions({
4579
- themeMode
4580
- }),
4581
- ..._extensions ?? []
4582
- ], [
4583
- themeMode,
4584
- placeholder3,
4585
- lineWrapping,
4586
- _extensions
4587
- ]);
4588
- return /* @__PURE__ */ React.createElement(BaseTextEditor, {
4589
- ref: forwardedRef,
4590
- readonly,
4591
- extensions,
4592
- theme,
4593
- slots: updatedSlots,
4594
- ...props
4595
- });
4596
- });
4597
- var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, theme = markdownTheme, slots, extensions: _extensions, ...props }, forwardedRef) => {
4598
- const { themeMode } = useThemeContext();
4599
- const updatedSlots = defaultsDeep3({}, slots, defaultMarkdownSlots);
4600
- const extensions = useMemo3(() => [
4601
- createMarkdownExtensions({
4602
- themeMode,
4603
- placeholder: placeholder3
4604
- }),
4605
- ..._extensions ?? []
4606
- ], [
4607
- themeMode,
4608
- placeholder3,
4609
- _extensions
4610
- ]);
4611
- return /* @__PURE__ */ React.createElement(BaseTextEditor, {
4612
- ref: forwardedRef,
4613
- readonly,
4614
- extensions,
4615
- theme,
4616
- slots: updatedSlots,
4617
- ...props
4480
+ className,
4481
+ "data-testid": dataTestId,
4482
+ ...tabsterDOMAttribute,
4483
+ onKeyUp: handleKeyUp
4618
4484
  });
4619
4485
  });
4620
- var defaultSlots = {
4621
- root: {
4622
- className: focusRing
4623
- },
4624
- editor: {
4625
- className: "bs-full"
4626
- }
4627
- };
4628
- var defaultTextSlots = {
4629
- ...defaultSlots
4630
- };
4631
- var defaultMarkdownSlots = {
4632
- ...defaultSlots
4633
- };
4634
4486
 
4635
4487
  // packages/ui/react-ui-editor/src/components/Toolbar/Toolbar.tsx
4636
- import { ChatText, Code, CodeBlock, Link, ListBullets, ListChecks, ListNumbers, Paragraph, TextStrikethrough, Table as Table2, TextB, TextHOne, TextHTwo, TextHThree, TextHFour, TextHFive, TextHSix, TextItalic, Quotes } from "@phosphor-icons/react";
4488
+ import { ChatText, Code, CodeBlock, Image, Link, ListBullets, ListChecks, ListNumbers, Paragraph, Quotes, TextStrikethrough, Table as Table2, TextB, TextHOne, TextHTwo, TextHThree, TextHFour, TextHFive, TextHSix, TextItalic } from "@phosphor-icons/react";
4637
4489
  import { createContext } from "@radix-ui/react-context";
4638
- import React2, { useRef as useRef4, useState as useState6 } from "react";
4490
+ import React2, { useEffect as useEffect3, useRef as useRef2, useState as useState3 } from "react";
4491
+ import { useDropzone } from "react-dropzone";
4639
4492
  import { DensityProvider, ElevationProvider, Select, Toolbar as NaturalToolbar, Tooltip, useTranslation } from "@dxos/react-ui";
4640
4493
  import { getSize } from "@dxos/react-ui-theme";
4641
4494
  var tooltipProps = {
@@ -4652,10 +4505,10 @@ var HeadingIcons = {
4652
4505
  "6": TextHSix
4653
4506
  };
4654
4507
  var [ToolbarContextProvider, useToolbarContext] = createContext("Toolbar");
4655
- var ToolbarRoot = ({ children, onAction, classNames, state }) => {
4508
+ var ToolbarRoot = ({ children, onAction, classNames, state: state2 }) => {
4656
4509
  return /* @__PURE__ */ React2.createElement(ToolbarContextProvider, {
4657
4510
  onAction,
4658
- state
4511
+ state: state2
4659
4512
  }, /* @__PURE__ */ React2.createElement(DensityProvider, {
4660
4513
  density: "fine"
4661
4514
  }, /* @__PURE__ */ React2.createElement(ElevationProvider, {
@@ -4669,7 +4522,7 @@ var ToolbarRoot = ({ children, onAction, classNames, state }) => {
4669
4522
  };
4670
4523
  var buttonStyles = "min-bs-0 p-2";
4671
4524
  var iconStyles = getSize(5);
4672
- var ToolbarButton = ({ Icon, children, ...props }) => {
4525
+ var ToolbarToggleButton = ({ Icon, children, ...props }) => {
4673
4526
  return /* @__PURE__ */ React2.createElement(Tooltip.Root, null, /* @__PURE__ */ React2.createElement(Tooltip.Trigger, {
4674
4527
  asChild: true
4675
4528
  }, /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroupItem, {
@@ -4682,20 +4535,33 @@ var ToolbarButton = ({ Icon, children, ...props }) => {
4682
4535
  className: "sr-only"
4683
4536
  }, children))), /* @__PURE__ */ React2.createElement(Tooltip.Portal, null, /* @__PURE__ */ React2.createElement(Tooltip.Content, tooltipProps, children, /* @__PURE__ */ React2.createElement(Tooltip.Arrow, null))));
4684
4537
  };
4538
+ var ToolbarButton = ({ Icon, children, ...props }) => {
4539
+ return /* @__PURE__ */ React2.createElement(Tooltip.Root, null, /* @__PURE__ */ React2.createElement(Tooltip.Trigger, {
4540
+ asChild: true
4541
+ }, /* @__PURE__ */ React2.createElement(NaturalToolbar.Button, {
4542
+ variant: "ghost",
4543
+ ...props,
4544
+ classNames: buttonStyles
4545
+ }, /* @__PURE__ */ React2.createElement(Icon, {
4546
+ className: iconStyles
4547
+ }), /* @__PURE__ */ React2.createElement("span", {
4548
+ className: "sr-only"
4549
+ }, children))), /* @__PURE__ */ React2.createElement(Tooltip.Portal, null, /* @__PURE__ */ React2.createElement(Tooltip.Content, tooltipProps, children, /* @__PURE__ */ React2.createElement(Tooltip.Arrow, null))));
4550
+ };
4685
4551
  var ToolbarSeparator = () => /* @__PURE__ */ React2.createElement("div", {
4686
4552
  role: "separator",
4687
4553
  className: "grow"
4688
4554
  });
4689
4555
  var MarkdownHeading = () => {
4690
4556
  const { t } = useTranslation(translationKey);
4691
- const { onAction, state } = useToolbarContext("MarkdownFormatting");
4692
- const blockType = state ? state.blockType : "paragraph";
4557
+ const { onAction, state: state2 } = useToolbarContext("MarkdownFormatting");
4558
+ const blockType = state2 ? state2.blockType : "paragraph";
4693
4559
  const header = blockType && /heading(\d)/.exec(blockType);
4694
4560
  const value = header ? header[1] : blockType === "paragraph" || !blockType ? "0" : void 0;
4695
4561
  const HeadingIcon = HeadingIcons[value ?? "0"];
4696
- const suppressNextTooltip = useRef4(false);
4697
- const [tooltipOpen, setTooltipOpen] = useState6(false);
4698
- const [selectOpen, setSelectOpen] = useState6(false);
4562
+ const suppressNextTooltip = useRef2(false);
4563
+ const [tooltipOpen, setTooltipOpen] = useState3(false);
4564
+ const [selectOpen, setSelectOpen] = useState3(false);
4699
4565
  return /* @__PURE__ */ React2.createElement(Tooltip.Root, {
4700
4566
  open: tooltipOpen,
4701
4567
  onOpenChange: (nextOpen) => {
@@ -4763,43 +4629,43 @@ var markdownStyles = [
4763
4629
  {
4764
4630
  type: "strong",
4765
4631
  Icon: TextB,
4766
- getState: (state) => state.strong
4632
+ getState: (state2) => state2.strong
4767
4633
  },
4768
4634
  {
4769
4635
  type: "emphasis",
4770
4636
  Icon: TextItalic,
4771
- getState: (state) => state.emphasis
4637
+ getState: (state2) => state2.emphasis
4772
4638
  },
4773
4639
  {
4774
4640
  type: "strikethrough",
4775
4641
  Icon: TextStrikethrough,
4776
- getState: (state) => state.strikethrough
4642
+ getState: (state2) => state2.strikethrough
4777
4643
  },
4778
4644
  {
4779
4645
  type: "code",
4780
4646
  Icon: Code,
4781
- getState: (state) => state.code
4647
+ getState: (state2) => state2.code
4782
4648
  },
4783
4649
  {
4784
4650
  type: "link",
4785
4651
  Icon: Link,
4786
- getState: (state) => state.link
4652
+ getState: (state2) => state2.link
4787
4653
  }
4788
4654
  ];
4789
4655
  var MarkdownStyles = () => {
4790
- const { onAction, state } = useToolbarContext("MarkdownStyles");
4656
+ const { onAction, state: state2 } = useToolbarContext("MarkdownStyles");
4791
4657
  const { t } = useTranslation(translationKey);
4792
4658
  return /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroup, {
4793
4659
  type: "multiple",
4794
- value: markdownStyles.filter(({ getState }) => state && getState(state)).map(({ type }) => type)
4795
- }, markdownStyles.map(({ type, getState, Icon }) => /* @__PURE__ */ React2.createElement(ToolbarButton, {
4660
+ value: markdownStyles.filter(({ getState }) => state2 && getState(state2)).map(({ type }) => type)
4661
+ }, markdownStyles.map(({ type, getState, Icon }) => /* @__PURE__ */ React2.createElement(ToolbarToggleButton, {
4796
4662
  key: type,
4797
4663
  value: type,
4798
4664
  Icon,
4799
- disabled: state?.blockType === "codeblock",
4800
- onClick: state ? () => onAction?.({
4665
+ disabled: state2?.blockType === "codeblock",
4666
+ onClick: state2 ? () => onAction?.({
4801
4667
  type,
4802
- data: !getState(state)
4668
+ data: !getState(state2)
4803
4669
  }) : void 0
4804
4670
  }, t(`${type} label`))));
4805
4671
  };
@@ -4807,32 +4673,32 @@ var markdownLists = [
4807
4673
  {
4808
4674
  type: "list-bullet",
4809
4675
  Icon: ListBullets,
4810
- getState: (state) => state.listStyle === "bullet"
4676
+ getState: (state2) => state2.listStyle === "bullet"
4811
4677
  },
4812
4678
  {
4813
4679
  type: "list-ordered",
4814
4680
  Icon: ListNumbers,
4815
- getState: (state) => state.listStyle === "ordered"
4681
+ getState: (state2) => state2.listStyle === "ordered"
4816
4682
  },
4817
4683
  {
4818
4684
  type: "list-task",
4819
4685
  Icon: ListChecks,
4820
- getState: (state) => state.listStyle === "task"
4686
+ getState: (state2) => state2.listStyle === "task"
4821
4687
  }
4822
4688
  ];
4823
4689
  var MarkdownLists = () => {
4824
- const { onAction, state } = useToolbarContext("MarkdownStyles");
4690
+ const { onAction, state: state2 } = useToolbarContext("MarkdownStyles");
4825
4691
  const { t } = useTranslation(translationKey);
4826
4692
  return /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroup, {
4827
4693
  type: "single",
4828
- value: state?.listStyle ? `list-${state.listStyle}` : ""
4829
- }, markdownLists.map(({ type, getState, Icon }) => /* @__PURE__ */ React2.createElement(ToolbarButton, {
4694
+ value: state2?.listStyle ? `list-${state2.listStyle}` : ""
4695
+ }, markdownLists.map(({ type, getState, Icon }) => /* @__PURE__ */ React2.createElement(ToolbarToggleButton, {
4830
4696
  key: type,
4831
4697
  value: type,
4832
4698
  Icon,
4833
- onClick: state ? () => onAction?.({
4699
+ onClick: state2 ? () => onAction?.({
4834
4700
  type,
4835
- data: !getState(state)
4701
+ data: !getState(state2)
4836
4702
  }) : void 0
4837
4703
  }, t(`${type} label`))));
4838
4704
  };
@@ -4840,72 +4706,229 @@ var markdownBlocks = [
4840
4706
  {
4841
4707
  type: "blockquote",
4842
4708
  Icon: Quotes,
4843
- getState: (state) => state.blockQuote
4709
+ getState: (state2) => state2.blockQuote
4844
4710
  },
4845
4711
  {
4846
4712
  type: "codeblock",
4847
4713
  Icon: CodeBlock,
4848
- getState: (state) => state.blockType === "codeblock"
4714
+ getState: (state2) => state2.blockType === "codeblock"
4849
4715
  },
4850
4716
  {
4851
4717
  type: "table",
4852
4718
  Icon: Table2,
4853
- getState: (state) => state.blockType === "tablecell",
4854
- disabled: (state) => !state.blankLine
4719
+ getState: (state2) => state2.blockType === "tablecell",
4720
+ disabled: (state2) => !state2.blankLine
4855
4721
  }
4856
4722
  ];
4857
4723
  var MarkdownBlocks = () => {
4858
- const { onAction, state } = useToolbarContext("MarkdownStyles");
4724
+ const { onAction, state: state2 } = useToolbarContext("MarkdownStyles");
4859
4725
  const { t } = useTranslation(translationKey);
4860
- const value = markdownBlocks.find(({ getState }) => state && getState(state));
4726
+ const value = markdownBlocks.find(({ getState }) => state2 && getState(state2));
4861
4727
  return /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroup, {
4862
4728
  type: "single",
4863
4729
  value: value?.type ?? ""
4864
- }, markdownBlocks.map(({ type, disabled, getState, Icon }) => /* @__PURE__ */ React2.createElement(ToolbarButton, {
4730
+ }, markdownBlocks.map(({ type, disabled, getState, Icon }) => /* @__PURE__ */ React2.createElement(ToolbarToggleButton, {
4865
4731
  key: type,
4866
4732
  value: type,
4867
4733
  Icon,
4868
- disabled: !state || disabled?.(state),
4869
- onClick: state ? () => onAction?.({
4734
+ disabled: !state2 || disabled?.(state2),
4735
+ onClick: state2 ? () => onAction?.({
4870
4736
  type,
4871
- data: !getState(state)
4737
+ data: !getState(state2)
4872
4738
  }) : void 0
4873
4739
  }, t(`${type} label`))));
4874
4740
  };
4875
4741
  var MarkdownStandard = () => /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(MarkdownHeading, null), /* @__PURE__ */ React2.createElement(MarkdownStyles, null), /* @__PURE__ */ React2.createElement(MarkdownLists, null), /* @__PURE__ */ React2.createElement(MarkdownBlocks, null));
4876
- var MarkdownExtended = () => {
4742
+ var MarkdownCustom = ({ onUpload } = {}) => {
4877
4743
  const { onAction } = useToolbarContext("MarkdownStyles");
4878
4744
  const { t } = useTranslation(translationKey);
4879
- return /* @__PURE__ */ React2.createElement(Tooltip.Root, null, /* @__PURE__ */ React2.createElement(Tooltip.Trigger, {
4880
- asChild: true
4881
- }, /* @__PURE__ */ React2.createElement(NaturalToolbar.Button, {
4882
- variant: "ghost",
4745
+ const { acceptedFiles, getInputProps, open } = useDropzone({
4746
+ multiple: false,
4747
+ noDrag: true,
4748
+ accept: {
4749
+ "image/*": [
4750
+ ".jpg",
4751
+ ".jpeg",
4752
+ ".png",
4753
+ ".gif"
4754
+ ]
4755
+ }
4756
+ });
4757
+ useEffect3(() => {
4758
+ if (onUpload && acceptedFiles.length) {
4759
+ requestAnimationFrame(async () => {
4760
+ const f = acceptedFiles[0];
4761
+ const file = new File([
4762
+ f
4763
+ ], f.name, {
4764
+ type: f.type,
4765
+ lastModified: f.lastModified
4766
+ });
4767
+ const { url } = await onUpload(file);
4768
+ if (url) {
4769
+ onAction?.({
4770
+ type: "image",
4771
+ data: url
4772
+ });
4773
+ }
4774
+ });
4775
+ }
4776
+ }, [
4777
+ acceptedFiles
4778
+ ]);
4779
+ return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement("input", getInputProps()), /* @__PURE__ */ React2.createElement(ToolbarButton, {
4780
+ value: "image",
4781
+ Icon: Image,
4782
+ onClick: () => open()
4783
+ }, t("image label")));
4784
+ };
4785
+ var MarkdownActions = () => {
4786
+ const { onAction } = useToolbarContext("MarkdownStyles");
4787
+ const { t } = useTranslation(translationKey);
4788
+ return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(ToolbarButton, {
4789
+ value: "comment",
4790
+ Icon: ChatText,
4883
4791
  "data-testid": "editor.toolbar.comment",
4884
4792
  onClick: () => onAction?.({
4885
4793
  type: "comment"
4886
- }),
4887
- classNames: buttonStyles
4888
- }, /* @__PURE__ */ React2.createElement(ChatText, {
4889
- className: iconStyles
4890
- }), /* @__PURE__ */ React2.createElement("span", {
4891
- className: "sr-only"
4892
- }, t("comment label")))), /* @__PURE__ */ React2.createElement(Tooltip.Portal, null, /* @__PURE__ */ React2.createElement(Tooltip.Content, tooltipProps, t("comment label"), /* @__PURE__ */ React2.createElement(Tooltip.Arrow, null))));
4794
+ })
4795
+ }, t("comment label")));
4893
4796
  };
4894
4797
  var Toolbar = {
4895
4798
  Root: ToolbarRoot,
4896
- Button: ToolbarButton,
4799
+ Button: ToolbarToggleButton,
4897
4800
  Separator: ToolbarSeparator,
4898
4801
  Markdown: MarkdownStandard,
4899
- Extended: MarkdownExtended
4802
+ Custom: MarkdownCustom,
4803
+ Actions: MarkdownActions
4804
+ };
4805
+
4806
+ // packages/ui/react-ui-editor/src/hooks/useActionHandler.ts
4807
+ var useActionHandler = (view) => {
4808
+ return (action) => view && processAction(view, action);
4809
+ };
4810
+
4811
+ // packages/ui/react-ui-editor/src/hooks/useDocAccessor.ts
4812
+ import { useMemo as useMemo2 } from "react";
4813
+ import { createDocAccessor, getTextContent } from "@dxos/echo-schema";
4814
+ var useDocAccessor = (text) => {
4815
+ return useMemo2(() => ({
4816
+ id: text.id,
4817
+ doc: getTextContent(text),
4818
+ accessor: createDocAccessor(text)
4819
+ }), [
4820
+ text
4821
+ ]);
4822
+ };
4823
+
4824
+ // packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
4825
+ import { EditorSelection as EditorSelection2, EditorState as EditorState3 } from "@codemirror/state";
4826
+ import { EditorView as EditorView17 } from "@codemirror/view";
4827
+ import { useEffect as useEffect4, useMemo as useMemo3, useRef as useRef3, useState as useState4 } from "react";
4828
+ import { log as log8 } from "@dxos/log";
4829
+ import { isNotFalsy as isNotFalsy5 } from "@dxos/util";
4830
+ var __dxlog_file11 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
4831
+ var useTextEditor = (cb = () => ({}), deps = []) => {
4832
+ let { id, doc, selection, extensions, autoFocus, scrollTo, debug } = useMemo3(cb, deps ?? []);
4833
+ const onUpdate = useRef3();
4834
+ const [view, setView] = useState4();
4835
+ const parentRef = useRef3(null);
4836
+ useEffect4(() => {
4837
+ let view2;
4838
+ if (parentRef.current) {
4839
+ log8("create", {
4840
+ id
4841
+ }, {
4842
+ F: __dxlog_file11,
4843
+ L: 36,
4844
+ S: void 0,
4845
+ C: (f, a) => f(...a)
4846
+ });
4847
+ const state2 = EditorState3.create({
4848
+ doc,
4849
+ selection,
4850
+ extensions: [
4851
+ id && documentId2.of(id),
4852
+ // TODO(burdon): Doesn't catch errors in keymap functions.
4853
+ EditorView17.exceptionSink.of((err) => {
4854
+ log8.catch(err, void 0, {
4855
+ F: __dxlog_file11,
4856
+ L: 46,
4857
+ S: void 0,
4858
+ C: (f, a) => f(...a)
4859
+ });
4860
+ }),
4861
+ extensions,
4862
+ EditorView17.updateListener.of(() => {
4863
+ onUpdate.current?.();
4864
+ })
4865
+ ].filter(isNotFalsy5)
4866
+ });
4867
+ view2 = new EditorView17({
4868
+ parent: parentRef.current,
4869
+ scrollTo,
4870
+ state: state2,
4871
+ // NOTE: Uncomment to debug/monitor all transactions.
4872
+ // https://codemirror.net/docs/ref/#view.EditorView.dispatch
4873
+ dispatchTransactions: (trs, view3) => {
4874
+ if (debug) {
4875
+ logChanges(trs);
4876
+ }
4877
+ view3.update(trs);
4878
+ }
4879
+ });
4880
+ setView(view2);
4881
+ }
4882
+ return () => {
4883
+ log8("destroy", {
4884
+ id
4885
+ }, {
4886
+ F: __dxlog_file11,
4887
+ L: 74,
4888
+ S: void 0,
4889
+ C: (f, a) => f(...a)
4890
+ });
4891
+ view2?.destroy();
4892
+ };
4893
+ }, deps);
4894
+ useEffect4(() => {
4895
+ if (view) {
4896
+ if (!selection && !view.state.selection.main.anchor) {
4897
+ selection = EditorSelection2.single(view.state.doc.line(1).to);
4898
+ }
4899
+ if (selection || scrollTo) {
4900
+ onUpdate.current = () => {
4901
+ onUpdate.current = void 0;
4902
+ view.dispatch({
4903
+ selection,
4904
+ effects: scrollTo && [
4905
+ scrollTo
4906
+ ],
4907
+ scrollIntoView: !scrollTo
4908
+ });
4909
+ };
4910
+ }
4911
+ if (autoFocus) {
4912
+ view.focus();
4913
+ }
4914
+ }
4915
+ }, [
4916
+ view,
4917
+ autoFocus,
4918
+ selection,
4919
+ scrollTo
4920
+ ]);
4921
+ return {
4922
+ parentRef,
4923
+ view
4924
+ };
4900
4925
  };
4901
4926
  export {
4902
- BaseTextEditor,
4903
4927
  Cursor,
4904
4928
  Doc,
4905
4929
  EditorModes,
4906
4930
  Inline,
4907
4931
  List,
4908
- MarkdownEditor,
4909
4932
  RemoteSelectionsDecorator,
4910
4933
  SpaceAwarenessProvider,
4911
4934
  TextEditor,
@@ -4925,43 +4948,41 @@ export {
4925
4948
  awarenessProvider,
4926
4949
  blast,
4927
4950
  callbackWrapper,
4928
- codeTheme,
4929
4951
  command,
4930
4952
  comments,
4931
- compareFormatting,
4932
4953
  createBasicExtensions,
4933
4954
  createComment,
4955
+ createDataExtensions,
4934
4956
  createMarkdownExtensions,
4935
4957
  createThemeExtensions,
4936
- cursorLineMargin,
4937
- cursorLineMarginFacet,
4938
4958
  decorateMarkdown,
4939
- defaultMarkdownSlots,
4940
4959
  defaultOptions,
4941
- defaultSlots,
4942
- defaultTextSlots,
4943
4960
  defaultTheme,
4944
- dnd,
4961
+ documentId2 as documentId,
4962
+ dropFile,
4945
4963
  editorFillLayoutEditor,
4946
4964
  editorFillLayoutRoot,
4947
4965
  editorMode,
4948
4966
  editorWithToolbarLayout,
4949
4967
  focusComment,
4950
- formatting,
4968
+ focusEvent,
4969
+ formattingEquals,
4970
+ formattingKeymap,
4951
4971
  getFormatting,
4952
4972
  getToken,
4953
4973
  image,
4974
+ imageUpload,
4954
4975
  insertTable,
4955
- keymap9 as keymap,
4976
+ keymap11 as keymap,
4956
4977
  linkTooltip,
4957
4978
  listener,
4979
+ localStorageStateStoreAdapter,
4958
4980
  logChanges,
4959
4981
  markdownHighlightStyle,
4960
4982
  markdownTags,
4961
4983
  markdownTagsExtensions,
4962
- markdownTheme,
4963
4984
  mention,
4964
- outliner,
4985
+ processAction,
4965
4986
  removeBlockquote,
4966
4987
  removeCodeblock,
4967
4988
  removeLink,
@@ -4972,9 +4993,9 @@ export {
4972
4993
  setHeading,
4973
4994
  setSelection,
4974
4995
  setStyle,
4996
+ state,
4975
4997
  table,
4976
4998
  tags2 as tags,
4977
- textTheme,
4978
4999
  toggleBlockquote,
4979
5000
  toggleCodeblock,
4980
5001
  toggleEmphasis,
@@ -4987,12 +5008,9 @@ export {
4987
5008
  typewriter,
4988
5009
  useActionHandler,
4989
5010
  useComments,
4990
- useEditorView,
5011
+ useDocAccessor,
4991
5012
  useFormattingState,
4992
- useInMemoryTextModel,
4993
5013
  useTextEditor,
4994
- useTextExtensions,
4995
- useTextModel,
4996
5014
  useToolbarContext
4997
5015
  };
4998
5016
  //# sourceMappingURL=index.mjs.map