@dxos/react-ui-editor 0.4.7-main.e015b9e → 0.4.7-main.e0789ae

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 (83) hide show
  1. package/dist/lib/browser/index.mjs +971 -741
  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/MarkdownEditor.stories.d.ts +9 -0
  5. package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
  6. package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
  7. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +0 -9
  8. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
  9. package/dist/types/src/components/TextEditor/index.d.ts +0 -2
  10. package/dist/types/src/components/TextEditor/index.d.ts.map +1 -1
  11. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -1
  12. package/dist/types/src/{components/TextEditor → extensions/automerge}/automerge.stories.d.ts +4 -2
  13. package/dist/types/src/extensions/automerge/automerge.stories.d.ts.map +1 -0
  14. package/dist/types/src/extensions/command/command.d.ts +10 -0
  15. package/dist/types/src/extensions/command/command.d.ts.map +1 -0
  16. package/dist/types/src/extensions/command/hint.d.ts +7 -0
  17. package/dist/types/src/extensions/command/hint.d.ts.map +1 -0
  18. package/dist/types/src/extensions/command/index.d.ts +2 -0
  19. package/dist/types/src/extensions/command/index.d.ts.map +1 -0
  20. package/dist/types/src/extensions/command/state.d.ts +18 -0
  21. package/dist/types/src/extensions/command/state.d.ts.map +1 -0
  22. package/dist/types/src/extensions/cursor-line-margin.d.ts.map +1 -1
  23. package/dist/types/src/extensions/dnd.d.ts +3 -0
  24. package/dist/types/src/extensions/dnd.d.ts.map +1 -0
  25. package/dist/types/src/extensions/index.d.ts +2 -1
  26. package/dist/types/src/extensions/index.d.ts.map +1 -1
  27. package/dist/types/src/extensions/listener.d.ts +1 -1
  28. package/dist/types/src/extensions/listener.d.ts.map +1 -1
  29. package/dist/types/src/extensions/markdown/bundle.d.ts +2 -2
  30. package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
  31. package/dist/types/src/extensions/markdown/decorate.d.ts +4 -0
  32. package/dist/types/src/extensions/markdown/decorate.d.ts.map +1 -1
  33. package/dist/types/src/extensions/util/dom.d.ts +15 -0
  34. package/dist/types/src/extensions/util/dom.d.ts.map +1 -0
  35. package/dist/types/src/hooks/defs.d.ts +5 -11
  36. package/dist/types/src/hooks/defs.d.ts.map +1 -1
  37. package/dist/types/src/hooks/useEditorView.d.ts.map +1 -1
  38. package/dist/types/src/hooks/useTextEditor.d.ts +20 -5
  39. package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
  40. package/dist/types/src/{components/TextEditor/hooks.stories.d.ts → hooks/useTextEditor.stories.d.ts} +1 -3
  41. package/dist/types/src/hooks/useTextEditor.stories.d.ts.map +1 -0
  42. package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
  43. package/dist/types/src/index.d.ts +1 -0
  44. package/dist/types/src/index.d.ts.map +1 -1
  45. package/dist/types/src/styles/index.d.ts +0 -1
  46. package/dist/types/src/styles/index.d.ts.map +1 -1
  47. package/dist/types/src/themes/default.d.ts.map +1 -1
  48. package/package.json +25 -25
  49. package/src/components/TextEditor/MarkdownEditor.stories.tsx +95 -8
  50. package/src/components/TextEditor/TextEditor.stories.tsx +0 -15
  51. package/src/components/TextEditor/TextEditor.tsx +13 -6
  52. package/src/components/TextEditor/index.ts +0 -3
  53. package/src/components/Toolbar/Toolbar.stories.tsx +2 -1
  54. package/src/{components/TextEditor → extensions/automerge}/automerge.stories.tsx +32 -37
  55. package/src/extensions/awareness.ts +3 -3
  56. package/src/extensions/command/command.ts +35 -0
  57. package/src/extensions/command/hint.ts +76 -0
  58. package/src/extensions/command/index.ts +5 -0
  59. package/src/extensions/command/state.ts +106 -0
  60. package/src/extensions/cursor-line-margin.ts +2 -1
  61. package/src/extensions/dnd.ts +15 -0
  62. package/src/extensions/index.ts +2 -1
  63. package/src/extensions/listener.ts +3 -3
  64. package/src/extensions/markdown/bundle.ts +4 -15
  65. package/src/extensions/markdown/decorate.ts +76 -32
  66. package/src/extensions/util/dom.ts +36 -0
  67. package/src/hooks/defs.ts +6 -20
  68. package/src/hooks/useActionHandler.ts +11 -11
  69. package/src/hooks/useEditorView.ts +0 -1
  70. package/src/{components/TextEditor/hooks.stories.tsx → hooks/useTextEditor.stories.tsx} +8 -8
  71. package/src/hooks/useTextEditor.ts +69 -14
  72. package/src/hooks/useTextModel.ts +18 -18
  73. package/src/index.ts +2 -0
  74. package/src/styles/index.ts +0 -1
  75. package/src/themes/default.ts +1 -0
  76. package/dist/types/src/components/TextEditor/automerge.stories.d.ts.map +0 -1
  77. package/dist/types/src/components/TextEditor/hooks.stories.d.ts.map +0 -1
  78. package/dist/types/src/extensions/basic.d.ts +0 -9
  79. package/dist/types/src/extensions/basic.d.ts.map +0 -1
  80. package/dist/types/src/styles/cursors.d.ts +0 -5
  81. package/dist/types/src/styles/cursors.d.ts.map +0 -1
  82. package/src/extensions/basic.ts +0 -41
  83. package/src/styles/cursors.ts +0 -21
@@ -23,20 +23,19 @@ var translations_default = [
23
23
  ];
24
24
 
25
25
  // packages/ui/react-ui-editor/src/index.ts
26
- import { keymap as keymap8 } from "@codemirror/view";
26
+ import { keymap as keymap9 } from "@codemirror/view";
27
+ import { tags as tags2 } from "@lezer/highlight";
27
28
  import { TextKind } from "@dxos/protocols/proto/dxos/echo/model/text";
28
29
  import { Doc, YText, YXmlFragment } from "@dxos/text-model";
29
30
 
30
- // packages/ui/react-ui-editor/src/components/TextEditor/index.ts
31
- import { tags as tags2 } from "@lezer/highlight";
32
-
33
31
  // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
34
- import { EditorState as EditorState2 } from "@codemirror/state";
35
- import { EditorView as EditorView14, scrollPastEnd } from "@codemirror/view";
32
+ import { EditorState as EditorState3 } from "@codemirror/state";
33
+ import { EditorView as EditorView17, scrollPastEnd as scrollPastEnd2 } from "@codemirror/view";
36
34
  import { useFocusableGroup } from "@fluentui/react-tabster";
37
- import defaultsDeep2 from "lodash.defaultsdeep";
38
- import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useRef, useState as useState2, useMemo as useMemo2 } from "react";
39
- import { log as log3 } from "@dxos/log";
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 log5 } from "@dxos/log";
40
39
  import { useThemeContext } from "@dxos/react-ui";
41
40
  import { focusRing } from "@dxos/react-ui-theme";
42
41
  import { isNotFalsy as isNotFalsy4 } from "@dxos/util";
@@ -596,7 +595,7 @@ var RemoteSelectionsDecorator = class {
596
595
  to: startLine.from + startLine.length,
597
596
  value: Decoration2.mark({
598
597
  attributes: {
599
- style: `background-color: ${color}`
598
+ style: `background-color: ${lightColor}`
600
599
  },
601
600
  class: "cm-collab-selection"
602
601
  })
@@ -606,7 +605,7 @@ var RemoteSelectionsDecorator = class {
606
605
  to: end,
607
606
  value: Decoration2.mark({
608
607
  attributes: {
609
- style: `background-color: ${color}`
608
+ style: `background-color: ${lightColor}`
610
609
  },
611
610
  class: "cm-collab-selection"
612
611
  })
@@ -618,7 +617,7 @@ var RemoteSelectionsDecorator = class {
618
617
  to: linePos,
619
618
  value: Decoration2.line({
620
619
  attributes: {
621
- style: `background-color: ${color}`,
620
+ style: `background-color: ${lightColor}`,
622
621
  class: "cm-collab-selectionLine"
623
622
  }
624
623
  })
@@ -733,28 +732,8 @@ var styles2 = EditorView3.baseTheme({
733
732
  }
734
733
  });
735
734
 
736
- // packages/ui/react-ui-editor/src/extensions/basic.ts
737
- import { closeBrackets } from "@codemirror/autocomplete";
738
- import { history } from "@codemirror/commands";
739
- import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
740
- import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
741
- import { drawSelection, EditorView as EditorView4, highlightActiveLine, placeholder } from "@codemirror/view";
742
- import { isNotFalsy as isNotFalsy2 } from "@dxos/util";
743
- var createBasicBundle = ({ themeMode, placeholder: _placeholder, lineWrapping = true, bracketMatching: _bracketMatching = true } = {}) => [
744
- lineWrapping && EditorView4.lineWrapping,
745
- // https://codemirror.net/docs/ref/#codemirror.minimalSetup
746
- _bracketMatching && bracketMatching(),
747
- closeBrackets(),
748
- drawSelection(),
749
- highlightActiveLine(),
750
- history(),
751
- _placeholder && placeholder(_placeholder),
752
- // https://github.com/codemirror/theme-one-dark
753
- themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)
754
- ].filter(isNotFalsy2);
755
-
756
735
  // packages/ui/react-ui-editor/src/extensions/blast.ts
757
- import { EditorView as EditorView5, keymap as keymap2 } from "@codemirror/view";
736
+ import { EditorView as EditorView4, keymap as keymap2 } from "@codemirror/view";
758
737
  import defaultsDeep from "lodash.defaultsdeep";
759
738
  import { invariant } from "@dxos/invariant";
760
739
  var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
@@ -802,7 +781,7 @@ var blast = (options = defaultOptions) => {
802
781
  };
803
782
  return [
804
783
  // Cursor moved.
805
- EditorView5.updateListener.of((update2) => {
784
+ EditorView4.updateListener.of((update2) => {
806
785
  if (blaster?.node !== update2.view.scrollDOM) {
807
786
  if (blaster) {
808
787
  blaster.destroy();
@@ -1063,52 +1042,231 @@ var random = (min, max) => {
1063
1042
  return min + ~~(Math.random() * (max - min + 1));
1064
1043
  };
1065
1044
 
1066
- // packages/ui/react-ui-editor/src/extensions/comments.ts
1067
- import { invertedEffects } from "@codemirror/commands";
1068
- import { Facet as Facet3, StateEffect as StateEffect2, StateField as StateField3 } from "@codemirror/state";
1069
- import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView as EditorView6 } from "@codemirror/view";
1070
- import sortBy from "lodash.sortby";
1071
- import { useEffect } from "react";
1072
- import { debounce } from "@dxos/async";
1073
- import { nonNullable } from "@dxos/util";
1045
+ // packages/ui/react-ui-editor/src/extensions/command/command.ts
1046
+ import { EditorView as EditorView6, keymap as keymap3 } from "@codemirror/view";
1074
1047
 
1075
- // packages/ui/react-ui-editor/src/styles/cursors.ts
1076
- import * as random2 from "lib0/random";
1077
- var cursorColors = [
1078
- {
1079
- color: "#30bced",
1080
- light: "#30bced33"
1081
- },
1082
- {
1083
- color: "#6eeb83",
1084
- light: "#6eeb8333"
1085
- },
1086
- {
1087
- color: "#ffbc42",
1088
- light: "#ffbc4233"
1089
- },
1090
- {
1091
- color: "#ecd444",
1092
- light: "#ecd44433"
1093
- },
1094
- {
1095
- color: "#ee6352",
1096
- light: "#ee635233"
1097
- },
1098
- {
1099
- color: "#9ac2c9",
1100
- light: "#9ac2c933"
1048
+ // packages/ui/react-ui-editor/src/extensions/command/hint.ts
1049
+ import { RangeSetBuilder } from "@codemirror/state";
1050
+ import { Decoration as Decoration3, EditorView as EditorView5, ViewPlugin as ViewPlugin3, WidgetType as WidgetType2 } from "@codemirror/view";
1051
+
1052
+ // packages/ui/react-ui-editor/src/extensions/command/state.ts
1053
+ import { Facet as Facet3, StateEffect as StateEffect2, StateField as StateField3 } from "@codemirror/state";
1054
+ import { showTooltip } from "@codemirror/view";
1055
+ var commandConfig = Facet3.define({
1056
+ combine: (providers) => providers[0]
1057
+ });
1058
+ var commandState = StateField3.define({
1059
+ create: () => ({}),
1060
+ update: (state, tr) => {
1061
+ for (const effect of tr.effects) {
1062
+ if (effect.is(closeEffect)) {
1063
+ return {};
1064
+ }
1065
+ if (effect.is(openEffect)) {
1066
+ const options = tr.state.facet(commandConfig);
1067
+ const { pos, fullWidth } = effect.value;
1068
+ const tooltip = {
1069
+ pos,
1070
+ above: false,
1071
+ arrow: false,
1072
+ strictSide: true,
1073
+ create: (view) => {
1074
+ const dom = document.createElement("div");
1075
+ const tooltipView = {
1076
+ dom,
1077
+ mount: (view2) => {
1078
+ if (fullWidth) {
1079
+ const parent = dom.parentElement;
1080
+ const { paddingLeft, paddingRight } = window.getComputedStyle(parent);
1081
+ const widthWithoutPadding = parent.clientWidth - parseFloat(paddingLeft) - parseFloat(paddingRight);
1082
+ dom.style.width = `${widthWithoutPadding}px`;
1083
+ }
1084
+ options.onRender(dom, (action) => {
1085
+ view2.dispatch({
1086
+ effects: closeEffect.of(null)
1087
+ });
1088
+ if (action?.insert?.length) {
1089
+ view2.dispatch({
1090
+ changes: {
1091
+ from: pos,
1092
+ insert: action.insert
1093
+ },
1094
+ selection: {
1095
+ anchor: pos + action.insert.length
1096
+ }
1097
+ });
1098
+ }
1099
+ setTimeout(() => view2.focus());
1100
+ });
1101
+ }
1102
+ };
1103
+ return tooltipView;
1104
+ }
1105
+ };
1106
+ return {
1107
+ tooltip
1108
+ };
1109
+ }
1110
+ }
1111
+ return state;
1101
1112
  },
1113
+ provide: (f) => [
1114
+ showTooltip.from(f, (value) => value.tooltip ?? null)
1115
+ ]
1116
+ });
1117
+ var openEffect = StateEffect2.define();
1118
+ var closeEffect = StateEffect2.define();
1119
+ var openCommand = (view) => {
1120
+ if (view.state.field(commandState, false)) {
1121
+ const selection = view.state.selection.main;
1122
+ const line = view.state.doc.lineAt(selection.from);
1123
+ if (line.from === selection.from && line.from === line.to) {
1124
+ view.dispatch({
1125
+ effects: openEffect.of({
1126
+ pos: selection.anchor,
1127
+ fullWidth: true
1128
+ })
1129
+ });
1130
+ return true;
1131
+ }
1132
+ }
1133
+ return false;
1134
+ };
1135
+ var closeCommand = (view) => {
1136
+ if (view.state.field(commandState, false)) {
1137
+ view.dispatch({
1138
+ effects: closeEffect.of(null)
1139
+ });
1140
+ return true;
1141
+ }
1142
+ return false;
1143
+ };
1144
+ var commandKeyBindings = [
1102
1145
  {
1103
- color: "#8acb88",
1104
- light: "#8acb8833"
1146
+ key: "/",
1147
+ run: openCommand
1105
1148
  },
1106
1149
  {
1107
- color: "#1be7ff",
1108
- light: "#1be7ff33"
1150
+ key: "Escape",
1151
+ run: closeCommand
1109
1152
  }
1110
1153
  ];
1111
- var cursorColor = cursorColors[random2.uint32() % cursorColors.length];
1154
+
1155
+ // packages/ui/react-ui-editor/src/extensions/util/dom.ts
1156
+ var flattenRect = (rect, left) => {
1157
+ const x = left ? rect.left : rect.right;
1158
+ return {
1159
+ left: x,
1160
+ right: x,
1161
+ top: rect.top,
1162
+ bottom: rect.bottom
1163
+ };
1164
+ };
1165
+ var scratchRange;
1166
+ var textRange = (node, from, to = from) => {
1167
+ const range = scratchRange || (scratchRange = document.createRange());
1168
+ range.setEnd(node, to);
1169
+ range.setStart(node, from);
1170
+ return range;
1171
+ };
1172
+ var clientRectsFor = (dom) => {
1173
+ if (dom.nodeType === 3) {
1174
+ return textRange(dom, 0, dom.nodeValue.length).getClientRects();
1175
+ } else if (dom.nodeType === 1) {
1176
+ return dom.getClientRects();
1177
+ } else {
1178
+ return [];
1179
+ }
1180
+ };
1181
+
1182
+ // packages/ui/react-ui-editor/src/extensions/command/hint.ts
1183
+ var CommandHint = class extends WidgetType2 {
1184
+ constructor(content) {
1185
+ super();
1186
+ this.content = content;
1187
+ }
1188
+ toDOM() {
1189
+ const wrap = document.createElement("span");
1190
+ wrap.className = "cm-placeholder";
1191
+ wrap.style.pointerEvents = "none";
1192
+ wrap.appendChild(typeof this.content === "string" ? document.createTextNode(this.content) : this.content);
1193
+ if (typeof this.content === "string") {
1194
+ wrap.setAttribute("aria-label", "placeholder " + this.content);
1195
+ } else {
1196
+ wrap.setAttribute("aria-hidden", "true");
1197
+ }
1198
+ return wrap;
1199
+ }
1200
+ coordsAt(dom) {
1201
+ const rects = dom.firstChild ? clientRectsFor(dom.firstChild) : [];
1202
+ if (!rects.length) {
1203
+ return null;
1204
+ }
1205
+ const style = window.getComputedStyle(dom.parentNode);
1206
+ const rect = flattenRect(rects[0], style.direction !== "rtl");
1207
+ const lineHeight = parseInt(style.lineHeight);
1208
+ if (rect.bottom - rect.top > lineHeight * 1.5) {
1209
+ return {
1210
+ left: rect.left,
1211
+ right: rect.right,
1212
+ top: rect.top,
1213
+ bottom: rect.top + lineHeight
1214
+ };
1215
+ }
1216
+ return rect;
1217
+ }
1218
+ ignoreEvent() {
1219
+ return false;
1220
+ }
1221
+ };
1222
+ var hintViewPlugin = ({ onHint }) => ViewPlugin3.fromClass(class {
1223
+ constructor() {
1224
+ this.deco = Decoration3.none;
1225
+ }
1226
+ update(update2) {
1227
+ const builder = new RangeSetBuilder();
1228
+ const cState = update2.view.state.field(commandState, false);
1229
+ if (!cState?.tooltip) {
1230
+ const selection = update2.view.state.selection.main;
1231
+ const line = update2.view.state.doc.lineAt(selection.from);
1232
+ if (selection.from === selection.to && line.from === line.to) {
1233
+ const hint = onHint();
1234
+ if (hint) {
1235
+ builder.add(selection.from, selection.to, Decoration3.widget({
1236
+ widget: new CommandHint(hint)
1237
+ }));
1238
+ }
1239
+ }
1240
+ }
1241
+ this.deco = builder.finish();
1242
+ }
1243
+ }, {
1244
+ provide: (plugin) => [
1245
+ EditorView5.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration3.none)
1246
+ ]
1247
+ });
1248
+
1249
+ // packages/ui/react-ui-editor/src/extensions/command/command.ts
1250
+ var command = (options) => {
1251
+ return [
1252
+ commandConfig.of(options),
1253
+ commandState,
1254
+ keymap3.of(commandKeyBindings),
1255
+ hintViewPlugin(options),
1256
+ EditorView6.focusChangeEffect.of((_, focusing) => {
1257
+ return focusing ? closeEffect.of(null) : null;
1258
+ })
1259
+ ];
1260
+ };
1261
+
1262
+ // packages/ui/react-ui-editor/src/extensions/comments.ts
1263
+ import { invertedEffects } from "@codemirror/commands";
1264
+ import { Facet as Facet4, StateEffect as StateEffect3, StateField as StateField4 } from "@codemirror/state";
1265
+ import { hoverTooltip, keymap as keymap4, Decoration as Decoration4, EditorView as EditorView7 } from "@codemirror/view";
1266
+ import sortBy from "lodash.sortby";
1267
+ import { useEffect } from "react";
1268
+ import { debounce } from "@dxos/async";
1269
+ import { nonNullable } from "@dxos/util";
1112
1270
 
1113
1271
  // packages/ui/react-ui-editor/src/styles/markdown.ts
1114
1272
  import { mx } from "@dxos/react-ui-theme";
@@ -1180,13 +1338,13 @@ var logChanges = (trs) => {
1180
1338
  };
1181
1339
 
1182
1340
  // packages/ui/react-ui-editor/src/extensions/comments.ts
1183
- var documentId = Facet3.define({
1341
+ var documentId = Facet4.define({
1184
1342
  combine: (values) => values[0]
1185
1343
  });
1186
- var setComments = StateEffect2.define();
1187
- var setSelection = StateEffect2.define();
1188
- var setCommentState = StateEffect2.define();
1189
- var commentsState = StateField3.define({
1344
+ var setComments = StateEffect3.define();
1345
+ var setSelection = StateEffect3.define();
1346
+ var setCommentState = StateEffect3.define();
1347
+ var commentsState = StateField4.define({
1190
1348
  create: (state) => ({
1191
1349
  id: state.facet(documentId),
1192
1350
  comments: [],
@@ -1224,7 +1382,7 @@ var commentsState = StateField3.define({
1224
1382
  return value;
1225
1383
  }
1226
1384
  });
1227
- var styles3 = EditorView6.baseTheme({
1385
+ var styles3 = EditorView7.baseTheme({
1228
1386
  "&light .cm-comment, &light .cm-comment-current": {
1229
1387
  mixBlendMode: "darken"
1230
1388
  },
@@ -1246,19 +1404,19 @@ var styles3 = EditorView6.baseTheme({
1246
1404
  backgroundColor: getToken("extend.colors.yellow.950")
1247
1405
  }
1248
1406
  });
1249
- var commentMark = Decoration3.mark({
1407
+ var commentMark = Decoration4.mark({
1250
1408
  class: "cm-comment",
1251
1409
  attributes: {
1252
1410
  "data-testid": "cm-comment"
1253
1411
  }
1254
1412
  });
1255
- var commentCurrentMark = Decoration3.mark({
1413
+ var commentCurrentMark = Decoration4.mark({
1256
1414
  class: "cm-comment-current",
1257
1415
  attributes: {
1258
1416
  "data-testid": "cm-comment"
1259
1417
  }
1260
1418
  });
1261
- var commentsDecorations = EditorView6.decorations.compute([
1419
+ var commentsDecorations = EditorView7.decorations.compute([
1262
1420
  commentsState
1263
1421
  ], (state) => {
1264
1422
  const { selection: { current }, comments: comments2 } = state.field(commentsState);
@@ -1274,7 +1432,7 @@ var commentsDecorations = EditorView6.decorations.compute([
1274
1432
  return commentMark.range(range.from, range.to);
1275
1433
  }
1276
1434
  }).filter(nonNullable);
1277
- return Decoration3.set(decorations);
1435
+ return Decoration4.set(decorations);
1278
1436
  });
1279
1437
  var trackPastedComments = (onUpdate) => {
1280
1438
  let tracked = null;
@@ -1296,7 +1454,7 @@ var trackPastedComments = (onUpdate) => {
1296
1454
  }
1297
1455
  };
1298
1456
  return [
1299
- EditorView6.domEventHandlers({
1457
+ EditorView7.domEventHandlers({
1300
1458
  cut: handleTrack,
1301
1459
  copy: handleTrack
1302
1460
  }),
@@ -1318,7 +1476,7 @@ var trackPastedComments = (onUpdate) => {
1318
1476
  return effects;
1319
1477
  }),
1320
1478
  // Handle paste or the undo of comment deletion.
1321
- EditorView6.updateListener.of((update2) => {
1479
+ EditorView7.updateListener.of((update2) => {
1322
1480
  const restore = [];
1323
1481
  for (let i = 0; i < update2.transactions.length; i++) {
1324
1482
  const tr = update2.transactions[i];
@@ -1374,7 +1532,7 @@ var mapTrackedComment = (comment, changes) => ({
1374
1532
  from: changes.mapPos(comment.from, 1),
1375
1533
  to: changes.mapPos(comment.to, 1)
1376
1534
  });
1377
- var restoreCommentEffect = StateEffect2.define({
1535
+ var restoreCommentEffect = StateEffect3.define({
1378
1536
  map: mapTrackedComment
1379
1537
  });
1380
1538
  var createComment = (view) => {
@@ -1415,7 +1573,7 @@ var createComment = (view) => {
1415
1573
  }
1416
1574
  return false;
1417
1575
  };
1418
- var optionsFacet = Facet3.define({
1576
+ var optionsFacet = Facet4.define({
1419
1577
  combine: (providers) => providers[0]
1420
1578
  });
1421
1579
  var comments = (options = {}) => {
@@ -1430,7 +1588,7 @@ var comments = (options = {}) => {
1430
1588
  //
1431
1589
  // Keymap.
1432
1590
  //
1433
- options.onCreate ? keymap3.of([
1591
+ options.onCreate ? keymap4.of([
1434
1592
  {
1435
1593
  key: shortcut,
1436
1594
  run: callbackWrapper(createComment)
@@ -1469,7 +1627,7 @@ var comments = (options = {}) => {
1469
1627
  //
1470
1628
  // Track deleted ranges and update ranges for decorations.
1471
1629
  //
1472
- EditorView6.updateListener.of(({ view, state, changes }) => {
1630
+ EditorView7.updateListener.of(({ view, state, changes }) => {
1473
1631
  let mod = false;
1474
1632
  const { comments: comments2, ...value } = state.field(commentsState);
1475
1633
  changes.iterChanges((from, to, from2, to2) => {
@@ -1501,7 +1659,7 @@ var comments = (options = {}) => {
1501
1659
  //
1502
1660
  // Track selection/proximity.
1503
1661
  //
1504
- EditorView6.updateListener.of(({ view, state }) => {
1662
+ EditorView7.updateListener.of(({ view, state }) => {
1505
1663
  let min = Infinity;
1506
1664
  const { selection: { current, closest }, comments: comments2 } = state.field(commentsState);
1507
1665
  const { head } = state.selection.main;
@@ -1550,7 +1708,7 @@ var focusComment = (view, id, center = true) => {
1550
1708
  },
1551
1709
  effects: [
1552
1710
  //
1553
- EditorView6.scrollIntoView(range.from, center ? {
1711
+ EditorView7.scrollIntoView(range.from, center ? {
1554
1712
  y: "center"
1555
1713
  } : void 0),
1556
1714
  setSelection.of({
@@ -1578,14 +1736,14 @@ var useComments = (view, id, comments2 = []) => {
1578
1736
  };
1579
1737
 
1580
1738
  // packages/ui/react-ui-editor/src/extensions/cursor-line-margin.ts
1581
- import { Facet as Facet4, Transaction } from "@codemirror/state";
1582
- import { EditorView as EditorView7 } from "@codemirror/view";
1583
- var cursorLineMarginFacet = Facet4.define({
1739
+ import { Facet as Facet5, Transaction } from "@codemirror/state";
1740
+ import { EditorView as EditorView8 } from "@codemirror/view";
1741
+ var cursorLineMarginFacet = Facet5.define({
1584
1742
  combine: (input) => input[0] ?? 3
1585
1743
  });
1586
1744
  var annotation = "cursorLineMargin";
1587
1745
  var lineAtPos = (s, pos) => s.doc.lineAt(pos).number;
1588
- var cursorLineMargin = EditorView7.updateListener.of(({ transactions, state, selectionSet, startState, view }) => {
1746
+ var cursorLineMargin = EditorView8.updateListener.of(({ transactions, state, selectionSet, startState, view }) => {
1589
1747
  if (transactions.length < 1 || transactions.some((tr) => tr.isUserEvent(annotation))) {
1590
1748
  return;
1591
1749
  }
@@ -1621,38 +1779,48 @@ var cursorLineMargin = EditorView7.updateListener.of(({ transactions, state, sel
1621
1779
  }
1622
1780
  view.dispatch({
1623
1781
  annotations: Transaction.userEvent.of(annotation),
1624
- effects: EditorView7.scrollIntoView(s.selection.main.head, {
1782
+ effects: EditorView8.scrollIntoView(s.selection.main.head, {
1625
1783
  y: needsScrollTop ? "start" : "end",
1626
1784
  yMargin: view.defaultLineHeight * cursorLineMargin2
1627
1785
  })
1628
1786
  });
1629
1787
  });
1630
1788
 
1789
+ // packages/ui/react-ui-editor/src/extensions/dnd.ts
1790
+ import { EditorView as EditorView9 } from "@codemirror/view";
1791
+ var dnd = () => {
1792
+ return EditorView9.domEventHandlers({
1793
+ drop: (event, view) => {
1794
+ console.log(event);
1795
+ }
1796
+ });
1797
+ };
1798
+
1631
1799
  // packages/ui/react-ui-editor/src/extensions/listener.ts
1632
- import { EditorView as EditorView8 } from "@codemirror/view";
1800
+ import { EditorView as EditorView10 } from "@codemirror/view";
1633
1801
  var listener = ({ onFocus, onChange }) => {
1634
1802
  const extensions = [];
1635
- onFocus && extensions.push(EditorView8.focusChangeEffect.of((_, focused) => {
1636
- onFocus(focused);
1803
+ onFocus && extensions.push(EditorView10.focusChangeEffect.of((_, focusing) => {
1804
+ onFocus(focusing);
1637
1805
  return null;
1638
1806
  }));
1639
- onChange && extensions.push(EditorView8.updateListener.of((update2) => {
1807
+ onChange && extensions.push(EditorView10.updateListener.of((update2) => {
1640
1808
  onChange(update2.state.doc.toString());
1641
1809
  }));
1642
1810
  return extensions;
1643
1811
  };
1644
1812
 
1645
1813
  // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
1646
- import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
1647
- import { history as history2, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
1814
+ import { closeBrackets, closeBracketsKeymap } from "@codemirror/autocomplete";
1815
+ import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
1648
1816
  import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
1649
- import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
1817
+ import { bracketMatching, defaultHighlightStyle, indentOnInput, syntaxHighlighting } from "@codemirror/language";
1650
1818
  import { languages } from "@codemirror/language-data";
1651
1819
  import { searchKeymap } from "@codemirror/search";
1652
1820
  import { EditorState } from "@codemirror/state";
1653
- import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
1654
- import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView9, highlightActiveLine as highlightActiveLine2, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
1655
- import { isNotFalsy as isNotFalsy3 } from "@dxos/util";
1821
+ import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
1822
+ import { EditorView as EditorView11, drawSelection, dropCursor, keymap as keymap5, placeholder } from "@codemirror/view";
1823
+ import { isNotFalsy as isNotFalsy2 } from "@dxos/util";
1656
1824
 
1657
1825
  // packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
1658
1826
  import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
@@ -1845,19 +2013,17 @@ var markdownHighlightStyle = (readonly) => {
1845
2013
  // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
1846
2014
  var createMarkdownExtensions = ({ themeMode, placeholder: _placeholder, lineWrapping = true } = {}) => {
1847
2015
  return [
1848
- lineWrapping && EditorView9.lineWrapping,
2016
+ // TODO(burdon): Reconcile with createBasicExtensions.
2017
+ lineWrapping && EditorView11.lineWrapping,
1849
2018
  EditorState.allowMultipleSelections.of(true),
1850
2019
  EditorState.tabSize.of(2),
1851
- // https://github.com/codemirror/basic-setup
1852
- bracketMatching2(),
1853
- closeBrackets2(),
1854
- crosshairCursor(),
2020
+ bracketMatching(),
2021
+ closeBrackets(),
1855
2022
  dropCursor(),
1856
- drawSelection2(),
1857
- highlightActiveLine2(),
1858
- history2(),
2023
+ drawSelection(),
2024
+ history(),
1859
2025
  indentOnInput(),
1860
- _placeholder && placeholder2(_placeholder),
2026
+ _placeholder && placeholder(_placeholder),
1861
2027
  // Main extension.
1862
2028
  // https://github.com/codemirror/lang-markdown
1863
2029
  // https://codemirror.net/5/mode/markdown/index.html (demo).
@@ -1877,10 +2043,10 @@ var createMarkdownExtensions = ({ themeMode, placeholder: _placeholder, lineWrap
1877
2043
  ]
1878
2044
  }),
1879
2045
  // https://github.com/codemirror/theme-one-dark
1880
- themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
2046
+ themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle),
1881
2047
  // Custom styles.
1882
- syntaxHighlighting2(markdownHighlightStyle()),
1883
- keymap4.of([
2048
+ syntaxHighlighting(markdownHighlightStyle()),
2049
+ keymap5.of([
1884
2050
  // https://codemirror.net/docs/ref/#commands.indentWithTab
1885
2051
  indentWithTab,
1886
2052
  // https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
@@ -1892,22 +2058,22 @@ var createMarkdownExtensions = ({ themeMode, placeholder: _placeholder, lineWrap
1892
2058
  // https://codemirror.net/docs/ref/#commands.standardKeymap
1893
2059
  ...standardKeymap
1894
2060
  ])
1895
- ].filter(isNotFalsy3);
2061
+ ].filter(isNotFalsy2);
1896
2062
  };
1897
2063
 
1898
2064
  // packages/ui/react-ui-editor/src/extensions/markdown/decorate.ts
1899
2065
  import { syntaxTree } from "@codemirror/language";
1900
- import { RangeSetBuilder } from "@codemirror/state";
1901
- import { EditorView as EditorView10, Decoration as Decoration4, WidgetType as WidgetType2, ViewPlugin as ViewPlugin3 } from "@codemirror/view";
2066
+ import { RangeSetBuilder as RangeSetBuilder2, StateEffect as StateEffect4 } from "@codemirror/state";
2067
+ import { EditorView as EditorView12, Decoration as Decoration5, WidgetType as WidgetType3, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
1902
2068
  import { mx as mx2 } from "@dxos/react-ui-theme";
1903
- var HorizontalRuleWidget = class extends WidgetType2 {
2069
+ var HorizontalRuleWidget = class extends WidgetType3 {
1904
2070
  toDOM() {
1905
2071
  const el = document.createElement("span");
1906
2072
  el.className = "cm-hr";
1907
2073
  return el;
1908
2074
  }
1909
2075
  };
1910
- var LinkButton = class extends WidgetType2 {
2076
+ var LinkButton = class extends WidgetType3 {
1911
2077
  constructor(url, render) {
1912
2078
  super();
1913
2079
  this.url = url;
@@ -1922,7 +2088,7 @@ var LinkButton = class extends WidgetType2 {
1922
2088
  return el;
1923
2089
  }
1924
2090
  };
1925
- var CheckboxWidget = class extends WidgetType2 {
2091
+ var CheckboxWidget = class extends WidgetType3 {
1926
2092
  constructor(_checked) {
1927
2093
  super();
1928
2094
  this._checked = _checked;
@@ -1959,28 +2125,28 @@ var CheckboxWidget = class extends WidgetType2 {
1959
2125
  return false;
1960
2126
  }
1961
2127
  };
1962
- var hide = Decoration4.replace({});
1963
- var fencedCodeLine = Decoration4.line({
2128
+ var hide = Decoration5.replace({});
2129
+ var fencedCodeLine = Decoration5.line({
1964
2130
  class: mx2("cm-code cm-codeblock-line")
1965
2131
  });
1966
- var fencedCodeLineFirst = Decoration4.line({
2132
+ var fencedCodeLineFirst = Decoration5.line({
1967
2133
  class: mx2("cm-code cm-codeblock-line", "cm-codeblock-first")
1968
2134
  });
1969
- var fencedCodeLineLast = Decoration4.line({
2135
+ var fencedCodeLineLast = Decoration5.line({
1970
2136
  class: mx2("cm-code cm-codeblock-line", "cm-codeblock-last")
1971
2137
  });
1972
- var horizontalRule = Decoration4.replace({
2138
+ var horizontalRule = Decoration5.replace({
1973
2139
  widget: new HorizontalRuleWidget()
1974
2140
  });
1975
- var checkedTask = Decoration4.replace({
2141
+ var checkedTask = Decoration5.replace({
1976
2142
  widget: new CheckboxWidget(true)
1977
2143
  });
1978
- var uncheckedTask = Decoration4.replace({
2144
+ var uncheckedTask = Decoration5.replace({
1979
2145
  widget: new CheckboxWidget(false)
1980
2146
  });
1981
- var editingRange = (state, range) => {
2147
+ var editingRange = (state, range, focus) => {
1982
2148
  const { readOnly, selection: { main: { head } } } = state;
1983
- return !readOnly && head >= range.from && head <= range.to;
2149
+ return focus && !readOnly && head >= range.from && head < range.to;
1984
2150
  };
1985
2151
  var MarksByParent = /* @__PURE__ */ new Set([
1986
2152
  "CodeMark",
@@ -1989,8 +2155,9 @@ var MarksByParent = /* @__PURE__ */ new Set([
1989
2155
  "SubscriptMark",
1990
2156
  "SuperscriptMark"
1991
2157
  ]);
1992
- var buildDecorations = (view, options) => {
1993
- const builder = new RangeSetBuilder();
2158
+ var buildDecorations = (view, options, focus) => {
2159
+ const deco = new RangeSetBuilder2();
2160
+ const atomicDeco = new RangeSetBuilder2();
1994
2161
  const { state } = view;
1995
2162
  for (const { from, to } of view.visibleRanges) {
1996
2163
  syntaxTree(state).iterate({
@@ -1998,7 +2165,7 @@ var buildDecorations = (view, options) => {
1998
2165
  to,
1999
2166
  enter: (node) => {
2000
2167
  if (node.name === "FencedCode") {
2001
- const editing = editingRange(state, node);
2168
+ const editing = editingRange(state, node, focus);
2002
2169
  for (const block of view.viewportLineBlocks) {
2003
2170
  if (block.to < node.from) {
2004
2171
  continue;
@@ -2007,23 +2174,23 @@ var buildDecorations = (view, options) => {
2007
2174
  break;
2008
2175
  }
2009
2176
  const first = block.from <= node.from;
2010
- const last = block.to >= node.to;
2011
- builder.add(block.from, block.from, first ? fencedCodeLineFirst : last ? fencedCodeLineLast : fencedCodeLine);
2177
+ const last = block.to >= node.to && /^(\s>)*```$/.test(state.doc.sliceString(block.from, block.to));
2178
+ deco.add(block.from, block.from, first ? fencedCodeLineFirst : last ? fencedCodeLineLast : fencedCodeLine);
2012
2179
  if (!editing && (first || last)) {
2013
- builder.add(block.from, block.to, hide);
2180
+ atomicDeco.add(block.from, block.to, hide);
2014
2181
  }
2015
2182
  }
2016
2183
  return false;
2017
2184
  } else if (node.name === "Link") {
2018
2185
  const marks = node.node.getChildren("LinkMark");
2019
2186
  const urlNode = node.node.getChild("URL");
2020
- const editing = editingRange(state, node);
2187
+ const editing = editingRange(state, node, focus);
2021
2188
  if (urlNode && marks.length >= 2) {
2022
2189
  const url = state.sliceDoc(urlNode.from, urlNode.to);
2023
2190
  if (!editing) {
2024
- builder.add(node.from, marks[0].to, hide);
2191
+ atomicDeco.add(node.from, marks[0].to, hide);
2025
2192
  }
2026
- builder.add(marks[0].to, marks[1].from, Decoration4.mark({
2193
+ deco.add(marks[0].to, marks[1].from, Decoration5.mark({
2027
2194
  tagName: "a",
2028
2195
  attributes: {
2029
2196
  class: "cm-link",
@@ -2033,57 +2200,87 @@ var buildDecorations = (view, options) => {
2033
2200
  }
2034
2201
  }));
2035
2202
  if (!editing) {
2036
- builder.add(marks[1].from, node.to, options.renderLinkButton ? Decoration4.replace({
2203
+ atomicDeco.add(marks[1].from, node.to, options.renderLinkButton ? Decoration5.replace({
2037
2204
  widget: new LinkButton(url, options.renderLinkButton)
2038
2205
  }) : hide);
2039
2206
  }
2040
2207
  }
2041
2208
  } else if (node.name === "HeaderMark") {
2042
2209
  const parent = node.node.parent;
2043
- if (/^ATX/.test(parent.name) && !editingRange(state, state.doc.lineAt(node.from))) {
2210
+ if (/^ATX/.test(parent.name) && !editingRange(state, state.doc.lineAt(node.from), focus)) {
2044
2211
  const next = state.doc.sliceString(node.to, node.to + 1);
2045
- builder.add(node.from, node.to + (next === " " ? 1 : 0), hide);
2212
+ atomicDeco.add(node.from, node.to + (next === " " ? 1 : 0), hide);
2046
2213
  }
2047
2214
  } else if (node.name === "HorizontalRule") {
2048
- if (!editingRange(state, node)) {
2049
- builder.add(node.from, node.to, horizontalRule);
2215
+ if (!editingRange(state, node, focus)) {
2216
+ deco.add(node.from, node.to, horizontalRule);
2050
2217
  }
2051
2218
  } else if (node.name === "TaskMarker") {
2052
- if (!editingRange(state, node)) {
2219
+ if (!editingRange(state, node, focus)) {
2053
2220
  const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
2054
- builder.add(node.from - 2, node.from - 1, Decoration4.mark({
2221
+ atomicDeco.add(node.from - 2, node.from - 1, Decoration5.mark({
2055
2222
  class: "cm-task"
2056
2223
  }));
2057
- builder.add(node.from, node.to, checked ? checkedTask : uncheckedTask);
2224
+ atomicDeco.add(node.from, node.to, checked ? checkedTask : uncheckedTask);
2058
2225
  }
2059
2226
  } else if (MarksByParent.has(node.name)) {
2060
- if (!editingRange(state, node.node.parent)) {
2061
- builder.add(node.from, node.to, hide);
2227
+ if (!editingRange(state, node.node.parent, focus)) {
2228
+ atomicDeco.add(node.from, node.to, hide);
2062
2229
  }
2063
2230
  }
2064
2231
  }
2065
2232
  });
2066
2233
  }
2067
- return builder.finish();
2234
+ return {
2235
+ deco: deco.finish(),
2236
+ atomicDeco: atomicDeco.finish()
2237
+ };
2068
2238
  };
2239
+ var forceUpdate = StateEffect4.define();
2069
2240
  var decorateMarkdown = (options = {}) => {
2070
2241
  return [
2071
- ViewPlugin3.fromClass(class {
2242
+ ViewPlugin4.fromClass(class {
2072
2243
  constructor(view) {
2073
- this.decorations = buildDecorations(view, options);
2244
+ ({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations(view, options, view.hasFocus));
2074
2245
  }
2075
2246
  update(update2) {
2076
- if (update2.docChanged || update2.selectionSet || update2.viewportChanged) {
2077
- this.decorations = buildDecorations(update2.view, options);
2247
+ if (update2.docChanged || update2.viewportChanged || update2.focusChanged || update2.transactions.some((tr) => tr.effects.some((e) => e.is(forceUpdate))) || update2.selectionSet && !options.selectionChangeDelay) {
2248
+ ({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations(update2.view, options, update2.view.hasFocus));
2249
+ this.clearUpdate();
2250
+ } else if (update2.selectionSet) {
2251
+ this.scheduleUpdate(update2.view);
2252
+ }
2253
+ }
2254
+ // TODO(burdon): BUG: If the cursor is at the end of a link at the end of a line,
2255
+ // the cursor will float in space or be in the wrong position after the decoration is applied.
2256
+ scheduleUpdate(view) {
2257
+ this.clearUpdate();
2258
+ this.pendingUpdate = setTimeout(() => {
2259
+ view.dispatch({
2260
+ effects: forceUpdate.of(null)
2261
+ });
2262
+ }, options.selectionChangeDelay);
2263
+ }
2264
+ clearUpdate() {
2265
+ if (this.pendingUpdate) {
2266
+ clearTimeout(this.pendingUpdate);
2267
+ this.pendingUpdate = void 0;
2078
2268
  }
2079
2269
  }
2270
+ destroy() {
2271
+ this.clearUpdate();
2272
+ }
2080
2273
  }, {
2081
- decorations: (value) => value.decorations
2274
+ provide: (plugin) => [
2275
+ EditorView12.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration5.none),
2276
+ EditorView12.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration5.none),
2277
+ EditorView12.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration5.none)
2278
+ ]
2082
2279
  }),
2083
2280
  formattingStyles
2084
2281
  ];
2085
2282
  };
2086
- var formattingStyles = EditorView10.baseTheme({
2283
+ var formattingStyles = EditorView12.baseTheme({
2087
2284
  "& .cm-code": {
2088
2285
  fontFamily: getToken("fontFamily.mono", []).join(",")
2089
2286
  },
@@ -2136,7 +2333,7 @@ var formattingStyles = EditorView10.baseTheme({
2136
2333
  import { snippet } from "@codemirror/autocomplete";
2137
2334
  import { syntaxTree as syntaxTree2 } from "@codemirror/language";
2138
2335
  import { EditorSelection } from "@codemirror/state";
2139
- import { EditorView as EditorView11, keymap as keymap5 } from "@codemirror/view";
2336
+ import { EditorView as EditorView13, keymap as keymap6 } from "@codemirror/view";
2140
2337
  import { useState, useMemo } from "react";
2141
2338
  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;
2142
2339
  var Inline;
@@ -3008,7 +3205,7 @@ var toggleCodeblock = (target) => {
3008
3205
  };
3009
3206
  var formatting = (options = {}) => {
3010
3207
  return [
3011
- keymap5.of([
3208
+ keymap6.of([
3012
3209
  {
3013
3210
  key: "meta-b",
3014
3211
  run: toggleStrong
@@ -3206,7 +3403,7 @@ var getFormatting = (state) => {
3206
3403
  };
3207
3404
  var useFormattingState = () => {
3208
3405
  const [state, setState] = useState(null);
3209
- const observer = useMemo(() => EditorView11.updateListener.of((update2) => {
3406
+ const observer = useMemo(() => EditorView13.updateListener.of((update2) => {
3210
3407
  if (update2.docChanged || update2.selectionSet) {
3211
3408
  const newState = getFormatting(update2.state);
3212
3409
  if (!state || !compareFormatting(state, newState)) {
@@ -3222,12 +3419,12 @@ var useFormattingState = () => {
3222
3419
 
3223
3420
  // packages/ui/react-ui-editor/src/extensions/markdown/image.ts
3224
3421
  import { syntaxTree as syntaxTree3 } from "@codemirror/language";
3225
- import { StateField as StateField4 } from "@codemirror/state";
3226
- import { Decoration as Decoration5, EditorView as EditorView12, WidgetType as WidgetType3 } from "@codemirror/view";
3422
+ import { StateField as StateField5 } from "@codemirror/state";
3423
+ import { Decoration as Decoration6, EditorView as EditorView14, WidgetType as WidgetType4 } from "@codemirror/view";
3227
3424
  var image = (options = {}) => {
3228
- return StateField4.define({
3425
+ return StateField5.define({
3229
3426
  create: (state) => {
3230
- return Decoration5.set(buildDecorations2(0, state.doc.length, state));
3427
+ return Decoration6.set(buildDecorations2(0, state.doc.length, state));
3231
3428
  },
3232
3429
  update: (value, tr) => {
3233
3430
  if (!tr.docChanged && !tr.selection) {
@@ -3250,7 +3447,7 @@ var image = (options = {}) => {
3250
3447
  add: buildDecorations2(from, to, tr.state)
3251
3448
  });
3252
3449
  },
3253
- provide: (field) => EditorView12.decorations.from(field)
3450
+ provide: (field) => EditorView14.decorations.from(field)
3254
3451
  });
3255
3452
  };
3256
3453
  var preloaded = /* @__PURE__ */ new Set();
@@ -3272,7 +3469,7 @@ var buildDecorations2 = (from, to, state) => {
3272
3469
  const hide2 = state.readOnly || cursor < node.from || cursor > node.to;
3273
3470
  const url = state.sliceDoc(urlNode.from, urlNode.to);
3274
3471
  preloadImage(url);
3275
- decorations.push(Decoration5.replace({
3472
+ decorations.push(Decoration6.replace({
3276
3473
  block: true,
3277
3474
  widget: new ImageWidget(url)
3278
3475
  }).range(hide2 ? node.from : node.to, node.to));
@@ -3284,7 +3481,7 @@ var buildDecorations2 = (from, to, state) => {
3284
3481
  });
3285
3482
  return decorations;
3286
3483
  };
3287
- var ImageWidget = class extends WidgetType3 {
3484
+ var ImageWidget = class extends WidgetType4 {
3288
3485
  constructor(_url) {
3289
3486
  super();
3290
3487
  this._url = _url;
@@ -3337,17 +3534,17 @@ var linkTooltip = (render) => hoverTooltip2((view, pos, side) => {
3337
3534
 
3338
3535
  // packages/ui/react-ui-editor/src/extensions/markdown/table.ts
3339
3536
  import { syntaxTree as syntaxTree5 } from "@codemirror/language";
3340
- import { RangeSetBuilder as RangeSetBuilder2, StateField as StateField5 } from "@codemirror/state";
3341
- import { Decoration as Decoration6, EditorView as EditorView13, WidgetType as WidgetType4 } from "@codemirror/view";
3537
+ import { RangeSetBuilder as RangeSetBuilder3, StateField as StateField6 } from "@codemirror/state";
3538
+ import { Decoration as Decoration7, EditorView as EditorView15, WidgetType as WidgetType5 } from "@codemirror/view";
3342
3539
  var table = (options = {}) => {
3343
- return StateField5.define({
3540
+ return StateField6.define({
3344
3541
  create: (state) => update(state, options),
3345
3542
  update: (_, tr) => update(tr.state, options),
3346
- provide: (field) => EditorView13.decorations.from(field)
3543
+ provide: (field) => EditorView15.decorations.from(field)
3347
3544
  });
3348
3545
  };
3349
3546
  var update = (state, options) => {
3350
- const builder = new RangeSetBuilder2();
3547
+ const builder = new RangeSetBuilder3();
3351
3548
  const cursor = state.selection.main.head;
3352
3549
  const tables = [];
3353
3550
  const getTable = () => tables[tables.length - 1];
@@ -3387,16 +3584,16 @@ var update = (state, options) => {
3387
3584
  });
3388
3585
  tables.forEach((table2) => {
3389
3586
  const hide2 = state.readOnly || cursor < table2.from || cursor > table2.to;
3390
- hide2 && builder.add(table2.from, table2.to, Decoration6.replace({
3587
+ hide2 && builder.add(table2.from, table2.to, Decoration7.replace({
3391
3588
  widget: new TableWidget(table2)
3392
3589
  }));
3393
- builder.add(table2.from, table2.to, Decoration6.mark({
3590
+ builder.add(table2.from, table2.to, Decoration7.mark({
3394
3591
  class: "cm-table"
3395
3592
  }));
3396
3593
  });
3397
3594
  return builder.finish();
3398
3595
  };
3399
- var TableWidget = class extends WidgetType4 {
3596
+ var TableWidget = class extends WidgetType5 {
3400
3597
  constructor(_table) {
3401
3598
  super();
3402
3599
  this._table = _table;
@@ -3463,10 +3660,10 @@ var mention = ({ onSearch }) => {
3463
3660
  };
3464
3661
 
3465
3662
  // packages/ui/react-ui-editor/src/extensions/modes.ts
3466
- import { Facet as Facet5 } from "@codemirror/state";
3467
- import { keymap as keymap6 } from "@codemirror/view";
3663
+ import { Facet as Facet6 } from "@codemirror/state";
3664
+ import { keymap as keymap7 } from "@codemirror/view";
3468
3665
  import { vim } from "@replit/codemirror-vim";
3469
- var editorMode = Facet5.define({
3666
+ var editorMode = Facet6.define({
3470
3667
  combine: (modes) => modes[0] ?? {}
3471
3668
  });
3472
3669
  var EditorModes = {
@@ -3477,7 +3674,7 @@ var EditorModes = {
3477
3674
  type: "vim",
3478
3675
  noTabster: true
3479
3676
  }),
3480
- keymap6.of([
3677
+ keymap7.of([
3481
3678
  {
3482
3679
  key: "Alt-Escape",
3483
3680
  run: (view) => {
@@ -3497,7 +3694,7 @@ var outliner = (options = {}) => {
3497
3694
  };
3498
3695
 
3499
3696
  // packages/ui/react-ui-editor/src/extensions/typewriter.ts
3500
- import { keymap as keymap7 } from "@codemirror/view";
3697
+ import { keymap as keymap8 } from "@codemirror/view";
3501
3698
  var defaultItems = [
3502
3699
  "hello world!",
3503
3700
  "this is a test.",
@@ -3507,7 +3704,7 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
3507
3704
  let t;
3508
3705
  let idx = 0;
3509
3706
  return [
3510
- keymap7.of([
3707
+ keymap8.of([
3511
3708
  {
3512
3709
  // Reset.
3513
3710
  key: "alt-meta-'",
@@ -3553,164 +3750,348 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
3553
3750
  ];
3554
3751
  };
3555
3752
 
3556
- // packages/ui/react-ui-editor/src/themes/default.ts
3557
- import get4 from "lodash.get";
3558
- var defaultTheme = {
3559
- //
3560
- // Main layout:
3561
- // https://codemirror.net/examples/styling
3562
- //
3563
- // <div class="cm-editor [cm-focused] [generated classes]">
3564
- // <div class="cm-scroller">
3565
- // <div class="cm-gutters">
3566
- // <div class="cm-gutter [...]">
3567
- // <div class="cm-gutterElement">...</div>
3568
- // </div>
3569
- // </div>
3570
- // <div class="cm-content" role="textbox" contenteditable="true">
3571
- // <div class="cm-line"></div>
3572
- // </div>
3573
- // <div class="cm-selectionLayer">
3574
- // <div class="cm-selectionBackground"></div>
3575
- // </div>
3576
- // <div class="cm-cursorLayer">
3577
- // <div class="cm-cursor"></div>
3578
- // </div>
3579
- // </div>
3580
- // </div>
3581
- //
3582
- "&": {},
3583
- "&.cm-focused": {
3584
- outline: "none"
3585
- },
3586
- // NOTE: See https://codemirror.net/docs/guide (DOM Structure).
3587
- ".cm-scroller": {
3588
- // TODO(burdon): Reconcile with docs: https://codemirror.net/docs/guide
3589
- // 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.
3590
- overflowY: "auto",
3591
- fontFamily: get4(tokens, "fontFamily.mono", []).join(","),
3592
- lineHeight: 1.5
3593
- },
3594
- ".cm-content": {
3595
- // TODO(burdon): Is it possible to remove the padding value from CM's default theme?
3596
- // padding: 'unset',
3597
- // NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
3598
- fontSize: "16px"
3599
- },
3600
- "&light .cm-content": {
3601
- color: get4(tokens, "extend.semanticColors.base.fg.light", "black"),
3602
- caretColor: "black"
3603
- },
3604
- "&dark .cm-content": {
3605
- color: get4(tokens, "extend.semanticColors.base.fg.dark", "white"),
3606
- caretColor: "white"
3607
- },
3608
- //
3609
- // Cursor
3610
- //
3611
- "&light .cm-cursor, &light .cm-dropCursor": {
3612
- borderLeft: "2px solid black"
3613
- },
3614
- "&dark .cm-cursor, &dark .cm-dropCursor": {
3615
- borderLeft: "2px solid white"
3616
- },
3617
- "&light .cm-placeholder": {
3618
- color: get4(tokens, "extend.semanticColors.description.light", "rgba(0,0,0,.2)")
3619
- },
3620
- "&dark .cm-placeholder": {
3621
- color: get4(tokens, "extend.semanticColors.description.dark", "rgba(255,255,255,.2)")
3622
- },
3623
- //
3624
- // line
3625
- //
3626
- ".cm-line": {
3627
- paddingInline: 0
3628
- },
3629
- ".cm-activeLine": {
3630
- background: "transparent"
3631
- },
3632
- //
3633
- // gutter
3634
- //
3635
- ".cm-gutterElement": {
3636
- width: "48px"
3637
- },
3638
- //
3639
- // Selection
3640
- //
3641
- "&light .cm-selectionBackground": {
3642
- background: get4(tokens, "extend.colors.primary.100")
3643
- },
3644
- "&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
3645
- background: get4(tokens, "extend.colors.primary.200")
3646
- },
3647
- "&dark .cm-selectionBackground": {
3648
- background: get4(tokens, "extend.colors.primary.700")
3649
- },
3650
- "&dark.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
3651
- background: get4(tokens, "extend.colors.primary.600")
3652
- },
3653
- //
3654
- // Search
3655
- //
3656
- "&light .cm-searchMatch": {
3657
- backgroundColor: get4(tokens, "extend.colors.yellow.100")
3658
- },
3659
- "&dark .cm-searchMatch": {
3660
- backgroundColor: get4(tokens, "extend.colors.yellow.700")
3661
- },
3662
- //
3663
- // link
3664
- //
3665
- ".cm-link": {
3666
- color: get4(tokens, "extend.colors.primary.500"),
3667
- textDecorationLine: "underline",
3668
- textDecorationThickness: "1px",
3669
- textUnderlineOffset: "2px",
3670
- borderRadius: ".125rem",
3671
- fontFamily: get4(tokens, "fontFamily.body", []).join(",")
3672
- },
3673
- //
3674
- // tooltip
3753
+ // packages/ui/react-ui-editor/src/hooks/awareness-provider.ts
3754
+ import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
3755
+ import { Context as Context2 } from "@dxos/context";
3756
+ import { invariant as invariant2 } from "@dxos/invariant";
3757
+ import { log as log3 } from "@dxos/log";
3758
+ var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
3759
+ var DEBOUNCE_INTERVAL = 100;
3760
+ var SpaceAwarenessProvider = class {
3761
+ constructor(params) {
3762
+ this._remoteStates = /* @__PURE__ */ new Map();
3763
+ this.remoteStateChange = new Event2();
3764
+ this._space = params.space;
3765
+ this._channel = params.channel;
3766
+ this._peerId = params.peerId;
3767
+ this._info = params.info;
3768
+ }
3769
+ open() {
3770
+ this._ctx = new Context2();
3771
+ this._postTask = new DeferredTask(this._ctx, async () => {
3772
+ if (this._localState) {
3773
+ await this._space.postMessage(this._channel, {
3774
+ kind: "post",
3775
+ state: this._localState
3776
+ });
3777
+ await sleep(DEBOUNCE_INTERVAL);
3778
+ }
3779
+ });
3780
+ this._ctx.onDispose(this._space.listen(this._channel, (message) => {
3781
+ switch (message.payload.kind) {
3782
+ case "query": {
3783
+ this._handleQueryMessage();
3784
+ break;
3785
+ }
3786
+ case "post": {
3787
+ this._handlePostMessage(message.payload);
3788
+ break;
3789
+ }
3790
+ }
3791
+ }));
3792
+ void this._space.postMessage(this._channel, {
3793
+ kind: "query"
3794
+ }).catch((err) => {
3795
+ log3.debug("failed to query awareness", {
3796
+ err
3797
+ }, {
3798
+ F: __dxlog_file4,
3799
+ L: 89,
3800
+ S: this,
3801
+ C: (f, a) => f(...a)
3802
+ });
3803
+ });
3804
+ }
3805
+ close() {
3806
+ void this._ctx?.dispose();
3807
+ this._ctx = void 0;
3808
+ this._postTask = void 0;
3809
+ }
3810
+ getRemoteStates() {
3811
+ return Array.from(this._remoteStates.values());
3812
+ }
3813
+ update(position) {
3814
+ invariant2(this._postTask, void 0, {
3815
+ F: __dxlog_file4,
3816
+ L: 104,
3817
+ S: this,
3818
+ A: [
3819
+ "this._postTask",
3820
+ ""
3821
+ ]
3822
+ });
3823
+ this._localState = {
3824
+ peerId: this._peerId,
3825
+ position,
3826
+ info: this._info
3827
+ };
3828
+ this._postTask.schedule();
3829
+ }
3830
+ _handleQueryMessage() {
3831
+ invariant2(this._postTask, void 0, {
3832
+ F: __dxlog_file4,
3833
+ L: 115,
3834
+ S: this,
3835
+ A: [
3836
+ "this._postTask",
3837
+ ""
3838
+ ]
3839
+ });
3840
+ this._postTask.schedule();
3841
+ }
3842
+ _handlePostMessage(message) {
3843
+ invariant2(message.kind === "post", void 0, {
3844
+ F: __dxlog_file4,
3845
+ L: 120,
3846
+ S: this,
3847
+ A: [
3848
+ "message.kind === 'post'",
3849
+ ""
3850
+ ]
3851
+ });
3852
+ this._remoteStates.set(message.state.peerId, message.state);
3853
+ this.remoteStateChange.emit();
3854
+ }
3855
+ };
3856
+
3857
+ // packages/ui/react-ui-editor/src/hooks/useActionHandler.ts
3858
+ var useActionHandler = (view) => {
3859
+ return (action) => {
3860
+ if (!view) {
3861
+ return;
3862
+ }
3863
+ let inlineType, listType;
3864
+ switch (action.type) {
3865
+ case "heading":
3866
+ setHeading(parseInt(action.data))(view);
3867
+ break;
3868
+ case "strong":
3869
+ case "emphasis":
3870
+ case "strikethrough":
3871
+ case "code":
3872
+ inlineType = action.type === "strong" ? Inline.Strong : action.type === "emphasis" ? Inline.Emphasis : action.type === "strikethrough" ? Inline.Strikethrough : Inline.Code;
3873
+ (typeof action.data === "boolean" ? setStyle(inlineType, action.data) : toggleStyle(inlineType))(view);
3874
+ break;
3875
+ case "list-ordered":
3876
+ case "list-bullet":
3877
+ case "list-task":
3878
+ listType = action.type === "list-ordered" ? List.Ordered : action.type === "list-bullet" ? List.Bullet : List.Task;
3879
+ (action.data === false ? removeList(listType) : action.data === true ? addList(listType) : toggleList(listType))(view);
3880
+ break;
3881
+ case "blockquote":
3882
+ (action.data === false ? removeBlockquote : action.data === true ? addBlockquote : toggleBlockquote)(view);
3883
+ break;
3884
+ case "codeblock":
3885
+ (action.data === false ? removeCodeblock : addCodeblock)(view);
3886
+ break;
3887
+ case "table":
3888
+ insertTable(view);
3889
+ break;
3890
+ case "link":
3891
+ (action.data === false ? removeLink : addLink)(view);
3892
+ break;
3893
+ case "comment":
3894
+ createComment(view);
3895
+ break;
3896
+ }
3897
+ setTimeout(() => {
3898
+ if (!view.hasFocus) {
3899
+ view.focus();
3900
+ }
3901
+ });
3902
+ };
3903
+ };
3904
+
3905
+ // packages/ui/react-ui-editor/src/hooks/useEditorView.ts
3906
+ import { useRef, useState as useState2 } from "react";
3907
+ var useEditorView = (id) => {
3908
+ const editorRef = useRef(null);
3909
+ const [prev, setPrev] = useState2([
3910
+ null,
3911
+ ""
3912
+ ]);
3913
+ if (prev[0] !== editorRef.current) {
3914
+ setPrev([
3915
+ editorRef.current,
3916
+ id
3917
+ ]);
3918
+ }
3919
+ return [
3920
+ editorRef,
3921
+ prev[1] !== id
3922
+ ];
3923
+ };
3924
+
3925
+ // packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
3926
+ import { closeBrackets as closeBrackets2 } from "@codemirror/autocomplete";
3927
+ import { history as history2 } from "@codemirror/commands";
3928
+ import { bracketMatching as bracketMatching2 } from "@codemirror/language";
3929
+ import { EditorSelection as EditorSelection2, EditorState as EditorState2 } from "@codemirror/state";
3930
+ import { crosshairCursor, drawSelection as drawSelection2, dropCursor as dropCursor2, EditorView as EditorView16, highlightActiveLine, lineNumbers, placeholder as placeholder2, scrollPastEnd } from "@codemirror/view";
3931
+ import defaultsDeep2 from "lodash.defaultsdeep";
3932
+ import { useEffect as useEffect2, useRef as useRef2, useState as useState3 } from "react";
3933
+ import { log as log4 } from "@dxos/log";
3934
+ import { isNotFalsy as isNotFalsy3 } from "@dxos/util";
3935
+
3936
+ // packages/ui/react-ui-editor/src/themes/default.ts
3937
+ import get4 from "lodash.get";
3938
+ var defaultTheme = {
3675
3939
  //
3676
- ".cm-tooltip": {
3677
- border: "none"
3678
- },
3679
- ".cm-tooltip-below": {},
3940
+ // Main layout:
3941
+ // https://codemirror.net/examples/styling
3680
3942
  //
3681
- // autocomplete
3943
+ // <div class="cm-editor [cm-focused] [generated classes]">
3944
+ // <div class="cm-scroller">
3945
+ // <div class="cm-gutters">
3946
+ // <div class="cm-gutter [...]">
3947
+ // <div class="cm-gutterElement">...</div>
3948
+ // </div>
3949
+ // </div>
3950
+ // <div class="cm-content" role="textbox" contenteditable="true">
3951
+ // <div class="cm-line"></div>
3952
+ // </div>
3953
+ // <div class="cm-selectionLayer">
3954
+ // <div class="cm-selectionBackground"></div>
3955
+ // </div>
3956
+ // <div class="cm-cursorLayer">
3957
+ // <div class="cm-cursor"></div>
3958
+ // </div>
3959
+ // </div>
3960
+ // </div>
3682
3961
  //
3683
- ".cm-tooltip-autocomplete": {
3684
- marginTop: "4px",
3685
- marginLeft: "-3px"
3962
+ "&": {},
3963
+ "&.cm-focused": {
3964
+ outline: "none"
3686
3965
  },
3687
- ".cm-tooltip-autocomplete ul li": {},
3688
- ".cm-tooltip-autocomplete ul li[aria-selected]": {},
3689
- ".cm-completionIcon": {
3690
- display: "none"
3966
+ // NOTE: See https://codemirror.net/docs/guide (DOM Structure).
3967
+ ".cm-scroller": {
3968
+ // TODO(burdon): Reconcile with docs: https://codemirror.net/docs/guide
3969
+ // 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.
3970
+ overflowY: "auto",
3971
+ fontFamily: get4(tokens, "fontFamily.mono", []).join(","),
3972
+ lineHeight: 1.5
3691
3973
  },
3692
- ".cm-completionLabel": {
3693
- fontFamily: get4(tokens, "fontFamily.body", []).join(",")
3974
+ ".cm-content": {
3975
+ // TODO(burdon): Is it possible to remove the padding value from CM's default theme?
3976
+ // padding: 'unset',
3977
+ // NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
3978
+ fontSize: "16px"
3694
3979
  },
3695
- ".cm-completionMatchedText": {
3696
- textDecoration: "none"
3980
+ "&light .cm-content": {
3981
+ color: get4(tokens, "extend.semanticColors.base.fg.light", "black"),
3982
+ caretColor: "black"
3983
+ },
3984
+ "&dark .cm-content": {
3985
+ color: get4(tokens, "extend.semanticColors.base.fg.dark", "white"),
3986
+ caretColor: "white"
3697
3987
  },
3698
3988
  //
3699
- // table
3989
+ // Cursor
3700
3990
  //
3701
- ".cm-table *": {
3702
- fontFamily: `${get4(tokens, "fontFamily.mono", []).join(",")} !important`,
3703
- textDecoration: "none !important"
3991
+ "&light .cm-cursor, &light .cm-dropCursor": {
3992
+ borderLeft: "2px solid black"
3704
3993
  },
3705
- ".cm-table-head": {
3706
- padding: "2px 16px 2px 0px",
3707
- borderBottom: `1px solid ${get4(tokens, "extend.colors.neutral.500")}`,
3708
- fontWeight: 100,
3709
- textAlign: "left",
3710
- color: get4(tokens, "extend.colors.neutral.500")
3994
+ "&dark .cm-cursor, &dark .cm-dropCursor": {
3995
+ borderLeft: "2px solid white"
3711
3996
  },
3712
- ".cm-table-cell": {
3713
- padding: "2px 16px 2px 0px"
3997
+ "&light .cm-placeholder": {
3998
+ color: get4(tokens, "extend.semanticColors.description.light", "rgba(0,0,0,.2)")
3999
+ },
4000
+ "&dark .cm-placeholder": {
4001
+ color: get4(tokens, "extend.semanticColors.description.dark", "rgba(255,255,255,.2)")
4002
+ },
4003
+ //
4004
+ // line
4005
+ //
4006
+ ".cm-line": {
4007
+ paddingInline: 0
4008
+ },
4009
+ ".cm-activeLine": {
4010
+ background: "transparent"
4011
+ },
4012
+ //
4013
+ // gutter
4014
+ //
4015
+ ".cm-gutterElement": {
4016
+ width: "48px"
4017
+ },
4018
+ //
4019
+ // Selection
4020
+ //
4021
+ "&light .cm-selectionBackground": {
4022
+ background: get4(tokens, "extend.colors.primary.100")
4023
+ },
4024
+ "&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
4025
+ background: get4(tokens, "extend.colors.primary.200")
4026
+ },
4027
+ "&dark .cm-selectionBackground": {
4028
+ background: get4(tokens, "extend.colors.primary.700")
4029
+ },
4030
+ "&dark.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
4031
+ background: get4(tokens, "extend.colors.primary.600")
4032
+ },
4033
+ //
4034
+ // Search
4035
+ //
4036
+ "&light .cm-searchMatch": {
4037
+ backgroundColor: get4(tokens, "extend.colors.yellow.100")
4038
+ },
4039
+ "&dark .cm-searchMatch": {
4040
+ backgroundColor: get4(tokens, "extend.colors.yellow.700")
4041
+ },
4042
+ //
4043
+ // link
4044
+ //
4045
+ ".cm-link": {
4046
+ color: get4(tokens, "extend.colors.primary.500"),
4047
+ textDecorationLine: "underline",
4048
+ textDecorationThickness: "1px",
4049
+ textUnderlineOffset: "2px",
4050
+ borderRadius: ".125rem",
4051
+ fontFamily: get4(tokens, "fontFamily.body", []).join(",")
4052
+ },
4053
+ //
4054
+ // tooltip
4055
+ //
4056
+ ".cm-tooltip": {
4057
+ border: "none",
4058
+ background: "unset"
4059
+ },
4060
+ ".cm-tooltip-below": {},
4061
+ //
4062
+ // autocomplete
4063
+ //
4064
+ ".cm-tooltip-autocomplete": {
4065
+ marginTop: "4px",
4066
+ marginLeft: "-3px"
4067
+ },
4068
+ ".cm-tooltip-autocomplete ul li": {},
4069
+ ".cm-tooltip-autocomplete ul li[aria-selected]": {},
4070
+ ".cm-completionIcon": {
4071
+ display: "none"
4072
+ },
4073
+ ".cm-completionLabel": {
4074
+ fontFamily: get4(tokens, "fontFamily.body", []).join(",")
4075
+ },
4076
+ ".cm-completionMatchedText": {
4077
+ textDecoration: "none"
4078
+ },
4079
+ //
4080
+ // table
4081
+ //
4082
+ ".cm-table *": {
4083
+ fontFamily: `${get4(tokens, "fontFamily.mono", []).join(",")} !important`,
4084
+ textDecoration: "none !important"
4085
+ },
4086
+ ".cm-table-head": {
4087
+ padding: "2px 16px 2px 0px",
4088
+ borderBottom: `1px solid ${get4(tokens, "extend.colors.neutral.500")}`,
4089
+ fontWeight: 100,
4090
+ textAlign: "left",
4091
+ color: get4(tokens, "extend.colors.neutral.500")
4092
+ },
4093
+ ".cm-table-cell": {
4094
+ padding: "2px 16px 2px 0px"
3714
4095
  },
3715
4096
  //
3716
4097
  // image
@@ -3803,19 +4184,238 @@ var codeTheme = {
3803
4184
  }
3804
4185
  };
3805
4186
 
4187
+ // packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
4188
+ var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
4189
+ var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions } = {}, deps = []) => {
4190
+ const onUpdate = useRef2();
4191
+ const [view, setView] = useState3();
4192
+ const parentRef = useRef2(null);
4193
+ useEffect2(() => {
4194
+ let view2;
4195
+ if (parentRef.current) {
4196
+ const state = EditorState2.create({
4197
+ doc,
4198
+ selection,
4199
+ extensions: [
4200
+ // TODO(burdon): Doesn't catch errors in keymap functions.
4201
+ EditorView16.exceptionSink.of((err) => {
4202
+ log4.catch(err, void 0, {
4203
+ F: __dxlog_file5,
4204
+ L: 70,
4205
+ S: void 0,
4206
+ C: (f, a) => f(...a)
4207
+ });
4208
+ }),
4209
+ extensions,
4210
+ EditorView16.updateListener.of(() => {
4211
+ onUpdate.current?.();
4212
+ })
4213
+ ].filter(isNotFalsy3)
4214
+ });
4215
+ view2 = new EditorView16({
4216
+ parent: parentRef.current,
4217
+ scrollTo,
4218
+ state,
4219
+ // NOTE: Uncomment to debug/monitor all transactions.
4220
+ // https://codemirror.net/docs/ref/#view.EditorView.dispatch
4221
+ dispatchTransactions: (trs, view3) => {
4222
+ if (debug) {
4223
+ logChanges(trs);
4224
+ }
4225
+ view3.update(trs);
4226
+ }
4227
+ });
4228
+ setView(view2);
4229
+ }
4230
+ return () => {
4231
+ view2?.destroy();
4232
+ };
4233
+ }, deps);
4234
+ useEffect2(() => {
4235
+ if (view) {
4236
+ if (!selection && !view.state.selection.main.anchor) {
4237
+ selection = EditorSelection2.single(view.state.doc.line(1).to);
4238
+ }
4239
+ if (selection || scrollTo) {
4240
+ onUpdate.current = () => {
4241
+ onUpdate.current = void 0;
4242
+ view.dispatch({
4243
+ selection,
4244
+ effects: scrollTo && [
4245
+ scrollTo
4246
+ ],
4247
+ scrollIntoView: !scrollTo
4248
+ });
4249
+ };
4250
+ }
4251
+ if (autoFocus) {
4252
+ view.focus();
4253
+ }
4254
+ }
4255
+ }, [
4256
+ view,
4257
+ autoFocus,
4258
+ selection,
4259
+ scrollTo
4260
+ ]);
4261
+ return {
4262
+ parentRef,
4263
+ view
4264
+ };
4265
+ };
4266
+ var defaults = {
4267
+ bracketMatching: true,
4268
+ closeBrackets: true,
4269
+ drawSelection: true,
4270
+ editable: true,
4271
+ history: true,
4272
+ lineWrapping: true
4273
+ };
4274
+ var createBasicExtensions = (_props) => {
4275
+ const props = defaultsDeep2({}, _props, defaults);
4276
+ return [
4277
+ // TODO(burdon): Doesn't catch errors in keymap functions.
4278
+ EditorView16.exceptionSink.of((err) => {
4279
+ log4.catch(err, void 0, {
4280
+ F: __dxlog_file5,
4281
+ L: 167,
4282
+ S: void 0,
4283
+ C: (f, a) => f(...a)
4284
+ });
4285
+ }),
4286
+ props.allowMultipleSelections && EditorState2.allowMultipleSelections.of(true),
4287
+ props.bracketMatching && bracketMatching2(),
4288
+ props.closeBrackets && closeBrackets2(),
4289
+ props.crosshairCursor && crosshairCursor(),
4290
+ props.dropCursor && dropCursor2(),
4291
+ props.drawSelection && drawSelection2(),
4292
+ props.highlightActiveLine && highlightActiveLine(),
4293
+ props.history && history2(),
4294
+ props.lineNumbers && lineNumbers(),
4295
+ props.lineWrapping && EditorView16.lineWrapping,
4296
+ props.placeholder && placeholder2(props.placeholder),
4297
+ props.readonly && [
4298
+ EditorState2.readOnly.of(true),
4299
+ EditorView16.editable.of(false)
4300
+ ],
4301
+ props.scrollPastEnd && scrollPastEnd(),
4302
+ props.tabSize && EditorState2.tabSize.of(props.tabSize)
4303
+ ].filter(isNotFalsy3);
4304
+ };
4305
+ var createThemeExtensions = ({ theme, themeMode, slots } = {}) => {
4306
+ return [
4307
+ EditorView16.baseTheme(defaultTheme),
4308
+ EditorView16.darkTheme.of(themeMode === "dark"),
4309
+ theme && EditorView16.theme(theme),
4310
+ slots?.editor?.className && EditorView16.editorAttributes.of({
4311
+ class: slots.editor.className
4312
+ }),
4313
+ slots?.content?.className && EditorView16.contentAttributes.of({
4314
+ class: slots.content.className
4315
+ })
4316
+ ].filter(isNotFalsy3);
4317
+ };
4318
+
4319
+ // packages/ui/react-ui-editor/src/hooks/useTextModel.ts
4320
+ import get5 from "lodash.get";
4321
+ import { useState as useState4, useMemo as useMemo2 } from "react";
4322
+ import { generateName } from "@dxos/display-name";
4323
+ import { getRawDoc } from "@dxos/echo-schema";
4324
+ import { invariant as invariant3 } from "@dxos/invariant";
4325
+ import { isAutomergeObject } from "@dxos/react-client/echo";
4326
+ import { hueTokens } from "@dxos/react-ui-theme";
4327
+ import { hexToHue } from "@dxos/util";
4328
+ var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
4329
+ var useTextExtensions = ({ id, text, space, identity }) => {
4330
+ const extensions = [
4331
+ automerge(text)
4332
+ ];
4333
+ const peerId = identity?.identityKey.toHex();
4334
+ const { cursorLightValue, cursorDarkValue } = hueTokens[hexToHue(peerId ?? "0")];
4335
+ if (space && identity) {
4336
+ const awarenessProvider2 = new SpaceAwarenessProvider({
4337
+ space,
4338
+ channel: `awareness.${id}`,
4339
+ peerId: identity.identityKey.toHex(),
4340
+ info: {
4341
+ displayName: identity.profile?.displayName ?? generateName(identity.identityKey.toHex()),
4342
+ color: cursorDarkValue,
4343
+ lightColor: cursorLightValue
4344
+ }
4345
+ });
4346
+ extensions.push(awareness(awarenessProvider2));
4347
+ }
4348
+ return extensions;
4349
+ };
4350
+ var useTextModel = (props) => useMemo2(() => createModel(props), Object.values(props));
4351
+ var useInMemoryTextModel = ({ id, defaultContent }) => {
4352
+ const [content, setContent] = useState4(defaultContent ?? "");
4353
+ return {
4354
+ id,
4355
+ content,
4356
+ text: () => content,
4357
+ setContent
4358
+ };
4359
+ };
4360
+ var createModel = ({ space, identity, text }) => {
4361
+ if (!text) {
4362
+ return void 0;
4363
+ }
4364
+ invariant3(isAutomergeObject(text), void 0, {
4365
+ F: __dxlog_file6,
4366
+ L: 88,
4367
+ S: void 0,
4368
+ A: [
4369
+ "isAutomergeObject(text)",
4370
+ ""
4371
+ ]
4372
+ });
4373
+ const obj = text;
4374
+ const doc = getRawDoc(obj, [
4375
+ obj.field
4376
+ ]);
4377
+ const peerId = identity?.identityKey.toHex();
4378
+ const { cursorLightValue, cursorDarkValue } = hueTokens[hexToHue(peerId ?? "0")];
4379
+ const awarenessProvider2 = space && new SpaceAwarenessProvider({
4380
+ space,
4381
+ channel: `automerge.awareness.${obj.id}`,
4382
+ info: {
4383
+ displayName: identity ? identity.profile?.displayName ?? generateName(identity.identityKey.toHex()) : void 0,
4384
+ color: cursorLightValue,
4385
+ lightColor: cursorDarkValue
4386
+ },
4387
+ peerId: identity?.identityKey.toHex() ?? "Anonymous"
4388
+ });
4389
+ const extensions = [
4390
+ automerge({
4391
+ handle: doc.handle,
4392
+ path: doc.path
4393
+ })
4394
+ ];
4395
+ if (awarenessProvider2) {
4396
+ extensions.push(awareness(awarenessProvider2));
4397
+ }
4398
+ return {
4399
+ id: obj.id,
4400
+ content: doc,
4401
+ text: () => get5(doc.handle.docSync(), doc.path),
4402
+ extension: extensions
4403
+ };
4404
+ };
4405
+
3806
4406
  // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
3807
- var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
3808
- var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo = EditorView14.scrollIntoView(0), moveToEndOfLine, selection, theme, slots = defaultSlots, extensions = [], scrollPastEnd: _scrollPastEnd, debug }, forwardedRef) => {
4407
+ var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
4408
+ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo = EditorView17.scrollIntoView(0), moveToEndOfLine, selection, theme, slots = defaultSlots, extensions = [], scrollPastEnd: _scrollPastEnd, debug }, forwardedRef) => {
3809
4409
  const tabsterDOMAttribute = useFocusableGroup({
3810
4410
  tabBehavior: "limited"
3811
4411
  });
3812
4412
  const { themeMode } = useThemeContext();
3813
- const rootRef = useRef(null);
3814
- const [view, setView] = useState2(null);
4413
+ const rootRef = useRef3(null);
4414
+ const [view, setView] = useState5(null);
3815
4415
  useImperativeHandle(forwardedRef, () => view, [
3816
4416
  view
3817
4417
  ]);
3818
- useEffect2(() => {
4418
+ useEffect3(() => {
3819
4419
  if (autoFocus) {
3820
4420
  view?.focus();
3821
4421
  }
@@ -3823,38 +4423,38 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
3823
4423
  view,
3824
4424
  autoFocus
3825
4425
  ]);
3826
- useEffect2(() => {
4426
+ useEffect3(() => {
3827
4427
  if (!model || !rootRef.current) {
3828
4428
  return;
3829
4429
  }
3830
- const state = EditorState2.create({
3831
- doc: model.text(),
4430
+ const state = EditorState3.create({
4431
+ doc: typeof model.content === "string" ? model.content : DocAccessor.getValue(model.content),
3832
4432
  selection,
3833
4433
  extensions: [
3834
4434
  // TODO(burdon): Doesn't catch errors in keymap functions.
3835
- EditorView14.exceptionSink.of((err) => {
3836
- log3.catch(err, void 0, {
3837
- F: __dxlog_file4,
3838
- L: 122,
4435
+ EditorView17.exceptionSink.of((err) => {
4436
+ log5.catch(err, void 0, {
4437
+ F: __dxlog_file7,
4438
+ L: 123,
3839
4439
  S: void 0,
3840
4440
  C: (f, a) => f(...a)
3841
4441
  });
3842
4442
  }),
3843
4443
  // Theme.
3844
4444
  // TODO(burdon): Make base theme configurable.
3845
- EditorView14.baseTheme(defaultTheme),
3846
- theme && EditorView14.theme(theme),
3847
- EditorView14.darkTheme.of(themeMode === "dark"),
3848
- slots.editor?.className && EditorView14.editorAttributes.of({
4445
+ EditorView17.baseTheme(defaultTheme),
4446
+ theme && EditorView17.theme(theme),
4447
+ EditorView17.darkTheme.of(themeMode === "dark"),
4448
+ slots.editor?.className && EditorView17.editorAttributes.of({
3849
4449
  class: slots.editor.className
3850
4450
  }),
3851
- slots.content?.className && EditorView14.contentAttributes.of({
4451
+ slots.content?.className && EditorView17.contentAttributes.of({
3852
4452
  class: slots.content.className
3853
4453
  }),
3854
4454
  // NOTE: Assumes default line height.
3855
- _scrollPastEnd && scrollPastEnd(),
4455
+ _scrollPastEnd && scrollPastEnd2(),
3856
4456
  // Focus.
3857
- EditorView14.updateListener.of((update2) => {
4457
+ EditorView17.updateListener.of((update2) => {
3858
4458
  update2.transactions.forEach((transaction) => {
3859
4459
  if (transaction.isUserEvent("focus.container")) {
3860
4460
  rootRef.current?.focus();
@@ -3862,8 +4462,8 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
3862
4462
  });
3863
4463
  }),
3864
4464
  // State.
3865
- EditorView14.editable.of(!readonly),
3866
- EditorState2.readOnly.of(!!readonly),
4465
+ EditorView17.editable.of(!readonly),
4466
+ EditorState3.readOnly.of(!!readonly),
3867
4467
  // Storage and replication.
3868
4468
  // NOTE: This must come before user extensions.
3869
4469
  model.extension,
@@ -3871,7 +4471,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
3871
4471
  ...extensions
3872
4472
  ].filter(isNotFalsy4)
3873
4473
  });
3874
- const view2 = new EditorView14({
4474
+ const view2 = new EditorView17({
3875
4475
  state,
3876
4476
  parent: rootRef.current,
3877
4477
  scrollTo,
@@ -3928,14 +4528,16 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
3928
4528
  ...tabsterDOMAttribute
3929
4529
  });
3930
4530
  });
3931
- var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, lineWrapping, theme = textTheme, slots, extensions: _extensions, ...props }, forwardedRef) => {
4531
+ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, lineWrapping = true, theme = textTheme, slots, extensions: _extensions, ...props }, forwardedRef) => {
3932
4532
  const { themeMode } = useThemeContext();
3933
- const updatedSlots = defaultsDeep2({}, slots, defaultTextSlots);
3934
- const extensions = useMemo2(() => [
3935
- createBasicBundle({
3936
- themeMode,
3937
- placeholder: placeholder3,
3938
- lineWrapping
4533
+ const updatedSlots = defaultsDeep3({}, slots, defaultTextSlots);
4534
+ const extensions = useMemo3(() => [
4535
+ createBasicExtensions({
4536
+ lineWrapping,
4537
+ placeholder: placeholder3
4538
+ }),
4539
+ createThemeExtensions({
4540
+ themeMode
3939
4541
  }),
3940
4542
  ..._extensions ?? []
3941
4543
  ], [
@@ -3955,8 +4557,8 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholde
3955
4557
  });
3956
4558
  var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, theme = markdownTheme, slots, extensions: _extensions, ...props }, forwardedRef) => {
3957
4559
  const { themeMode } = useThemeContext();
3958
- const updatedSlots = defaultsDeep2({}, slots, defaultMarkdownSlots);
3959
- const extensions = useMemo2(() => [
4560
+ const updatedSlots = defaultsDeep3({}, slots, defaultMarkdownSlots);
4561
+ const extensions = useMemo3(() => [
3960
4562
  createMarkdownExtensions({
3961
4563
  themeMode,
3962
4564
  placeholder: placeholder3
@@ -3994,7 +4596,7 @@ var defaultMarkdownSlots = {
3994
4596
  // packages/ui/react-ui-editor/src/components/Toolbar/Toolbar.tsx
3995
4597
  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";
3996
4598
  import { createContext } from "@radix-ui/react-context";
3997
- import React2, { useRef as useRef2, useState as useState3 } from "react";
4599
+ import React2, { useRef as useRef4, useState as useState6 } from "react";
3998
4600
  import { DensityProvider, ElevationProvider, Select, Toolbar as NaturalToolbar, Tooltip, useTranslation } from "@dxos/react-ui";
3999
4601
  import { getSize } from "@dxos/react-ui-theme";
4000
4602
  var tooltipProps = {
@@ -4052,9 +4654,9 @@ var MarkdownHeading = () => {
4052
4654
  const header = blockType && /heading(\d)/.exec(blockType);
4053
4655
  const value = header ? header[1] : blockType === "paragraph" || !blockType ? "0" : void 0;
4054
4656
  const HeadingIcon = HeadingIcons[value ?? "0"];
4055
- const suppressNextTooltip = useRef2(false);
4056
- const [tooltipOpen, setTooltipOpen] = useState3(false);
4057
- const [selectOpen, setSelectOpen] = useState3(false);
4657
+ const suppressNextTooltip = useRef4(false);
4658
+ const [tooltipOpen, setTooltipOpen] = useState6(false);
4659
+ const [selectOpen, setSelectOpen] = useState6(false);
4058
4660
  return /* @__PURE__ */ React2.createElement(Tooltip.Root, {
4059
4661
  open: tooltipOpen,
4060
4662
  onOpenChange: (nextOpen) => {
@@ -4257,378 +4859,6 @@ var Toolbar = {
4257
4859
  Markdown: MarkdownStandard,
4258
4860
  Extended: MarkdownExtended
4259
4861
  };
4260
-
4261
- // packages/ui/react-ui-editor/src/hooks/awareness-provider.ts
4262
- import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
4263
- import { Context as Context2 } from "@dxos/context";
4264
- import { invariant as invariant2 } from "@dxos/invariant";
4265
- import { log as log4 } from "@dxos/log";
4266
- var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
4267
- var DEBOUNCE_INTERVAL = 100;
4268
- var SpaceAwarenessProvider = class {
4269
- constructor(params) {
4270
- this._remoteStates = /* @__PURE__ */ new Map();
4271
- this.remoteStateChange = new Event2();
4272
- this._space = params.space;
4273
- this._channel = params.channel;
4274
- this._peerId = params.peerId;
4275
- this._info = params.info;
4276
- }
4277
- open() {
4278
- this._ctx = new Context2();
4279
- this._postTask = new DeferredTask(this._ctx, async () => {
4280
- if (this._localState) {
4281
- await this._space.postMessage(this._channel, {
4282
- kind: "post",
4283
- state: this._localState
4284
- });
4285
- await sleep(DEBOUNCE_INTERVAL);
4286
- }
4287
- });
4288
- this._ctx.onDispose(this._space.listen(this._channel, (message) => {
4289
- switch (message.payload.kind) {
4290
- case "query": {
4291
- this._handleQueryMessage();
4292
- break;
4293
- }
4294
- case "post": {
4295
- this._handlePostMessage(message.payload);
4296
- break;
4297
- }
4298
- }
4299
- }));
4300
- void this._space.postMessage(this._channel, {
4301
- kind: "query"
4302
- }).catch((err) => {
4303
- log4.debug("failed to query awareness", {
4304
- err
4305
- }, {
4306
- F: __dxlog_file5,
4307
- L: 89,
4308
- S: this,
4309
- C: (f, a) => f(...a)
4310
- });
4311
- });
4312
- }
4313
- close() {
4314
- void this._ctx?.dispose();
4315
- this._ctx = void 0;
4316
- this._postTask = void 0;
4317
- }
4318
- getRemoteStates() {
4319
- return Array.from(this._remoteStates.values());
4320
- }
4321
- update(position) {
4322
- invariant2(this._postTask, void 0, {
4323
- F: __dxlog_file5,
4324
- L: 104,
4325
- S: this,
4326
- A: [
4327
- "this._postTask",
4328
- ""
4329
- ]
4330
- });
4331
- this._localState = {
4332
- peerId: this._peerId,
4333
- position,
4334
- info: this._info
4335
- };
4336
- this._postTask.schedule();
4337
- }
4338
- _handleQueryMessage() {
4339
- invariant2(this._postTask, void 0, {
4340
- F: __dxlog_file5,
4341
- L: 115,
4342
- S: this,
4343
- A: [
4344
- "this._postTask",
4345
- ""
4346
- ]
4347
- });
4348
- this._postTask.schedule();
4349
- }
4350
- _handlePostMessage(message) {
4351
- invariant2(message.kind === "post", void 0, {
4352
- F: __dxlog_file5,
4353
- L: 120,
4354
- S: this,
4355
- A: [
4356
- "message.kind === 'post'",
4357
- ""
4358
- ]
4359
- });
4360
- this._remoteStates.set(message.state.peerId, message.state);
4361
- this.remoteStateChange.emit();
4362
- }
4363
- };
4364
-
4365
- // packages/ui/react-ui-editor/src/hooks/defs.ts
4366
- import { StateField as StateField6 } from "@codemirror/state";
4367
- var modelState = StateField6.define({
4368
- create: () => void 0,
4369
- update: (model) => model
4370
- });
4371
-
4372
- // packages/ui/react-ui-editor/src/hooks/useActionHandler.ts
4373
- var useActionHandler = (view) => {
4374
- return (action) => {
4375
- if (!view) {
4376
- return;
4377
- }
4378
- let inlineType, listType;
4379
- switch (action.type) {
4380
- case "heading":
4381
- setHeading(parseInt(action.data))(view);
4382
- break;
4383
- case "strong":
4384
- case "emphasis":
4385
- case "strikethrough":
4386
- case "code":
4387
- inlineType = action.type === "strong" ? Inline.Strong : action.type === "emphasis" ? Inline.Emphasis : action.type === "strikethrough" ? Inline.Strikethrough : Inline.Code;
4388
- (typeof action.data === "boolean" ? setStyle(inlineType, action.data) : toggleStyle(inlineType))(view);
4389
- break;
4390
- case "list-ordered":
4391
- case "list-bullet":
4392
- case "list-task":
4393
- listType = action.type === "list-ordered" ? List.Ordered : action.type === "list-bullet" ? List.Bullet : List.Task;
4394
- (action.data === false ? removeList(listType) : action.data === true ? addList(listType) : toggleList(listType))(view);
4395
- break;
4396
- case "blockquote":
4397
- (action.data === false ? removeBlockquote : action.data === true ? addBlockquote : toggleBlockquote)(view);
4398
- break;
4399
- case "codeblock":
4400
- (action.data === false ? removeCodeblock : addCodeblock)(view);
4401
- break;
4402
- case "table":
4403
- insertTable(view);
4404
- break;
4405
- case "link":
4406
- (action.data === false ? removeLink : addLink)(view);
4407
- break;
4408
- case "comment":
4409
- createComment(view);
4410
- break;
4411
- }
4412
- setTimeout(() => {
4413
- if (!view.hasFocus) {
4414
- view.focus();
4415
- }
4416
- });
4417
- };
4418
- };
4419
-
4420
- // packages/ui/react-ui-editor/src/hooks/useEditorView.ts
4421
- import { useRef as useRef3, useState as useState4 } from "react";
4422
- var useEditorView = (id) => {
4423
- const editorRef = useRef3(null);
4424
- const [prev, setPrev] = useState4([
4425
- null,
4426
- ""
4427
- ]);
4428
- if (prev[0] !== editorRef.current) {
4429
- setPrev([
4430
- editorRef.current,
4431
- id
4432
- ]);
4433
- }
4434
- return [
4435
- editorRef,
4436
- prev[1] !== id
4437
- ];
4438
- };
4439
-
4440
- // packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
4441
- import { EditorSelection as EditorSelection2, EditorState as EditorState3 } from "@codemirror/state";
4442
- import { EditorView as EditorView15 } from "@codemirror/view";
4443
- import { useEffect as useEffect3, useRef as useRef4, useState as useState5 } from "react";
4444
- import { log as log5 } from "@dxos/log";
4445
- import { isNotFalsy as isNotFalsy5 } from "@dxos/util";
4446
- var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
4447
- var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions } = {}, deps) => {
4448
- const onUpdate = useRef4();
4449
- const [view, setView] = useState5();
4450
- const parentRef = useRef4(null);
4451
- useEffect3(() => {
4452
- let view2;
4453
- if (parentRef.current) {
4454
- const state = EditorState3.create({
4455
- doc,
4456
- selection,
4457
- extensions: [
4458
- // TODO(burdon): Doesn't catch errors in keymap functions.
4459
- EditorView15.exceptionSink.of((err) => {
4460
- log5.catch(err, void 0, {
4461
- F: __dxlog_file6,
4462
- L: 57,
4463
- S: void 0,
4464
- C: (f, a) => f(...a)
4465
- });
4466
- }),
4467
- extensions,
4468
- EditorView15.updateListener.of(() => {
4469
- onUpdate.current?.();
4470
- })
4471
- ].filter(isNotFalsy5)
4472
- });
4473
- view2 = new EditorView15({
4474
- parent: parentRef.current,
4475
- scrollTo,
4476
- state,
4477
- // NOTE: Uncomment to debug/monitor all transactions.
4478
- // https://codemirror.net/docs/ref/#view.EditorView.dispatch
4479
- dispatchTransactions: (trs, view3) => {
4480
- if (debug) {
4481
- logChanges(trs);
4482
- }
4483
- view3.update(trs);
4484
- }
4485
- });
4486
- setView(view2);
4487
- }
4488
- return () => {
4489
- view2?.destroy();
4490
- };
4491
- }, deps);
4492
- useEffect3(() => {
4493
- if (view) {
4494
- if (!selection && !view.state.selection.main.anchor) {
4495
- selection = EditorSelection2.single(view.state.doc.line(1).to);
4496
- }
4497
- if (selection || scrollTo) {
4498
- onUpdate.current = () => {
4499
- onUpdate.current = void 0;
4500
- view.dispatch({
4501
- selection,
4502
- effects: scrollTo && [
4503
- scrollTo
4504
- ],
4505
- scrollIntoView: !scrollTo
4506
- });
4507
- };
4508
- }
4509
- if (autoFocus) {
4510
- view.focus();
4511
- }
4512
- }
4513
- }, [
4514
- view,
4515
- autoFocus,
4516
- selection,
4517
- scrollTo
4518
- ]);
4519
- return {
4520
- parentRef,
4521
- view
4522
- };
4523
- };
4524
- var createDataExtensions = ({ readonly = false } = {}) => {
4525
- return [
4526
- //
4527
- EditorState3.readOnly.of(readonly),
4528
- EditorView15.editable.of(!readonly)
4529
- ];
4530
- };
4531
- var createThemeExtensions = ({ theme, themeMode, slots } = {}) => {
4532
- return [
4533
- //
4534
- EditorView15.baseTheme(defaultTheme),
4535
- theme && EditorView15.theme(theme),
4536
- EditorView15.darkTheme.of(themeMode === "dark"),
4537
- EditorView15.editorAttributes.of({
4538
- class: slots?.editor?.className ?? ""
4539
- }),
4540
- EditorView15.contentAttributes.of({
4541
- class: slots?.content?.className ?? ""
4542
- })
4543
- ].filter(isNotFalsy5);
4544
- };
4545
-
4546
- // packages/ui/react-ui-editor/src/hooks/useTextModel.ts
4547
- import get5 from "lodash.get";
4548
- import { useState as useState6, useMemo as useMemo3 } from "react";
4549
- import { generateName } from "@dxos/display-name";
4550
- import { getRawDoc } from "@dxos/echo-schema";
4551
- import { invariant as invariant3 } from "@dxos/invariant";
4552
- import { isAutomergeObject } from "@dxos/react-client/echo";
4553
- var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
4554
- var useTextExtensions = ({ id, text, space, identity }) => {
4555
- const extensions = [
4556
- automerge(text)
4557
- ];
4558
- if (space && identity) {
4559
- const awarenessProvider2 = new SpaceAwarenessProvider({
4560
- space,
4561
- channel: `awareness.${id}`,
4562
- peerId: identity.identityKey.toHex(),
4563
- info: {
4564
- displayName: identity.profile?.displayName ?? generateName(identity.identityKey.toHex()),
4565
- color: cursorColor.color,
4566
- lightColor: cursorColor.light
4567
- }
4568
- });
4569
- extensions.push(awareness(awarenessProvider2));
4570
- }
4571
- return extensions;
4572
- };
4573
- var useTextModel = (props) => useMemo3(() => createModel(props), Object.values(props));
4574
- var useInMemoryTextModel = ({ id, defaultContent }) => {
4575
- const [content, setContent] = useState6(defaultContent ?? "");
4576
- return {
4577
- id,
4578
- content,
4579
- setContent,
4580
- text: () => content
4581
- };
4582
- };
4583
- var createModel = ({ space, identity, text }) => {
4584
- if (!text) {
4585
- return void 0;
4586
- }
4587
- invariant3(isAutomergeObject(text), void 0, {
4588
- F: __dxlog_file7,
4589
- L: 83,
4590
- S: void 0,
4591
- A: [
4592
- "isAutomergeObject(text)",
4593
- ""
4594
- ]
4595
- });
4596
- const obj = text;
4597
- const doc = getRawDoc(obj, [
4598
- obj.field
4599
- ]);
4600
- const awarenessProvider2 = space && new SpaceAwarenessProvider({
4601
- space,
4602
- channel: `automerge.awareness.${obj.id}`,
4603
- info: {
4604
- displayName: identity ? identity.profile?.displayName ?? generateName(identity.identityKey.toHex()) : void 0,
4605
- color: cursorColor.color,
4606
- lightColor: cursorColor.light
4607
- },
4608
- peerId: identity?.identityKey.toHex() ?? "Anonymous"
4609
- });
4610
- const extensions = [
4611
- modelState.init(() => model),
4612
- automerge({
4613
- handle: doc.handle,
4614
- path: doc.path
4615
- })
4616
- ];
4617
- if (awarenessProvider2) {
4618
- extensions.push(awareness(awarenessProvider2));
4619
- }
4620
- const model = {
4621
- id: obj.id,
4622
- content: doc,
4623
- text: () => get5(doc.handle.docSync(), doc.path),
4624
- extension: extensions,
4625
- peer: identity ? {
4626
- id: identity.identityKey.toHex(),
4627
- name: identity.profile?.displayName
4628
- } : void 0
4629
- };
4630
- return model;
4631
- };
4632
4862
  export {
4633
4863
  BaseTextEditor,
4634
4864
  Cursor,
@@ -4657,11 +4887,11 @@ export {
4657
4887
  blast,
4658
4888
  callbackWrapper,
4659
4889
  codeTheme,
4890
+ command,
4660
4891
  comments,
4661
4892
  compareFormatting,
4662
- createBasicBundle,
4893
+ createBasicExtensions,
4663
4894
  createComment,
4664
- createDataExtensions,
4665
4895
  createMarkdownExtensions,
4666
4896
  createThemeExtensions,
4667
4897
  cursorLineMargin,
@@ -4672,6 +4902,7 @@ export {
4672
4902
  defaultSlots,
4673
4903
  defaultTextSlots,
4674
4904
  defaultTheme,
4905
+ dnd,
4675
4906
  editorFillLayoutEditor,
4676
4907
  editorFillLayoutRoot,
4677
4908
  editorMode,
@@ -4682,7 +4913,7 @@ export {
4682
4913
  getToken,
4683
4914
  image,
4684
4915
  insertTable,
4685
- keymap8 as keymap,
4916
+ keymap9 as keymap,
4686
4917
  linkTooltip,
4687
4918
  listener,
4688
4919
  logChanges,
@@ -4691,7 +4922,6 @@ export {
4691
4922
  markdownTagsExtensions,
4692
4923
  markdownTheme,
4693
4924
  mention,
4694
- modelState,
4695
4925
  outliner,
4696
4926
  removeBlockquote,
4697
4927
  removeCodeblock,