@dxos/react-ui-editor 0.3.11-main.dafb7f2 → 0.3.11-main.e0dc42b

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 (46) hide show
  1. package/dist/lib/browser/index.mjs +137 -137
  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 -5
  5. package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
  6. package/dist/types/src/components/TextEditor/TextEditor.d.ts +10 -10
  7. package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
  8. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +2 -2
  9. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
  10. package/dist/types/src/components/TextEditor/yjs.stories.d.ts +1 -1
  11. package/dist/types/src/extensions/autocomplete.d.ts.map +1 -1
  12. package/dist/types/src/extensions/automerge/index.d.ts +1 -0
  13. package/dist/types/src/extensions/automerge/index.d.ts.map +1 -1
  14. package/dist/types/src/extensions/code.d.ts.map +1 -1
  15. package/dist/types/src/extensions/comments.d.ts +1 -1
  16. package/dist/types/src/extensions/comments.d.ts.map +1 -1
  17. package/dist/types/src/extensions/hr.d.ts.map +1 -1
  18. package/dist/types/src/extensions/index.d.ts +0 -1
  19. package/dist/types/src/extensions/index.d.ts.map +1 -1
  20. package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
  21. package/dist/types/src/index.d.ts +3 -0
  22. package/dist/types/src/index.d.ts.map +1 -1
  23. package/dist/types/src/styles/tokens.d.ts +1 -0
  24. package/dist/types/src/styles/tokens.d.ts.map +1 -1
  25. package/package.json +23 -22
  26. package/src/components/TextEditor/MarkdownEditor.stories.tsx +18 -15
  27. package/src/components/TextEditor/TextEditor.stories.tsx +3 -4
  28. package/src/components/TextEditor/TextEditor.tsx +59 -45
  29. package/src/extensions/autocomplete.ts +18 -17
  30. package/src/extensions/automerge/index.ts +1 -0
  31. package/src/extensions/awareness.ts +14 -15
  32. package/src/extensions/code.ts +14 -7
  33. package/src/extensions/comments.ts +45 -47
  34. package/src/extensions/hr.ts +4 -5
  35. package/src/extensions/image.ts +2 -2
  36. package/src/extensions/index.ts +0 -1
  37. package/src/extensions/link.ts +5 -5
  38. package/src/extensions/markdown/highlight.ts +3 -4
  39. package/src/extensions/table.ts +6 -3
  40. package/src/extensions/tasklist.ts +2 -2
  41. package/src/hooks/useTextModel.ts +1 -1
  42. package/src/index.ts +3 -0
  43. package/src/styles/tokens.ts +3 -0
  44. package/dist/types/src/extensions/mermaid.d.ts +0 -3
  45. package/dist/types/src/extensions/mermaid.d.ts.map +0 -1
  46. package/src/extensions/mermaid.ts +0 -11
@@ -11,40 +11,41 @@ import { EditorView as EditorView12 } 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, useImperativeHandle, useState } from "react";
14
+ import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useState, useRef } from "react";
15
15
  import { generateName } from "@dxos/display-name";
16
16
  import { useThemeContext } from "@dxos/react-ui";
17
17
  import { getColorForValue, inputSurface, 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";
21
+ import { markdownLanguage } from "@codemirror/lang-markdown";
21
22
  import { keymap } from "@codemirror/view";
22
23
  var autocomplete = ({ onSearch }) => {
23
24
  return [
24
25
  // https://codemirror.net/docs/ref/#view.keymap
25
26
  // https://discuss.codemirror.net/t/how-can-i-replace-the-default-autocompletion-keymap-v6/3322
27
+ // TODO(burdon): Set custom keymap.
26
28
  keymap.of(completionKeymap),
27
29
  // https://codemirror.net/examples/autocompletion
28
30
  // https://codemirror.net/docs/ref/#autocomplete.autocompletion
29
31
  autocompletion({
30
- // TODO(burdon): Set custom keymap.
31
- // defaultKeymap: false,
32
+ defaultKeymap: false,
32
33
  // Don't start unless key press.
33
- activateOnTyping: false,
34
- // TODO(burdon): Option to create new page?
35
- // TODO(burdon): Optional decoration via addToOptions
36
- override: [
37
- (context) => {
38
- const match = context.matchBefore(/\w*/);
39
- if (!match || match.from === match.to && !context.explicit) {
40
- return null;
41
- }
42
- return {
43
- from: match.from,
44
- options: onSearch(match.text.toLowerCase())
45
- };
34
+ activateOnTyping: false
35
+ }),
36
+ // TODO(burdon): Option to create new page?
37
+ // TODO(burdon): Optional decoration via addToOptions
38
+ markdownLanguage.data.of({
39
+ autocomplete: (context) => {
40
+ const match = context.matchBefore(/\w*/);
41
+ if (!match || match.from === match.to && !context.explicit) {
42
+ return null;
46
43
  }
47
- ]
44
+ return {
45
+ from: match.from,
46
+ options: onSearch(match.text.toLowerCase())
47
+ };
48
+ }
48
49
  })
49
50
  ];
50
51
  };
@@ -504,23 +505,21 @@ var RemoteSelectionsDecorator = class {
504
505
  }
505
506
  };
506
507
  var RemoteCaretWidget = class extends WidgetType {
507
- constructor(name, color) {
508
+ constructor(_name, _color) {
508
509
  super();
509
- this.name = name;
510
- this.color = color;
511
- this.name = name;
512
- this.color = color;
510
+ this._name = _name;
511
+ this._color = _color;
513
512
  }
514
513
  toDOM() {
515
514
  const span = document.createElement("span");
516
515
  span.className = "cm-ySelectionCaret";
517
- span.style.backgroundColor = this.color;
518
- span.style.borderColor = this.color;
516
+ span.style.backgroundColor = this._color;
517
+ span.style.borderColor = this._color;
519
518
  const dot = document.createElement("div");
520
519
  dot.className = "cm-ySelectionCaretDot";
521
520
  const info = document.createElement("div");
522
521
  info.className = "cm-ySelectionInfo";
523
- info.innerText = this.name;
522
+ info.innerText = this._name;
524
523
  span.appendChild(document.createTextNode("\u2060"));
525
524
  span.appendChild(dot);
526
525
  span.appendChild(document.createTextNode("\u2060"));
@@ -528,21 +527,22 @@ var RemoteCaretWidget = class extends WidgetType {
528
527
  span.appendChild(document.createTextNode("\u2060"));
529
528
  return span;
530
529
  }
531
- eq(widget) {
532
- return widget.color === this.color;
533
- }
534
- compare(widget) {
535
- return widget.color === this.color;
536
- }
537
530
  updateDOM() {
538
531
  return false;
539
532
  }
533
+ eq(widget) {
534
+ return widget._color === this._color;
535
+ }
540
536
  get estimatedHeight() {
541
537
  return -1;
542
538
  }
543
539
  ignoreEvent() {
544
540
  return true;
545
541
  }
542
+ // TODO(burdon): Not used?
543
+ compare(widget) {
544
+ return widget._color === this._color;
545
+ }
546
546
  };
547
547
  var styles = EditorView.baseTheme({
548
548
  ".cm-ySelection": {},
@@ -930,7 +930,6 @@ var random = (min, max) => {
930
930
 
931
931
  // packages/ui/react-ui-editor/src/extensions/code.ts
932
932
  import { ViewPlugin as ViewPlugin3, EditorView as EditorView4, Decoration as Decoration2 } from "@codemirror/view";
933
- import get2 from "lodash.get";
934
933
  import { mx as mx2 } from "@dxos/react-ui-theme";
935
934
 
936
935
  // packages/ui/react-ui-editor/src/styles/cursors.ts
@@ -1014,20 +1013,22 @@ var inlineUrl = mx(code, "px-1");
1014
1013
  var blockquote = mx("pl-1 mr-1 border-is-4 border-primary-500/70 dark:border-primary-500/30", light);
1015
1014
 
1016
1015
  // packages/ui/react-ui-editor/src/styles/tokens.ts
1016
+ import get2 from "lodash.get";
1017
1017
  import { tailwindConfig } from "@dxos/react-ui-theme";
1018
1018
  var tokens = tailwindConfig({}).theme;
1019
+ var getToken = (path, defaultValue = void 0) => get2(tokens, path, defaultValue);
1019
1020
 
1020
1021
  // packages/ui/react-ui-editor/src/extensions/code.ts
1021
1022
  var CODE_REGEX = /```[\s\S]*?```/gs;
1022
1023
  var styles2 = EditorView4.baseTheme({
1023
1024
  "& .cm-codeblock": {
1024
- fontFamily: get2(tokens, "fontFamily.mono", []).join(",")
1025
+ fontFamily: getToken("fontFamily.mono", []).join(",")
1025
1026
  },
1026
1027
  '&light [aria-readonly="true"] .cm-codeblock': {
1027
- background: get2(tokens, "extend.colors.neutral.50")
1028
+ background: getToken("extend.colors.neutral.50")
1028
1029
  },
1029
1030
  '&dark [aria-readonly="true"] .cm-codeblock': {
1030
- background: get2(tokens, "extend.colors.neutral.850")
1031
+ background: getToken("extend.colors.neutral.850")
1031
1032
  },
1032
1033
  '& [aria-readonly="true"] .cm-codeblock': {
1033
1034
  display: "block",
@@ -1055,7 +1056,7 @@ var getLineRange = (lines, from, to) => {
1055
1056
  var code2 = () => {
1056
1057
  const getDecorations = (view) => {
1057
1058
  const decorations = [];
1058
- if (view.state.readOnly) {
1059
+ if (!view.hasFocus || view.state.readOnly) {
1059
1060
  const text = view.state.doc.sliceString(0);
1060
1061
  const matches = text.matchAll(CODE_REGEX);
1061
1062
  const blocks = view.viewportLineBlocks;
@@ -1074,10 +1075,15 @@ var code2 = () => {
1074
1075
  return [
1075
1076
  ViewPlugin3.fromClass(class {
1076
1077
  constructor(view) {
1078
+ this.hasFocus = false;
1077
1079
  this.decorations = getDecorations(view);
1078
1080
  }
1079
1081
  update(update2) {
1080
- if (update2.docChanged || update2.viewportChanged) {
1082
+ if (
1083
+ // TODO(burdon): Generalize for other extensions.
1084
+ this.hasFocus !== update2.view.hasFocus || update2.startState.readOnly !== update2.view.state.readOnly || update2.docChanged || update2.viewportChanged
1085
+ ) {
1086
+ this.hasFocus = update2.view.hasFocus;
1081
1087
  this.decorations = getDecorations(update2.view);
1082
1088
  }
1083
1089
  }
@@ -1091,7 +1097,6 @@ var code2 = () => {
1091
1097
  // packages/ui/react-ui-editor/src/extensions/comments.ts
1092
1098
  import { StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
1093
1099
  import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView as EditorView5, MatchDecorator, ViewPlugin as ViewPlugin4, WidgetType as WidgetType2 } from "@codemirror/view";
1094
- import get3 from "lodash.get";
1095
1100
  import sortBy from "lodash.sortby";
1096
1101
  import { debounce } from "@dxos/async";
1097
1102
  import { invariant as invariant2 } from "@dxos/invariant";
@@ -1109,10 +1114,10 @@ var styles3 = EditorView5.baseTheme({
1109
1114
  backgroundColor: "orange"
1110
1115
  },
1111
1116
  "& .cm-comment": {
1112
- backgroundColor: get3(tokens, "extend.colors.yellow.50")
1117
+ backgroundColor: getToken("extend.colors.yellow.50")
1113
1118
  },
1114
1119
  "& .cm-comment-active": {
1115
- backgroundColor: get3(tokens, "extend.colors.yellow.100")
1120
+ backgroundColor: getToken("extend.colors.yellow.100")
1116
1121
  }
1117
1122
  });
1118
1123
  var marks = {
@@ -1196,14 +1201,13 @@ var highlightDecorations = EditorView5.decorations.compute([
1196
1201
  return Decoration3.set(decorations);
1197
1202
  });
1198
1203
  var BookmarkWidget = class extends WidgetType2 {
1199
- constructor(_anchor, _id, _handleClick) {
1204
+ constructor(_id, _handleClick) {
1200
1205
  super();
1201
- this._anchor = _anchor;
1202
1206
  this._id = _id;
1203
1207
  this._handleClick = _handleClick;
1204
1208
  invariant2(this._id, void 0, {
1205
1209
  F: __dxlog_file3,
1206
- L: 169,
1210
+ L: 164,
1207
1211
  S: this,
1208
1212
  A: [
1209
1213
  "this._id",
@@ -1212,7 +1216,7 @@ var BookmarkWidget = class extends WidgetType2 {
1212
1216
  });
1213
1217
  }
1214
1218
  eq(other) {
1215
- return this._anchor === other._anchor && this._id === other._id;
1219
+ return this._id === other._id;
1216
1220
  }
1217
1221
  toDOM() {
1218
1222
  const span = document.createElement("span");
@@ -1225,12 +1229,13 @@ var BookmarkWidget = class extends WidgetType2 {
1225
1229
  }
1226
1230
  };
1227
1231
  var comments = (options = {}) => {
1232
+ const { key: shortcut = "meta-'" } = options;
1228
1233
  const handleSelect = debounce((state) => options.onSelect?.(state), 200);
1229
1234
  const createCommentThread = (view) => {
1230
1235
  const cursorConverter3 = view.state.facet(CursorConverter);
1231
1236
  invariant2(options.onCreate, void 0, {
1232
1237
  F: __dxlog_file3,
1233
- L: 225,
1238
+ L: 222,
1234
1239
  S: void 0,
1235
1240
  A: [
1236
1241
  "options.onCreate",
@@ -1273,17 +1278,17 @@ var comments = (options = {}) => {
1273
1278
  }
1274
1279
  return false;
1275
1280
  };
1276
- const bookmarksViewPlugin = ViewPlugin4.fromClass(class BookmarkViewPlugin {
1281
+ const bookmarksViewPlugin = options.footnote ? ViewPlugin4.fromClass(class BookmarkViewPlugin {
1277
1282
  static {
1278
1283
  // Match markdown footnotes (option).
1279
1284
  // https://www.markdownguide.org/extended-syntax/#footnotes
1280
1285
  this.bookmarkMatcher = new MatchDecorator({
1281
1286
  regexp: /\[\^(\w+)\]/g,
1282
- decoration: (match, view, pos) => {
1287
+ decoration: (match) => {
1283
1288
  const id = match[1];
1284
1289
  return Decoration3.replace({
1285
1290
  id,
1286
- widget: new BookmarkWidget(pos, id)
1291
+ widget: new BookmarkWidget(id)
1287
1292
  });
1288
1293
  }
1289
1294
  });
@@ -1299,7 +1304,7 @@ var comments = (options = {}) => {
1299
1304
  provide: (plugin) => EditorView5.atomicRanges.of((view) => {
1300
1305
  return view.plugin(plugin)?.bookmarks || Decoration3.none;
1301
1306
  })
1302
- });
1307
+ }) : [];
1303
1308
  return [
1304
1309
  bookmarksViewPlugin,
1305
1310
  commentsStateField,
@@ -1310,7 +1315,7 @@ var comments = (options = {}) => {
1310
1315
  //
1311
1316
  options.onCreate ? keymap3.of([
1312
1317
  {
1313
- key: options?.key ?? "meta-'",
1318
+ key: shortcut,
1314
1319
  run: callbackWrapper(createCommentThread)
1315
1320
  }
1316
1321
  ]) : [],
@@ -1327,7 +1332,7 @@ var comments = (options = {}) => {
1327
1332
  above: true,
1328
1333
  create: () => {
1329
1334
  const el = document.createElement("div");
1330
- options.onHover?.(el);
1335
+ options.onHover?.(el, shortcut);
1331
1336
  return {
1332
1337
  dom: el,
1333
1338
  offset: {
@@ -1361,7 +1366,7 @@ var comments = (options = {}) => {
1361
1366
  thread: range.id
1362
1367
  }, {
1363
1368
  F: __dxlog_file3,
1364
- L: 359,
1369
+ L: 355,
1365
1370
  S: void 0,
1366
1371
  C: (f, a) => f(...a)
1367
1372
  });
@@ -1429,7 +1434,7 @@ var getRangeFromCursor = (cursorConverter3, cursor) => {
1429
1434
  const parts = cursor.split(":");
1430
1435
  const from = cursorConverter3.fromCursor(parts[0]);
1431
1436
  const to = cursorConverter3.fromCursor(parts[1]);
1432
- return from && to ? {
1437
+ return from !== void 0 && to !== void 0 ? {
1433
1438
  from,
1434
1439
  to
1435
1440
  } : void 0;
@@ -1437,12 +1442,11 @@ var getRangeFromCursor = (cursorConverter3, cursor) => {
1437
1442
 
1438
1443
  // packages/ui/react-ui-editor/src/extensions/hr.ts
1439
1444
  import { Decoration as Decoration4, EditorView as EditorView6, MatchDecorator as MatchDecorator2, ViewPlugin as ViewPlugin5, WidgetType as WidgetType3 } from "@codemirror/view";
1440
- import get4 from "lodash.get";
1441
1445
  var styles4 = EditorView6.baseTheme({
1442
1446
  "& .cm-hr": {
1443
1447
  // TODO(burdon): ???
1444
1448
  // Note that block-level decorations should not have vertical margins,
1445
- borderBottom: `1px solid ${get4(tokens, "extend.colors.neutral.200")}`
1449
+ borderBottom: `1px solid ${getToken("extend.colors.neutral.200")}`
1446
1450
  }
1447
1451
  });
1448
1452
  var HorizontalRuleWidget = class extends WidgetType3 {
@@ -1672,7 +1676,7 @@ var buildDecorations2 = (view, options) => {
1672
1676
  if (!url) {
1673
1677
  return false;
1674
1678
  }
1675
- if (state.readOnly || cursor < node.from || cursor > node.to) {
1679
+ if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
1676
1680
  builder.add(node.from, node.to, Decoration6.replace({
1677
1681
  widget: new LinkText(text, options.link ? url : void 0)
1678
1682
  }));
@@ -1709,7 +1713,7 @@ var listener = ({ onFocus, onChange }) => {
1709
1713
  // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
1710
1714
  import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
1711
1715
  import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
1712
- import { markdownLanguage as markdownLanguage2, markdown } from "@codemirror/lang-markdown";
1716
+ import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
1713
1717
  import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
1714
1718
  import { languages } from "@codemirror/language-data";
1715
1719
  import { searchKeymap } from "@codemirror/search";
@@ -1718,11 +1722,10 @@ import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/the
1718
1722
  import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView9, highlightActiveLine, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
1719
1723
 
1720
1724
  // packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
1721
- import { markdownLanguage } from "@codemirror/lang-markdown";
1725
+ import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
1722
1726
  import { HighlightStyle } from "@codemirror/language";
1723
1727
  import { tags, styleTags, Tag } from "@lezer/highlight";
1724
1728
  import { Table } from "@lezer/markdown";
1725
- import get5 from "lodash.get";
1726
1729
  var markdownTags = {
1727
1730
  Blockquote: Tag.define(),
1728
1731
  CodeMark: Tag.define(),
@@ -1906,9 +1909,9 @@ var markdownHighlightStyle = (readonly) => {
1906
1909
  class: "font-mono"
1907
1910
  }
1908
1911
  ], {
1909
- scope: markdownLanguage,
1912
+ scope: markdownLanguage2,
1910
1913
  all: {
1911
- fontFamily: get5(tokens, "fontFamily.body", []).join(",")
1914
+ fontFamily: getToken("fontFamily.body", []).join(",")
1912
1915
  }
1913
1916
  });
1914
1917
  };
@@ -1938,7 +1941,7 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
1938
1941
  // NOTE: This extends the parser; it doesn't affect rendering.
1939
1942
  // https://github.github.com/gfm
1940
1943
  // https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
1941
- base: markdownLanguage2,
1944
+ base: markdownLanguage3,
1942
1945
  // Languages for syntax highlighting fenced code blocks.
1943
1946
  codeLanguages: languages,
1944
1947
  // Parser extensions.
@@ -1989,11 +1992,6 @@ var mention = ({ onSearch }) => {
1989
1992
  });
1990
1993
  };
1991
1994
 
1992
- // packages/ui/react-ui-editor/src/extensions/mermaid.ts
1993
- var mermaid = () => {
1994
- return [];
1995
- };
1996
-
1997
1995
  // packages/ui/react-ui-editor/src/extensions/table.ts
1998
1996
  import { syntaxTree as syntaxTree3 } from "@codemirror/language";
1999
1997
  import { RangeSetBuilder as RangeSetBuilder2, StateField as StateField4 } from "@codemirror/state";
@@ -2047,7 +2045,6 @@ var update = (state, options) => {
2047
2045
  tables.forEach((table2) => {
2048
2046
  const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
2049
2047
  hide && builder.add(table2.from, table2.to, Decoration7.replace({
2050
- block: true,
2051
2048
  widget: new TableWidget(table2)
2052
2049
  }));
2053
2050
  builder.add(table2.from, table2.to, Decoration7.mark({
@@ -2088,6 +2085,9 @@ var TableWidget = class extends WidgetType6 {
2088
2085
  }
2089
2086
  return table2;
2090
2087
  }
2088
+ ignoreEvent(e) {
2089
+ return !/^mouse/.test(e.type);
2090
+ }
2091
2091
  };
2092
2092
 
2093
2093
  // packages/ui/react-ui-editor/src/extensions/tasklist.ts
@@ -2253,7 +2253,7 @@ var yjs = (content, awareness2) => [
2253
2253
  ];
2254
2254
 
2255
2255
  // packages/ui/react-ui-editor/src/themes/default.ts
2256
- import get6 from "lodash.get";
2256
+ import get3 from "lodash.get";
2257
2257
  var defaultTheme = {
2258
2258
  //
2259
2259
  // Main layout:
@@ -2284,7 +2284,7 @@ var defaultTheme = {
2284
2284
  },
2285
2285
  ".cm-scroller": {
2286
2286
  overflow: "visible",
2287
- fontFamily: get6(tokens, "fontFamily.mono", []).join(",")
2287
+ fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
2288
2288
  },
2289
2289
  ".cm-content": {
2290
2290
  padding: 0,
@@ -2292,11 +2292,11 @@ var defaultTheme = {
2292
2292
  fontSize: "16px"
2293
2293
  },
2294
2294
  "&light .cm-content": {
2295
- color: get6(tokens, "extend.colors.neutral.900", "black"),
2295
+ color: get3(tokens, "extend.colors.neutral.900", "black"),
2296
2296
  caretColor: "black"
2297
2297
  },
2298
2298
  "&dark .cm-content": {
2299
- color: get6(tokens, "extend.colors.neutral.100", "white"),
2299
+ color: get3(tokens, "extend.colors.neutral.100", "white"),
2300
2300
  caretColor: "white"
2301
2301
  },
2302
2302
  //
@@ -2324,25 +2324,25 @@ var defaultTheme = {
2324
2324
  // Selection
2325
2325
  //
2326
2326
  "&light .cm-selectionBackground": {
2327
- background: get6(tokens, "extend.colors.primary.100")
2327
+ background: get3(tokens, "extend.colors.primary.100")
2328
2328
  },
2329
2329
  "&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
2330
- background: get6(tokens, "extend.colors.primary.200")
2330
+ background: get3(tokens, "extend.colors.primary.200")
2331
2331
  },
2332
2332
  "&dark .cm-selectionBackground": {
2333
- background: get6(tokens, "extend.colors.primary.700")
2333
+ background: get3(tokens, "extend.colors.primary.700")
2334
2334
  },
2335
2335
  "&dark.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
2336
- background: get6(tokens, "extend.colors.primary.600")
2336
+ background: get3(tokens, "extend.colors.primary.600")
2337
2337
  },
2338
2338
  //
2339
2339
  // Search
2340
2340
  //
2341
2341
  "&light .cm-searchMatch": {
2342
- backgroundColor: get6(tokens, "extend.colors.yellow.100")
2342
+ backgroundColor: get3(tokens, "extend.colors.yellow.100")
2343
2343
  },
2344
2344
  "&dark .cm-searchMatch": {
2345
- backgroundColor: get6(tokens, "extend.colors.yellow.700")
2345
+ backgroundColor: get3(tokens, "extend.colors.yellow.700")
2346
2346
  },
2347
2347
  //
2348
2348
  // collaboration
@@ -2375,12 +2375,12 @@ var defaultTheme = {
2375
2375
  // link
2376
2376
  //
2377
2377
  ".cm-link": {
2378
- color: get6(tokens, "extend.colors.primary.500"),
2378
+ color: get3(tokens, "extend.colors.primary.500"),
2379
2379
  textDecorationLine: "underline",
2380
2380
  textDecorationThickness: "1px",
2381
2381
  textUnderlineOffset: "2px",
2382
2382
  borderRadius: ".125rem",
2383
- fontFamily: get6(tokens, "fontFamily.body", []).join(",")
2383
+ fontFamily: get3(tokens, "fontFamily.body", []).join(",")
2384
2384
  },
2385
2385
  //
2386
2386
  // tooltip
@@ -2402,7 +2402,7 @@ var defaultTheme = {
2402
2402
  display: "none"
2403
2403
  },
2404
2404
  ".cm-completionLabel": {
2405
- fontFamily: get6(tokens, "fontFamily.body", []).join(",")
2405
+ fontFamily: get3(tokens, "fontFamily.body", []).join(",")
2406
2406
  },
2407
2407
  ".cm-completionMatchedText": {
2408
2408
  textDecoration: "none"
@@ -2418,15 +2418,15 @@ var defaultTheme = {
2418
2418
  // table
2419
2419
  //
2420
2420
  ".cm-table *": {
2421
- fontFamily: `${get6(tokens, "fontFamily.mono", []).join(",")} !important`,
2421
+ fontFamily: `${get3(tokens, "fontFamily.mono", []).join(",")} !important`,
2422
2422
  textDecoration: "none !important"
2423
2423
  },
2424
2424
  ".cm-table-head": {
2425
2425
  padding: "2px 16px 2px 0px",
2426
- borderBottom: `1px solid ${get6(tokens, "extend.colors.neutral.500")}`,
2426
+ borderBottom: `1px solid ${get3(tokens, "extend.colors.neutral.500")}`,
2427
2427
  fontWeight: 100,
2428
2428
  textAlign: "left",
2429
- color: get6(tokens, "extend.colors.neutral.500")
2429
+ color: get3(tokens, "extend.colors.neutral.500")
2430
2430
  },
2431
2431
  ".cm-table-cell": {
2432
2432
  padding: "2px 16px 2px 0px"
@@ -2447,8 +2447,8 @@ var defaultTheme = {
2447
2447
  // font size
2448
2448
  // TODO(thure): This appears to be the best or only way to set selection caret heights, but it's far more verbose than it needs to be.
2449
2449
  //
2450
- ...Object.keys(get6(tokens, "extend.fontSize", {})).reduce((acc, fontSize) => {
2451
- const height = get6(tokens, [
2450
+ ...Object.keys(get3(tokens, "extend.fontSize", {})).reduce((acc, fontSize) => {
2451
+ const height = get3(tokens, [
2452
2452
  "extend",
2453
2453
  "fontSize",
2454
2454
  fontSize,
@@ -2483,23 +2483,23 @@ var defaultTheme = {
2483
2483
  * </div
2484
2484
  */
2485
2485
  ".cm-panels": {
2486
- border: `1px solid ${get6(tokens, "extend.colors.neutral.200")}`
2486
+ border: `1px solid ${get3(tokens, "extend.colors.neutral.200")}`
2487
2487
  },
2488
2488
  ".cm-panel": {
2489
- background: get6(tokens, "extend.colors.neutral.50"),
2490
- fontFamily: get6(tokens, "fontFamily.body", []).join(",")
2489
+ background: get3(tokens, "extend.colors.neutral.50"),
2490
+ fontFamily: get3(tokens, "fontFamily.body", []).join(",")
2491
2491
  },
2492
2492
  ".cm-button": {
2493
2493
  margin: "4px",
2494
- fontFamily: get6(tokens, "fontFamily.body", []).join(","),
2495
- background: get6(tokens, "extend.colors.neutral.100"),
2494
+ fontFamily: get3(tokens, "fontFamily.body", []).join(","),
2495
+ background: get3(tokens, "extend.colors.neutral.100"),
2496
2496
  backgroundImage: "none",
2497
2497
  border: "none",
2498
2498
  "&:hover": {
2499
- background: get6(tokens, "extend.colors.neutral.200")
2499
+ background: get3(tokens, "extend.colors.neutral.200")
2500
2500
  },
2501
2501
  "&:active": {
2502
- background: get6(tokens, "extend.colors.neutral.300"),
2502
+ background: get3(tokens, "extend.colors.neutral.300"),
2503
2503
  backgroundImage: "none"
2504
2504
  }
2505
2505
  },
@@ -2509,24 +2509,24 @@ var defaultTheme = {
2509
2509
  };
2510
2510
  var textTheme = {
2511
2511
  ".cm-scroller": {
2512
- fontFamily: get6(tokens, "fontFamily.body", []).join(",")
2512
+ fontFamily: get3(tokens, "fontFamily.body", []).join(",")
2513
2513
  },
2514
2514
  ".cm-placeholder": {
2515
- fontFamily: get6(tokens, "fontFamily.body", []).join(",")
2515
+ fontFamily: get3(tokens, "fontFamily.body", []).join(",")
2516
2516
  }
2517
2517
  };
2518
2518
  var markdownTheme = {
2519
2519
  // NOTE: Must leave base font family as is (i.e., monospace) due to fenced code blocks.
2520
2520
  ".cm-placeholder": {
2521
- fontFamily: get6(tokens, "fontFamily.body", []).join(",")
2521
+ fontFamily: get3(tokens, "fontFamily.body", []).join(",")
2522
2522
  }
2523
2523
  };
2524
2524
  var codeTheme = {
2525
2525
  ".cm-scroller": {
2526
- fontFamily: get6(tokens, "fontFamily.mono", []).join(",")
2526
+ fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
2527
2527
  },
2528
2528
  ".cm-placeholder": {
2529
- fontFamily: get6(tokens, "fontFamily.mono", []).join(",")
2529
+ fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
2530
2530
  }
2531
2531
  };
2532
2532
 
@@ -2535,21 +2535,23 @@ var EditorModes = [
2535
2535
  "default",
2536
2536
  "vim"
2537
2537
  ];
2538
- var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: comments2, extensions = [], editorMode, slots = defaultSlots }, forwardedRef) => {
2539
- const { themeMode } = useThemeContext();
2538
+ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, focus, selection, readonly, comments: comments2, extensions = [], editorMode, slots = defaultSlots }, forwardedRef) => {
2540
2539
  const tabsterDOMAttribute = useFocusableGroup({
2541
2540
  tabBehavior: "limited"
2542
2541
  });
2543
- const [root, setRoot] = useState(null);
2544
- const [{ state = void 0, view = void 0 } = {}, setEditor] = useState();
2545
- useImperativeHandle(forwardedRef, () => ({
2546
- root,
2547
- state,
2542
+ const { themeMode } = useThemeContext();
2543
+ const rootRef = useRef(null);
2544
+ const [view, setView] = useState(null);
2545
+ useImperativeHandle(forwardedRef, () => view, [
2548
2546
  view
2549
- }), [
2547
+ ]);
2548
+ useEffect(() => {
2549
+ if (view && focus) {
2550
+ view.focus();
2551
+ }
2552
+ }, [
2550
2553
  view,
2551
- state,
2552
- root
2554
+ focus
2553
2555
  ]);
2554
2556
  const { awareness: awareness2, peer } = model;
2555
2557
  useEffect(() => {
@@ -2586,11 +2588,12 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
2586
2588
  comments2
2587
2589
  ]);
2588
2590
  useEffect(() => {
2589
- if (!root) {
2591
+ if (!model || !rootRef.current) {
2590
2592
  return;
2591
2593
  }
2592
- const state2 = EditorState2.create({
2594
+ const state = EditorState2.create({
2593
2595
  doc: model.text(),
2596
+ selection,
2594
2597
  extensions: [
2595
2598
  readonly && EditorState2.readOnly.of(readonly),
2596
2599
  // TODO(burdon): Factor out VIM mode? (manage via MarkdownPlugin).
@@ -2607,19 +2610,17 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
2607
2610
  ].filter(Boolean)
2608
2611
  });
2609
2612
  view?.destroy();
2610
- setEditor({
2611
- state: state2,
2612
- view: new EditorView12({
2613
- state: state2,
2614
- parent: root
2615
- })
2613
+ const newView = new EditorView12({
2614
+ parent: rootRef.current,
2615
+ state
2616
2616
  });
2617
+ setView(newView);
2617
2618
  return () => {
2618
- view?.destroy();
2619
- setEditor(void 0);
2619
+ newView?.destroy();
2620
+ setView(null);
2620
2621
  };
2621
2622
  }, [
2622
- root,
2623
+ rootRef,
2623
2624
  model,
2624
2625
  readonly,
2625
2626
  editorMode,
@@ -2628,12 +2629,8 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
2628
2629
  const handleKeyUp = useCallback((event) => {
2629
2630
  const { key, altKey, shiftKey, metaKey, ctrlKey } = event;
2630
2631
  switch (key) {
2631
- case "Enter": {
2632
- view?.contentDOM.focus();
2633
- break;
2634
- }
2635
2632
  case "Escape": {
2636
- editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey) && root?.focus();
2633
+ editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey) && rootRef.current?.focus();
2637
2634
  break;
2638
2635
  }
2639
2636
  }
@@ -2643,16 +2640,16 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
2643
2640
  ]);
2644
2641
  return /* @__PURE__ */ React.createElement("div", {
2645
2642
  key: model.id,
2646
- ref: setRoot,
2643
+ ref: rootRef,
2647
2644
  tabIndex: 0,
2648
2645
  ...slots?.root,
2649
2646
  ...editorMode !== "vim" && tabsterDOMAttribute,
2650
2647
  onKeyUp: handleKeyUp
2651
2648
  });
2652
2649
  });
2653
- var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, extensions = [], slots: _slots, ...props }, forwardedRef) => {
2650
+ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, extensions = [], slots, ...props }, forwardedRef) => {
2654
2651
  const { themeMode } = useThemeContext();
2655
- const slots = defaultsDeep2({}, _slots, defaultTextSlots);
2652
+ const updatedSlots = defaultsDeep2({}, slots, defaultTextSlots);
2656
2653
  return /* @__PURE__ */ React.createElement(BaseTextEditor, {
2657
2654
  ref: forwardedRef,
2658
2655
  readonly,
@@ -2660,17 +2657,17 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, extensions = [], slots:
2660
2657
  basicBundle({
2661
2658
  readonly,
2662
2659
  themeMode,
2663
- placeholder: slots?.editor?.placeholder
2660
+ placeholder: updatedSlots?.editor?.placeholder
2664
2661
  }),
2665
2662
  ...extensions
2666
2663
  ],
2667
- slots,
2664
+ slots: updatedSlots,
2668
2665
  ...props
2669
2666
  });
2670
2667
  });
2671
- var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, extensions = [], slots: _slots, ...props }, forwardedRef) => {
2668
+ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, extensions = [], slots, ...props }, forwardedRef) => {
2672
2669
  const { themeMode } = useThemeContext();
2673
- const slots = defaultsDeep2({}, _slots, defaultMarkdownSlots);
2670
+ const updatedSlots = defaultsDeep2({}, slots, defaultMarkdownSlots);
2674
2671
  return /* @__PURE__ */ React.createElement(BaseTextEditor, {
2675
2672
  ref: forwardedRef,
2676
2673
  readonly,
@@ -2678,11 +2675,11 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, extensions = [], sl
2678
2675
  markdownBundle({
2679
2676
  readonly,
2680
2677
  themeMode,
2681
- placeholder: slots?.editor?.placeholder
2678
+ placeholder: updatedSlots?.editor?.placeholder
2682
2679
  }),
2683
2680
  ...extensions
2684
2681
  ],
2685
- slots,
2682
+ slots: updatedSlots,
2686
2683
  ...props
2687
2684
  });
2688
2685
  });
@@ -2705,7 +2702,7 @@ var defaultMarkdownSlots = {
2705
2702
  };
2706
2703
 
2707
2704
  // packages/ui/react-ui-editor/src/hooks/automerge.ts
2708
- import get7 from "lodash.get";
2705
+ import get4 from "lodash.get";
2709
2706
  import { getRawDoc } from "@dxos/echo-schema";
2710
2707
  import { isNotNullOrUndefined } from "@dxos/util";
2711
2708
 
@@ -2988,7 +2985,7 @@ var modelState = StateField5.define({
2988
2985
  });
2989
2986
  var useTextModel = (props) => {
2990
2987
  const { identity, space, text } = props;
2991
- const [model, setModel] = useState2(() => createModel(props));
2988
+ const [model, setModel] = useState2();
2992
2989
  useEffect2(() => setModel(createModel(props)), [
2993
2990
  identity,
2994
2991
  space,
@@ -3026,7 +3023,7 @@ var createAutomergeModel = ({ space, identity, text }) => {
3026
3023
  const model = {
3027
3024
  id: obj.id,
3028
3025
  content: doc,
3029
- text: () => get7(doc.handle.docSync(), doc.path),
3026
+ text: () => get4(doc.handle.docSync(), doc.path),
3030
3027
  // TODO(burdon): https://automerge.org/automerge/api-docs/js/functions/next.getCursor.html
3031
3028
  extension: [
3032
3029
  modelState.init(() => model),
@@ -3047,6 +3044,7 @@ var createAutomergeModel = ({ space, identity, text }) => {
3047
3044
  export {
3048
3045
  AwarenessProvider,
3049
3046
  BaseTextEditor,
3047
+ CursorConverter,
3050
3048
  Doc,
3051
3049
  EditorModes,
3052
3050
  MarkdownEditor,
@@ -3062,16 +3060,19 @@ export {
3062
3060
  awareness,
3063
3061
  basicBundle,
3064
3062
  blast,
3063
+ callbackWrapper,
3065
3064
  code2 as code,
3066
3065
  codeTheme,
3067
3066
  comments,
3068
3067
  createAutomergeModel,
3069
3068
  createYjsModel,
3069
+ cursorConverter,
3070
3070
  defaultMarkdownSlots,
3071
3071
  defaultOptions,
3072
3072
  defaultSlots,
3073
3073
  defaultTextSlots,
3074
3074
  defaultTheme,
3075
+ getToken,
3075
3076
  hr,
3076
3077
  image,
3077
3078
  link,
@@ -3082,7 +3083,6 @@ export {
3082
3083
  markdownTagsExtensions,
3083
3084
  markdownTheme,
3084
3085
  mention,
3085
- mermaid,
3086
3086
  modelState,
3087
3087
  setCommentRange,
3088
3088
  setFocus,