@dxos/react-ui-editor 0.6.10-main.bbdfaa4 → 0.6.10-staging.3cfcc89

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 (72) hide show
  1. package/dist/lib/browser/index.mjs +736 -717
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/types/src/InputMode.stories.d.ts +1 -0
  5. package/dist/types/src/InputMode.stories.d.ts.map +1 -1
  6. package/dist/types/src/TextEditor.stories.d.ts +19 -12
  7. package/dist/types/src/TextEditor.stories.d.ts.map +1 -1
  8. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
  9. package/dist/types/src/defaults.d.ts +5 -1
  10. package/dist/types/src/defaults.d.ts.map +1 -1
  11. package/dist/types/src/extensions/autocomplete.d.ts +3 -2
  12. package/dist/types/src/extensions/autocomplete.d.ts.map +1 -1
  13. package/dist/types/src/extensions/automerge/automerge.stories.d.ts +1 -0
  14. package/dist/types/src/extensions/automerge/automerge.stories.d.ts.map +1 -1
  15. package/dist/types/src/extensions/comments.d.ts.map +1 -1
  16. package/dist/types/src/extensions/dnd.d.ts.map +1 -1
  17. package/dist/types/src/extensions/factories.d.ts +2 -2
  18. package/dist/types/src/extensions/factories.d.ts.map +1 -1
  19. package/dist/types/src/extensions/folding.d.ts.map +1 -1
  20. package/dist/types/src/extensions/markdown/action.d.ts +1 -1
  21. package/dist/types/src/extensions/markdown/action.d.ts.map +1 -1
  22. package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
  23. package/dist/types/src/extensions/markdown/changes.d.ts +10 -0
  24. package/dist/types/src/extensions/markdown/changes.d.ts.map +1 -0
  25. package/dist/types/src/extensions/markdown/changes.test.d.ts +2 -0
  26. package/dist/types/src/extensions/markdown/changes.test.d.ts.map +1 -0
  27. package/dist/types/src/extensions/markdown/debug.d.ts +11 -0
  28. package/dist/types/src/extensions/markdown/debug.d.ts.map +1 -0
  29. package/dist/types/src/extensions/markdown/decorate.d.ts.map +1 -1
  30. package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -1
  31. package/dist/types/src/extensions/markdown/index.d.ts +1 -0
  32. package/dist/types/src/extensions/markdown/index.d.ts.map +1 -1
  33. package/dist/types/src/extensions/markdown/styles.d.ts +4 -0
  34. package/dist/types/src/extensions/markdown/styles.d.ts.map +1 -0
  35. package/dist/types/src/index.d.ts +0 -1
  36. package/dist/types/src/index.d.ts.map +1 -1
  37. package/dist/types/src/styles/theme.d.ts +1 -1
  38. package/dist/types/src/styles/theme.d.ts.map +1 -1
  39. package/dist/types/src/styles/tokens.d.ts +2 -4
  40. package/dist/types/src/styles/tokens.d.ts.map +1 -1
  41. package/dist/types/src/translations.d.ts +1 -0
  42. package/dist/types/src/translations.d.ts.map +1 -1
  43. package/package.json +26 -27
  44. package/src/TextEditor.stories.tsx +122 -74
  45. package/src/components/Toolbar/Toolbar.tsx +91 -92
  46. package/src/defaults.ts +16 -11
  47. package/src/extensions/annotations.ts +2 -2
  48. package/src/extensions/autocomplete.ts +4 -1
  49. package/src/extensions/awareness/awareness.ts +1 -1
  50. package/src/extensions/comments.ts +11 -45
  51. package/src/extensions/dnd.ts +3 -5
  52. package/src/extensions/factories.ts +4 -4
  53. package/src/extensions/folding.tsx +3 -4
  54. package/src/extensions/markdown/action.ts +1 -0
  55. package/src/extensions/markdown/bundle.ts +0 -1
  56. package/src/extensions/markdown/{link-paste.test.ts → changes.test.ts} +2 -2
  57. package/src/extensions/markdown/changes.ts +148 -0
  58. package/src/extensions/markdown/debug.ts +44 -0
  59. package/src/extensions/markdown/decorate.ts +14 -93
  60. package/src/extensions/markdown/formatting.ts +1 -2
  61. package/src/extensions/markdown/highlight.ts +2 -2
  62. package/src/extensions/markdown/index.ts +1 -0
  63. package/src/extensions/markdown/styles.ts +103 -0
  64. package/src/index.ts +0 -2
  65. package/src/styles/theme.ts +85 -147
  66. package/src/styles/tokens.ts +4 -2
  67. package/src/translations.ts +1 -0
  68. package/dist/types/src/extensions/markdown/link-paste.d.ts +0 -9
  69. package/dist/types/src/extensions/markdown/link-paste.d.ts.map +0 -1
  70. package/dist/types/src/extensions/markdown/link-paste.test.d.ts +0 -2
  71. package/dist/types/src/extensions/markdown/link-paste.test.d.ts.map +0 -1
  72. package/src/extensions/markdown/link-paste.ts +0 -107
@@ -26,6 +26,7 @@ var translations_default = [
26
26
  "view mode label": "Editor view",
27
27
  "preview mode label": "Live preview",
28
28
  "readonly mode label": "Read only",
29
+ "search label": "Search",
29
30
  "source mode label": "Source"
30
31
  }
31
32
  }
@@ -37,281 +38,8 @@ import { keymap as keymap11 } from "@codemirror/view";
37
38
  import { tags as tags2 } from "@lezer/highlight";
38
39
  import { TextKind } from "@dxos/protocols/proto/dxos/echo/model/text";
39
40
 
40
- // packages/ui/react-ui-editor/src/styles/markdown.ts
41
- import { mx } from "@dxos/react-ui-theme";
42
- var headings = {
43
- 1: "text-4xl",
44
- 2: "text-3xl",
45
- 3: "text-2xl",
46
- 4: "text-xl",
47
- 5: "text-lg",
48
- 6: "text-md"
49
- };
50
- var theme = {
51
- mark: "opacity-50",
52
- code: "font-mono !no-underline text-neutral-700 dark:text-neutral-300",
53
- codeMark: "font-mono text-primary-500",
54
- // TODO(burdon): Replace with widget.
55
- blockquote: "pl-1 mr-1 border-is-4 border-orange-500 dark:border-orange-500 dark:text-neutral-500",
56
- heading: (level) => {
57
- return mx(headings[level], "dark:text-primary-400");
58
- }
59
- };
60
-
61
- // packages/ui/react-ui-editor/src/styles/tokens.ts
62
- import get from "lodash.get";
63
- import { tokens } from "@dxos/react-ui-theme";
64
- var getToken = (path, defaultValue) => {
65
- const value = get(tokens, path, defaultValue);
66
- return value?.toString() ?? "";
67
- };
68
-
69
- // packages/ui/react-ui-editor/src/styles/theme.ts
70
- var defaultTheme = {
71
- "&": {},
72
- "&.cm-focused": {
73
- outline: "none"
74
- },
75
- /**
76
- * Scroller
77
- */
78
- ".cm-scroller": {
79
- overflowY: "auto"
80
- },
81
- /**
82
- * Content
83
- * NOTE: Apply margins to content so that scrollbar is at the edge of the container.
84
- */
85
- ".cm-content": {
86
- padding: "unset",
87
- // NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
88
- fontSize: "16px",
89
- fontFamily: getToken("fontFamily.body"),
90
- lineHeight: 1.5
91
- },
92
- "&light .cm-content": {
93
- color: getToken("extend.semanticColors.base.fg.light", "black")
94
- },
95
- "&dark .cm-content": {
96
- color: getToken("extend.semanticColors.base.fg.dark", "white")
97
- },
98
- /**
99
- * Gutters
100
- * NOTE: Gutters should have the same top margin as the content.
101
- */
102
- ".cm-gutters": {
103
- background: "transparent"
104
- },
105
- ".cm-gutter": {},
106
- ".cm-gutterElement": {
107
- lineHeight: 1.5
108
- },
109
- //
110
- // Cursor
111
- //
112
- "&light .cm-cursor, &light .cm-dropCursor": {
113
- borderLeft: "2px solid black"
114
- },
115
- "&dark .cm-cursor, &dark .cm-dropCursor": {
116
- borderLeft: "2px solid white"
117
- },
118
- "&light .cm-placeholder": {
119
- color: getToken("extend.semanticColors.description.light", "rgba(0,0,0,.2)")
120
- },
121
- "&dark .cm-placeholder": {
122
- color: getToken("extend.semanticColors.description.dark", "rgba(255,255,255,.2)")
123
- },
124
- //
125
- // line
126
- //
127
- ".cm-line": {
128
- paddingInline: 0
129
- },
130
- ".cm-activeLine": {
131
- background: "transparent"
132
- },
133
- //
134
- // gutter
135
- //
136
- ".cm-lineNumbers": {
137
- minWidth: "36px"
138
- },
139
- //
140
- // Selection
141
- //
142
- "&light .cm-selectionBackground": {
143
- background: getToken("extend.colors.primary.100")
144
- },
145
- "&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
146
- background: getToken("extend.colors.primary.200")
147
- },
148
- "&dark .cm-selectionBackground": {
149
- background: getToken("extend.colors.primary.700")
150
- },
151
- "&dark.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
152
- background: getToken("extend.colors.primary.600")
153
- },
154
- //
155
- // Search
156
- //
157
- "&light .cm-searchMatch": {
158
- backgroundColor: getToken("extend.colors.yellow.100")
159
- },
160
- "&dark .cm-searchMatch": {
161
- backgroundColor: getToken("extend.colors.yellow.700")
162
- },
163
- //
164
- // link
165
- //
166
- ".cm-link": {
167
- textDecorationLine: "underline",
168
- textDecorationThickness: "1px",
169
- textUnderlineOffset: "2px",
170
- borderRadius: ".125rem",
171
- fontFamily: getToken("fontFamily.body")
172
- },
173
- "&light .cm-link > span": {
174
- color: getToken("extend.colors.primary.600")
175
- },
176
- "&dark .cm-link > span": {
177
- color: getToken("extend.colors.primary.400")
178
- },
179
- //
180
- // tooltip
181
- //
182
- ".cm-tooltip": {},
183
- "&light .cm-tooltip": {
184
- background: `${getToken("extend.colors.neutral.100")} !important`
185
- },
186
- "&dark .cm-tooltip": {
187
- background: `${getToken("extend.colors.neutral.900")} !important`
188
- },
189
- ".cm-tooltip-below": {},
190
- //
191
- // autocomplete
192
- // https://github.com/codemirror/autocomplete/blob/main/src/completion.ts
193
- //
194
- ".cm-tooltip.cm-tooltip-autocomplete": {
195
- marginTop: "4px",
196
- marginLeft: "-3px"
197
- },
198
- ".cm-tooltip.cm-tooltip-autocomplete > ul": {
199
- maxHeight: "20em !important"
200
- },
201
- ".cm-tooltip.cm-tooltip-autocomplete > ul > li": {},
202
- ".cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected]": {},
203
- ".cm-tooltip.cm-tooltip-autocomplete > ul > completion-section": {
204
- paddingLeft: "4px !important",
205
- borderBottom: "none !important",
206
- color: getToken("extend.colors.primary.500")
207
- },
208
- ".cm-tooltip.cm-completionInfo": {
209
- border: getToken("extend.colors.neutral.500"),
210
- width: "360px !important",
211
- margin: "-10px 1px 0 1px",
212
- padding: "8px !important"
213
- },
214
- ".cm-completionIcon": {
215
- display: "none"
216
- },
217
- ".cm-completionLabel": {
218
- fontFamily: getToken("fontFamily.body")
219
- },
220
- ".cm-completionMatchedText": {
221
- textDecoration: "none !important",
222
- opacity: 0.5
223
- },
224
- // TODO(burdon): Override vars --cm-background.
225
- // https://www.npmjs.com/package/codemirror-theme-vars
226
- /**
227
- * Panels
228
- * TODO(burdon): Needs styling attention (esp. dark mode).
229
- * https://github.com/codemirror/search/blob/main/src/search.ts#L745
230
- *
231
- * Find/replace panel.
232
- * <div class="cm-announced">...</div>
233
- * <div class="cm-scroller">...</div>
234
- * <div class="cm-panels cm-panels-bottom">
235
- * <div class="cm-search cm-panel">
236
- * <input class="cm-textfield" />
237
- * <button class="cm-button">...</button>
238
- * <label><input type="checkbox" />...</label>
239
- * </div>
240
- * </div
241
- */
242
- ".cm-panels": {},
243
- ".cm-panel": {
244
- fontFamily: getToken("fontFamily.body")
245
- },
246
- ".cm-panel input[type=checkbox]": {
247
- marginRight: "0.4rem !important"
248
- },
249
- "&light .cm-panel": {
250
- background: getToken("extend.colors.neutral.50")
251
- },
252
- "&dark .cm-panel": {
253
- background: getToken("extend.colors.neutral.850")
254
- },
255
- ".cm-button": {
256
- margin: "4px",
257
- fontFamily: getToken("fontFamily.body"),
258
- backgroundImage: "none",
259
- border: "none",
260
- "&:active": {
261
- backgroundImage: "none"
262
- }
263
- },
264
- "&light .cm-button": {
265
- background: getToken("extend.colors.neutral.100"),
266
- "&:hover": {
267
- background: getToken("extend.colors.neutral.200")
268
- },
269
- "&:active": {
270
- background: getToken("extend.colors.neutral.300")
271
- }
272
- },
273
- "&dark .cm-button": {
274
- background: getToken("extend.colors.neutral.800"),
275
- "&:hover": {
276
- background: getToken("extend.colors.neutral.700")
277
- },
278
- "&:active": {
279
- background: getToken("extend.colors.neutral.600")
280
- }
281
- },
282
- // TODO(burdon): Factor out element specific logic.
283
- //
284
- // table
285
- //
286
- ".cm-table *": {
287
- fontFamily: `${getToken("fontFamily.mono")} !important`,
288
- textDecoration: "none !important"
289
- },
290
- ".cm-table-head": {
291
- padding: "2px 16px 2px 0px",
292
- textAlign: "left",
293
- borderBottom: `1px solid ${getToken("extend.colors.primary.500")}`,
294
- color: getToken("extend.colors.neutral.500")
295
- },
296
- ".cm-table-cell": {
297
- padding: "2px 16px 2px 0px"
298
- },
299
- //
300
- // image
301
- //
302
- ".cm-image": {
303
- display: "block",
304
- height: "0"
305
- },
306
- ".cm-image.cm-loaded-image": {
307
- height: "auto",
308
- borderTop: "0.5rem solid transparent",
309
- borderBottom: "0.5rem solid transparent"
310
- }
311
- };
312
-
313
41
  // packages/ui/react-ui-editor/src/components/Toolbar/Toolbar.tsx
314
- import { ChatText, Code, CodeBlock, Image, Link, ListBullets, ListChecks, ListNumbers, Paragraph, Quotes, TextStrikethrough, Table as Table2, TextB, TextHOne, TextHTwo, TextHThree, TextHFour, TextHFive, TextHSix, TextItalic, CaretDown, Check, PencilSimpleSlash, MarkdownLogo, PencilSimple } from "@phosphor-icons/react";
42
+ import { ChatText, Code, CodeBlock, Image, Link, ListBullets, ListChecks, ListNumbers, MagnifyingGlass, Paragraph, Quotes, TextStrikethrough, Table as Table2, TextB, TextHOne, TextHTwo, TextHThree, TextHFour, TextHFive, TextHSix, TextItalic, CaretDown, Check, PencilSimpleSlash, MarkdownLogo, PencilSimple } from "@phosphor-icons/react";
315
43
  import { createContext } from "@radix-ui/react-context";
316
44
  import React3, { useEffect as useEffect2, useRef, useState as useState3 } from "react";
317
45
  import { useDropzone } from "react-dropzone";
@@ -412,11 +140,11 @@ var annotations = (options = {}) => {
412
140
  styles
413
141
  ];
414
142
  };
415
- var styles = EditorView.baseTheme({
143
+ var styles = EditorView.theme({
416
144
  ".cm-annotation": {
417
145
  textDecoration: "underline",
418
146
  textDecorationStyle: "wavy",
419
- textDecorationColor: "red"
147
+ textDecorationColor: "var(--dx-error)"
420
148
  }
421
149
  });
422
150
 
@@ -424,7 +152,7 @@ var styles = EditorView.baseTheme({
424
152
  import { autocompletion, completionKeymap } from "@codemirror/autocomplete";
425
153
  import { markdownLanguage } from "@codemirror/lang-markdown";
426
154
  import { keymap } from "@codemirror/view";
427
- var autocomplete = ({ activateOnTyping, onSearch } = {}) => {
155
+ var autocomplete = ({ activateOnTyping, override, onSearch } = {}) => {
428
156
  const extentions = [
429
157
  // https://codemirror.net/docs/ref/#view.keymap
430
158
  // https://discuss.codemirror.net/t/how-can-i-replace-the-default-autocompletion-keymap-v6/3322
@@ -434,6 +162,7 @@ var autocomplete = ({ activateOnTyping, onSearch } = {}) => {
434
162
  // https://codemirror.net/docs/ref/#autocomplete.autocompletion
435
163
  autocompletion({
436
164
  activateOnTyping,
165
+ override,
437
166
  // closeOnBlur: false,
438
167
  // defaultKeymap: false,
439
168
  // TODO(burdon): Styles/fragments.
@@ -932,7 +661,7 @@ var RemoteCaretWidget = class extends WidgetType {
932
661
  return true;
933
662
  }
934
663
  };
935
- var styles2 = EditorView3.baseTheme({
664
+ var styles2 = EditorView3.theme({
936
665
  ".cm-collab-selection": {},
937
666
  ".cm-collab-selectionLine": {
938
667
  padding: 0,
@@ -1755,50 +1484,17 @@ var commentsState = StateField4.define({
1755
1484
  return value;
1756
1485
  }
1757
1486
  });
1758
- var styles3 = EditorView7.baseTheme({
1487
+ var styles3 = EditorView7.theme({
1759
1488
  ".cm-comment, .cm-comment-current": {
1760
- cursor: "pointer",
1761
- borderWidth: "1px",
1762
- borderStyle: "solid",
1763
- borderRadius: "2px",
1764
- transition: "background-color 0.1s ease"
1765
- },
1766
- // Light theme.
1767
- "&light .cm-comment": {
1768
- backgroundColor: getToken("extend.colors.yellow.50"),
1769
- mixBlendMode: "darken",
1770
- borderColor: getToken("extend.colors.yellow.100")
1771
- },
1772
- "&light .cm-comment:hover": {
1773
- backgroundColor: getToken("extend.colors.yellow.100")
1774
- },
1775
- "&light .cm-comment-current": {
1776
- backgroundColor: getToken("extend.colors.primary.100"),
1777
- borderColor: getToken("extend.colors.primary.200")
1778
- },
1779
- "&light .cm-comment-current:hover": {
1780
- backgroundColor: getToken("extend.colors.primary.150"),
1781
- borderColor: getToken("extend.colors.primary.250")
1782
- },
1783
- // Dark theme.
1784
- "&dark .cm-comment": {
1785
- color: getToken("extend.colors.yellow.50"),
1786
- backgroundColor: getToken("extend.colors.yellow.800"),
1787
- borderColor: getToken("extend.colors.yellow.700"),
1788
- mixBlendMode: "plus-lighter"
1789
- },
1790
- "&dark .cm-comment:hover": {
1791
- backgroundColor: getToken("extend.colors.yellow.700"),
1792
- borderColor: getToken("extend.colors.yellow.650")
1793
- },
1794
- "&dark .cm-comment-current": {
1795
- color: getToken("extend.colors.primary.50"),
1796
- backgroundColor: getToken("extend.colors.primary.800"),
1797
- borderColor: getToken("extend.colors.primary.700")
1489
+ margin: "0 -3px",
1490
+ padding: "3px",
1491
+ borderRadius: "3px",
1492
+ backgroundColor: "var(--dx-cmCommentSurface)",
1493
+ color: "var(--dx-cmComment)",
1494
+ cursor: "pointer"
1798
1495
  },
1799
- "&dark .cm-comment-current:hover": {
1800
- backgroundColor: getToken("extend.colors.primary.700"),
1801
- borderColor: getToken("extend.colors.primary.650")
1496
+ ".cm-comment:hover, .cm-comment-current": {
1497
+ textDecoration: "underline"
1802
1498
  }
1803
1499
  });
1804
1500
  var createCommentMark = (id, isCurrent) => Decoration4.mark({
@@ -1817,7 +1513,7 @@ var commentsDecorations = EditorView7.decorations.compute([
1817
1513
  if (!range) {
1818
1514
  log5.warn("Invalid range:", range, {
1819
1515
  F: __dxlog_file7,
1820
- L: 181,
1516
+ L: 147,
1821
1517
  S: void 0,
1822
1518
  C: (f, a) => f(...a)
1823
1519
  });
@@ -2258,10 +1954,10 @@ var documentId2 = Facet5.define({
2258
1954
 
2259
1955
  // packages/ui/react-ui-editor/src/extensions/dnd.ts
2260
1956
  import { dropCursor, EditorView as EditorView8 } from "@codemirror/view";
2261
- var styles4 = EditorView8.baseTheme({
1957
+ var styles4 = EditorView8.theme({
2262
1958
  ".cm-dropCursor": {
2263
- borderLeft: `2px solid ${getToken("extend.colors.primary.500")}`,
2264
- color: getToken("extend.colors.primary.500"),
1959
+ borderLeft: "2px solid var(--dx-accentText)",
1960
+ color: "var(--dx-accentText)",
2265
1961
  padding: "0 4px"
2266
1962
  },
2267
1963
  ".cm-dropCursor:after": {
@@ -2300,67 +1996,293 @@ import { searchKeymap } from "@codemirror/search";
2300
1996
  import { EditorState } from "@codemirror/state";
2301
1997
  import { EditorView as EditorView9, drawSelection, dropCursor as dropCursor2, highlightActiveLine, keymap as keymap5, lineNumbers, placeholder, scrollPastEnd } from "@codemirror/view";
2302
1998
  import defaultsDeep2 from "lodash.defaultsdeep";
1999
+ import merge from "lodash.merge";
2303
2000
  import { generateName } from "@dxos/display-name";
2304
2001
  import { log as log6 } from "@dxos/log";
2305
2002
  import { hueTokens } from "@dxos/react-ui-theme";
2306
2003
  import { hexToHue, isNotFalsy as isNotFalsy2 } from "@dxos/util";
2307
- var __dxlog_file9 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/factories.ts";
2308
- var preventNewline = EditorState.transactionFilter.of((tr) => tr.newDoc.lines > 1 ? [] : tr);
2309
- var defaultBasicOptions = {
2310
- allowMultipleSelections: true,
2311
- bracketMatching: true,
2312
- closeBrackets: true,
2313
- drawSelection: true,
2314
- editable: true,
2315
- history: true,
2316
- keymap: "standard",
2317
- lineWrapping: true,
2318
- search: true
2004
+
2005
+ // packages/ui/react-ui-editor/src/styles/markdown.ts
2006
+ import { mx } from "@dxos/react-ui-theme";
2007
+ var headings = {
2008
+ 1: "text-4xl",
2009
+ 2: "text-3xl",
2010
+ 3: "text-2xl",
2011
+ 4: "text-xl",
2012
+ 5: "text-lg",
2013
+ 6: "text-md"
2319
2014
  };
2320
- var keymaps = {
2321
- // https://codemirror.net/docs/ref/#commands.standardKeymap
2322
- standard: standardKeymap,
2323
- // https://codemirror.net/docs/ref/#commands.defaultKeymap
2324
- default: defaultKeymap
2015
+ var theme = {
2016
+ mark: "opacity-50",
2017
+ code: "font-mono !no-underline text-neutral-700 dark:text-neutral-300",
2018
+ codeMark: "font-mono text-primary-500",
2019
+ // TODO(burdon): Replace with widget.
2020
+ blockquote: "pl-1 mr-1 border-is-4 border-orange-500 dark:border-orange-500 dark:text-neutral-500",
2021
+ heading: (level) => {
2022
+ return mx(headings[level], "dark:text-primary-400");
2023
+ }
2325
2024
  };
2326
- var createBasicExtensions = (_props) => {
2327
- const props = defaultsDeep2({}, _props, defaultBasicOptions);
2328
- return [
2329
- // NOTE: Doesn't catch errors in keymap functions.
2330
- EditorView9.exceptionSink.of((err) => {
2331
- log6.catch(err, void 0, {
2332
- F: __dxlog_file9,
2333
- L: 91,
2334
- S: void 0,
2335
- C: (f, a) => f(...a)
2336
- });
2337
- }),
2338
- props.allowMultipleSelections && EditorState.allowMultipleSelections.of(true),
2339
- props.bracketMatching && bracketMatching(),
2340
- props.closeBrackets && closeBrackets(),
2341
- props.dropCursor && dropCursor2(),
2342
- props.drawSelection && drawSelection({
2343
- cursorBlinkRate: 1200
2344
- }),
2345
- props.highlightActiveLine && highlightActiveLine(),
2346
- props.history && history(),
2347
- props.lineNumbers && lineNumbers(),
2348
- props.lineWrapping && EditorView9.lineWrapping,
2349
- props.placeholder && placeholder(props.placeholder),
2350
- props.readonly && [
2351
- EditorState.readOnly.of(true),
2352
- EditorView9.editable.of(false)
2353
- ],
2354
- props.scrollPastEnd && scrollPastEnd(),
2355
- props.tabSize && EditorState.tabSize.of(props.tabSize),
2356
- // https://codemirror.net/docs/ref/#view.KeyBinding
2357
- keymap5.of([
2358
- ...(props.keymap && keymaps[props.keymap]) ?? [],
2359
- // NOTE: Tabs are also configured by markdown extension.
2360
- // https://codemirror.net/docs/ref/#commands.indentWithTab
2361
- ...props.indentWithTab ? [
2362
- indentWithTab
2363
- ] : [],
2025
+
2026
+ // packages/ui/react-ui-editor/src/styles/tokens.ts
2027
+ import get from "lodash.get";
2028
+ import { tokens } from "@dxos/react-ui-theme";
2029
+ var getToken = (path, defaultValue) => {
2030
+ const value = get(tokens, path, defaultValue);
2031
+ return value?.toString() ?? "";
2032
+ };
2033
+ var fontBody = getToken("fontFamily.body");
2034
+ var fontMono = getToken("fontFamily.mono");
2035
+
2036
+ // packages/ui/react-ui-editor/src/styles/theme.ts
2037
+ var defaultTheme = {
2038
+ "&": {},
2039
+ "&.cm-focused": {
2040
+ outline: "none"
2041
+ },
2042
+ /**
2043
+ * Scroller
2044
+ */
2045
+ ".cm-scroller": {
2046
+ overflowY: "auto"
2047
+ },
2048
+ /**
2049
+ * Content
2050
+ * NOTE: Apply margins to content so that scrollbar is at the edge of the container.
2051
+ */
2052
+ ".cm-content": {
2053
+ padding: "unset",
2054
+ fontFamily: fontBody,
2055
+ // NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
2056
+ fontSize: "16px",
2057
+ lineHeight: 1.5,
2058
+ color: "unset"
2059
+ },
2060
+ /**
2061
+ * Gutters
2062
+ * NOTE: Gutters should have the same top margin as the content.
2063
+ */
2064
+ ".cm-gutters": {
2065
+ background: "unset"
2066
+ },
2067
+ ".cm-gutter": {},
2068
+ ".cm-gutterElement": {
2069
+ fontSize: "16px",
2070
+ lineHeight: 1.5
2071
+ },
2072
+ ".cm-lineNumbers": {
2073
+ minWidth: "36px"
2074
+ },
2075
+ /**
2076
+ * Line.
2077
+ */
2078
+ ".cm-line": {
2079
+ paddingInline: 0
2080
+ },
2081
+ ".cm-activeLine": {
2082
+ background: "var(--dx-hoverSurface)"
2083
+ },
2084
+ /**
2085
+ * Cursor (layer).
2086
+ */
2087
+ ".cm-cursor, .cm-dropCursor": {
2088
+ borderLeft: "2px solid var(--dx-cmCursor)"
2089
+ },
2090
+ ".cm-placeholder": {
2091
+ color: "var(--dx-subdued)"
2092
+ },
2093
+ /**
2094
+ * Selection (layer).
2095
+ */
2096
+ ".cm-selectionBackground": {
2097
+ background: "var(--dx-cmSelection)"
2098
+ },
2099
+ /**
2100
+ * Search.
2101
+ * NOTE: Matches comment.
2102
+ */
2103
+ ".cm-searchMatch": {
2104
+ margin: "0 -3px",
2105
+ padding: "3px",
2106
+ borderRadius: "3px",
2107
+ background: "var(--dx-cmHighlightSurface)",
2108
+ color: "var(--dx-cmHighlight)"
2109
+ },
2110
+ ".cm-searchMatch-selected": {
2111
+ textDecoration: "underline"
2112
+ },
2113
+ /**
2114
+ * Link.
2115
+ */
2116
+ ".cm-link": {
2117
+ textDecorationLine: "underline",
2118
+ textDecorationThickness: "1px",
2119
+ textUnderlineOffset: "2px",
2120
+ borderRadius: ".125rem"
2121
+ },
2122
+ ".cm-link > span": {
2123
+ color: "var(--dx-accentText)"
2124
+ },
2125
+ /**
2126
+ * Tooltip.
2127
+ */
2128
+ ".cm-tooltip": {
2129
+ background: "var(--dx-base)"
2130
+ },
2131
+ ".cm-tooltip-below": {},
2132
+ /**
2133
+ * Autocomplete.
2134
+ * https://github.com/codemirror/autocomplete/blob/main/src/completion.ts
2135
+ */
2136
+ ".cm-tooltip.cm-tooltip-autocomplete": {
2137
+ marginTop: "4px",
2138
+ marginLeft: "-3px"
2139
+ },
2140
+ ".cm-tooltip.cm-tooltip-autocomplete > ul": {
2141
+ maxHeight: "20em !important"
2142
+ },
2143
+ ".cm-tooltip.cm-tooltip-autocomplete > ul > li": {},
2144
+ ".cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected]": {},
2145
+ ".cm-tooltip.cm-tooltip-autocomplete > ul > completion-section": {
2146
+ paddingLeft: "4px !important",
2147
+ borderBottom: "none !important",
2148
+ color: "var(--dx-accentText)"
2149
+ },
2150
+ ".cm-tooltip.cm-completionInfo": {
2151
+ width: "360px !important",
2152
+ margin: "-10px 1px 0 1px",
2153
+ padding: "8px !important",
2154
+ borderColor: "var(--dx-separator)"
2155
+ },
2156
+ ".cm-completionIcon": {
2157
+ display: "none"
2158
+ },
2159
+ ".cm-completionLabel": {
2160
+ fontFamily: fontBody
2161
+ },
2162
+ ".cm-completionMatchedText": {
2163
+ textDecoration: "none !important",
2164
+ opacity: 0.5
2165
+ },
2166
+ /**
2167
+ * Panels
2168
+ * https://github.com/codemirror/search/blob/main/src/search.ts#L745
2169
+ *
2170
+ * Find/replace panel.
2171
+ * <div class="cm-announced">...</div>
2172
+ * <div class="cm-scroller">...</div>
2173
+ * <div class="cm-panels cm-panels-bottom">
2174
+ * <div class="cm-search cm-panel">
2175
+ * <input class="cm-textfield" />
2176
+ * <button class="cm-button">...</button>
2177
+ * <label><input type="checkbox" />...</label>
2178
+ * </div>
2179
+ * </div
2180
+ */
2181
+ // TODO(burdon): Apply react-ui-theme or replace panel.
2182
+ ".cm-panels": {},
2183
+ ".cm-panel": {
2184
+ fontFamily: fontBody,
2185
+ backgroundColor: "var(--dx-base)"
2186
+ },
2187
+ ".cm-panel input, .cm-panel button, .cm-panel label": {
2188
+ fontFamily: fontBody,
2189
+ fontSize: "14px",
2190
+ all: "unset",
2191
+ margin: "3px !important",
2192
+ padding: "2px 6px !important",
2193
+ outline: "1px solid transparent"
2194
+ },
2195
+ ".cm-panel input, .cm-panel button": {
2196
+ backgroundColor: "var(--dx-input)"
2197
+ },
2198
+ ".cm-panel input:focus, .cm-panel button:focus": {
2199
+ outline: "1px solid var(--dx-accentFocusIndicator)"
2200
+ },
2201
+ ".cm-panel label": {
2202
+ display: "inline-flex",
2203
+ alignItems: "center",
2204
+ cursor: "pointer"
2205
+ },
2206
+ ".cm-panel input.cm-textfield": {},
2207
+ ".cm-panel input[type=checkbox]": {
2208
+ width: "8px",
2209
+ height: "8px",
2210
+ marginRight: "6px !important",
2211
+ padding: "2px !important",
2212
+ color: "var(--dx-accentFocusIndicator)"
2213
+ },
2214
+ ".cm-panel button": {
2215
+ "&:hover": {
2216
+ backgroundColor: "var(--dx-accentSurfaceHover) !important"
2217
+ },
2218
+ "&:active": {
2219
+ backgroundColor: "var(--dx-accentSurfaceHover)"
2220
+ }
2221
+ },
2222
+ ".cm-panel.cm-search": {
2223
+ padding: "4px",
2224
+ borderTop: "1px solid var(--dx-separator)"
2225
+ }
2226
+ };
2227
+
2228
+ // packages/ui/react-ui-editor/src/extensions/factories.ts
2229
+ var __dxlog_file9 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/factories.ts";
2230
+ var preventNewline = EditorState.transactionFilter.of((tr) => tr.newDoc.lines > 1 ? [] : tr);
2231
+ var defaultBasicOptions = {
2232
+ allowMultipleSelections: true,
2233
+ bracketMatching: true,
2234
+ closeBrackets: true,
2235
+ drawSelection: true,
2236
+ editable: true,
2237
+ history: true,
2238
+ keymap: "standard",
2239
+ lineWrapping: true,
2240
+ search: true
2241
+ };
2242
+ var keymaps = {
2243
+ // https://codemirror.net/docs/ref/#commands.standardKeymap
2244
+ standard: standardKeymap,
2245
+ // https://codemirror.net/docs/ref/#commands.defaultKeymap
2246
+ default: defaultKeymap
2247
+ };
2248
+ var createBasicExtensions = (_props) => {
2249
+ const props = defaultsDeep2({}, _props, defaultBasicOptions);
2250
+ return [
2251
+ // NOTE: Doesn't catch errors in keymap functions.
2252
+ EditorView9.exceptionSink.of((err) => {
2253
+ log6.catch(err, void 0, {
2254
+ F: __dxlog_file9,
2255
+ L: 92,
2256
+ S: void 0,
2257
+ C: (f, a) => f(...a)
2258
+ });
2259
+ }),
2260
+ props.allowMultipleSelections && EditorState.allowMultipleSelections.of(true),
2261
+ props.bracketMatching && bracketMatching(),
2262
+ props.closeBrackets && closeBrackets(),
2263
+ props.dropCursor && dropCursor2(),
2264
+ props.drawSelection && drawSelection({
2265
+ cursorBlinkRate: 1200
2266
+ }),
2267
+ props.highlightActiveLine && highlightActiveLine(),
2268
+ props.history && history(),
2269
+ props.lineNumbers && lineNumbers(),
2270
+ props.lineWrapping && EditorView9.lineWrapping,
2271
+ props.placeholder && placeholder(props.placeholder),
2272
+ props.readonly && [
2273
+ EditorState.readOnly.of(true),
2274
+ EditorView9.editable.of(false)
2275
+ ],
2276
+ props.scrollPastEnd && scrollPastEnd(),
2277
+ props.tabSize && EditorState.tabSize.of(props.tabSize),
2278
+ // https://codemirror.net/docs/ref/#view.KeyBinding
2279
+ keymap5.of([
2280
+ ...(props.keymap && keymaps[props.keymap]) ?? [],
2281
+ // NOTE: Tabs are also configured by markdown extension.
2282
+ // https://codemirror.net/docs/ref/#commands.indentWithTab
2283
+ ...props.indentWithTab ? [
2284
+ indentWithTab
2285
+ ] : [],
2364
2286
  // https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
2365
2287
  ...props.closeBrackets ? closeBracketsKeymap : [],
2366
2288
  // https://codemirror.net/docs/ref/#commands.historyKeymap
@@ -2375,12 +2297,11 @@ var defaultThemeSlots = {
2375
2297
  className: "w-full bs-full"
2376
2298
  }
2377
2299
  };
2378
- var createThemeExtensions = ({ theme: theme2, themeMode, slots: _slots } = {}) => {
2300
+ var createThemeExtensions = ({ themeMode, styles: styles5, slots: _slots } = {}) => {
2379
2301
  const slots = defaultsDeep2({}, _slots, defaultThemeSlots);
2380
2302
  return [
2381
- EditorView9.baseTheme(defaultTheme),
2382
2303
  EditorView9.darkTheme.of(themeMode === "dark"),
2383
- theme2 && EditorView9.theme(theme2),
2304
+ EditorView9.baseTheme(styles5 ? merge({}, defaultTheme, styles5) : defaultTheme),
2384
2305
  slots.editor?.className && EditorView9.editorAttributes.of({
2385
2306
  class: slots.editor.className
2386
2307
  }),
@@ -2414,18 +2335,22 @@ var createDataExtensions = ({ id, text, space, identity }) => {
2414
2335
  // packages/ui/react-ui-editor/src/extensions/folding.tsx
2415
2336
  import { codeFolding, foldGutter } from "@codemirror/language";
2416
2337
  import React2 from "react";
2417
- import { getSize, mx as mx2 } from "@dxos/react-ui-theme";
2338
+ import { Icon } from "@dxos/react-ui";
2339
+ import { getSize } from "@dxos/react-ui-theme";
2418
2340
  var folding = (_props = {}) => [
2419
2341
  codeFolding({
2420
2342
  placeholderDOM: () => document.createElement("div")
2421
2343
  }),
2422
2344
  foldGutter({
2423
2345
  markerDOM: (open) => {
2424
- return renderRoot(document.createElement("div"), /* @__PURE__ */ React2.createElement("svg", {
2425
- className: mx2(getSize(3), "m-3 cursor-pointer", open && "rotate-90")
2426
- }, /* @__PURE__ */ React2.createElement("use", {
2427
- href: "/icons.svg#ph--caret-right--regular"
2428
- })));
2346
+ return renderRoot(document.createElement("div"), /* @__PURE__ */ React2.createElement(Icon, {
2347
+ icon: "ph--caret-right--regular",
2348
+ classNames: [
2349
+ getSize(3),
2350
+ "m-2 cursor-pointer",
2351
+ open && "rotate-90"
2352
+ ]
2353
+ }));
2429
2354
  }
2430
2355
  })
2431
2356
  ];
@@ -2446,7 +2371,6 @@ var listener = ({ onFocus, onChange }) => {
2446
2371
 
2447
2372
  // packages/ui/react-ui-editor/src/extensions/markdown/formatting.ts
2448
2373
  import { snippet } from "@codemirror/autocomplete";
2449
- import { indentWithTab as indentWithTab2 } from "@codemirror/commands";
2450
2374
  import { syntaxTree as syntaxTree2 } from "@codemirror/language";
2451
2375
  import { EditorSelection } from "@codemirror/state";
2452
2376
  import { EditorView as EditorView11, keymap as keymap6 } from "@codemirror/view";
@@ -3607,7 +3531,7 @@ var processAction = (view, action) => {
3607
3531
 
3608
3532
  // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
3609
3533
  import { completionKeymap as completionKeymap2 } from "@codemirror/autocomplete";
3610
- import { defaultKeymap as defaultKeymap2, indentWithTab as indentWithTab3 } from "@codemirror/commands";
3534
+ import { defaultKeymap as defaultKeymap2, indentWithTab as indentWithTab2 } from "@codemirror/commands";
3611
3535
  import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
3612
3536
  import { defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
3613
3537
  import { languages } from "@codemirror/language-data";
@@ -3795,7 +3719,7 @@ var markdownHighlightStyle = (_options = {}) => {
3795
3719
  ], {
3796
3720
  scope: markdownLanguage2,
3797
3721
  all: {
3798
- fontFamily: getToken("fontFamily.body")
3722
+ fontFamily: fontBody
3799
3723
  }
3800
3724
  });
3801
3725
  };
@@ -3828,9 +3752,8 @@ var createMarkdownExtensions = ({ themeMode } = {}) => {
3828
3752
  // Custom styles.
3829
3753
  syntaxHighlighting(markdownHighlightStyle()),
3830
3754
  keymap7.of([
3831
- // TODO(burdon): Indent by 4 if in task list.
3832
3755
  // https://codemirror.net/docs/ref/#commands.indentWithTab
3833
- indentWithTab3,
3756
+ indentWithTab2,
3834
3757
  // https://codemirror.net/docs/ref/#commands.defaultKeymap
3835
3758
  ...defaultKeymap2,
3836
3759
  ...completionKeymap2,
@@ -3839,128 +3762,130 @@ var createMarkdownExtensions = ({ themeMode } = {}) => {
3839
3762
  ];
3840
3763
  };
3841
3764
 
3765
+ // packages/ui/react-ui-editor/src/extensions/markdown/debug.ts
3766
+ import { syntaxTree as syntaxTree3 } from "@codemirror/language";
3767
+ import { StateField as StateField6 } from "@codemirror/state";
3768
+ var debugTree = (cb) => StateField6.define({
3769
+ create: (state2) => cb(convertTreeToJson(state2)),
3770
+ update: (value, tr) => cb(convertTreeToJson(tr.state))
3771
+ });
3772
+ var convertTreeToJson = (state2) => {
3773
+ const treeToJson = (cursor) => {
3774
+ const node = {
3775
+ type: cursor.type.name,
3776
+ from: cursor.from,
3777
+ to: cursor.to,
3778
+ text: state2.doc.slice(cursor.from, cursor.to).toString(),
3779
+ children: []
3780
+ };
3781
+ if (cursor.firstChild()) {
3782
+ do {
3783
+ node.children.push(treeToJson(cursor));
3784
+ } while (cursor.nextSibling());
3785
+ cursor.parent();
3786
+ }
3787
+ return node;
3788
+ };
3789
+ return treeToJson(syntaxTree3(state2).cursor());
3790
+ };
3791
+
3842
3792
  // packages/ui/react-ui-editor/src/extensions/markdown/decorate.ts
3843
- import { syntaxTree as syntaxTree6 } from "@codemirror/language";
3793
+ import { syntaxTree as syntaxTree7 } from "@codemirror/language";
3844
3794
  import { RangeSetBuilder as RangeSetBuilder3, StateEffect as StateEffect4 } from "@codemirror/state";
3845
- import { EditorView as EditorView14, Decoration as Decoration7, WidgetType as WidgetType5, ViewPlugin as ViewPlugin6 } from "@codemirror/view";
3795
+ import { EditorView as EditorView15, Decoration as Decoration7, WidgetType as WidgetType5, ViewPlugin as ViewPlugin6 } from "@codemirror/view";
3846
3796
  import { invariant as invariant4 } from "@dxos/invariant";
3847
- import { mx as mx3 } from "@dxos/react-ui-theme";
3797
+ import { mx as mx2 } from "@dxos/react-ui-theme";
3848
3798
 
3849
- // packages/ui/react-ui-editor/src/extensions/markdown/image.ts
3850
- import { syntaxTree as syntaxTree3 } from "@codemirror/language";
3851
- import { StateField as StateField6 } from "@codemirror/state";
3852
- import { Decoration as Decoration5, EditorView as EditorView12, WidgetType as WidgetType3 } from "@codemirror/view";
3853
- var image = (_options = {}) => {
3854
- return StateField6.define({
3855
- create: (state2) => {
3856
- return Decoration5.set(buildDecorations(0, state2.doc.length, state2));
3857
- },
3858
- update: (value, tr) => {
3859
- if (!tr.docChanged && !tr.selection) {
3860
- return value;
3799
+ // packages/ui/react-ui-editor/src/extensions/markdown/changes.ts
3800
+ import { syntaxTree as syntaxTree4 } from "@codemirror/language";
3801
+ import { Transaction } from "@codemirror/state";
3802
+ import { ViewPlugin as ViewPlugin5 } from "@codemirror/view";
3803
+ var adjustChanges = () => {
3804
+ return ViewPlugin5.fromClass(class {
3805
+ update(update2) {
3806
+ const tree = syntaxTree4(update2.state);
3807
+ const adjustments = [];
3808
+ for (const tr of update2.transactions) {
3809
+ const event = tr.annotation(Transaction.userEvent);
3810
+ switch (event) {
3811
+ case "input": {
3812
+ const changes = tr.changes;
3813
+ if (changes.empty) {
3814
+ break;
3815
+ }
3816
+ changes.iterChanges((fromA) => {
3817
+ const node = tree.resolveInner(fromA, 1);
3818
+ if (node?.name === "BulletList") {
3819
+ const { text } = update2.state.doc.lineAt(fromA);
3820
+ if (text.endsWith("]")) {
3821
+ adjustments.push({
3822
+ from: fromA,
3823
+ to: fromA,
3824
+ insert: " "
3825
+ });
3826
+ }
3827
+ }
3828
+ });
3829
+ break;
3830
+ }
3831
+ case "input.paste": {
3832
+ const changes = tr.changes;
3833
+ if (changes.empty) {
3834
+ break;
3835
+ }
3836
+ changes.iterChanges((fromA, toA, fromB, toB, text) => {
3837
+ const url = getValidUrl(update2.view.state.sliceDoc(fromB, toB));
3838
+ if (url) {
3839
+ const node = tree.resolveInner(fromA, -1);
3840
+ const invalidPositions = /* @__PURE__ */ new Set([
3841
+ "Link",
3842
+ "LinkMark",
3843
+ "Code",
3844
+ "CodeText",
3845
+ "FencedCode",
3846
+ "URL"
3847
+ ]);
3848
+ if (!invalidPositions.has(node?.name)) {
3849
+ const replacedText = tr.startState.sliceDoc(fromA, toA);
3850
+ adjustments.push({
3851
+ from: fromA,
3852
+ to: toB,
3853
+ insert: createLink(url, replacedText)
3854
+ });
3855
+ }
3856
+ } else {
3857
+ const node = tree.resolveInner(fromA, 1);
3858
+ switch (node?.name) {
3859
+ case "Task": {
3860
+ const str = text.toString();
3861
+ const match = str.match(/\s*- \[[ xX]\]\s*(.+)/);
3862
+ if (match) {
3863
+ const [, replacement] = match;
3864
+ adjustments.push({
3865
+ from: fromA,
3866
+ to: toB,
3867
+ insert: replacement
3868
+ });
3869
+ }
3870
+ break;
3871
+ }
3872
+ }
3873
+ }
3874
+ });
3875
+ break;
3876
+ }
3877
+ }
3861
3878
  }
3862
- const cursor = tr.state.selection.main.head;
3863
- const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
3864
- let from = Math.min(cursor, oldCursor);
3865
- let to = Math.max(cursor, oldCursor);
3866
- tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
3867
- from = Math.min(from, fromB);
3868
- to = Math.max(to, toB);
3869
- });
3870
- from = tr.state.doc.lineAt(from).from;
3871
- to = tr.state.doc.lineAt(to).to;
3872
- return value.map(tr.changes).update({
3873
- filterFrom: from,
3874
- filterTo: to,
3875
- filter: () => false,
3876
- add: buildDecorations(from, to, tr.state)
3877
- });
3878
- },
3879
- provide: (field) => EditorView12.decorations.from(field)
3880
- });
3881
- };
3882
- var preloaded = /* @__PURE__ */ new Set();
3883
- var preloadImage = (url) => {
3884
- if (!preloaded.has(url)) {
3885
- const img = document.createElement("img");
3886
- img.src = url;
3887
- preloaded.add(url);
3888
- }
3889
- };
3890
- var buildDecorations = (from, to, state2) => {
3891
- const decorations = [];
3892
- const cursor = state2.selection.main.head;
3893
- syntaxTree3(state2).iterate({
3894
- enter: (node) => {
3895
- if (node.name === "Image") {
3896
- const urlNode = node.node.getChild("URL");
3897
- if (urlNode) {
3898
- const hide2 = state2.readOnly || cursor < node.from || cursor > node.to;
3899
- const url = state2.sliceDoc(urlNode.from, urlNode.to);
3900
- preloadImage(url);
3901
- decorations.push(Decoration5.replace({
3902
- block: true,
3903
- widget: new ImageWidget(url)
3904
- }).range(hide2 ? node.from : node.to, node.to));
3905
- }
3906
- }
3907
- },
3908
- from,
3909
- to
3910
- });
3911
- return decorations;
3912
- };
3913
- var ImageWidget = class extends WidgetType3 {
3914
- constructor(_url) {
3915
- super();
3916
- this._url = _url;
3917
- }
3918
- eq(other) {
3919
- return this._url === other._url;
3920
- }
3921
- toDOM(view) {
3922
- const img = document.createElement("img");
3923
- img.setAttribute("src", this._url);
3924
- img.setAttribute("class", "cm-image");
3925
- img.onload = () => img.classList.add("cm-loaded-image");
3926
- return img;
3927
- }
3928
- };
3929
- var imageUpload = (options = {}) => {
3930
- };
3931
-
3932
- // packages/ui/react-ui-editor/src/extensions/markdown/link-paste.ts
3933
- import { syntaxTree as syntaxTree4 } from "@codemirror/language";
3934
- import { Transaction } from "@codemirror/state";
3935
- import { ViewPlugin as ViewPlugin5 } from "@codemirror/view";
3936
- var linkPastePlugin = ViewPlugin5.fromClass(class {
3937
- update(update2) {
3938
- for (const tr of update2.transactions) {
3939
- const event = tr.annotation(Transaction.userEvent);
3940
- if (event === "input.paste") {
3941
- const changes = tr.changes;
3942
- if (changes.empty) {
3943
- return;
3944
- }
3945
- changes.iterChangedRanges((fromA, toA, fromB, toB) => {
3946
- const insertedUrl = getValidUrl(update2.view.state.sliceDoc(fromB, toB));
3947
- if (insertedUrl && isValidPosition(update2.view.state, fromB)) {
3948
- const replacedText = tr.startState.sliceDoc(fromA, toA);
3949
- setTimeout(() => {
3950
- update2.view.dispatch(update2.view.state.update({
3951
- changes: {
3952
- from: fromA,
3953
- to: toB,
3954
- insert: createLink(insertedUrl, replacedText)
3955
- }
3956
- }));
3957
- });
3958
- }
3879
+ if (adjustments.length) {
3880
+ setTimeout(() => {
3881
+ update2.view.dispatch(update2.view.state.update({
3882
+ changes: adjustments
3883
+ }));
3959
3884
  });
3960
3885
  }
3961
3886
  }
3962
- }
3963
- });
3887
+ });
3888
+ };
3964
3889
  var createLink = (url, label) => {
3965
3890
  const { host, pathname } = url;
3966
3891
  const [, extension] = pathname.split(".");
@@ -4008,33 +3933,191 @@ var getValidUrl = (str) => {
4008
3933
  return void 0;
4009
3934
  }
4010
3935
  };
4011
- var isValidPosition = (state2, pos) => {
4012
- const invalidPositions = /* @__PURE__ */ new Set([
4013
- "Link",
4014
- "LinkMark",
4015
- "Code",
4016
- "FencedCode"
4017
- ]);
4018
- const tree = syntaxTree4(state2);
4019
- let node = tree.resolveInner(pos, -1);
4020
- while (node) {
4021
- if (invalidPositions.has(node.name)) {
4022
- return false;
4023
- }
4024
- node = node.parent;
3936
+
3937
+ // packages/ui/react-ui-editor/src/extensions/markdown/image.ts
3938
+ import { syntaxTree as syntaxTree5 } from "@codemirror/language";
3939
+ import { StateField as StateField7 } from "@codemirror/state";
3940
+ import { Decoration as Decoration5, EditorView as EditorView12, WidgetType as WidgetType3 } from "@codemirror/view";
3941
+ var image = (_options = {}) => {
3942
+ return StateField7.define({
3943
+ create: (state2) => {
3944
+ return Decoration5.set(buildDecorations(0, state2.doc.length, state2));
3945
+ },
3946
+ update: (value, tr) => {
3947
+ if (!tr.docChanged && !tr.selection) {
3948
+ return value;
3949
+ }
3950
+ const cursor = tr.state.selection.main.head;
3951
+ const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
3952
+ let from = Math.min(cursor, oldCursor);
3953
+ let to = Math.max(cursor, oldCursor);
3954
+ tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
3955
+ from = Math.min(from, fromB);
3956
+ to = Math.max(to, toB);
3957
+ });
3958
+ from = tr.state.doc.lineAt(from).from;
3959
+ to = tr.state.doc.lineAt(to).to;
3960
+ return value.map(tr.changes).update({
3961
+ filterFrom: from,
3962
+ filterTo: to,
3963
+ filter: () => false,
3964
+ add: buildDecorations(from, to, tr.state)
3965
+ });
3966
+ },
3967
+ provide: (field) => EditorView12.decorations.from(field)
3968
+ });
3969
+ };
3970
+ var preloaded = /* @__PURE__ */ new Set();
3971
+ var preloadImage = (url) => {
3972
+ if (!preloaded.has(url)) {
3973
+ const img = document.createElement("img");
3974
+ img.src = url;
3975
+ preloaded.add(url);
4025
3976
  }
4026
- return true;
4027
3977
  };
3978
+ var buildDecorations = (from, to, state2) => {
3979
+ const decorations = [];
3980
+ const cursor = state2.selection.main.head;
3981
+ syntaxTree5(state2).iterate({
3982
+ enter: (node) => {
3983
+ if (node.name === "Image") {
3984
+ const urlNode = node.node.getChild("URL");
3985
+ if (urlNode) {
3986
+ const hide2 = state2.readOnly || cursor < node.from || cursor > node.to;
3987
+ const url = state2.sliceDoc(urlNode.from, urlNode.to);
3988
+ preloadImage(url);
3989
+ decorations.push(Decoration5.replace({
3990
+ block: true,
3991
+ widget: new ImageWidget(url)
3992
+ }).range(hide2 ? node.from : node.to, node.to));
3993
+ }
3994
+ }
3995
+ },
3996
+ from,
3997
+ to
3998
+ });
3999
+ return decorations;
4000
+ };
4001
+ var ImageWidget = class extends WidgetType3 {
4002
+ constructor(_url) {
4003
+ super();
4004
+ this._url = _url;
4005
+ }
4006
+ eq(other) {
4007
+ return this._url === other._url;
4008
+ }
4009
+ toDOM(view) {
4010
+ const img = document.createElement("img");
4011
+ img.setAttribute("src", this._url);
4012
+ img.setAttribute("class", "cm-image");
4013
+ img.onload = () => img.classList.add("cm-loaded-image");
4014
+ return img;
4015
+ }
4016
+ };
4017
+ var imageUpload = (options = {}) => {
4018
+ };
4019
+
4020
+ // packages/ui/react-ui-editor/src/extensions/markdown/styles.ts
4021
+ import { EditorView as EditorView13 } from "@codemirror/view";
4022
+ var bulletListIndentationWidth = 24;
4023
+ var orderedListIndentationWidth = 36;
4024
+ var formattingStyles = EditorView13.theme({
4025
+ /**
4026
+ * Horizontal rule.
4027
+ */
4028
+ "& .cm-hr": {
4029
+ display: "inline-block",
4030
+ width: "100%",
4031
+ height: "0",
4032
+ verticalAlign: "middle",
4033
+ borderTop: "1px solid var(--dx-cmSeparator)",
4034
+ opacity: 0.5
4035
+ },
4036
+ /**
4037
+ * Lists.
4038
+ */
4039
+ "& .cm-list-item": {},
4040
+ "& .cm-list-mark": {
4041
+ display: "inline-block",
4042
+ textAlign: "right",
4043
+ paddingRight: "0.5em",
4044
+ fontVariant: "tabular-nums"
4045
+ },
4046
+ "& .cm-list-mark-bullet": {
4047
+ width: `${bulletListIndentationWidth}px`
4048
+ },
4049
+ "& .cm-list-mark-ordered": {
4050
+ width: `${orderedListIndentationWidth}px`
4051
+ },
4052
+ /**
4053
+ * Code and codeblocks.
4054
+ */
4055
+ "& .cm-code": {
4056
+ fontFamily: fontMono
4057
+ },
4058
+ "& .cm-codeblock-line": {
4059
+ background: "var(--dx-cmCodeblock)",
4060
+ paddingInline: "1rem !important"
4061
+ },
4062
+ "& .cm-codeblock-first": {
4063
+ borderTopLeftRadius: ".25rem",
4064
+ borderTopRightRadius: ".25rem"
4065
+ },
4066
+ "& .cm-codeblock-last": {
4067
+ borderBottomLeftRadius: ".25rem",
4068
+ borderBottomRightRadius: ".25rem"
4069
+ },
4070
+ /**
4071
+ * Task list.
4072
+ */
4073
+ "& .cm-task": {
4074
+ display: "inline-block",
4075
+ width: `${bulletListIndentationWidth}px`
4076
+ },
4077
+ "& .cm-task-checkbox": {
4078
+ display: "grid",
4079
+ margin: "0",
4080
+ transform: "translateY(2px)"
4081
+ },
4082
+ /**
4083
+ * Table.
4084
+ */
4085
+ ".cm-table *": {
4086
+ fontFamily: fontMono,
4087
+ textDecoration: "none !important"
4088
+ },
4089
+ ".cm-table-head": {
4090
+ padding: "2px 16px 2px 0px",
4091
+ textAlign: "left",
4092
+ borderBottom: "1px solid var(--dx-cmSeparator)",
4093
+ color: "var(--dx-subdued)"
4094
+ },
4095
+ ".cm-table-cell": {
4096
+ padding: "2px 16px 2px 0px"
4097
+ },
4098
+ /**
4099
+ * Image.
4100
+ */
4101
+ ".cm-image": {
4102
+ display: "block",
4103
+ height: "0"
4104
+ },
4105
+ ".cm-image.cm-loaded-image": {
4106
+ height: "auto",
4107
+ borderTop: "0.5rem solid transparent",
4108
+ borderBottom: "0.5rem solid transparent"
4109
+ }
4110
+ });
4028
4111
 
4029
4112
  // packages/ui/react-ui-editor/src/extensions/markdown/table.ts
4030
- import { syntaxTree as syntaxTree5 } from "@codemirror/language";
4031
- import { RangeSetBuilder as RangeSetBuilder2, StateField as StateField7 } from "@codemirror/state";
4032
- import { Decoration as Decoration6, EditorView as EditorView13, WidgetType as WidgetType4 } from "@codemirror/view";
4113
+ import { syntaxTree as syntaxTree6 } from "@codemirror/language";
4114
+ import { RangeSetBuilder as RangeSetBuilder2, StateField as StateField8 } from "@codemirror/state";
4115
+ import { Decoration as Decoration6, EditorView as EditorView14, WidgetType as WidgetType4 } from "@codemirror/view";
4033
4116
  var table = (options = {}) => {
4034
- return StateField7.define({
4117
+ return StateField8.define({
4035
4118
  create: (state2) => update(state2, options),
4036
4119
  update: (_, tr) => update(tr.state, options),
4037
- provide: (field) => EditorView13.decorations.from(field)
4120
+ provide: (field) => EditorView14.decorations.from(field)
4038
4121
  });
4039
4122
  };
4040
4123
  var update = (state2, _options) => {
@@ -4046,7 +4129,7 @@ var update = (state2, _options) => {
4046
4129
  const table2 = getTable();
4047
4130
  return table2.rows?.[table2.rows.length - 1];
4048
4131
  };
4049
- syntaxTree5(state2).iterate({
4132
+ syntaxTree6(state2).iterate({
4050
4133
  enter: (node) => {
4051
4134
  switch (node.name) {
4052
4135
  case "Table": {
@@ -4207,13 +4290,13 @@ var TextWidget = class extends WidgetType5 {
4207
4290
  };
4208
4291
  var hide = Decoration7.replace({});
4209
4292
  var fencedCodeLine = Decoration7.line({
4210
- class: mx3("cm-code cm-codeblock-line")
4293
+ class: mx2("cm-code cm-codeblock-line")
4211
4294
  });
4212
4295
  var fencedCodeLineFirst = Decoration7.line({
4213
- class: mx3("cm-code cm-codeblock-line", "cm-codeblock-first")
4296
+ class: mx2("cm-code cm-codeblock-line", "cm-codeblock-first")
4214
4297
  });
4215
4298
  var fencedCodeLineLast = Decoration7.line({
4216
- class: mx3("cm-code cm-codeblock-line", "cm-codeblock-last")
4299
+ class: mx2("cm-code cm-codeblock-line", "cm-codeblock-last")
4217
4300
  });
4218
4301
  var commentBlockLine = fencedCodeLine;
4219
4302
  var commentBlockLineFirst = fencedCodeLineFirst;
@@ -4239,8 +4322,6 @@ var autoHideTags = /* @__PURE__ */ new Set([
4239
4322
  "SubscriptMark",
4240
4323
  "SuperscriptMark"
4241
4324
  ]);
4242
- var bulletListIndentationWidth = 24;
4243
- var orderedListIndentationWidth = 36;
4244
4325
  var buildDecorations2 = (view, options, focus) => {
4245
4326
  const deco = new RangeSetBuilder3();
4246
4327
  const atomicDeco = new RangeSetBuilder3();
@@ -4249,7 +4330,7 @@ var buildDecorations2 = (view, options, focus) => {
4249
4330
  const getHeaderLevels = (node, level) => {
4250
4331
  invariant4(level > 0, void 0, {
4251
4332
  F: __dxlog_file10,
4252
- L: 159,
4333
+ L: 157,
4253
4334
  S: void 0,
4254
4335
  A: [
4255
4336
  "level > 0",
@@ -4285,10 +4366,10 @@ var buildDecorations2 = (view, options, focus) => {
4285
4366
  const leaveList = () => {
4286
4367
  listLevels.pop();
4287
4368
  };
4288
- const getCurrentList = () => {
4369
+ const getCurrentListLevel = () => {
4289
4370
  invariant4(listLevels.length, void 0, {
4290
4371
  F: __dxlog_file10,
4291
- L: 181,
4372
+ L: 179,
4292
4373
  S: void 0,
4293
4374
  A: [
4294
4375
  "listLevels.length",
@@ -4338,7 +4419,7 @@ var buildDecorations2 = (view, options, focus) => {
4338
4419
  break;
4339
4420
  }
4340
4421
  case "ListItem": {
4341
- const list = getCurrentList();
4422
+ const list = getCurrentListLevel();
4342
4423
  const width = list.type === "OrderedList" ? orderedListIndentationWidth : bulletListIndentationWidth;
4343
4424
  const offset = ((list.level ?? 0) + 1) * width;
4344
4425
  const line = state2.doc.lineAt(node.from);
@@ -4364,11 +4445,7 @@ var buildDecorations2 = (view, options, focus) => {
4364
4445
  atomicDeco.add(node.from, node.to + 1, hide);
4365
4446
  break;
4366
4447
  }
4367
- const list = getCurrentList();
4368
- const text = state2.doc.sliceString(node.from, node.to + 1);
4369
- if (list.type === "BulletList" && text[1] !== " ") {
4370
- return false;
4371
- }
4448
+ const list = getCurrentListLevel();
4372
4449
  const label = list.type === "OrderedList" ? `${++list.number}.` : "\u2022";
4373
4450
  atomicDeco.add(node.from, node.to + 1, Decoration7.replace({
4374
4451
  widget: new TextWidget(label, list.type === "OrderedList" ? "cm-list-mark cm-list-mark-ordered" : "cm-list-mark cm-list-mark-bullet")
@@ -4468,7 +4545,7 @@ var buildDecorations2 = (view, options, focus) => {
4468
4545
  }
4469
4546
  }
4470
4547
  };
4471
- const tree = syntaxTree6(state2);
4548
+ const tree = syntaxTree7(state2);
4472
4549
  if (options.numberedHeadings?.from === void 0) {
4473
4550
  for (const { from, to } of view.visibleRanges) {
4474
4551
  tree.iterate({
@@ -4497,13 +4574,14 @@ var decorateMarkdown = (options = {}) => {
4497
4574
  ({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations2(view, options, view.hasFocus));
4498
4575
  }
4499
4576
  update(update2) {
4500
- if (update2.docChanged || update2.viewportChanged || update2.focusChanged || update2.transactions.some((tr) => tr.effects.some((e) => e.is(forceUpdate))) || update2.selectionSet && !options.selectionChangeDelay) {
4577
+ if (update2.docChanged || update2.viewportChanged || update2.focusChanged || update2.transactions.some((tr) => tr.effects.some((effect) => effect.is(forceUpdate))) || update2.selectionSet && !options.selectionChangeDelay) {
4501
4578
  ({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations2(update2.view, options, update2.view.hasFocus));
4502
4579
  this.clearUpdate();
4503
4580
  } else if (update2.selectionSet) {
4504
4581
  this.scheduleUpdate(update2.view);
4505
4582
  }
4506
4583
  }
4584
+ // Defer update in case moving through the document.
4507
4585
  scheduleUpdate(view) {
4508
4586
  this.clearUpdate();
4509
4587
  this.pendingUpdate = setTimeout(() => {
@@ -4523,89 +4601,24 @@ var decorateMarkdown = (options = {}) => {
4523
4601
  }
4524
4602
  }, {
4525
4603
  provide: (plugin) => [
4526
- EditorView14.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration7.none),
4527
- EditorView14.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration7.none),
4528
- EditorView14.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration7.none)
4604
+ EditorView15.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration7.none),
4605
+ EditorView15.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration7.none),
4606
+ EditorView15.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration7.none)
4529
4607
  ]
4530
4608
  }),
4531
- formattingStyles,
4532
- linkPastePlugin,
4533
4609
  image(),
4534
- table()
4610
+ table(),
4611
+ adjustChanges(),
4612
+ formattingStyles
4535
4613
  ];
4536
4614
  };
4537
- var formattingStyles = EditorView14.baseTheme({
4538
- "& .cm-code": {
4539
- fontFamily: getToken("fontFamily.mono")
4540
- },
4541
- "& .cm-codeblock-line": {
4542
- paddingInline: "1rem !important"
4543
- },
4544
- "& .cm-codeblock-end": {
4545
- display: "inline-block",
4546
- width: "100%",
4547
- position: "relative",
4548
- "&::after": {
4549
- position: "absolute",
4550
- inset: 0,
4551
- content: '""'
4552
- }
4553
- },
4554
- "& .cm-codeblock-first": {
4555
- borderTopLeftRadius: ".25rem",
4556
- borderTopRightRadius: ".25rem"
4557
- },
4558
- "& .cm-codeblock-last": {
4559
- borderBottomLeftRadius: ".25rem",
4560
- borderBottomRightRadius: ".25rem"
4561
- },
4562
- "&light .cm-codeblock-line, &light .cm-activeLine.cm-codeblock-line": {
4563
- background: getToken("extend.semanticColors.input.light"),
4564
- mixBlendMode: "darken"
4565
- },
4566
- "&dark .cm-codeblock-line, &dark .cm-activeLine.cm-codeblock-line": {
4567
- background: getToken("extend.semanticColors.input.dark"),
4568
- mixBlendMode: "lighten"
4569
- },
4570
- "& .cm-hr": {
4571
- display: "inline-block",
4572
- width: "100%",
4573
- height: "0",
4574
- verticalAlign: "middle",
4575
- borderTop: `1px solid ${getToken("extend.colors.primary.500")}`,
4576
- opacity: 0.5
4577
- },
4578
- "& .cm-task": {
4579
- display: "inline-block",
4580
- width: `${bulletListIndentationWidth}px`,
4581
- color: getToken("extend.colors.blue.500")
4582
- },
4583
- "& .cm-task-checkbox": {
4584
- display: "grid",
4585
- margin: "0",
4586
- transform: "translateY(2px)"
4587
- },
4588
- "& .cm-list-item": {},
4589
- "& .cm-list-mark": {
4590
- display: "inline-block",
4591
- textAlign: "right",
4592
- paddingRight: "0.5em",
4593
- fontVariant: "tabular-nums"
4594
- },
4595
- "& .cm-list-mark-bullet": {
4596
- width: `${bulletListIndentationWidth}px`
4597
- },
4598
- "& .cm-list-mark-ordered": {
4599
- width: `${orderedListIndentationWidth}px`
4600
- }
4601
- });
4602
4615
 
4603
4616
  // packages/ui/react-ui-editor/src/extensions/markdown/link.ts
4604
- import { syntaxTree as syntaxTree7 } from "@codemirror/language";
4617
+ import { syntaxTree as syntaxTree8 } from "@codemirror/language";
4605
4618
  import { hoverTooltip as hoverTooltip2 } from "@codemirror/view";
4606
4619
  import { tooltipContent } from "@dxos/react-ui-theme";
4607
4620
  var linkTooltip = (render) => hoverTooltip2((view, pos, side) => {
4608
- const syntax = syntaxTree7(view.state).resolveInner(pos, side);
4621
+ const syntax = syntaxTree8(view.state).resolveInner(pos, side);
4609
4622
  let link = null;
4610
4623
  for (let i = 0, node = syntax; !link && node && i < 5; node = node.parent, i++) {
4611
4624
  link = node.name === "Link" ? node : null;
@@ -4723,7 +4736,7 @@ var InputModeExtensions = {
4723
4736
 
4724
4737
  // packages/ui/react-ui-editor/src/extensions/state.ts
4725
4738
  import { Transaction as Transaction2 } from "@codemirror/state";
4726
- import { EditorView as EditorView15, keymap as keymap9 } from "@codemirror/view";
4739
+ import { EditorView as EditorView16, keymap as keymap9 } from "@codemirror/view";
4727
4740
  import { debounce as debounce2 } from "@dxos/async";
4728
4741
  import { invariant as invariant5 } from "@dxos/invariant";
4729
4742
  import { isNotFalsy as isNotFalsy3 } from "@dxos/util";
@@ -4761,7 +4774,7 @@ var createEditorStateTransaction = ({ scrollTo, selection }) => {
4761
4774
  return {
4762
4775
  selection,
4763
4776
  scrollIntoView: !scrollTo,
4764
- effects: scrollTo ? EditorView15.scrollIntoView(scrollTo, {
4777
+ effects: scrollTo ? EditorView16.scrollIntoView(scrollTo, {
4765
4778
  yMargin: 96
4766
4779
  }) : void 0,
4767
4780
  annotations: Transaction2.userEvent.of(stateRestoreAnnotation)
@@ -4776,7 +4789,7 @@ var state = ({ getState, setState } = {}) => {
4776
4789
  // setStateDebounced(id, {});
4777
4790
  // },
4778
4791
  // }),
4779
- EditorView15.updateListener.of(({ view, transactions }) => {
4792
+ EditorView16.updateListener.of(({ view, transactions }) => {
4780
4793
  const id = view.state.facet(documentId2);
4781
4794
  if (!id || transactions.some((tr) => tr.isUserEvent(stateRestoreAnnotation))) {
4782
4795
  return;
@@ -4901,96 +4914,32 @@ var ToolbarRoot = ({ children, onAction, classNames, state: state2 }) => {
4901
4914
  }
4902
4915
  }, children))));
4903
4916
  };
4904
- var ToolbarToggleButton = ({ Icon, children, ...props }) => {
4917
+ var ToolbarToggleButton = ({ Icon: Icon2, children, ...props }) => {
4905
4918
  return /* @__PURE__ */ React3.createElement(Tooltip.Root, null, /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
4906
4919
  asChild: true
4907
4920
  }, /* @__PURE__ */ React3.createElement(NaturalToolbar.ToggleGroupItem, {
4908
4921
  variant: "ghost",
4909
4922
  ...props,
4910
4923
  classNames: buttonStyles
4911
- }, /* @__PURE__ */ React3.createElement(Icon, {
4924
+ }, /* @__PURE__ */ React3.createElement(Icon2, {
4912
4925
  className: iconStyles
4913
4926
  }), /* @__PURE__ */ React3.createElement("span", {
4914
4927
  className: "sr-only"
4915
4928
  }, children))), /* @__PURE__ */ React3.createElement(Tooltip.Portal, null, /* @__PURE__ */ React3.createElement(Tooltip.Content, tooltipProps, children, /* @__PURE__ */ React3.createElement(Tooltip.Arrow, null))));
4916
4929
  };
4917
- var ToolbarButton = ({ Icon, children, ...props }) => {
4930
+ var ToolbarButton = ({ Icon: Icon2, children, ...props }) => {
4918
4931
  return /* @__PURE__ */ React3.createElement(Tooltip.Root, null, /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
4919
4932
  asChild: true
4920
4933
  }, /* @__PURE__ */ React3.createElement(NaturalToolbar.Button, {
4921
4934
  variant: "ghost",
4922
4935
  ...props,
4923
4936
  classNames: buttonStyles
4924
- }, /* @__PURE__ */ React3.createElement(Icon, {
4937
+ }, /* @__PURE__ */ React3.createElement(Icon2, {
4925
4938
  className: iconStyles
4926
4939
  }), /* @__PURE__ */ React3.createElement("span", {
4927
4940
  className: "sr-only"
4928
4941
  }, children))), /* @__PURE__ */ React3.createElement(Tooltip.Portal, null, /* @__PURE__ */ React3.createElement(Tooltip.Content, tooltipProps, children, /* @__PURE__ */ React3.createElement(Tooltip.Arrow, null))));
4929
4942
  };
4930
- var ViewModeIcons = {
4931
- preview: PencilSimple,
4932
- readonly: PencilSimpleSlash,
4933
- source: MarkdownLogo
4934
- };
4935
- var MarkdownView = ({ mode }) => {
4936
- const { t } = useTranslation(translationKey);
4937
- const { onAction } = useToolbarContext("ViewMode");
4938
- const ModeIcon = ViewModeIcons[mode ?? "preview"];
4939
- const suppressNextTooltip = useRef(false);
4940
- const [tooltipOpen, setTooltipOpen] = useState3(false);
4941
- const [selectOpen, setSelectOpen] = useState3(false);
4942
- return /* @__PURE__ */ React3.createElement(Tooltip.Root, {
4943
- open: tooltipOpen,
4944
- onOpenChange: (nextOpen) => {
4945
- if (nextOpen && suppressNextTooltip.current) {
4946
- suppressNextTooltip.current = false;
4947
- return setTooltipOpen(false);
4948
- } else {
4949
- return setTooltipOpen(nextOpen);
4950
- }
4951
- }
4952
- }, /* @__PURE__ */ React3.createElement(DropdownMenu.Root, {
4953
- open: selectOpen,
4954
- onOpenChange: (nextOpen) => {
4955
- if (!nextOpen) {
4956
- suppressNextTooltip.current = true;
4957
- }
4958
- return setSelectOpen(nextOpen);
4959
- }
4960
- }, /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
4961
- asChild: true
4962
- }, /* @__PURE__ */ React3.createElement(NaturalToolbar.Button, {
4963
- asChild: true
4964
- }, /* @__PURE__ */ React3.createElement(DropdownMenu.Trigger, {
4965
- asChild: true
4966
- }, /* @__PURE__ */ React3.createElement(Button, {
4967
- variant: "ghost",
4968
- classNames: buttonStyles
4969
- }, /* @__PURE__ */ React3.createElement("span", {
4970
- className: "sr-only"
4971
- }, t("mode label")), /* @__PURE__ */ React3.createElement(ModeIcon, {
4972
- className: iconStyles
4973
- }), /* @__PURE__ */ React3.createElement(CaretDown, null))))), /* @__PURE__ */ React3.createElement(DropdownMenu.Portal, null, /* @__PURE__ */ React3.createElement(DropdownMenu.Content, {
4974
- classNames: "is-min md:is-min",
4975
- onCloseAutoFocus: (e) => e.preventDefault()
4976
- }, /* @__PURE__ */ React3.createElement(DropdownMenu.Viewport, null, EditorViewModes.map((value) => {
4977
- const Icon = ViewModeIcons[value];
4978
- return /* @__PURE__ */ React3.createElement(DropdownMenu.CheckboxItem, {
4979
- key: value,
4980
- checked: value === mode,
4981
- onClick: () => onAction?.({
4982
- type: "view-mode",
4983
- data: value
4984
- })
4985
- }, /* @__PURE__ */ React3.createElement(Icon, {
4986
- className: iconStyles
4987
- }), /* @__PURE__ */ React3.createElement("span", {
4988
- className: "whitespace-nowrap grow"
4989
- }, t(`${value} mode label`)), /* @__PURE__ */ React3.createElement(Check, {
4990
- className: value === mode ? "visible" : "invisible"
4991
- }));
4992
- })), /* @__PURE__ */ React3.createElement(DropdownMenu.Arrow, null)))), /* @__PURE__ */ React3.createElement(Tooltip.Portal, null, /* @__PURE__ */ React3.createElement(Tooltip.Content, tooltipProps, t("view mode label"), /* @__PURE__ */ React3.createElement(Tooltip.Arrow, null))));
4993
- };
4994
4943
  var HeadingIcons = {
4995
4944
  "0": Paragraph,
4996
4945
  "1": TextHOne,
@@ -5046,7 +4995,7 @@ var MarkdownHeading = () => {
5046
4995
  classNames: "is-min md:is-min",
5047
4996
  onCloseAutoFocus: (e) => e.preventDefault()
5048
4997
  }, /* @__PURE__ */ React3.createElement(DropdownMenu.Viewport, null, Object.keys(HeadingIcons).map((level) => {
5049
- const Icon = HeadingIcons[level];
4998
+ const Icon2 = HeadingIcons[level];
5050
4999
  return /* @__PURE__ */ React3.createElement(DropdownMenu.CheckboxItem, {
5051
5000
  key: level,
5052
5001
  checked: value === level,
@@ -5058,7 +5007,7 @@ var MarkdownHeading = () => {
5058
5007
  className: "sr-only"
5059
5008
  }, t("heading level label", {
5060
5009
  count: parseInt(level)
5061
- })), /* @__PURE__ */ React3.createElement(Icon, {
5010
+ })), /* @__PURE__ */ React3.createElement(Icon2, {
5062
5011
  className: iconStyles
5063
5012
  }), /* @__PURE__ */ React3.createElement(DropdownMenu.ItemIndicator, null, /* @__PURE__ */ React3.createElement(Check, null)));
5064
5013
  })), /* @__PURE__ */ React3.createElement(DropdownMenu.Arrow, null)))), /* @__PURE__ */ React3.createElement(Tooltip.Portal, null, /* @__PURE__ */ React3.createElement(Tooltip.Content, tooltipProps, t("heading label"), /* @__PURE__ */ React3.createElement(Tooltip.Arrow, null))));
@@ -5096,10 +5045,10 @@ var MarkdownStyles = () => {
5096
5045
  return /* @__PURE__ */ React3.createElement(NaturalToolbar.ToggleGroup, {
5097
5046
  type: "multiple",
5098
5047
  value: markdownStyles.filter(({ getState }) => state2 && getState(state2)).map(({ type }) => type)
5099
- }, markdownStyles.map(({ type, getState, Icon }) => /* @__PURE__ */ React3.createElement(ToolbarToggleButton, {
5048
+ }, markdownStyles.map(({ type, getState, Icon: Icon2 }) => /* @__PURE__ */ React3.createElement(ToolbarToggleButton, {
5100
5049
  key: type,
5101
5050
  value: type,
5102
- Icon,
5051
+ Icon: Icon2,
5103
5052
  disabled: state2?.blockType === "codeblock",
5104
5053
  onClick: state2 ? () => onAction?.({
5105
5054
  type,
@@ -5130,10 +5079,10 @@ var MarkdownLists = () => {
5130
5079
  return /* @__PURE__ */ React3.createElement(NaturalToolbar.ToggleGroup, {
5131
5080
  type: "single",
5132
5081
  value: state2?.listStyle ? `list-${state2.listStyle}` : ""
5133
- }, markdownLists.map(({ type, getState, Icon }) => /* @__PURE__ */ React3.createElement(ToolbarToggleButton, {
5082
+ }, markdownLists.map(({ type, getState, Icon: Icon2 }) => /* @__PURE__ */ React3.createElement(ToolbarToggleButton, {
5134
5083
  key: type,
5135
5084
  value: type,
5136
- Icon,
5085
+ Icon: Icon2,
5137
5086
  onClick: state2 ? () => onAction?.({
5138
5087
  type,
5139
5088
  data: !getState(state2)
@@ -5165,10 +5114,10 @@ var MarkdownBlocks = () => {
5165
5114
  return /* @__PURE__ */ React3.createElement(NaturalToolbar.ToggleGroup, {
5166
5115
  type: "single",
5167
5116
  value: value?.type ?? ""
5168
- }, markdownBlocks.map(({ type, disabled, getState, Icon }) => /* @__PURE__ */ React3.createElement(ToolbarToggleButton, {
5117
+ }, markdownBlocks.map(({ type, disabled, getState, Icon: Icon2 }) => /* @__PURE__ */ React3.createElement(ToolbarToggleButton, {
5169
5118
  key: type,
5170
5119
  value: type,
5171
- Icon,
5120
+ Icon: Icon2,
5172
5121
  disabled: !state2 || disabled?.(state2),
5173
5122
  onClick: state2 ? () => onAction?.({
5174
5123
  type,
@@ -5220,16 +5169,86 @@ var MarkdownCustom = ({ onUpload } = {}) => {
5220
5169
  onClick: () => open()
5221
5170
  }, t("image label")));
5222
5171
  };
5172
+ var ViewModeIcons = {
5173
+ preview: PencilSimple,
5174
+ readonly: PencilSimpleSlash,
5175
+ source: MarkdownLogo
5176
+ };
5177
+ var MarkdownView = ({ mode }) => {
5178
+ const { t } = useTranslation(translationKey);
5179
+ const { onAction } = useToolbarContext("ViewMode");
5180
+ const ModeIcon = ViewModeIcons[mode ?? "preview"];
5181
+ const suppressNextTooltip = useRef(false);
5182
+ const [tooltipOpen, setTooltipOpen] = useState3(false);
5183
+ const [selectOpen, setSelectOpen] = useState3(false);
5184
+ return /* @__PURE__ */ React3.createElement(Tooltip.Root, {
5185
+ open: tooltipOpen,
5186
+ onOpenChange: (nextOpen) => {
5187
+ if (nextOpen && suppressNextTooltip.current) {
5188
+ suppressNextTooltip.current = false;
5189
+ return setTooltipOpen(false);
5190
+ } else {
5191
+ return setTooltipOpen(nextOpen);
5192
+ }
5193
+ }
5194
+ }, /* @__PURE__ */ React3.createElement(DropdownMenu.Root, {
5195
+ open: selectOpen,
5196
+ onOpenChange: (nextOpen) => {
5197
+ if (!nextOpen) {
5198
+ suppressNextTooltip.current = true;
5199
+ }
5200
+ return setSelectOpen(nextOpen);
5201
+ }
5202
+ }, /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
5203
+ asChild: true
5204
+ }, /* @__PURE__ */ React3.createElement(NaturalToolbar.Button, {
5205
+ asChild: true
5206
+ }, /* @__PURE__ */ React3.createElement(DropdownMenu.Trigger, {
5207
+ asChild: true
5208
+ }, /* @__PURE__ */ React3.createElement(Button, {
5209
+ variant: "ghost",
5210
+ classNames: buttonStyles
5211
+ }, /* @__PURE__ */ React3.createElement("span", {
5212
+ className: "sr-only"
5213
+ }, t("mode label")), /* @__PURE__ */ React3.createElement(ModeIcon, {
5214
+ className: iconStyles
5215
+ }), /* @__PURE__ */ React3.createElement(CaretDown, null))))), /* @__PURE__ */ React3.createElement(DropdownMenu.Portal, null, /* @__PURE__ */ React3.createElement(DropdownMenu.Content, {
5216
+ classNames: "is-min md:is-min",
5217
+ onCloseAutoFocus: (e) => e.preventDefault()
5218
+ }, /* @__PURE__ */ React3.createElement(DropdownMenu.Viewport, null, EditorViewModes.map((value) => {
5219
+ const Icon2 = ViewModeIcons[value];
5220
+ return /* @__PURE__ */ React3.createElement(DropdownMenu.CheckboxItem, {
5221
+ key: value,
5222
+ checked: value === mode,
5223
+ onClick: () => onAction?.({
5224
+ type: "view-mode",
5225
+ data: value
5226
+ })
5227
+ }, /* @__PURE__ */ React3.createElement(Icon2, {
5228
+ className: iconStyles
5229
+ }), /* @__PURE__ */ React3.createElement("span", {
5230
+ className: "whitespace-nowrap grow"
5231
+ }, t(`${value} mode label`)), /* @__PURE__ */ React3.createElement(Check, {
5232
+ className: value === mode ? "visible" : "invisible"
5233
+ }));
5234
+ })), /* @__PURE__ */ React3.createElement(DropdownMenu.Arrow, null)))), /* @__PURE__ */ React3.createElement(Tooltip.Portal, null, /* @__PURE__ */ React3.createElement(Tooltip.Content, tooltipProps, t("view mode label"), /* @__PURE__ */ React3.createElement(Tooltip.Arrow, null))));
5235
+ };
5223
5236
  var MarkdownActions = () => {
5224
5237
  const { onAction, state: state2 } = useToolbarContext("MarkdownActions");
5225
5238
  const { t } = useTranslation(translationKey);
5226
- let toolTipKey = "comment label";
5239
+ let commentToolTipKey = "comment label";
5227
5240
  if (state2?.comment) {
5228
- toolTipKey = "selection overlaps existing comment label";
5241
+ commentToolTipKey = "selection overlaps existing comment label";
5229
5242
  } else if (state2?.selection === false) {
5230
- toolTipKey = "select text to comment label";
5243
+ commentToolTipKey = "select text to comment label";
5231
5244
  }
5232
5245
  return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(ToolbarButton, {
5246
+ value: "search",
5247
+ Icon: MagnifyingGlass,
5248
+ onClick: () => onAction?.({
5249
+ type: "search"
5250
+ })
5251
+ }, t("search label")), /* @__PURE__ */ React3.createElement(ToolbarButton, {
5233
5252
  value: "comment",
5234
5253
  Icon: ChatText,
5235
5254
  "data-testid": "editor.toolbar.comment",
@@ -5237,7 +5256,7 @@ var MarkdownActions = () => {
5237
5256
  type: "comment"
5238
5257
  }),
5239
5258
  disabled: !state2 || state2.comment || !state2.selection
5240
- }, t(toolTipKey)));
5259
+ }, t(commentToolTipKey)));
5241
5260
  };
5242
5261
  var Toolbar = {
5243
5262
  Root: ToolbarRoot,
@@ -5250,23 +5269,21 @@ var Toolbar = {
5250
5269
  };
5251
5270
 
5252
5271
  // packages/ui/react-ui-editor/src/defaults.ts
5253
- import { EditorView as EditorView16 } from "@codemirror/view";
5254
- var editorContent = "!mt-[16px] !mb-[32px] !mli-auto w-full max-w-[min(50rem,100%-4rem)]";
5272
+ import { EditorView as EditorView17 } from "@codemirror/view";
5273
+ import { mx as mx3 } from "@dxos/react-ui-theme";
5274
+ var margin = "!mt-[16px]";
5275
+ var editorContent = mx3(margin, "!mli-auto w-full max-w-[min(50rem,100%-2rem)]");
5276
+ var editorFullWidth = mx3(margin, "!ml-[3rem]");
5255
5277
  var editorWithToolbarLayout = "grid grid-cols-1 grid-rows-[min-content_1fr] data-[toolbar=disabled]:grid-rows-[1fr] justify-center content-start overflow-hidden";
5256
- var editorGutter = EditorView16.baseTheme({
5278
+ var editorGutter = EditorView17.theme({
5279
+ // Match margin from content.
5257
5280
  ".cm-gutters": {
5258
- // Match margin from content.
5259
- marginTop: "16px",
5260
- marginBottom: "16px",
5261
- // Inside within content margin.
5262
- marginRight: "-32px",
5263
- width: "32px",
5264
- backgroundColor: "transparent !important"
5281
+ marginTop: "16px"
5265
5282
  }
5266
5283
  });
5267
- var editorMonospace = EditorView16.baseTheme({
5284
+ var editorMonospace = EditorView17.theme({
5268
5285
  ".cm-content": {
5269
- fontFamily: `${getToken("fontFamily.mono")} !important`
5286
+ fontFamily: fontMono
5270
5287
  }
5271
5288
  });
5272
5289
 
@@ -5277,7 +5294,7 @@ var useActionHandler = (view) => {
5277
5294
 
5278
5295
  // packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
5279
5296
  import { EditorState as EditorState2 } from "@codemirror/state";
5280
- import { EditorView as EditorView17 } from "@codemirror/view";
5297
+ import { EditorView as EditorView18 } from "@codemirror/view";
5281
5298
  import { useFocusableGroup } from "@fluentui/react-tabster";
5282
5299
  import { useCallback, useEffect as useEffect3, useMemo as useMemo3, useRef as useRef2, useState as useState4 } from "react";
5283
5300
  import { log as log8 } from "@dxos/log";
@@ -5323,7 +5340,7 @@ var useTextEditor = (props = {}, deps = []) => {
5323
5340
  extensions: [
5324
5341
  id && documentId2.of(id),
5325
5342
  // NOTE: Doesn't catch errors in keymap functions.
5326
- EditorView17.exceptionSink.of((err) => {
5343
+ EditorView18.exceptionSink.of((err) => {
5327
5344
  log8.catch(err, void 0, {
5328
5345
  F: __dxlog_file13,
5329
5346
  L: 100,
@@ -5332,14 +5349,14 @@ var useTextEditor = (props = {}, deps = []) => {
5332
5349
  });
5333
5350
  }),
5334
5351
  extensions,
5335
- EditorView17.updateListener.of(() => {
5352
+ EditorView18.updateListener.of(() => {
5336
5353
  setTimeout(() => {
5337
5354
  onUpdate.current?.();
5338
5355
  });
5339
5356
  })
5340
5357
  ].filter(isNotFalsy4)
5341
5358
  });
5342
- view2 = new EditorView17({
5359
+ view2 = new EditorView18({
5343
5360
  parent: parentRef.current,
5344
5361
  selection: initialSelection,
5345
5362
  state: state2,
@@ -5453,6 +5470,7 @@ export {
5453
5470
  command,
5454
5471
  comments,
5455
5472
  commentsState,
5473
+ convertTreeToJson,
5456
5474
  createBasicExtensions,
5457
5475
  createComment,
5458
5476
  createDataExtensions,
@@ -5461,11 +5479,13 @@ export {
5461
5479
  createMarkdownExtensions,
5462
5480
  createThemeExtensions,
5463
5481
  debugNodeLogger,
5482
+ debugTree,
5464
5483
  decorateMarkdown,
5465
5484
  defaultOptions,
5466
5485
  documentId2 as documentId,
5467
5486
  dropFile,
5468
5487
  editorContent,
5488
+ editorFullWidth,
5469
5489
  editorGutter,
5470
5490
  editorInputMode,
5471
5491
  editorMonospace,
@@ -5475,7 +5495,6 @@ export {
5475
5495
  formattingEquals,
5476
5496
  formattingKeymap,
5477
5497
  getFormatting,
5478
- getToken,
5479
5498
  image,
5480
5499
  imageUpload,
5481
5500
  insertTable,