@dxos/react-ui-editor 0.3.11-main.121f5a8 → 0.3.11-main.13264f1

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 (103) hide show
  1. package/dist/lib/browser/index.mjs +618 -748
  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.map +1 -1
  5. package/dist/types/src/components/TextEditor/TextEditor.d.ts +2 -2
  6. package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
  7. package/dist/types/src/extensions/awareness.d.ts +1 -3
  8. package/dist/types/src/extensions/awareness.d.ts.map +1 -1
  9. package/dist/types/src/extensions/basic.d.ts +2 -2
  10. package/dist/types/src/extensions/basic.d.ts.map +1 -1
  11. package/dist/types/src/extensions/comments.d.ts +3 -3
  12. package/dist/types/src/extensions/comments.d.ts.map +1 -1
  13. package/dist/types/src/extensions/index.d.ts +0 -7
  14. package/dist/types/src/extensions/index.d.ts.map +1 -1
  15. package/dist/types/src/extensions/markdown/code.d.ts.map +1 -0
  16. package/dist/types/src/extensions/markdown/heading.d.ts +6 -0
  17. package/dist/types/src/extensions/markdown/heading.d.ts.map +1 -0
  18. package/dist/types/src/extensions/markdown/hr.d.ts.map +1 -0
  19. package/dist/types/src/extensions/markdown/image.d.ts.map +1 -0
  20. package/dist/types/src/extensions/markdown/index.d.ts +7 -0
  21. package/dist/types/src/extensions/markdown/index.d.ts.map +1 -1
  22. package/dist/types/src/extensions/markdown/link.d.ts.map +1 -0
  23. package/dist/types/src/extensions/markdown/table.d.ts.map +1 -0
  24. package/dist/types/src/extensions/markdown/tasklist.d.ts.map +1 -0
  25. package/dist/types/src/hooks/awareness-provider.d.ts +7 -4
  26. package/dist/types/src/hooks/awareness-provider.d.ts.map +1 -1
  27. package/dist/types/src/hooks/defs.d.ts +1 -4
  28. package/dist/types/src/hooks/defs.d.ts.map +1 -1
  29. package/dist/types/src/hooks/index.d.ts +1 -2
  30. package/dist/types/src/hooks/index.d.ts.map +1 -1
  31. package/dist/types/src/hooks/useTextEditor.d.ts +17 -0
  32. package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -0
  33. package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
  34. package/package.json +24 -27
  35. package/src/components/TextEditor/MarkdownEditor.stories.tsx +3 -1
  36. package/src/components/TextEditor/TextEditor.tsx +11 -14
  37. package/src/components/TextEditor/comments.stories.tsx +5 -5
  38. package/src/extensions/awareness.ts +14 -31
  39. package/src/extensions/basic.ts +3 -3
  40. package/src/extensions/comments.ts +15 -15
  41. package/src/extensions/index.ts +0 -7
  42. package/src/extensions/{code.ts → markdown/code.ts} +1 -1
  43. package/src/extensions/markdown/heading.ts +60 -0
  44. package/src/extensions/{hr.ts → markdown/hr.ts} +1 -1
  45. package/src/extensions/markdown/index.ts +7 -0
  46. package/src/extensions/{tasklist.ts → markdown/tasklist.ts} +1 -1
  47. package/src/hooks/awareness-provider.ts +24 -20
  48. package/src/hooks/defs.ts +1 -6
  49. package/src/hooks/index.ts +1 -2
  50. package/src/hooks/useTextEditor.ts +29 -0
  51. package/src/hooks/useTextModel.ts +46 -12
  52. package/dist/types/src/components/TextEditor/codemirror.stories.d.ts +0 -12
  53. package/dist/types/src/components/TextEditor/codemirror.stories.d.ts.map +0 -1
  54. package/dist/types/src/components/TextEditor/yjs.stories.d.ts +0 -12
  55. package/dist/types/src/components/TextEditor/yjs.stories.d.ts.map +0 -1
  56. package/dist/types/src/extensions/code.d.ts.map +0 -1
  57. package/dist/types/src/extensions/hr.d.ts.map +0 -1
  58. package/dist/types/src/extensions/image.d.ts.map +0 -1
  59. package/dist/types/src/extensions/link.d.ts.map +0 -1
  60. package/dist/types/src/extensions/table.d.ts.map +0 -1
  61. package/dist/types/src/extensions/tasklist.d.ts.map +0 -1
  62. package/dist/types/src/extensions/yjs/cursor.d.ts +0 -4
  63. package/dist/types/src/extensions/yjs/cursor.d.ts.map +0 -1
  64. package/dist/types/src/extensions/yjs/index.d.ts +0 -2
  65. package/dist/types/src/extensions/yjs/index.d.ts.map +0 -1
  66. package/dist/types/src/extensions/yjs/yjs.d.ts +0 -4
  67. package/dist/types/src/extensions/yjs/yjs.d.ts.map +0 -1
  68. package/dist/types/src/extensions/yjs/yjs.test.d.ts +0 -2
  69. package/dist/types/src/extensions/yjs/yjs.test.d.ts.map +0 -1
  70. package/dist/types/src/hooks/automerge.d.ts +0 -4
  71. package/dist/types/src/hooks/automerge.d.ts.map +0 -1
  72. package/dist/types/src/hooks/yjs.d.ts +0 -28
  73. package/dist/types/src/hooks/yjs.d.ts.map +0 -1
  74. package/dist/types/src/testing/index.d.ts +0 -3
  75. package/dist/types/src/testing/index.d.ts.map +0 -1
  76. package/dist/types/src/testing/proto/gen/schema.d.ts +0 -15
  77. package/dist/types/src/testing/proto/gen/schema.d.ts.map +0 -1
  78. package/dist/types/src/testing/proto/index.d.ts +0 -2
  79. package/dist/types/src/testing/proto/index.d.ts.map +0 -1
  80. package/dist/types/src/testing/replicator.d.ts +0 -45
  81. package/dist/types/src/testing/replicator.d.ts.map +0 -1
  82. package/src/components/TextEditor/codemirror.stories.ts +0 -115
  83. package/src/components/TextEditor/yjs.stories.tsx +0 -56
  84. package/src/extensions/yjs/cursor.ts +0 -22
  85. package/src/extensions/yjs/index.ts +0 -5
  86. package/src/extensions/yjs/yjs.test.ts +0 -35
  87. package/src/extensions/yjs/yjs.ts +0 -16
  88. package/src/hooks/automerge.ts +0 -53
  89. package/src/hooks/yjs.ts +0 -157
  90. package/src/testing/index.ts +0 -6
  91. package/src/testing/proto/gen/schema.ts +0 -49
  92. package/src/testing/proto/index.ts +0 -5
  93. package/src/testing/proto/schema.proto +0 -15
  94. package/src/testing/replicator.ts +0 -184
  95. /package/dist/types/src/extensions/{code.d.ts → markdown/code.d.ts} +0 -0
  96. /package/dist/types/src/extensions/{hr.d.ts → markdown/hr.d.ts} +0 -0
  97. /package/dist/types/src/extensions/{image.d.ts → markdown/image.d.ts} +0 -0
  98. /package/dist/types/src/extensions/{link.d.ts → markdown/link.d.ts} +0 -0
  99. /package/dist/types/src/extensions/{table.d.ts → markdown/table.d.ts} +0 -0
  100. /package/dist/types/src/extensions/{tasklist.d.ts → markdown/tasklist.d.ts} +0 -0
  101. /package/src/extensions/{image.ts → markdown/image.ts} +0 -0
  102. /package/src/extensions/{link.ts → markdown/link.ts} +0 -0
  103. /package/src/extensions/{table.ts → markdown/table.ts} +0 -0
@@ -11,10 +11,10 @@ import { EditorView as EditorView13 } from "@codemirror/view";
11
11
  import { useFocusableGroup } from "@fluentui/react-tabster";
12
12
  import { vim } from "@replit/codemirror-vim";
13
13
  import defaultsDeep2 from "lodash.defaultsdeep";
14
- import React, { forwardRef, useCallback, useEffect as useEffect3, useImperativeHandle, useRef, useState } from "react";
14
+ import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useRef, useState } from "react";
15
15
  import { log as log2 } from "@dxos/log";
16
- import { useThemeContext as useThemeContext2 } from "@dxos/react-ui";
17
- import { inputSurface, mx as mx3 } from "@dxos/react-ui-theme";
16
+ import { useThemeContext } from "@dxos/react-ui";
17
+ import { attentionSurface, mx as mx3 } from "@dxos/react-ui-theme";
18
18
 
19
19
  // packages/ui/react-ui-editor/src/extensions/autocomplete.ts
20
20
  import { autocompletion, completionKeymap } from "@codemirror/autocomplete";
@@ -293,9 +293,9 @@ var Cursor = class _Cursor {
293
293
  }
294
294
  static {
295
295
  this.getCursorFromRange = (state, range) => {
296
- const cursorConverter3 = state.facet(_Cursor.converter);
297
- const from = cursorConverter3.toCursor(range.from);
298
- const to = cursorConverter3.toCursor(range.to, -1);
296
+ const cursorConverter2 = state.facet(_Cursor.converter);
297
+ const from = cursorConverter2.toCursor(range.from);
298
+ const to = cursorConverter2.toCursor(range.to, -1);
299
299
  return [
300
300
  from,
301
301
  to
@@ -304,10 +304,10 @@ var Cursor = class _Cursor {
304
304
  }
305
305
  static {
306
306
  this.getRangeFromCursor = (state, cursor) => {
307
- const cursorConverter3 = state.facet(_Cursor.converter);
307
+ const cursorConverter2 = state.facet(_Cursor.converter);
308
308
  const parts = cursor.split(":");
309
- const from = cursorConverter3.fromCursor(parts[0]);
310
- const to = cursorConverter3.fromCursor(parts[1]);
309
+ const from = cursorConverter2.fromCursor(parts[0]);
310
+ const to = cursorConverter2.fromCursor(parts[1]);
311
311
  return from !== void 0 && to !== void 0 ? {
312
312
  from,
313
313
  to
@@ -386,21 +386,17 @@ var automerge3 = ({ handle, path }) => {
386
386
  // packages/ui/react-ui-editor/src/extensions/awareness.ts
387
387
  import { Annotation as Annotation2, Facet as Facet2, RangeSet } from "@codemirror/state";
388
388
  import { Decoration, EditorView as EditorView2, ViewPlugin as ViewPlugin2, WidgetType } from "@codemirror/view";
389
- import { useEffect } from "react";
390
389
  import { Event } from "@dxos/async";
391
390
  import { Context } from "@dxos/context";
392
- import { generateName } from "@dxos/display-name";
393
- import { useThemeContext } from "@dxos/react-ui";
394
- import { getColorForValue } from "@dxos/react-ui-theme";
395
391
  var dummyProvider = {
396
392
  remoteStateChange: new Event(),
397
393
  open: () => {
398
394
  },
399
395
  close: () => {
400
396
  },
397
+ getRemoteStates: () => [],
401
398
  update: () => {
402
- },
403
- getRemoteStates: () => []
399
+ }
404
400
  };
405
401
  var AwarenessProvider = Facet2.define({
406
402
  combine: (providers) => providers[0] ?? dummyProvider
@@ -415,29 +411,6 @@ var awareness = (provider = dummyProvider) => {
415
411
  styles
416
412
  ];
417
413
  };
418
- var useAwareness = ({ awareness: awareness2, peer }) => {
419
- const { themeMode } = useThemeContext();
420
- useEffect(() => {
421
- if (awareness2 && peer) {
422
- awareness2.setLocalStateField("user", {
423
- name: peer.name ?? generateName(peer.id),
424
- color: getColorForValue({
425
- value: peer.id,
426
- type: "color"
427
- }),
428
- colorLight: getColorForValue({
429
- value: peer.id,
430
- themeMode,
431
- type: "highlight"
432
- })
433
- });
434
- }
435
- }, [
436
- awareness2,
437
- peer,
438
- themeMode
439
- ]);
440
- };
441
414
  var RemoteSelectionsDecorator = class {
442
415
  constructor(view) {
443
416
  this.decorations = RangeSet.of([]);
@@ -599,39 +572,41 @@ var styles = EditorView2.baseTheme({
599
572
  marginLeft: "-1px",
600
573
  marginRight: "-1px",
601
574
  boxSizing: "border-box",
602
- display: "inline"
575
+ display: "inline",
576
+ cursor: "pointer"
603
577
  },
604
578
  ".cm-collab-selectionCaretDot": {
605
579
  borderRadius: "50%",
606
580
  position: "absolute",
607
- width: ".4em",
608
- height: ".4em",
609
- top: "-.2em",
610
- left: "-.2em",
581
+ width: ".5em",
582
+ height: ".5em",
583
+ top: "-.25em",
584
+ left: "-.25em",
611
585
  backgroundColor: "inherit",
612
586
  transition: "transform .3s ease-in-out",
613
587
  boxSizing: "border-box"
614
588
  },
615
589
  ".cm-collab-selectionCaret:hover > .cm-collab-selectionCaretDot": {
616
- transformOrigin: "bottom center",
617
- transform: "scale(0)"
590
+ transform: "scale(0)",
591
+ transformOrigin: "center"
618
592
  },
619
593
  ".cm-collab-selectionInfo": {
620
594
  position: "absolute",
621
- top: "-1.05em",
622
- left: "-1px",
595
+ transform: "translate(-50%, 0)",
596
+ top: "-20px",
597
+ left: 0,
623
598
  fontSize: ".75em",
624
- fontFamily: "serif",
599
+ fontFamily: "sans-serif",
625
600
  fontStyle: "normal",
626
601
  fontWeight: "normal",
627
602
  lineHeight: "normal",
628
603
  userSelect: "none",
629
604
  color: "white",
630
- paddingLeft: "2px",
631
- paddingRight: "2px",
605
+ padding: "2px",
632
606
  zIndex: 101,
633
607
  transition: "opacity .3s ease-in-out",
634
608
  backgroundColor: "inherit",
609
+ borderRadius: "2px",
635
610
  // These should be separate.
636
611
  opacity: 0,
637
612
  transitionDelay: "0s",
@@ -649,8 +624,8 @@ import { history } from "@codemirror/commands";
649
624
  import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
650
625
  import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
651
626
  import { drawSelection, EditorView as EditorView3, highlightActiveLine, placeholder } from "@codemirror/view";
652
- var basicBundle = ({ themeMode, placeholder: _placeholder, multiline = true }) => [
653
- multiline ? EditorView3.lineWrapping : [],
627
+ var basicBundle = ({ themeMode, placeholder: _placeholder, lineWrapping = true }) => [
628
+ lineWrapping ? EditorView3.lineWrapping : [],
654
629
  // https://codemirror.net/docs/ref/#codemirror.minimalSetup
655
630
  bracketMatching(),
656
631
  closeBrackets(),
@@ -972,9 +947,14 @@ var random = (min, max) => {
972
947
  return min + ~~(Math.random() * (max - min + 1));
973
948
  };
974
949
 
975
- // packages/ui/react-ui-editor/src/extensions/code.ts
976
- import { ViewPlugin as ViewPlugin3, EditorView as EditorView5, Decoration as Decoration2 } from "@codemirror/view";
977
- import { mx as mx2 } from "@dxos/react-ui-theme";
950
+ // packages/ui/react-ui-editor/src/extensions/comments.ts
951
+ import { StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
952
+ import { hoverTooltip, keymap as keymap3, Decoration as Decoration2, EditorView as EditorView5 } from "@codemirror/view";
953
+ import sortBy from "lodash.sortby";
954
+ import { useEffect } from "react";
955
+ import { debounce } from "@dxos/async";
956
+ import { invariant as invariant3 } from "@dxos/invariant";
957
+ import { nonNullable } from "@dxos/util";
978
958
 
979
959
  // packages/ui/react-ui-editor/src/styles/cursors.ts
980
960
  import * as random2 from "lib0/random";
@@ -1062,89 +1042,6 @@ import { tailwindConfig } from "@dxos/react-ui-theme";
1062
1042
  var tokens = tailwindConfig({}).theme;
1063
1043
  var getToken = (path, defaultValue = void 0) => get2(tokens, path, defaultValue);
1064
1044
 
1065
- // packages/ui/react-ui-editor/src/extensions/code.ts
1066
- var CODE_REGEX = /```[\s\S]*?```/gs;
1067
- var styles2 = EditorView5.baseTheme({
1068
- "& .cm-codeblock": {
1069
- fontFamily: getToken("fontFamily.mono", []).join(",")
1070
- },
1071
- '&light [aria-readonly="true"] .cm-codeblock': {
1072
- background: getToken("extend.colors.neutral.50")
1073
- },
1074
- '&dark [aria-readonly="true"] .cm-codeblock': {
1075
- background: getToken("extend.colors.neutral.850")
1076
- },
1077
- '& [aria-readonly="true"] .cm-codeblock': {
1078
- display: "block",
1079
- paddingInline: "4px !important"
1080
- },
1081
- '& [aria-readonly="true"] .cm-codeblock-first': {
1082
- paddingTop: "4px !important",
1083
- borderTopLeftRadius: "4px",
1084
- borderTopRightRadius: "4px"
1085
- },
1086
- '& [aria-readonly="true"] .cm-codeblock-last': {
1087
- paddingBottom: "4px !important",
1088
- borderBottomLeftRadius: "4px",
1089
- borderBottomRightRadius: "4px"
1090
- }
1091
- });
1092
- var getLineRange = (lines, from, to) => {
1093
- const start = lines.findIndex((line) => line.from >= from);
1094
- const end = lines.findIndex((line) => line.to >= to);
1095
- return [
1096
- start,
1097
- end
1098
- ];
1099
- };
1100
- var code2 = () => {
1101
- const buildDecorations5 = (view) => {
1102
- const decorations = [];
1103
- const text = view.state.doc.sliceString(0);
1104
- const matches = text.matchAll(CODE_REGEX);
1105
- const blocks = view.viewportLineBlocks;
1106
- for (const match of matches) {
1107
- const range = getLineRange(blocks, match.index, match.index + match[0].length);
1108
- for (let i = range[0]; i <= range[1]; i++) {
1109
- const block = blocks[i];
1110
- decorations.push(Decoration2.line({
1111
- class: mx2("cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
1112
- }).range(block.from));
1113
- }
1114
- }
1115
- return Decoration2.set(decorations);
1116
- };
1117
- return [
1118
- ViewPlugin3.fromClass(class {
1119
- constructor(view) {
1120
- this.hasFocus = false;
1121
- this.decorations = buildDecorations5(view);
1122
- }
1123
- update(update2) {
1124
- if (
1125
- // TODO(burdon): Generalize for other extensions.
1126
- this.hasFocus !== update2.view.hasFocus || update2.startState.readOnly !== update2.view.state.readOnly || update2.docChanged || update2.viewportChanged
1127
- ) {
1128
- this.hasFocus = update2.view.hasFocus;
1129
- this.decorations = buildDecorations5(update2.view);
1130
- }
1131
- }
1132
- }, {
1133
- decorations: (value) => value.decorations
1134
- }),
1135
- styles2
1136
- ];
1137
- };
1138
-
1139
- // packages/ui/react-ui-editor/src/extensions/comments.ts
1140
- import { StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
1141
- import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView as EditorView6 } from "@codemirror/view";
1142
- import sortBy from "lodash.sortby";
1143
- import { useEffect as useEffect2 } from "react";
1144
- import { debounce } from "@dxos/async";
1145
- import { invariant as invariant3 } from "@dxos/invariant";
1146
- import { nonNullable } from "@dxos/util";
1147
-
1148
1045
  // packages/ui/react-ui-editor/src/util.ts
1149
1046
  import { log } from "@dxos/log";
1150
1047
  var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util.ts";
@@ -1182,20 +1079,20 @@ var logChanges = (trs) => {
1182
1079
 
1183
1080
  // packages/ui/react-ui-editor/src/extensions/comments.ts
1184
1081
  var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/comments.ts";
1185
- var styles3 = EditorView6.baseTheme({
1082
+ var styles2 = EditorView5.baseTheme({
1186
1083
  "& .cm-comment": {
1187
1084
  backgroundColor: getToken("extend.colors.yellow.50")
1188
1085
  },
1189
- "& .cm-comment-active": {
1086
+ "& .cm-comment-current": {
1190
1087
  backgroundColor: getToken("extend.colors.yellow.100")
1191
1088
  }
1192
1089
  });
1193
1090
  var marks = {
1194
- highlight: Decoration3.mark({
1091
+ highlight: Decoration2.mark({
1195
1092
  class: "cm-comment"
1196
1093
  }),
1197
- highlightActive: Decoration3.mark({
1198
- class: "cm-comment-active"
1094
+ highlightActive: Decoration2.mark({
1095
+ class: "cm-comment-current"
1199
1096
  })
1200
1097
  };
1201
1098
  var setFocus = (view, id, center = true) => {
@@ -1211,11 +1108,11 @@ var setFocus = (view, id, center = true) => {
1211
1108
  },
1212
1109
  effects: [
1213
1110
  //
1214
- EditorView6.scrollIntoView(range.from, center ? {
1111
+ EditorView5.scrollIntoView(range.from, center ? {
1215
1112
  y: "center"
1216
1113
  } : void 0),
1217
1114
  setSelection.of({
1218
- active: id
1115
+ current: id
1219
1116
  })
1220
1117
  ]
1221
1118
  });
@@ -1260,23 +1157,23 @@ var commentsState = StateField2.define({
1260
1157
  return value;
1261
1158
  }
1262
1159
  });
1263
- var highlightDecorations = EditorView6.decorations.compute([
1160
+ var highlightDecorations = EditorView5.decorations.compute([
1264
1161
  commentsState
1265
1162
  ], (state) => {
1266
- const { selection: { active }, comments: comments2 } = state.field(commentsState);
1163
+ const { selection: { current }, comments: comments2 } = state.field(commentsState);
1267
1164
  const decorations = sortBy(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
1268
1165
  const range = comment.range;
1269
1166
  if (!range || range.from === range.to) {
1270
1167
  console.warn("Invalid range:", range);
1271
1168
  return void 0;
1272
1169
  }
1273
- if (comment.comment.id === active) {
1170
+ if (comment.comment.id === current) {
1274
1171
  return marks.highlightActive.range(range.from, range.to);
1275
1172
  } else {
1276
1173
  return marks.highlight.range(range.from, range.to);
1277
1174
  }
1278
1175
  }).filter(nonNullable);
1279
- return Decoration3.set(decorations);
1176
+ return Decoration2.set(decorations);
1280
1177
  });
1281
1178
  var trackPastedComments = (onUpdate) => {
1282
1179
  let tracked = null;
@@ -1298,12 +1195,12 @@ var trackPastedComments = (onUpdate) => {
1298
1195
  }
1299
1196
  };
1300
1197
  return [
1301
- EditorView6.domEventHandlers({
1198
+ EditorView5.domEventHandlers({
1302
1199
  cut: handleTrack,
1303
1200
  copy: handleTrack
1304
1201
  }),
1305
1202
  // Handle paste.
1306
- EditorView6.updateListener.of(({ view, state, transactions }) => {
1203
+ EditorView5.updateListener.of(({ view, state, transactions }) => {
1307
1204
  if (tracked) {
1308
1205
  const paste = transactions.find((tr) => tr.isUserEvent("input.paste"));
1309
1206
  if (paste) {
@@ -1366,7 +1263,7 @@ var comments = (options = {}) => {
1366
1263
  if (id) {
1367
1264
  view.dispatch({
1368
1265
  effects: setSelection.of({
1369
- active: id
1266
+ current: id
1370
1267
  }),
1371
1268
  selection: {
1372
1269
  anchor: from
@@ -1380,7 +1277,7 @@ var comments = (options = {}) => {
1380
1277
  return [
1381
1278
  commentsState,
1382
1279
  highlightDecorations,
1383
- styles3,
1280
+ styles2,
1384
1281
  //
1385
1282
  // Keymap.
1386
1283
  //
@@ -1423,7 +1320,7 @@ var comments = (options = {}) => {
1423
1320
  //
1424
1321
  // Track deleted ranges and update ranges for decorations.
1425
1322
  //
1426
- EditorView6.updateListener.of(({ view, state, changes }) => {
1323
+ EditorView5.updateListener.of(({ view, state, changes }) => {
1427
1324
  let mod = false;
1428
1325
  const { comments: comments2, ...value } = state.field(commentsState);
1429
1326
  changes.iterChanges((from, to, from2, to2) => {
@@ -1453,17 +1350,17 @@ var comments = (options = {}) => {
1453
1350
  //
1454
1351
  // Track selection/proximity.
1455
1352
  //
1456
- EditorView6.updateListener.of(({ view, state, changes }) => {
1353
+ EditorView5.updateListener.of(({ view, state }) => {
1457
1354
  let min = Infinity;
1458
- const { selection: { active, closest }, comments: comments2 } = state.field(commentsState);
1355
+ const { selection: { current, closest }, comments: comments2 } = state.field(commentsState);
1459
1356
  const { head } = state.selection.main;
1460
1357
  const selection = {};
1461
1358
  comments2.forEach(({ comment, range }) => {
1462
1359
  if (head >= range.from && head <= range.to) {
1463
- selection.active = comment.id;
1360
+ selection.current = comment.id;
1464
1361
  selection.closest = void 0;
1465
1362
  }
1466
- if (!selection.active) {
1363
+ if (!selection.current) {
1467
1364
  const d = Math.min(Math.abs(head - range.from), Math.abs(head - range.to));
1468
1365
  if (d < min) {
1469
1366
  selection.closest = comment.id;
@@ -1471,7 +1368,7 @@ var comments = (options = {}) => {
1471
1368
  }
1472
1369
  }
1473
1370
  });
1474
- if (selection.active !== active || selection.closest !== closest) {
1371
+ if (selection.current !== current || selection.closest !== closest) {
1475
1372
  view.dispatch({
1476
1373
  effects: setSelection.of(selection)
1477
1374
  });
@@ -1488,9 +1385,9 @@ var comments = (options = {}) => {
1488
1385
  options.onUpdate ? trackPastedComments(options.onUpdate) : []
1489
1386
  ];
1490
1387
  };
1491
- var useComments = (view, comments2) => {
1492
- useEffect2(() => {
1493
- if (view && comments2) {
1388
+ var useComments = (view, comments2 = []) => {
1389
+ useEffect(() => {
1390
+ if (view) {
1494
1391
  view.dispatch({
1495
1392
  effects: setComments.of(comments2)
1496
1393
  });
@@ -1501,329 +1398,65 @@ var useComments = (view, comments2) => {
1501
1398
  ]);
1502
1399
  };
1503
1400
 
1504
- // packages/ui/react-ui-editor/src/extensions/hr.ts
1505
- import { syntaxTree } from "@codemirror/language";
1506
- import { RangeSetBuilder } from "@codemirror/state";
1507
- import { Decoration as Decoration4, EditorView as EditorView7, ViewPlugin as ViewPlugin4, WidgetType as WidgetType2 } from "@codemirror/view";
1508
- var styles4 = EditorView7.baseTheme({
1509
- "& .cm-hr": {
1510
- // Note that block-level decorations should not have vertical margins,
1511
- borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
1512
- }
1513
- });
1514
- var HorizontalRuleWidget = class extends WidgetType2 {
1515
- toDOM() {
1516
- const el = document.createElement("div");
1517
- el.className = "cm-hr";
1518
- return el;
1519
- }
1520
- };
1521
- var decoration = Decoration4.replace({
1522
- widget: new HorizontalRuleWidget()
1523
- });
1524
- var buildDecorations = (view) => {
1525
- const builder = new RangeSetBuilder();
1526
- const { state } = view;
1527
- const cursor = state.selection.main.head;
1528
- for (const { from, to } of view.visibleRanges) {
1529
- syntaxTree(state).iterate({
1530
- enter: (node) => {
1531
- if (node.name === "HorizontalRule") {
1532
- if (cursor <= node.from || cursor >= node.to) {
1533
- builder.add(node.from, node.to, decoration);
1534
- }
1535
- }
1536
- },
1537
- from,
1538
- to
1539
- });
1540
- }
1541
- return builder.finish();
1542
- };
1543
- var hr = () => {
1544
- return [
1545
- styles4,
1546
- ViewPlugin4.fromClass(class {
1547
- constructor(view) {
1548
- this.decorations = buildDecorations(view);
1549
- }
1550
- update(update2) {
1551
- this.decorations = buildDecorations(update2.view);
1552
- }
1553
- }, {
1554
- decorations: (v) => v.decorations
1555
- })
1556
- ];
1401
+ // packages/ui/react-ui-editor/src/extensions/listener.ts
1402
+ import { EditorView as EditorView6 } from "@codemirror/view";
1403
+ var listener = ({ onFocus, onChange }) => {
1404
+ const extensions = [];
1405
+ onFocus && extensions.push(EditorView6.focusChangeEffect.of((_, focused) => {
1406
+ onFocus(focused);
1407
+ return null;
1408
+ }));
1409
+ onChange && extensions.push(EditorView6.updateListener.of((update2) => {
1410
+ onChange(update2.state.doc.toString());
1411
+ }));
1412
+ return extensions;
1557
1413
  };
1558
1414
 
1559
- // packages/ui/react-ui-editor/src/extensions/image.ts
1560
- import { syntaxTree as syntaxTree2 } from "@codemirror/language";
1561
- import { StateField as StateField3 } from "@codemirror/state";
1562
- import { Decoration as Decoration5, EditorView as EditorView8, WidgetType as WidgetType3 } from "@codemirror/view";
1563
- var image = (options = {}) => {
1564
- return StateField3.define({
1565
- create: (state) => {
1566
- return Decoration5.set(buildDecorations2(0, state.doc.length, state));
1567
- },
1568
- update: (value, tr) => {
1569
- if (!tr.docChanged && !tr.selection) {
1570
- return value;
1571
- }
1572
- const cursor = tr.state.selection.main.head;
1573
- const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
1574
- let from = Math.min(cursor, oldCursor);
1575
- let to = Math.max(cursor, oldCursor);
1576
- tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
1577
- from = Math.min(from, fromB);
1578
- to = Math.max(to, toB);
1579
- });
1580
- from = tr.state.doc.lineAt(from).from;
1581
- to = tr.state.doc.lineAt(to).to;
1582
- return value.map(tr.changes).update({
1583
- filterFrom: from,
1584
- filterTo: to,
1585
- filter: () => false,
1586
- add: buildDecorations2(from, to, tr.state)
1587
- });
1588
- },
1589
- provide: (field) => EditorView8.decorations.from(field)
1590
- });
1591
- };
1592
- var buildDecorations2 = (from, to, state) => {
1593
- const decorations = [];
1594
- const cursor = state.selection.main.head;
1595
- syntaxTree2(state).iterate({
1596
- enter: (node) => {
1597
- if (node.name === "Image") {
1598
- const urlNode = node.node.getChild("URL");
1599
- if (urlNode) {
1600
- const hide = state.readOnly || cursor < node.from || cursor > node.to;
1601
- const url = state.sliceDoc(urlNode.from, urlNode.to);
1602
- decorations.push(Decoration5.replace({
1603
- block: true,
1604
- widget: new ImageWidget(url)
1605
- }).range(hide ? node.from : node.to, node.to));
1606
- }
1607
- }
1608
- },
1609
- from,
1610
- to
1611
- });
1612
- return decorations;
1415
+ // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
1416
+ import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
1417
+ import { history as history2, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
1418
+ import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
1419
+ import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
1420
+ import { languages } from "@codemirror/language-data";
1421
+ import { searchKeymap } from "@codemirror/search";
1422
+ import { EditorState } from "@codemirror/state";
1423
+ import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
1424
+ import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView7, highlightActiveLine as highlightActiveLine2, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
1425
+
1426
+ // packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
1427
+ import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
1428
+ import { HighlightStyle } from "@codemirror/language";
1429
+ import { tags, styleTags, Tag } from "@lezer/highlight";
1430
+ import { Table } from "@lezer/markdown";
1431
+ var markdownTags = {
1432
+ Blockquote: Tag.define(),
1433
+ CodeMark: Tag.define(),
1434
+ CodeText: Tag.define(),
1435
+ EmphasisMark: Tag.define(),
1436
+ HeaderMark: Tag.define(),
1437
+ InlineCode: Tag.define(),
1438
+ LinkLabel: Tag.define(),
1439
+ LinkReference: Tag.define(),
1440
+ ListMark: Tag.define(),
1441
+ QuoteMark: Tag.define(),
1442
+ URL: Tag.define(),
1443
+ // Custom.
1444
+ TableCell: Tag.define()
1613
1445
  };
1614
- var ImageWidget = class extends WidgetType3 {
1615
- constructor(_url) {
1616
- super();
1617
- this._url = _url;
1446
+ Table.defineNodes?.forEach((node) => {
1447
+ switch (node?.name) {
1448
+ case "TableCell": {
1449
+ node.style = markdownTags.TableCell;
1450
+ break;
1451
+ }
1618
1452
  }
1619
- eq(other) {
1620
- return this._url === other._url;
1621
- }
1622
- toDOM(view) {
1623
- const img = document.createElement("img");
1624
- img.setAttribute("src", this._url);
1625
- img.setAttribute("class", "cm-image");
1626
- img.onload = () => img.classList.add("cm-loaded-image");
1627
- return img;
1628
- }
1629
- };
1630
-
1631
- // packages/ui/react-ui-editor/src/extensions/link.ts
1632
- import { syntaxTree as syntaxTree3 } from "@codemirror/language";
1633
- import { RangeSetBuilder as RangeSetBuilder2 } from "@codemirror/state";
1634
- import { hoverTooltip as hoverTooltip2, Decoration as Decoration6, ViewPlugin as ViewPlugin5, WidgetType as WidgetType4 } from "@codemirror/view";
1635
- import { tooltipContent } from "@dxos/react-ui-theme";
1636
- var link = (options = {}) => {
1637
- const extensions = [
1638
- ViewPlugin5.fromClass(class {
1639
- constructor(view) {
1640
- this.decorations = buildDecorations3(view, options);
1641
- }
1642
- update(update2) {
1643
- if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
1644
- this.decorations = buildDecorations3(update2.view, options);
1645
- }
1646
- }
1647
- }, {
1648
- decorations: (v) => v.decorations
1649
- })
1650
- ];
1651
- if (options.onHover) {
1652
- extensions.push(
1653
- // https://codemirror.net/examples/tooltip
1654
- // https://codemirror.net/docs/ref/#view.hoverTooltip
1655
- // https://github.com/codemirror/view/blob/main/src/tooltip.ts
1656
- hoverTooltip2((view, pos, side) => {
1657
- const syntax = syntaxTree3(view.state).resolveInner(pos, side);
1658
- let link2 = null;
1659
- for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
1660
- link2 = node.name === "Link" ? node : null;
1661
- }
1662
- const url = link2 && link2.getChild("URL");
1663
- if (!url || !link2) {
1664
- return null;
1665
- }
1666
- const urlText = view.state.sliceDoc(url.from, url.to);
1667
- return {
1668
- pos: link2.from,
1669
- end: link2.to,
1670
- above: true,
1671
- create: () => {
1672
- const el = document.createElement("div");
1673
- el.className = tooltipContent({}, "pli-2 plb-1");
1674
- options.onHover(el, urlText);
1675
- return {
1676
- dom: el,
1677
- offset: {
1678
- x: 0,
1679
- y: 4
1680
- }
1681
- };
1682
- }
1683
- };
1684
- })
1685
- );
1686
- }
1687
- return extensions;
1688
- };
1689
- var LinkButton = class extends WidgetType4 {
1690
- constructor(_url, _onAttach) {
1691
- super();
1692
- this._url = _url;
1693
- this._onAttach = _onAttach;
1694
- }
1695
- eq(other) {
1696
- return this._url === other._url;
1697
- }
1698
- toDOM(view) {
1699
- const el = document.createElement("span");
1700
- this._onAttach(el, this._url);
1701
- return el;
1702
- }
1703
- };
1704
- var LinkText = class extends WidgetType4 {
1705
- constructor(_text, _url) {
1706
- super();
1707
- this._text = _text;
1708
- this._url = _url;
1709
- }
1710
- eq(other) {
1711
- return this._url === other._url;
1712
- }
1713
- toDOM(view) {
1714
- const link2 = document.createElement("a");
1715
- link2.setAttribute("class", "cm-link");
1716
- link2.textContent = this._text;
1717
- if (this._url) {
1718
- link2.setAttribute("rel", "noreferrer");
1719
- link2.setAttribute("target", "_blank");
1720
- link2.href = this._url;
1721
- } else {
1722
- link2.onclick = () => {
1723
- view.dispatch({
1724
- selection: {
1725
- anchor: view.posAtDOM(link2)
1726
- }
1727
- });
1728
- };
1729
- }
1730
- return link2;
1731
- }
1732
- };
1733
- var buildDecorations3 = (view, options) => {
1734
- const builder = new RangeSetBuilder2();
1735
- const { state } = view;
1736
- const cursor = state.selection.main.head;
1737
- for (const { from, to } of view.visibleRanges) {
1738
- syntaxTree3(state).iterate({
1739
- enter: (node) => {
1740
- if (node.name === "Link") {
1741
- const marks2 = node.node.getChildren("LinkMark");
1742
- const text = marks2.length >= 2 ? state.sliceDoc(marks2[0].to, marks2[1].from) : "";
1743
- const urlNode = node.node.getChild("URL");
1744
- const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
1745
- if (!url) {
1746
- return false;
1747
- }
1748
- if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
1749
- builder.add(node.from, node.to, Decoration6.replace({
1750
- widget: new LinkText(text, options.link ? url : void 0)
1751
- }));
1752
- }
1753
- if (options.onRender) {
1754
- builder.add(node.to, node.to, Decoration6.replace({
1755
- widget: new LinkButton(url, options.onRender)
1756
- }));
1757
- }
1758
- return false;
1759
- }
1760
- },
1761
- from,
1762
- to
1763
- });
1764
- }
1765
- return builder.finish();
1766
- };
1767
-
1768
- // packages/ui/react-ui-editor/src/extensions/listener.ts
1769
- import { EditorView as EditorView9 } from "@codemirror/view";
1770
- var listener = ({ onFocus, onChange }) => {
1771
- const extensions = [];
1772
- onFocus && extensions.push(EditorView9.focusChangeEffect.of((_, focused) => {
1773
- onFocus(focused);
1774
- return null;
1775
- }));
1776
- onChange && extensions.push(EditorView9.updateListener.of((update2) => {
1777
- onChange(update2.state.doc.toString());
1778
- }));
1779
- return extensions;
1780
- };
1781
-
1782
- // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
1783
- import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
1784
- import { history as history2, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
1785
- import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
1786
- import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
1787
- import { languages } from "@codemirror/language-data";
1788
- import { searchKeymap } from "@codemirror/search";
1789
- import { EditorState } from "@codemirror/state";
1790
- import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
1791
- import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView10, highlightActiveLine as highlightActiveLine2, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
1792
-
1793
- // packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
1794
- import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
1795
- import { HighlightStyle } from "@codemirror/language";
1796
- import { tags, styleTags, Tag } from "@lezer/highlight";
1797
- import { Table } from "@lezer/markdown";
1798
- var markdownTags = {
1799
- Blockquote: Tag.define(),
1800
- CodeMark: Tag.define(),
1801
- CodeText: Tag.define(),
1802
- EmphasisMark: Tag.define(),
1803
- HeaderMark: Tag.define(),
1804
- InlineCode: Tag.define(),
1805
- LinkLabel: Tag.define(),
1806
- LinkReference: Tag.define(),
1807
- ListMark: Tag.define(),
1808
- QuoteMark: Tag.define(),
1809
- URL: Tag.define(),
1810
- // Custom.
1811
- TableCell: Tag.define()
1812
- };
1813
- Table.defineNodes?.forEach((node) => {
1814
- switch (node?.name) {
1815
- case "TableCell": {
1816
- node.style = markdownTags.TableCell;
1817
- break;
1818
- }
1819
- }
1820
- });
1821
- var markdownTagsExtensions = [
1822
- Table,
1823
- {
1824
- props: [
1825
- styleTags(markdownTags)
1826
- ]
1453
+ });
1454
+ var markdownTagsExtensions = [
1455
+ Table,
1456
+ {
1457
+ props: [
1458
+ styleTags(markdownTags)
1459
+ ]
1827
1460
  }
1828
1461
  ];
1829
1462
  var markdownHighlightStyle = (readonly) => {
@@ -1983,7 +1616,7 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
1983
1616
  return [
1984
1617
  EditorState.allowMultipleSelections.of(true),
1985
1618
  EditorState.tabSize.of(2),
1986
- EditorView10.lineWrapping,
1619
+ EditorView7.lineWrapping,
1987
1620
  // https://github.com/codemirror/basic-setup
1988
1621
  bracketMatching2(),
1989
1622
  closeBrackets2(),
@@ -2031,44 +1664,396 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
2031
1664
  ];
2032
1665
  };
2033
1666
 
2034
- // packages/ui/react-ui-editor/src/extensions/mention.ts
2035
- import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
2036
- var mention = ({ onSearch }) => {
2037
- return autocompletion2({
2038
- // TODO(burdon): Not working.
2039
- activateOnTyping: true,
2040
- // activateOnTypingDelay: 100,
2041
- // selectOnOpen: true,
2042
- closeOnBlur: false,
2043
- // defaultKeymap: false,
2044
- icons: false,
2045
- override: [
2046
- (context) => {
2047
- console.log(context);
2048
- const match = context.matchBefore(/@(\w+)?/);
2049
- if (!match || match.from === match.to && !context.explicit) {
2050
- return null;
1667
+ // packages/ui/react-ui-editor/src/extensions/markdown/code.ts
1668
+ import { ViewPlugin as ViewPlugin3, EditorView as EditorView8, Decoration as Decoration3 } from "@codemirror/view";
1669
+ import { mx as mx2 } from "@dxos/react-ui-theme";
1670
+ var CODE_REGEX = /```[\s\S]*?```/gs;
1671
+ var styles3 = EditorView8.baseTheme({
1672
+ "& .cm-codeblock": {
1673
+ fontFamily: getToken("fontFamily.mono", []).join(",")
1674
+ },
1675
+ '&light [aria-readonly="true"] .cm-codeblock': {
1676
+ background: getToken("extend.colors.neutral.50")
1677
+ },
1678
+ '&dark [aria-readonly="true"] .cm-codeblock': {
1679
+ background: getToken("extend.colors.neutral.850")
1680
+ },
1681
+ '& [aria-readonly="true"] .cm-codeblock': {
1682
+ display: "block",
1683
+ paddingInline: "4px !important"
1684
+ },
1685
+ '& [aria-readonly="true"] .cm-codeblock-first': {
1686
+ paddingTop: "4px !important",
1687
+ borderTopLeftRadius: "4px",
1688
+ borderTopRightRadius: "4px"
1689
+ },
1690
+ '& [aria-readonly="true"] .cm-codeblock-last': {
1691
+ paddingBottom: "4px !important",
1692
+ borderBottomLeftRadius: "4px",
1693
+ borderBottomRightRadius: "4px"
1694
+ }
1695
+ });
1696
+ var getLineRange = (lines, from, to) => {
1697
+ const start = lines.findIndex((line) => line.from >= from);
1698
+ const end = lines.findIndex((line) => line.to >= to);
1699
+ return [
1700
+ start,
1701
+ end
1702
+ ];
1703
+ };
1704
+ var code2 = () => {
1705
+ const buildDecorations6 = (view) => {
1706
+ const decorations = [];
1707
+ const text = view.state.doc.sliceString(0);
1708
+ const matches = text.matchAll(CODE_REGEX);
1709
+ const blocks = view.viewportLineBlocks;
1710
+ for (const match of matches) {
1711
+ const range = getLineRange(blocks, match.index, match.index + match[0].length);
1712
+ for (let i = range[0]; i <= range[1]; i++) {
1713
+ const block = blocks[i];
1714
+ decorations.push(Decoration3.line({
1715
+ class: mx2("cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
1716
+ }).range(block.from));
1717
+ }
1718
+ }
1719
+ return Decoration3.set(decorations);
1720
+ };
1721
+ return [
1722
+ ViewPlugin3.fromClass(class {
1723
+ constructor(view) {
1724
+ this.hasFocus = false;
1725
+ this.decorations = buildDecorations6(view);
1726
+ }
1727
+ update(update2) {
1728
+ if (
1729
+ // TODO(burdon): Generalize for other extensions.
1730
+ this.hasFocus !== update2.view.hasFocus || update2.startState.readOnly !== update2.view.state.readOnly || update2.docChanged || update2.viewportChanged
1731
+ ) {
1732
+ this.hasFocus = update2.view.hasFocus;
1733
+ this.decorations = buildDecorations6(update2.view);
2051
1734
  }
2052
- return {
2053
- from: match.from,
2054
- options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
2055
- label: `@${value}`
2056
- }))
1735
+ }
1736
+ }, {
1737
+ decorations: (value) => value.decorations
1738
+ }),
1739
+ styles3
1740
+ ];
1741
+ };
1742
+
1743
+ // packages/ui/react-ui-editor/src/extensions/markdown/heading.ts
1744
+ import { syntaxTree } from "@codemirror/language";
1745
+ import { RangeSetBuilder } from "@codemirror/state";
1746
+ import { Decoration as Decoration4, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
1747
+ var buildDecorations = (view) => {
1748
+ const builder = new RangeSetBuilder();
1749
+ const { state } = view;
1750
+ const cursor = state.selection.main.head;
1751
+ for (const { from, to } of view.visibleRanges) {
1752
+ syntaxTree(state).iterate({
1753
+ enter: (node) => {
1754
+ switch (node.name) {
1755
+ case "ATXHeading1":
1756
+ case "ATXHeading2":
1757
+ case "ATXHeading3":
1758
+ case "ATXHeading4":
1759
+ case "ATXHeading5":
1760
+ case "ATXHeading6": {
1761
+ const mark2 = node.node.getChild("HeaderMark");
1762
+ if (mark2 && (cursor < node.from || cursor > node.to)) {
1763
+ builder.add(mark2.from, mark2.to + 1, Decoration4.replace({}));
1764
+ }
1765
+ }
1766
+ }
1767
+ },
1768
+ from,
1769
+ to
1770
+ });
1771
+ }
1772
+ return builder.finish();
1773
+ };
1774
+ var heading2 = () => {
1775
+ return [
1776
+ ViewPlugin4.fromClass(class {
1777
+ constructor(view) {
1778
+ this.decorations = buildDecorations(view);
1779
+ }
1780
+ update(update2) {
1781
+ this.decorations = buildDecorations(update2.view);
1782
+ }
1783
+ }, {
1784
+ decorations: (v) => v.decorations
1785
+ })
1786
+ ];
1787
+ };
1788
+
1789
+ // packages/ui/react-ui-editor/src/extensions/markdown/hr.ts
1790
+ import { syntaxTree as syntaxTree2 } from "@codemirror/language";
1791
+ import { RangeSetBuilder as RangeSetBuilder2 } from "@codemirror/state";
1792
+ import { Decoration as Decoration5, EditorView as EditorView9, ViewPlugin as ViewPlugin5, WidgetType as WidgetType2 } from "@codemirror/view";
1793
+ var styles4 = EditorView9.baseTheme({
1794
+ "& .cm-hr": {
1795
+ // Note that block-level decorations should not have vertical margins,
1796
+ borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
1797
+ }
1798
+ });
1799
+ var HorizontalRuleWidget = class extends WidgetType2 {
1800
+ toDOM() {
1801
+ const el = document.createElement("div");
1802
+ el.className = "cm-hr";
1803
+ return el;
1804
+ }
1805
+ };
1806
+ var decoration = Decoration5.replace({
1807
+ widget: new HorizontalRuleWidget()
1808
+ });
1809
+ var buildDecorations2 = (view) => {
1810
+ const builder = new RangeSetBuilder2();
1811
+ const { state } = view;
1812
+ const cursor = state.selection.main.head;
1813
+ for (const { from, to } of view.visibleRanges) {
1814
+ syntaxTree2(state).iterate({
1815
+ enter: (node) => {
1816
+ if (node.name === "HorizontalRule") {
1817
+ if (cursor <= node.from || cursor >= node.to) {
1818
+ builder.add(node.from, node.to, decoration);
1819
+ }
1820
+ }
1821
+ },
1822
+ from,
1823
+ to
1824
+ });
1825
+ }
1826
+ return builder.finish();
1827
+ };
1828
+ var hr = () => {
1829
+ return [
1830
+ styles4,
1831
+ ViewPlugin5.fromClass(class {
1832
+ constructor(view) {
1833
+ this.decorations = buildDecorations2(view);
1834
+ }
1835
+ update(update2) {
1836
+ this.decorations = buildDecorations2(update2.view);
1837
+ }
1838
+ }, {
1839
+ decorations: (v) => v.decorations
1840
+ })
1841
+ ];
1842
+ };
1843
+
1844
+ // packages/ui/react-ui-editor/src/extensions/markdown/image.ts
1845
+ import { syntaxTree as syntaxTree3 } from "@codemirror/language";
1846
+ import { StateField as StateField3 } from "@codemirror/state";
1847
+ import { Decoration as Decoration6, EditorView as EditorView10, WidgetType as WidgetType3 } from "@codemirror/view";
1848
+ var image = (options = {}) => {
1849
+ return StateField3.define({
1850
+ create: (state) => {
1851
+ return Decoration6.set(buildDecorations3(0, state.doc.length, state));
1852
+ },
1853
+ update: (value, tr) => {
1854
+ if (!tr.docChanged && !tr.selection) {
1855
+ return value;
1856
+ }
1857
+ const cursor = tr.state.selection.main.head;
1858
+ const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
1859
+ let from = Math.min(cursor, oldCursor);
1860
+ let to = Math.max(cursor, oldCursor);
1861
+ tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
1862
+ from = Math.min(from, fromB);
1863
+ to = Math.max(to, toB);
1864
+ });
1865
+ from = tr.state.doc.lineAt(from).from;
1866
+ to = tr.state.doc.lineAt(to).to;
1867
+ return value.map(tr.changes).update({
1868
+ filterFrom: from,
1869
+ filterTo: to,
1870
+ filter: () => false,
1871
+ add: buildDecorations3(from, to, tr.state)
1872
+ });
1873
+ },
1874
+ provide: (field) => EditorView10.decorations.from(field)
1875
+ });
1876
+ };
1877
+ var buildDecorations3 = (from, to, state) => {
1878
+ const decorations = [];
1879
+ const cursor = state.selection.main.head;
1880
+ syntaxTree3(state).iterate({
1881
+ enter: (node) => {
1882
+ if (node.name === "Image") {
1883
+ const urlNode = node.node.getChild("URL");
1884
+ if (urlNode) {
1885
+ const hide = state.readOnly || cursor < node.from || cursor > node.to;
1886
+ const url = state.sliceDoc(urlNode.from, urlNode.to);
1887
+ decorations.push(Decoration6.replace({
1888
+ block: true,
1889
+ widget: new ImageWidget(url)
1890
+ }).range(hide ? node.from : node.to, node.to));
1891
+ }
1892
+ }
1893
+ },
1894
+ from,
1895
+ to
1896
+ });
1897
+ return decorations;
1898
+ };
1899
+ var ImageWidget = class extends WidgetType3 {
1900
+ constructor(_url) {
1901
+ super();
1902
+ this._url = _url;
1903
+ }
1904
+ eq(other) {
1905
+ return this._url === other._url;
1906
+ }
1907
+ toDOM(view) {
1908
+ const img = document.createElement("img");
1909
+ img.setAttribute("src", this._url);
1910
+ img.setAttribute("class", "cm-image");
1911
+ img.onload = () => img.classList.add("cm-loaded-image");
1912
+ return img;
1913
+ }
1914
+ };
1915
+
1916
+ // packages/ui/react-ui-editor/src/extensions/markdown/link.ts
1917
+ import { syntaxTree as syntaxTree4 } from "@codemirror/language";
1918
+ import { RangeSetBuilder as RangeSetBuilder3 } from "@codemirror/state";
1919
+ import { hoverTooltip as hoverTooltip2, Decoration as Decoration7, ViewPlugin as ViewPlugin6, WidgetType as WidgetType4 } from "@codemirror/view";
1920
+ import { tooltipContent } from "@dxos/react-ui-theme";
1921
+ var link = (options = {}) => {
1922
+ const extensions = [
1923
+ ViewPlugin6.fromClass(class {
1924
+ constructor(view) {
1925
+ this.decorations = buildDecorations4(view, options);
1926
+ }
1927
+ update(update2) {
1928
+ if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
1929
+ this.decorations = buildDecorations4(update2.view, options);
1930
+ }
1931
+ }
1932
+ }, {
1933
+ decorations: (v) => v.decorations
1934
+ })
1935
+ ];
1936
+ if (options.onHover) {
1937
+ extensions.push(
1938
+ // https://codemirror.net/examples/tooltip
1939
+ // https://codemirror.net/docs/ref/#view.hoverTooltip
1940
+ // https://github.com/codemirror/view/blob/main/src/tooltip.ts
1941
+ hoverTooltip2((view, pos, side) => {
1942
+ const syntax = syntaxTree4(view.state).resolveInner(pos, side);
1943
+ let link2 = null;
1944
+ for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
1945
+ link2 = node.name === "Link" ? node : null;
1946
+ }
1947
+ const url = link2 && link2.getChild("URL");
1948
+ if (!url || !link2) {
1949
+ return null;
1950
+ }
1951
+ const urlText = view.state.sliceDoc(url.from, url.to);
1952
+ return {
1953
+ pos: link2.from,
1954
+ end: link2.to,
1955
+ above: true,
1956
+ create: () => {
1957
+ const el = document.createElement("div");
1958
+ el.className = tooltipContent({}, "pli-2 plb-1");
1959
+ options.onHover(el, urlText);
1960
+ return {
1961
+ dom: el,
1962
+ offset: {
1963
+ x: 0,
1964
+ y: 4
1965
+ }
1966
+ };
1967
+ }
2057
1968
  };
2058
- }
2059
- ]
2060
- });
1969
+ })
1970
+ );
1971
+ }
1972
+ return extensions;
2061
1973
  };
2062
-
2063
- // packages/ui/react-ui-editor/src/extensions/outliner.ts
2064
- var outliner = (options = {}) => {
2065
- return [];
1974
+ var LinkButton = class extends WidgetType4 {
1975
+ constructor(_url, _onAttach) {
1976
+ super();
1977
+ this._url = _url;
1978
+ this._onAttach = _onAttach;
1979
+ }
1980
+ eq(other) {
1981
+ return this._url === other._url;
1982
+ }
1983
+ toDOM(view) {
1984
+ const el = document.createElement("span");
1985
+ this._onAttach(el, this._url);
1986
+ return el;
1987
+ }
1988
+ };
1989
+ var LinkText = class extends WidgetType4 {
1990
+ constructor(_text, _url) {
1991
+ super();
1992
+ this._text = _text;
1993
+ this._url = _url;
1994
+ }
1995
+ eq(other) {
1996
+ return this._url === other._url;
1997
+ }
1998
+ toDOM(view) {
1999
+ const link2 = document.createElement("a");
2000
+ link2.setAttribute("class", "cm-link");
2001
+ link2.textContent = this._text;
2002
+ if (this._url) {
2003
+ link2.setAttribute("rel", "noreferrer");
2004
+ link2.setAttribute("target", "_blank");
2005
+ link2.href = this._url;
2006
+ } else {
2007
+ link2.onclick = () => {
2008
+ view.dispatch({
2009
+ selection: {
2010
+ anchor: view.posAtDOM(link2)
2011
+ }
2012
+ });
2013
+ };
2014
+ }
2015
+ return link2;
2016
+ }
2017
+ };
2018
+ var buildDecorations4 = (view, options) => {
2019
+ const builder = new RangeSetBuilder3();
2020
+ const { state } = view;
2021
+ const cursor = state.selection.main.head;
2022
+ for (const { from, to } of view.visibleRanges) {
2023
+ syntaxTree4(state).iterate({
2024
+ enter: (node) => {
2025
+ if (node.name === "Link") {
2026
+ const marks2 = node.node.getChildren("LinkMark");
2027
+ const text = marks2.length >= 2 ? state.sliceDoc(marks2[0].to, marks2[1].from) : "";
2028
+ const urlNode = node.node.getChild("URL");
2029
+ const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
2030
+ if (!url) {
2031
+ return false;
2032
+ }
2033
+ if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
2034
+ builder.add(node.from, node.to, Decoration7.replace({
2035
+ widget: new LinkText(text, options.link ? url : void 0)
2036
+ }));
2037
+ }
2038
+ if (options.onRender) {
2039
+ builder.add(node.to, node.to, Decoration7.replace({
2040
+ widget: new LinkButton(url, options.onRender)
2041
+ }));
2042
+ }
2043
+ return false;
2044
+ }
2045
+ },
2046
+ from,
2047
+ to
2048
+ });
2049
+ }
2050
+ return builder.finish();
2066
2051
  };
2067
2052
 
2068
- // packages/ui/react-ui-editor/src/extensions/table.ts
2069
- import { syntaxTree as syntaxTree4 } from "@codemirror/language";
2070
- import { RangeSetBuilder as RangeSetBuilder3, StateField as StateField4 } from "@codemirror/state";
2071
- import { Decoration as Decoration7, EditorView as EditorView11, WidgetType as WidgetType5 } from "@codemirror/view";
2053
+ // packages/ui/react-ui-editor/src/extensions/markdown/table.ts
2054
+ import { syntaxTree as syntaxTree5 } from "@codemirror/language";
2055
+ import { RangeSetBuilder as RangeSetBuilder4, StateField as StateField4 } from "@codemirror/state";
2056
+ import { Decoration as Decoration8, EditorView as EditorView11, WidgetType as WidgetType5 } from "@codemirror/view";
2072
2057
  var table = (options = {}) => {
2073
2058
  return StateField4.define({
2074
2059
  create: (state) => update(state, options),
@@ -2077,7 +2062,7 @@ var table = (options = {}) => {
2077
2062
  });
2078
2063
  };
2079
2064
  var update = (state, options) => {
2080
- const builder = new RangeSetBuilder3();
2065
+ const builder = new RangeSetBuilder4();
2081
2066
  const cursor = state.selection.main.head;
2082
2067
  const tables = [];
2083
2068
  const getTable = () => tables[tables.length - 1];
@@ -2085,7 +2070,7 @@ var update = (state, options) => {
2085
2070
  const table2 = getTable();
2086
2071
  return table2.rows?.[table2.rows.length - 1];
2087
2072
  };
2088
- syntaxTree4(state).iterate({
2073
+ syntaxTree5(state).iterate({
2089
2074
  enter: (node) => {
2090
2075
  switch (node.name) {
2091
2076
  case "Table": {
@@ -2117,10 +2102,10 @@ var update = (state, options) => {
2117
2102
  });
2118
2103
  tables.forEach((table2) => {
2119
2104
  const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
2120
- hide && builder.add(table2.from, table2.to, Decoration7.replace({
2105
+ hide && builder.add(table2.from, table2.to, Decoration8.replace({
2121
2106
  widget: new TableWidget(table2)
2122
2107
  }));
2123
- builder.add(table2.from, table2.to, Decoration7.mark({
2108
+ builder.add(table2.from, table2.to, Decoration8.mark({
2124
2109
  class: "cm-table"
2125
2110
  }));
2126
2111
  });
@@ -2163,10 +2148,10 @@ var TableWidget = class extends WidgetType5 {
2163
2148
  }
2164
2149
  };
2165
2150
 
2166
- // packages/ui/react-ui-editor/src/extensions/tasklist.ts
2167
- import { syntaxTree as syntaxTree5 } from "@codemirror/language";
2168
- import { RangeSetBuilder as RangeSetBuilder4 } from "@codemirror/state";
2169
- import { EditorView as EditorView12, Decoration as Decoration8, WidgetType as WidgetType6, ViewPlugin as ViewPlugin6 } from "@codemirror/view";
2151
+ // packages/ui/react-ui-editor/src/extensions/markdown/tasklist.ts
2152
+ import { syntaxTree as syntaxTree6 } from "@codemirror/language";
2153
+ import { RangeSetBuilder as RangeSetBuilder5 } from "@codemirror/state";
2154
+ import { EditorView as EditorView12, Decoration as Decoration9, WidgetType as WidgetType6, ViewPlugin as ViewPlugin7 } from "@codemirror/view";
2170
2155
  var styles5 = EditorView12.baseTheme({
2171
2156
  "& .cm-task": {
2172
2157
  color: getToken("extend.colors.blue.500")
@@ -2213,23 +2198,23 @@ var CheckboxWidget = class extends WidgetType6 {
2213
2198
  return false;
2214
2199
  }
2215
2200
  };
2216
- var checkedDecoration = Decoration8.replace({
2201
+ var checkedDecoration = Decoration9.replace({
2217
2202
  widget: new CheckboxWidget(true)
2218
2203
  });
2219
- var uncheckedDecoration = Decoration8.replace({
2204
+ var uncheckedDecoration = Decoration9.replace({
2220
2205
  widget: new CheckboxWidget(false)
2221
2206
  });
2222
- var buildDecorations4 = (view) => {
2223
- const builder = new RangeSetBuilder4();
2207
+ var buildDecorations5 = (view) => {
2208
+ const builder = new RangeSetBuilder5();
2224
2209
  const { state } = view;
2225
2210
  const cursor = state.selection.main.head;
2226
2211
  for (const { from, to } of view.visibleRanges) {
2227
- syntaxTree5(state).iterate({
2212
+ syntaxTree6(state).iterate({
2228
2213
  enter: (node) => {
2229
2214
  if (node.name === "TaskMarker") {
2230
2215
  if (cursor < node.from || cursor > node.to) {
2231
2216
  const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
2232
- builder.add(node.from - 2, node.from - 1, Decoration8.mark({
2217
+ builder.add(node.from - 2, node.from - 1, Decoration9.mark({
2233
2218
  class: "cm-task"
2234
2219
  }));
2235
2220
  builder.add(node.from, node.to, checked ? checkedDecoration : uncheckedDecoration);
@@ -2244,13 +2229,13 @@ var buildDecorations4 = (view) => {
2244
2229
  };
2245
2230
  var tasklist = (options = {}) => {
2246
2231
  return [
2247
- ViewPlugin6.fromClass(class {
2232
+ ViewPlugin7.fromClass(class {
2248
2233
  constructor(view) {
2249
- this.decorations = buildDecorations4(view);
2234
+ this.decorations = buildDecorations5(view);
2250
2235
  }
2251
2236
  update(update2) {
2252
2237
  if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
2253
- this.decorations = buildDecorations4(update2.view);
2238
+ this.decorations = buildDecorations5(update2.view);
2254
2239
  }
2255
2240
  }
2256
2241
  }, {
@@ -2260,6 +2245,40 @@ var tasklist = (options = {}) => {
2260
2245
  ];
2261
2246
  };
2262
2247
 
2248
+ // packages/ui/react-ui-editor/src/extensions/mention.ts
2249
+ import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
2250
+ var mention = ({ onSearch }) => {
2251
+ return autocompletion2({
2252
+ // TODO(burdon): Not working.
2253
+ activateOnTyping: true,
2254
+ // activateOnTypingDelay: 100,
2255
+ // selectOnOpen: true,
2256
+ closeOnBlur: false,
2257
+ // defaultKeymap: false,
2258
+ icons: false,
2259
+ override: [
2260
+ (context) => {
2261
+ console.log(context);
2262
+ const match = context.matchBefore(/@(\w+)?/);
2263
+ if (!match || match.from === match.to && !context.explicit) {
2264
+ return null;
2265
+ }
2266
+ return {
2267
+ from: match.from,
2268
+ options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
2269
+ label: `@${value}`
2270
+ }))
2271
+ };
2272
+ }
2273
+ ]
2274
+ });
2275
+ };
2276
+
2277
+ // packages/ui/react-ui-editor/src/extensions/outliner.ts
2278
+ var outliner = (options = {}) => {
2279
+ return [];
2280
+ };
2281
+
2263
2282
  // packages/ui/react-ui-editor/src/extensions/typewriter.ts
2264
2283
  import { keymap as keymap5 } from "@codemirror/view";
2265
2284
  var defaultItems = [
@@ -2317,27 +2336,6 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
2317
2336
  ];
2318
2337
  };
2319
2338
 
2320
- // packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
2321
- import { yCollab } from "y-codemirror.next";
2322
-
2323
- // packages/ui/react-ui-editor/src/extensions/yjs/cursor.ts
2324
- import * as Y from "yjs";
2325
- import { arrayToString, stringToArray } from "@dxos/util";
2326
- var cursorConverter2 = (text) => ({
2327
- toCursor: (index, assoc) => {
2328
- return arrayToString(Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text, index, assoc)));
2329
- },
2330
- fromCursor: (cursor) => {
2331
- return Y.createAbsolutePositionFromRelativePosition(Y.decodeRelativePosition(stringToArray(cursor)), text.doc)?.index ?? 0;
2332
- }
2333
- });
2334
-
2335
- // packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
2336
- var yjs = (content, awareness2) => [
2337
- Cursor.converter.of(cursorConverter2(content)),
2338
- yCollab(content, awareness2)
2339
- ];
2340
-
2341
2339
  // packages/ui/react-ui-editor/src/themes/default.ts
2342
2340
  import get3 from "lodash.get";
2343
2341
  var defaultTheme = {
@@ -2580,26 +2578,25 @@ var EditorModes = [
2580
2578
  "default",
2581
2579
  "vim"
2582
2580
  ];
2583
- var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autofocus, scrollTo, selection, editorMode, theme, slots = defaultSlots, extensions = [], debug }, forwardedRef) => {
2581
+ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo, selection, editorMode, theme, slots = defaultSlots, extensions = [], debug }, forwardedRef) => {
2584
2582
  const tabsterDOMAttribute = useFocusableGroup({
2585
2583
  tabBehavior: "limited"
2586
2584
  });
2587
- const { themeMode } = useThemeContext2();
2585
+ const { themeMode } = useThemeContext();
2588
2586
  const rootRef = useRef(null);
2589
2587
  const [view, setView] = useState(null);
2590
2588
  useImperativeHandle(forwardedRef, () => view, [
2591
2589
  view
2592
2590
  ]);
2593
- useEffect3(() => {
2594
- if (autofocus) {
2591
+ useEffect2(() => {
2592
+ if (autoFocus) {
2595
2593
  view?.focus();
2596
2594
  }
2597
2595
  }, [
2598
2596
  view,
2599
- autofocus
2597
+ autoFocus
2600
2598
  ]);
2601
- useAwareness(model);
2602
- useEffect3(() => {
2599
+ useEffect2(() => {
2603
2600
  if (!model || !rootRef.current) {
2604
2601
  return;
2605
2602
  }
@@ -2611,7 +2608,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autofocus, s
2611
2608
  EditorView13.exceptionSink.of((err) => {
2612
2609
  log2.catch(err, void 0, {
2613
2610
  F: __dxlog_file5,
2614
- L: 126,
2611
+ L: 123,
2615
2612
  S: void 0,
2616
2613
  C: (f, a) => f(...a)
2617
2614
  });
@@ -2692,8 +2689,8 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autofocus, s
2692
2689
  ref: rootRef
2693
2690
  });
2694
2691
  });
2695
- var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, multiline, theme = textTheme, slots, extensions = [], ...props }, forwardedRef) => {
2696
- const { themeMode } = useThemeContext2();
2692
+ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, lineWrapping, theme = textTheme, slots, extensions = [], ...props }, forwardedRef) => {
2693
+ const { themeMode } = useThemeContext();
2697
2694
  const updatedSlots = defaultsDeep2({}, slots, defaultTextSlots);
2698
2695
  return /* @__PURE__ */ React.createElement(BaseTextEditor, {
2699
2696
  ref: forwardedRef,
@@ -2702,7 +2699,7 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholde
2702
2699
  basicBundle({
2703
2700
  themeMode,
2704
2701
  placeholder: placeholder3,
2705
- multiline
2702
+ lineWrapping
2706
2703
  }),
2707
2704
  ...extensions
2708
2705
  ],
@@ -2712,7 +2709,7 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholde
2712
2709
  });
2713
2710
  });
2714
2711
  var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, theme = markdownTheme, slots, extensions = [], ...props }, forwardedRef) => {
2715
- const { themeMode } = useThemeContext2();
2712
+ const { themeMode } = useThemeContext();
2716
2713
  const updatedSlots = defaultsDeep2({}, slots, defaultMarkdownSlots);
2717
2714
  return /* @__PURE__ */ React.createElement(BaseTextEditor, {
2718
2715
  ref: forwardedRef,
@@ -2733,7 +2730,7 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeh
2733
2730
  var defaultSlots = {
2734
2731
  root: {
2735
2732
  // TODO(burdon): Add focusRing by default/as property?
2736
- className: mx3("flex flex-col grow overflow-y-auto", inputSurface)
2733
+ className: mx3("flex flex-col grow overflow-y-auto", attentionSurface)
2737
2734
  },
2738
2735
  editor: {
2739
2736
  className: "h-full p-2"
@@ -2746,11 +2743,6 @@ var defaultMarkdownSlots = {
2746
2743
  ...defaultSlots
2747
2744
  };
2748
2745
 
2749
- // packages/ui/react-ui-editor/src/hooks/automerge.ts
2750
- import get4 from "lodash.get";
2751
- import { getRawDoc } from "@dxos/echo-schema";
2752
- import { isNotNullOrUndefined } from "@dxos/util";
2753
-
2754
2746
  // packages/ui/react-ui-editor/src/hooks/awareness-provider.ts
2755
2747
  import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
2756
2748
  import { Context as Context2 } from "@dxos/context";
@@ -2760,8 +2752,8 @@ var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src
2760
2752
  var DEBOUNCE_INTERVAL = 100;
2761
2753
  var SpaceAwarenessProvider = class {
2762
2754
  constructor(params) {
2763
- this.remoteStateChange = new Event2();
2764
2755
  this._remoteStates = /* @__PURE__ */ new Map();
2756
+ this.remoteStateChange = new Event2();
2765
2757
  this._space = params.space;
2766
2758
  this._channel = params.channel;
2767
2759
  this._peerId = params.peerId;
@@ -2778,7 +2770,7 @@ var SpaceAwarenessProvider = class {
2778
2770
  await sleep(DEBOUNCE_INTERVAL);
2779
2771
  }
2780
2772
  });
2781
- const unsubscribe = this._space.listen(this._channel, (message) => {
2773
+ this._ctx.onDispose(this._space.listen(this._channel, (message) => {
2782
2774
  switch (message.payload.kind) {
2783
2775
  case "query": {
2784
2776
  this._handleQueryMessage();
@@ -2789,8 +2781,7 @@ var SpaceAwarenessProvider = class {
2789
2781
  break;
2790
2782
  }
2791
2783
  }
2792
- });
2793
- this._ctx.onDispose(unsubscribe);
2784
+ }));
2794
2785
  void this._space.postMessage(this._channel, {
2795
2786
  kind: "query"
2796
2787
  }).catch((err) => {
@@ -2798,7 +2789,7 @@ var SpaceAwarenessProvider = class {
2798
2789
  err
2799
2790
  }, {
2800
2791
  F: __dxlog_file6,
2801
- L: 85,
2792
+ L: 89,
2802
2793
  S: this,
2803
2794
  C: (f, a) => f(...a)
2804
2795
  });
@@ -2809,10 +2800,13 @@ var SpaceAwarenessProvider = class {
2809
2800
  this._ctx = void 0;
2810
2801
  this._postTask = void 0;
2811
2802
  }
2803
+ getRemoteStates() {
2804
+ return Array.from(this._remoteStates.values());
2805
+ }
2812
2806
  update(position) {
2813
2807
  invariant4(this._postTask, void 0, {
2814
2808
  F: __dxlog_file6,
2815
- L: 96,
2809
+ L: 104,
2816
2810
  S: this,
2817
2811
  A: [
2818
2812
  "this._postTask",
@@ -2826,13 +2820,10 @@ var SpaceAwarenessProvider = class {
2826
2820
  };
2827
2821
  this._postTask.schedule();
2828
2822
  }
2829
- getRemoteStates() {
2830
- return Array.from(this._remoteStates.values());
2831
- }
2832
2823
  _handleQueryMessage() {
2833
2824
  invariant4(this._postTask, void 0, {
2834
2825
  F: __dxlog_file6,
2835
- L: 111,
2826
+ L: 115,
2836
2827
  S: this,
2837
2828
  A: [
2838
2829
  "this._postTask",
@@ -2844,7 +2835,7 @@ var SpaceAwarenessProvider = class {
2844
2835
  _handlePostMessage(message) {
2845
2836
  invariant4(message.kind === "post", void 0, {
2846
2837
  F: __dxlog_file6,
2847
- L: 116,
2838
+ L: 120,
2848
2839
  S: this,
2849
2840
  A: [
2850
2841
  "message.kind === 'post'",
@@ -2863,8 +2854,47 @@ var modelState = StateField5.define({
2863
2854
  update: (model) => model
2864
2855
  });
2865
2856
 
2866
- // packages/ui/react-ui-editor/src/hooks/automerge.ts
2867
- var createAutomergeModel = ({ space, identity, text }) => {
2857
+ // packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
2858
+ import { useState as useState2 } from "react";
2859
+ var useTextEditor = () => {
2860
+ const [view, setView] = useState2(null);
2861
+ return [
2862
+ (ref) => {
2863
+ setView(ref);
2864
+ },
2865
+ view
2866
+ ];
2867
+ };
2868
+
2869
+ // packages/ui/react-ui-editor/src/hooks/useTextModel.ts
2870
+ import get4 from "lodash.get";
2871
+ import { useEffect as useEffect3, useState as useState3 } from "react";
2872
+ import { generateName } from "@dxos/display-name";
2873
+ import { getRawDoc } from "@dxos/echo-schema";
2874
+ import { invariant as invariant5 } from "@dxos/invariant";
2875
+ import { isAutomergeObject } from "@dxos/react-client/echo";
2876
+ import { isNotNullOrUndefined } from "@dxos/util";
2877
+ var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
2878
+ var useTextModel = (props) => {
2879
+ const { identity, space, text } = props;
2880
+ const [model, setModel] = useState3();
2881
+ useEffect3(() => setModel(createModel(props)), [
2882
+ identity,
2883
+ space,
2884
+ text
2885
+ ]);
2886
+ return model;
2887
+ };
2888
+ var createModel = ({ space, identity, text }) => {
2889
+ invariant5(isAutomergeObject(text), void 0, {
2890
+ F: __dxlog_file7,
2891
+ L: 35,
2892
+ S: void 0,
2893
+ A: [
2894
+ "isAutomergeObject(text)",
2895
+ ""
2896
+ ]
2897
+ });
2868
2898
  const obj = text;
2869
2899
  const doc = getRawDoc(obj, [
2870
2900
  obj.field
@@ -2873,7 +2903,7 @@ var createAutomergeModel = ({ space, identity, text }) => {
2873
2903
  space,
2874
2904
  channel: `automerge.awareness.${obj.id}`,
2875
2905
  info: {
2876
- displayName: identity?.profile?.displayName ?? "",
2906
+ displayName: identity ? identity.profile?.displayName ?? generateName(identity.identityKey.toHex()) : void 0,
2877
2907
  color: cursorColor.color,
2878
2908
  lightColor: cursorColor.light
2879
2909
  },
@@ -2883,7 +2913,6 @@ var createAutomergeModel = ({ space, identity, text }) => {
2883
2913
  id: obj.id,
2884
2914
  content: doc,
2885
2915
  text: () => get4(doc.handle.docSync(), doc.path),
2886
- // TODO(burdon): https://automerge.org/automerge/api-docs/js/functions/next.getCursor.html
2887
2916
  extension: [
2888
2917
  modelState.init(() => model),
2889
2918
  automerge3({
@@ -2900,162 +2929,6 @@ var createAutomergeModel = ({ space, identity, text }) => {
2900
2929
  };
2901
2930
  return model;
2902
2931
  };
2903
-
2904
- // packages/ui/react-ui-editor/src/hooks/yjs.ts
2905
- import * as decoding from "lib0/decoding";
2906
- import * as encoding from "lib0/encoding";
2907
- import { Observable } from "lib0/observable";
2908
- import * as YP from "y-protocols/awareness";
2909
- import { invariant as invariant5 } from "@dxos/invariant";
2910
- import { log as log4 } from "@dxos/log";
2911
- var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs.ts";
2912
- var createYjsModel = ({ identity, space, text }) => {
2913
- invariant5(text?.doc && text?.content, void 0, {
2914
- F: __dxlog_file7,
2915
- L: 22,
2916
- S: void 0,
2917
- A: [
2918
- "text?.doc && text?.content",
2919
- ""
2920
- ]
2921
- });
2922
- const provider = space ? new YAwarenessProvider({
2923
- space,
2924
- doc: text.doc,
2925
- channel: `yjs.awareness.${text.id}`
2926
- }) : void 0;
2927
- const model = {
2928
- id: text.doc.guid,
2929
- content: text.content,
2930
- text: () => text.content.toString(),
2931
- extension: [
2932
- modelState.init(() => model),
2933
- yjs(text.content, provider?.awareness)
2934
- ],
2935
- awareness: provider?.awareness,
2936
- peer: identity ? {
2937
- id: identity.identityKey.toHex(),
2938
- name: identity.profile?.displayName
2939
- } : void 0
2940
- };
2941
- return model;
2942
- };
2943
- var messageAwareness = 1;
2944
- var messageQueryAwareness = 3;
2945
- var YAwarenessProvider = class extends Observable {
2946
- constructor({ space, doc, channel, awareness: awareness2 }) {
2947
- super();
2948
- this._space = space;
2949
- this._awareness = awareness2 ?? new YP.Awareness(doc);
2950
- this._channel = channel;
2951
- this._clientId = doc.clientID;
2952
- this._awareness.on("update", this._handleAwarenessUpdate.bind(this));
2953
- this._space.listen(this._channel, this._handleSpaceMessage.bind(this));
2954
- if (typeof window !== "undefined") {
2955
- window.addEventListener("beforeunload", this._handleBeforeUnload.bind(this));
2956
- } else if (typeof process !== "undefined") {
2957
- process.on("exit", this._handleBeforeUnload.bind(this));
2958
- }
2959
- const encoderAwarenessQuery = encoding.createEncoder();
2960
- encoding.writeVarUint(encoderAwarenessQuery, messageQueryAwareness);
2961
- void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessQuery));
2962
- const encoderAwarenessState = encoding.createEncoder();
2963
- encoding.writeVarUint(encoderAwarenessState, messageAwareness);
2964
- encoding.writeVarUint8Array(encoderAwarenessState, YP.encodeAwarenessUpdate(this.awareness, [
2965
- this._clientId
2966
- ]));
2967
- void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessState));
2968
- }
2969
- get awareness() {
2970
- return this._awareness;
2971
- }
2972
- _handleAwarenessUpdate({ added, updated, removed }, origin) {
2973
- log4("awareness update", {
2974
- added,
2975
- updated,
2976
- removed,
2977
- origin
2978
- }, {
2979
- F: __dxlog_file7,
2980
- L: 101,
2981
- S: this,
2982
- C: (f, a) => f(...a)
2983
- });
2984
- const changedClients = added.concat(updated).concat(removed);
2985
- const encoderAwareness = encoding.createEncoder();
2986
- encoding.writeVarUint(encoderAwareness, messageAwareness);
2987
- encoding.writeVarUint8Array(encoderAwareness, YP.encodeAwarenessUpdate(this._awareness, changedClients));
2988
- void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwareness));
2989
- }
2990
- _handleSpaceMessage({ payload }) {
2991
- log4("space message", payload, {
2992
- F: __dxlog_file7,
2993
- L: 110,
2994
- S: this,
2995
- C: (f, a) => f(...a)
2996
- });
2997
- const data = new Uint8Array(Array.from(Object.values(payload)));
2998
- const encoder = this._readMessage(data);
2999
- if (encoder) {
3000
- void this._space.postMessage(this._channel, encoding.toUint8Array(encoder));
3001
- }
3002
- }
3003
- _readMessage(message) {
3004
- const decoder = decoding.createDecoder(message);
3005
- const encoder = encoding.createEncoder();
3006
- const messageType = decoding.readVarUint(decoder);
3007
- let sendReply = false;
3008
- switch (messageType) {
3009
- case messageAwareness: {
3010
- YP.applyAwarenessUpdate(this._awareness, decoding.readVarUint8Array(decoder), this);
3011
- break;
3012
- }
3013
- case messageQueryAwareness: {
3014
- encoding.writeVarUint(encoder, messageAwareness);
3015
- encoding.writeVarUint8Array(encoder, YP.encodeAwarenessUpdate(this._awareness, Array.from(this._awareness.getStates().keys())));
3016
- sendReply = true;
3017
- break;
3018
- }
3019
- default: {
3020
- console.error("Invalid message:", messageType);
3021
- return encoder;
3022
- }
3023
- }
3024
- if (!sendReply) {
3025
- return null;
3026
- }
3027
- return encoder;
3028
- }
3029
- _handleBeforeUnload() {
3030
- YP.removeAwarenessStates(this._awareness, [
3031
- this._clientId
3032
- ], "window unload");
3033
- }
3034
- };
3035
-
3036
- // packages/ui/react-ui-editor/src/hooks/useTextModel.ts
3037
- import { useEffect as useEffect4, useState as useState2 } from "react";
3038
- import { isAutomergeObject } from "@dxos/react-client/echo";
3039
- var useTextModel = (props) => {
3040
- const { identity, space, text } = props;
3041
- const [model, setModel] = useState2();
3042
- useEffect4(() => setModel(createModel(props)), [
3043
- identity,
3044
- space,
3045
- text
3046
- ]);
3047
- return model;
3048
- };
3049
- var createModel = (props) => {
3050
- const { text } = props;
3051
- if (isAutomergeObject(text)) {
3052
- return createAutomergeModel(props);
3053
- } else if (text?.doc) {
3054
- return createYjsModel(props);
3055
- } else {
3056
- return void 0;
3057
- }
3058
- };
3059
2932
  export {
3060
2933
  AwarenessProvider,
3061
2934
  BaseTextEditor,
@@ -3067,7 +2940,6 @@ export {
3067
2940
  SpaceAwarenessProvider,
3068
2941
  TextEditor,
3069
2942
  TextKind,
3070
- YAwarenessProvider,
3071
2943
  YText,
3072
2944
  YXmlFragment,
3073
2945
  autocomplete,
@@ -3079,14 +2951,13 @@ export {
3079
2951
  code2 as code,
3080
2952
  codeTheme,
3081
2953
  comments,
3082
- createAutomergeModel,
3083
- createYjsModel,
3084
2954
  defaultMarkdownSlots,
3085
2955
  defaultOptions,
3086
2956
  defaultSlots,
3087
2957
  defaultTextSlots,
3088
2958
  defaultTheme,
3089
2959
  getToken,
2960
+ heading2 as heading,
3090
2961
  hr,
3091
2962
  image,
3092
2963
  link,
@@ -3108,9 +2979,8 @@ export {
3108
2979
  tasklist,
3109
2980
  textTheme,
3110
2981
  typewriter,
3111
- useAwareness,
3112
2982
  useComments,
3113
- useTextModel,
3114
- yjs
2983
+ useTextEditor,
2984
+ useTextModel
3115
2985
  };
3116
2986
  //# sourceMappingURL=index.mjs.map