@dxos/react-ui-editor 0.4.8-main.4a229ac → 0.4.8-main.4ad174a

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 (44) hide show
  1. package/dist/lib/browser/index.mjs +1447 -1443
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
  5. package/dist/types/src/components/Toolbar/Toolbar.d.ts +1 -6
  6. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
  7. package/dist/types/src/extensions/dnd.d.ts +7 -1
  8. package/dist/types/src/extensions/dnd.d.ts.map +1 -1
  9. package/dist/types/src/extensions/factories.d.ts +5 -0
  10. package/dist/types/src/extensions/factories.d.ts.map +1 -1
  11. package/dist/types/src/extensions/index.d.ts +0 -1
  12. package/dist/types/src/extensions/index.d.ts.map +1 -1
  13. package/dist/types/src/extensions/markdown/action.d.ts +9 -0
  14. package/dist/types/src/extensions/markdown/action.d.ts.map +1 -0
  15. package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
  16. package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -1
  17. package/dist/types/src/extensions/markdown/index.d.ts +1 -0
  18. package/dist/types/src/extensions/markdown/index.d.ts.map +1 -1
  19. package/dist/types/src/extensions/modes.d.ts +1 -1
  20. package/dist/types/src/extensions/modes.d.ts.map +1 -1
  21. package/dist/types/src/hooks/useActionHandler.d.ts +2 -2
  22. package/dist/types/src/hooks/useActionHandler.d.ts.map +1 -1
  23. package/dist/types/src/hooks/useDocAccessor.d.ts +4 -2
  24. package/dist/types/src/hooks/useDocAccessor.d.ts.map +1 -1
  25. package/dist/types/src/themes/default.d.ts.map +1 -1
  26. package/package.json +25 -24
  27. package/src/components/TextEditor/TextEditor.stories.tsx +14 -2
  28. package/src/components/Toolbar/Toolbar.tsx +2 -26
  29. package/src/extensions/automerge/automerge.ts +4 -4
  30. package/src/extensions/command/state.ts +2 -2
  31. package/src/extensions/dnd.ts +31 -9
  32. package/src/extensions/factories.ts +36 -7
  33. package/src/extensions/index.ts +0 -1
  34. package/src/extensions/markdown/action.ts +112 -0
  35. package/src/extensions/markdown/bundle.ts +8 -11
  36. package/src/extensions/markdown/formatting.ts +11 -11
  37. package/src/extensions/markdown/index.ts +1 -0
  38. package/src/extensions/modes.ts +8 -1
  39. package/src/hooks/useActionHandler.ts +4 -89
  40. package/src/hooks/useDocAccessor.ts +8 -2
  41. package/src/themes/default.ts +24 -8
  42. package/dist/types/src/extensions/cursor-line-margin.d.ts +0 -7
  43. package/dist/types/src/extensions/cursor-line-margin.d.ts.map +0 -1
  44. package/src/extensions/cursor-line-margin.ts +0 -94
@@ -24,17 +24,17 @@ var translations_default = [
24
24
  ];
25
25
 
26
26
  // packages/ui/react-ui-editor/src/index.ts
27
- import { keymap as keymap10 } from "@codemirror/view";
27
+ import { keymap as keymap11 } from "@codemirror/view";
28
28
  import { tags as tags2 } from "@lezer/highlight";
29
29
  import { TextKind } from "@dxos/protocols/proto/dxos/echo/model/text";
30
30
  import { Doc, YText, YXmlFragment } from "@dxos/text-model";
31
31
 
32
32
  // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
33
33
  import { EditorState as EditorState2 } from "@codemirror/state";
34
- import { EditorView as EditorView17 } from "@codemirror/view";
34
+ import { EditorView as EditorView16 } from "@codemirror/view";
35
35
  import { useFocusableGroup } from "@fluentui/react-tabster";
36
- import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useRef, useState } from "react";
37
- import { log as log9 } from "@dxos/log";
36
+ import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useRef, useState as useState2 } from "react";
37
+ import { log as log7 } from "@dxos/log";
38
38
  import { isNotFalsy as isNotFalsy4 } from "@dxos/util";
39
39
 
40
40
  // packages/ui/react-ui-editor/src/extensions/annotations.ts
@@ -122,8 +122,8 @@ var annotations = (options = {}) => {
122
122
  annotationsState
123
123
  ], (state2) => {
124
124
  const annotations2 = state2.field(annotationsState);
125
- const decorations = annotations2.map((annotation2) => {
126
- const range = Cursor.getRangeFromCursor(state2, annotation2.cursor);
125
+ const decorations = annotations2.map((annotation) => {
126
+ const range = Cursor.getRangeFromCursor(state2, annotation.cursor);
127
127
  return range && annotationMark.range(range.from, range.to);
128
128
  }).filter(isNotFalsy);
129
129
  return Decoration.set(decorations);
@@ -475,13 +475,13 @@ var automerge = (accessor) => {
475
475
  ViewPlugin.fromClass(class {
476
476
  constructor(_view) {
477
477
  this._view = _view;
478
- accessor.handle.addListener("change", this._handleChange.bind(this));
478
+ this._handleChange = () => {
479
+ syncer.reconcile(this._view, false);
480
+ };
481
+ accessor.handle.addListener("change", this._handleChange);
479
482
  }
480
483
  destroy() {
481
- accessor.handle.removeListener("change", this._handleChange.bind(this));
482
- }
483
- _handleChange() {
484
- syncer.reconcile(this._view, false);
484
+ accessor.handle.removeListener("change", this._handleChange);
485
485
  }
486
486
  }),
487
487
  // Reconcile local updates.
@@ -1196,7 +1196,7 @@ var commandState = StateField3.define({
1196
1196
  }
1197
1197
  });
1198
1198
  }
1199
- setTimeout(() => view2.focus());
1199
+ requestAnimationFrame(() => view2.focus());
1200
1200
  });
1201
1201
  }
1202
1202
  };
@@ -1851,76 +1851,14 @@ var useComments = (view, id, comments2) => {
1851
1851
  ]);
1852
1852
  };
1853
1853
 
1854
- // packages/ui/react-ui-editor/src/extensions/cursor-line-margin.ts
1855
- import { Transaction } from "@codemirror/state";
1856
- import { EditorView as EditorView8 } from "@codemirror/view";
1857
- import { log as log5 } from "@dxos/log";
1858
- var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/cursor-line-margin.ts";
1859
- var annotation = "cursorLineMargin";
1860
- var lineAtPos = (s, pos) => s.doc.lineAt(pos).number;
1861
- var cursorLineMargin = (options = {
1862
- lines: 3
1863
- }) => {
1864
- const { lines } = options;
1865
- if (!lines || lines <= 0) {
1866
- return [];
1867
- }
1868
- return EditorView8.updateListener.of(({ transactions, state: state2, selectionSet, startState, view }) => {
1869
- if (transactions.length < 1 || transactions.some((tr) => tr.isUserEvent(annotation))) {
1870
- return;
1871
- }
1872
- const s = state2;
1873
- const { main } = s.selection;
1874
- const rect = view.dom.getBoundingClientRect();
1875
- const viewportTop = rect.top - view.documentTop;
1876
- const viewportBottom = rect.bottom - view.documentTop;
1877
- const mainLine = lineAtPos(s, main.head);
1878
- const _visTopLine = lineAtPos(s, view.lineBlockAtHeight(viewportTop).from);
1879
- const botLineBlk = view.lineBlockAtHeight(viewportBottom);
1880
- const visBotLineDoc = lineAtPos(s, Math.min(botLineBlk.to, s.doc.length));
1881
- const visBotLine = botLineBlk.bottom >= viewportBottom ? visBotLineDoc : visBotLineDoc + Math.floor((viewportBottom - botLineBlk.bottom) / view.defaultLineHeight);
1882
- const needsScrollTop = false;
1883
- const needsScrollBot = mainLine >= visBotLine - lines;
1884
- if (needsScrollTop && needsScrollBot) {
1885
- log5.warn("is cursorScrollMargin too large for the editor size?", void 0, {
1886
- F: __dxlog_file6,
1887
- L: 65,
1888
- S: void 0,
1889
- C: (f, a) => f(...a)
1890
- });
1891
- return;
1892
- }
1893
- if (!needsScrollTop && !needsScrollBot) {
1894
- return;
1895
- }
1896
- if (selectionSet) {
1897
- const { head } = startState.selection.main;
1898
- const oldMainLine = lineAtPos(startState, head);
1899
- if (needsScrollTop && oldMainLine < mainLine) {
1900
- return;
1901
- }
1902
- if (needsScrollBot && oldMainLine > mainLine) {
1903
- return;
1904
- }
1905
- }
1906
- view.dispatch({
1907
- annotations: Transaction.userEvent.of(annotation),
1908
- effects: EditorView8.scrollIntoView(s.selection.main.head, {
1909
- y: needsScrollTop ? "start" : "end",
1910
- yMargin: view.defaultLineHeight * lines
1911
- })
1912
- });
1913
- });
1914
- };
1915
-
1916
1854
  // packages/ui/react-ui-editor/src/extensions/doc.ts
1917
1855
  import { Facet as Facet5 } from "@codemirror/state";
1918
1856
  import { invariant as invariant3 } from "@dxos/invariant";
1919
- var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/doc.ts";
1857
+ var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/doc.ts";
1920
1858
  var documentId2 = Facet5.define({
1921
1859
  combine: (providers) => {
1922
1860
  invariant3(providers.length <= 1, void 0, {
1923
- F: __dxlog_file7,
1861
+ F: __dxlog_file6,
1924
1862
  L: 11,
1925
1863
  S: void 0,
1926
1864
  A: [
@@ -1933,33 +1871,51 @@ var documentId2 = Facet5.define({
1933
1871
  });
1934
1872
 
1935
1873
  // packages/ui/react-ui-editor/src/extensions/dnd.ts
1936
- import { EditorView as EditorView9 } from "@codemirror/view";
1937
- import { log as log6 } from "@dxos/log";
1938
- var __dxlog_file8 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/dnd.ts";
1939
- var dnd = () => {
1940
- return EditorView9.domEventHandlers({
1941
- drop: (event, view) => {
1942
- log6.info("domEventHandlersDrop", {
1943
- event
1944
- }, {
1945
- F: __dxlog_file8,
1946
- L: 14,
1947
- S: void 0,
1948
- C: (f, a) => f(...a)
1949
- });
1950
- }
1951
- });
1874
+ import { dropCursor, EditorView as EditorView8 } from "@codemirror/view";
1875
+ var styles4 = EditorView8.baseTheme({
1876
+ ".cm-dropCursor": {
1877
+ borderLeft: `2px solid ${getToken("extend.colors.primary.500")}`,
1878
+ color: getToken("extend.colors.primary.500"),
1879
+ padding: "0 4px"
1880
+ },
1881
+ ".cm-dropCursor:after": {
1882
+ content: '"\u2190"'
1883
+ }
1884
+ });
1885
+ var dropFile = (options = {}) => {
1886
+ return [
1887
+ styles4,
1888
+ dropCursor(),
1889
+ EditorView8.domEventHandlers({
1890
+ drop: (event, view) => {
1891
+ event.preventDefault();
1892
+ const files = event.dataTransfer?.files;
1893
+ const pos = view.posAtCoords(event);
1894
+ if (files?.length && pos !== null) {
1895
+ view.dispatch({
1896
+ selection: {
1897
+ anchor: pos
1898
+ }
1899
+ });
1900
+ options.onDrop?.(view, {
1901
+ files
1902
+ });
1903
+ }
1904
+ }
1905
+ })
1906
+ ];
1952
1907
  };
1953
1908
 
1954
1909
  // packages/ui/react-ui-editor/src/extensions/factories.ts
1955
- import { closeBrackets } from "@codemirror/autocomplete";
1956
- import { history } from "@codemirror/commands";
1910
+ import { closeBrackets, closeBracketsKeymap } from "@codemirror/autocomplete";
1911
+ import { defaultKeymap, history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
1957
1912
  import { bracketMatching } from "@codemirror/language";
1913
+ import { searchKeymap } from "@codemirror/search";
1958
1914
  import { EditorState } from "@codemirror/state";
1959
- import { EditorView as EditorView10, crosshairCursor, drawSelection, dropCursor, highlightActiveLine, lineNumbers, placeholder, scrollPastEnd } from "@codemirror/view";
1915
+ import { EditorView as EditorView9, crosshairCursor, drawSelection, dropCursor as dropCursor2, highlightActiveLine, keymap as keymap5, lineNumbers, placeholder, scrollPastEnd } from "@codemirror/view";
1960
1916
  import defaultsDeep2 from "lodash.defaultsdeep";
1961
1917
  import { generateName } from "@dxos/display-name";
1962
- import { log as log7 } from "@dxos/log";
1918
+ import { log as log5 } from "@dxos/log";
1963
1919
  import { hueTokens } from "@dxos/react-ui-theme";
1964
1920
  import { hexToHue, isNotFalsy as isNotFalsy2 } from "@dxos/util";
1965
1921
 
@@ -2164,50 +2120,75 @@ var defaultTheme = {
2164
2120
  * </div>
2165
2121
  * </div
2166
2122
  */
2167
- ".cm-panels": {
2168
- border: `1px solid ${get3(tokens, "extend.colors.neutral.200")}`
2169
- },
2123
+ ".cm-panels": {},
2170
2124
  ".cm-panel": {
2171
- background: get3(tokens, "extend.colors.neutral.50"),
2172
2125
  fontFamily: get3(tokens, "fontFamily.body", []).join(",")
2173
2126
  },
2127
+ ".cm-panel input[type=checkbox]": {
2128
+ marginRight: "0.4rem !important"
2129
+ },
2130
+ "&light .cm-panel": {
2131
+ background: get3(tokens, "extend.colors.neutral.50")
2132
+ },
2133
+ "&dark .cm-panel": {
2134
+ background: get3(tokens, "extend.colors.neutral.850")
2135
+ },
2174
2136
  ".cm-button": {
2175
2137
  margin: "4px",
2176
2138
  fontFamily: get3(tokens, "fontFamily.body", []).join(","),
2177
- background: get3(tokens, "extend.colors.neutral.100"),
2178
2139
  backgroundImage: "none",
2179
2140
  border: "none",
2141
+ "&:active": {
2142
+ backgroundImage: "none"
2143
+ }
2144
+ },
2145
+ "&light .cm-button": {
2146
+ background: get3(tokens, "extend.colors.neutral.100"),
2180
2147
  "&:hover": {
2181
2148
  background: get3(tokens, "extend.colors.neutral.200")
2182
2149
  },
2183
2150
  "&:active": {
2184
- background: get3(tokens, "extend.colors.neutral.300"),
2185
- backgroundImage: "none"
2151
+ background: get3(tokens, "extend.colors.neutral.300")
2186
2152
  }
2187
2153
  },
2188
- ".cm-panel input[type=checkbox]": {
2189
- marginRight: "0.4rem !important"
2154
+ "&dark .cm-button": {
2155
+ background: get3(tokens, "extend.colors.neutral.800"),
2156
+ "&:hover": {
2157
+ background: get3(tokens, "extend.colors.neutral.700")
2158
+ },
2159
+ "&:active": {
2160
+ background: get3(tokens, "extend.colors.neutral.600")
2161
+ }
2190
2162
  }
2191
2163
  };
2192
2164
 
2193
2165
  // packages/ui/react-ui-editor/src/extensions/factories.ts
2194
- var __dxlog_file9 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/factories.ts";
2166
+ var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/factories.ts";
2195
2167
  var defaults = {
2168
+ allowMultipleSelections: true,
2196
2169
  bracketMatching: true,
2197
2170
  closeBrackets: true,
2198
2171
  drawSelection: true,
2199
2172
  editable: true,
2200
2173
  history: true,
2201
- lineWrapping: true
2174
+ lineWrapping: true,
2175
+ search: true,
2176
+ keymap: "standard"
2177
+ };
2178
+ var keymaps = {
2179
+ // https://codemirror.net/docs/ref/#commands.standardKeymap
2180
+ standard: standardKeymap,
2181
+ // https://codemirror.net/docs/ref/#commands.defaultKeymap
2182
+ default: defaultKeymap
2202
2183
  };
2203
2184
  var createBasicExtensions = (_props) => {
2204
2185
  const props = defaultsDeep2({}, _props, defaults);
2205
2186
  return [
2206
2187
  // TODO(burdon): Doesn't catch errors in keymap functions.
2207
- EditorView10.exceptionSink.of((err) => {
2208
- log7.catch(err, void 0, {
2209
- F: __dxlog_file9,
2210
- L: 78,
2188
+ EditorView9.exceptionSink.of((err) => {
2189
+ log5.catch(err, void 0, {
2190
+ F: __dxlog_file7,
2191
+ L: 93,
2211
2192
  S: void 0,
2212
2193
  C: (f, a) => f(...a)
2213
2194
  });
@@ -2216,19 +2197,33 @@ var createBasicExtensions = (_props) => {
2216
2197
  props.bracketMatching && bracketMatching(),
2217
2198
  props.closeBrackets && closeBrackets(),
2218
2199
  props.crosshairCursor && crosshairCursor(),
2219
- props.dropCursor && dropCursor(),
2200
+ props.dropCursor && dropCursor2(),
2220
2201
  props.drawSelection && drawSelection(),
2221
2202
  props.highlightActiveLine && highlightActiveLine(),
2222
2203
  props.history && history(),
2223
2204
  props.lineNumbers && lineNumbers(),
2224
- props.lineWrapping && EditorView10.lineWrapping,
2205
+ props.lineWrapping && EditorView9.lineWrapping,
2225
2206
  props.placeholder && placeholder(props.placeholder),
2226
2207
  props.readonly && [
2227
2208
  EditorState.readOnly.of(true),
2228
- EditorView10.editable.of(false)
2209
+ EditorView9.editable.of(false)
2229
2210
  ],
2230
2211
  props.scrollPastEnd && scrollPastEnd(),
2231
- props.tabSize && EditorState.tabSize.of(props.tabSize)
2212
+ props.tabSize && EditorState.tabSize.of(props.tabSize),
2213
+ // https://codemirror.net/docs/ref/#view.KeyBinding
2214
+ keymap5.of([
2215
+ ...(props.keymap && keymaps[props.keymap]) ?? [],
2216
+ // https://codemirror.net/docs/ref/#commands.indentWithTab
2217
+ ...props.indentWithTab ? [
2218
+ indentWithTab
2219
+ ] : [],
2220
+ // https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
2221
+ ...props.closeBrackets ? closeBracketsKeymap : [],
2222
+ // https://codemirror.net/docs/ref/#commands.historyKeymap
2223
+ ...props.history ? historyKeymap : [],
2224
+ // https://codemirror.net/docs/ref/#search.searchKeymap
2225
+ ...props.search ? searchKeymap : []
2226
+ ].filter(isNotFalsy2))
2232
2227
  ].filter(isNotFalsy2);
2233
2228
  };
2234
2229
  var defaultSlots = {
@@ -2239,13 +2234,13 @@ var defaultSlots = {
2239
2234
  var createThemeExtensions = ({ theme, themeMode, slots: _slots } = {}) => {
2240
2235
  const slots = defaultsDeep2({}, _slots, defaultSlots);
2241
2236
  return [
2242
- EditorView10.baseTheme(defaultTheme),
2243
- EditorView10.darkTheme.of(themeMode === "dark"),
2244
- theme && EditorView10.theme(theme),
2245
- slots.editor?.className && EditorView10.editorAttributes.of({
2237
+ EditorView9.baseTheme(defaultTheme),
2238
+ EditorView9.darkTheme.of(themeMode === "dark"),
2239
+ theme && EditorView9.theme(theme),
2240
+ slots.editor?.className && EditorView9.editorAttributes.of({
2246
2241
  class: slots.editor.className
2247
2242
  }),
2248
- slots.content?.className && EditorView10.contentAttributes.of({
2243
+ slots.content?.className && EditorView9.contentAttributes.of({
2249
2244
  class: slots.content.className
2250
2245
  })
2251
2246
  ].filter(isNotFalsy2);
@@ -2273,615 +2268,108 @@ var createDataExtensions = ({ id, text, space, identity }) => {
2273
2268
  };
2274
2269
 
2275
2270
  // packages/ui/react-ui-editor/src/extensions/listener.ts
2276
- import { EditorView as EditorView11 } from "@codemirror/view";
2271
+ import { EditorView as EditorView10 } from "@codemirror/view";
2277
2272
  var listener = ({ onFocus, onChange }) => {
2278
2273
  const extensions = [];
2279
- onFocus && extensions.push(EditorView11.focusChangeEffect.of((_, focusing) => {
2274
+ onFocus && extensions.push(EditorView10.focusChangeEffect.of((_, focusing) => {
2280
2275
  onFocus(focusing);
2281
2276
  return null;
2282
2277
  }));
2283
- onChange && extensions.push(EditorView11.updateListener.of((update2) => {
2278
+ onChange && extensions.push(EditorView10.updateListener.of((update2) => {
2284
2279
  onChange(update2.state.doc.toString());
2285
2280
  }));
2286
2281
  return extensions;
2287
2282
  };
2288
2283
 
2289
- // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
2290
- import { closeBracketsKeymap } from "@codemirror/autocomplete";
2291
- import { historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
2292
- import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
2293
- import { defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
2294
- import { languages } from "@codemirror/language-data";
2295
- import { searchKeymap } from "@codemirror/search";
2296
- import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
2297
- import { keymap as keymap5 } from "@codemirror/view";
2298
-
2299
- // packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
2300
- import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
2301
- import { HighlightStyle } from "@codemirror/language";
2302
- import { tags, styleTags, Tag } from "@lezer/highlight";
2303
- import { Table } from "@lezer/markdown";
2304
- var markdownTags = {
2305
- Blockquote: Tag.define(),
2306
- CodeMark: Tag.define(),
2307
- CodeText: Tag.define(),
2308
- EmphasisMark: Tag.define(),
2309
- HeaderMark: Tag.define(),
2310
- InlineCode: Tag.define(),
2311
- LinkLabel: Tag.define(),
2312
- LinkReference: Tag.define(),
2313
- ListMark: Tag.define(),
2314
- QuoteMark: Tag.define(),
2315
- URL: Tag.define(),
2316
- // Custom.
2317
- TableCell: Tag.define()
2318
- };
2319
- Table.defineNodes?.forEach((node) => {
2320
- switch (node?.name) {
2321
- case "TableCell": {
2322
- node.style = markdownTags.TableCell;
2323
- break;
2284
+ // packages/ui/react-ui-editor/src/extensions/markdown/formatting.ts
2285
+ import { snippet } from "@codemirror/autocomplete";
2286
+ import { syntaxTree } from "@codemirror/language";
2287
+ import { EditorSelection } from "@codemirror/state";
2288
+ import { EditorView as EditorView11, keymap as keymap6 } from "@codemirror/view";
2289
+ import { useMemo, useState } from "react";
2290
+ var formattingEquals = (a, b) => a.blockType === b.blockType && a.strong === b.strong && a.emphasis === b.emphasis && a.strikethrough === b.strikethrough && a.code === b.code && a.link === b.link && a.listStyle === b.listStyle && a.blockQuote === b.blockQuote;
2291
+ var Inline;
2292
+ (function(Inline2) {
2293
+ Inline2[Inline2["Strong"] = 0] = "Strong";
2294
+ Inline2[Inline2["Emphasis"] = 1] = "Emphasis";
2295
+ Inline2[Inline2["Strikethrough"] = 2] = "Strikethrough";
2296
+ Inline2[Inline2["Code"] = 3] = "Code";
2297
+ })(Inline || (Inline = {}));
2298
+ var List;
2299
+ (function(List2) {
2300
+ List2[List2["Ordered"] = 0] = "Ordered";
2301
+ List2[List2["Bullet"] = 1] = "Bullet";
2302
+ List2[List2["Task"] = 2] = "Task";
2303
+ })(List || (List = {}));
2304
+ var setHeading = (level) => ({ state: state2, dispatch }) => {
2305
+ const { selection: { ranges }, doc } = state2;
2306
+ const changes = [];
2307
+ let prevBlock = -1;
2308
+ for (const range of ranges) {
2309
+ let sawBlock = false;
2310
+ syntaxTree(state2).iterate({
2311
+ from: range.from,
2312
+ to: range.to,
2313
+ enter: (node) => {
2314
+ if (!Object.hasOwn(Textblocks, node.name) || prevBlock === node.from) {
2315
+ return;
2316
+ }
2317
+ sawBlock = true;
2318
+ prevBlock = node.from;
2319
+ const blockType = Textblocks[node.name];
2320
+ const isHeading = /heading(\d)/.exec(blockType);
2321
+ const curLevel = isHeading ? +isHeading[1] : node.name === "Paragraph" ? 0 : -1;
2322
+ if (curLevel < 0 || curLevel === level) {
2323
+ return;
2324
+ }
2325
+ if (curLevel === 0) {
2326
+ changes.push({
2327
+ from: node.from,
2328
+ insert: "#".repeat(level) + " "
2329
+ });
2330
+ } else if (node.name === "SetextHeading1" || node.name === "SetextHeading2") {
2331
+ const nextLine = doc.lineAt(node.to);
2332
+ if (level) {
2333
+ changes.push({
2334
+ from: node.from,
2335
+ insert: "#".repeat(level) + " "
2336
+ });
2337
+ }
2338
+ changes.push({
2339
+ from: nextLine.from - 1,
2340
+ to: nextLine.to
2341
+ });
2342
+ } else {
2343
+ if (level === 0) {
2344
+ changes.push({
2345
+ from: node.from,
2346
+ to: Math.min(node.to, node.from + curLevel + 1)
2347
+ });
2348
+ } else if (level < curLevel) {
2349
+ changes.push({
2350
+ from: node.from,
2351
+ to: node.from + (curLevel - level)
2352
+ });
2353
+ } else {
2354
+ changes.push({
2355
+ from: node.from,
2356
+ insert: "#".repeat(level - curLevel)
2357
+ });
2358
+ }
2359
+ }
2360
+ }
2361
+ });
2362
+ let line;
2363
+ if (!sawBlock && range.empty && level > 0 && !/\S/.test((line = state2.doc.lineAt(range.from)).text)) {
2364
+ changes.push({
2365
+ from: line.from,
2366
+ to: line.to,
2367
+ insert: "#".repeat(level) + " "
2368
+ });
2324
2369
  }
2325
2370
  }
2326
- });
2327
- var markdownTagsExtensions = [
2328
- Table,
2329
- {
2330
- props: [
2331
- styleTags(markdownTags)
2332
- ]
2333
- }
2334
- ];
2335
- var markdownHighlightStyle = (readonly) => {
2336
- return HighlightStyle.define([
2337
- {
2338
- tag: [
2339
- tags.keyword,
2340
- tags.name,
2341
- tags.deleted,
2342
- tags.character,
2343
- tags.propertyName,
2344
- tags.macroName,
2345
- tags.color,
2346
- tags.constant(tags.name),
2347
- tags.standard(tags.name),
2348
- tags.definition(tags.name),
2349
- tags.separator,
2350
- tags.typeName,
2351
- tags.className,
2352
- tags.number,
2353
- tags.changed,
2354
- tags.annotation,
2355
- tags.modifier,
2356
- tags.self,
2357
- tags.namespace,
2358
- tags.operator,
2359
- tags.operatorKeyword,
2360
- tags.escape,
2361
- tags.regexp,
2362
- tags.special(tags.string),
2363
- tags.meta,
2364
- tags.comment,
2365
- tags.atom,
2366
- tags.bool,
2367
- tags.special(tags.variableName),
2368
- tags.processingInstruction,
2369
- tags.string,
2370
- tags.inserted,
2371
- tags.invalid
2372
- ],
2373
- color: "inherit !important"
2374
- },
2375
- // Markdown marks.
2376
- {
2377
- tag: [
2378
- tags.meta,
2379
- tags.processingInstruction,
2380
- markdownTags.LinkLabel,
2381
- markdownTags.LinkReference,
2382
- markdownTags.ListMark
2383
- ],
2384
- class: mark
2385
- },
2386
- // Markdown marks.
2387
- {
2388
- tag: [
2389
- markdownTags.CodeMark,
2390
- markdownTags.HeaderMark,
2391
- markdownTags.QuoteMark,
2392
- markdownTags.EmphasisMark
2393
- ],
2394
- class: mark
2395
- },
2396
- // E.g., code block language (after ```).
2397
- {
2398
- tag: [
2399
- tags.function(tags.variableName),
2400
- tags.labelName
2401
- ],
2402
- class: codeMark
2403
- },
2404
- {
2405
- tag: [
2406
- tags.monospace
2407
- ],
2408
- class: "font-mono"
2409
- },
2410
- // Headings.
2411
- {
2412
- tag: tags.heading1,
2413
- class: heading(1)
2414
- },
2415
- {
2416
- tag: tags.heading2,
2417
- class: heading(2)
2418
- },
2419
- {
2420
- tag: tags.heading3,
2421
- class: heading(3)
2422
- },
2423
- {
2424
- tag: tags.heading4,
2425
- class: heading(4)
2426
- },
2427
- {
2428
- tag: tags.heading5,
2429
- class: heading(5)
2430
- },
2431
- {
2432
- tag: tags.heading6,
2433
- class: heading(6)
2434
- },
2435
- // Emphasis.
2436
- {
2437
- tag: tags.emphasis,
2438
- class: italic
2439
- },
2440
- {
2441
- tag: tags.strong,
2442
- class: bold
2443
- },
2444
- {
2445
- tag: tags.strikethrough,
2446
- class: strikethrough
2447
- },
2448
- // Naked URLs.
2449
- {
2450
- tag: [
2451
- markdownTags.URL
2452
- ],
2453
- class: inlineUrl
2454
- },
2455
- // NOTE: The `markdown` extension configures extensions for `lezer` to parse markdown tokens (incl. below).
2456
- // However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
2457
- // when a language is specified. In this case, the syntax highlighting extensions will colorize
2458
- // the code, but all other CSS properties will be inherited.
2459
- // IMPORTANT: Therefore, the fenced code block will use the base editor font unless changed by an extension.
2460
- {
2461
- tag: [
2462
- markdownTags.CodeText,
2463
- markdownTags.InlineCode
2464
- ],
2465
- class: code
2466
- },
2467
- {
2468
- tag: [
2469
- markdownTags.QuoteMark
2470
- ],
2471
- class: blockquote
2472
- },
2473
- {
2474
- tag: [
2475
- markdownTags.TableCell
2476
- ],
2477
- class: "font-mono"
2478
- }
2479
- ], {
2480
- scope: markdownLanguage2,
2481
- all: {
2482
- fontFamily: getToken("fontFamily.body", []).join(",")
2483
- }
2484
- });
2485
- };
2486
-
2487
- // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
2488
- var createMarkdownExtensions = ({ themeMode } = {}) => {
2489
- return [
2490
- // Main extension.
2491
- // https://github.com/codemirror/lang-markdown
2492
- // https://codemirror.net/5/mode/markdown/index.html (demo).
2493
- markdown({
2494
- // GRM by default (vs strict CommonMark):
2495
- // Table, TaskList, Strikethrough, and Autolink.
2496
- // NOTE: This extends the parser; it doesn't affect rendering.
2497
- // https://github.github.com/gfm
2498
- // https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
2499
- base: markdownLanguage3,
2500
- // Languages for syntax highlighting fenced code blocks.
2501
- codeLanguages: languages,
2502
- // Parser extensions.
2503
- extensions: [
2504
- // GFM provided by default.
2505
- markdownTagsExtensions
2506
- ]
2507
- }),
2508
- // https://github.com/codemirror/theme-one-dark
2509
- themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle),
2510
- // Custom styles.
2511
- syntaxHighlighting(markdownHighlightStyle()),
2512
- keymap5.of([
2513
- // https://codemirror.net/docs/ref/#commands.indentWithTab
2514
- indentWithTab,
2515
- // https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
2516
- ...closeBracketsKeymap,
2517
- // https://codemirror.net/docs/ref/#commands.historyKeymap
2518
- ...historyKeymap,
2519
- // https://codemirror.net/docs/ref/#search.searchKeymap
2520
- ...searchKeymap,
2521
- // https://codemirror.net/docs/ref/#commands.standardKeymap
2522
- ...standardKeymap
2523
- ])
2524
- ];
2525
- };
2526
-
2527
- // packages/ui/react-ui-editor/src/extensions/markdown/decorate.ts
2528
- import { syntaxTree } from "@codemirror/language";
2529
- import { RangeSetBuilder as RangeSetBuilder2, StateEffect as StateEffect4 } from "@codemirror/state";
2530
- import { EditorView as EditorView12, Decoration as Decoration5, WidgetType as WidgetType3, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
2531
- import { mx as mx2 } from "@dxos/react-ui-theme";
2532
- var HorizontalRuleWidget = class extends WidgetType3 {
2533
- toDOM() {
2534
- const el = document.createElement("span");
2535
- el.className = "cm-hr";
2536
- return el;
2537
- }
2538
- };
2539
- var LinkButton = class extends WidgetType3 {
2540
- constructor(url, render) {
2541
- super();
2542
- this.url = url;
2543
- this.render = render;
2544
- }
2545
- eq(other) {
2546
- return this.url === other.url;
2547
- }
2548
- toDOM(view) {
2549
- const el = document.createElement("span");
2550
- this.render(el, this.url);
2551
- return el;
2552
- }
2553
- };
2554
- var CheckboxWidget = class extends WidgetType3 {
2555
- constructor(_checked) {
2556
- super();
2557
- this._checked = _checked;
2558
- }
2559
- eq(other) {
2560
- return this._checked === other._checked;
2561
- }
2562
- toDOM(view) {
2563
- const input = document.createElement("input");
2564
- input.className = "cm-task-checkbox ch-checkbox ch-focus-ring -mbs-0.5";
2565
- input.type = "checkbox";
2566
- input.checked = this._checked;
2567
- if (view.state.readOnly) {
2568
- input.setAttribute("disabled", "true");
2569
- } else {
2570
- input.onmousedown = (event) => {
2571
- const pos = view.posAtDOM(input);
2572
- const text = view.state.sliceDoc(pos, pos + 3);
2573
- if (text === (this._checked ? "[x]" : "[ ]")) {
2574
- view.dispatch({
2575
- changes: {
2576
- from: pos + 1,
2577
- to: pos + 2,
2578
- insert: this._checked ? " " : "x"
2579
- }
2580
- });
2581
- event.preventDefault();
2582
- }
2583
- };
2584
- }
2585
- return input;
2586
- }
2587
- ignoreEvent() {
2588
- return false;
2589
- }
2590
- };
2591
- var hide = Decoration5.replace({});
2592
- var fencedCodeLine = Decoration5.line({
2593
- class: mx2("cm-code cm-codeblock-line")
2594
- });
2595
- var fencedCodeLineFirst = Decoration5.line({
2596
- class: mx2("cm-code cm-codeblock-line", "cm-codeblock-first")
2597
- });
2598
- var fencedCodeLineLast = Decoration5.line({
2599
- class: mx2("cm-code cm-codeblock-line", "cm-codeblock-last")
2600
- });
2601
- var horizontalRule = Decoration5.replace({
2602
- widget: new HorizontalRuleWidget()
2603
- });
2604
- var checkedTask = Decoration5.replace({
2605
- widget: new CheckboxWidget(true)
2606
- });
2607
- var uncheckedTask = Decoration5.replace({
2608
- widget: new CheckboxWidget(false)
2609
- });
2610
- var editingRange = (state2, range, focus) => {
2611
- const { readOnly, selection: { main: { head } } } = state2;
2612
- return focus && !readOnly && head >= range.from && head <= range.to;
2613
- };
2614
- var MarksByParent = /* @__PURE__ */ new Set([
2615
- "CodeMark",
2616
- "EmphasisMark",
2617
- "StrikethroughMark",
2618
- "SubscriptMark",
2619
- "SuperscriptMark"
2620
- ]);
2621
- var buildDecorations = (view, options, focus) => {
2622
- const deco = new RangeSetBuilder2();
2623
- const atomicDeco = new RangeSetBuilder2();
2624
- const { state: state2 } = view;
2625
- for (const { from, to } of view.visibleRanges) {
2626
- syntaxTree(state2).iterate({
2627
- from,
2628
- to,
2629
- enter: (node) => {
2630
- if (node.name === "FencedCode") {
2631
- const editing = editingRange(state2, node, focus);
2632
- for (const block of view.viewportLineBlocks) {
2633
- if (block.to < node.from) {
2634
- continue;
2635
- }
2636
- if (block.from > node.to) {
2637
- break;
2638
- }
2639
- const first = block.from <= node.from;
2640
- const last = block.to >= node.to && /^(\s>)*```$/.test(state2.doc.sliceString(block.from, block.to));
2641
- deco.add(block.from, block.from, first ? fencedCodeLineFirst : last ? fencedCodeLineLast : fencedCodeLine);
2642
- if (!editing && (first || last)) {
2643
- atomicDeco.add(block.from, block.to, hide);
2644
- }
2645
- }
2646
- return false;
2647
- } else if (node.name === "Link") {
2648
- const marks = node.node.getChildren("LinkMark");
2649
- const urlNode = node.node.getChild("URL");
2650
- const editing = editingRange(state2, node, focus);
2651
- if (urlNode && marks.length >= 2) {
2652
- const url = state2.sliceDoc(urlNode.from, urlNode.to);
2653
- if (!editing) {
2654
- atomicDeco.add(node.from, marks[0].to, hide);
2655
- }
2656
- deco.add(marks[0].to, marks[1].from, Decoration5.mark({
2657
- tagName: "a",
2658
- attributes: {
2659
- class: "cm-link",
2660
- href: url,
2661
- rel: "noreferrer",
2662
- target: "_blank"
2663
- }
2664
- }));
2665
- if (!editing) {
2666
- atomicDeco.add(marks[1].from, node.to, options.renderLinkButton ? Decoration5.replace({
2667
- widget: new LinkButton(url, options.renderLinkButton)
2668
- }) : hide);
2669
- }
2670
- }
2671
- } else if (node.name === "HeaderMark") {
2672
- const parent = node.node.parent;
2673
- if (/^ATX/.test(parent.name) && !editingRange(state2, state2.doc.lineAt(node.from), focus)) {
2674
- const next = state2.doc.sliceString(node.to, node.to + 1);
2675
- atomicDeco.add(node.from, node.to + (next === " " ? 1 : 0), hide);
2676
- }
2677
- } else if (node.name === "HorizontalRule") {
2678
- if (!editingRange(state2, node, focus)) {
2679
- deco.add(node.from, node.to, horizontalRule);
2680
- }
2681
- } else if (node.name === "TaskMarker") {
2682
- if (!editingRange(state2, node, focus)) {
2683
- const checked = state2.doc.sliceString(node.from + 1, node.to - 1) === "x";
2684
- atomicDeco.add(node.from - 2, node.from - 1, Decoration5.mark({
2685
- class: "cm-task"
2686
- }));
2687
- atomicDeco.add(node.from, node.to, checked ? checkedTask : uncheckedTask);
2688
- }
2689
- } else if (MarksByParent.has(node.name)) {
2690
- if (!editingRange(state2, node.node.parent, focus)) {
2691
- atomicDeco.add(node.from, node.to, hide);
2692
- }
2693
- }
2694
- }
2695
- });
2696
- }
2697
- return {
2698
- deco: deco.finish(),
2699
- atomicDeco: atomicDeco.finish()
2700
- };
2701
- };
2702
- var forceUpdate = StateEffect4.define();
2703
- var decorateMarkdown = (options = {}) => {
2704
- return [
2705
- ViewPlugin4.fromClass(class {
2706
- constructor(view) {
2707
- ({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations(view, options, view.hasFocus));
2708
- }
2709
- update(update2) {
2710
- if (update2.docChanged || update2.viewportChanged || update2.focusChanged || update2.transactions.some((tr) => tr.effects.some((e) => e.is(forceUpdate))) || update2.selectionSet && !options.selectionChangeDelay) {
2711
- ({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations(update2.view, options, update2.view.hasFocus));
2712
- this.clearUpdate();
2713
- } else if (update2.selectionSet) {
2714
- this.scheduleUpdate(update2.view);
2715
- }
2716
- }
2717
- // TODO(burdon): BUG: If the cursor is at the end of a link at the end of a line,
2718
- // the cursor will float in space or be in the wrong position after the decoration is applied.
2719
- scheduleUpdate(view) {
2720
- this.clearUpdate();
2721
- this.pendingUpdate = setTimeout(() => {
2722
- view.dispatch({
2723
- effects: forceUpdate.of(null)
2724
- });
2725
- }, options.selectionChangeDelay);
2726
- }
2727
- clearUpdate() {
2728
- if (this.pendingUpdate) {
2729
- clearTimeout(this.pendingUpdate);
2730
- this.pendingUpdate = void 0;
2731
- }
2732
- }
2733
- destroy() {
2734
- this.clearUpdate();
2735
- }
2736
- }, {
2737
- provide: (plugin) => [
2738
- EditorView12.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration5.none),
2739
- EditorView12.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration5.none),
2740
- EditorView12.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration5.none)
2741
- ]
2742
- }),
2743
- formattingStyles
2744
- ];
2745
- };
2746
- var formattingStyles = EditorView12.baseTheme({
2747
- "& .cm-code": {
2748
- fontFamily: getToken("fontFamily.mono", []).join(",")
2749
- },
2750
- "& .cm-codeblock-line": {
2751
- paddingInline: "1rem !important"
2752
- },
2753
- "& .cm-codeblock-end": {
2754
- display: "inline-block",
2755
- width: "100%",
2756
- position: "relative",
2757
- "&::after": {
2758
- position: "absolute",
2759
- inset: 0,
2760
- content: '""'
2761
- }
2762
- },
2763
- "& .cm-codeblock-first": {
2764
- borderTopLeftRadius: ".5rem",
2765
- borderTopRightRadius: ".5rem"
2766
- },
2767
- "& .cm-codeblock-last": {
2768
- borderBottomLeftRadius: ".5rem",
2769
- borderBottomRightRadius: ".5rem"
2770
- },
2771
- "&light .cm-codeblock-line, &light .cm-activeLine.cm-codeblock-line": {
2772
- background: getToken("extend.semanticColors.input.light"),
2773
- mixBlendMode: "darken"
2774
- },
2775
- "&dark .cm-codeblock-line, &dark .cm-activeLine.cm-codeblock-line": {
2776
- background: getToken("extend.semanticColors.input.dark"),
2777
- mixBlendMode: "lighten"
2778
- },
2779
- "& .cm-hr": {
2780
- display: "inline-block",
2781
- width: "100%",
2782
- height: "0",
2783
- verticalAlign: "middle",
2784
- borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
2785
- },
2786
- "& .cm-task": {
2787
- color: getToken("extend.colors.blue.500")
2788
- },
2789
- "& .cm-task-checkbox": {
2790
- marginLeft: "4px",
2791
- marginRight: "4px"
2792
- }
2793
- });
2794
-
2795
- // packages/ui/react-ui-editor/src/extensions/markdown/formatting.ts
2796
- import { snippet } from "@codemirror/autocomplete";
2797
- import { syntaxTree as syntaxTree2 } from "@codemirror/language";
2798
- import { EditorSelection } from "@codemirror/state";
2799
- import { EditorView as EditorView13, keymap as keymap6 } from "@codemirror/view";
2800
- import { useMemo } from "react";
2801
- import { useStateRef } from "@dxos/react-async";
2802
- var formattingEquals = (a, b) => a.blockType === b.blockType && a.strong === b.strong && a.emphasis === b.emphasis && a.strikethrough === b.strikethrough && a.code === b.code && a.link === b.link && a.listStyle === b.listStyle && a.blockQuote === b.blockQuote;
2803
- var Inline;
2804
- (function(Inline2) {
2805
- Inline2[Inline2["Strong"] = 0] = "Strong";
2806
- Inline2[Inline2["Emphasis"] = 1] = "Emphasis";
2807
- Inline2[Inline2["Strikethrough"] = 2] = "Strikethrough";
2808
- Inline2[Inline2["Code"] = 3] = "Code";
2809
- })(Inline || (Inline = {}));
2810
- var List;
2811
- (function(List2) {
2812
- List2[List2["Ordered"] = 0] = "Ordered";
2813
- List2[List2["Bullet"] = 1] = "Bullet";
2814
- List2[List2["Task"] = 2] = "Task";
2815
- })(List || (List = {}));
2816
- var setHeading = (level) => ({ state: state2, dispatch }) => {
2817
- const { selection: { ranges }, doc } = state2;
2818
- const changes = [];
2819
- let prevBlock = -1;
2820
- for (const range of ranges) {
2821
- let sawBlock = false;
2822
- syntaxTree2(state2).iterate({
2823
- from: range.from,
2824
- to: range.to,
2825
- enter: (node) => {
2826
- if (!Object.hasOwn(Textblocks, node.name) || prevBlock === node.from) {
2827
- return;
2828
- }
2829
- sawBlock = true;
2830
- prevBlock = node.from;
2831
- const blockType = Textblocks[node.name];
2832
- const isHeading = /heading(\d)/.exec(blockType);
2833
- const curLevel = isHeading ? +isHeading[1] : node.name === "Paragraph" ? 0 : -1;
2834
- if (curLevel < 0 || curLevel === level) {
2835
- return;
2836
- }
2837
- if (curLevel === 0) {
2838
- changes.push({
2839
- from: node.from,
2840
- insert: "#".repeat(level) + " "
2841
- });
2842
- } else if (node.name === "SetextHeading1" || node.name === "SetextHeading2") {
2843
- const nextLine = doc.lineAt(node.to);
2844
- if (level) {
2845
- changes.push({
2846
- from: node.from,
2847
- insert: "#".repeat(level) + " "
2848
- });
2849
- }
2850
- changes.push({
2851
- from: nextLine.from - 1,
2852
- to: nextLine.to
2853
- });
2854
- } else {
2855
- if (level === 0) {
2856
- changes.push({
2857
- from: node.from,
2858
- to: Math.min(node.to, node.from + curLevel + 1)
2859
- });
2860
- } else if (level < curLevel) {
2861
- changes.push({
2862
- from: node.from,
2863
- to: node.from + (curLevel - level)
2864
- });
2865
- } else {
2866
- changes.push({
2867
- from: node.from,
2868
- insert: "#".repeat(level - curLevel)
2869
- });
2870
- }
2871
- }
2872
- }
2873
- });
2874
- let line;
2875
- if (!sawBlock && range.empty && level > 0 && !/\S/.test((line = state2.doc.lineAt(range.from)).text)) {
2876
- changes.push({
2877
- from: line.from,
2878
- to: line.to,
2879
- insert: "#".repeat(level) + " "
2880
- });
2881
- }
2882
- }
2883
- if (!changes.length) {
2884
- return false;
2371
+ if (!changes.length) {
2372
+ return false;
2885
2373
  }
2886
2374
  const changeSet = state2.changes(changes);
2887
2375
  dispatch(state2.update({
@@ -2926,7 +2414,7 @@ var setStyle = (type, enable) => ({ state: state2, dispatch }) => {
2926
2414
  let startCovered = false;
2927
2415
  let endCovered = false;
2928
2416
  let { from, to } = range;
2929
- syntaxTree2(state2).iterate({
2417
+ syntaxTree(state2).iterate({
2930
2418
  from,
2931
2419
  to,
2932
2420
  enter: (node) => {
@@ -3126,7 +2614,7 @@ var insertTable = (view) => {
3126
2614
  snippets.table(view, null, from, from);
3127
2615
  };
3128
2616
  var removeLinkInner = (from, to, changes, state2) => {
3129
- syntaxTree2(state2).iterate({
2617
+ syntaxTree(state2).iterate({
3130
2618
  from,
3131
2619
  to,
3132
2620
  enter: (node) => {
@@ -3148,743 +2636,1299 @@ var removeLinkInner = (from, to, changes, state2) => {
3148
2636
  return false;
3149
2637
  }
3150
2638
  }
3151
- });
2639
+ });
2640
+ };
2641
+ var removeLink = ({ state: state2, dispatch }) => {
2642
+ const changes = [];
2643
+ for (const { from, to } of state2.selection.ranges) {
2644
+ removeLinkInner(from, to, changes, state2);
2645
+ }
2646
+ if (!changes) {
2647
+ return false;
2648
+ }
2649
+ dispatch(state2.update({
2650
+ changes,
2651
+ userEvent: "format.link.remove",
2652
+ scrollIntoView: true
2653
+ }));
2654
+ return true;
2655
+ };
2656
+ var addLink = ({ url, image: image2 } = {}) => ({ state: state2, dispatch }) => {
2657
+ const changes = state2.changeByRange((range) => {
2658
+ let { from, to } = range;
2659
+ const cutStyles = [];
2660
+ let okay = null;
2661
+ syntaxTree(state2).iterate({
2662
+ from,
2663
+ to,
2664
+ enter: (node) => {
2665
+ if (Object.hasOwn(Textblocks, node.name)) {
2666
+ okay = Textblocks[node.name] !== "codeblock" && from >= blockContentStart(node) && to <= blockContentEnd(node, state2.doc);
2667
+ } else if (Object.hasOwn(InlineMarker, node.name)) {
2668
+ const sNode = node.node;
2669
+ if (node.from < from && node.to <= to) {
2670
+ if (sNode.firstChild.to === from) {
2671
+ from = node.from;
2672
+ } else {
2673
+ cutStyles.push(sNode);
2674
+ }
2675
+ } else if (node.from >= from && node.to > to) {
2676
+ if (sNode.lastChild.from === to) {
2677
+ to = node.to;
2678
+ } else {
2679
+ cutStyles.push(sNode);
2680
+ }
2681
+ }
2682
+ }
2683
+ }
2684
+ });
2685
+ if (okay === null) {
2686
+ const line = state2.doc.lineAt(from);
2687
+ okay = to <= line.to && !/\S/.test(line.text.slice(from - line.from));
2688
+ }
2689
+ if (!okay) {
2690
+ return {
2691
+ range
2692
+ };
2693
+ }
2694
+ const changes2 = [];
2695
+ const changesAfter = [];
2696
+ removeLinkInner(from, to, changesAfter, state2);
2697
+ let cursorOffset = 1;
2698
+ for (const style of cutStyles) {
2699
+ const type = InlineMarker[style.name];
2700
+ const mark2 = inlineMarkerText(type);
2701
+ if (style.from < from) {
2702
+ changes2.push({
2703
+ from: skipSpaces(from, state2.doc, -1),
2704
+ insert: mark2
2705
+ });
2706
+ changesAfter.push({
2707
+ from: skipSpaces(from, state2.doc, 1, to),
2708
+ insert: mark2
2709
+ });
2710
+ } else {
2711
+ changes2.push({
2712
+ from: skipSpaces(to, state2.doc, -1, from),
2713
+ insert: mark2
2714
+ });
2715
+ const after = skipSpaces(to, state2.doc, 1);
2716
+ if (after === to) {
2717
+ cursorOffset += mark2.length;
2718
+ }
2719
+ changesAfter.push({
2720
+ from: after,
2721
+ insert: mark2
2722
+ });
2723
+ }
2724
+ }
2725
+ changes2.push({
2726
+ from,
2727
+ insert: image2 ? "![" : "["
2728
+ }, {
2729
+ from: to,
2730
+ insert: `](${url ?? ""})`
2731
+ });
2732
+ const changeSet = state2.changes(changes2.concat(changesAfter));
2733
+ return {
2734
+ changes: changeSet,
2735
+ range: EditorSelection.cursor(changeSet.mapPos(to, 1) - cursorOffset - (url ? url.length + 2 : 0))
2736
+ };
2737
+ });
2738
+ if (changes.changes.empty) {
2739
+ return false;
2740
+ }
2741
+ dispatch(state2.update(changes, {
2742
+ userEvent: "format.link.add",
2743
+ scrollIntoView: true
2744
+ }));
2745
+ return true;
2746
+ };
2747
+ var addList = (type) => ({ state: state2, dispatch }) => {
2748
+ let lastBlock = -1;
2749
+ let counter = 1;
2750
+ let first = true;
2751
+ let parentColumn = null;
2752
+ const blocks = [];
2753
+ for (const { from, to } of state2.selection.ranges) {
2754
+ syntaxTree(state2).iterate({
2755
+ from,
2756
+ to,
2757
+ enter: (node) => {
2758
+ if (Object.hasOwn(Textblocks, node.name) && node.name !== "TableCell" || node.name === "Table") {
2759
+ if (first) {
2760
+ let before = node.node.prevSibling;
2761
+ while (before && /Mark$/.test(before.name)) {
2762
+ before = before.prevSibling;
2763
+ }
2764
+ if (before?.name === (type === 0 ? "OrderedList" : "BulletList")) {
2765
+ const item = before.lastChild;
2766
+ const itemLine = state2.doc.lineAt(item.from);
2767
+ const itemText = itemLine.text.slice(item.from - itemLine.from);
2768
+ parentColumn = item.from - itemLine.from + /^\s*/.exec(itemText)[0].length;
2769
+ if (type === 0) {
2770
+ const mark2 = /^\s*(\d+)[.)]/.exec(itemText);
2771
+ if (mark2) {
2772
+ parentColumn += mark2[1].length;
2773
+ counter = +mark2[1] + 1;
2774
+ }
2775
+ }
2776
+ }
2777
+ first = false;
2778
+ }
2779
+ if (node.from === lastBlock) {
2780
+ return;
2781
+ }
2782
+ lastBlock = node.from;
2783
+ blocks.push({
2784
+ node: node.node,
2785
+ counter,
2786
+ parentColumn
2787
+ });
2788
+ counter++;
2789
+ return false;
2790
+ }
2791
+ },
2792
+ leave: (node) => {
2793
+ if (node.name === "BulletList" || node.name === "OrderedList" || node.name === "Blockquote") {
2794
+ counter = 1;
2795
+ parentColumn = null;
2796
+ }
2797
+ }
2798
+ });
2799
+ }
2800
+ if (!blocks.length) {
2801
+ const { from, to } = state2.doc.lineAt(state2.selection.main.anchor);
2802
+ if (from === to) {
2803
+ const insert = type === 1 ? "- " : type === 0 ? "1. " : "- [ ] ";
2804
+ dispatch(state2.update({
2805
+ changes: [
2806
+ {
2807
+ from,
2808
+ insert
2809
+ }
2810
+ ],
2811
+ selection: {
2812
+ anchor: from + insert.length
2813
+ },
2814
+ userEvent: "format.list.add",
2815
+ scrollIntoView: true
2816
+ }));
2817
+ return true;
2818
+ }
2819
+ return false;
2820
+ }
2821
+ const changes = [];
2822
+ for (let i = 0; i < blocks.length; i++) {
2823
+ const { node, counter: counter2, parentColumn: parentColumn2 } = blocks[i];
2824
+ const nodeFrom = node.name === "CodeBlock" ? node.from - 4 : node.from;
2825
+ let padding = nodeFrom > 0 && !/\s/.test(state2.doc.sliceString(nodeFrom - 1, nodeFrom)) ? 1 : 0;
2826
+ if (type === 0) {
2827
+ padding += String(counter2).length;
2828
+ }
2829
+ let line = state2.doc.lineAt(nodeFrom);
2830
+ const column = nodeFrom - line.from;
2831
+ if (parentColumn2 !== null && parentColumn2 > column) {
2832
+ padding = Math.max(padding, parentColumn2 - column);
2833
+ }
2834
+ let mark2;
2835
+ if (type === 0) {
2836
+ let max = counter2;
2837
+ for (let j = i + 1; j < blocks.length; j++) {
2838
+ if (blocks[j].counter !== max + 1) {
2839
+ break;
2840
+ }
2841
+ max++;
2842
+ }
2843
+ const num = String(counter2);
2844
+ padding = Math.max(String(max).length, padding);
2845
+ mark2 = " ".repeat(Math.max(0, padding - num.length)) + num + ". ";
2846
+ } else {
2847
+ mark2 = " ".repeat(padding) + "- " + (type === 2 ? "[ ] " : "");
2848
+ }
2849
+ changes.push({
2850
+ from: nodeFrom,
2851
+ insert: mark2
2852
+ });
2853
+ while (line.to < node.to) {
2854
+ line = state2.doc.lineAt(line.to + 1);
2855
+ const open = /^[\s>]*/.exec(line.text)[0].length;
2856
+ changes.push({
2857
+ from: line.from + Math.min(open, column),
2858
+ insert: " ".repeat(mark2.length)
2859
+ });
2860
+ }
2861
+ }
2862
+ if (type === 0) {
2863
+ const last = blocks[blocks.length - 1];
2864
+ let next = last.node.nextSibling;
2865
+ while (next && /Mark$/.test(next.name)) {
2866
+ next = next.nextSibling;
2867
+ }
2868
+ if (next?.name === "OrderedList") {
2869
+ renumberListItems(next.firstChild, last.counter + 1, changes, state2.doc);
2870
+ }
2871
+ }
2872
+ const changeSet = state2.changes(changes);
2873
+ dispatch(state2.update({
2874
+ changes: changeSet,
2875
+ selection: state2.selection.map(changeSet, 1),
2876
+ userEvent: "format.list.add",
2877
+ scrollIntoView: true
2878
+ }));
2879
+ return true;
3152
2880
  };
3153
- var removeLink = ({ state: state2, dispatch }) => {
2881
+ var removeList = (type) => ({ state: state2, dispatch }) => {
2882
+ let lastBlock = -1;
3154
2883
  const changes = [];
2884
+ const stack = [];
2885
+ const targetNodeType = type === 0 ? "OrderedList" : type === 1 ? "BulletList" : "TaskList";
3155
2886
  for (const { from, to } of state2.selection.ranges) {
3156
- removeLinkInner(from, to, changes, state2);
2887
+ syntaxTree(state2).iterate({
2888
+ from,
2889
+ to,
2890
+ enter: (node) => {
2891
+ const { name } = node;
2892
+ if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
2893
+ stack.push(name);
2894
+ } else if (name === "Task" && stack[stack.length - 1] === "BulletList") {
2895
+ stack[stack.length - 1] = "TaskList";
2896
+ }
2897
+ },
2898
+ leave: (node) => {
2899
+ const { name } = node;
2900
+ if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
2901
+ stack.pop();
2902
+ } else if (name === "ListItem" && stack[stack.length - 1] === targetNodeType && node.from !== lastBlock) {
2903
+ lastBlock = node.from;
2904
+ let line = state2.doc.lineAt(node.from);
2905
+ const mark2 = /^\s*(\d+[.)] |[-*+] (\[[ x]\] )?)/.exec(line.text.slice(node.from - line.from));
2906
+ if (!mark2) {
2907
+ return false;
2908
+ }
2909
+ const column = node.from - line.from;
2910
+ changes.push({
2911
+ from: node.from,
2912
+ to: node.from + mark2[0].length
2913
+ });
2914
+ while (line.to < node.to) {
2915
+ line = state2.doc.lineAt(line.to + 1);
2916
+ const open = /^[\s>]*/.exec(line.text)[0].length;
2917
+ if (open > column) {
2918
+ changes.push({
2919
+ from: line.from + column,
2920
+ to: line.from + Math.min(column + mark2[0].length, open)
2921
+ });
2922
+ }
2923
+ }
2924
+ if (node.to >= to) {
2925
+ renumberListItems(node.node.nextSibling, 1, changes, state2.doc);
2926
+ }
2927
+ return false;
2928
+ }
2929
+ }
2930
+ });
3157
2931
  }
3158
- if (!changes) {
2932
+ if (!changes.length) {
3159
2933
  return false;
3160
2934
  }
3161
2935
  dispatch(state2.update({
3162
2936
  changes,
3163
- userEvent: "format.link.remove",
2937
+ userEvent: "format.list.remove",
3164
2938
  scrollIntoView: true
3165
2939
  }));
3166
2940
  return true;
3167
2941
  };
3168
- var addLink = ({ url, image: image2 } = {}) => ({ state: state2, dispatch }) => {
3169
- const changes = state2.changeByRange((range) => {
3170
- let { from, to } = range;
3171
- const cutStyles = [];
3172
- let okay = null;
3173
- syntaxTree2(state2).iterate({
2942
+ var toggleList = (type) => (target) => {
2943
+ const formatting = getFormatting(target.state);
2944
+ const active = formatting.listStyle === (type === 1 ? "bullet" : type === 0 ? "ordered" : "task");
2945
+ return (active ? removeList(type) : addList(type))(target);
2946
+ };
2947
+ var renumberListItems = (item, counter, changes, doc) => {
2948
+ for (; item; item = item.nextSibling) {
2949
+ if (item.name === "ListItem") {
2950
+ const number = /(\s*)(\d+)[.)]/.exec(doc.sliceString(item.from, item.from + 10));
2951
+ if (!number || +number[2] === counter) {
2952
+ break;
2953
+ }
2954
+ const size = number[1].length + number[2].length;
2955
+ const newNum = String(counter);
2956
+ changes.push({
2957
+ from: item.from + Math.max(0, size - newNum.length),
2958
+ to: item.from + size,
2959
+ insert: newNum
2960
+ });
2961
+ counter++;
2962
+ }
2963
+ }
2964
+ };
2965
+ var setBlockquote = (enable) => ({ state: state2, dispatch }) => {
2966
+ const lines = [];
2967
+ let lastBlock = -1;
2968
+ for (const { from, to } of state2.selection.ranges) {
2969
+ const sawBlock = false;
2970
+ syntaxTree(state2).iterate({
3174
2971
  from,
3175
2972
  to,
3176
2973
  enter: (node) => {
3177
- if (Object.hasOwn(Textblocks, node.name)) {
3178
- okay = Textblocks[node.name] !== "codeblock" && from >= blockContentStart(node) && to <= blockContentEnd(node, state2.doc);
3179
- } else if (Object.hasOwn(InlineMarker, node.name)) {
3180
- const sNode = node.node;
3181
- if (node.from < from && node.to <= to) {
3182
- if (sNode.firstChild.to === from) {
3183
- from = node.from;
3184
- } else {
3185
- cutStyles.push(sNode);
2974
+ if (Object.hasOwn(Textblocks, node.name) || node.name === "Table") {
2975
+ if (node.from === lastBlock) {
2976
+ return false;
2977
+ }
2978
+ lastBlock = node.from;
2979
+ let line2 = state2.doc.lineAt(node.from);
2980
+ if (line2.number > 1) {
2981
+ const prevLine = state2.doc.line(line2.number - 1);
2982
+ if (/^[>\s]*$/.test(prevLine.text)) {
2983
+ if (!enable || lines.length && lines[lines.length - 1].number === prevLine.number - 1) {
2984
+ lines.push(prevLine);
2985
+ }
3186
2986
  }
3187
- } else if (node.from >= from && node.to > to) {
3188
- if (sNode.lastChild.from === to) {
3189
- to = node.to;
3190
- } else {
3191
- cutStyles.push(sNode);
2987
+ }
2988
+ for (; ; ) {
2989
+ lines.push(line2);
2990
+ if (line2.to >= node.to) {
2991
+ break;
2992
+ }
2993
+ line2 = state2.doc.line(line2.number + 1);
2994
+ }
2995
+ if (!enable && line2.number < state2.doc.lines) {
2996
+ const nextLine = state2.doc.line(line2.number + 1);
2997
+ if (/^[>\s]*$/.test(nextLine.text)) {
2998
+ lines.push(nextLine);
3192
2999
  }
3193
3000
  }
3001
+ return false;
3194
3002
  }
3195
3003
  }
3196
3004
  });
3197
- if (okay === null) {
3198
- const line = state2.doc.lineAt(from);
3199
- okay = to <= line.to && !/\S/.test(line.text.slice(from - line.from));
3200
- }
3201
- if (!okay) {
3202
- return {
3203
- range
3204
- };
3005
+ let line;
3006
+ if (!sawBlock && enable && from === to && !/\S/.test((line = state2.doc.lineAt(from)).text)) {
3007
+ lines.push(line);
3205
3008
  }
3206
- const changes2 = [];
3207
- const changesAfter = [];
3208
- removeLinkInner(from, to, changesAfter, state2);
3209
- let cursorOffset = 1;
3210
- for (const style of cutStyles) {
3211
- const type = InlineMarker[style.name];
3212
- const mark2 = inlineMarkerText(type);
3213
- if (style.from < from) {
3214
- changes2.push({
3215
- from: skipSpaces(from, state2.doc, -1),
3216
- insert: mark2
3217
- });
3218
- changesAfter.push({
3219
- from: skipSpaces(from, state2.doc, 1, to),
3220
- insert: mark2
3221
- });
3222
- } else {
3223
- changes2.push({
3224
- from: skipSpaces(to, state2.doc, -1, from),
3225
- insert: mark2
3226
- });
3227
- const after = skipSpaces(to, state2.doc, 1);
3228
- if (after === to) {
3229
- cursorOffset += mark2.length;
3230
- }
3231
- changesAfter.push({
3232
- from: after,
3233
- insert: mark2
3009
+ }
3010
+ const changes = [];
3011
+ for (const line of lines) {
3012
+ if (enable) {
3013
+ changes.push({
3014
+ from: line.from,
3015
+ insert: /\S/.test(line.text) ? "> " : ">"
3016
+ });
3017
+ } else {
3018
+ const quote = /((?:[\s>\-+*]|\d+[.)])*?)> ?/.exec(line.text);
3019
+ if (quote) {
3020
+ changes.push({
3021
+ from: line.from + quote[1].length,
3022
+ to: line.from + quote[0].length
3234
3023
  });
3235
3024
  }
3236
3025
  }
3237
- changes2.push({
3026
+ }
3027
+ if (!changes.length) {
3028
+ return false;
3029
+ }
3030
+ const changeSet = state2.changes(changes);
3031
+ dispatch(state2.update({
3032
+ changes: changeSet,
3033
+ selection: state2.selection.map(changeSet, 1),
3034
+ userEvent: enable ? "format.blockquote.add" : "format.blockquote.remove",
3035
+ scrollIntoView: true
3036
+ }));
3037
+ return true;
3038
+ };
3039
+ var addBlockquote = setBlockquote(true);
3040
+ var removeBlockquote = setBlockquote(false);
3041
+ var toggleBlockquote = (target) => {
3042
+ return (getFormatting(target.state).blockQuote ? removeBlockquote : addBlockquote)(target);
3043
+ };
3044
+ var addCodeblock = (target) => {
3045
+ const { state: state2, dispatch } = target;
3046
+ const { selection } = state2;
3047
+ if (selection.ranges.length === 1 && selection.main.empty) {
3048
+ const { head } = selection.main;
3049
+ const line = state2.doc.lineAt(head);
3050
+ if (!/\S/.test(line.text) && head === line.from) {
3051
+ snippets.codeblock(target, null, line.from, line.to);
3052
+ return true;
3053
+ }
3054
+ }
3055
+ const ranges = [];
3056
+ for (const { from, to } of selection.ranges) {
3057
+ let blockFrom = from;
3058
+ let blockTo = to;
3059
+ syntaxTree(state2).iterate({
3238
3060
  from,
3239
- insert: image2 ? "![" : "["
3240
- }, {
3241
- from: to,
3242
- insert: `](${url ?? ""})`
3061
+ to,
3062
+ enter: (node) => {
3063
+ if (Object.hasOwn(Textblocks, node.name)) {
3064
+ if (from >= node.from && to <= node.to) {
3065
+ blockFrom = node.from;
3066
+ blockTo = node.to;
3067
+ } else {
3068
+ blockFrom = Math.min(blockFrom, state2.doc.lineAt(node.from).from);
3069
+ blockTo = Math.max(blockTo, state2.doc.lineAt(node.to).to);
3070
+ }
3071
+ }
3072
+ }
3243
3073
  });
3244
- const changeSet = state2.changes(changes2.concat(changesAfter));
3245
- return {
3246
- changes: changeSet,
3247
- range: EditorSelection.cursor(changeSet.mapPos(to, 1) - cursorOffset - (url ? url.length + 2 : 0))
3248
- };
3249
- });
3250
- if (changes.changes.empty) {
3074
+ if (ranges.length && ranges[ranges.length - 1].to >= blockFrom - 1) {
3075
+ ranges[ranges.length - 1].to = blockTo;
3076
+ } else {
3077
+ ranges.push({
3078
+ from: blockFrom,
3079
+ to: blockTo
3080
+ });
3081
+ }
3082
+ }
3083
+ if (!ranges.length) {
3251
3084
  return false;
3252
3085
  }
3253
- dispatch(state2.update(changes, {
3254
- userEvent: "format.link.add",
3086
+ const changes = ranges.map(({ from, to }) => {
3087
+ const column = from - state2.doc.lineAt(from).from;
3088
+ return [
3089
+ {
3090
+ from,
3091
+ insert: "```\n" + " ".repeat(column)
3092
+ },
3093
+ {
3094
+ from: to,
3095
+ insert: "\n" + " ".repeat(column) + "```"
3096
+ }
3097
+ ];
3098
+ });
3099
+ dispatch(state2.update({
3100
+ changes,
3101
+ userEvent: "format.codeblock.add",
3255
3102
  scrollIntoView: true
3256
3103
  }));
3257
3104
  return true;
3258
3105
  };
3259
- var addList = (type) => ({ state: state2, dispatch }) => {
3106
+ var removeCodeblock = ({ state: state2, dispatch }) => {
3107
+ const changes = [];
3260
3108
  let lastBlock = -1;
3261
- let counter = 1;
3262
- let first = true;
3263
- let parentColumn = null;
3264
- const blocks = [];
3265
3109
  for (const { from, to } of state2.selection.ranges) {
3266
- syntaxTree2(state2).iterate({
3110
+ syntaxTree(state2).iterate({
3267
3111
  from,
3268
3112
  to,
3269
3113
  enter: (node) => {
3270
- if (Object.hasOwn(Textblocks, node.name) && node.name !== "TableCell" || node.name === "Table") {
3271
- if (first) {
3272
- let before = node.node.prevSibling;
3273
- while (before && /Mark$/.test(before.name)) {
3274
- before = before.prevSibling;
3114
+ if (Textblocks[node.name] === "codeblock" && lastBlock !== node.from) {
3115
+ lastBlock = node.from;
3116
+ const firstLine = state2.doc.lineAt(node.from);
3117
+ if (node.name === "FencedCode") {
3118
+ changes.push({
3119
+ from: node.from,
3120
+ to: firstLine.to + 1 + node.from - firstLine.from
3121
+ });
3122
+ const lastLine = state2.doc.lineAt(node.to);
3123
+ if (/^([\s>]|[-*+] |\d+[).])*`+$/.test(lastLine.text)) {
3124
+ changes.push({
3125
+ from: lastLine.from - (lastLine.number === firstLine.number + 1 ? 0 : 1),
3126
+ to: lastLine.to
3127
+ });
3275
3128
  }
3276
- if (before?.name === (type === 0 ? "OrderedList" : "BulletList")) {
3277
- const item = before.lastChild;
3278
- const itemLine = state2.doc.lineAt(item.from);
3279
- const itemText = itemLine.text.slice(item.from - itemLine.from);
3280
- parentColumn = item.from - itemLine.from + /^\s*/.exec(itemText)[0].length;
3281
- if (type === 0) {
3282
- const mark2 = /^\s*(\d+)[.)]/.exec(itemText);
3283
- if (mark2) {
3284
- parentColumn += mark2[1].length;
3285
- counter = +mark2[1] + 1;
3286
- }
3129
+ } else {
3130
+ const column = node.from - firstLine.from;
3131
+ for (let line = firstLine; ; line = state2.doc.line(line.number + 1)) {
3132
+ changes.push({
3133
+ from: line.from + column - 4,
3134
+ to: line.from + column
3135
+ });
3136
+ if (line.to >= node.to) {
3137
+ break;
3287
3138
  }
3288
3139
  }
3289
- first = false;
3290
- }
3291
- if (node.from === lastBlock) {
3292
- return;
3293
3140
  }
3294
- lastBlock = node.from;
3295
- blocks.push({
3296
- node: node.node,
3297
- counter,
3298
- parentColumn
3299
- });
3300
- counter++;
3301
- return false;
3302
- }
3303
- },
3304
- leave: (node) => {
3305
- if (node.name === "BulletList" || node.name === "OrderedList" || node.name === "Blockquote") {
3306
- counter = 1;
3307
- parentColumn = null;
3308
3141
  }
3309
3142
  }
3310
3143
  });
3311
3144
  }
3312
- if (!blocks.length) {
3313
- const { from, to } = state2.doc.lineAt(state2.selection.main.anchor);
3314
- if (from === to) {
3315
- const insert = type === 1 ? "- " : type === 0 ? "1. " : "- [ ] ";
3316
- dispatch(state2.update({
3317
- changes: [
3318
- {
3319
- from,
3320
- insert
3321
- }
3322
- ],
3323
- selection: {
3324
- anchor: from + insert.length
3325
- },
3326
- userEvent: "format.list.add",
3327
- scrollIntoView: true
3328
- }));
3329
- return true;
3330
- }
3145
+ if (!changes.length) {
3331
3146
  return false;
3332
3147
  }
3333
- const changes = [];
3334
- for (let i = 0; i < blocks.length; i++) {
3335
- const { node, counter: counter2, parentColumn: parentColumn2 } = blocks[i];
3336
- const nodeFrom = node.name === "CodeBlock" ? node.from - 4 : node.from;
3337
- let padding = nodeFrom > 0 && !/\s/.test(state2.doc.sliceString(nodeFrom - 1, nodeFrom)) ? 1 : 0;
3338
- if (type === 0) {
3339
- padding += String(counter2).length;
3148
+ dispatch(state2.update({
3149
+ changes,
3150
+ userEvent: "format.codeblock.remove",
3151
+ scrollIntoView: true
3152
+ }));
3153
+ return true;
3154
+ };
3155
+ var toggleCodeblock = (target) => {
3156
+ return (getFormatting(target.state).blockType === "codeblock" ? removeCodeblock : addCodeblock)(target);
3157
+ };
3158
+ var formattingKeymap = (options = {}) => {
3159
+ return [
3160
+ keymap6.of([
3161
+ {
3162
+ key: "meta-b",
3163
+ run: toggleStrong
3164
+ }
3165
+ ])
3166
+ ];
3167
+ };
3168
+ var InlineMarker = {
3169
+ Emphasis: 1,
3170
+ StrongEmphasis: 0,
3171
+ InlineCode: 3,
3172
+ Strikethrough: 2
3173
+ };
3174
+ var IgnoreInline = /* @__PURE__ */ new Set([
3175
+ "Autolink",
3176
+ "CodeMark",
3177
+ "CodeText",
3178
+ "Comment",
3179
+ "EmphasisMark",
3180
+ "Hardbreak",
3181
+ "HeaderMark",
3182
+ "HTMLTag",
3183
+ "LinkMark",
3184
+ "ListMark",
3185
+ "ProcessingInstruction",
3186
+ "QuoteMark",
3187
+ "StrikethroughMark",
3188
+ "SubscriptMark",
3189
+ "SuperscriptMark",
3190
+ "TaskMarker"
3191
+ ]);
3192
+ var Textblocks = {
3193
+ ATXHeading1: "heading1",
3194
+ ATXHeading2: "heading2",
3195
+ ATXHeading3: "heading3",
3196
+ ATXHeading4: "heading4",
3197
+ ATXHeading5: "heading5",
3198
+ ATXHeading6: "heading6",
3199
+ CodeBlock: "codeblock",
3200
+ FencedCode: "codeblock",
3201
+ Paragraph: "paragraph",
3202
+ SetextHeading1: "heading1",
3203
+ SetextHeading2: "heading2",
3204
+ TableCell: "tablecell",
3205
+ Task: "paragraph"
3206
+ };
3207
+ var getFormatting = (state2) => {
3208
+ let blockType = null;
3209
+ const inline = [
3210
+ null,
3211
+ null,
3212
+ null,
3213
+ null
3214
+ ];
3215
+ let link = false;
3216
+ let blockQuote = null;
3217
+ let listStyle = null;
3218
+ const stack = [];
3219
+ let currentBlock = null;
3220
+ const advanceInline = (upto) => {
3221
+ if (!currentBlock) {
3222
+ return;
3340
3223
  }
3341
- let line = state2.doc.lineAt(nodeFrom);
3342
- const column = nodeFrom - line.from;
3343
- if (parentColumn2 !== null && parentColumn2 > column) {
3344
- padding = Math.max(padding, parentColumn2 - column);
3224
+ upto = Math.min(upto, currentBlock.end);
3225
+ if (upto <= currentBlock.pos) {
3226
+ return;
3345
3227
  }
3346
- let mark2;
3347
- if (type === 0) {
3348
- let max = counter2;
3349
- for (let j = i + 1; j < blocks.length; j++) {
3350
- if (blocks[j].counter !== max + 1) {
3351
- break;
3352
- }
3353
- max++;
3228
+ for (let i = 0; i < currentBlock.active.length; i++) {
3229
+ if (inline[i] === false) {
3230
+ continue;
3231
+ } else if (currentBlock.active[i]) {
3232
+ inline[i] = true;
3233
+ } else if (/\S/.test(state2.doc.sliceString(currentBlock.pos, upto))) {
3234
+ inline[i] = false;
3354
3235
  }
3355
- const num = String(counter2);
3356
- padding = Math.max(String(max).length, padding);
3357
- mark2 = " ".repeat(Math.max(0, padding - num.length)) + num + ". ";
3358
- } else {
3359
- mark2 = " ".repeat(padding) + "- " + (type === 2 ? "[ ] " : "");
3360
- }
3361
- changes.push({
3362
- from: nodeFrom,
3363
- insert: mark2
3364
- });
3365
- while (line.to < node.to) {
3366
- line = state2.doc.lineAt(line.to + 1);
3367
- const open = /^[\s>]*/.exec(line.text)[0].length;
3368
- changes.push({
3369
- from: line.from + Math.min(open, column),
3370
- insert: " ".repeat(mark2.length)
3371
- });
3372
3236
  }
3373
- }
3374
- if (type === 0) {
3375
- const last = blocks[blocks.length - 1];
3376
- let next = last.node.nextSibling;
3377
- while (next && /Mark$/.test(next.name)) {
3378
- next = next.nextSibling;
3237
+ currentBlock.pos = upto;
3238
+ };
3239
+ const skipInline = (upto) => {
3240
+ if (currentBlock && upto > currentBlock.pos) {
3241
+ currentBlock.pos = Math.min(upto, currentBlock.end);
3379
3242
  }
3380
- if (next?.name === "OrderedList") {
3381
- renumberListItems(next.firstChild, last.counter + 1, changes, state2.doc);
3243
+ };
3244
+ const { selection } = state2;
3245
+ for (const range of selection.ranges) {
3246
+ if (range.empty && inline.some((v) => v === null)) {
3247
+ const contextSize = Math.min(range.head, 6);
3248
+ const contextBefore = state2.doc.sliceString(range.head - contextSize, range.head);
3249
+ let contextAfter = state2.doc.sliceString(range.head, range.head + contextSize);
3250
+ for (let i = 0; i < contextSize; i++) {
3251
+ const ch = contextAfter[i];
3252
+ if (ch !== contextBefore[contextBefore.length - 1 - i] || !/[~`*]/.test(ch)) {
3253
+ contextAfter = contextAfter.slice(0, i);
3254
+ break;
3255
+ }
3256
+ }
3257
+ for (let i = 0; i < inline.length; i++) {
3258
+ const mark2 = inlineMarkerText(i);
3259
+ const found = contextAfter.indexOf(mark2);
3260
+ if (found > -1) {
3261
+ contextAfter = contextAfter.slice(0, found) + contextAfter.slice(found + mark2.length);
3262
+ if (inline[i] === null) {
3263
+ inline[i] = true;
3264
+ }
3265
+ }
3266
+ }
3382
3267
  }
3383
- }
3384
- const changeSet = state2.changes(changes);
3385
- dispatch(state2.update({
3386
- changes: changeSet,
3387
- selection: state2.selection.map(changeSet, 1),
3388
- userEvent: "format.list.add",
3389
- scrollIntoView: true
3390
- }));
3391
- return true;
3392
- };
3393
- var removeList = (type) => ({ state: state2, dispatch }) => {
3394
- let lastBlock = -1;
3395
- const changes = [];
3396
- const stack = [];
3397
- const targetNodeType = type === 0 ? "OrderedList" : type === 1 ? "BulletList" : "TaskList";
3398
- for (const { from, to } of state2.selection.ranges) {
3399
- syntaxTree2(state2).iterate({
3400
- from,
3401
- to,
3268
+ syntaxTree(state2).iterate({
3269
+ from: range.from,
3270
+ to: range.to,
3402
3271
  enter: (node) => {
3272
+ advanceInline(node.from);
3403
3273
  const { name } = node;
3404
3274
  if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
3405
3275
  stack.push(name);
3406
- } else if (name === "Task" && stack[stack.length - 1] === "BulletList") {
3407
- stack[stack.length - 1] = "TaskList";
3276
+ } else if (name === "Link") {
3277
+ link = true;
3278
+ } else if (Object.hasOwn(Textblocks, name) && (range.empty || node.to > range.from || node.from < range.to)) {
3279
+ if (name === "Task" && stack[stack.length - 1] === "BulletList") {
3280
+ stack[stack.length - 1] = "TaskList";
3281
+ }
3282
+ const blockCode = Textblocks[name];
3283
+ if (blockType === null) {
3284
+ blockType = blockCode;
3285
+ } else if (blockType !== blockCode) {
3286
+ blockType = false;
3287
+ }
3288
+ if (blockCode !== "codeblock" && inline.some((i) => i !== false)) {
3289
+ currentBlock = {
3290
+ pos: Math.max(range.from, node.from),
3291
+ end: Math.min(range.to, node.to),
3292
+ active: [
3293
+ false,
3294
+ false,
3295
+ false,
3296
+ false
3297
+ ]
3298
+ };
3299
+ }
3300
+ } else if (Object.hasOwn(InlineMarker, name) && currentBlock) {
3301
+ const index = InlineMarker[name];
3302
+ if (range.empty && inline[index] === null) {
3303
+ inline[index] = true;
3304
+ }
3305
+ currentBlock.active[index] = true;
3306
+ } else if (IgnoreInline.has(name)) {
3307
+ skipInline(node.to);
3408
3308
  }
3409
3309
  },
3410
3310
  leave: (node) => {
3311
+ advanceInline(node.to);
3411
3312
  const { name } = node;
3412
3313
  if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
3413
3314
  stack.pop();
3414
- } else if (name === "ListItem" && stack[stack.length - 1] === targetNodeType && node.from !== lastBlock) {
3415
- lastBlock = node.from;
3416
- let line = state2.doc.lineAt(node.from);
3417
- const mark2 = /^\s*(\d+[.)] |[-*+] (\[[ x]\] )?)/.exec(line.text.slice(node.from - line.from));
3418
- if (!mark2) {
3419
- return false;
3420
- }
3421
- const column = node.from - line.from;
3422
- changes.push({
3423
- from: node.from,
3424
- to: node.from + mark2[0].length
3425
- });
3426
- while (line.to < node.to) {
3427
- line = state2.doc.lineAt(line.to + 1);
3428
- const open = /^[\s>]*/.exec(line.text)[0].length;
3429
- if (open > column) {
3430
- changes.push({
3431
- from: line.from + column,
3432
- to: line.from + Math.min(column + mark2[0].length, open)
3433
- });
3315
+ } else if (Object.hasOwn(Textblocks, name)) {
3316
+ let hasList = false;
3317
+ let hasQuote = false;
3318
+ for (let i = stack.length - 1; i >= 0; i--) {
3319
+ if (stack[i] === "Blockquote") {
3320
+ hasQuote = true;
3321
+ } else if (!hasList) {
3322
+ hasList = stack[i] === "TaskList" ? "task" : stack[i] === "BulletList" ? "bullet" : "ordered";
3434
3323
  }
3435
3324
  }
3436
- if (node.to >= to) {
3437
- renumberListItems(node.node.nextSibling, 1, changes, state2.doc);
3325
+ if (blockQuote === null) {
3326
+ blockQuote = hasQuote;
3327
+ } else if (!hasQuote && blockQuote) {
3328
+ blockQuote = false;
3438
3329
  }
3439
- return false;
3330
+ if (listStyle === null) {
3331
+ listStyle = hasList;
3332
+ } else if (listStyle !== hasList) {
3333
+ listStyle = false;
3334
+ }
3335
+ currentBlock = null;
3336
+ } else if (Object.hasOwn(InlineMarker, name) && currentBlock) {
3337
+ currentBlock.active[InlineMarker[name]] = false;
3440
3338
  }
3441
3339
  }
3442
3340
  });
3443
3341
  }
3444
- if (!changes.length) {
3445
- return false;
3446
- }
3447
- dispatch(state2.update({
3448
- changes,
3449
- userEvent: "format.list.remove",
3450
- scrollIntoView: true
3451
- }));
3452
- return true;
3453
- };
3454
- var toggleList = (type) => (target) => {
3455
- const formatting = getFormatting(target.state);
3456
- const active = formatting.listStyle === (type === 1 ? "bullet" : type === 0 ? "ordered" : "task");
3457
- return (active ? removeList(type) : addList(type))(target);
3342
+ const { from, to } = state2.doc.lineAt(selection.main.anchor);
3343
+ const blankLine = from === to;
3344
+ return {
3345
+ blankLine,
3346
+ blockType: blockType || null,
3347
+ blockQuote: blockQuote ?? false,
3348
+ code: inline[3] ?? false,
3349
+ emphasis: inline[1] ?? false,
3350
+ strong: inline[0] ?? false,
3351
+ strikethrough: inline[2] ?? false,
3352
+ link,
3353
+ listStyle: listStyle || null
3354
+ };
3458
3355
  };
3459
- var renumberListItems = (item, counter, changes, doc) => {
3460
- for (; item; item = item.nextSibling) {
3461
- if (item.name === "ListItem") {
3462
- const number = /(\s*)(\d+)[.)]/.exec(doc.sliceString(item.from, item.from + 10));
3463
- if (!number || +number[2] === counter) {
3464
- break;
3465
- }
3466
- const size = number[1].length + number[2].length;
3467
- const newNum = String(counter);
3468
- changes.push({
3469
- from: item.from + Math.max(0, size - newNum.length),
3470
- to: item.from + size,
3471
- insert: newNum
3356
+ var useFormattingState = () => {
3357
+ const [state2, setState] = useState();
3358
+ const observer = useMemo(() => EditorView11.updateListener.of((update2) => {
3359
+ if (update2.docChanged || update2.selectionSet) {
3360
+ setState((prevState) => {
3361
+ const newState = getFormatting(update2.state);
3362
+ if (!prevState || !formattingEquals(prevState, newState)) {
3363
+ return newState;
3364
+ }
3365
+ return prevState;
3472
3366
  });
3473
- counter++;
3474
3367
  }
3475
- }
3368
+ }), [
3369
+ setState
3370
+ ]);
3371
+ return [
3372
+ state2,
3373
+ observer
3374
+ ];
3476
3375
  };
3477
- var setBlockquote = (enable) => ({ state: state2, dispatch }) => {
3478
- const lines = [];
3479
- let lastBlock = -1;
3480
- for (const { from, to } of state2.selection.ranges) {
3481
- const sawBlock = false;
3482
- syntaxTree2(state2).iterate({
3483
- from,
3484
- to,
3485
- enter: (node) => {
3486
- if (Object.hasOwn(Textblocks, node.name) || node.name === "Table") {
3487
- if (node.from === lastBlock) {
3488
- return false;
3489
- }
3490
- lastBlock = node.from;
3491
- let line2 = state2.doc.lineAt(node.from);
3492
- if (line2.number > 1) {
3493
- const prevLine = state2.doc.line(line2.number - 1);
3494
- if (/^[>\s]*$/.test(prevLine.text)) {
3495
- if (!enable || lines.length && lines[lines.length - 1].number === prevLine.number - 1) {
3496
- lines.push(prevLine);
3497
- }
3498
- }
3499
- }
3500
- for (; ; ) {
3501
- lines.push(line2);
3502
- if (line2.to >= node.to) {
3503
- break;
3504
- }
3505
- line2 = state2.doc.line(line2.number + 1);
3506
- }
3507
- if (!enable && line2.number < state2.doc.lines) {
3508
- const nextLine = state2.doc.line(line2.number + 1);
3509
- if (/^[>\s]*$/.test(nextLine.text)) {
3510
- lines.push(nextLine);
3511
- }
3512
- }
3513
- return false;
3514
- }
3515
- }
3516
- });
3517
- let line;
3518
- if (!sawBlock && enable && from === to && !/\S/.test((line = state2.doc.lineAt(from)).text)) {
3519
- lines.push(line);
3520
- }
3376
+
3377
+ // packages/ui/react-ui-editor/src/extensions/markdown/action.ts
3378
+ var processAction = (view, action) => {
3379
+ let inlineType, listType;
3380
+ switch (action.type) {
3381
+ case "heading":
3382
+ setHeading(parseInt(action.data))(view);
3383
+ break;
3384
+ case "strong":
3385
+ case "emphasis":
3386
+ case "strikethrough":
3387
+ case "code":
3388
+ inlineType = action.type === "strong" ? Inline.Strong : action.type === "emphasis" ? Inline.Emphasis : action.type === "strikethrough" ? Inline.Strikethrough : Inline.Code;
3389
+ (typeof action.data === "boolean" ? setStyle(inlineType, action.data) : toggleStyle(inlineType))(view);
3390
+ break;
3391
+ case "list-ordered":
3392
+ case "list-bullet":
3393
+ case "list-task":
3394
+ listType = action.type === "list-ordered" ? List.Ordered : action.type === "list-bullet" ? List.Bullet : List.Task;
3395
+ (action.data === false ? removeList(listType) : action.data === true ? addList(listType) : toggleList(listType))(view);
3396
+ break;
3397
+ case "blockquote":
3398
+ (action.data === false ? removeBlockquote : action.data === true ? addBlockquote : toggleBlockquote)(view);
3399
+ break;
3400
+ case "codeblock":
3401
+ (action.data === false ? removeCodeblock : addCodeblock)(view);
3402
+ break;
3403
+ case "table":
3404
+ insertTable(view);
3405
+ break;
3406
+ case "link":
3407
+ (action.data === false ? removeLink : addLink())(view);
3408
+ break;
3409
+ case "image":
3410
+ addLink({
3411
+ url: action.data,
3412
+ image: true
3413
+ })(view);
3414
+ break;
3415
+ case "comment":
3416
+ createComment(view);
3417
+ break;
3521
3418
  }
3522
- const changes = [];
3523
- for (const line of lines) {
3524
- if (enable) {
3525
- changes.push({
3526
- from: line.from,
3527
- insert: /\S/.test(line.text) ? "> " : ">"
3528
- });
3529
- } else {
3530
- const quote = /((?:[\s>\-+*]|\d+[.)])*?)> ?/.exec(line.text);
3531
- if (quote) {
3532
- changes.push({
3533
- from: line.from + quote[1].length,
3534
- to: line.from + quote[0].length
3535
- });
3536
- }
3419
+ requestAnimationFrame(() => {
3420
+ if (!view.hasFocus) {
3421
+ view.focus();
3422
+ }
3423
+ });
3424
+ };
3425
+
3426
+ // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
3427
+ import { completionKeymap as completionKeymap2 } from "@codemirror/autocomplete";
3428
+ import { defaultKeymap as defaultKeymap2, indentWithTab as indentWithTab2 } from "@codemirror/commands";
3429
+ import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
3430
+ import { defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
3431
+ import { languages } from "@codemirror/language-data";
3432
+ import { lintKeymap } from "@codemirror/lint";
3433
+ import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
3434
+ import { keymap as keymap7 } from "@codemirror/view";
3435
+
3436
+ // packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
3437
+ import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
3438
+ import { HighlightStyle } from "@codemirror/language";
3439
+ import { tags, styleTags, Tag } from "@lezer/highlight";
3440
+ import { Table } from "@lezer/markdown";
3441
+ var markdownTags = {
3442
+ Blockquote: Tag.define(),
3443
+ CodeMark: Tag.define(),
3444
+ CodeText: Tag.define(),
3445
+ EmphasisMark: Tag.define(),
3446
+ HeaderMark: Tag.define(),
3447
+ InlineCode: Tag.define(),
3448
+ LinkLabel: Tag.define(),
3449
+ LinkReference: Tag.define(),
3450
+ ListMark: Tag.define(),
3451
+ QuoteMark: Tag.define(),
3452
+ URL: Tag.define(),
3453
+ // Custom.
3454
+ TableCell: Tag.define()
3455
+ };
3456
+ Table.defineNodes?.forEach((node) => {
3457
+ switch (node?.name) {
3458
+ case "TableCell": {
3459
+ node.style = markdownTags.TableCell;
3460
+ break;
3537
3461
  }
3538
3462
  }
3539
- if (!changes.length) {
3540
- return false;
3463
+ });
3464
+ var markdownTagsExtensions = [
3465
+ Table,
3466
+ {
3467
+ props: [
3468
+ styleTags(markdownTags)
3469
+ ]
3541
3470
  }
3542
- const changeSet = state2.changes(changes);
3543
- dispatch(state2.update({
3544
- changes: changeSet,
3545
- selection: state2.selection.map(changeSet, 1),
3546
- userEvent: enable ? "format.blockquote.add" : "format.blockquote.remove",
3547
- scrollIntoView: true
3548
- }));
3549
- return true;
3550
- };
3551
- var addBlockquote = setBlockquote(true);
3552
- var removeBlockquote = setBlockquote(false);
3553
- var toggleBlockquote = (target) => {
3554
- return (getFormatting(target.state).blockQuote ? removeBlockquote : addBlockquote)(target);
3555
- };
3556
- var addCodeblock = (target) => {
3557
- const { state: state2, dispatch } = target;
3558
- const { selection } = state2;
3559
- if (selection.ranges.length === 1 && selection.main.empty) {
3560
- const { head } = selection.main;
3561
- const line = state2.doc.lineAt(head);
3562
- if (!/\S/.test(line.text) && head === line.from) {
3563
- snippets.codeblock(target, null, line.from, line.to);
3564
- return true;
3471
+ ];
3472
+ var markdownHighlightStyle = (readonly) => {
3473
+ return HighlightStyle.define([
3474
+ {
3475
+ tag: [
3476
+ tags.keyword,
3477
+ tags.name,
3478
+ tags.deleted,
3479
+ tags.character,
3480
+ tags.propertyName,
3481
+ tags.macroName,
3482
+ tags.color,
3483
+ tags.constant(tags.name),
3484
+ tags.standard(tags.name),
3485
+ tags.definition(tags.name),
3486
+ tags.separator,
3487
+ tags.typeName,
3488
+ tags.className,
3489
+ tags.number,
3490
+ tags.changed,
3491
+ tags.annotation,
3492
+ tags.modifier,
3493
+ tags.self,
3494
+ tags.namespace,
3495
+ tags.operator,
3496
+ tags.operatorKeyword,
3497
+ tags.escape,
3498
+ tags.regexp,
3499
+ tags.special(tags.string),
3500
+ tags.meta,
3501
+ tags.comment,
3502
+ tags.atom,
3503
+ tags.bool,
3504
+ tags.special(tags.variableName),
3505
+ tags.processingInstruction,
3506
+ tags.string,
3507
+ tags.inserted,
3508
+ tags.invalid
3509
+ ],
3510
+ color: "inherit !important"
3511
+ },
3512
+ // Markdown marks.
3513
+ {
3514
+ tag: [
3515
+ tags.meta,
3516
+ tags.processingInstruction,
3517
+ markdownTags.LinkLabel,
3518
+ markdownTags.LinkReference,
3519
+ markdownTags.ListMark
3520
+ ],
3521
+ class: mark
3522
+ },
3523
+ // Markdown marks.
3524
+ {
3525
+ tag: [
3526
+ markdownTags.CodeMark,
3527
+ markdownTags.HeaderMark,
3528
+ markdownTags.QuoteMark,
3529
+ markdownTags.EmphasisMark
3530
+ ],
3531
+ class: mark
3532
+ },
3533
+ // E.g., code block language (after ```).
3534
+ {
3535
+ tag: [
3536
+ tags.function(tags.variableName),
3537
+ tags.labelName
3538
+ ],
3539
+ class: codeMark
3540
+ },
3541
+ {
3542
+ tag: [
3543
+ tags.monospace
3544
+ ],
3545
+ class: "font-mono"
3546
+ },
3547
+ // Headings.
3548
+ {
3549
+ tag: tags.heading1,
3550
+ class: heading(1)
3551
+ },
3552
+ {
3553
+ tag: tags.heading2,
3554
+ class: heading(2)
3555
+ },
3556
+ {
3557
+ tag: tags.heading3,
3558
+ class: heading(3)
3559
+ },
3560
+ {
3561
+ tag: tags.heading4,
3562
+ class: heading(4)
3563
+ },
3564
+ {
3565
+ tag: tags.heading5,
3566
+ class: heading(5)
3567
+ },
3568
+ {
3569
+ tag: tags.heading6,
3570
+ class: heading(6)
3571
+ },
3572
+ // Emphasis.
3573
+ {
3574
+ tag: tags.emphasis,
3575
+ class: italic
3576
+ },
3577
+ {
3578
+ tag: tags.strong,
3579
+ class: bold
3580
+ },
3581
+ {
3582
+ tag: tags.strikethrough,
3583
+ class: strikethrough
3584
+ },
3585
+ // Naked URLs.
3586
+ {
3587
+ tag: [
3588
+ markdownTags.URL
3589
+ ],
3590
+ class: inlineUrl
3591
+ },
3592
+ // NOTE: The `markdown` extension configures extensions for `lezer` to parse markdown tokens (incl. below).
3593
+ // However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
3594
+ // when a language is specified. In this case, the syntax highlighting extensions will colorize
3595
+ // the code, but all other CSS properties will be inherited.
3596
+ // IMPORTANT: Therefore, the fenced code block will use the base editor font unless changed by an extension.
3597
+ {
3598
+ tag: [
3599
+ markdownTags.CodeText,
3600
+ markdownTags.InlineCode
3601
+ ],
3602
+ class: code
3603
+ },
3604
+ {
3605
+ tag: [
3606
+ markdownTags.QuoteMark
3607
+ ],
3608
+ class: blockquote
3609
+ },
3610
+ {
3611
+ tag: [
3612
+ markdownTags.TableCell
3613
+ ],
3614
+ class: "font-mono"
3565
3615
  }
3566
- }
3567
- const ranges = [];
3568
- for (const { from, to } of selection.ranges) {
3569
- let blockFrom = from;
3570
- let blockTo = to;
3571
- syntaxTree2(state2).iterate({
3572
- from,
3573
- to,
3574
- enter: (node) => {
3575
- if (Object.hasOwn(Textblocks, node.name)) {
3576
- if (from >= node.from && to <= node.to) {
3577
- blockFrom = node.from;
3578
- blockTo = node.to;
3579
- } else {
3580
- blockFrom = Math.min(blockFrom, state2.doc.lineAt(node.from).from);
3581
- blockTo = Math.max(blockTo, state2.doc.lineAt(node.to).to);
3582
- }
3583
- }
3584
- }
3585
- });
3586
- if (ranges.length && ranges[ranges.length - 1].to >= blockFrom - 1) {
3587
- ranges[ranges.length - 1].to = blockTo;
3588
- } else {
3589
- ranges.push({
3590
- from: blockFrom,
3591
- to: blockTo
3592
- });
3616
+ ], {
3617
+ scope: markdownLanguage2,
3618
+ all: {
3619
+ fontFamily: getToken("fontFamily.body", []).join(",")
3593
3620
  }
3621
+ });
3622
+ };
3623
+
3624
+ // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
3625
+ var createMarkdownExtensions = ({ themeMode } = {}) => {
3626
+ return [
3627
+ // Main extension.
3628
+ // https://github.com/codemirror/lang-markdown
3629
+ // https://codemirror.net/5/mode/markdown/index.html (demo).
3630
+ markdown({
3631
+ // GRM by default (vs strict CommonMark):
3632
+ // Table, TaskList, Strikethrough, and Autolink.
3633
+ // NOTE: This extends the parser; it doesn't affect rendering.
3634
+ // https://github.github.com/gfm
3635
+ // https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
3636
+ base: markdownLanguage3,
3637
+ // Languages for syntax highlighting fenced code blocks.
3638
+ codeLanguages: languages,
3639
+ // Parser extensions.
3640
+ extensions: [
3641
+ // GFM provided by default.
3642
+ markdownTagsExtensions
3643
+ ]
3644
+ }),
3645
+ // https://github.com/codemirror/theme-one-dark
3646
+ themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle),
3647
+ // Custom styles.
3648
+ syntaxHighlighting(markdownHighlightStyle()),
3649
+ keymap7.of([
3650
+ // https://codemirror.net/docs/ref/#commands.indentWithTab
3651
+ indentWithTab2,
3652
+ // https://codemirror.net/docs/ref/#commands.defaultKeymap
3653
+ ...defaultKeymap2,
3654
+ ...completionKeymap2,
3655
+ ...lintKeymap
3656
+ ])
3657
+ ];
3658
+ };
3659
+
3660
+ // packages/ui/react-ui-editor/src/extensions/markdown/decorate.ts
3661
+ import { syntaxTree as syntaxTree2 } from "@codemirror/language";
3662
+ import { RangeSetBuilder as RangeSetBuilder2, StateEffect as StateEffect4 } from "@codemirror/state";
3663
+ import { EditorView as EditorView12, Decoration as Decoration5, WidgetType as WidgetType3, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
3664
+ import { mx as mx2 } from "@dxos/react-ui-theme";
3665
+ var HorizontalRuleWidget = class extends WidgetType3 {
3666
+ toDOM() {
3667
+ const el = document.createElement("span");
3668
+ el.className = "cm-hr";
3669
+ return el;
3594
3670
  }
3595
- if (!ranges.length) {
3596
- return false;
3671
+ };
3672
+ var LinkButton = class extends WidgetType3 {
3673
+ constructor(url, render) {
3674
+ super();
3675
+ this.url = url;
3676
+ this.render = render;
3677
+ }
3678
+ eq(other) {
3679
+ return this.url === other.url;
3680
+ }
3681
+ toDOM(view) {
3682
+ const el = document.createElement("span");
3683
+ this.render(el, this.url);
3684
+ return el;
3597
3685
  }
3598
- const changes = ranges.map(({ from, to }) => {
3599
- const column = from - state2.doc.lineAt(from).from;
3600
- return [
3601
- {
3602
- from,
3603
- insert: "```\n" + " ".repeat(column)
3604
- },
3605
- {
3606
- from: to,
3607
- insert: "\n" + " ".repeat(column) + "```"
3608
- }
3609
- ];
3610
- });
3611
- dispatch(state2.update({
3612
- changes,
3613
- userEvent: "format.codeblock.add",
3614
- scrollIntoView: true
3615
- }));
3616
- return true;
3617
3686
  };
3618
- var removeCodeblock = ({ state: state2, dispatch }) => {
3619
- const changes = [];
3620
- let lastBlock = -1;
3621
- for (const { from, to } of state2.selection.ranges) {
3622
- syntaxTree2(state2).iterate({
3623
- from,
3624
- to,
3625
- enter: (node) => {
3626
- if (Textblocks[node.name] === "codeblock" && lastBlock !== node.from) {
3627
- lastBlock = node.from;
3628
- const firstLine = state2.doc.lineAt(node.from);
3629
- if (node.name === "FencedCode") {
3630
- changes.push({
3631
- from: node.from,
3632
- to: firstLine.to + 1 + node.from - firstLine.from
3633
- });
3634
- const lastLine = state2.doc.lineAt(node.to);
3635
- if (/^([\s>]|[-*+] |\d+[).])*`+$/.test(lastLine.text)) {
3636
- changes.push({
3637
- from: lastLine.from - (lastLine.number === firstLine.number + 1 ? 0 : 1),
3638
- to: lastLine.to
3639
- });
3640
- }
3641
- } else {
3642
- const column = node.from - firstLine.from;
3643
- for (let line = firstLine; ; line = state2.doc.line(line.number + 1)) {
3644
- changes.push({
3645
- from: line.from + column - 4,
3646
- to: line.from + column
3647
- });
3648
- if (line.to >= node.to) {
3649
- break;
3650
- }
3687
+ var CheckboxWidget = class extends WidgetType3 {
3688
+ constructor(_checked) {
3689
+ super();
3690
+ this._checked = _checked;
3691
+ }
3692
+ eq(other) {
3693
+ return this._checked === other._checked;
3694
+ }
3695
+ toDOM(view) {
3696
+ const input = document.createElement("input");
3697
+ input.className = "cm-task-checkbox ch-checkbox ch-focus-ring -mbs-0.5";
3698
+ input.type = "checkbox";
3699
+ input.checked = this._checked;
3700
+ if (view.state.readOnly) {
3701
+ input.setAttribute("disabled", "true");
3702
+ } else {
3703
+ input.onmousedown = (event) => {
3704
+ const pos = view.posAtDOM(input);
3705
+ const text = view.state.sliceDoc(pos, pos + 3);
3706
+ if (text === (this._checked ? "[x]" : "[ ]")) {
3707
+ view.dispatch({
3708
+ changes: {
3709
+ from: pos + 1,
3710
+ to: pos + 2,
3711
+ insert: this._checked ? " " : "x"
3651
3712
  }
3652
- }
3713
+ });
3714
+ event.preventDefault();
3653
3715
  }
3654
- }
3655
- });
3716
+ };
3717
+ }
3718
+ return input;
3656
3719
  }
3657
- if (!changes.length) {
3720
+ ignoreEvent() {
3658
3721
  return false;
3659
3722
  }
3660
- dispatch(state2.update({
3661
- changes,
3662
- userEvent: "format.codeblock.remove",
3663
- scrollIntoView: true
3664
- }));
3665
- return true;
3666
- };
3667
- var toggleCodeblock = (target) => {
3668
- return (getFormatting(target.state).blockType === "codeblock" ? removeCodeblock : addCodeblock)(target);
3669
- };
3670
- var formattingKeymap = (options = {}) => {
3671
- return [
3672
- keymap6.of([
3673
- {
3674
- key: "meta-b",
3675
- run: toggleStrong
3676
- }
3677
- ])
3678
- ];
3679
3723
  };
3680
- var InlineMarker = {
3681
- Emphasis: 1,
3682
- StrongEmphasis: 0,
3683
- InlineCode: 3,
3684
- Strikethrough: 2
3724
+ var hide = Decoration5.replace({});
3725
+ var fencedCodeLine = Decoration5.line({
3726
+ class: mx2("cm-code cm-codeblock-line")
3727
+ });
3728
+ var fencedCodeLineFirst = Decoration5.line({
3729
+ class: mx2("cm-code cm-codeblock-line", "cm-codeblock-first")
3730
+ });
3731
+ var fencedCodeLineLast = Decoration5.line({
3732
+ class: mx2("cm-code cm-codeblock-line", "cm-codeblock-last")
3733
+ });
3734
+ var horizontalRule = Decoration5.replace({
3735
+ widget: new HorizontalRuleWidget()
3736
+ });
3737
+ var checkedTask = Decoration5.replace({
3738
+ widget: new CheckboxWidget(true)
3739
+ });
3740
+ var uncheckedTask = Decoration5.replace({
3741
+ widget: new CheckboxWidget(false)
3742
+ });
3743
+ var editingRange = (state2, range, focus) => {
3744
+ const { readOnly, selection: { main: { head } } } = state2;
3745
+ return focus && !readOnly && head >= range.from && head <= range.to;
3685
3746
  };
3686
- var IgnoreInline = /* @__PURE__ */ new Set([
3687
- "Autolink",
3747
+ var MarksByParent = /* @__PURE__ */ new Set([
3688
3748
  "CodeMark",
3689
- "CodeText",
3690
- "Comment",
3691
3749
  "EmphasisMark",
3692
- "Hardbreak",
3693
- "HeaderMark",
3694
- "HTMLTag",
3695
- "LinkMark",
3696
- "ListMark",
3697
- "ProcessingInstruction",
3698
- "QuoteMark",
3699
3750
  "StrikethroughMark",
3700
3751
  "SubscriptMark",
3701
- "SuperscriptMark",
3702
- "TaskMarker"
3752
+ "SuperscriptMark"
3703
3753
  ]);
3704
- var Textblocks = {
3705
- ATXHeading1: "heading1",
3706
- ATXHeading2: "heading2",
3707
- ATXHeading3: "heading3",
3708
- ATXHeading4: "heading4",
3709
- ATXHeading5: "heading5",
3710
- ATXHeading6: "heading6",
3711
- CodeBlock: "codeblock",
3712
- FencedCode: "codeblock",
3713
- Paragraph: "paragraph",
3714
- SetextHeading1: "heading1",
3715
- SetextHeading2: "heading2",
3716
- TableCell: "tablecell",
3717
- Task: "paragraph"
3718
- };
3719
- var getFormatting = (state2) => {
3720
- let blockType = null;
3721
- const inline = [
3722
- null,
3723
- null,
3724
- null,
3725
- null
3726
- ];
3727
- let link = false;
3728
- let blockQuote = null;
3729
- let listStyle = null;
3730
- const stack = [];
3731
- let currentBlock = null;
3732
- const advanceInline = (upto) => {
3733
- if (!currentBlock) {
3734
- return;
3735
- }
3736
- upto = Math.min(upto, currentBlock.end);
3737
- if (upto <= currentBlock.pos) {
3738
- return;
3739
- }
3740
- for (let i = 0; i < currentBlock.active.length; i++) {
3741
- if (inline[i] === false) {
3742
- continue;
3743
- } else if (currentBlock.active[i]) {
3744
- inline[i] = true;
3745
- } else if (/\S/.test(state2.doc.sliceString(currentBlock.pos, upto))) {
3746
- inline[i] = false;
3747
- }
3748
- }
3749
- currentBlock.pos = upto;
3750
- };
3751
- const skipInline = (upto) => {
3752
- if (currentBlock && upto > currentBlock.pos) {
3753
- currentBlock.pos = Math.min(upto, currentBlock.end);
3754
- }
3755
- };
3756
- const { selection } = state2;
3757
- for (const range of selection.ranges) {
3758
- if (range.empty && inline.some((v) => v === null)) {
3759
- const contextSize = Math.min(range.head, 6);
3760
- const contextBefore = state2.doc.sliceString(range.head - contextSize, range.head);
3761
- let contextAfter = state2.doc.sliceString(range.head, range.head + contextSize);
3762
- for (let i = 0; i < contextSize; i++) {
3763
- const ch = contextAfter[i];
3764
- if (ch !== contextBefore[contextBefore.length - 1 - i] || !/[~`*]/.test(ch)) {
3765
- contextAfter = contextAfter.slice(0, i);
3766
- break;
3767
- }
3768
- }
3769
- for (let i = 0; i < inline.length; i++) {
3770
- const mark2 = inlineMarkerText(i);
3771
- const found = contextAfter.indexOf(mark2);
3772
- if (found > -1) {
3773
- contextAfter = contextAfter.slice(0, found) + contextAfter.slice(found + mark2.length);
3774
- if (inline[i] === null) {
3775
- inline[i] = true;
3776
- }
3777
- }
3778
- }
3779
- }
3780
- syntaxTree2(state2).iterate({
3781
- from: range.from,
3782
- to: range.to,
3754
+ var buildDecorations = (view, options, focus) => {
3755
+ const deco = new RangeSetBuilder2();
3756
+ const atomicDeco = new RangeSetBuilder2();
3757
+ const { state: state2 } = view;
3758
+ for (const { from, to } of view.visibleRanges) {
3759
+ syntaxTree2(state2).iterate({
3760
+ from,
3761
+ to,
3783
3762
  enter: (node) => {
3784
- advanceInline(node.from);
3785
- const { name } = node;
3786
- if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
3787
- stack.push(name);
3788
- } else if (name === "Link") {
3789
- link = true;
3790
- } else if (Object.hasOwn(Textblocks, name) && (range.empty || node.to > range.from || node.from < range.to)) {
3791
- if (name === "Task" && stack[stack.length - 1] === "BulletList") {
3792
- stack[stack.length - 1] = "TaskList";
3793
- }
3794
- const blockCode = Textblocks[name];
3795
- if (blockType === null) {
3796
- blockType = blockCode;
3797
- } else if (blockType !== blockCode) {
3798
- blockType = false;
3763
+ if (node.name === "FencedCode") {
3764
+ const editing = editingRange(state2, node, focus);
3765
+ for (const block of view.viewportLineBlocks) {
3766
+ if (block.to < node.from) {
3767
+ continue;
3768
+ }
3769
+ if (block.from > node.to) {
3770
+ break;
3771
+ }
3772
+ const first = block.from <= node.from;
3773
+ const last = block.to >= node.to && /^(\s>)*```$/.test(state2.doc.sliceString(block.from, block.to));
3774
+ deco.add(block.from, block.from, first ? fencedCodeLineFirst : last ? fencedCodeLineLast : fencedCodeLine);
3775
+ if (!editing && (first || last)) {
3776
+ atomicDeco.add(block.from, block.to, hide);
3777
+ }
3799
3778
  }
3800
- if (blockCode !== "codeblock" && inline.some((i) => i !== false)) {
3801
- currentBlock = {
3802
- pos: Math.max(range.from, node.from),
3803
- end: Math.min(range.to, node.to),
3804
- active: [
3805
- false,
3806
- false,
3807
- false,
3808
- false
3809
- ]
3810
- };
3779
+ return false;
3780
+ } else if (node.name === "Link") {
3781
+ const marks = node.node.getChildren("LinkMark");
3782
+ const urlNode = node.node.getChild("URL");
3783
+ const editing = editingRange(state2, node, focus);
3784
+ if (urlNode && marks.length >= 2) {
3785
+ const url = state2.sliceDoc(urlNode.from, urlNode.to);
3786
+ if (!editing) {
3787
+ atomicDeco.add(node.from, marks[0].to, hide);
3788
+ }
3789
+ deco.add(marks[0].to, marks[1].from, Decoration5.mark({
3790
+ tagName: "a",
3791
+ attributes: {
3792
+ class: "cm-link",
3793
+ href: url,
3794
+ rel: "noreferrer",
3795
+ target: "_blank"
3796
+ }
3797
+ }));
3798
+ if (!editing) {
3799
+ atomicDeco.add(marks[1].from, node.to, options.renderLinkButton ? Decoration5.replace({
3800
+ widget: new LinkButton(url, options.renderLinkButton)
3801
+ }) : hide);
3802
+ }
3811
3803
  }
3812
- } else if (Object.hasOwn(InlineMarker, name) && currentBlock) {
3813
- const index = InlineMarker[name];
3814
- if (range.empty && inline[index] === null) {
3815
- inline[index] = true;
3804
+ } else if (node.name === "HeaderMark") {
3805
+ const parent = node.node.parent;
3806
+ if (/^ATX/.test(parent.name) && !editingRange(state2, state2.doc.lineAt(node.from), focus)) {
3807
+ const next = state2.doc.sliceString(node.to, node.to + 1);
3808
+ atomicDeco.add(node.from, node.to + (next === " " ? 1 : 0), hide);
3816
3809
  }
3817
- currentBlock.active[index] = true;
3818
- } else if (IgnoreInline.has(name)) {
3819
- skipInline(node.to);
3820
- }
3821
- },
3822
- leave: (node) => {
3823
- advanceInline(node.to);
3824
- const { name } = node;
3825
- if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
3826
- stack.pop();
3827
- } else if (Object.hasOwn(Textblocks, name)) {
3828
- let hasList = false;
3829
- let hasQuote = false;
3830
- for (let i = stack.length - 1; i >= 0; i--) {
3831
- if (stack[i] === "Blockquote") {
3832
- hasQuote = true;
3833
- } else if (!hasList) {
3834
- hasList = stack[i] === "TaskList" ? "task" : stack[i] === "BulletList" ? "bullet" : "ordered";
3835
- }
3810
+ } else if (node.name === "HorizontalRule") {
3811
+ if (!editingRange(state2, node, focus)) {
3812
+ deco.add(node.from, node.to, horizontalRule);
3836
3813
  }
3837
- if (blockQuote === null) {
3838
- blockQuote = hasQuote;
3839
- } else if (!hasQuote && blockQuote) {
3840
- blockQuote = false;
3814
+ } else if (node.name === "TaskMarker") {
3815
+ if (!editingRange(state2, node, focus)) {
3816
+ const checked = state2.doc.sliceString(node.from + 1, node.to - 1) === "x";
3817
+ atomicDeco.add(node.from - 2, node.from - 1, Decoration5.mark({
3818
+ class: "cm-task"
3819
+ }));
3820
+ atomicDeco.add(node.from, node.to, checked ? checkedTask : uncheckedTask);
3841
3821
  }
3842
- if (listStyle === null) {
3843
- listStyle = hasList;
3844
- } else if (listStyle !== hasList) {
3845
- listStyle = false;
3822
+ } else if (MarksByParent.has(node.name)) {
3823
+ if (!editingRange(state2, node.node.parent, focus)) {
3824
+ atomicDeco.add(node.from, node.to, hide);
3846
3825
  }
3847
- currentBlock = null;
3848
- } else if (Object.hasOwn(InlineMarker, name) && currentBlock) {
3849
- currentBlock.active[InlineMarker[name]] = false;
3850
3826
  }
3851
3827
  }
3852
3828
  });
3853
3829
  }
3854
- const { from, to } = state2.doc.lineAt(selection.main.anchor);
3855
- const blankLine = from === to;
3856
3830
  return {
3857
- blankLine,
3858
- blockType: blockType || null,
3859
- blockQuote: blockQuote ?? false,
3860
- code: inline[3] ?? false,
3861
- emphasis: inline[1] ?? false,
3862
- strong: inline[0] ?? false,
3863
- strikethrough: inline[2] ?? false,
3864
- link,
3865
- listStyle: listStyle || null
3831
+ deco: deco.finish(),
3832
+ atomicDeco: atomicDeco.finish()
3866
3833
  };
3867
3834
  };
3868
- var useFormattingState = () => {
3869
- const [state2, setState, stateRef] = useStateRef();
3870
- const observer = useMemo(() => EditorView13.updateListener.of((update2) => {
3871
- if (update2.docChanged || update2.selectionSet) {
3872
- const newState = getFormatting(update2.state);
3873
- if (!stateRef.current || !formattingEquals(stateRef.current, newState)) {
3874
- setState(newState);
3875
- }
3876
- }
3877
- }), []);
3835
+ var forceUpdate = StateEffect4.define();
3836
+ var decorateMarkdown = (options = {}) => {
3878
3837
  return [
3879
- state2,
3880
- observer
3838
+ ViewPlugin4.fromClass(class {
3839
+ constructor(view) {
3840
+ ({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations(view, options, view.hasFocus));
3841
+ }
3842
+ update(update2) {
3843
+ if (update2.docChanged || update2.viewportChanged || update2.focusChanged || update2.transactions.some((tr) => tr.effects.some((e) => e.is(forceUpdate))) || update2.selectionSet && !options.selectionChangeDelay) {
3844
+ ({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations(update2.view, options, update2.view.hasFocus));
3845
+ this.clearUpdate();
3846
+ } else if (update2.selectionSet) {
3847
+ this.scheduleUpdate(update2.view);
3848
+ }
3849
+ }
3850
+ // TODO(burdon): BUG: If the cursor is at the end of a link at the end of a line,
3851
+ // the cursor will float in space or be in the wrong position after the decoration is applied.
3852
+ scheduleUpdate(view) {
3853
+ this.clearUpdate();
3854
+ this.pendingUpdate = setTimeout(() => {
3855
+ view.dispatch({
3856
+ effects: forceUpdate.of(null)
3857
+ });
3858
+ }, options.selectionChangeDelay);
3859
+ }
3860
+ clearUpdate() {
3861
+ if (this.pendingUpdate) {
3862
+ clearTimeout(this.pendingUpdate);
3863
+ this.pendingUpdate = void 0;
3864
+ }
3865
+ }
3866
+ destroy() {
3867
+ this.clearUpdate();
3868
+ }
3869
+ }, {
3870
+ provide: (plugin) => [
3871
+ EditorView12.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration5.none),
3872
+ EditorView12.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration5.none),
3873
+ EditorView12.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration5.none)
3874
+ ]
3875
+ }),
3876
+ formattingStyles
3881
3877
  ];
3882
3878
  };
3879
+ var formattingStyles = EditorView12.baseTheme({
3880
+ "& .cm-code": {
3881
+ fontFamily: getToken("fontFamily.mono", []).join(",")
3882
+ },
3883
+ "& .cm-codeblock-line": {
3884
+ paddingInline: "1rem !important"
3885
+ },
3886
+ "& .cm-codeblock-end": {
3887
+ display: "inline-block",
3888
+ width: "100%",
3889
+ position: "relative",
3890
+ "&::after": {
3891
+ position: "absolute",
3892
+ inset: 0,
3893
+ content: '""'
3894
+ }
3895
+ },
3896
+ "& .cm-codeblock-first": {
3897
+ borderTopLeftRadius: ".5rem",
3898
+ borderTopRightRadius: ".5rem"
3899
+ },
3900
+ "& .cm-codeblock-last": {
3901
+ borderBottomLeftRadius: ".5rem",
3902
+ borderBottomRightRadius: ".5rem"
3903
+ },
3904
+ "&light .cm-codeblock-line, &light .cm-activeLine.cm-codeblock-line": {
3905
+ background: getToken("extend.semanticColors.input.light"),
3906
+ mixBlendMode: "darken"
3907
+ },
3908
+ "&dark .cm-codeblock-line, &dark .cm-activeLine.cm-codeblock-line": {
3909
+ background: getToken("extend.semanticColors.input.dark"),
3910
+ mixBlendMode: "lighten"
3911
+ },
3912
+ "& .cm-hr": {
3913
+ display: "inline-block",
3914
+ width: "100%",
3915
+ height: "0",
3916
+ verticalAlign: "middle",
3917
+ borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
3918
+ },
3919
+ "& .cm-task": {
3920
+ color: getToken("extend.colors.blue.500")
3921
+ },
3922
+ "& .cm-task-checkbox": {
3923
+ marginLeft: "4px",
3924
+ marginRight: "4px"
3925
+ }
3926
+ });
3883
3927
 
3884
3928
  // packages/ui/react-ui-editor/src/extensions/markdown/image.ts
3885
3929
  import { syntaxTree as syntaxTree3 } from "@codemirror/language";
3886
3930
  import { StateField as StateField5 } from "@codemirror/state";
3887
- import { Decoration as Decoration6, EditorView as EditorView14, WidgetType as WidgetType4 } from "@codemirror/view";
3931
+ import { Decoration as Decoration6, EditorView as EditorView13, WidgetType as WidgetType4 } from "@codemirror/view";
3888
3932
  var image = (options = {}) => {
3889
3933
  return StateField5.define({
3890
3934
  create: (state2) => {
@@ -3911,7 +3955,7 @@ var image = (options = {}) => {
3911
3955
  add: buildDecorations2(from, to, tr.state)
3912
3956
  });
3913
3957
  },
3914
- provide: (field) => EditorView14.decorations.from(field)
3958
+ provide: (field) => EditorView13.decorations.from(field)
3915
3959
  });
3916
3960
  };
3917
3961
  var preloaded = /* @__PURE__ */ new Set();
@@ -4001,12 +4045,12 @@ var linkTooltip = (render) => hoverTooltip2((view, pos, side) => {
4001
4045
  // packages/ui/react-ui-editor/src/extensions/markdown/table.ts
4002
4046
  import { syntaxTree as syntaxTree5 } from "@codemirror/language";
4003
4047
  import { RangeSetBuilder as RangeSetBuilder3, StateField as StateField6 } from "@codemirror/state";
4004
- import { Decoration as Decoration7, EditorView as EditorView15, WidgetType as WidgetType5 } from "@codemirror/view";
4048
+ import { Decoration as Decoration7, EditorView as EditorView14, WidgetType as WidgetType5 } from "@codemirror/view";
4005
4049
  var table = (options = {}) => {
4006
4050
  return StateField6.define({
4007
4051
  create: (state2) => update(state2, options),
4008
4052
  update: (_, tr) => update(tr.state, options),
4009
- provide: (field) => EditorView15.decorations.from(field)
4053
+ provide: (field) => EditorView14.decorations.from(field)
4010
4054
  });
4011
4055
  };
4012
4056
  var update = (state2, options) => {
@@ -4100,8 +4144,8 @@ var TableWidget = class extends WidgetType5 {
4100
4144
 
4101
4145
  // packages/ui/react-ui-editor/src/extensions/mention.ts
4102
4146
  import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
4103
- import { log as log8 } from "@dxos/log";
4104
- var __dxlog_file10 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/mention.ts";
4147
+ import { log as log6 } from "@dxos/log";
4148
+ var __dxlog_file8 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/mention.ts";
4105
4149
  var mention = ({ onSearch }) => {
4106
4150
  return autocompletion2({
4107
4151
  // TODO(burdon): Not working.
@@ -4113,10 +4157,10 @@ var mention = ({ onSearch }) => {
4113
4157
  icons: false,
4114
4158
  override: [
4115
4159
  (context) => {
4116
- log8.info("completion context", {
4160
+ log6.info("completion context", {
4117
4161
  context
4118
4162
  }, {
4119
- F: __dxlog_file10,
4163
+ F: __dxlog_file8,
4120
4164
  L: 26,
4121
4165
  S: void 0,
4122
4166
  C: (f, a) => f(...a)
@@ -4138,21 +4182,30 @@ var mention = ({ onSearch }) => {
4138
4182
 
4139
4183
  // packages/ui/react-ui-editor/src/extensions/modes.ts
4140
4184
  import { Facet as Facet6 } from "@codemirror/state";
4141
- import { keymap as keymap7 } from "@codemirror/view";
4185
+ import { keymap as keymap8 } from "@codemirror/view";
4142
4186
  import { vim } from "@replit/codemirror-vim";
4187
+ import { vscodeKeymap } from "@replit/codemirror-vscode-keymap";
4143
4188
  var focusEvent = "focus.container";
4144
4189
  var editorMode = Facet6.define({
4145
4190
  combine: (modes) => modes[0] ?? {}
4146
4191
  });
4147
4192
  var EditorModes = {
4148
4193
  default: [],
4194
+ vscode: [
4195
+ // https://github.com/replit/codemirror-vscode-keymap
4196
+ editorMode.of({
4197
+ type: "vscode"
4198
+ }),
4199
+ keymap8.of(vscodeKeymap)
4200
+ ],
4149
4201
  vim: [
4202
+ // https://github.com/replit/codemirror-vim
4150
4203
  vim(),
4151
4204
  editorMode.of({
4152
4205
  type: "vim",
4153
4206
  noTabster: true
4154
4207
  }),
4155
- keymap7.of([
4208
+ keymap8.of([
4156
4209
  {
4157
4210
  key: "Alt-Escape",
4158
4211
  run: (view) => {
@@ -4167,18 +4220,18 @@ var EditorModes = {
4167
4220
  };
4168
4221
 
4169
4222
  // packages/ui/react-ui-editor/src/extensions/state.ts
4170
- import { Transaction as Transaction2 } from "@codemirror/state";
4171
- import { EditorView as EditorView16, keymap as keymap8 } from "@codemirror/view";
4223
+ import { Transaction } from "@codemirror/state";
4224
+ import { EditorView as EditorView15, keymap as keymap9 } from "@codemirror/view";
4172
4225
  import { debounce as debounce2 } from "@dxos/async";
4173
4226
  import { invariant as invariant4 } from "@dxos/invariant";
4174
4227
  import { isNotFalsy as isNotFalsy3 } from "@dxos/util";
4175
- var __dxlog_file11 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/state.ts";
4228
+ var __dxlog_file9 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/state.ts";
4176
4229
  var scrollAnnotation = "dxos.org/cm/scrolling";
4177
4230
  var keyPrefix = "dxos.org/react-ui-editor/state";
4178
4231
  var localStorageStateStoreAdapter = {
4179
4232
  setState: (id, state2) => {
4180
4233
  invariant4(id, void 0, {
4181
- F: __dxlog_file11,
4234
+ F: __dxlog_file9,
4182
4235
  L: 35,
4183
4236
  S: void 0,
4184
4237
  A: [
@@ -4190,7 +4243,7 @@ var localStorageStateStoreAdapter = {
4190
4243
  },
4191
4244
  getState: (id) => {
4192
4245
  invariant4(id, void 0, {
4193
- F: __dxlog_file11,
4246
+ F: __dxlog_file9,
4194
4247
  L: 39,
4195
4248
  S: void 0,
4196
4249
  A: [
@@ -4206,7 +4259,7 @@ var state = ({ getState, setState } = {}) => {
4206
4259
  const setStateDebounced = debounce2(setState, 1e3);
4207
4260
  return [
4208
4261
  // TODO(burdon): Track scrolling (currently only updates when cursor moves).
4209
- EditorView16.updateListener.of(({ view, changes, transactions }) => {
4262
+ EditorView15.updateListener.of(({ view, changes, transactions }) => {
4210
4263
  const id = view.state.facet(documentId2);
4211
4264
  if (!id || transactions.some((tr) => tr.isUserEvent(scrollAnnotation))) {
4212
4265
  return;
@@ -4232,18 +4285,18 @@ var state = ({ getState, setState } = {}) => {
4232
4285
  }
4233
4286
  }
4234
4287
  }),
4235
- getState && keymap8.of([
4288
+ getState && keymap9.of([
4236
4289
  {
4237
4290
  key: "ctrl-r",
4238
4291
  run: (view) => {
4239
4292
  const state2 = getState(view.state.facet(documentId2));
4240
4293
  if (state2) {
4241
4294
  view.dispatch({
4242
- effects: EditorView16.scrollIntoView(state2.scrollTo.from, {
4295
+ effects: EditorView15.scrollIntoView(state2.scrollTo.from, {
4243
4296
  yMargin: 0
4244
4297
  }),
4245
4298
  selection: state2.selection,
4246
- annotations: Transaction2.userEvent.of(scrollAnnotation)
4299
+ annotations: Transaction.userEvent.of(scrollAnnotation)
4247
4300
  });
4248
4301
  }
4249
4302
  return true;
@@ -4254,7 +4307,7 @@ var state = ({ getState, setState } = {}) => {
4254
4307
  };
4255
4308
 
4256
4309
  // packages/ui/react-ui-editor/src/extensions/typewriter.ts
4257
- import { keymap as keymap9 } from "@codemirror/view";
4310
+ import { keymap as keymap10 } from "@codemirror/view";
4258
4311
  var defaultItems = [
4259
4312
  "hello world!",
4260
4313
  "this is a test.",
@@ -4264,7 +4317,7 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
4264
4317
  let t;
4265
4318
  let idx = 0;
4266
4319
  return [
4267
- keymap9.of([
4320
+ keymap10.of([
4268
4321
  {
4269
4322
  // Reset.
4270
4323
  key: "alt-meta-'",
@@ -4311,17 +4364,17 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
4311
4364
  };
4312
4365
 
4313
4366
  // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
4314
- var __dxlog_file12 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
4367
+ var __dxlog_file10 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
4315
4368
  var instanceCount = 0;
4316
- var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, className, autoFocus, scrollTo = EditorView17.scrollIntoView(0, {
4369
+ var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, className, autoFocus, scrollTo = EditorView16.scrollIntoView(0, {
4317
4370
  yMargin: 0
4318
4371
  }), moveToEndOfLine, debug, dataTestId }, forwardedRef) => {
4319
- const [instanceId] = useState(() => `text-editor-${++instanceCount}`);
4372
+ const [instanceId] = useState2(() => `text-editor-${++instanceCount}`);
4320
4373
  const tabsterDOMAttribute = useFocusableGroup({
4321
4374
  tabBehavior: "limited"
4322
4375
  });
4323
4376
  const rootRef = useRef(null);
4324
- const [view, setView] = useState(null);
4377
+ const [view, setView] = useState2(null);
4325
4378
  useImperativeHandle(forwardedRef, () => view, [
4326
4379
  view
4327
4380
  ]);
@@ -4334,11 +4387,11 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, c
4334
4387
  autoFocus
4335
4388
  ]);
4336
4389
  useEffect2(() => {
4337
- log9("create", {
4390
+ log7("create", {
4338
4391
  id,
4339
4392
  instanceId
4340
4393
  }, {
4341
- F: __dxlog_file12,
4394
+ F: __dxlog_file10,
4342
4395
  L: 88,
4343
4396
  S: void 0,
4344
4397
  C: (f, a) => f(...a)
@@ -4349,16 +4402,16 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, c
4349
4402
  extensions: [
4350
4403
  id && documentId2.of(id),
4351
4404
  // TODO(burdon): NOTE: Doesn't catch errors in keymap functions.
4352
- EditorView17.exceptionSink.of((err) => {
4353
- log9.catch(err, void 0, {
4354
- F: __dxlog_file12,
4405
+ EditorView16.exceptionSink.of((err) => {
4406
+ log7.catch(err, void 0, {
4407
+ F: __dxlog_file10,
4355
4408
  L: 101,
4356
4409
  S: void 0,
4357
4410
  C: (f, a) => f(...a)
4358
4411
  });
4359
4412
  }),
4360
4413
  // Focus.
4361
- EditorView17.updateListener.of((update2) => {
4414
+ EditorView16.updateListener.of((update2) => {
4362
4415
  update2.transactions.forEach((transaction) => {
4363
4416
  if (transaction.isUserEvent(focusEvent)) {
4364
4417
  rootRef.current?.focus();
@@ -4368,7 +4421,7 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, c
4368
4421
  extensions
4369
4422
  ].filter(isNotFalsy4)
4370
4423
  });
4371
- const view2 = new EditorView17({
4424
+ const view2 = new EditorView16({
4372
4425
  state: state2,
4373
4426
  parent: rootRef.current,
4374
4427
  scrollTo,
@@ -4394,11 +4447,11 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, c
4394
4447
  }
4395
4448
  setView(view2);
4396
4449
  return () => {
4397
- log9("destroy", {
4450
+ log7("destroy", {
4398
4451
  id,
4399
4452
  instanceId
4400
4453
  }, {
4401
- F: __dxlog_file12,
4454
+ F: __dxlog_file10,
4402
4455
  L: 150,
4403
4456
  S: void 0,
4404
4457
  C: (f, a) => f(...a)
@@ -4435,7 +4488,7 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, c
4435
4488
  // packages/ui/react-ui-editor/src/components/Toolbar/Toolbar.tsx
4436
4489
  import { ChatText, Code, CodeBlock, Image, Link, ListBullets, ListChecks, ListNumbers, Paragraph, Quotes, TextStrikethrough, Table as Table2, TextB, TextHOne, TextHTwo, TextHThree, TextHFour, TextHFive, TextHSix, TextItalic } from "@phosphor-icons/react";
4437
4490
  import { createContext } from "@radix-ui/react-context";
4438
- import React2, { useEffect as useEffect3, useRef as useRef2, useState as useState2 } from "react";
4491
+ import React2, { useEffect as useEffect3, useRef as useRef2, useState as useState3 } from "react";
4439
4492
  import { useDropzone } from "react-dropzone";
4440
4493
  import { DensityProvider, ElevationProvider, Select, Toolbar as NaturalToolbar, Tooltip, useTranslation } from "@dxos/react-ui";
4441
4494
  import { getSize } from "@dxos/react-ui-theme";
@@ -4508,8 +4561,8 @@ var MarkdownHeading = () => {
4508
4561
  const value = header ? header[1] : blockType === "paragraph" || !blockType ? "0" : void 0;
4509
4562
  const HeadingIcon = HeadingIcons[value ?? "0"];
4510
4563
  const suppressNextTooltip = useRef2(false);
4511
- const [tooltipOpen, setTooltipOpen] = useState2(false);
4512
- const [selectOpen, setSelectOpen] = useState2(false);
4564
+ const [tooltipOpen, setTooltipOpen] = useState3(false);
4565
+ const [selectOpen, setSelectOpen] = useState3(false);
4513
4566
  return /* @__PURE__ */ React2.createElement(Tooltip.Root, {
4514
4567
  open: tooltipOpen,
4515
4568
  onOpenChange: (nextOpen) => {
@@ -4704,7 +4757,7 @@ var MarkdownCustom = ({ onUpload } = {}) => {
4704
4757
  });
4705
4758
  useEffect3(() => {
4706
4759
  if (onUpload && acceptedFiles.length) {
4707
- setTimeout(async () => {
4760
+ requestAnimationFrame(async () => {
4708
4761
  const f = acceptedFiles[0];
4709
4762
  const file = new File([
4710
4763
  f
@@ -4753,56 +4806,7 @@ var Toolbar = {
4753
4806
 
4754
4807
  // packages/ui/react-ui-editor/src/hooks/useActionHandler.ts
4755
4808
  var useActionHandler = (view) => {
4756
- return (action) => {
4757
- if (!view) {
4758
- return;
4759
- }
4760
- let inlineType, listType;
4761
- switch (action.type) {
4762
- case "heading":
4763
- setHeading(parseInt(action.data))(view);
4764
- break;
4765
- case "strong":
4766
- case "emphasis":
4767
- case "strikethrough":
4768
- case "code":
4769
- inlineType = action.type === "strong" ? Inline.Strong : action.type === "emphasis" ? Inline.Emphasis : action.type === "strikethrough" ? Inline.Strikethrough : Inline.Code;
4770
- (typeof action.data === "boolean" ? setStyle(inlineType, action.data) : toggleStyle(inlineType))(view);
4771
- break;
4772
- case "list-ordered":
4773
- case "list-bullet":
4774
- case "list-task":
4775
- listType = action.type === "list-ordered" ? List.Ordered : action.type === "list-bullet" ? List.Bullet : List.Task;
4776
- (action.data === false ? removeList(listType) : action.data === true ? addList(listType) : toggleList(listType))(view);
4777
- break;
4778
- case "blockquote":
4779
- (action.data === false ? removeBlockquote : action.data === true ? addBlockquote : toggleBlockquote)(view);
4780
- break;
4781
- case "codeblock":
4782
- (action.data === false ? removeCodeblock : addCodeblock)(view);
4783
- break;
4784
- case "table":
4785
- insertTable(view);
4786
- break;
4787
- case "link":
4788
- (action.data === false ? removeLink : addLink())(view);
4789
- break;
4790
- case "image":
4791
- addLink({
4792
- url: action.data,
4793
- image: true
4794
- })(view);
4795
- break;
4796
- case "comment":
4797
- createComment(view);
4798
- break;
4799
- }
4800
- setTimeout(() => {
4801
- if (!view.hasFocus) {
4802
- view.focus();
4803
- }
4804
- });
4805
- };
4809
+ return (action) => view && processAction(view, action);
4806
4810
  };
4807
4811
 
4808
4812
  // packages/ui/react-ui-editor/src/hooks/useDocAccessor.ts
@@ -4820,23 +4824,23 @@ var useDocAccessor = (text) => {
4820
4824
 
4821
4825
  // packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
4822
4826
  import { EditorSelection as EditorSelection2, EditorState as EditorState3 } from "@codemirror/state";
4823
- import { EditorView as EditorView18 } from "@codemirror/view";
4824
- import { useEffect as useEffect4, useMemo as useMemo3, useRef as useRef3, useState as useState3 } from "react";
4825
- import { log as log10 } from "@dxos/log";
4827
+ import { EditorView as EditorView17 } from "@codemirror/view";
4828
+ import { useEffect as useEffect4, useMemo as useMemo3, useRef as useRef3, useState as useState4 } from "react";
4829
+ import { log as log8 } from "@dxos/log";
4826
4830
  import { isNotFalsy as isNotFalsy5 } from "@dxos/util";
4827
- var __dxlog_file13 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
4831
+ var __dxlog_file11 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
4828
4832
  var useTextEditor = (cb = () => ({}), deps = []) => {
4829
4833
  let { id, doc, selection, extensions, autoFocus, scrollTo, debug } = useMemo3(cb, deps ?? []);
4830
4834
  const onUpdate = useRef3();
4831
- const [view, setView] = useState3();
4835
+ const [view, setView] = useState4();
4832
4836
  const parentRef = useRef3(null);
4833
4837
  useEffect4(() => {
4834
4838
  let view2;
4835
4839
  if (parentRef.current) {
4836
- log10("create", {
4840
+ log8("create", {
4837
4841
  id
4838
4842
  }, {
4839
- F: __dxlog_file13,
4843
+ F: __dxlog_file11,
4840
4844
  L: 36,
4841
4845
  S: void 0,
4842
4846
  C: (f, a) => f(...a)
@@ -4847,21 +4851,21 @@ var useTextEditor = (cb = () => ({}), deps = []) => {
4847
4851
  extensions: [
4848
4852
  id && documentId2.of(id),
4849
4853
  // TODO(burdon): Doesn't catch errors in keymap functions.
4850
- EditorView18.exceptionSink.of((err) => {
4851
- log10.catch(err, void 0, {
4852
- F: __dxlog_file13,
4854
+ EditorView17.exceptionSink.of((err) => {
4855
+ log8.catch(err, void 0, {
4856
+ F: __dxlog_file11,
4853
4857
  L: 46,
4854
4858
  S: void 0,
4855
4859
  C: (f, a) => f(...a)
4856
4860
  });
4857
4861
  }),
4858
4862
  extensions,
4859
- EditorView18.updateListener.of(() => {
4863
+ EditorView17.updateListener.of(() => {
4860
4864
  onUpdate.current?.();
4861
4865
  })
4862
4866
  ].filter(isNotFalsy5)
4863
4867
  });
4864
- view2 = new EditorView18({
4868
+ view2 = new EditorView17({
4865
4869
  parent: parentRef.current,
4866
4870
  scrollTo,
4867
4871
  state: state2,
@@ -4877,10 +4881,10 @@ var useTextEditor = (cb = () => ({}), deps = []) => {
4877
4881
  setView(view2);
4878
4882
  }
4879
4883
  return () => {
4880
- log10("destroy", {
4884
+ log8("destroy", {
4881
4885
  id
4882
4886
  }, {
4883
- F: __dxlog_file13,
4887
+ F: __dxlog_file11,
4884
4888
  L: 74,
4885
4889
  S: void 0,
4886
4890
  C: (f, a) => f(...a)
@@ -4952,12 +4956,11 @@ export {
4952
4956
  createDataExtensions,
4953
4957
  createMarkdownExtensions,
4954
4958
  createThemeExtensions,
4955
- cursorLineMargin,
4956
4959
  decorateMarkdown,
4957
4960
  defaultOptions,
4958
4961
  defaultTheme,
4959
- dnd,
4960
4962
  documentId2 as documentId,
4963
+ dropFile,
4961
4964
  editorFillLayoutEditor,
4962
4965
  editorFillLayoutRoot,
4963
4966
  editorMode,
@@ -4971,7 +4974,7 @@ export {
4971
4974
  image,
4972
4975
  imageUpload,
4973
4976
  insertTable,
4974
- keymap10 as keymap,
4977
+ keymap11 as keymap,
4975
4978
  linkTooltip,
4976
4979
  listener,
4977
4980
  localStorageStateStoreAdapter,
@@ -4980,6 +4983,7 @@ export {
4980
4983
  markdownTags,
4981
4984
  markdownTagsExtensions,
4982
4985
  mention,
4986
+ processAction,
4983
4987
  removeBlockquote,
4984
4988
  removeCodeblock,
4985
4989
  removeLink,