@dxos/react-ui-editor 0.4.7-main.ea67fec → 0.4.7-main.f4b92be

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 (76) hide show
  1. package/dist/lib/browser/index.mjs +1048 -816
  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 +3 -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/themes/default.d.ts.map +1 -1
  46. package/package.json +24 -24
  47. package/src/components/TextEditor/MarkdownEditor.stories.tsx +95 -8
  48. package/src/components/TextEditor/TextEditor.stories.tsx +0 -15
  49. package/src/components/TextEditor/TextEditor.tsx +11 -6
  50. package/src/components/TextEditor/index.ts +0 -3
  51. package/src/components/Toolbar/Toolbar.stories.tsx +2 -1
  52. package/src/{components/TextEditor → extensions/automerge}/automerge.stories.tsx +32 -37
  53. package/src/extensions/command/command.ts +35 -0
  54. package/src/extensions/command/hint.ts +76 -0
  55. package/src/extensions/command/index.ts +5 -0
  56. package/src/extensions/command/state.ts +106 -0
  57. package/src/extensions/cursor-line-margin.ts +2 -1
  58. package/src/extensions/dnd.ts +15 -0
  59. package/src/extensions/index.ts +2 -1
  60. package/src/extensions/listener.ts +3 -3
  61. package/src/extensions/markdown/bundle.ts +4 -14
  62. package/src/extensions/markdown/decorate.ts +20 -13
  63. package/src/extensions/util/dom.ts +36 -0
  64. package/src/hooks/defs.ts +6 -20
  65. package/src/hooks/useActionHandler.ts +11 -11
  66. package/src/hooks/useEditorView.ts +0 -1
  67. package/src/{components/TextEditor/hooks.stories.tsx → hooks/useTextEditor.stories.tsx} +8 -8
  68. package/src/hooks/useTextEditor.ts +69 -14
  69. package/src/hooks/useTextModel.ts +6 -13
  70. package/src/index.ts +2 -0
  71. package/src/themes/default.ts +1 -0
  72. package/dist/types/src/components/TextEditor/automerge.stories.d.ts.map +0 -1
  73. package/dist/types/src/components/TextEditor/hooks.stories.d.ts.map +0 -1
  74. package/dist/types/src/extensions/basic.d.ts +0 -9
  75. package/dist/types/src/extensions/basic.d.ts.map +0 -1
  76. package/src/extensions/basic.ts +0 -41
@@ -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";
@@ -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,10 +1042,227 @@ var random = (min, max) => {
1063
1042
  return min + ~~(Math.random() * (max - min + 1));
1064
1043
  };
1065
1044
 
1045
+ // packages/ui/react-ui-editor/src/extensions/command/command.ts
1046
+ import { EditorView as EditorView6, keymap as keymap3 } from "@codemirror/view";
1047
+
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;
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 = [
1145
+ {
1146
+ key: "/",
1147
+ run: openCommand
1148
+ },
1149
+ {
1150
+ key: "Escape",
1151
+ run: closeCommand
1152
+ }
1153
+ ];
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
+
1066
1262
  // packages/ui/react-ui-editor/src/extensions/comments.ts
1067
1263
  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";
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";
1070
1266
  import sortBy from "lodash.sortby";
1071
1267
  import { useEffect } from "react";
1072
1268
  import { debounce } from "@dxos/async";
@@ -1142,13 +1338,13 @@ var logChanges = (trs) => {
1142
1338
  };
1143
1339
 
1144
1340
  // packages/ui/react-ui-editor/src/extensions/comments.ts
1145
- var documentId = Facet3.define({
1341
+ var documentId = Facet4.define({
1146
1342
  combine: (values) => values[0]
1147
1343
  });
1148
- var setComments = StateEffect2.define();
1149
- var setSelection = StateEffect2.define();
1150
- var setCommentState = StateEffect2.define();
1151
- var commentsState = StateField3.define({
1344
+ var setComments = StateEffect3.define();
1345
+ var setSelection = StateEffect3.define();
1346
+ var setCommentState = StateEffect3.define();
1347
+ var commentsState = StateField4.define({
1152
1348
  create: (state) => ({
1153
1349
  id: state.facet(documentId),
1154
1350
  comments: [],
@@ -1186,7 +1382,7 @@ var commentsState = StateField3.define({
1186
1382
  return value;
1187
1383
  }
1188
1384
  });
1189
- var styles3 = EditorView6.baseTheme({
1385
+ var styles3 = EditorView7.baseTheme({
1190
1386
  "&light .cm-comment, &light .cm-comment-current": {
1191
1387
  mixBlendMode: "darken"
1192
1388
  },
@@ -1208,19 +1404,19 @@ var styles3 = EditorView6.baseTheme({
1208
1404
  backgroundColor: getToken("extend.colors.yellow.950")
1209
1405
  }
1210
1406
  });
1211
- var commentMark = Decoration3.mark({
1407
+ var commentMark = Decoration4.mark({
1212
1408
  class: "cm-comment",
1213
1409
  attributes: {
1214
1410
  "data-testid": "cm-comment"
1215
1411
  }
1216
1412
  });
1217
- var commentCurrentMark = Decoration3.mark({
1413
+ var commentCurrentMark = Decoration4.mark({
1218
1414
  class: "cm-comment-current",
1219
1415
  attributes: {
1220
1416
  "data-testid": "cm-comment"
1221
1417
  }
1222
1418
  });
1223
- var commentsDecorations = EditorView6.decorations.compute([
1419
+ var commentsDecorations = EditorView7.decorations.compute([
1224
1420
  commentsState
1225
1421
  ], (state) => {
1226
1422
  const { selection: { current }, comments: comments2 } = state.field(commentsState);
@@ -1236,7 +1432,7 @@ var commentsDecorations = EditorView6.decorations.compute([
1236
1432
  return commentMark.range(range.from, range.to);
1237
1433
  }
1238
1434
  }).filter(nonNullable);
1239
- return Decoration3.set(decorations);
1435
+ return Decoration4.set(decorations);
1240
1436
  });
1241
1437
  var trackPastedComments = (onUpdate) => {
1242
1438
  let tracked = null;
@@ -1258,7 +1454,7 @@ var trackPastedComments = (onUpdate) => {
1258
1454
  }
1259
1455
  };
1260
1456
  return [
1261
- EditorView6.domEventHandlers({
1457
+ EditorView7.domEventHandlers({
1262
1458
  cut: handleTrack,
1263
1459
  copy: handleTrack
1264
1460
  }),
@@ -1280,7 +1476,7 @@ var trackPastedComments = (onUpdate) => {
1280
1476
  return effects;
1281
1477
  }),
1282
1478
  // Handle paste or the undo of comment deletion.
1283
- EditorView6.updateListener.of((update2) => {
1479
+ EditorView7.updateListener.of((update2) => {
1284
1480
  const restore = [];
1285
1481
  for (let i = 0; i < update2.transactions.length; i++) {
1286
1482
  const tr = update2.transactions[i];
@@ -1336,7 +1532,7 @@ var mapTrackedComment = (comment, changes) => ({
1336
1532
  from: changes.mapPos(comment.from, 1),
1337
1533
  to: changes.mapPos(comment.to, 1)
1338
1534
  });
1339
- var restoreCommentEffect = StateEffect2.define({
1535
+ var restoreCommentEffect = StateEffect3.define({
1340
1536
  map: mapTrackedComment
1341
1537
  });
1342
1538
  var createComment = (view) => {
@@ -1377,7 +1573,7 @@ var createComment = (view) => {
1377
1573
  }
1378
1574
  return false;
1379
1575
  };
1380
- var optionsFacet = Facet3.define({
1576
+ var optionsFacet = Facet4.define({
1381
1577
  combine: (providers) => providers[0]
1382
1578
  });
1383
1579
  var comments = (options = {}) => {
@@ -1392,7 +1588,7 @@ var comments = (options = {}) => {
1392
1588
  //
1393
1589
  // Keymap.
1394
1590
  //
1395
- options.onCreate ? keymap3.of([
1591
+ options.onCreate ? keymap4.of([
1396
1592
  {
1397
1593
  key: shortcut,
1398
1594
  run: callbackWrapper(createComment)
@@ -1431,7 +1627,7 @@ var comments = (options = {}) => {
1431
1627
  //
1432
1628
  // Track deleted ranges and update ranges for decorations.
1433
1629
  //
1434
- EditorView6.updateListener.of(({ view, state, changes }) => {
1630
+ EditorView7.updateListener.of(({ view, state, changes }) => {
1435
1631
  let mod = false;
1436
1632
  const { comments: comments2, ...value } = state.field(commentsState);
1437
1633
  changes.iterChanges((from, to, from2, to2) => {
@@ -1463,7 +1659,7 @@ var comments = (options = {}) => {
1463
1659
  //
1464
1660
  // Track selection/proximity.
1465
1661
  //
1466
- EditorView6.updateListener.of(({ view, state }) => {
1662
+ EditorView7.updateListener.of(({ view, state }) => {
1467
1663
  let min = Infinity;
1468
1664
  const { selection: { current, closest }, comments: comments2 } = state.field(commentsState);
1469
1665
  const { head } = state.selection.main;
@@ -1512,7 +1708,7 @@ var focusComment = (view, id, center = true) => {
1512
1708
  },
1513
1709
  effects: [
1514
1710
  //
1515
- EditorView6.scrollIntoView(range.from, center ? {
1711
+ EditorView7.scrollIntoView(range.from, center ? {
1516
1712
  y: "center"
1517
1713
  } : void 0),
1518
1714
  setSelection.of({
@@ -1540,14 +1736,14 @@ var useComments = (view, id, comments2 = []) => {
1540
1736
  };
1541
1737
 
1542
1738
  // packages/ui/react-ui-editor/src/extensions/cursor-line-margin.ts
1543
- import { Facet as Facet4, Transaction } from "@codemirror/state";
1544
- import { EditorView as EditorView7 } from "@codemirror/view";
1545
- 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({
1546
1742
  combine: (input) => input[0] ?? 3
1547
1743
  });
1548
1744
  var annotation = "cursorLineMargin";
1549
1745
  var lineAtPos = (s, pos) => s.doc.lineAt(pos).number;
1550
- var cursorLineMargin = EditorView7.updateListener.of(({ transactions, state, selectionSet, startState, view }) => {
1746
+ var cursorLineMargin = EditorView8.updateListener.of(({ transactions, state, selectionSet, startState, view }) => {
1551
1747
  if (transactions.length < 1 || transactions.some((tr) => tr.isUserEvent(annotation))) {
1552
1748
  return;
1553
1749
  }
@@ -1583,38 +1779,48 @@ var cursorLineMargin = EditorView7.updateListener.of(({ transactions, state, sel
1583
1779
  }
1584
1780
  view.dispatch({
1585
1781
  annotations: Transaction.userEvent.of(annotation),
1586
- effects: EditorView7.scrollIntoView(s.selection.main.head, {
1782
+ effects: EditorView8.scrollIntoView(s.selection.main.head, {
1587
1783
  y: needsScrollTop ? "start" : "end",
1588
1784
  yMargin: view.defaultLineHeight * cursorLineMargin2
1589
1785
  })
1590
1786
  });
1591
1787
  });
1592
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
+
1593
1799
  // packages/ui/react-ui-editor/src/extensions/listener.ts
1594
- import { EditorView as EditorView8 } from "@codemirror/view";
1800
+ import { EditorView as EditorView10 } from "@codemirror/view";
1595
1801
  var listener = ({ onFocus, onChange }) => {
1596
1802
  const extensions = [];
1597
- onFocus && extensions.push(EditorView8.focusChangeEffect.of((_, focused) => {
1598
- onFocus(focused);
1803
+ onFocus && extensions.push(EditorView10.focusChangeEffect.of((_, focusing) => {
1804
+ onFocus(focusing);
1599
1805
  return null;
1600
1806
  }));
1601
- onChange && extensions.push(EditorView8.updateListener.of((update2) => {
1807
+ onChange && extensions.push(EditorView10.updateListener.of((update2) => {
1602
1808
  onChange(update2.state.doc.toString());
1603
1809
  }));
1604
1810
  return extensions;
1605
1811
  };
1606
1812
 
1607
1813
  // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
1608
- import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
1609
- 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";
1610
1816
  import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
1611
- import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
1817
+ import { bracketMatching, defaultHighlightStyle, indentOnInput, syntaxHighlighting } from "@codemirror/language";
1612
1818
  import { languages } from "@codemirror/language-data";
1613
1819
  import { searchKeymap } from "@codemirror/search";
1614
1820
  import { EditorState } from "@codemirror/state";
1615
- import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
1616
- import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView9, highlightActiveLine as highlightActiveLine2, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
1617
- 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";
1618
1824
 
1619
1825
  // packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
1620
1826
  import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
@@ -1807,19 +2013,17 @@ var markdownHighlightStyle = (readonly) => {
1807
2013
  // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
1808
2014
  var createMarkdownExtensions = ({ themeMode, placeholder: _placeholder, lineWrapping = true } = {}) => {
1809
2015
  return [
1810
- lineWrapping && EditorView9.lineWrapping,
2016
+ // TODO(burdon): Reconcile with createBasicExtensions.
2017
+ lineWrapping && EditorView11.lineWrapping,
1811
2018
  EditorState.allowMultipleSelections.of(true),
1812
2019
  EditorState.tabSize.of(2),
1813
- // https://github.com/codemirror/basic-setup
1814
- bracketMatching2(),
1815
- closeBrackets2(),
1816
- crosshairCursor(),
2020
+ bracketMatching(),
2021
+ closeBrackets(),
1817
2022
  dropCursor(),
1818
- drawSelection2(),
1819
- highlightActiveLine2(),
1820
- history2(),
2023
+ drawSelection(),
2024
+ history(),
1821
2025
  indentOnInput(),
1822
- _placeholder && placeholder2(_placeholder),
2026
+ _placeholder && placeholder(_placeholder),
1823
2027
  // Main extension.
1824
2028
  // https://github.com/codemirror/lang-markdown
1825
2029
  // https://codemirror.net/5/mode/markdown/index.html (demo).
@@ -1839,10 +2043,10 @@ var createMarkdownExtensions = ({ themeMode, placeholder: _placeholder, lineWrap
1839
2043
  ]
1840
2044
  }),
1841
2045
  // https://github.com/codemirror/theme-one-dark
1842
- themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
2046
+ themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle),
1843
2047
  // Custom styles.
1844
- syntaxHighlighting2(markdownHighlightStyle()),
1845
- keymap4.of([
2048
+ syntaxHighlighting(markdownHighlightStyle()),
2049
+ keymap5.of([
1846
2050
  // https://codemirror.net/docs/ref/#commands.indentWithTab
1847
2051
  indentWithTab,
1848
2052
  // https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
@@ -1854,22 +2058,22 @@ var createMarkdownExtensions = ({ themeMode, placeholder: _placeholder, lineWrap
1854
2058
  // https://codemirror.net/docs/ref/#commands.standardKeymap
1855
2059
  ...standardKeymap
1856
2060
  ])
1857
- ].filter(isNotFalsy3);
2061
+ ].filter(isNotFalsy2);
1858
2062
  };
1859
2063
 
1860
2064
  // packages/ui/react-ui-editor/src/extensions/markdown/decorate.ts
1861
2065
  import { syntaxTree } from "@codemirror/language";
1862
- import { RangeSetBuilder, StateEffect as StateEffect3 } from "@codemirror/state";
1863
- 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";
1864
2068
  import { mx as mx2 } from "@dxos/react-ui-theme";
1865
- var HorizontalRuleWidget = class extends WidgetType2 {
2069
+ var HorizontalRuleWidget = class extends WidgetType3 {
1866
2070
  toDOM() {
1867
2071
  const el = document.createElement("span");
1868
2072
  el.className = "cm-hr";
1869
2073
  return el;
1870
2074
  }
1871
2075
  };
1872
- var LinkButton = class extends WidgetType2 {
2076
+ var LinkButton = class extends WidgetType3 {
1873
2077
  constructor(url, render) {
1874
2078
  super();
1875
2079
  this.url = url;
@@ -1884,7 +2088,7 @@ var LinkButton = class extends WidgetType2 {
1884
2088
  return el;
1885
2089
  }
1886
2090
  };
1887
- var CheckboxWidget = class extends WidgetType2 {
2091
+ var CheckboxWidget = class extends WidgetType3 {
1888
2092
  constructor(_checked) {
1889
2093
  super();
1890
2094
  this._checked = _checked;
@@ -1921,23 +2125,23 @@ var CheckboxWidget = class extends WidgetType2 {
1921
2125
  return false;
1922
2126
  }
1923
2127
  };
1924
- var hide = Decoration4.replace({});
1925
- var fencedCodeLine = Decoration4.line({
2128
+ var hide = Decoration5.replace({});
2129
+ var fencedCodeLine = Decoration5.line({
1926
2130
  class: mx2("cm-code cm-codeblock-line")
1927
2131
  });
1928
- var fencedCodeLineFirst = Decoration4.line({
2132
+ var fencedCodeLineFirst = Decoration5.line({
1929
2133
  class: mx2("cm-code cm-codeblock-line", "cm-codeblock-first")
1930
2134
  });
1931
- var fencedCodeLineLast = Decoration4.line({
2135
+ var fencedCodeLineLast = Decoration5.line({
1932
2136
  class: mx2("cm-code cm-codeblock-line", "cm-codeblock-last")
1933
2137
  });
1934
- var horizontalRule = Decoration4.replace({
2138
+ var horizontalRule = Decoration5.replace({
1935
2139
  widget: new HorizontalRuleWidget()
1936
2140
  });
1937
- var checkedTask = Decoration4.replace({
2141
+ var checkedTask = Decoration5.replace({
1938
2142
  widget: new CheckboxWidget(true)
1939
2143
  });
1940
- var uncheckedTask = Decoration4.replace({
2144
+ var uncheckedTask = Decoration5.replace({
1941
2145
  widget: new CheckboxWidget(false)
1942
2146
  });
1943
2147
  var editingRange = (state, range, focus) => {
@@ -1952,8 +2156,8 @@ var MarksByParent = /* @__PURE__ */ new Set([
1952
2156
  "SuperscriptMark"
1953
2157
  ]);
1954
2158
  var buildDecorations = (view, options, focus) => {
1955
- const deco = new RangeSetBuilder();
1956
- const atomicDeco = new RangeSetBuilder();
2159
+ const deco = new RangeSetBuilder2();
2160
+ const atomicDeco = new RangeSetBuilder2();
1957
2161
  const { state } = view;
1958
2162
  for (const { from, to } of view.visibleRanges) {
1959
2163
  syntaxTree(state).iterate({
@@ -1970,7 +2174,7 @@ var buildDecorations = (view, options, focus) => {
1970
2174
  break;
1971
2175
  }
1972
2176
  const first = block.from <= node.from;
1973
- const last = block.to >= node.to;
2177
+ const last = block.to >= node.to && /^(\s>)*```$/.test(state.doc.sliceString(block.from, block.to));
1974
2178
  deco.add(block.from, block.from, first ? fencedCodeLineFirst : last ? fencedCodeLineLast : fencedCodeLine);
1975
2179
  if (!editing && (first || last)) {
1976
2180
  atomicDeco.add(block.from, block.to, hide);
@@ -1986,7 +2190,7 @@ var buildDecorations = (view, options, focus) => {
1986
2190
  if (!editing) {
1987
2191
  atomicDeco.add(node.from, marks[0].to, hide);
1988
2192
  }
1989
- deco.add(marks[0].to, marks[1].from, Decoration4.mark({
2193
+ deco.add(marks[0].to, marks[1].from, Decoration5.mark({
1990
2194
  tagName: "a",
1991
2195
  attributes: {
1992
2196
  class: "cm-link",
@@ -1996,7 +2200,7 @@ var buildDecorations = (view, options, focus) => {
1996
2200
  }
1997
2201
  }));
1998
2202
  if (!editing) {
1999
- atomicDeco.add(marks[1].from, node.to, options.renderLinkButton ? Decoration4.replace({
2203
+ atomicDeco.add(marks[1].from, node.to, options.renderLinkButton ? Decoration5.replace({
2000
2204
  widget: new LinkButton(url, options.renderLinkButton)
2001
2205
  }) : hide);
2002
2206
  }
@@ -2014,7 +2218,7 @@ var buildDecorations = (view, options, focus) => {
2014
2218
  } else if (node.name === "TaskMarker") {
2015
2219
  if (!editingRange(state, node, focus)) {
2016
2220
  const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
2017
- atomicDeco.add(node.from - 2, node.from - 1, Decoration4.mark({
2221
+ atomicDeco.add(node.from - 2, node.from - 1, Decoration5.mark({
2018
2222
  class: "cm-task"
2019
2223
  }));
2020
2224
  atomicDeco.add(node.from, node.to, checked ? checkedTask : uncheckedTask);
@@ -2032,50 +2236,51 @@ var buildDecorations = (view, options, focus) => {
2032
2236
  atomicDeco: atomicDeco.finish()
2033
2237
  };
2034
2238
  };
2035
- var forceUpdate = StateEffect3.define();
2239
+ var forceUpdate = StateEffect4.define();
2036
2240
  var decorateMarkdown = (options = {}) => {
2037
2241
  return [
2038
- ViewPlugin3.fromClass(class {
2242
+ ViewPlugin4.fromClass(class {
2039
2243
  constructor(view) {
2040
- this.pendingUpdate = -1;
2041
2244
  ({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations(view, options, view.hasFocus));
2042
2245
  }
2043
2246
  update(update2) {
2044
- if (update2.docChanged || update2.viewportChanged || update2.focusChanged || update2.transactions.some((tr) => tr.effects.some((e) => e.is(forceUpdate)))) {
2247
+ if (update2.docChanged || update2.viewportChanged || update2.focusChanged || update2.transactions.some((tr) => tr.effects.some((e) => e.is(forceUpdate))) || update2.selectionSet && !options.selectionChangeDelay) {
2045
2248
  ({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations(update2.view, options, update2.view.hasFocus));
2046
2249
  this.clearUpdate();
2047
2250
  } else if (update2.selectionSet) {
2048
2251
  this.scheduleUpdate(update2.view);
2049
2252
  }
2050
2253
  }
2051
- clearUpdate() {
2052
- if (this.pendingUpdate > -1) {
2053
- window.clearTimeout(this.pendingUpdate);
2054
- this.pendingUpdate = -1;
2055
- }
2056
- }
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.
2057
2256
  scheduleUpdate(view) {
2058
2257
  this.clearUpdate();
2059
- this.pendingUpdate = window.setTimeout(() => {
2258
+ this.pendingUpdate = setTimeout(() => {
2060
2259
  view.dispatch({
2061
2260
  effects: forceUpdate.of(null)
2062
2261
  });
2063
- }, options.selectionChangeDelay ?? 400);
2262
+ }, options.selectionChangeDelay);
2263
+ }
2264
+ clearUpdate() {
2265
+ if (this.pendingUpdate) {
2266
+ clearTimeout(this.pendingUpdate);
2267
+ this.pendingUpdate = void 0;
2268
+ }
2064
2269
  }
2065
2270
  destroy() {
2066
2271
  this.clearUpdate();
2067
2272
  }
2068
2273
  }, {
2069
2274
  provide: (plugin) => [
2070
- EditorView10.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration4.none),
2071
- EditorView10.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration4.none),
2072
- EditorView10.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration4.none)
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)
2073
2278
  ]
2074
2279
  }),
2075
2280
  formattingStyles
2076
2281
  ];
2077
2282
  };
2078
- var formattingStyles = EditorView10.baseTheme({
2283
+ var formattingStyles = EditorView12.baseTheme({
2079
2284
  "& .cm-code": {
2080
2285
  fontFamily: getToken("fontFamily.mono", []).join(",")
2081
2286
  },
@@ -2128,7 +2333,7 @@ var formattingStyles = EditorView10.baseTheme({
2128
2333
  import { snippet } from "@codemirror/autocomplete";
2129
2334
  import { syntaxTree as syntaxTree2 } from "@codemirror/language";
2130
2335
  import { EditorSelection } from "@codemirror/state";
2131
- import { EditorView as EditorView11, keymap as keymap5 } from "@codemirror/view";
2336
+ import { EditorView as EditorView13, keymap as keymap6 } from "@codemirror/view";
2132
2337
  import { useState, useMemo } from "react";
2133
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;
2134
2339
  var Inline;
@@ -3000,7 +3205,7 @@ var toggleCodeblock = (target) => {
3000
3205
  };
3001
3206
  var formatting = (options = {}) => {
3002
3207
  return [
3003
- keymap5.of([
3208
+ keymap6.of([
3004
3209
  {
3005
3210
  key: "meta-b",
3006
3211
  run: toggleStrong
@@ -3198,7 +3403,7 @@ var getFormatting = (state) => {
3198
3403
  };
3199
3404
  var useFormattingState = () => {
3200
3405
  const [state, setState] = useState(null);
3201
- const observer = useMemo(() => EditorView11.updateListener.of((update2) => {
3406
+ const observer = useMemo(() => EditorView13.updateListener.of((update2) => {
3202
3407
  if (update2.docChanged || update2.selectionSet) {
3203
3408
  const newState = getFormatting(update2.state);
3204
3409
  if (!state || !compareFormatting(state, newState)) {
@@ -3214,12 +3419,12 @@ var useFormattingState = () => {
3214
3419
 
3215
3420
  // packages/ui/react-ui-editor/src/extensions/markdown/image.ts
3216
3421
  import { syntaxTree as syntaxTree3 } from "@codemirror/language";
3217
- import { StateField as StateField4 } from "@codemirror/state";
3218
- 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";
3219
3424
  var image = (options = {}) => {
3220
- return StateField4.define({
3425
+ return StateField5.define({
3221
3426
  create: (state) => {
3222
- return Decoration5.set(buildDecorations2(0, state.doc.length, state));
3427
+ return Decoration6.set(buildDecorations2(0, state.doc.length, state));
3223
3428
  },
3224
3429
  update: (value, tr) => {
3225
3430
  if (!tr.docChanged && !tr.selection) {
@@ -3242,7 +3447,7 @@ var image = (options = {}) => {
3242
3447
  add: buildDecorations2(from, to, tr.state)
3243
3448
  });
3244
3449
  },
3245
- provide: (field) => EditorView12.decorations.from(field)
3450
+ provide: (field) => EditorView14.decorations.from(field)
3246
3451
  });
3247
3452
  };
3248
3453
  var preloaded = /* @__PURE__ */ new Set();
@@ -3264,7 +3469,7 @@ var buildDecorations2 = (from, to, state) => {
3264
3469
  const hide2 = state.readOnly || cursor < node.from || cursor > node.to;
3265
3470
  const url = state.sliceDoc(urlNode.from, urlNode.to);
3266
3471
  preloadImage(url);
3267
- decorations.push(Decoration5.replace({
3472
+ decorations.push(Decoration6.replace({
3268
3473
  block: true,
3269
3474
  widget: new ImageWidget(url)
3270
3475
  }).range(hide2 ? node.from : node.to, node.to));
@@ -3276,7 +3481,7 @@ var buildDecorations2 = (from, to, state) => {
3276
3481
  });
3277
3482
  return decorations;
3278
3483
  };
3279
- var ImageWidget = class extends WidgetType3 {
3484
+ var ImageWidget = class extends WidgetType4 {
3280
3485
  constructor(_url) {
3281
3486
  super();
3282
3487
  this._url = _url;
@@ -3329,17 +3534,17 @@ var linkTooltip = (render) => hoverTooltip2((view, pos, side) => {
3329
3534
 
3330
3535
  // packages/ui/react-ui-editor/src/extensions/markdown/table.ts
3331
3536
  import { syntaxTree as syntaxTree5 } from "@codemirror/language";
3332
- import { RangeSetBuilder as RangeSetBuilder2, StateField as StateField5 } from "@codemirror/state";
3333
- 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";
3334
3539
  var table = (options = {}) => {
3335
- return StateField5.define({
3540
+ return StateField6.define({
3336
3541
  create: (state) => update(state, options),
3337
3542
  update: (_, tr) => update(tr.state, options),
3338
- provide: (field) => EditorView13.decorations.from(field)
3543
+ provide: (field) => EditorView15.decorations.from(field)
3339
3544
  });
3340
3545
  };
3341
3546
  var update = (state, options) => {
3342
- const builder = new RangeSetBuilder2();
3547
+ const builder = new RangeSetBuilder3();
3343
3548
  const cursor = state.selection.main.head;
3344
3549
  const tables = [];
3345
3550
  const getTable = () => tables[tables.length - 1];
@@ -3379,16 +3584,16 @@ var update = (state, options) => {
3379
3584
  });
3380
3585
  tables.forEach((table2) => {
3381
3586
  const hide2 = state.readOnly || cursor < table2.from || cursor > table2.to;
3382
- hide2 && builder.add(table2.from, table2.to, Decoration6.replace({
3587
+ hide2 && builder.add(table2.from, table2.to, Decoration7.replace({
3383
3588
  widget: new TableWidget(table2)
3384
3589
  }));
3385
- builder.add(table2.from, table2.to, Decoration6.mark({
3590
+ builder.add(table2.from, table2.to, Decoration7.mark({
3386
3591
  class: "cm-table"
3387
3592
  }));
3388
3593
  });
3389
3594
  return builder.finish();
3390
3595
  };
3391
- var TableWidget = class extends WidgetType4 {
3596
+ var TableWidget = class extends WidgetType5 {
3392
3597
  constructor(_table) {
3393
3598
  super();
3394
3599
  this._table = _table;
@@ -3455,10 +3660,10 @@ var mention = ({ onSearch }) => {
3455
3660
  };
3456
3661
 
3457
3662
  // packages/ui/react-ui-editor/src/extensions/modes.ts
3458
- import { Facet as Facet5 } from "@codemirror/state";
3459
- import { keymap as keymap6 } from "@codemirror/view";
3663
+ import { Facet as Facet6 } from "@codemirror/state";
3664
+ import { keymap as keymap7 } from "@codemirror/view";
3460
3665
  import { vim } from "@replit/codemirror-vim";
3461
- var editorMode = Facet5.define({
3666
+ var editorMode = Facet6.define({
3462
3667
  combine: (modes) => modes[0] ?? {}
3463
3668
  });
3464
3669
  var EditorModes = {
@@ -3469,7 +3674,7 @@ var EditorModes = {
3469
3674
  type: "vim",
3470
3675
  noTabster: true
3471
3676
  }),
3472
- keymap6.of([
3677
+ keymap7.of([
3473
3678
  {
3474
3679
  key: "Alt-Escape",
3475
3680
  run: (view) => {
@@ -3489,7 +3694,7 @@ var outliner = (options = {}) => {
3489
3694
  };
3490
3695
 
3491
3696
  // packages/ui/react-ui-editor/src/extensions/typewriter.ts
3492
- import { keymap as keymap7 } from "@codemirror/view";
3697
+ import { keymap as keymap8 } from "@codemirror/view";
3493
3698
  var defaultItems = [
3494
3699
  "hello world!",
3495
3700
  "this is a test.",
@@ -3499,7 +3704,7 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
3499
3704
  let t;
3500
3705
  let idx = 0;
3501
3706
  return [
3502
- keymap7.of([
3707
+ keymap8.of([
3503
3708
  {
3504
3709
  // Reset.
3505
3710
  key: "alt-meta-'",
@@ -3545,186 +3750,370 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
3545
3750
  ];
3546
3751
  };
3547
3752
 
3548
- // packages/ui/react-ui-editor/src/themes/default.ts
3549
- import get4 from "lodash.get";
3550
- var defaultTheme = {
3551
- //
3552
- // Main layout:
3553
- // https://codemirror.net/examples/styling
3554
- //
3555
- // <div class="cm-editor [cm-focused] [generated classes]">
3556
- // <div class="cm-scroller">
3557
- // <div class="cm-gutters">
3558
- // <div class="cm-gutter [...]">
3559
- // <div class="cm-gutterElement">...</div>
3560
- // </div>
3561
- // </div>
3562
- // <div class="cm-content" role="textbox" contenteditable="true">
3563
- // <div class="cm-line"></div>
3564
- // </div>
3565
- // <div class="cm-selectionLayer">
3566
- // <div class="cm-selectionBackground"></div>
3567
- // </div>
3568
- // <div class="cm-cursorLayer">
3569
- // <div class="cm-cursor"></div>
3570
- // </div>
3571
- // </div>
3572
- // </div>
3573
- //
3574
- "&": {},
3575
- "&.cm-focused": {
3576
- outline: "none"
3577
- },
3578
- // NOTE: See https://codemirror.net/docs/guide (DOM Structure).
3579
- ".cm-scroller": {
3580
- // TODO(burdon): Reconcile with docs: https://codemirror.net/docs/guide
3581
- // 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.
3582
- overflowY: "auto",
3583
- fontFamily: get4(tokens, "fontFamily.mono", []).join(","),
3584
- lineHeight: 1.5
3585
- },
3586
- ".cm-content": {
3587
- // TODO(burdon): Is it possible to remove the padding value from CM's default theme?
3588
- // padding: 'unset',
3589
- // NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
3590
- fontSize: "16px"
3591
- },
3592
- "&light .cm-content": {
3593
- color: get4(tokens, "extend.semanticColors.base.fg.light", "black"),
3594
- caretColor: "black"
3595
- },
3596
- "&dark .cm-content": {
3597
- color: get4(tokens, "extend.semanticColors.base.fg.dark", "white"),
3598
- caretColor: "white"
3599
- },
3600
- //
3601
- // Cursor
3602
- //
3603
- "&light .cm-cursor, &light .cm-dropCursor": {
3604
- borderLeft: "2px solid black"
3605
- },
3606
- "&dark .cm-cursor, &dark .cm-dropCursor": {
3607
- borderLeft: "2px solid white"
3608
- },
3609
- "&light .cm-placeholder": {
3610
- color: get4(tokens, "extend.semanticColors.description.light", "rgba(0,0,0,.2)")
3611
- },
3612
- "&dark .cm-placeholder": {
3613
- color: get4(tokens, "extend.semanticColors.description.dark", "rgba(255,255,255,.2)")
3614
- },
3615
- //
3616
- // line
3617
- //
3618
- ".cm-line": {
3619
- paddingInline: 0
3620
- },
3621
- ".cm-activeLine": {
3622
- background: "transparent"
3623
- },
3624
- //
3625
- // gutter
3626
- //
3627
- ".cm-gutterElement": {
3628
- width: "48px"
3629
- },
3630
- //
3631
- // Selection
3632
- //
3633
- "&light .cm-selectionBackground": {
3634
- background: get4(tokens, "extend.colors.primary.100")
3635
- },
3636
- "&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
3637
- background: get4(tokens, "extend.colors.primary.200")
3638
- },
3639
- "&dark .cm-selectionBackground": {
3640
- background: get4(tokens, "extend.colors.primary.700")
3641
- },
3642
- "&dark.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
3643
- background: get4(tokens, "extend.colors.primary.600")
3644
- },
3645
- //
3646
- // Search
3647
- //
3648
- "&light .cm-searchMatch": {
3649
- backgroundColor: get4(tokens, "extend.colors.yellow.100")
3650
- },
3651
- "&dark .cm-searchMatch": {
3652
- backgroundColor: get4(tokens, "extend.colors.yellow.700")
3653
- },
3654
- //
3655
- // link
3656
- //
3657
- ".cm-link": {
3658
- color: get4(tokens, "extend.colors.primary.500"),
3659
- textDecorationLine: "underline",
3660
- textDecorationThickness: "1px",
3661
- textUnderlineOffset: "2px",
3662
- borderRadius: ".125rem",
3663
- fontFamily: get4(tokens, "fontFamily.body", []).join(",")
3664
- },
3665
- //
3666
- // tooltip
3667
- //
3668
- ".cm-tooltip": {
3669
- border: "none"
3670
- },
3671
- ".cm-tooltip-below": {},
3672
- //
3673
- // autocomplete
3674
- //
3675
- ".cm-tooltip-autocomplete": {
3676
- marginTop: "4px",
3677
- marginLeft: "-3px"
3678
- },
3679
- ".cm-tooltip-autocomplete ul li": {},
3680
- ".cm-tooltip-autocomplete ul li[aria-selected]": {},
3681
- ".cm-completionIcon": {
3682
- display: "none"
3683
- },
3684
- ".cm-completionLabel": {
3685
- fontFamily: get4(tokens, "fontFamily.body", []).join(",")
3686
- },
3687
- ".cm-completionMatchedText": {
3688
- textDecoration: "none"
3689
- },
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 = {
3690
3939
  //
3691
- // table
3940
+ // Main layout:
3941
+ // https://codemirror.net/examples/styling
3692
3942
  //
3693
- ".cm-table *": {
3694
- fontFamily: `${get4(tokens, "fontFamily.mono", []).join(",")} !important`,
3695
- textDecoration: "none !important"
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>
3961
+ //
3962
+ "&": {},
3963
+ "&.cm-focused": {
3964
+ outline: "none"
3696
3965
  },
3697
- ".cm-table-head": {
3698
- padding: "2px 16px 2px 0px",
3699
- borderBottom: `1px solid ${get4(tokens, "extend.colors.neutral.500")}`,
3700
- fontWeight: 100,
3701
- textAlign: "left",
3702
- color: get4(tokens, "extend.colors.neutral.500")
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
3703
3973
  },
3704
- ".cm-table-cell": {
3705
- padding: "2px 16px 2px 0px"
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"
3979
+ },
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"
3706
3987
  },
3707
3988
  //
3708
- // image
3989
+ // Cursor
3709
3990
  //
3710
- ".cm-image": {
3711
- display: "block",
3712
- height: "0"
3991
+ "&light .cm-cursor, &light .cm-dropCursor": {
3992
+ borderLeft: "2px solid black"
3713
3993
  },
3714
- ".cm-image.cm-loaded-image": {
3715
- height: "auto",
3716
- borderTop: "0.5rem solid transparent",
3717
- borderBottom: "0.5rem solid transparent"
3994
+ "&dark .cm-cursor, &dark .cm-dropCursor": {
3995
+ borderLeft: "2px solid white"
3996
+ },
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)")
3718
4002
  },
3719
4003
  //
3720
- // font size
3721
- // TODO(thure): This appears to be the best or only way to set selection caret heights,
3722
- // but it's far more verbose than it needs to be.
3723
- //
3724
- // ...Object.keys(get(tokens, 'extend.fontSize', {})).reduce((acc: Record<string, any>, fontSize) => {
3725
- // const height = get(tokens, ['extend', 'fontSize', fontSize, 1, 'lineHeight']);
4004
+ // line
3726
4005
  //
3727
- // acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = { height };
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"
4095
+ },
4096
+ //
4097
+ // image
4098
+ //
4099
+ ".cm-image": {
4100
+ display: "block",
4101
+ height: "0"
4102
+ },
4103
+ ".cm-image.cm-loaded-image": {
4104
+ height: "auto",
4105
+ borderTop: "0.5rem solid transparent",
4106
+ borderBottom: "0.5rem solid transparent"
4107
+ },
4108
+ //
4109
+ // font size
4110
+ // TODO(thure): This appears to be the best or only way to set selection caret heights,
4111
+ // but it's far more verbose than it needs to be.
4112
+ //
4113
+ // ...Object.keys(get(tokens, 'extend.fontSize', {})).reduce((acc: Record<string, any>, fontSize) => {
4114
+ // const height = get(tokens, ['extend', 'fontSize', fontSize, 1, 'lineHeight']);
4115
+ //
4116
+ // acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = { height };
3728
4117
  // acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = { height };
3729
4118
  // acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = { height };
3730
4119
  // return acc;
@@ -3795,139 +4184,360 @@ var codeTheme = {
3795
4184
  }
3796
4185
  };
3797
4186
 
3798
- // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
3799
- var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
3800
- var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo = EditorView14.scrollIntoView(0), moveToEndOfLine, selection, theme, slots = defaultSlots, extensions = [], scrollPastEnd: _scrollPastEnd, debug }, forwardedRef) => {
3801
- const tabsterDOMAttribute = useFocusableGroup({
3802
- tabBehavior: "limited"
3803
- });
3804
- const { themeMode } = useThemeContext();
3805
- const rootRef = useRef(null);
3806
- const [view, setView] = useState2(null);
3807
- useImperativeHandle(forwardedRef, () => view, [
3808
- view
3809
- ]);
3810
- useEffect2(() => {
3811
- if (autoFocus) {
3812
- view?.focus();
3813
- }
3814
- }, [
3815
- view,
3816
- autoFocus
3817
- ]);
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);
3818
4193
  useEffect2(() => {
3819
- if (!model || !rootRef.current) {
3820
- return;
3821
- }
3822
- const state = EditorState2.create({
3823
- doc: model.text(),
3824
- selection,
3825
- extensions: [
3826
- // TODO(burdon): Doesn't catch errors in keymap functions.
3827
- EditorView14.exceptionSink.of((err) => {
3828
- log3.catch(err, void 0, {
3829
- F: __dxlog_file4,
3830
- L: 122,
3831
- S: void 0,
3832
- C: (f, a) => f(...a)
3833
- });
3834
- }),
3835
- // Theme.
3836
- // TODO(burdon): Make base theme configurable.
3837
- EditorView14.baseTheme(defaultTheme),
3838
- theme && EditorView14.theme(theme),
3839
- EditorView14.darkTheme.of(themeMode === "dark"),
3840
- slots.editor?.className && EditorView14.editorAttributes.of({
3841
- class: slots.editor.className
3842
- }),
3843
- slots.content?.className && EditorView14.contentAttributes.of({
3844
- class: slots.content.className
3845
- }),
3846
- // NOTE: Assumes default line height.
3847
- _scrollPastEnd && scrollPastEnd(),
3848
- // Focus.
3849
- EditorView14.updateListener.of((update2) => {
3850
- update2.transactions.forEach((transaction) => {
3851
- if (transaction.isUserEvent("focus.container")) {
3852
- rootRef.current?.focus();
3853
- }
3854
- });
3855
- }),
3856
- // State.
3857
- EditorView14.editable.of(!readonly),
3858
- EditorState2.readOnly.of(!!readonly),
3859
- // Storage and replication.
3860
- // NOTE: This must come before user extensions.
3861
- model.extension,
3862
- // Custom.
3863
- ...extensions
3864
- ].filter(isNotFalsy4)
3865
- });
3866
- const view2 = new EditorView14({
3867
- state,
3868
- parent: rootRef.current,
3869
- scrollTo,
3870
- // NOTE: Uncomment to debug/monitor all transactions.
3871
- // https://codemirror.net/docs/ref/#view.EditorView.dispatch
3872
- dispatchTransactions: (trs, view3) => {
3873
- if (debug) {
3874
- logChanges(trs);
3875
- }
3876
- view3.update(trs);
3877
- }
3878
- });
3879
- setView(view2);
3880
- if (moveToEndOfLine) {
3881
- const { to } = view2.state.doc.lineAt(0);
3882
- view2?.dispatch({
3883
- selection: {
3884
- anchor: to
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);
3885
4226
  }
3886
4227
  });
3887
- }
3888
- if (state.facet(editorMode).noTabster) {
3889
- rootRef.current.removeAttribute("data-tabster");
4228
+ setView(view2);
3890
4229
  }
3891
4230
  return () => {
3892
4231
  view2?.destroy();
3893
- setView(null);
3894
4232
  };
3895
- }, [
3896
- rootRef,
3897
- extensions,
3898
- model,
3899
- readonly,
3900
- themeMode
3901
- ]);
3902
- const handleKeyUp = useCallback((event) => {
3903
- const { key } = event;
3904
- switch (key) {
3905
- case "Enter": {
3906
- view?.focus();
3907
- break;
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();
3908
4253
  }
3909
4254
  }
3910
4255
  }, [
3911
- view
4256
+ view,
4257
+ autoFocus,
4258
+ selection,
4259
+ scrollTo
3912
4260
  ]);
3913
- return /* @__PURE__ */ React.createElement("div", {
3914
- role: "none",
3915
- ref: rootRef,
3916
- key: model.id,
3917
- tabIndex: 0,
3918
- onKeyUp: handleKeyUp,
3919
- ...slots.root,
3920
- ...tabsterDOMAttribute
3921
- });
3922
- });
3923
- var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, lineWrapping, theme = textTheme, slots, extensions: _extensions, ...props }, forwardedRef) => {
3924
- const { themeMode } = useThemeContext();
3925
- const updatedSlots = defaultsDeep2({}, slots, defaultTextSlots);
3926
- const extensions = useMemo2(() => [
3927
- createBasicBundle({
3928
- themeMode,
3929
- placeholder: placeholder3,
3930
- lineWrapping
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
+
4406
+ // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
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) => {
4409
+ const tabsterDOMAttribute = useFocusableGroup({
4410
+ tabBehavior: "limited"
4411
+ });
4412
+ const { themeMode } = useThemeContext();
4413
+ const rootRef = useRef3(null);
4414
+ const [view, setView] = useState5(null);
4415
+ useImperativeHandle(forwardedRef, () => view, [
4416
+ view
4417
+ ]);
4418
+ useEffect3(() => {
4419
+ if (autoFocus) {
4420
+ view?.focus();
4421
+ }
4422
+ }, [
4423
+ view,
4424
+ autoFocus
4425
+ ]);
4426
+ useEffect3(() => {
4427
+ if (!model || !rootRef.current) {
4428
+ return;
4429
+ }
4430
+ const state = EditorState3.create({
4431
+ doc: typeof model.content === "string" ? model.content : DocAccessor.getValue(model.content),
4432
+ selection,
4433
+ extensions: [
4434
+ // TODO(burdon): Doesn't catch errors in keymap functions.
4435
+ EditorView17.exceptionSink.of((err) => {
4436
+ log5.catch(err, void 0, {
4437
+ F: __dxlog_file7,
4438
+ L: 123,
4439
+ S: void 0,
4440
+ C: (f, a) => f(...a)
4441
+ });
4442
+ }),
4443
+ // Theme.
4444
+ // TODO(burdon): Make base theme configurable.
4445
+ EditorView17.baseTheme(defaultTheme),
4446
+ theme && EditorView17.theme(theme),
4447
+ EditorView17.darkTheme.of(themeMode === "dark"),
4448
+ slots.editor?.className && EditorView17.editorAttributes.of({
4449
+ class: slots.editor.className
4450
+ }),
4451
+ slots.content?.className && EditorView17.contentAttributes.of({
4452
+ class: slots.content.className
4453
+ }),
4454
+ // NOTE: Assumes default line height.
4455
+ _scrollPastEnd && scrollPastEnd2(),
4456
+ // Focus.
4457
+ EditorView17.updateListener.of((update2) => {
4458
+ update2.transactions.forEach((transaction) => {
4459
+ if (transaction.isUserEvent("focus.container")) {
4460
+ rootRef.current?.focus();
4461
+ }
4462
+ });
4463
+ }),
4464
+ // State.
4465
+ EditorView17.editable.of(!readonly),
4466
+ EditorState3.readOnly.of(!!readonly),
4467
+ // Storage and replication.
4468
+ // NOTE: This must come before user extensions.
4469
+ model.extension,
4470
+ // Custom.
4471
+ ...extensions
4472
+ ].filter(isNotFalsy4)
4473
+ });
4474
+ const view2 = new EditorView17({
4475
+ state,
4476
+ parent: rootRef.current,
4477
+ scrollTo,
4478
+ // NOTE: Uncomment to debug/monitor all transactions.
4479
+ // https://codemirror.net/docs/ref/#view.EditorView.dispatch
4480
+ dispatchTransactions: (trs, view3) => {
4481
+ if (debug) {
4482
+ logChanges(trs);
4483
+ }
4484
+ view3.update(trs);
4485
+ }
4486
+ });
4487
+ setView(view2);
4488
+ if (moveToEndOfLine) {
4489
+ const { to } = view2.state.doc.lineAt(0);
4490
+ view2?.dispatch({
4491
+ selection: {
4492
+ anchor: to
4493
+ }
4494
+ });
4495
+ }
4496
+ if (state.facet(editorMode).noTabster) {
4497
+ rootRef.current.removeAttribute("data-tabster");
4498
+ }
4499
+ return () => {
4500
+ view2?.destroy();
4501
+ setView(null);
4502
+ };
4503
+ }, [
4504
+ rootRef,
4505
+ extensions,
4506
+ model,
4507
+ readonly,
4508
+ themeMode
4509
+ ]);
4510
+ const handleKeyUp = useCallback((event) => {
4511
+ const { key } = event;
4512
+ switch (key) {
4513
+ case "Enter": {
4514
+ view?.focus();
4515
+ break;
4516
+ }
4517
+ }
4518
+ }, [
4519
+ view
4520
+ ]);
4521
+ return /* @__PURE__ */ React.createElement("div", {
4522
+ role: "none",
4523
+ ref: rootRef,
4524
+ key: model.id,
4525
+ tabIndex: 0,
4526
+ onKeyUp: handleKeyUp,
4527
+ ...slots.root,
4528
+ ...tabsterDOMAttribute
4529
+ });
4530
+ });
4531
+ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, lineWrapping = true, theme = textTheme, slots, extensions: _extensions, ...props }, forwardedRef) => {
4532
+ const { themeMode } = useThemeContext();
4533
+ const updatedSlots = defaultsDeep3({}, slots, defaultTextSlots);
4534
+ const extensions = useMemo3(() => [
4535
+ createBasicExtensions({
4536
+ lineWrapping,
4537
+ placeholder: placeholder3
4538
+ }),
4539
+ createThemeExtensions({
4540
+ themeMode
3931
4541
  }),
3932
4542
  ..._extensions ?? []
3933
4543
  ], [
@@ -3947,8 +4557,8 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholde
3947
4557
  });
3948
4558
  var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, theme = markdownTheme, slots, extensions: _extensions, ...props }, forwardedRef) => {
3949
4559
  const { themeMode } = useThemeContext();
3950
- const updatedSlots = defaultsDeep2({}, slots, defaultMarkdownSlots);
3951
- const extensions = useMemo2(() => [
4560
+ const updatedSlots = defaultsDeep3({}, slots, defaultMarkdownSlots);
4561
+ const extensions = useMemo3(() => [
3952
4562
  createMarkdownExtensions({
3953
4563
  themeMode,
3954
4564
  placeholder: placeholder3
@@ -3986,7 +4596,7 @@ var defaultMarkdownSlots = {
3986
4596
  // packages/ui/react-ui-editor/src/components/Toolbar/Toolbar.tsx
3987
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";
3988
4598
  import { createContext } from "@radix-ui/react-context";
3989
- import React2, { useRef as useRef2, useState as useState3 } from "react";
4599
+ import React2, { useRef as useRef4, useState as useState6 } from "react";
3990
4600
  import { DensityProvider, ElevationProvider, Select, Toolbar as NaturalToolbar, Tooltip, useTranslation } from "@dxos/react-ui";
3991
4601
  import { getSize } from "@dxos/react-ui-theme";
3992
4602
  var tooltipProps = {
@@ -4044,9 +4654,9 @@ var MarkdownHeading = () => {
4044
4654
  const header = blockType && /heading(\d)/.exec(blockType);
4045
4655
  const value = header ? header[1] : blockType === "paragraph" || !blockType ? "0" : void 0;
4046
4656
  const HeadingIcon = HeadingIcons[value ?? "0"];
4047
- const suppressNextTooltip = useRef2(false);
4048
- const [tooltipOpen, setTooltipOpen] = useState3(false);
4049
- const [selectOpen, setSelectOpen] = useState3(false);
4657
+ const suppressNextTooltip = useRef4(false);
4658
+ const [tooltipOpen, setTooltipOpen] = useState6(false);
4659
+ const [selectOpen, setSelectOpen] = useState6(false);
4050
4660
  return /* @__PURE__ */ React2.createElement(Tooltip.Root, {
4051
4661
  open: tooltipOpen,
4052
4662
  onOpenChange: (nextOpen) => {
@@ -4249,384 +4859,6 @@ var Toolbar = {
4249
4859
  Markdown: MarkdownStandard,
4250
4860
  Extended: MarkdownExtended
4251
4861
  };
4252
-
4253
- // packages/ui/react-ui-editor/src/hooks/awareness-provider.ts
4254
- import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
4255
- import { Context as Context2 } from "@dxos/context";
4256
- import { invariant as invariant2 } from "@dxos/invariant";
4257
- import { log as log4 } from "@dxos/log";
4258
- var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
4259
- var DEBOUNCE_INTERVAL = 100;
4260
- var SpaceAwarenessProvider = class {
4261
- constructor(params) {
4262
- this._remoteStates = /* @__PURE__ */ new Map();
4263
- this.remoteStateChange = new Event2();
4264
- this._space = params.space;
4265
- this._channel = params.channel;
4266
- this._peerId = params.peerId;
4267
- this._info = params.info;
4268
- }
4269
- open() {
4270
- this._ctx = new Context2();
4271
- this._postTask = new DeferredTask(this._ctx, async () => {
4272
- if (this._localState) {
4273
- await this._space.postMessage(this._channel, {
4274
- kind: "post",
4275
- state: this._localState
4276
- });
4277
- await sleep(DEBOUNCE_INTERVAL);
4278
- }
4279
- });
4280
- this._ctx.onDispose(this._space.listen(this._channel, (message) => {
4281
- switch (message.payload.kind) {
4282
- case "query": {
4283
- this._handleQueryMessage();
4284
- break;
4285
- }
4286
- case "post": {
4287
- this._handlePostMessage(message.payload);
4288
- break;
4289
- }
4290
- }
4291
- }));
4292
- void this._space.postMessage(this._channel, {
4293
- kind: "query"
4294
- }).catch((err) => {
4295
- log4.debug("failed to query awareness", {
4296
- err
4297
- }, {
4298
- F: __dxlog_file5,
4299
- L: 89,
4300
- S: this,
4301
- C: (f, a) => f(...a)
4302
- });
4303
- });
4304
- }
4305
- close() {
4306
- void this._ctx?.dispose();
4307
- this._ctx = void 0;
4308
- this._postTask = void 0;
4309
- }
4310
- getRemoteStates() {
4311
- return Array.from(this._remoteStates.values());
4312
- }
4313
- update(position) {
4314
- invariant2(this._postTask, void 0, {
4315
- F: __dxlog_file5,
4316
- L: 104,
4317
- S: this,
4318
- A: [
4319
- "this._postTask",
4320
- ""
4321
- ]
4322
- });
4323
- this._localState = {
4324
- peerId: this._peerId,
4325
- position,
4326
- info: this._info
4327
- };
4328
- this._postTask.schedule();
4329
- }
4330
- _handleQueryMessage() {
4331
- invariant2(this._postTask, void 0, {
4332
- F: __dxlog_file5,
4333
- L: 115,
4334
- S: this,
4335
- A: [
4336
- "this._postTask",
4337
- ""
4338
- ]
4339
- });
4340
- this._postTask.schedule();
4341
- }
4342
- _handlePostMessage(message) {
4343
- invariant2(message.kind === "post", void 0, {
4344
- F: __dxlog_file5,
4345
- L: 120,
4346
- S: this,
4347
- A: [
4348
- "message.kind === 'post'",
4349
- ""
4350
- ]
4351
- });
4352
- this._remoteStates.set(message.state.peerId, message.state);
4353
- this.remoteStateChange.emit();
4354
- }
4355
- };
4356
-
4357
- // packages/ui/react-ui-editor/src/hooks/defs.ts
4358
- import { StateField as StateField6 } from "@codemirror/state";
4359
- var modelState = StateField6.define({
4360
- create: () => void 0,
4361
- update: (model) => model
4362
- });
4363
-
4364
- // packages/ui/react-ui-editor/src/hooks/useActionHandler.ts
4365
- var useActionHandler = (view) => {
4366
- return (action) => {
4367
- if (!view) {
4368
- return;
4369
- }
4370
- let inlineType, listType;
4371
- switch (action.type) {
4372
- case "heading":
4373
- setHeading(parseInt(action.data))(view);
4374
- break;
4375
- case "strong":
4376
- case "emphasis":
4377
- case "strikethrough":
4378
- case "code":
4379
- inlineType = action.type === "strong" ? Inline.Strong : action.type === "emphasis" ? Inline.Emphasis : action.type === "strikethrough" ? Inline.Strikethrough : Inline.Code;
4380
- (typeof action.data === "boolean" ? setStyle(inlineType, action.data) : toggleStyle(inlineType))(view);
4381
- break;
4382
- case "list-ordered":
4383
- case "list-bullet":
4384
- case "list-task":
4385
- listType = action.type === "list-ordered" ? List.Ordered : action.type === "list-bullet" ? List.Bullet : List.Task;
4386
- (action.data === false ? removeList(listType) : action.data === true ? addList(listType) : toggleList(listType))(view);
4387
- break;
4388
- case "blockquote":
4389
- (action.data === false ? removeBlockquote : action.data === true ? addBlockquote : toggleBlockquote)(view);
4390
- break;
4391
- case "codeblock":
4392
- (action.data === false ? removeCodeblock : addCodeblock)(view);
4393
- break;
4394
- case "table":
4395
- insertTable(view);
4396
- break;
4397
- case "link":
4398
- (action.data === false ? removeLink : addLink)(view);
4399
- break;
4400
- case "comment":
4401
- createComment(view);
4402
- break;
4403
- }
4404
- setTimeout(() => {
4405
- if (!view.hasFocus) {
4406
- view.focus();
4407
- }
4408
- });
4409
- };
4410
- };
4411
-
4412
- // packages/ui/react-ui-editor/src/hooks/useEditorView.ts
4413
- import { useRef as useRef3, useState as useState4 } from "react";
4414
- var useEditorView = (id) => {
4415
- const editorRef = useRef3(null);
4416
- const [prev, setPrev] = useState4([
4417
- null,
4418
- ""
4419
- ]);
4420
- if (prev[0] !== editorRef.current) {
4421
- setPrev([
4422
- editorRef.current,
4423
- id
4424
- ]);
4425
- }
4426
- return [
4427
- editorRef,
4428
- prev[1] !== id
4429
- ];
4430
- };
4431
-
4432
- // packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
4433
- import { EditorSelection as EditorSelection2, EditorState as EditorState3 } from "@codemirror/state";
4434
- import { EditorView as EditorView15 } from "@codemirror/view";
4435
- import { useEffect as useEffect3, useRef as useRef4, useState as useState5 } from "react";
4436
- import { log as log5 } from "@dxos/log";
4437
- import { isNotFalsy as isNotFalsy5 } from "@dxos/util";
4438
- var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
4439
- var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions } = {}, deps) => {
4440
- const onUpdate = useRef4();
4441
- const [view, setView] = useState5();
4442
- const parentRef = useRef4(null);
4443
- useEffect3(() => {
4444
- let view2;
4445
- if (parentRef.current) {
4446
- const state = EditorState3.create({
4447
- doc,
4448
- selection,
4449
- extensions: [
4450
- // TODO(burdon): Doesn't catch errors in keymap functions.
4451
- EditorView15.exceptionSink.of((err) => {
4452
- log5.catch(err, void 0, {
4453
- F: __dxlog_file6,
4454
- L: 57,
4455
- S: void 0,
4456
- C: (f, a) => f(...a)
4457
- });
4458
- }),
4459
- extensions,
4460
- EditorView15.updateListener.of(() => {
4461
- onUpdate.current?.();
4462
- })
4463
- ].filter(isNotFalsy5)
4464
- });
4465
- view2 = new EditorView15({
4466
- parent: parentRef.current,
4467
- scrollTo,
4468
- state,
4469
- // NOTE: Uncomment to debug/monitor all transactions.
4470
- // https://codemirror.net/docs/ref/#view.EditorView.dispatch
4471
- dispatchTransactions: (trs, view3) => {
4472
- if (debug) {
4473
- logChanges(trs);
4474
- }
4475
- view3.update(trs);
4476
- }
4477
- });
4478
- setView(view2);
4479
- }
4480
- return () => {
4481
- view2?.destroy();
4482
- };
4483
- }, deps);
4484
- useEffect3(() => {
4485
- if (view) {
4486
- if (!selection && !view.state.selection.main.anchor) {
4487
- selection = EditorSelection2.single(view.state.doc.line(1).to);
4488
- }
4489
- if (selection || scrollTo) {
4490
- onUpdate.current = () => {
4491
- onUpdate.current = void 0;
4492
- view.dispatch({
4493
- selection,
4494
- effects: scrollTo && [
4495
- scrollTo
4496
- ],
4497
- scrollIntoView: !scrollTo
4498
- });
4499
- };
4500
- }
4501
- if (autoFocus) {
4502
- view.focus();
4503
- }
4504
- }
4505
- }, [
4506
- view,
4507
- autoFocus,
4508
- selection,
4509
- scrollTo
4510
- ]);
4511
- return {
4512
- parentRef,
4513
- view
4514
- };
4515
- };
4516
- var createDataExtensions = ({ readonly = false } = {}) => {
4517
- return [
4518
- //
4519
- EditorState3.readOnly.of(readonly),
4520
- EditorView15.editable.of(!readonly)
4521
- ];
4522
- };
4523
- var createThemeExtensions = ({ theme, themeMode, slots } = {}) => {
4524
- return [
4525
- //
4526
- EditorView15.baseTheme(defaultTheme),
4527
- theme && EditorView15.theme(theme),
4528
- EditorView15.darkTheme.of(themeMode === "dark"),
4529
- EditorView15.editorAttributes.of({
4530
- class: slots?.editor?.className ?? ""
4531
- }),
4532
- EditorView15.contentAttributes.of({
4533
- class: slots?.content?.className ?? ""
4534
- })
4535
- ].filter(isNotFalsy5);
4536
- };
4537
-
4538
- // packages/ui/react-ui-editor/src/hooks/useTextModel.ts
4539
- import get5 from "lodash.get";
4540
- import { useState as useState6, useMemo as useMemo3 } from "react";
4541
- import { generateName } from "@dxos/display-name";
4542
- import { getRawDoc } from "@dxos/echo-schema";
4543
- import { invariant as invariant3 } from "@dxos/invariant";
4544
- import { isAutomergeObject } from "@dxos/react-client/echo";
4545
- import { hueTokens } from "@dxos/react-ui-theme";
4546
- import { hexToHue } from "@dxos/util";
4547
- var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
4548
- var useTextExtensions = ({ id, text, space, identity }) => {
4549
- const extensions = [
4550
- automerge(text)
4551
- ];
4552
- const peerId = identity?.identityKey.toHex();
4553
- const { cursorLightValue, cursorDarkValue } = hueTokens[hexToHue(peerId ?? "0")];
4554
- if (space && identity) {
4555
- const awarenessProvider2 = new SpaceAwarenessProvider({
4556
- space,
4557
- channel: `awareness.${id}`,
4558
- peerId: identity.identityKey.toHex(),
4559
- info: {
4560
- displayName: identity.profile?.displayName ?? generateName(identity.identityKey.toHex()),
4561
- color: cursorDarkValue,
4562
- lightColor: cursorLightValue
4563
- }
4564
- });
4565
- extensions.push(awareness(awarenessProvider2));
4566
- }
4567
- return extensions;
4568
- };
4569
- var useTextModel = (props) => useMemo3(() => createModel(props), Object.values(props));
4570
- var useInMemoryTextModel = ({ id, defaultContent }) => {
4571
- const [content, setContent] = useState6(defaultContent ?? "");
4572
- return {
4573
- id,
4574
- content,
4575
- setContent,
4576
- text: () => content
4577
- };
4578
- };
4579
- var createModel = ({ space, identity, text }) => {
4580
- if (!text) {
4581
- return void 0;
4582
- }
4583
- invariant3(isAutomergeObject(text), void 0, {
4584
- F: __dxlog_file7,
4585
- L: 87,
4586
- S: void 0,
4587
- A: [
4588
- "isAutomergeObject(text)",
4589
- ""
4590
- ]
4591
- });
4592
- const obj = text;
4593
- const doc = getRawDoc(obj, [
4594
- obj.field
4595
- ]);
4596
- const peerId = identity?.identityKey.toHex();
4597
- const { cursorLightValue, cursorDarkValue } = hueTokens[hexToHue(peerId ?? "0")];
4598
- const awarenessProvider2 = space && new SpaceAwarenessProvider({
4599
- space,
4600
- channel: `automerge.awareness.${obj.id}`,
4601
- info: {
4602
- displayName: identity ? identity.profile?.displayName ?? generateName(identity.identityKey.toHex()) : void 0,
4603
- color: cursorLightValue,
4604
- lightColor: cursorDarkValue
4605
- },
4606
- peerId: identity?.identityKey.toHex() ?? "Anonymous"
4607
- });
4608
- const extensions = [
4609
- modelState.init(() => model),
4610
- automerge({
4611
- handle: doc.handle,
4612
- path: doc.path
4613
- })
4614
- ];
4615
- if (awarenessProvider2) {
4616
- extensions.push(awareness(awarenessProvider2));
4617
- }
4618
- const model = {
4619
- id: obj.id,
4620
- content: doc,
4621
- text: () => get5(doc.handle.docSync(), doc.path),
4622
- extension: extensions,
4623
- peer: identity ? {
4624
- id: identity.identityKey.toHex(),
4625
- name: identity.profile?.displayName
4626
- } : void 0
4627
- };
4628
- return model;
4629
- };
4630
4862
  export {
4631
4863
  BaseTextEditor,
4632
4864
  Cursor,
@@ -4655,11 +4887,11 @@ export {
4655
4887
  blast,
4656
4888
  callbackWrapper,
4657
4889
  codeTheme,
4890
+ command,
4658
4891
  comments,
4659
4892
  compareFormatting,
4660
- createBasicBundle,
4893
+ createBasicExtensions,
4661
4894
  createComment,
4662
- createDataExtensions,
4663
4895
  createMarkdownExtensions,
4664
4896
  createThemeExtensions,
4665
4897
  cursorLineMargin,
@@ -4670,6 +4902,7 @@ export {
4670
4902
  defaultSlots,
4671
4903
  defaultTextSlots,
4672
4904
  defaultTheme,
4905
+ dnd,
4673
4906
  editorFillLayoutEditor,
4674
4907
  editorFillLayoutRoot,
4675
4908
  editorMode,
@@ -4680,7 +4913,7 @@ export {
4680
4913
  getToken,
4681
4914
  image,
4682
4915
  insertTable,
4683
- keymap8 as keymap,
4916
+ keymap9 as keymap,
4684
4917
  linkTooltip,
4685
4918
  listener,
4686
4919
  logChanges,
@@ -4689,7 +4922,6 @@ export {
4689
4922
  markdownTagsExtensions,
4690
4923
  markdownTheme,
4691
4924
  mention,
4692
- modelState,
4693
4925
  outliner,
4694
4926
  removeBlockquote,
4695
4927
  removeCodeblock,