@dxos/react-ui-editor 0.6.9 → 0.6.10-main.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 (75) hide show
  1. package/dist/lib/browser/index.mjs +759 -732
  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 +2 -1
  5. package/dist/types/src/InputMode.stories.d.ts.map +1 -1
  6. package/dist/types/src/TextEditor.stories.d.ts +20 -13
  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 +2 -1
  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 -5
  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/InputMode.stories.tsx +1 -1
  45. package/src/TextEditor.stories.tsx +125 -77
  46. package/src/components/Toolbar/Toolbar.tsx +91 -92
  47. package/src/defaults.ts +16 -11
  48. package/src/extensions/annotations.ts +2 -2
  49. package/src/extensions/autocomplete.ts +4 -1
  50. package/src/extensions/automerge/automerge.stories.tsx +1 -1
  51. package/src/extensions/awareness/awareness.ts +1 -1
  52. package/src/extensions/comments.ts +11 -45
  53. package/src/extensions/dnd.ts +3 -5
  54. package/src/extensions/factories.ts +8 -8
  55. package/src/extensions/folding.tsx +3 -4
  56. package/src/extensions/markdown/action.ts +1 -0
  57. package/src/extensions/markdown/bundle.ts +3 -1
  58. package/src/extensions/markdown/{link-paste.test.ts → changes.test.ts} +2 -2
  59. package/src/extensions/markdown/changes.ts +148 -0
  60. package/src/extensions/markdown/debug.ts +44 -0
  61. package/src/extensions/markdown/decorate.ts +35 -108
  62. package/src/extensions/markdown/formatting.ts +1 -2
  63. package/src/extensions/markdown/highlight.ts +2 -2
  64. package/src/extensions/markdown/index.ts +1 -0
  65. package/src/extensions/markdown/parser.test.ts +29 -0
  66. package/src/extensions/markdown/styles.ts +103 -0
  67. package/src/index.ts +0 -2
  68. package/src/styles/theme.ts +85 -147
  69. package/src/styles/tokens.ts +6 -6
  70. package/src/translations.ts +1 -0
  71. package/dist/types/src/extensions/markdown/link-paste.d.ts +0 -9
  72. package/dist/types/src/extensions/markdown/link-paste.d.ts.map +0 -1
  73. package/dist/types/src/extensions/markdown/link-paste.test.d.ts +0 -2
  74. package/dist/types/src/extensions/markdown/link-paste.test.d.ts.map +0 -1
  75. 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": {
@@ -2295,89 +1990,318 @@ var dropFile = (options = {}) => {
2295
1990
 
2296
1991
  // packages/ui/react-ui-editor/src/extensions/factories.ts
2297
1992
  import { closeBrackets, closeBracketsKeymap } from "@codemirror/autocomplete";
2298
- import { defaultKeymap, history, historyKeymap, standardKeymap } from "@codemirror/commands";
1993
+ import { defaultKeymap, history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
2299
1994
  import { bracketMatching } from "@codemirror/language";
2300
1995
  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
- props.highlightActiveLine && highlightActiveLine(),
2345
- props.history && history(),
2346
- props.lineNumbers && lineNumbers(),
2347
- props.lineWrapping && EditorView9.lineWrapping,
2348
- props.placeholder && placeholder(props.placeholder),
2349
- props.readonly && [
2350
- EditorState.readOnly.of(true),
2351
- EditorView9.editable.of(false)
2352
- ],
2353
- props.scrollPastEnd && scrollPastEnd(),
2354
- props.tabSize && EditorState.tabSize.of(props.tabSize),
2355
- // https://codemirror.net/docs/ref/#view.KeyBinding
2356
- keymap5.of([
2357
- ...(props.keymap && keymaps[props.keymap]) ?? [],
2358
- // NOTE: Tab configured by markdown extension.
2359
- // https://codemirror.net/docs/ref/#commands.indentWithTab
2360
- // ...(props.indentWithTab ? [indentWithTab] : []),
2361
- // https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
2362
- ...props.closeBrackets ? closeBracketsKeymap : [],
2363
- // https://codemirror.net/docs/ref/#commands.historyKeymap
2364
- ...props.history ? historyKeymap : [],
2365
- // https://codemirror.net/docs/ref/#search.searchKeymap
2366
- ...props.search ? searchKeymap : []
2367
- ].filter(isNotFalsy2))
2368
- ].filter(isNotFalsy2);
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
2287
+ ...props.closeBrackets ? closeBracketsKeymap : [],
2288
+ // https://codemirror.net/docs/ref/#commands.historyKeymap
2289
+ ...props.history ? historyKeymap : [],
2290
+ // https://codemirror.net/docs/ref/#search.searchKeymap
2291
+ ...props.search ? searchKeymap : []
2292
+ ].filter(isNotFalsy2))
2293
+ ].filter(isNotFalsy2);
2369
2294
  };
2370
2295
  var defaultThemeSlots = {
2371
2296
  editor: {
2372
2297
  className: "w-full bs-full"
2373
2298
  }
2374
2299
  };
2375
- var createThemeExtensions = ({ theme: theme2, themeMode, slots: _slots } = {}) => {
2300
+ var createThemeExtensions = ({ themeMode, styles: styles5, slots: _slots } = {}) => {
2376
2301
  const slots = defaultsDeep2({}, _slots, defaultThemeSlots);
2377
2302
  return [
2378
- EditorView9.baseTheme(defaultTheme),
2379
2303
  EditorView9.darkTheme.of(themeMode === "dark"),
2380
- theme2 && EditorView9.theme(theme2),
2304
+ EditorView9.baseTheme(styles5 ? merge({}, defaultTheme, styles5) : defaultTheme),
2381
2305
  slots.editor?.className && EditorView9.editorAttributes.of({
2382
2306
  class: slots.editor.className
2383
2307
  }),
@@ -2411,18 +2335,22 @@ var createDataExtensions = ({ id, text, space, identity }) => {
2411
2335
  // packages/ui/react-ui-editor/src/extensions/folding.tsx
2412
2336
  import { codeFolding, foldGutter } from "@codemirror/language";
2413
2337
  import React2 from "react";
2414
- 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";
2415
2340
  var folding = (_props = {}) => [
2416
2341
  codeFolding({
2417
2342
  placeholderDOM: () => document.createElement("div")
2418
2343
  }),
2419
2344
  foldGutter({
2420
2345
  markerDOM: (open) => {
2421
- return renderRoot(document.createElement("div"), /* @__PURE__ */ React2.createElement("svg", {
2422
- className: mx2(getSize(3), "m-3 cursor-pointer", open && "rotate-90")
2423
- }, /* @__PURE__ */ React2.createElement("use", {
2424
- href: "/icons.svg#ph--caret-right--regular"
2425
- })));
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
+ }));
2426
2354
  }
2427
2355
  })
2428
2356
  ];
@@ -2443,7 +2371,6 @@ var listener = ({ onFocus, onChange }) => {
2443
2371
 
2444
2372
  // packages/ui/react-ui-editor/src/extensions/markdown/formatting.ts
2445
2373
  import { snippet } from "@codemirror/autocomplete";
2446
- import { indentWithTab } from "@codemirror/commands";
2447
2374
  import { syntaxTree as syntaxTree2 } from "@codemirror/language";
2448
2375
  import { EditorSelection } from "@codemirror/state";
2449
2376
  import { EditorView as EditorView11, keymap as keymap6 } from "@codemirror/view";
@@ -3792,7 +3719,7 @@ var markdownHighlightStyle = (_options = {}) => {
3792
3719
  ], {
3793
3720
  scope: markdownLanguage2,
3794
3721
  all: {
3795
- fontFamily: getToken("fontFamily.body")
3722
+ fontFamily: fontBody
3796
3723
  }
3797
3724
  });
3798
3725
  };
@@ -3812,6 +3739,8 @@ var createMarkdownExtensions = ({ themeMode } = {}) => {
3812
3739
  base: markdownLanguage3,
3813
3740
  // Languages for syntax highlighting fenced code blocks.
3814
3741
  codeLanguages: languages,
3742
+ // Don't complete HTML tags.
3743
+ completeHTMLTags: false,
3815
3744
  // Parser extensions.
3816
3745
  extensions: [
3817
3746
  // GFM provided by default.
@@ -3823,7 +3752,6 @@ var createMarkdownExtensions = ({ themeMode } = {}) => {
3823
3752
  // Custom styles.
3824
3753
  syntaxHighlighting(markdownHighlightStyle()),
3825
3754
  keymap7.of([
3826
- // TODO(burdon): Indent by 4 if in task list.
3827
3755
  // https://codemirror.net/docs/ref/#commands.indentWithTab
3828
3756
  indentWithTab2,
3829
3757
  // https://codemirror.net/docs/ref/#commands.defaultKeymap
@@ -3834,44 +3762,209 @@ var createMarkdownExtensions = ({ themeMode } = {}) => {
3834
3762
  ];
3835
3763
  };
3836
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
+
3837
3792
  // packages/ui/react-ui-editor/src/extensions/markdown/decorate.ts
3838
- import { syntaxTree as syntaxTree6 } from "@codemirror/language";
3793
+ import { syntaxTree as syntaxTree7 } from "@codemirror/language";
3839
3794
  import { RangeSetBuilder as RangeSetBuilder3, StateEffect as StateEffect4 } from "@codemirror/state";
3840
- 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";
3841
3796
  import { invariant as invariant4 } from "@dxos/invariant";
3842
- import { mx as mx3 } from "@dxos/react-ui-theme";
3797
+ import { mx as mx2 } from "@dxos/react-ui-theme";
3843
3798
 
3844
- // packages/ui/react-ui-editor/src/extensions/markdown/image.ts
3845
- import { syntaxTree as syntaxTree3 } from "@codemirror/language";
3846
- import { StateField as StateField6 } from "@codemirror/state";
3847
- import { Decoration as Decoration5, EditorView as EditorView12, WidgetType as WidgetType3 } from "@codemirror/view";
3848
- var image = (_options = {}) => {
3849
- return StateField6.define({
3850
- create: (state2) => {
3851
- return Decoration5.set(buildDecorations(0, state2.doc.length, state2));
3852
- },
3853
- update: (value, tr) => {
3854
- if (!tr.docChanged && !tr.selection) {
3855
- 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
+ }
3856
3878
  }
3857
- const cursor = tr.state.selection.main.head;
3858
- const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
3859
- let from = Math.min(cursor, oldCursor);
3860
- let to = Math.max(cursor, oldCursor);
3861
- tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
3862
- from = Math.min(from, fromB);
3863
- to = Math.max(to, toB);
3864
- });
3865
- from = tr.state.doc.lineAt(from).from;
3866
- to = tr.state.doc.lineAt(to).to;
3867
- return value.map(tr.changes).update({
3868
- filterFrom: from,
3869
- filterTo: to,
3870
- filter: () => false,
3871
- add: buildDecorations(from, to, tr.state)
3872
- });
3873
- },
3874
- provide: (field) => EditorView12.decorations.from(field)
3879
+ if (adjustments.length) {
3880
+ setTimeout(() => {
3881
+ update2.view.dispatch(update2.view.state.update({
3882
+ changes: adjustments
3883
+ }));
3884
+ });
3885
+ }
3886
+ }
3887
+ });
3888
+ };
3889
+ var createLink = (url, label) => {
3890
+ const { host, pathname } = url;
3891
+ const [, extension] = pathname.split(".");
3892
+ const imageExtensions = [
3893
+ "jpg",
3894
+ "jpeg",
3895
+ "png",
3896
+ "gif",
3897
+ "svg",
3898
+ "webp"
3899
+ ];
3900
+ if (imageExtensions.includes(extension)) {
3901
+ return `![${label || host}](${url})`;
3902
+ }
3903
+ if (!label) {
3904
+ label = createLinkLabel(url);
3905
+ }
3906
+ return `[${label}](${url})`;
3907
+ };
3908
+ var createLinkLabel = (url) => {
3909
+ let { protocol, host, pathname } = url;
3910
+ if (protocol === "http:" || protocol === "https:") {
3911
+ protocol = "";
3912
+ }
3913
+ host = host.replace(/^www\./, "");
3914
+ return [
3915
+ protocol,
3916
+ host
3917
+ ].filter(Boolean).join("//") + (pathname !== "/" ? pathname : "");
3918
+ };
3919
+ var getValidUrl = (str) => {
3920
+ const validProtocols = [
3921
+ "http:",
3922
+ "https:",
3923
+ "mailto:",
3924
+ "tel:"
3925
+ ];
3926
+ try {
3927
+ const url = new URL(str);
3928
+ if (!validProtocols.includes(url.protocol)) {
3929
+ return void 0;
3930
+ }
3931
+ return url;
3932
+ } catch (_err) {
3933
+ return void 0;
3934
+ }
3935
+ };
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)
3875
3968
  });
3876
3969
  };
3877
3970
  var preloaded = /* @__PURE__ */ new Set();
@@ -3885,7 +3978,7 @@ var preloadImage = (url) => {
3885
3978
  var buildDecorations = (from, to, state2) => {
3886
3979
  const decorations = [];
3887
3980
  const cursor = state2.selection.main.head;
3888
- syntaxTree3(state2).iterate({
3981
+ syntaxTree5(state2).iterate({
3889
3982
  enter: (node) => {
3890
3983
  if (node.name === "Image") {
3891
3984
  const urlNode = node.node.getChild("URL");
@@ -3924,112 +4017,107 @@ var ImageWidget = class extends WidgetType3 {
3924
4017
  var imageUpload = (options = {}) => {
3925
4018
  };
3926
4019
 
3927
- // packages/ui/react-ui-editor/src/extensions/markdown/link-paste.ts
3928
- import { syntaxTree as syntaxTree4 } from "@codemirror/language";
3929
- import { Transaction } from "@codemirror/state";
3930
- import { ViewPlugin as ViewPlugin5 } from "@codemirror/view";
3931
- var linkPastePlugin = ViewPlugin5.fromClass(class {
3932
- update(update2) {
3933
- for (const tr of update2.transactions) {
3934
- const event = tr.annotation(Transaction.userEvent);
3935
- if (event === "input.paste") {
3936
- const changes = tr.changes;
3937
- if (changes.empty) {
3938
- return;
3939
- }
3940
- changes.iterChangedRanges((fromA, toA, fromB, toB) => {
3941
- const insertedUrl = getValidUrl(update2.view.state.sliceDoc(fromB, toB));
3942
- if (insertedUrl && isValidPosition(update2.view.state, fromB)) {
3943
- const replacedText = tr.startState.sliceDoc(fromA, toA);
3944
- setTimeout(() => {
3945
- update2.view.dispatch(update2.view.state.update({
3946
- changes: {
3947
- from: fromA,
3948
- to: toB,
3949
- insert: createLink(insertedUrl, replacedText)
3950
- }
3951
- }));
3952
- });
3953
- }
3954
- });
3955
- }
3956
- }
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"
3957
4109
  }
3958
4110
  });
3959
- var createLink = (url, label) => {
3960
- const { host, pathname } = url;
3961
- const [, extension] = pathname.split(".");
3962
- const imageExtensions = [
3963
- "jpg",
3964
- "jpeg",
3965
- "png",
3966
- "gif",
3967
- "svg",
3968
- "webp"
3969
- ];
3970
- if (imageExtensions.includes(extension)) {
3971
- return `![${label || host}](${url})`;
3972
- }
3973
- if (!label) {
3974
- label = createLinkLabel(url);
3975
- }
3976
- return `[${label}](${url})`;
3977
- };
3978
- var createLinkLabel = (url) => {
3979
- let { protocol, host, pathname } = url;
3980
- if (protocol === "http:" || protocol === "https:") {
3981
- protocol = "";
3982
- }
3983
- host = host.replace(/^www\./, "");
3984
- return [
3985
- protocol,
3986
- host
3987
- ].filter(Boolean).join("//") + (pathname !== "/" ? pathname : "");
3988
- };
3989
- var getValidUrl = (str) => {
3990
- const validProtocols = [
3991
- "http:",
3992
- "https:",
3993
- "mailto:",
3994
- "tel:"
3995
- ];
3996
- try {
3997
- const url = new URL(str);
3998
- if (!validProtocols.includes(url.protocol)) {
3999
- return void 0;
4000
- }
4001
- return url;
4002
- } catch (_err) {
4003
- return void 0;
4004
- }
4005
- };
4006
- var isValidPosition = (state2, pos) => {
4007
- const invalidPositions = /* @__PURE__ */ new Set([
4008
- "Link",
4009
- "LinkMark",
4010
- "Code",
4011
- "FencedCode"
4012
- ]);
4013
- const tree = syntaxTree4(state2);
4014
- let node = tree.resolveInner(pos, -1);
4015
- while (node) {
4016
- if (invalidPositions.has(node.name)) {
4017
- return false;
4018
- }
4019
- node = node.parent;
4020
- }
4021
- return true;
4022
- };
4023
4111
 
4024
4112
  // packages/ui/react-ui-editor/src/extensions/markdown/table.ts
4025
- import { syntaxTree as syntaxTree5 } from "@codemirror/language";
4026
- import { RangeSetBuilder as RangeSetBuilder2, StateField as StateField7 } from "@codemirror/state";
4027
- 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";
4028
4116
  var table = (options = {}) => {
4029
- return StateField7.define({
4117
+ return StateField8.define({
4030
4118
  create: (state2) => update(state2, options),
4031
4119
  update: (_, tr) => update(tr.state, options),
4032
- provide: (field) => EditorView13.decorations.from(field)
4120
+ provide: (field) => EditorView14.decorations.from(field)
4033
4121
  });
4034
4122
  };
4035
4123
  var update = (state2, _options) => {
@@ -4041,7 +4129,7 @@ var update = (state2, _options) => {
4041
4129
  const table2 = getTable();
4042
4130
  return table2.rows?.[table2.rows.length - 1];
4043
4131
  };
4044
- syntaxTree5(state2).iterate({
4132
+ syntaxTree6(state2).iterate({
4045
4133
  enter: (node) => {
4046
4134
  switch (node.name) {
4047
4135
  case "Table": {
@@ -4202,13 +4290,13 @@ var TextWidget = class extends WidgetType5 {
4202
4290
  };
4203
4291
  var hide = Decoration7.replace({});
4204
4292
  var fencedCodeLine = Decoration7.line({
4205
- class: mx3("cm-code cm-codeblock-line")
4293
+ class: mx2("cm-code cm-codeblock-line")
4206
4294
  });
4207
4295
  var fencedCodeLineFirst = Decoration7.line({
4208
- class: mx3("cm-code cm-codeblock-line", "cm-codeblock-first")
4296
+ class: mx2("cm-code cm-codeblock-line", "cm-codeblock-first")
4209
4297
  });
4210
4298
  var fencedCodeLineLast = Decoration7.line({
4211
- class: mx3("cm-code cm-codeblock-line", "cm-codeblock-last")
4299
+ class: mx2("cm-code cm-codeblock-line", "cm-codeblock-last")
4212
4300
  });
4213
4301
  var commentBlockLine = fencedCodeLine;
4214
4302
  var commentBlockLineFirst = fencedCodeLineFirst;
@@ -4234,8 +4322,6 @@ var autoHideTags = /* @__PURE__ */ new Set([
4234
4322
  "SubscriptMark",
4235
4323
  "SuperscriptMark"
4236
4324
  ]);
4237
- var bulletListIndentationWidth = 24;
4238
- var orderedListIndentationWidth = 32;
4239
4325
  var buildDecorations2 = (view, options, focus) => {
4240
4326
  const deco = new RangeSetBuilder3();
4241
4327
  const atomicDeco = new RangeSetBuilder3();
@@ -4244,7 +4330,7 @@ var buildDecorations2 = (view, options, focus) => {
4244
4330
  const getHeaderLevels = (node, level) => {
4245
4331
  invariant4(level > 0, void 0, {
4246
4332
  F: __dxlog_file10,
4247
- L: 159,
4333
+ L: 157,
4248
4334
  S: void 0,
4249
4335
  A: [
4250
4336
  "level > 0",
@@ -4280,10 +4366,10 @@ var buildDecorations2 = (view, options, focus) => {
4280
4366
  const leaveList = () => {
4281
4367
  listLevels.pop();
4282
4368
  };
4283
- const getCurrentList = () => {
4369
+ const getCurrentListLevel = () => {
4284
4370
  invariant4(listLevels.length, void 0, {
4285
4371
  F: __dxlog_file10,
4286
- L: 181,
4372
+ L: 179,
4287
4373
  S: void 0,
4288
4374
  A: [
4289
4375
  "listLevels.length",
@@ -4333,34 +4419,35 @@ var buildDecorations2 = (view, options, focus) => {
4333
4419
  break;
4334
4420
  }
4335
4421
  case "ListItem": {
4336
- const list = getCurrentList();
4422
+ const list = getCurrentListLevel();
4337
4423
  const width = list.type === "OrderedList" ? orderedListIndentationWidth : bulletListIndentationWidth;
4338
4424
  const offset = ((list.level ?? 0) + 1) * width;
4339
- const start = state2.doc.lineAt(node.from);
4340
- deco.add(start.from, start.from, Decoration7.line({
4425
+ const line = state2.doc.lineAt(node.from);
4426
+ if (node.from === line.to - 1) {
4427
+ return false;
4428
+ }
4429
+ deco.add(line.from, line.from, Decoration7.line({
4341
4430
  class: "cm-list-item",
4342
4431
  attributes: {
4343
- // Subtract 0.25em to account for the space CM adds to Paragraph nodes following the ListItem.
4344
- // Note: This makes the cursor appear to be left of the margin.
4345
- style: `padding-left: ${offset}px; text-indent: calc(-${width}px - 0.25em);`
4432
+ style: `padding-left: ${offset}px; text-indent: -${width}px;`
4346
4433
  }
4347
4434
  }));
4348
- const line = state2.doc.sliceString(start.from, node.to);
4349
- const whitespace = line.match(/^ */)?.[0].length ?? 0;
4435
+ const text = state2.doc.sliceString(line.from, node.to);
4436
+ const whitespace = text.match(/^ */)?.[0].length ?? 0;
4350
4437
  if (whitespace) {
4351
- atomicDeco.add(start.from, start.from + whitespace, hide);
4438
+ atomicDeco.add(line.from, line.from + whitespace, hide);
4352
4439
  }
4353
4440
  break;
4354
4441
  }
4355
4442
  case "ListMark": {
4356
- const task = tree.resolve(node.to + 1, 1).name === "TaskMarker";
4357
- if (task) {
4358
- atomicDeco.add(node.from, node.to, hide);
4443
+ const next = tree.resolve(node.to + 1, 1);
4444
+ if (next?.name === "TaskMarker") {
4445
+ atomicDeco.add(node.from, node.to + 1, hide);
4359
4446
  break;
4360
4447
  }
4361
- const list = getCurrentList();
4362
- const label = list.type === "OrderedList" ? `${++list.number}.` : "-";
4363
- atomicDeco.add(node.from, node.to, Decoration7.replace({
4448
+ const list = getCurrentListLevel();
4449
+ const label = list.type === "OrderedList" ? `${++list.number}.` : "\u2022";
4450
+ atomicDeco.add(node.from, node.to + 1, Decoration7.replace({
4364
4451
  widget: new TextWidget(label, list.type === "OrderedList" ? "cm-list-mark cm-list-mark-ordered" : "cm-list-mark cm-list-mark-bullet")
4365
4452
  }));
4366
4453
  break;
@@ -4368,10 +4455,7 @@ var buildDecorations2 = (view, options, focus) => {
4368
4455
  case "TaskMarker": {
4369
4456
  if (!editingRange(state2, node, focus)) {
4370
4457
  const checked = state2.doc.sliceString(node.from + 1, node.to - 1) === "x";
4371
- atomicDeco.add(node.from - 2, node.from - 1, Decoration7.mark({
4372
- class: "cm-task-checkbox"
4373
- }));
4374
- atomicDeco.add(node.from, node.to, checked ? checkedTask : uncheckedTask);
4458
+ atomicDeco.add(node.from, node.to + 1, checked ? checkedTask : uncheckedTask);
4375
4459
  }
4376
4460
  break;
4377
4461
  }
@@ -4461,7 +4545,7 @@ var buildDecorations2 = (view, options, focus) => {
4461
4545
  }
4462
4546
  }
4463
4547
  };
4464
- const tree = syntaxTree6(state2);
4548
+ const tree = syntaxTree7(state2);
4465
4549
  if (options.numberedHeadings?.from === void 0) {
4466
4550
  for (const { from, to } of view.visibleRanges) {
4467
4551
  tree.iterate({
@@ -4490,13 +4574,14 @@ var decorateMarkdown = (options = {}) => {
4490
4574
  ({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations2(view, options, view.hasFocus));
4491
4575
  }
4492
4576
  update(update2) {
4493
- 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) {
4494
4578
  ({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations2(update2.view, options, update2.view.hasFocus));
4495
4579
  this.clearUpdate();
4496
4580
  } else if (update2.selectionSet) {
4497
4581
  this.scheduleUpdate(update2.view);
4498
4582
  }
4499
4583
  }
4584
+ // Defer update in case moving through the document.
4500
4585
  scheduleUpdate(view) {
4501
4586
  this.clearUpdate();
4502
4587
  this.pendingUpdate = setTimeout(() => {
@@ -4516,88 +4601,24 @@ var decorateMarkdown = (options = {}) => {
4516
4601
  }
4517
4602
  }, {
4518
4603
  provide: (plugin) => [
4519
- EditorView14.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration7.none),
4520
- EditorView14.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration7.none),
4521
- 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)
4522
4607
  ]
4523
4608
  }),
4524
- formattingStyles,
4525
- linkPastePlugin,
4526
4609
  image(),
4527
- table()
4610
+ table(),
4611
+ adjustChanges(),
4612
+ formattingStyles
4528
4613
  ];
4529
4614
  };
4530
- var formattingStyles = EditorView14.baseTheme({
4531
- "& .cm-code": {
4532
- fontFamily: getToken("fontFamily.mono")
4533
- },
4534
- "& .cm-codeblock-line": {
4535
- paddingInline: "1rem !important"
4536
- },
4537
- "& .cm-codeblock-end": {
4538
- display: "inline-block",
4539
- width: "100%",
4540
- position: "relative",
4541
- "&::after": {
4542
- position: "absolute",
4543
- inset: 0,
4544
- content: '""'
4545
- }
4546
- },
4547
- "& .cm-codeblock-first": {
4548
- borderTopLeftRadius: ".25rem",
4549
- borderTopRightRadius: ".25rem"
4550
- },
4551
- "& .cm-codeblock-last": {
4552
- borderBottomLeftRadius: ".25rem",
4553
- borderBottomRightRadius: ".25rem"
4554
- },
4555
- "&light .cm-codeblock-line, &light .cm-activeLine.cm-codeblock-line": {
4556
- background: getToken("extend.semanticColors.input.light"),
4557
- mixBlendMode: "darken"
4558
- },
4559
- "&dark .cm-codeblock-line, &dark .cm-activeLine.cm-codeblock-line": {
4560
- background: getToken("extend.semanticColors.input.dark"),
4561
- mixBlendMode: "lighten"
4562
- },
4563
- "& .cm-hr": {
4564
- display: "inline-block",
4565
- width: "100%",
4566
- height: "0",
4567
- verticalAlign: "middle",
4568
- borderTop: `1px solid ${getToken("extend.colors.primary.500")}`,
4569
- opacity: 0.5
4570
- },
4571
- "& .cm-task": {
4572
- display: "inline-block",
4573
- width: `calc(${bulletListIndentationWidth}px - 0.25em)`,
4574
- color: getToken("extend.colors.blue.500")
4575
- },
4576
- "& .cm-task-checkbox": {
4577
- display: "grid",
4578
- margin: "0",
4579
- transform: "translateY(2px)"
4580
- },
4581
- "& .cm-list-item": {},
4582
- "& .cm-list-mark": {
4583
- display: "inline-block",
4584
- textAlign: "right",
4585
- fontVariant: "tabular-nums"
4586
- },
4587
- "& .cm-list-mark-bullet": {
4588
- width: `${bulletListIndentationWidth}px`
4589
- },
4590
- "& .cm-list-mark-ordered": {
4591
- width: `${orderedListIndentationWidth}px`
4592
- }
4593
- });
4594
4615
 
4595
4616
  // packages/ui/react-ui-editor/src/extensions/markdown/link.ts
4596
- import { syntaxTree as syntaxTree7 } from "@codemirror/language";
4617
+ import { syntaxTree as syntaxTree8 } from "@codemirror/language";
4597
4618
  import { hoverTooltip as hoverTooltip2 } from "@codemirror/view";
4598
4619
  import { tooltipContent } from "@dxos/react-ui-theme";
4599
4620
  var linkTooltip = (render) => hoverTooltip2((view, pos, side) => {
4600
- const syntax = syntaxTree7(view.state).resolveInner(pos, side);
4621
+ const syntax = syntaxTree8(view.state).resolveInner(pos, side);
4601
4622
  let link = null;
4602
4623
  for (let i = 0, node = syntax; !link && node && i < 5; node = node.parent, i++) {
4603
4624
  link = node.name === "Link" ? node : null;
@@ -4715,7 +4736,7 @@ var InputModeExtensions = {
4715
4736
 
4716
4737
  // packages/ui/react-ui-editor/src/extensions/state.ts
4717
4738
  import { Transaction as Transaction2 } from "@codemirror/state";
4718
- import { EditorView as EditorView15, keymap as keymap9 } from "@codemirror/view";
4739
+ import { EditorView as EditorView16, keymap as keymap9 } from "@codemirror/view";
4719
4740
  import { debounce as debounce2 } from "@dxos/async";
4720
4741
  import { invariant as invariant5 } from "@dxos/invariant";
4721
4742
  import { isNotFalsy as isNotFalsy3 } from "@dxos/util";
@@ -4753,7 +4774,7 @@ var createEditorStateTransaction = ({ scrollTo, selection }) => {
4753
4774
  return {
4754
4775
  selection,
4755
4776
  scrollIntoView: !scrollTo,
4756
- effects: scrollTo ? EditorView15.scrollIntoView(scrollTo, {
4777
+ effects: scrollTo ? EditorView16.scrollIntoView(scrollTo, {
4757
4778
  yMargin: 96
4758
4779
  }) : void 0,
4759
4780
  annotations: Transaction2.userEvent.of(stateRestoreAnnotation)
@@ -4768,7 +4789,7 @@ var state = ({ getState, setState } = {}) => {
4768
4789
  // setStateDebounced(id, {});
4769
4790
  // },
4770
4791
  // }),
4771
- EditorView15.updateListener.of(({ view, transactions }) => {
4792
+ EditorView16.updateListener.of(({ view, transactions }) => {
4772
4793
  const id = view.state.facet(documentId2);
4773
4794
  if (!id || transactions.some((tr) => tr.isUserEvent(stateRestoreAnnotation))) {
4774
4795
  return;
@@ -4893,96 +4914,32 @@ var ToolbarRoot = ({ children, onAction, classNames, state: state2 }) => {
4893
4914
  }
4894
4915
  }, children))));
4895
4916
  };
4896
- var ToolbarToggleButton = ({ Icon, children, ...props }) => {
4917
+ var ToolbarToggleButton = ({ Icon: Icon2, children, ...props }) => {
4897
4918
  return /* @__PURE__ */ React3.createElement(Tooltip.Root, null, /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
4898
4919
  asChild: true
4899
4920
  }, /* @__PURE__ */ React3.createElement(NaturalToolbar.ToggleGroupItem, {
4900
4921
  variant: "ghost",
4901
4922
  ...props,
4902
4923
  classNames: buttonStyles
4903
- }, /* @__PURE__ */ React3.createElement(Icon, {
4924
+ }, /* @__PURE__ */ React3.createElement(Icon2, {
4904
4925
  className: iconStyles
4905
4926
  }), /* @__PURE__ */ React3.createElement("span", {
4906
4927
  className: "sr-only"
4907
4928
  }, children))), /* @__PURE__ */ React3.createElement(Tooltip.Portal, null, /* @__PURE__ */ React3.createElement(Tooltip.Content, tooltipProps, children, /* @__PURE__ */ React3.createElement(Tooltip.Arrow, null))));
4908
4929
  };
4909
- var ToolbarButton = ({ Icon, children, ...props }) => {
4930
+ var ToolbarButton = ({ Icon: Icon2, children, ...props }) => {
4910
4931
  return /* @__PURE__ */ React3.createElement(Tooltip.Root, null, /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
4911
4932
  asChild: true
4912
4933
  }, /* @__PURE__ */ React3.createElement(NaturalToolbar.Button, {
4913
4934
  variant: "ghost",
4914
4935
  ...props,
4915
4936
  classNames: buttonStyles
4916
- }, /* @__PURE__ */ React3.createElement(Icon, {
4937
+ }, /* @__PURE__ */ React3.createElement(Icon2, {
4917
4938
  className: iconStyles
4918
4939
  }), /* @__PURE__ */ React3.createElement("span", {
4919
4940
  className: "sr-only"
4920
4941
  }, children))), /* @__PURE__ */ React3.createElement(Tooltip.Portal, null, /* @__PURE__ */ React3.createElement(Tooltip.Content, tooltipProps, children, /* @__PURE__ */ React3.createElement(Tooltip.Arrow, null))));
4921
4942
  };
4922
- var ViewModeIcons = {
4923
- preview: PencilSimple,
4924
- readonly: PencilSimpleSlash,
4925
- source: MarkdownLogo
4926
- };
4927
- var MarkdownView = ({ mode }) => {
4928
- const { t } = useTranslation(translationKey);
4929
- const { onAction } = useToolbarContext("ViewMode");
4930
- const ModeIcon = ViewModeIcons[mode ?? "preview"];
4931
- const suppressNextTooltip = useRef(false);
4932
- const [tooltipOpen, setTooltipOpen] = useState3(false);
4933
- const [selectOpen, setSelectOpen] = useState3(false);
4934
- return /* @__PURE__ */ React3.createElement(Tooltip.Root, {
4935
- open: tooltipOpen,
4936
- onOpenChange: (nextOpen) => {
4937
- if (nextOpen && suppressNextTooltip.current) {
4938
- suppressNextTooltip.current = false;
4939
- return setTooltipOpen(false);
4940
- } else {
4941
- return setTooltipOpen(nextOpen);
4942
- }
4943
- }
4944
- }, /* @__PURE__ */ React3.createElement(DropdownMenu.Root, {
4945
- open: selectOpen,
4946
- onOpenChange: (nextOpen) => {
4947
- if (!nextOpen) {
4948
- suppressNextTooltip.current = true;
4949
- }
4950
- return setSelectOpen(nextOpen);
4951
- }
4952
- }, /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
4953
- asChild: true
4954
- }, /* @__PURE__ */ React3.createElement(NaturalToolbar.Button, {
4955
- asChild: true
4956
- }, /* @__PURE__ */ React3.createElement(DropdownMenu.Trigger, {
4957
- asChild: true
4958
- }, /* @__PURE__ */ React3.createElement(Button, {
4959
- variant: "ghost",
4960
- classNames: buttonStyles
4961
- }, /* @__PURE__ */ React3.createElement("span", {
4962
- className: "sr-only"
4963
- }, t("mode label")), /* @__PURE__ */ React3.createElement(ModeIcon, {
4964
- className: iconStyles
4965
- }), /* @__PURE__ */ React3.createElement(CaretDown, null))))), /* @__PURE__ */ React3.createElement(DropdownMenu.Portal, null, /* @__PURE__ */ React3.createElement(DropdownMenu.Content, {
4966
- classNames: "is-min md:is-min",
4967
- onCloseAutoFocus: (e) => e.preventDefault()
4968
- }, /* @__PURE__ */ React3.createElement(DropdownMenu.Viewport, null, EditorViewModes.map((value) => {
4969
- const Icon = ViewModeIcons[value];
4970
- return /* @__PURE__ */ React3.createElement(DropdownMenu.CheckboxItem, {
4971
- key: value,
4972
- checked: value === mode,
4973
- onClick: () => onAction?.({
4974
- type: "view-mode",
4975
- data: value
4976
- })
4977
- }, /* @__PURE__ */ React3.createElement(Icon, {
4978
- className: iconStyles
4979
- }), /* @__PURE__ */ React3.createElement("span", {
4980
- className: "whitespace-nowrap grow"
4981
- }, t(`${value} mode label`)), /* @__PURE__ */ React3.createElement(Check, {
4982
- className: value === mode ? "visible" : "invisible"
4983
- }));
4984
- })), /* @__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))));
4985
- };
4986
4943
  var HeadingIcons = {
4987
4944
  "0": Paragraph,
4988
4945
  "1": TextHOne,
@@ -5038,7 +4995,7 @@ var MarkdownHeading = () => {
5038
4995
  classNames: "is-min md:is-min",
5039
4996
  onCloseAutoFocus: (e) => e.preventDefault()
5040
4997
  }, /* @__PURE__ */ React3.createElement(DropdownMenu.Viewport, null, Object.keys(HeadingIcons).map((level) => {
5041
- const Icon = HeadingIcons[level];
4998
+ const Icon2 = HeadingIcons[level];
5042
4999
  return /* @__PURE__ */ React3.createElement(DropdownMenu.CheckboxItem, {
5043
5000
  key: level,
5044
5001
  checked: value === level,
@@ -5050,7 +5007,7 @@ var MarkdownHeading = () => {
5050
5007
  className: "sr-only"
5051
5008
  }, t("heading level label", {
5052
5009
  count: parseInt(level)
5053
- })), /* @__PURE__ */ React3.createElement(Icon, {
5010
+ })), /* @__PURE__ */ React3.createElement(Icon2, {
5054
5011
  className: iconStyles
5055
5012
  }), /* @__PURE__ */ React3.createElement(DropdownMenu.ItemIndicator, null, /* @__PURE__ */ React3.createElement(Check, null)));
5056
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))));
@@ -5088,10 +5045,10 @@ var MarkdownStyles = () => {
5088
5045
  return /* @__PURE__ */ React3.createElement(NaturalToolbar.ToggleGroup, {
5089
5046
  type: "multiple",
5090
5047
  value: markdownStyles.filter(({ getState }) => state2 && getState(state2)).map(({ type }) => type)
5091
- }, markdownStyles.map(({ type, getState, Icon }) => /* @__PURE__ */ React3.createElement(ToolbarToggleButton, {
5048
+ }, markdownStyles.map(({ type, getState, Icon: Icon2 }) => /* @__PURE__ */ React3.createElement(ToolbarToggleButton, {
5092
5049
  key: type,
5093
5050
  value: type,
5094
- Icon,
5051
+ Icon: Icon2,
5095
5052
  disabled: state2?.blockType === "codeblock",
5096
5053
  onClick: state2 ? () => onAction?.({
5097
5054
  type,
@@ -5122,10 +5079,10 @@ var MarkdownLists = () => {
5122
5079
  return /* @__PURE__ */ React3.createElement(NaturalToolbar.ToggleGroup, {
5123
5080
  type: "single",
5124
5081
  value: state2?.listStyle ? `list-${state2.listStyle}` : ""
5125
- }, markdownLists.map(({ type, getState, Icon }) => /* @__PURE__ */ React3.createElement(ToolbarToggleButton, {
5082
+ }, markdownLists.map(({ type, getState, Icon: Icon2 }) => /* @__PURE__ */ React3.createElement(ToolbarToggleButton, {
5126
5083
  key: type,
5127
5084
  value: type,
5128
- Icon,
5085
+ Icon: Icon2,
5129
5086
  onClick: state2 ? () => onAction?.({
5130
5087
  type,
5131
5088
  data: !getState(state2)
@@ -5157,10 +5114,10 @@ var MarkdownBlocks = () => {
5157
5114
  return /* @__PURE__ */ React3.createElement(NaturalToolbar.ToggleGroup, {
5158
5115
  type: "single",
5159
5116
  value: value?.type ?? ""
5160
- }, markdownBlocks.map(({ type, disabled, getState, Icon }) => /* @__PURE__ */ React3.createElement(ToolbarToggleButton, {
5117
+ }, markdownBlocks.map(({ type, disabled, getState, Icon: Icon2 }) => /* @__PURE__ */ React3.createElement(ToolbarToggleButton, {
5161
5118
  key: type,
5162
5119
  value: type,
5163
- Icon,
5120
+ Icon: Icon2,
5164
5121
  disabled: !state2 || disabled?.(state2),
5165
5122
  onClick: state2 ? () => onAction?.({
5166
5123
  type,
@@ -5212,16 +5169,86 @@ var MarkdownCustom = ({ onUpload } = {}) => {
5212
5169
  onClick: () => open()
5213
5170
  }, t("image label")));
5214
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
+ };
5215
5236
  var MarkdownActions = () => {
5216
5237
  const { onAction, state: state2 } = useToolbarContext("MarkdownActions");
5217
5238
  const { t } = useTranslation(translationKey);
5218
- let toolTipKey = "comment label";
5239
+ let commentToolTipKey = "comment label";
5219
5240
  if (state2?.comment) {
5220
- toolTipKey = "selection overlaps existing comment label";
5241
+ commentToolTipKey = "selection overlaps existing comment label";
5221
5242
  } else if (state2?.selection === false) {
5222
- toolTipKey = "select text to comment label";
5243
+ commentToolTipKey = "select text to comment label";
5223
5244
  }
5224
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, {
5225
5252
  value: "comment",
5226
5253
  Icon: ChatText,
5227
5254
  "data-testid": "editor.toolbar.comment",
@@ -5229,7 +5256,7 @@ var MarkdownActions = () => {
5229
5256
  type: "comment"
5230
5257
  }),
5231
5258
  disabled: !state2 || state2.comment || !state2.selection
5232
- }, t(toolTipKey)));
5259
+ }, t(commentToolTipKey)));
5233
5260
  };
5234
5261
  var Toolbar = {
5235
5262
  Root: ToolbarRoot,
@@ -5242,23 +5269,21 @@ var Toolbar = {
5242
5269
  };
5243
5270
 
5244
5271
  // packages/ui/react-ui-editor/src/defaults.ts
5245
- import { EditorView as EditorView16 } from "@codemirror/view";
5246
- 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]");
5247
5277
  var editorWithToolbarLayout = "grid grid-cols-1 grid-rows-[min-content_1fr] data-[toolbar=disabled]:grid-rows-[1fr] justify-center content-start overflow-hidden";
5248
- var editorGutter = EditorView16.baseTheme({
5278
+ var editorGutter = EditorView17.theme({
5279
+ // Match margin from content.
5249
5280
  ".cm-gutters": {
5250
- // Match margin from content.
5251
- marginTop: "16px",
5252
- marginBottom: "16px",
5253
- // Inside within content margin.
5254
- marginRight: "-32px",
5255
- width: "32px",
5256
- backgroundColor: "transparent !important"
5281
+ marginTop: "16px"
5257
5282
  }
5258
5283
  });
5259
- var editorMonospace = EditorView16.baseTheme({
5284
+ var editorMonospace = EditorView17.theme({
5260
5285
  ".cm-content": {
5261
- fontFamily: `${getToken("fontFamily.mono")} !important`
5286
+ fontFamily: fontMono
5262
5287
  }
5263
5288
  });
5264
5289
 
@@ -5269,7 +5294,7 @@ var useActionHandler = (view) => {
5269
5294
 
5270
5295
  // packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
5271
5296
  import { EditorState as EditorState2 } from "@codemirror/state";
5272
- import { EditorView as EditorView17 } from "@codemirror/view";
5297
+ import { EditorView as EditorView18 } from "@codemirror/view";
5273
5298
  import { useFocusableGroup } from "@fluentui/react-tabster";
5274
5299
  import { useCallback, useEffect as useEffect3, useMemo as useMemo3, useRef as useRef2, useState as useState4 } from "react";
5275
5300
  import { log as log8 } from "@dxos/log";
@@ -5315,7 +5340,7 @@ var useTextEditor = (props = {}, deps = []) => {
5315
5340
  extensions: [
5316
5341
  id && documentId2.of(id),
5317
5342
  // NOTE: Doesn't catch errors in keymap functions.
5318
- EditorView17.exceptionSink.of((err) => {
5343
+ EditorView18.exceptionSink.of((err) => {
5319
5344
  log8.catch(err, void 0, {
5320
5345
  F: __dxlog_file13,
5321
5346
  L: 100,
@@ -5324,14 +5349,14 @@ var useTextEditor = (props = {}, deps = []) => {
5324
5349
  });
5325
5350
  }),
5326
5351
  extensions,
5327
- EditorView17.updateListener.of(() => {
5352
+ EditorView18.updateListener.of(() => {
5328
5353
  setTimeout(() => {
5329
5354
  onUpdate.current?.();
5330
5355
  });
5331
5356
  })
5332
5357
  ].filter(isNotFalsy4)
5333
5358
  });
5334
- view2 = new EditorView17({
5359
+ view2 = new EditorView18({
5335
5360
  parent: parentRef.current,
5336
5361
  selection: initialSelection,
5337
5362
  state: state2,
@@ -5445,6 +5470,7 @@ export {
5445
5470
  command,
5446
5471
  comments,
5447
5472
  commentsState,
5473
+ convertTreeToJson,
5448
5474
  createBasicExtensions,
5449
5475
  createComment,
5450
5476
  createDataExtensions,
@@ -5453,11 +5479,13 @@ export {
5453
5479
  createMarkdownExtensions,
5454
5480
  createThemeExtensions,
5455
5481
  debugNodeLogger,
5482
+ debugTree,
5456
5483
  decorateMarkdown,
5457
5484
  defaultOptions,
5458
5485
  documentId2 as documentId,
5459
5486
  dropFile,
5460
5487
  editorContent,
5488
+ editorFullWidth,
5461
5489
  editorGutter,
5462
5490
  editorInputMode,
5463
5491
  editorMonospace,
@@ -5467,7 +5495,6 @@ export {
5467
5495
  formattingEquals,
5468
5496
  formattingKeymap,
5469
5497
  getFormatting,
5470
- getToken,
5471
5498
  image,
5472
5499
  imageUpload,
5473
5500
  insertTable,