@dxos/react-ui-editor 0.6.10-main.e92b5eb → 0.6.10-staging.00555f6

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 +737 -719
  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 +123 -75
  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 +5 -5
  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,282 +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 { tailwindConfig } from "@dxos/react-ui-theme";
64
- var tokens = tailwindConfig({}).theme;
65
- var getToken = (path, defaultValue) => {
66
- const value = get(tokens, path, defaultValue);
67
- return value?.toString() ?? "";
68
- };
69
-
70
- // packages/ui/react-ui-editor/src/styles/theme.ts
71
- var defaultTheme = {
72
- "&": {},
73
- "&.cm-focused": {
74
- outline: "none"
75
- },
76
- /**
77
- * Scroller
78
- */
79
- ".cm-scroller": {
80
- overflowY: "auto"
81
- },
82
- /**
83
- * Content
84
- * NOTE: Apply margins to content so that scrollbar is at the edge of the container.
85
- */
86
- ".cm-content": {
87
- padding: "unset",
88
- // NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
89
- fontSize: "16px",
90
- fontFamily: getToken("fontFamily.body"),
91
- lineHeight: 1.5
92
- },
93
- "&light .cm-content": {
94
- color: getToken("extend.semanticColors.base.fg.light", "black")
95
- },
96
- "&dark .cm-content": {
97
- color: getToken("extend.semanticColors.base.fg.dark", "white")
98
- },
99
- /**
100
- * Gutters
101
- * NOTE: Gutters should have the same top margin as the content.
102
- */
103
- ".cm-gutters": {
104
- background: "transparent"
105
- },
106
- ".cm-gutter": {},
107
- ".cm-gutterElement": {
108
- lineHeight: 1.5
109
- },
110
- //
111
- // Cursor
112
- //
113
- "&light .cm-cursor, &light .cm-dropCursor": {
114
- borderLeft: "2px solid black"
115
- },
116
- "&dark .cm-cursor, &dark .cm-dropCursor": {
117
- borderLeft: "2px solid white"
118
- },
119
- "&light .cm-placeholder": {
120
- color: getToken("extend.semanticColors.description.light", "rgba(0,0,0,.2)")
121
- },
122
- "&dark .cm-placeholder": {
123
- color: getToken("extend.semanticColors.description.dark", "rgba(255,255,255,.2)")
124
- },
125
- //
126
- // line
127
- //
128
- ".cm-line": {
129
- paddingInline: 0
130
- },
131
- ".cm-activeLine": {
132
- background: "transparent"
133
- },
134
- //
135
- // gutter
136
- //
137
- ".cm-lineNumbers": {
138
- minWidth: "36px"
139
- },
140
- //
141
- // Selection
142
- //
143
- "&light .cm-selectionBackground": {
144
- background: getToken("extend.colors.primary.100")
145
- },
146
- "&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
147
- background: getToken("extend.colors.primary.200")
148
- },
149
- "&dark .cm-selectionBackground": {
150
- background: getToken("extend.colors.primary.700")
151
- },
152
- "&dark.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
153
- background: getToken("extend.colors.primary.600")
154
- },
155
- //
156
- // Search
157
- //
158
- "&light .cm-searchMatch": {
159
- backgroundColor: getToken("extend.colors.yellow.100")
160
- },
161
- "&dark .cm-searchMatch": {
162
- backgroundColor: getToken("extend.colors.yellow.700")
163
- },
164
- //
165
- // link
166
- //
167
- ".cm-link": {
168
- textDecorationLine: "underline",
169
- textDecorationThickness: "1px",
170
- textUnderlineOffset: "2px",
171
- borderRadius: ".125rem",
172
- fontFamily: getToken("fontFamily.body")
173
- },
174
- "&light .cm-link > span": {
175
- color: getToken("extend.colors.primary.600")
176
- },
177
- "&dark .cm-link > span": {
178
- color: getToken("extend.colors.primary.400")
179
- },
180
- //
181
- // tooltip
182
- //
183
- ".cm-tooltip": {},
184
- "&light .cm-tooltip": {
185
- background: `${getToken("extend.colors.neutral.100")} !important`
186
- },
187
- "&dark .cm-tooltip": {
188
- background: `${getToken("extend.colors.neutral.900")} !important`
189
- },
190
- ".cm-tooltip-below": {},
191
- //
192
- // autocomplete
193
- // https://github.com/codemirror/autocomplete/blob/main/src/completion.ts
194
- //
195
- ".cm-tooltip.cm-tooltip-autocomplete": {
196
- marginTop: "4px",
197
- marginLeft: "-3px"
198
- },
199
- ".cm-tooltip.cm-tooltip-autocomplete > ul": {
200
- maxHeight: "20em !important"
201
- },
202
- ".cm-tooltip.cm-tooltip-autocomplete > ul > li": {},
203
- ".cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected]": {},
204
- ".cm-tooltip.cm-tooltip-autocomplete > ul > completion-section": {
205
- paddingLeft: "4px !important",
206
- borderBottom: "none !important",
207
- color: getToken("extend.colors.primary.500")
208
- },
209
- ".cm-tooltip.cm-completionInfo": {
210
- border: getToken("extend.colors.neutral.500"),
211
- width: "360px !important",
212
- margin: "-10px 1px 0 1px",
213
- padding: "8px !important"
214
- },
215
- ".cm-completionIcon": {
216
- display: "none"
217
- },
218
- ".cm-completionLabel": {
219
- fontFamily: getToken("fontFamily.body")
220
- },
221
- ".cm-completionMatchedText": {
222
- textDecoration: "none !important",
223
- opacity: 0.5
224
- },
225
- // TODO(burdon): Override vars --cm-background.
226
- // https://www.npmjs.com/package/codemirror-theme-vars
227
- /**
228
- * Panels
229
- * TODO(burdon): Needs styling attention (esp. dark mode).
230
- * https://github.com/codemirror/search/blob/main/src/search.ts#L745
231
- *
232
- * Find/replace panel.
233
- * <div class="cm-announced">...</div>
234
- * <div class="cm-scroller">...</div>
235
- * <div class="cm-panels cm-panels-bottom">
236
- * <div class="cm-search cm-panel">
237
- * <input class="cm-textfield" />
238
- * <button class="cm-button">...</button>
239
- * <label><input type="checkbox" />...</label>
240
- * </div>
241
- * </div
242
- */
243
- ".cm-panels": {},
244
- ".cm-panel": {
245
- fontFamily: getToken("fontFamily.body")
246
- },
247
- ".cm-panel input[type=checkbox]": {
248
- marginRight: "0.4rem !important"
249
- },
250
- "&light .cm-panel": {
251
- background: getToken("extend.colors.neutral.50")
252
- },
253
- "&dark .cm-panel": {
254
- background: getToken("extend.colors.neutral.850")
255
- },
256
- ".cm-button": {
257
- margin: "4px",
258
- fontFamily: getToken("fontFamily.body"),
259
- backgroundImage: "none",
260
- border: "none",
261
- "&:active": {
262
- backgroundImage: "none"
263
- }
264
- },
265
- "&light .cm-button": {
266
- background: getToken("extend.colors.neutral.100"),
267
- "&:hover": {
268
- background: getToken("extend.colors.neutral.200")
269
- },
270
- "&:active": {
271
- background: getToken("extend.colors.neutral.300")
272
- }
273
- },
274
- "&dark .cm-button": {
275
- background: getToken("extend.colors.neutral.800"),
276
- "&:hover": {
277
- background: getToken("extend.colors.neutral.700")
278
- },
279
- "&:active": {
280
- background: getToken("extend.colors.neutral.600")
281
- }
282
- },
283
- // TODO(burdon): Factor out element specific logic.
284
- //
285
- // table
286
- //
287
- ".cm-table *": {
288
- fontFamily: `${getToken("fontFamily.mono")} !important`,
289
- textDecoration: "none !important"
290
- },
291
- ".cm-table-head": {
292
- padding: "2px 16px 2px 0px",
293
- textAlign: "left",
294
- borderBottom: `1px solid ${getToken("extend.colors.primary.500")}`,
295
- color: getToken("extend.colors.neutral.500")
296
- },
297
- ".cm-table-cell": {
298
- padding: "2px 16px 2px 0px"
299
- },
300
- //
301
- // image
302
- //
303
- ".cm-image": {
304
- display: "block",
305
- height: "0"
306
- },
307
- ".cm-image.cm-loaded-image": {
308
- height: "auto",
309
- borderTop: "0.5rem solid transparent",
310
- borderBottom: "0.5rem solid transparent"
311
- }
312
- };
313
-
314
41
  // packages/ui/react-ui-editor/src/components/Toolbar/Toolbar.tsx
315
- 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";
316
43
  import { createContext } from "@radix-ui/react-context";
317
44
  import React3, { useEffect as useEffect2, useRef, useState as useState3 } from "react";
318
45
  import { useDropzone } from "react-dropzone";
@@ -413,11 +140,11 @@ var annotations = (options = {}) => {
413
140
  styles
414
141
  ];
415
142
  };
416
- var styles = EditorView.baseTheme({
143
+ var styles = EditorView.theme({
417
144
  ".cm-annotation": {
418
145
  textDecoration: "underline",
419
146
  textDecorationStyle: "wavy",
420
- textDecorationColor: "red"
147
+ textDecorationColor: "var(--dx-error)"
421
148
  }
422
149
  });
423
150
 
@@ -425,7 +152,7 @@ var styles = EditorView.baseTheme({
425
152
  import { autocompletion, completionKeymap } from "@codemirror/autocomplete";
426
153
  import { markdownLanguage } from "@codemirror/lang-markdown";
427
154
  import { keymap } from "@codemirror/view";
428
- var autocomplete = ({ activateOnTyping, onSearch } = {}) => {
155
+ var autocomplete = ({ activateOnTyping, override, onSearch } = {}) => {
429
156
  const extentions = [
430
157
  // https://codemirror.net/docs/ref/#view.keymap
431
158
  // https://discuss.codemirror.net/t/how-can-i-replace-the-default-autocompletion-keymap-v6/3322
@@ -435,6 +162,7 @@ var autocomplete = ({ activateOnTyping, onSearch } = {}) => {
435
162
  // https://codemirror.net/docs/ref/#autocomplete.autocompletion
436
163
  autocompletion({
437
164
  activateOnTyping,
165
+ override,
438
166
  // closeOnBlur: false,
439
167
  // defaultKeymap: false,
440
168
  // TODO(burdon): Styles/fragments.
@@ -933,7 +661,7 @@ var RemoteCaretWidget = class extends WidgetType {
933
661
  return true;
934
662
  }
935
663
  };
936
- var styles2 = EditorView3.baseTheme({
664
+ var styles2 = EditorView3.theme({
937
665
  ".cm-collab-selection": {},
938
666
  ".cm-collab-selectionLine": {
939
667
  padding: 0,
@@ -1756,50 +1484,17 @@ var commentsState = StateField4.define({
1756
1484
  return value;
1757
1485
  }
1758
1486
  });
1759
- var styles3 = EditorView7.baseTheme({
1487
+ var styles3 = EditorView7.theme({
1760
1488
  ".cm-comment, .cm-comment-current": {
1761
- cursor: "pointer",
1762
- borderWidth: "1px",
1763
- borderStyle: "solid",
1764
- borderRadius: "2px",
1765
- transition: "background-color 0.1s ease"
1766
- },
1767
- // Light theme.
1768
- "&light .cm-comment": {
1769
- backgroundColor: getToken("extend.colors.yellow.50"),
1770
- mixBlendMode: "darken",
1771
- borderColor: getToken("extend.colors.yellow.100")
1772
- },
1773
- "&light .cm-comment:hover": {
1774
- backgroundColor: getToken("extend.colors.yellow.100")
1775
- },
1776
- "&light .cm-comment-current": {
1777
- backgroundColor: getToken("extend.colors.primary.100"),
1778
- borderColor: getToken("extend.colors.primary.200")
1779
- },
1780
- "&light .cm-comment-current:hover": {
1781
- backgroundColor: getToken("extend.colors.primary.150"),
1782
- borderColor: getToken("extend.colors.primary.250")
1783
- },
1784
- // Dark theme.
1785
- "&dark .cm-comment": {
1786
- color: getToken("extend.colors.yellow.50"),
1787
- backgroundColor: getToken("extend.colors.yellow.800"),
1788
- borderColor: getToken("extend.colors.yellow.700"),
1789
- mixBlendMode: "plus-lighter"
1790
- },
1791
- "&dark .cm-comment:hover": {
1792
- backgroundColor: getToken("extend.colors.yellow.700"),
1793
- borderColor: getToken("extend.colors.yellow.650")
1794
- },
1795
- "&dark .cm-comment-current": {
1796
- color: getToken("extend.colors.primary.50"),
1797
- backgroundColor: getToken("extend.colors.primary.800"),
1798
- 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"
1799
1495
  },
1800
- "&dark .cm-comment-current:hover": {
1801
- backgroundColor: getToken("extend.colors.primary.700"),
1802
- borderColor: getToken("extend.colors.primary.650")
1496
+ ".cm-comment:hover, .cm-comment-current": {
1497
+ textDecoration: "underline"
1803
1498
  }
1804
1499
  });
1805
1500
  var createCommentMark = (id, isCurrent) => Decoration4.mark({
@@ -1818,7 +1513,7 @@ var commentsDecorations = EditorView7.decorations.compute([
1818
1513
  if (!range) {
1819
1514
  log5.warn("Invalid range:", range, {
1820
1515
  F: __dxlog_file7,
1821
- L: 181,
1516
+ L: 147,
1822
1517
  S: void 0,
1823
1518
  C: (f, a) => f(...a)
1824
1519
  });
@@ -2259,10 +1954,10 @@ var documentId2 = Facet5.define({
2259
1954
 
2260
1955
  // packages/ui/react-ui-editor/src/extensions/dnd.ts
2261
1956
  import { dropCursor, EditorView as EditorView8 } from "@codemirror/view";
2262
- var styles4 = EditorView8.baseTheme({
1957
+ var styles4 = EditorView8.theme({
2263
1958
  ".cm-dropCursor": {
2264
- borderLeft: `2px solid ${getToken("extend.colors.primary.500")}`,
2265
- color: getToken("extend.colors.primary.500"),
1959
+ borderLeft: "2px solid var(--dx-accentText)",
1960
+ color: "var(--dx-accentText)",
2266
1961
  padding: "0 4px"
2267
1962
  },
2268
1963
  ".cm-dropCursor:after": {
@@ -2301,68 +1996,294 @@ import { searchKeymap } from "@codemirror/search";
2301
1996
  import { EditorState } from "@codemirror/state";
2302
1997
  import { EditorView as EditorView9, drawSelection, dropCursor as dropCursor2, highlightActiveLine, keymap as keymap5, lineNumbers, placeholder, scrollPastEnd } from "@codemirror/view";
2303
1998
  import defaultsDeep2 from "lodash.defaultsdeep";
1999
+ import merge from "lodash.merge";
2304
2000
  import { generateName } from "@dxos/display-name";
2305
2001
  import { log as log6 } from "@dxos/log";
2306
2002
  import { hueTokens } from "@dxos/react-ui-theme";
2307
2003
  import { hexToHue, isNotFalsy as isNotFalsy2 } from "@dxos/util";
2308
- var __dxlog_file9 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/factories.ts";
2309
- var preventNewline = EditorState.transactionFilter.of((tr) => tr.newDoc.lines > 1 ? [] : tr);
2310
- var defaultBasicOptions = {
2311
- allowMultipleSelections: true,
2312
- bracketMatching: true,
2313
- closeBrackets: true,
2314
- drawSelection: true,
2315
- editable: true,
2316
- history: true,
2317
- keymap: "standard",
2318
- lineWrapping: true,
2319
- 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"
2320
2014
  };
2321
- var keymaps = {
2322
- // https://codemirror.net/docs/ref/#commands.standardKeymap
2323
- standard: standardKeymap,
2324
- // https://codemirror.net/docs/ref/#commands.defaultKeymap
2325
- 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
+ }
2326
2024
  };
2327
- var createBasicExtensions = (_props) => {
2328
- const props = defaultsDeep2({}, _props, defaultBasicOptions);
2329
- return [
2330
- // NOTE: Doesn't catch errors in keymap functions.
2331
- EditorView9.exceptionSink.of((err) => {
2332
- log6.catch(err, void 0, {
2333
- F: __dxlog_file9,
2334
- L: 91,
2335
- S: void 0,
2336
- C: (f, a) => f(...a)
2337
- });
2338
- }),
2339
- props.allowMultipleSelections && EditorState.allowMultipleSelections.of(true),
2340
- props.bracketMatching && bracketMatching(),
2341
- props.closeBrackets && closeBrackets(),
2342
- props.dropCursor && dropCursor2(),
2343
- props.drawSelection && drawSelection({
2344
- cursorBlinkRate: 1200
2345
- }),
2346
- props.highlightActiveLine && highlightActiveLine(),
2347
- props.history && history(),
2348
- props.lineNumbers && lineNumbers(),
2349
- props.lineWrapping && EditorView9.lineWrapping,
2350
- props.placeholder && placeholder(props.placeholder),
2351
- props.readonly && [
2352
- EditorState.readOnly.of(true),
2353
- EditorView9.editable.of(false)
2354
- ],
2355
- props.scrollPastEnd && scrollPastEnd(),
2356
- props.tabSize && EditorState.tabSize.of(props.tabSize),
2357
- // https://codemirror.net/docs/ref/#view.KeyBinding
2358
- keymap5.of([
2359
- ...(props.keymap && keymaps[props.keymap]) ?? [],
2360
- // NOTE: Tabs are also configured by markdown extension.
2361
- // https://codemirror.net/docs/ref/#commands.indentWithTab
2362
- ...props.indentWithTab ? [
2363
- indentWithTab
2364
- ] : [],
2365
- // https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
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
+ ] : [],
2286
+ // https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
2366
2287
  ...props.closeBrackets ? closeBracketsKeymap : [],
2367
2288
  // https://codemirror.net/docs/ref/#commands.historyKeymap
2368
2289
  ...props.history ? historyKeymap : [],
@@ -2376,12 +2297,11 @@ var defaultThemeSlots = {
2376
2297
  className: "w-full bs-full"
2377
2298
  }
2378
2299
  };
2379
- var createThemeExtensions = ({ theme: theme2, themeMode, slots: _slots } = {}) => {
2300
+ var createThemeExtensions = ({ themeMode, styles: styles5, slots: _slots } = {}) => {
2380
2301
  const slots = defaultsDeep2({}, _slots, defaultThemeSlots);
2381
2302
  return [
2382
- EditorView9.baseTheme(defaultTheme),
2383
2303
  EditorView9.darkTheme.of(themeMode === "dark"),
2384
- theme2 && EditorView9.theme(theme2),
2304
+ EditorView9.baseTheme(styles5 ? merge({}, defaultTheme, styles5) : defaultTheme),
2385
2305
  slots.editor?.className && EditorView9.editorAttributes.of({
2386
2306
  class: slots.editor.className
2387
2307
  }),
@@ -2415,18 +2335,22 @@ var createDataExtensions = ({ id, text, space, identity }) => {
2415
2335
  // packages/ui/react-ui-editor/src/extensions/folding.tsx
2416
2336
  import { codeFolding, foldGutter } from "@codemirror/language";
2417
2337
  import React2 from "react";
2418
- 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";
2419
2340
  var folding = (_props = {}) => [
2420
2341
  codeFolding({
2421
2342
  placeholderDOM: () => document.createElement("div")
2422
2343
  }),
2423
2344
  foldGutter({
2424
2345
  markerDOM: (open) => {
2425
- return renderRoot(document.createElement("div"), /* @__PURE__ */ React2.createElement("svg", {
2426
- className: mx2(getSize(3), "m-3 cursor-pointer", open && "rotate-90")
2427
- }, /* @__PURE__ */ React2.createElement("use", {
2428
- href: "/icons.svg#ph--caret-right--regular"
2429
- })));
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
+ }));
2430
2354
  }
2431
2355
  })
2432
2356
  ];
@@ -2447,7 +2371,6 @@ var listener = ({ onFocus, onChange }) => {
2447
2371
 
2448
2372
  // packages/ui/react-ui-editor/src/extensions/markdown/formatting.ts
2449
2373
  import { snippet } from "@codemirror/autocomplete";
2450
- import { indentWithTab as indentWithTab2 } from "@codemirror/commands";
2451
2374
  import { syntaxTree as syntaxTree2 } from "@codemirror/language";
2452
2375
  import { EditorSelection } from "@codemirror/state";
2453
2376
  import { EditorView as EditorView11, keymap as keymap6 } from "@codemirror/view";
@@ -3608,7 +3531,7 @@ var processAction = (view, action) => {
3608
3531
 
3609
3532
  // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
3610
3533
  import { completionKeymap as completionKeymap2 } from "@codemirror/autocomplete";
3611
- import { defaultKeymap as defaultKeymap2, indentWithTab as indentWithTab3 } from "@codemirror/commands";
3534
+ import { defaultKeymap as defaultKeymap2, indentWithTab as indentWithTab2 } from "@codemirror/commands";
3612
3535
  import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
3613
3536
  import { defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
3614
3537
  import { languages } from "@codemirror/language-data";
@@ -3796,7 +3719,7 @@ var markdownHighlightStyle = (_options = {}) => {
3796
3719
  ], {
3797
3720
  scope: markdownLanguage2,
3798
3721
  all: {
3799
- fontFamily: getToken("fontFamily.body")
3722
+ fontFamily: fontBody
3800
3723
  }
3801
3724
  });
3802
3725
  };
@@ -3829,9 +3752,8 @@ var createMarkdownExtensions = ({ themeMode } = {}) => {
3829
3752
  // Custom styles.
3830
3753
  syntaxHighlighting(markdownHighlightStyle()),
3831
3754
  keymap7.of([
3832
- // TODO(burdon): Indent by 4 if in task list.
3833
3755
  // https://codemirror.net/docs/ref/#commands.indentWithTab
3834
- indentWithTab3,
3756
+ indentWithTab2,
3835
3757
  // https://codemirror.net/docs/ref/#commands.defaultKeymap
3836
3758
  ...defaultKeymap2,
3837
3759
  ...completionKeymap2,
@@ -3840,128 +3762,130 @@ var createMarkdownExtensions = ({ themeMode } = {}) => {
3840
3762
  ];
3841
3763
  };
3842
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
+
3843
3792
  // packages/ui/react-ui-editor/src/extensions/markdown/decorate.ts
3844
- import { syntaxTree as syntaxTree6 } from "@codemirror/language";
3793
+ import { syntaxTree as syntaxTree7 } from "@codemirror/language";
3845
3794
  import { RangeSetBuilder as RangeSetBuilder3, StateEffect as StateEffect4 } from "@codemirror/state";
3846
- 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";
3847
3796
  import { invariant as invariant4 } from "@dxos/invariant";
3848
- import { mx as mx3 } from "@dxos/react-ui-theme";
3797
+ import { mx as mx2 } from "@dxos/react-ui-theme";
3849
3798
 
3850
- // packages/ui/react-ui-editor/src/extensions/markdown/image.ts
3851
- import { syntaxTree as syntaxTree3 } from "@codemirror/language";
3852
- import { StateField as StateField6 } from "@codemirror/state";
3853
- import { Decoration as Decoration5, EditorView as EditorView12, WidgetType as WidgetType3 } from "@codemirror/view";
3854
- var image = (_options = {}) => {
3855
- return StateField6.define({
3856
- create: (state2) => {
3857
- return Decoration5.set(buildDecorations(0, state2.doc.length, state2));
3858
- },
3859
- update: (value, tr) => {
3860
- if (!tr.docChanged && !tr.selection) {
3861
- 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
+ }
3862
3878
  }
3863
- const cursor = tr.state.selection.main.head;
3864
- const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
3865
- let from = Math.min(cursor, oldCursor);
3866
- let to = Math.max(cursor, oldCursor);
3867
- tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
3868
- from = Math.min(from, fromB);
3869
- to = Math.max(to, toB);
3870
- });
3871
- from = tr.state.doc.lineAt(from).from;
3872
- to = tr.state.doc.lineAt(to).to;
3873
- return value.map(tr.changes).update({
3874
- filterFrom: from,
3875
- filterTo: to,
3876
- filter: () => false,
3877
- add: buildDecorations(from, to, tr.state)
3878
- });
3879
- },
3880
- provide: (field) => EditorView12.decorations.from(field)
3881
- });
3882
- };
3883
- var preloaded = /* @__PURE__ */ new Set();
3884
- var preloadImage = (url) => {
3885
- if (!preloaded.has(url)) {
3886
- const img = document.createElement("img");
3887
- img.src = url;
3888
- preloaded.add(url);
3889
- }
3890
- };
3891
- var buildDecorations = (from, to, state2) => {
3892
- const decorations = [];
3893
- const cursor = state2.selection.main.head;
3894
- syntaxTree3(state2).iterate({
3895
- enter: (node) => {
3896
- if (node.name === "Image") {
3897
- const urlNode = node.node.getChild("URL");
3898
- if (urlNode) {
3899
- const hide2 = state2.readOnly || cursor < node.from || cursor > node.to;
3900
- const url = state2.sliceDoc(urlNode.from, urlNode.to);
3901
- preloadImage(url);
3902
- decorations.push(Decoration5.replace({
3903
- block: true,
3904
- widget: new ImageWidget(url)
3905
- }).range(hide2 ? node.from : node.to, node.to));
3906
- }
3907
- }
3908
- },
3909
- from,
3910
- to
3911
- });
3912
- return decorations;
3913
- };
3914
- var ImageWidget = class extends WidgetType3 {
3915
- constructor(_url) {
3916
- super();
3917
- this._url = _url;
3918
- }
3919
- eq(other) {
3920
- return this._url === other._url;
3921
- }
3922
- toDOM(view) {
3923
- const img = document.createElement("img");
3924
- img.setAttribute("src", this._url);
3925
- img.setAttribute("class", "cm-image");
3926
- img.onload = () => img.classList.add("cm-loaded-image");
3927
- return img;
3928
- }
3929
- };
3930
- var imageUpload = (options = {}) => {
3931
- };
3932
-
3933
- // packages/ui/react-ui-editor/src/extensions/markdown/link-paste.ts
3934
- import { syntaxTree as syntaxTree4 } from "@codemirror/language";
3935
- import { Transaction } from "@codemirror/state";
3936
- import { ViewPlugin as ViewPlugin5 } from "@codemirror/view";
3937
- var linkPastePlugin = ViewPlugin5.fromClass(class {
3938
- update(update2) {
3939
- for (const tr of update2.transactions) {
3940
- const event = tr.annotation(Transaction.userEvent);
3941
- if (event === "input.paste") {
3942
- const changes = tr.changes;
3943
- if (changes.empty) {
3944
- return;
3945
- }
3946
- changes.iterChangedRanges((fromA, toA, fromB, toB) => {
3947
- const insertedUrl = getValidUrl(update2.view.state.sliceDoc(fromB, toB));
3948
- if (insertedUrl && isValidPosition(update2.view.state, fromB)) {
3949
- const replacedText = tr.startState.sliceDoc(fromA, toA);
3950
- setTimeout(() => {
3951
- update2.view.dispatch(update2.view.state.update({
3952
- changes: {
3953
- from: fromA,
3954
- to: toB,
3955
- insert: createLink(insertedUrl, replacedText)
3956
- }
3957
- }));
3958
- });
3959
- }
3879
+ if (adjustments.length) {
3880
+ setTimeout(() => {
3881
+ update2.view.dispatch(update2.view.state.update({
3882
+ changes: adjustments
3883
+ }));
3960
3884
  });
3961
3885
  }
3962
3886
  }
3963
- }
3964
- });
3887
+ });
3888
+ };
3965
3889
  var createLink = (url, label) => {
3966
3890
  const { host, pathname } = url;
3967
3891
  const [, extension] = pathname.split(".");
@@ -4009,33 +3933,191 @@ var getValidUrl = (str) => {
4009
3933
  return void 0;
4010
3934
  }
4011
3935
  };
4012
- var isValidPosition = (state2, pos) => {
4013
- const invalidPositions = /* @__PURE__ */ new Set([
4014
- "Link",
4015
- "LinkMark",
4016
- "Code",
4017
- "FencedCode"
4018
- ]);
4019
- const tree = syntaxTree4(state2);
4020
- let node = tree.resolveInner(pos, -1);
4021
- while (node) {
4022
- if (invalidPositions.has(node.name)) {
4023
- return false;
4024
- }
4025
- 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);
4026
3976
  }
4027
- return true;
4028
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
+ });
4029
4111
 
4030
4112
  // packages/ui/react-ui-editor/src/extensions/markdown/table.ts
4031
- import { syntaxTree as syntaxTree5 } from "@codemirror/language";
4032
- import { RangeSetBuilder as RangeSetBuilder2, StateField as StateField7 } from "@codemirror/state";
4033
- 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";
4034
4116
  var table = (options = {}) => {
4035
- return StateField7.define({
4117
+ return StateField8.define({
4036
4118
  create: (state2) => update(state2, options),
4037
4119
  update: (_, tr) => update(tr.state, options),
4038
- provide: (field) => EditorView13.decorations.from(field)
4120
+ provide: (field) => EditorView14.decorations.from(field)
4039
4121
  });
4040
4122
  };
4041
4123
  var update = (state2, _options) => {
@@ -4047,7 +4129,7 @@ var update = (state2, _options) => {
4047
4129
  const table2 = getTable();
4048
4130
  return table2.rows?.[table2.rows.length - 1];
4049
4131
  };
4050
- syntaxTree5(state2).iterate({
4132
+ syntaxTree6(state2).iterate({
4051
4133
  enter: (node) => {
4052
4134
  switch (node.name) {
4053
4135
  case "Table": {
@@ -4208,13 +4290,13 @@ var TextWidget = class extends WidgetType5 {
4208
4290
  };
4209
4291
  var hide = Decoration7.replace({});
4210
4292
  var fencedCodeLine = Decoration7.line({
4211
- class: mx3("cm-code cm-codeblock-line")
4293
+ class: mx2("cm-code cm-codeblock-line")
4212
4294
  });
4213
4295
  var fencedCodeLineFirst = Decoration7.line({
4214
- class: mx3("cm-code cm-codeblock-line", "cm-codeblock-first")
4296
+ class: mx2("cm-code cm-codeblock-line", "cm-codeblock-first")
4215
4297
  });
4216
4298
  var fencedCodeLineLast = Decoration7.line({
4217
- class: mx3("cm-code cm-codeblock-line", "cm-codeblock-last")
4299
+ class: mx2("cm-code cm-codeblock-line", "cm-codeblock-last")
4218
4300
  });
4219
4301
  var commentBlockLine = fencedCodeLine;
4220
4302
  var commentBlockLineFirst = fencedCodeLineFirst;
@@ -4240,8 +4322,6 @@ var autoHideTags = /* @__PURE__ */ new Set([
4240
4322
  "SubscriptMark",
4241
4323
  "SuperscriptMark"
4242
4324
  ]);
4243
- var bulletListIndentationWidth = 24;
4244
- var orderedListIndentationWidth = 36;
4245
4325
  var buildDecorations2 = (view, options, focus) => {
4246
4326
  const deco = new RangeSetBuilder3();
4247
4327
  const atomicDeco = new RangeSetBuilder3();
@@ -4250,7 +4330,7 @@ var buildDecorations2 = (view, options, focus) => {
4250
4330
  const getHeaderLevels = (node, level) => {
4251
4331
  invariant4(level > 0, void 0, {
4252
4332
  F: __dxlog_file10,
4253
- L: 159,
4333
+ L: 157,
4254
4334
  S: void 0,
4255
4335
  A: [
4256
4336
  "level > 0",
@@ -4286,10 +4366,10 @@ var buildDecorations2 = (view, options, focus) => {
4286
4366
  const leaveList = () => {
4287
4367
  listLevels.pop();
4288
4368
  };
4289
- const getCurrentList = () => {
4369
+ const getCurrentListLevel = () => {
4290
4370
  invariant4(listLevels.length, void 0, {
4291
4371
  F: __dxlog_file10,
4292
- L: 181,
4372
+ L: 179,
4293
4373
  S: void 0,
4294
4374
  A: [
4295
4375
  "listLevels.length",
@@ -4339,7 +4419,7 @@ var buildDecorations2 = (view, options, focus) => {
4339
4419
  break;
4340
4420
  }
4341
4421
  case "ListItem": {
4342
- const list = getCurrentList();
4422
+ const list = getCurrentListLevel();
4343
4423
  const width = list.type === "OrderedList" ? orderedListIndentationWidth : bulletListIndentationWidth;
4344
4424
  const offset = ((list.level ?? 0) + 1) * width;
4345
4425
  const line = state2.doc.lineAt(node.from);
@@ -4365,11 +4445,7 @@ var buildDecorations2 = (view, options, focus) => {
4365
4445
  atomicDeco.add(node.from, node.to + 1, hide);
4366
4446
  break;
4367
4447
  }
4368
- const list = getCurrentList();
4369
- const text = state2.doc.sliceString(node.from, node.to + 1);
4370
- if (list.type === "BulletList" && text[1] !== " ") {
4371
- return false;
4372
- }
4448
+ const list = getCurrentListLevel();
4373
4449
  const label = list.type === "OrderedList" ? `${++list.number}.` : "\u2022";
4374
4450
  atomicDeco.add(node.from, node.to + 1, Decoration7.replace({
4375
4451
  widget: new TextWidget(label, list.type === "OrderedList" ? "cm-list-mark cm-list-mark-ordered" : "cm-list-mark cm-list-mark-bullet")
@@ -4469,7 +4545,7 @@ var buildDecorations2 = (view, options, focus) => {
4469
4545
  }
4470
4546
  }
4471
4547
  };
4472
- const tree = syntaxTree6(state2);
4548
+ const tree = syntaxTree7(state2);
4473
4549
  if (options.numberedHeadings?.from === void 0) {
4474
4550
  for (const { from, to } of view.visibleRanges) {
4475
4551
  tree.iterate({
@@ -4498,13 +4574,14 @@ var decorateMarkdown = (options = {}) => {
4498
4574
  ({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations2(view, options, view.hasFocus));
4499
4575
  }
4500
4576
  update(update2) {
4501
- 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) {
4502
4578
  ({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations2(update2.view, options, update2.view.hasFocus));
4503
4579
  this.clearUpdate();
4504
4580
  } else if (update2.selectionSet) {
4505
4581
  this.scheduleUpdate(update2.view);
4506
4582
  }
4507
4583
  }
4584
+ // Defer update in case moving through the document.
4508
4585
  scheduleUpdate(view) {
4509
4586
  this.clearUpdate();
4510
4587
  this.pendingUpdate = setTimeout(() => {
@@ -4524,89 +4601,24 @@ var decorateMarkdown = (options = {}) => {
4524
4601
  }
4525
4602
  }, {
4526
4603
  provide: (plugin) => [
4527
- EditorView14.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration7.none),
4528
- EditorView14.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration7.none),
4529
- 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)
4530
4607
  ]
4531
4608
  }),
4532
- formattingStyles,
4533
- linkPastePlugin,
4534
4609
  image(),
4535
- table()
4610
+ table(),
4611
+ adjustChanges(),
4612
+ formattingStyles
4536
4613
  ];
4537
4614
  };
4538
- var formattingStyles = EditorView14.baseTheme({
4539
- "& .cm-code": {
4540
- fontFamily: getToken("fontFamily.mono")
4541
- },
4542
- "& .cm-codeblock-line": {
4543
- paddingInline: "1rem !important"
4544
- },
4545
- "& .cm-codeblock-end": {
4546
- display: "inline-block",
4547
- width: "100%",
4548
- position: "relative",
4549
- "&::after": {
4550
- position: "absolute",
4551
- inset: 0,
4552
- content: '""'
4553
- }
4554
- },
4555
- "& .cm-codeblock-first": {
4556
- borderTopLeftRadius: ".25rem",
4557
- borderTopRightRadius: ".25rem"
4558
- },
4559
- "& .cm-codeblock-last": {
4560
- borderBottomLeftRadius: ".25rem",
4561
- borderBottomRightRadius: ".25rem"
4562
- },
4563
- "&light .cm-codeblock-line, &light .cm-activeLine.cm-codeblock-line": {
4564
- background: getToken("extend.semanticColors.input.light"),
4565
- mixBlendMode: "darken"
4566
- },
4567
- "&dark .cm-codeblock-line, &dark .cm-activeLine.cm-codeblock-line": {
4568
- background: getToken("extend.semanticColors.input.dark"),
4569
- mixBlendMode: "lighten"
4570
- },
4571
- "& .cm-hr": {
4572
- display: "inline-block",
4573
- width: "100%",
4574
- height: "0",
4575
- verticalAlign: "middle",
4576
- borderTop: `1px solid ${getToken("extend.colors.primary.500")}`,
4577
- opacity: 0.5
4578
- },
4579
- "& .cm-task": {
4580
- display: "inline-block",
4581
- width: `${bulletListIndentationWidth}px`,
4582
- color: getToken("extend.colors.blue.500")
4583
- },
4584
- "& .cm-task-checkbox": {
4585
- display: "grid",
4586
- margin: "0",
4587
- transform: "translateY(2px)"
4588
- },
4589
- "& .cm-list-item": {},
4590
- "& .cm-list-mark": {
4591
- display: "inline-block",
4592
- textAlign: "right",
4593
- paddingRight: "0.5em",
4594
- fontVariant: "tabular-nums"
4595
- },
4596
- "& .cm-list-mark-bullet": {
4597
- width: `${bulletListIndentationWidth}px`
4598
- },
4599
- "& .cm-list-mark-ordered": {
4600
- width: `${orderedListIndentationWidth}px`
4601
- }
4602
- });
4603
4615
 
4604
4616
  // packages/ui/react-ui-editor/src/extensions/markdown/link.ts
4605
- import { syntaxTree as syntaxTree7 } from "@codemirror/language";
4617
+ import { syntaxTree as syntaxTree8 } from "@codemirror/language";
4606
4618
  import { hoverTooltip as hoverTooltip2 } from "@codemirror/view";
4607
4619
  import { tooltipContent } from "@dxos/react-ui-theme";
4608
4620
  var linkTooltip = (render) => hoverTooltip2((view, pos, side) => {
4609
- const syntax = syntaxTree7(view.state).resolveInner(pos, side);
4621
+ const syntax = syntaxTree8(view.state).resolveInner(pos, side);
4610
4622
  let link = null;
4611
4623
  for (let i = 0, node = syntax; !link && node && i < 5; node = node.parent, i++) {
4612
4624
  link = node.name === "Link" ? node : null;
@@ -4724,7 +4736,7 @@ var InputModeExtensions = {
4724
4736
 
4725
4737
  // packages/ui/react-ui-editor/src/extensions/state.ts
4726
4738
  import { Transaction as Transaction2 } from "@codemirror/state";
4727
- import { EditorView as EditorView15, keymap as keymap9 } from "@codemirror/view";
4739
+ import { EditorView as EditorView16, keymap as keymap9 } from "@codemirror/view";
4728
4740
  import { debounce as debounce2 } from "@dxos/async";
4729
4741
  import { invariant as invariant5 } from "@dxos/invariant";
4730
4742
  import { isNotFalsy as isNotFalsy3 } from "@dxos/util";
@@ -4762,7 +4774,7 @@ var createEditorStateTransaction = ({ scrollTo, selection }) => {
4762
4774
  return {
4763
4775
  selection,
4764
4776
  scrollIntoView: !scrollTo,
4765
- effects: scrollTo ? EditorView15.scrollIntoView(scrollTo, {
4777
+ effects: scrollTo ? EditorView16.scrollIntoView(scrollTo, {
4766
4778
  yMargin: 96
4767
4779
  }) : void 0,
4768
4780
  annotations: Transaction2.userEvent.of(stateRestoreAnnotation)
@@ -4777,7 +4789,7 @@ var state = ({ getState, setState } = {}) => {
4777
4789
  // setStateDebounced(id, {});
4778
4790
  // },
4779
4791
  // }),
4780
- EditorView15.updateListener.of(({ view, transactions }) => {
4792
+ EditorView16.updateListener.of(({ view, transactions }) => {
4781
4793
  const id = view.state.facet(documentId2);
4782
4794
  if (!id || transactions.some((tr) => tr.isUserEvent(stateRestoreAnnotation))) {
4783
4795
  return;
@@ -4902,96 +4914,32 @@ var ToolbarRoot = ({ children, onAction, classNames, state: state2 }) => {
4902
4914
  }
4903
4915
  }, children))));
4904
4916
  };
4905
- var ToolbarToggleButton = ({ Icon, children, ...props }) => {
4917
+ var ToolbarToggleButton = ({ Icon: Icon2, children, ...props }) => {
4906
4918
  return /* @__PURE__ */ React3.createElement(Tooltip.Root, null, /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
4907
4919
  asChild: true
4908
4920
  }, /* @__PURE__ */ React3.createElement(NaturalToolbar.ToggleGroupItem, {
4909
4921
  variant: "ghost",
4910
4922
  ...props,
4911
4923
  classNames: buttonStyles
4912
- }, /* @__PURE__ */ React3.createElement(Icon, {
4924
+ }, /* @__PURE__ */ React3.createElement(Icon2, {
4913
4925
  className: iconStyles
4914
4926
  }), /* @__PURE__ */ React3.createElement("span", {
4915
4927
  className: "sr-only"
4916
4928
  }, children))), /* @__PURE__ */ React3.createElement(Tooltip.Portal, null, /* @__PURE__ */ React3.createElement(Tooltip.Content, tooltipProps, children, /* @__PURE__ */ React3.createElement(Tooltip.Arrow, null))));
4917
4929
  };
4918
- var ToolbarButton = ({ Icon, children, ...props }) => {
4930
+ var ToolbarButton = ({ Icon: Icon2, children, ...props }) => {
4919
4931
  return /* @__PURE__ */ React3.createElement(Tooltip.Root, null, /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
4920
4932
  asChild: true
4921
4933
  }, /* @__PURE__ */ React3.createElement(NaturalToolbar.Button, {
4922
4934
  variant: "ghost",
4923
4935
  ...props,
4924
4936
  classNames: buttonStyles
4925
- }, /* @__PURE__ */ React3.createElement(Icon, {
4937
+ }, /* @__PURE__ */ React3.createElement(Icon2, {
4926
4938
  className: iconStyles
4927
4939
  }), /* @__PURE__ */ React3.createElement("span", {
4928
4940
  className: "sr-only"
4929
4941
  }, children))), /* @__PURE__ */ React3.createElement(Tooltip.Portal, null, /* @__PURE__ */ React3.createElement(Tooltip.Content, tooltipProps, children, /* @__PURE__ */ React3.createElement(Tooltip.Arrow, null))));
4930
4942
  };
4931
- var ViewModeIcons = {
4932
- preview: PencilSimple,
4933
- readonly: PencilSimpleSlash,
4934
- source: MarkdownLogo
4935
- };
4936
- var MarkdownView = ({ mode }) => {
4937
- const { t } = useTranslation(translationKey);
4938
- const { onAction } = useToolbarContext("ViewMode");
4939
- const ModeIcon = ViewModeIcons[mode ?? "preview"];
4940
- const suppressNextTooltip = useRef(false);
4941
- const [tooltipOpen, setTooltipOpen] = useState3(false);
4942
- const [selectOpen, setSelectOpen] = useState3(false);
4943
- return /* @__PURE__ */ React3.createElement(Tooltip.Root, {
4944
- open: tooltipOpen,
4945
- onOpenChange: (nextOpen) => {
4946
- if (nextOpen && suppressNextTooltip.current) {
4947
- suppressNextTooltip.current = false;
4948
- return setTooltipOpen(false);
4949
- } else {
4950
- return setTooltipOpen(nextOpen);
4951
- }
4952
- }
4953
- }, /* @__PURE__ */ React3.createElement(DropdownMenu.Root, {
4954
- open: selectOpen,
4955
- onOpenChange: (nextOpen) => {
4956
- if (!nextOpen) {
4957
- suppressNextTooltip.current = true;
4958
- }
4959
- return setSelectOpen(nextOpen);
4960
- }
4961
- }, /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
4962
- asChild: true
4963
- }, /* @__PURE__ */ React3.createElement(NaturalToolbar.Button, {
4964
- asChild: true
4965
- }, /* @__PURE__ */ React3.createElement(DropdownMenu.Trigger, {
4966
- asChild: true
4967
- }, /* @__PURE__ */ React3.createElement(Button, {
4968
- variant: "ghost",
4969
- classNames: buttonStyles
4970
- }, /* @__PURE__ */ React3.createElement("span", {
4971
- className: "sr-only"
4972
- }, t("mode label")), /* @__PURE__ */ React3.createElement(ModeIcon, {
4973
- className: iconStyles
4974
- }), /* @__PURE__ */ React3.createElement(CaretDown, null))))), /* @__PURE__ */ React3.createElement(DropdownMenu.Portal, null, /* @__PURE__ */ React3.createElement(DropdownMenu.Content, {
4975
- classNames: "is-min md:is-min",
4976
- onCloseAutoFocus: (e) => e.preventDefault()
4977
- }, /* @__PURE__ */ React3.createElement(DropdownMenu.Viewport, null, EditorViewModes.map((value) => {
4978
- const Icon = ViewModeIcons[value];
4979
- return /* @__PURE__ */ React3.createElement(DropdownMenu.CheckboxItem, {
4980
- key: value,
4981
- checked: value === mode,
4982
- onClick: () => onAction?.({
4983
- type: "view-mode",
4984
- data: value
4985
- })
4986
- }, /* @__PURE__ */ React3.createElement(Icon, {
4987
- className: iconStyles
4988
- }), /* @__PURE__ */ React3.createElement("span", {
4989
- className: "whitespace-nowrap grow"
4990
- }, t(`${value} mode label`)), /* @__PURE__ */ React3.createElement(Check, {
4991
- className: value === mode ? "visible" : "invisible"
4992
- }));
4993
- })), /* @__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))));
4994
- };
4995
4943
  var HeadingIcons = {
4996
4944
  "0": Paragraph,
4997
4945
  "1": TextHOne,
@@ -5047,7 +4995,7 @@ var MarkdownHeading = () => {
5047
4995
  classNames: "is-min md:is-min",
5048
4996
  onCloseAutoFocus: (e) => e.preventDefault()
5049
4997
  }, /* @__PURE__ */ React3.createElement(DropdownMenu.Viewport, null, Object.keys(HeadingIcons).map((level) => {
5050
- const Icon = HeadingIcons[level];
4998
+ const Icon2 = HeadingIcons[level];
5051
4999
  return /* @__PURE__ */ React3.createElement(DropdownMenu.CheckboxItem, {
5052
5000
  key: level,
5053
5001
  checked: value === level,
@@ -5059,7 +5007,7 @@ var MarkdownHeading = () => {
5059
5007
  className: "sr-only"
5060
5008
  }, t("heading level label", {
5061
5009
  count: parseInt(level)
5062
- })), /* @__PURE__ */ React3.createElement(Icon, {
5010
+ })), /* @__PURE__ */ React3.createElement(Icon2, {
5063
5011
  className: iconStyles
5064
5012
  }), /* @__PURE__ */ React3.createElement(DropdownMenu.ItemIndicator, null, /* @__PURE__ */ React3.createElement(Check, null)));
5065
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))));
@@ -5097,10 +5045,10 @@ var MarkdownStyles = () => {
5097
5045
  return /* @__PURE__ */ React3.createElement(NaturalToolbar.ToggleGroup, {
5098
5046
  type: "multiple",
5099
5047
  value: markdownStyles.filter(({ getState }) => state2 && getState(state2)).map(({ type }) => type)
5100
- }, markdownStyles.map(({ type, getState, Icon }) => /* @__PURE__ */ React3.createElement(ToolbarToggleButton, {
5048
+ }, markdownStyles.map(({ type, getState, Icon: Icon2 }) => /* @__PURE__ */ React3.createElement(ToolbarToggleButton, {
5101
5049
  key: type,
5102
5050
  value: type,
5103
- Icon,
5051
+ Icon: Icon2,
5104
5052
  disabled: state2?.blockType === "codeblock",
5105
5053
  onClick: state2 ? () => onAction?.({
5106
5054
  type,
@@ -5131,10 +5079,10 @@ var MarkdownLists = () => {
5131
5079
  return /* @__PURE__ */ React3.createElement(NaturalToolbar.ToggleGroup, {
5132
5080
  type: "single",
5133
5081
  value: state2?.listStyle ? `list-${state2.listStyle}` : ""
5134
- }, markdownLists.map(({ type, getState, Icon }) => /* @__PURE__ */ React3.createElement(ToolbarToggleButton, {
5082
+ }, markdownLists.map(({ type, getState, Icon: Icon2 }) => /* @__PURE__ */ React3.createElement(ToolbarToggleButton, {
5135
5083
  key: type,
5136
5084
  value: type,
5137
- Icon,
5085
+ Icon: Icon2,
5138
5086
  onClick: state2 ? () => onAction?.({
5139
5087
  type,
5140
5088
  data: !getState(state2)
@@ -5166,10 +5114,10 @@ var MarkdownBlocks = () => {
5166
5114
  return /* @__PURE__ */ React3.createElement(NaturalToolbar.ToggleGroup, {
5167
5115
  type: "single",
5168
5116
  value: value?.type ?? ""
5169
- }, markdownBlocks.map(({ type, disabled, getState, Icon }) => /* @__PURE__ */ React3.createElement(ToolbarToggleButton, {
5117
+ }, markdownBlocks.map(({ type, disabled, getState, Icon: Icon2 }) => /* @__PURE__ */ React3.createElement(ToolbarToggleButton, {
5170
5118
  key: type,
5171
5119
  value: type,
5172
- Icon,
5120
+ Icon: Icon2,
5173
5121
  disabled: !state2 || disabled?.(state2),
5174
5122
  onClick: state2 ? () => onAction?.({
5175
5123
  type,
@@ -5221,16 +5169,86 @@ var MarkdownCustom = ({ onUpload } = {}) => {
5221
5169
  onClick: () => open()
5222
5170
  }, t("image label")));
5223
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
+ };
5224
5236
  var MarkdownActions = () => {
5225
5237
  const { onAction, state: state2 } = useToolbarContext("MarkdownActions");
5226
5238
  const { t } = useTranslation(translationKey);
5227
- let toolTipKey = "comment label";
5239
+ let commentToolTipKey = "comment label";
5228
5240
  if (state2?.comment) {
5229
- toolTipKey = "selection overlaps existing comment label";
5241
+ commentToolTipKey = "selection overlaps existing comment label";
5230
5242
  } else if (state2?.selection === false) {
5231
- toolTipKey = "select text to comment label";
5243
+ commentToolTipKey = "select text to comment label";
5232
5244
  }
5233
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, {
5234
5252
  value: "comment",
5235
5253
  Icon: ChatText,
5236
5254
  "data-testid": "editor.toolbar.comment",
@@ -5238,7 +5256,7 @@ var MarkdownActions = () => {
5238
5256
  type: "comment"
5239
5257
  }),
5240
5258
  disabled: !state2 || state2.comment || !state2.selection
5241
- }, t(toolTipKey)));
5259
+ }, t(commentToolTipKey)));
5242
5260
  };
5243
5261
  var Toolbar = {
5244
5262
  Root: ToolbarRoot,
@@ -5251,23 +5269,21 @@ var Toolbar = {
5251
5269
  };
5252
5270
 
5253
5271
  // packages/ui/react-ui-editor/src/defaults.ts
5254
- import { EditorView as EditorView16 } from "@codemirror/view";
5255
- 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]");
5256
5277
  var editorWithToolbarLayout = "grid grid-cols-1 grid-rows-[min-content_1fr] data-[toolbar=disabled]:grid-rows-[1fr] justify-center content-start overflow-hidden";
5257
- var editorGutter = EditorView16.baseTheme({
5278
+ var editorGutter = EditorView17.theme({
5279
+ // Match margin from content.
5258
5280
  ".cm-gutters": {
5259
- // Match margin from content.
5260
- marginTop: "16px",
5261
- marginBottom: "16px",
5262
- // Inside within content margin.
5263
- marginRight: "-32px",
5264
- width: "32px",
5265
- backgroundColor: "transparent !important"
5281
+ marginTop: "16px"
5266
5282
  }
5267
5283
  });
5268
- var editorMonospace = EditorView16.baseTheme({
5284
+ var editorMonospace = EditorView17.theme({
5269
5285
  ".cm-content": {
5270
- fontFamily: `${getToken("fontFamily.mono")} !important`
5286
+ fontFamily: fontMono
5271
5287
  }
5272
5288
  });
5273
5289
 
@@ -5278,7 +5294,7 @@ var useActionHandler = (view) => {
5278
5294
 
5279
5295
  // packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
5280
5296
  import { EditorState as EditorState2 } from "@codemirror/state";
5281
- import { EditorView as EditorView17 } from "@codemirror/view";
5297
+ import { EditorView as EditorView18 } from "@codemirror/view";
5282
5298
  import { useFocusableGroup } from "@fluentui/react-tabster";
5283
5299
  import { useCallback, useEffect as useEffect3, useMemo as useMemo3, useRef as useRef2, useState as useState4 } from "react";
5284
5300
  import { log as log8 } from "@dxos/log";
@@ -5324,7 +5340,7 @@ var useTextEditor = (props = {}, deps = []) => {
5324
5340
  extensions: [
5325
5341
  id && documentId2.of(id),
5326
5342
  // NOTE: Doesn't catch errors in keymap functions.
5327
- EditorView17.exceptionSink.of((err) => {
5343
+ EditorView18.exceptionSink.of((err) => {
5328
5344
  log8.catch(err, void 0, {
5329
5345
  F: __dxlog_file13,
5330
5346
  L: 100,
@@ -5333,14 +5349,14 @@ var useTextEditor = (props = {}, deps = []) => {
5333
5349
  });
5334
5350
  }),
5335
5351
  extensions,
5336
- EditorView17.updateListener.of(() => {
5352
+ EditorView18.updateListener.of(() => {
5337
5353
  setTimeout(() => {
5338
5354
  onUpdate.current?.();
5339
5355
  });
5340
5356
  })
5341
5357
  ].filter(isNotFalsy4)
5342
5358
  });
5343
- view2 = new EditorView17({
5359
+ view2 = new EditorView18({
5344
5360
  parent: parentRef.current,
5345
5361
  selection: initialSelection,
5346
5362
  state: state2,
@@ -5454,6 +5470,7 @@ export {
5454
5470
  command,
5455
5471
  comments,
5456
5472
  commentsState,
5473
+ convertTreeToJson,
5457
5474
  createBasicExtensions,
5458
5475
  createComment,
5459
5476
  createDataExtensions,
@@ -5462,11 +5479,13 @@ export {
5462
5479
  createMarkdownExtensions,
5463
5480
  createThemeExtensions,
5464
5481
  debugNodeLogger,
5482
+ debugTree,
5465
5483
  decorateMarkdown,
5466
5484
  defaultOptions,
5467
5485
  documentId2 as documentId,
5468
5486
  dropFile,
5469
5487
  editorContent,
5488
+ editorFullWidth,
5470
5489
  editorGutter,
5471
5490
  editorInputMode,
5472
5491
  editorMonospace,
@@ -5476,7 +5495,6 @@ export {
5476
5495
  formattingEquals,
5477
5496
  formattingKeymap,
5478
5497
  getFormatting,
5479
- getToken,
5480
5498
  image,
5481
5499
  imageUpload,
5482
5500
  insertTable,