@dxos/react-ui-editor 0.4.8-main.46f461d → 0.4.8-main.49cea32

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 (31) hide show
  1. package/dist/lib/browser/index.mjs +1289 -1328
  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 +2 -1
  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/index.d.ts +1 -0
  16. package/dist/types/src/extensions/markdown/index.d.ts.map +1 -1
  17. package/dist/types/src/hooks/useActionHandler.d.ts +2 -2
  18. package/dist/types/src/hooks/useActionHandler.d.ts.map +1 -1
  19. package/package.json +24 -24
  20. package/src/components/TextEditor/TextEditor.stories.tsx +14 -2
  21. package/src/components/Toolbar/Toolbar.tsx +2 -26
  22. package/src/extensions/command/state.ts +2 -2
  23. package/src/extensions/dnd.ts +31 -9
  24. package/src/extensions/factories.ts +19 -16
  25. package/src/extensions/index.ts +0 -1
  26. package/src/extensions/markdown/action.ts +112 -0
  27. package/src/extensions/markdown/index.ts +1 -0
  28. package/src/hooks/useActionHandler.ts +4 -89
  29. package/dist/types/src/extensions/cursor-line-margin.d.ts +0 -7
  30. package/dist/types/src/extensions/cursor-line-margin.d.ts.map +0 -1
  31. package/src/extensions/cursor-line-margin.ts +0 -94
@@ -31,10 +31,10 @@ 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
36
  import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useRef, useState as useState2 } from "react";
37
- import { log as log9 } from "@dxos/log";
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);
@@ -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,34 +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
1910
  import { closeBrackets, closeBracketsKeymap } from "@codemirror/autocomplete";
1956
- import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
1911
+ import { defaultKeymap, history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
1957
1912
  import { bracketMatching } from "@codemirror/language";
1958
1913
  import { searchKeymap } from "@codemirror/search";
1959
1914
  import { EditorState } from "@codemirror/state";
1960
- import { EditorView as EditorView10, crosshairCursor, drawSelection, dropCursor, highlightActiveLine, highlightSpecialChars, keymap as keymap5, lineNumbers, placeholder, scrollPastEnd } from "@codemirror/view";
1915
+ import { EditorView as EditorView9, drawSelection, dropCursor as dropCursor2, highlightActiveLine, keymap as keymap5, lineNumbers, placeholder, scrollPastEnd } from "@codemirror/view";
1961
1916
  import defaultsDeep2 from "lodash.defaultsdeep";
1962
1917
  import { generateName } from "@dxos/display-name";
1963
- import { log as log7 } from "@dxos/log";
1918
+ import { log as log5 } from "@dxos/log";
1964
1919
  import { hueTokens } from "@dxos/react-ui-theme";
1965
1920
  import { hexToHue, isNotFalsy as isNotFalsy2 } from "@dxos/util";
1966
1921
 
@@ -2208,25 +2163,32 @@ var defaultTheme = {
2208
2163
  };
2209
2164
 
2210
2165
  // packages/ui/react-ui-editor/src/extensions/factories.ts
2211
- var __dxlog_file9 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/factories.ts";
2212
- var defaults = {
2166
+ var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/factories.ts";
2167
+ var defaultBasicOptions = {
2213
2168
  allowMultipleSelections: true,
2214
2169
  bracketMatching: true,
2215
2170
  closeBrackets: true,
2216
2171
  drawSelection: true,
2217
2172
  editable: true,
2218
2173
  history: true,
2174
+ keymap: "standard",
2219
2175
  lineWrapping: true,
2220
2176
  search: true
2221
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
2183
+ };
2222
2184
  var createBasicExtensions = (_props) => {
2223
- const props = defaultsDeep2({}, _props, defaults);
2185
+ const props = defaultsDeep2({}, _props, defaultBasicOptions);
2224
2186
  return [
2225
- // TODO(burdon): Doesn't catch errors in keymap functions.
2226
- EditorView10.exceptionSink.of((err) => {
2227
- log7.catch(err, void 0, {
2228
- F: __dxlog_file9,
2229
- L: 83,
2187
+ // NOTE: Doesn't catch errors in keymap functions.
2188
+ EditorView9.exceptionSink.of((err) => {
2189
+ log5.catch(err, void 0, {
2190
+ F: __dxlog_file7,
2191
+ L: 91,
2230
2192
  S: void 0,
2231
2193
  C: (f, a) => f(...a)
2232
2194
  });
@@ -2234,27 +2196,26 @@ var createBasicExtensions = (_props) => {
2234
2196
  props.allowMultipleSelections && EditorState.allowMultipleSelections.of(true),
2235
2197
  props.bracketMatching && bracketMatching(),
2236
2198
  props.closeBrackets && closeBrackets(),
2237
- props.crosshairCursor && crosshairCursor(),
2238
- props.dropCursor && dropCursor(),
2199
+ props.dropCursor && dropCursor2(),
2239
2200
  props.drawSelection && drawSelection(),
2240
2201
  props.highlightActiveLine && highlightActiveLine(),
2241
- highlightSpecialChars(),
2242
2202
  props.history && history(),
2243
2203
  props.lineNumbers && lineNumbers(),
2244
- props.lineWrapping && EditorView10.lineWrapping,
2204
+ props.lineWrapping && EditorView9.lineWrapping,
2245
2205
  props.placeholder && placeholder(props.placeholder),
2246
2206
  props.readonly && [
2247
2207
  EditorState.readOnly.of(true),
2248
- EditorView10.editable.of(false)
2208
+ EditorView9.editable.of(false)
2249
2209
  ],
2250
2210
  props.scrollPastEnd && scrollPastEnd(),
2251
2211
  props.tabSize && EditorState.tabSize.of(props.tabSize),
2252
2212
  // https://codemirror.net/docs/ref/#view.KeyBinding
2253
2213
  keymap5.of([
2254
- // https://codemirror.net/docs/ref/#commands.standardKeymap
2255
- ...standardKeymap,
2214
+ ...(props.keymap && keymaps[props.keymap]) ?? [],
2256
2215
  // https://codemirror.net/docs/ref/#commands.indentWithTab
2257
- props.indentWithTab && indentWithTab,
2216
+ ...props.indentWithTab ? [
2217
+ indentWithTab
2218
+ ] : [],
2258
2219
  // https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
2259
2220
  ...props.closeBrackets ? closeBracketsKeymap : [],
2260
2221
  // https://codemirror.net/docs/ref/#commands.historyKeymap
@@ -2264,21 +2225,21 @@ var createBasicExtensions = (_props) => {
2264
2225
  ].filter(isNotFalsy2))
2265
2226
  ].filter(isNotFalsy2);
2266
2227
  };
2267
- var defaultSlots = {
2228
+ var defaultThemeSlots = {
2268
2229
  editor: {
2269
2230
  className: "w-full bs-full"
2270
2231
  }
2271
2232
  };
2272
2233
  var createThemeExtensions = ({ theme, themeMode, slots: _slots } = {}) => {
2273
- const slots = defaultsDeep2({}, _slots, defaultSlots);
2234
+ const slots = defaultsDeep2({}, _slots, defaultThemeSlots);
2274
2235
  return [
2275
- EditorView10.baseTheme(defaultTheme),
2276
- EditorView10.darkTheme.of(themeMode === "dark"),
2277
- theme && EditorView10.theme(theme),
2278
- slots.editor?.className && EditorView10.editorAttributes.of({
2236
+ EditorView9.baseTheme(defaultTheme),
2237
+ EditorView9.darkTheme.of(themeMode === "dark"),
2238
+ theme && EditorView9.theme(theme),
2239
+ slots.editor?.className && EditorView9.editorAttributes.of({
2279
2240
  class: slots.editor.className
2280
2241
  }),
2281
- slots.content?.className && EditorView10.contentAttributes.of({
2242
+ slots.content?.className && EditorView9.contentAttributes.of({
2282
2243
  class: slots.content.className
2283
2244
  })
2284
2245
  ].filter(isNotFalsy2);
@@ -2306,917 +2267,415 @@ var createDataExtensions = ({ id, text, space, identity }) => {
2306
2267
  };
2307
2268
 
2308
2269
  // packages/ui/react-ui-editor/src/extensions/listener.ts
2309
- import { EditorView as EditorView11 } from "@codemirror/view";
2270
+ import { EditorView as EditorView10 } from "@codemirror/view";
2310
2271
  var listener = ({ onFocus, onChange }) => {
2311
2272
  const extensions = [];
2312
- onFocus && extensions.push(EditorView11.focusChangeEffect.of((_, focusing) => {
2273
+ onFocus && extensions.push(EditorView10.focusChangeEffect.of((_, focusing) => {
2313
2274
  onFocus(focusing);
2314
2275
  return null;
2315
2276
  }));
2316
- onChange && extensions.push(EditorView11.updateListener.of((update2) => {
2277
+ onChange && extensions.push(EditorView10.updateListener.of((update2) => {
2317
2278
  onChange(update2.state.doc.toString());
2318
2279
  }));
2319
2280
  return extensions;
2320
2281
  };
2321
2282
 
2322
- // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
2323
- import { completionKeymap as completionKeymap2 } from "@codemirror/autocomplete";
2324
- import { defaultKeymap, indentWithTab as indentWithTab2 } from "@codemirror/commands";
2325
- import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
2326
- import { defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
2327
- import { languages } from "@codemirror/language-data";
2328
- import { lintKeymap } from "@codemirror/lint";
2329
- import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
2330
- import { keymap as keymap6 } from "@codemirror/view";
2331
-
2332
- // packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
2333
- import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
2334
- import { HighlightStyle } from "@codemirror/language";
2335
- import { tags, styleTags, Tag } from "@lezer/highlight";
2336
- import { Table } from "@lezer/markdown";
2337
- var markdownTags = {
2338
- Blockquote: Tag.define(),
2339
- CodeMark: Tag.define(),
2340
- CodeText: Tag.define(),
2341
- EmphasisMark: Tag.define(),
2342
- HeaderMark: Tag.define(),
2343
- InlineCode: Tag.define(),
2344
- LinkLabel: Tag.define(),
2345
- LinkReference: Tag.define(),
2346
- ListMark: Tag.define(),
2347
- QuoteMark: Tag.define(),
2348
- URL: Tag.define(),
2349
- // Custom.
2350
- TableCell: Tag.define()
2351
- };
2352
- Table.defineNodes?.forEach((node) => {
2353
- switch (node?.name) {
2354
- case "TableCell": {
2355
- node.style = markdownTags.TableCell;
2356
- break;
2283
+ // packages/ui/react-ui-editor/src/extensions/markdown/formatting.ts
2284
+ import { snippet } from "@codemirror/autocomplete";
2285
+ import { syntaxTree } from "@codemirror/language";
2286
+ import { EditorSelection } from "@codemirror/state";
2287
+ import { EditorView as EditorView11, keymap as keymap6 } from "@codemirror/view";
2288
+ import { useMemo, useState } from "react";
2289
+ 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;
2290
+ var Inline;
2291
+ (function(Inline2) {
2292
+ Inline2[Inline2["Strong"] = 0] = "Strong";
2293
+ Inline2[Inline2["Emphasis"] = 1] = "Emphasis";
2294
+ Inline2[Inline2["Strikethrough"] = 2] = "Strikethrough";
2295
+ Inline2[Inline2["Code"] = 3] = "Code";
2296
+ })(Inline || (Inline = {}));
2297
+ var List;
2298
+ (function(List2) {
2299
+ List2[List2["Ordered"] = 0] = "Ordered";
2300
+ List2[List2["Bullet"] = 1] = "Bullet";
2301
+ List2[List2["Task"] = 2] = "Task";
2302
+ })(List || (List = {}));
2303
+ var setHeading = (level) => ({ state: state2, dispatch }) => {
2304
+ const { selection: { ranges }, doc } = state2;
2305
+ const changes = [];
2306
+ let prevBlock = -1;
2307
+ for (const range of ranges) {
2308
+ let sawBlock = false;
2309
+ syntaxTree(state2).iterate({
2310
+ from: range.from,
2311
+ to: range.to,
2312
+ enter: (node) => {
2313
+ if (!Object.hasOwn(Textblocks, node.name) || prevBlock === node.from) {
2314
+ return;
2315
+ }
2316
+ sawBlock = true;
2317
+ prevBlock = node.from;
2318
+ const blockType = Textblocks[node.name];
2319
+ const isHeading = /heading(\d)/.exec(blockType);
2320
+ const curLevel = isHeading ? +isHeading[1] : node.name === "Paragraph" ? 0 : -1;
2321
+ if (curLevel < 0 || curLevel === level) {
2322
+ return;
2323
+ }
2324
+ if (curLevel === 0) {
2325
+ changes.push({
2326
+ from: node.from,
2327
+ insert: "#".repeat(level) + " "
2328
+ });
2329
+ } else if (node.name === "SetextHeading1" || node.name === "SetextHeading2") {
2330
+ const nextLine = doc.lineAt(node.to);
2331
+ if (level) {
2332
+ changes.push({
2333
+ from: node.from,
2334
+ insert: "#".repeat(level) + " "
2335
+ });
2336
+ }
2337
+ changes.push({
2338
+ from: nextLine.from - 1,
2339
+ to: nextLine.to
2340
+ });
2341
+ } else {
2342
+ if (level === 0) {
2343
+ changes.push({
2344
+ from: node.from,
2345
+ to: Math.min(node.to, node.from + curLevel + 1)
2346
+ });
2347
+ } else if (level < curLevel) {
2348
+ changes.push({
2349
+ from: node.from,
2350
+ to: node.from + (curLevel - level)
2351
+ });
2352
+ } else {
2353
+ changes.push({
2354
+ from: node.from,
2355
+ insert: "#".repeat(level - curLevel)
2356
+ });
2357
+ }
2358
+ }
2359
+ }
2360
+ });
2361
+ let line;
2362
+ if (!sawBlock && range.empty && level > 0 && !/\S/.test((line = state2.doc.lineAt(range.from)).text)) {
2363
+ changes.push({
2364
+ from: line.from,
2365
+ to: line.to,
2366
+ insert: "#".repeat(level) + " "
2367
+ });
2357
2368
  }
2358
2369
  }
2359
- });
2360
- var markdownTagsExtensions = [
2361
- Table,
2362
- {
2363
- props: [
2364
- styleTags(markdownTags)
2365
- ]
2366
- }
2367
- ];
2368
- var markdownHighlightStyle = (readonly) => {
2369
- return HighlightStyle.define([
2370
- {
2371
- tag: [
2372
- tags.keyword,
2373
- tags.name,
2374
- tags.deleted,
2375
- tags.character,
2376
- tags.propertyName,
2377
- tags.macroName,
2378
- tags.color,
2379
- tags.constant(tags.name),
2380
- tags.standard(tags.name),
2381
- tags.definition(tags.name),
2382
- tags.separator,
2383
- tags.typeName,
2384
- tags.className,
2385
- tags.number,
2386
- tags.changed,
2387
- tags.annotation,
2388
- tags.modifier,
2389
- tags.self,
2390
- tags.namespace,
2391
- tags.operator,
2392
- tags.operatorKeyword,
2393
- tags.escape,
2394
- tags.regexp,
2395
- tags.special(tags.string),
2396
- tags.meta,
2397
- tags.comment,
2398
- tags.atom,
2399
- tags.bool,
2400
- tags.special(tags.variableName),
2401
- tags.processingInstruction,
2402
- tags.string,
2403
- tags.inserted,
2404
- tags.invalid
2405
- ],
2406
- color: "inherit !important"
2407
- },
2408
- // Markdown marks.
2409
- {
2410
- tag: [
2411
- tags.meta,
2412
- tags.processingInstruction,
2413
- markdownTags.LinkLabel,
2414
- markdownTags.LinkReference,
2415
- markdownTags.ListMark
2416
- ],
2417
- class: mark
2418
- },
2419
- // Markdown marks.
2420
- {
2421
- tag: [
2422
- markdownTags.CodeMark,
2423
- markdownTags.HeaderMark,
2424
- markdownTags.QuoteMark,
2425
- markdownTags.EmphasisMark
2426
- ],
2427
- class: mark
2428
- },
2429
- // E.g., code block language (after ```).
2430
- {
2431
- tag: [
2432
- tags.function(tags.variableName),
2433
- tags.labelName
2434
- ],
2435
- class: codeMark
2436
- },
2437
- {
2438
- tag: [
2439
- tags.monospace
2440
- ],
2441
- class: "font-mono"
2442
- },
2443
- // Headings.
2444
- {
2445
- tag: tags.heading1,
2446
- class: heading(1)
2447
- },
2448
- {
2449
- tag: tags.heading2,
2450
- class: heading(2)
2451
- },
2452
- {
2453
- tag: tags.heading3,
2454
- class: heading(3)
2455
- },
2456
- {
2457
- tag: tags.heading4,
2458
- class: heading(4)
2459
- },
2460
- {
2461
- tag: tags.heading5,
2462
- class: heading(5)
2463
- },
2464
- {
2465
- tag: tags.heading6,
2466
- class: heading(6)
2467
- },
2468
- // Emphasis.
2469
- {
2470
- tag: tags.emphasis,
2471
- class: italic
2472
- },
2473
- {
2474
- tag: tags.strong,
2475
- class: bold
2476
- },
2477
- {
2478
- tag: tags.strikethrough,
2479
- class: strikethrough
2480
- },
2481
- // Naked URLs.
2482
- {
2483
- tag: [
2484
- markdownTags.URL
2485
- ],
2486
- class: inlineUrl
2487
- },
2488
- // NOTE: The `markdown` extension configures extensions for `lezer` to parse markdown tokens (incl. below).
2489
- // However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
2490
- // when a language is specified. In this case, the syntax highlighting extensions will colorize
2491
- // the code, but all other CSS properties will be inherited.
2492
- // IMPORTANT: Therefore, the fenced code block will use the base editor font unless changed by an extension.
2493
- {
2494
- tag: [
2495
- markdownTags.CodeText,
2496
- markdownTags.InlineCode
2497
- ],
2498
- class: code
2499
- },
2500
- {
2501
- tag: [
2502
- markdownTags.QuoteMark
2503
- ],
2504
- class: blockquote
2505
- },
2506
- {
2507
- tag: [
2508
- markdownTags.TableCell
2509
- ],
2510
- class: "font-mono"
2511
- }
2512
- ], {
2513
- scope: markdownLanguage2,
2514
- all: {
2515
- fontFamily: getToken("fontFamily.body", []).join(",")
2516
- }
2517
- });
2518
- };
2519
-
2520
- // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
2521
- var createMarkdownExtensions = ({ themeMode } = {}) => {
2522
- return [
2523
- // Main extension.
2524
- // https://github.com/codemirror/lang-markdown
2525
- // https://codemirror.net/5/mode/markdown/index.html (demo).
2526
- markdown({
2527
- // GRM by default (vs strict CommonMark):
2528
- // Table, TaskList, Strikethrough, and Autolink.
2529
- // NOTE: This extends the parser; it doesn't affect rendering.
2530
- // https://github.github.com/gfm
2531
- // https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
2532
- base: markdownLanguage3,
2533
- // Languages for syntax highlighting fenced code blocks.
2534
- codeLanguages: languages,
2535
- // Parser extensions.
2536
- extensions: [
2537
- // GFM provided by default.
2538
- markdownTagsExtensions
2539
- ]
2540
- }),
2541
- // https://github.com/codemirror/theme-one-dark
2542
- themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle),
2543
- // Custom styles.
2544
- syntaxHighlighting(markdownHighlightStyle()),
2545
- keymap6.of([
2546
- // https://codemirror.net/docs/ref/#commands.indentWithTab
2547
- indentWithTab2,
2548
- // https://codemirror.net/docs/ref/#commands.defaultKeymap
2549
- ...defaultKeymap,
2550
- ...completionKeymap2,
2551
- ...lintKeymap
2552
- ])
2553
- ];
2554
- };
2555
-
2556
- // packages/ui/react-ui-editor/src/extensions/markdown/decorate.ts
2557
- import { syntaxTree } from "@codemirror/language";
2558
- import { RangeSetBuilder as RangeSetBuilder2, StateEffect as StateEffect4 } from "@codemirror/state";
2559
- import { EditorView as EditorView12, Decoration as Decoration5, WidgetType as WidgetType3, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
2560
- import { mx as mx2 } from "@dxos/react-ui-theme";
2561
- var HorizontalRuleWidget = class extends WidgetType3 {
2562
- toDOM() {
2563
- const el = document.createElement("span");
2564
- el.className = "cm-hr";
2565
- return el;
2566
- }
2567
- };
2568
- var LinkButton = class extends WidgetType3 {
2569
- constructor(url, render) {
2570
- super();
2571
- this.url = url;
2572
- this.render = render;
2573
- }
2574
- eq(other) {
2575
- return this.url === other.url;
2576
- }
2577
- toDOM(view) {
2578
- const el = document.createElement("span");
2579
- this.render(el, this.url);
2580
- return el;
2370
+ if (!changes.length) {
2371
+ return false;
2581
2372
  }
2373
+ const changeSet = state2.changes(changes);
2374
+ dispatch(state2.update({
2375
+ changes: changeSet,
2376
+ selection: state2.selection.map(changeSet, 1),
2377
+ userEvent: "format.setHeading",
2378
+ scrollIntoView: true
2379
+ }));
2380
+ return true;
2582
2381
  };
2583
- var CheckboxWidget = class extends WidgetType3 {
2584
- constructor(_checked) {
2585
- super();
2586
- this._checked = _checked;
2587
- }
2588
- eq(other) {
2589
- return this._checked === other._checked;
2590
- }
2591
- toDOM(view) {
2592
- const input = document.createElement("input");
2593
- input.className = "cm-task-checkbox ch-checkbox ch-focus-ring -mbs-0.5";
2594
- input.type = "checkbox";
2595
- input.checked = this._checked;
2596
- if (view.state.readOnly) {
2597
- input.setAttribute("disabled", "true");
2598
- } else {
2599
- input.onmousedown = (event) => {
2600
- const pos = view.posAtDOM(input);
2601
- const text = view.state.sliceDoc(pos, pos + 3);
2602
- if (text === (this._checked ? "[x]" : "[ ]")) {
2603
- view.dispatch({
2604
- changes: {
2605
- from: pos + 1,
2606
- to: pos + 2,
2607
- insert: this._checked ? " " : "x"
2608
- }
2609
- });
2610
- event.preventDefault();
2382
+ var setStyle = (type, enable) => ({ state: state2, dispatch }) => {
2383
+ const marker = inlineMarkerText(type);
2384
+ const changes = state2.changeByRange((range) => {
2385
+ if (!enable && range.empty) {
2386
+ const after = state2.doc.sliceString(range.head, range.head + 6);
2387
+ const found = after.indexOf(marker);
2388
+ if (found >= 0 && /^[*~`]*$/.test(after.slice(0, found))) {
2389
+ const before = state2.doc.sliceString(range.head - 6, range.head);
2390
+ if (before.slice(before.length - found - marker.length, before.length - found) === marker && [
2391
+ ...before.slice(before.length - found)
2392
+ ].reverse().join("") === after.slice(0, found)) {
2393
+ return {
2394
+ changes: [
2395
+ {
2396
+ from: range.head - marker.length - found,
2397
+ to: range.head - found
2398
+ },
2399
+ {
2400
+ from: range.head + found,
2401
+ to: range.head + found + marker.length
2402
+ }
2403
+ ],
2404
+ range: EditorSelection.cursor(range.from - marker.length)
2405
+ };
2611
2406
  }
2612
- };
2407
+ }
2613
2408
  }
2614
- return input;
2615
- }
2616
- ignoreEvent() {
2617
- return false;
2618
- }
2619
- };
2620
- var hide = Decoration5.replace({});
2621
- var fencedCodeLine = Decoration5.line({
2622
- class: mx2("cm-code cm-codeblock-line")
2623
- });
2624
- var fencedCodeLineFirst = Decoration5.line({
2625
- class: mx2("cm-code cm-codeblock-line", "cm-codeblock-first")
2626
- });
2627
- var fencedCodeLineLast = Decoration5.line({
2628
- class: mx2("cm-code cm-codeblock-line", "cm-codeblock-last")
2629
- });
2630
- var horizontalRule = Decoration5.replace({
2631
- widget: new HorizontalRuleWidget()
2632
- });
2633
- var checkedTask = Decoration5.replace({
2634
- widget: new CheckboxWidget(true)
2635
- });
2636
- var uncheckedTask = Decoration5.replace({
2637
- widget: new CheckboxWidget(false)
2638
- });
2639
- var editingRange = (state2, range, focus) => {
2640
- const { readOnly, selection: { main: { head } } } = state2;
2641
- return focus && !readOnly && head >= range.from && head <= range.to;
2642
- };
2643
- var MarksByParent = /* @__PURE__ */ new Set([
2644
- "CodeMark",
2645
- "EmphasisMark",
2646
- "StrikethroughMark",
2647
- "SubscriptMark",
2648
- "SuperscriptMark"
2649
- ]);
2650
- var buildDecorations = (view, options, focus) => {
2651
- const deco = new RangeSetBuilder2();
2652
- const atomicDeco = new RangeSetBuilder2();
2653
- const { state: state2 } = view;
2654
- for (const { from, to } of view.visibleRanges) {
2409
+ const changes2 = [];
2410
+ const changesAtEnd = [];
2411
+ let blockStart = -1;
2412
+ let blockEnd = -1;
2413
+ let startCovered = false;
2414
+ let endCovered = false;
2415
+ let { from, to } = range;
2655
2416
  syntaxTree(state2).iterate({
2656
2417
  from,
2657
2418
  to,
2658
2419
  enter: (node) => {
2659
- if (node.name === "FencedCode") {
2660
- const editing = editingRange(state2, node, focus);
2661
- for (const block of view.viewportLineBlocks) {
2662
- if (block.to < node.from) {
2663
- continue;
2664
- }
2665
- if (block.from > node.to) {
2666
- break;
2667
- }
2668
- const first = block.from <= node.from;
2669
- const last = block.to >= node.to && /^(\s>)*```$/.test(state2.doc.sliceString(block.from, block.to));
2670
- deco.add(block.from, block.from, first ? fencedCodeLineFirst : last ? fencedCodeLineLast : fencedCodeLine);
2671
- if (!editing && (first || last)) {
2672
- atomicDeco.add(block.from, block.to, hide);
2673
- }
2420
+ const { name } = node;
2421
+ if (Object.hasOwn(Textblocks, name) && Textblocks[name] !== "codeblock") {
2422
+ blockStart = blockContentStart(node);
2423
+ blockEnd = blockContentEnd(node, state2.doc);
2424
+ startCovered = endCovered = false;
2425
+ } else if (name === "Link" || name === "Image" && enable) {
2426
+ if (from < node.from && to > node.from && to <= node.to) {
2427
+ to = node.to;
2428
+ } else if (to > node.to && from >= node.from && from < node.to) {
2429
+ from = node.from;
2674
2430
  }
2675
- return false;
2676
- } else if (node.name === "Link") {
2677
- const marks = node.node.getChildren("LinkMark");
2678
- const urlNode = node.node.getChild("URL");
2679
- const editing = editingRange(state2, node, focus);
2680
- if (urlNode && marks.length >= 2) {
2681
- const url = state2.sliceDoc(urlNode.from, urlNode.to);
2682
- if (!editing) {
2683
- atomicDeco.add(node.from, marks[0].to, hide);
2684
- }
2685
- deco.add(marks[0].to, marks[1].from, Decoration5.mark({
2686
- tagName: "a",
2687
- attributes: {
2688
- class: "cm-link",
2689
- href: url,
2690
- rel: "noreferrer",
2691
- target: "_blank"
2692
- }
2693
- }));
2694
- if (!editing) {
2695
- atomicDeco.add(marks[1].from, node.to, options.renderLinkButton ? Decoration5.replace({
2696
- widget: new LinkButton(url, options.renderLinkButton)
2697
- }) : hide);
2431
+ } else if (IgnoreInline.has(name) && enable) {
2432
+ if (node.from < from && node.to > from) {
2433
+ if (to === from) {
2434
+ to = node.to;
2698
2435
  }
2436
+ from = node.to;
2699
2437
  }
2700
- } else if (node.name === "HeaderMark") {
2701
- const parent = node.node.parent;
2702
- if (/^ATX/.test(parent.name) && !editingRange(state2, state2.doc.lineAt(node.from), focus)) {
2703
- const next = state2.doc.sliceString(node.to, node.to + 1);
2704
- atomicDeco.add(node.from, node.to + (next === " " ? 1 : 0), hide);
2438
+ if (node.from < to && node.to > to) {
2439
+ to = node.from;
2705
2440
  }
2706
- } else if (node.name === "HorizontalRule") {
2707
- if (!editingRange(state2, node, focus)) {
2708
- deco.add(node.from, node.to, horizontalRule);
2441
+ } else if (Object.hasOwn(InlineMarker, name)) {
2442
+ const markType = InlineMarker[name];
2443
+ const size = inlineMarkerText(markType).length;
2444
+ const openEnd = node.from + size;
2445
+ const closeStart = node.to - size;
2446
+ if (markType === type) {
2447
+ if (openEnd <= from && closeStart >= from) {
2448
+ startCovered = !enable && openEnd === skipMarkers(from, node.node, -1, openEnd) ? {
2449
+ from: node.from,
2450
+ to: openEnd
2451
+ } : true;
2452
+ }
2453
+ if (openEnd <= to && closeStart >= to) {
2454
+ endCovered = !enable && closeStart === skipMarkers(to, node.node, 1, closeStart) ? {
2455
+ from: closeStart,
2456
+ to: node.to
2457
+ } : true;
2458
+ }
2709
2459
  }
2710
- } else if (node.name === "TaskMarker") {
2711
- if (!editingRange(state2, node, focus)) {
2712
- const checked = state2.doc.sliceString(node.from + 1, node.to - 1) === "x";
2713
- atomicDeco.add(node.from - 2, node.from - 1, Decoration5.mark({
2714
- class: "cm-task"
2715
- }));
2716
- atomicDeco.add(node.from, node.to, checked ? checkedTask : uncheckedTask);
2460
+ if (markType === type || type === 3 && enable) {
2461
+ if (node.from >= from && openEnd <= to) {
2462
+ changes2.push({
2463
+ from: node.from,
2464
+ to: openEnd
2465
+ });
2466
+ if (markType !== type && closeStart >= to) {
2467
+ changesAtEnd.push({
2468
+ from: skipSpaces(Math.min(to, blockEnd), state2.doc, 1, blockEnd),
2469
+ insert: inlineMarkerText(markType)
2470
+ });
2471
+ }
2472
+ }
2473
+ if (closeStart >= from && node.to <= to) {
2474
+ changes2.push({
2475
+ from: closeStart,
2476
+ to: node.to
2477
+ });
2478
+ if (markType !== type && openEnd <= from) {
2479
+ changes2.push({
2480
+ from: skipSpaces(Math.max(from, blockStart), state2.doc, -1, blockStart),
2481
+ insert: inlineMarkerText(markType)
2482
+ });
2483
+ }
2484
+ }
2717
2485
  }
2718
- } else if (MarksByParent.has(node.name)) {
2719
- if (!editingRange(state2, node.node.parent, focus)) {
2720
- atomicDeco.add(node.from, node.to, hide);
2486
+ }
2487
+ },
2488
+ leave: (node) => {
2489
+ if (Object.hasOwn(Textblocks, node.name) && Textblocks[node.name] !== "codeblock") {
2490
+ const rangeStart = Math.max(from, blockStart);
2491
+ const rangeEnd = Math.min(to, blockEnd);
2492
+ if (enable) {
2493
+ if (!startCovered) {
2494
+ changes2.push({
2495
+ from: rangeStart,
2496
+ insert: marker
2497
+ });
2498
+ }
2499
+ if (!endCovered) {
2500
+ changes2.push({
2501
+ from: rangeEnd,
2502
+ insert: marker
2503
+ });
2504
+ }
2505
+ } else {
2506
+ if (typeof startCovered === "object") {
2507
+ changes2.push(startCovered);
2508
+ } else if (startCovered) {
2509
+ changes2.push({
2510
+ from: skipSpaces(rangeStart, state2.doc, -1, blockStart),
2511
+ insert: marker
2512
+ });
2513
+ }
2514
+ if (typeof endCovered === "object") {
2515
+ changes2.push(endCovered);
2516
+ } else if (endCovered) {
2517
+ changes2.push({
2518
+ from: skipSpaces(rangeEnd, state2.doc, 1, blockEnd),
2519
+ insert: marker
2520
+ });
2521
+ }
2721
2522
  }
2722
2523
  }
2723
2524
  }
2724
2525
  });
2526
+ if (blockStart < 0 && range.empty && enable && !/\S/.test(state2.doc.lineAt(range.from).text)) {
2527
+ return {
2528
+ changes: {
2529
+ from: range.head,
2530
+ insert: marker + marker
2531
+ },
2532
+ range: EditorSelection.cursor(range.head + marker.length)
2533
+ };
2534
+ }
2535
+ const changeSet = state2.changes(changes2.concat(changesAtEnd));
2536
+ return {
2537
+ changes: changeSet,
2538
+ range: range.empty && !changeSet.empty ? EditorSelection.cursor(range.head + marker.length) : EditorSelection.range(changeSet.mapPos(range.from, 1), changeSet.mapPos(range.to, -1))
2539
+ };
2540
+ });
2541
+ dispatch(state2.update(changes, {
2542
+ userEvent: enable ? "format.style.add" : "format.style.remove",
2543
+ scrollIntoView: true
2544
+ }));
2545
+ return true;
2546
+ };
2547
+ var addStyle = (style) => setStyle(style, true);
2548
+ var removeStyle = (style) => setStyle(style, false);
2549
+ var toggleStyle = (style) => (arg) => {
2550
+ const form = getFormatting(arg.state);
2551
+ return setStyle(style, style === 0 ? !form.strong : style === 1 ? !form.emphasis : style === 2 ? !form.strikethrough : !form.code)(arg);
2552
+ };
2553
+ var toggleStrong = toggleStyle(0);
2554
+ var toggleEmphasis = toggleStyle(1);
2555
+ var toggleStrikethrough = toggleStyle(2);
2556
+ var toggleInlineCode = toggleStyle(3);
2557
+ var inlineMarkerText = (type) => type === 0 ? "**" : type === 2 ? "~~" : type === 1 ? "*" : "`";
2558
+ var blockContentStart = (node) => {
2559
+ const atx = /^ATXHeading(\d)/.exec(node.name);
2560
+ if (atx) {
2561
+ return Math.min(node.to, node.from + +atx[1] + 1);
2725
2562
  }
2726
- return {
2727
- deco: deco.finish(),
2728
- atomicDeco: atomicDeco.finish()
2729
- };
2563
+ return node.from;
2730
2564
  };
2731
- var forceUpdate = StateEffect4.define();
2732
- var decorateMarkdown = (options = {}) => {
2733
- return [
2734
- ViewPlugin4.fromClass(class {
2735
- constructor(view) {
2736
- ({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations(view, options, view.hasFocus));
2737
- }
2738
- update(update2) {
2739
- if (update2.docChanged || update2.viewportChanged || update2.focusChanged || update2.transactions.some((tr) => tr.effects.some((e) => e.is(forceUpdate))) || update2.selectionSet && !options.selectionChangeDelay) {
2740
- ({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations(update2.view, options, update2.view.hasFocus));
2741
- this.clearUpdate();
2742
- } else if (update2.selectionSet) {
2743
- this.scheduleUpdate(update2.view);
2744
- }
2745
- }
2746
- // TODO(burdon): BUG: If the cursor is at the end of a link at the end of a line,
2747
- // the cursor will float in space or be in the wrong position after the decoration is applied.
2748
- scheduleUpdate(view) {
2749
- this.clearUpdate();
2750
- this.pendingUpdate = setTimeout(() => {
2751
- view.dispatch({
2752
- effects: forceUpdate.of(null)
2753
- });
2754
- }, options.selectionChangeDelay);
2755
- }
2756
- clearUpdate() {
2757
- if (this.pendingUpdate) {
2758
- clearTimeout(this.pendingUpdate);
2759
- this.pendingUpdate = void 0;
2760
- }
2761
- }
2762
- destroy() {
2763
- this.clearUpdate();
2764
- }
2765
- }, {
2766
- provide: (plugin) => [
2767
- EditorView12.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration5.none),
2768
- EditorView12.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration5.none),
2769
- EditorView12.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration5.none)
2770
- ]
2771
- }),
2772
- formattingStyles
2773
- ];
2565
+ var blockContentEnd = (node, doc) => {
2566
+ const setext = /^SetextHeading(\d)/.exec(node.name);
2567
+ const lastLine = doc.lineAt(node.to);
2568
+ if (setext || /^[\s>]*$/.exec(lastLine.text)) {
2569
+ return lastLine.from - 1;
2570
+ }
2571
+ return node.to;
2774
2572
  };
2775
- var formattingStyles = EditorView12.baseTheme({
2776
- "& .cm-code": {
2777
- fontFamily: getToken("fontFamily.mono", []).join(",")
2778
- },
2779
- "& .cm-codeblock-line": {
2780
- paddingInline: "1rem !important"
2781
- },
2782
- "& .cm-codeblock-end": {
2783
- display: "inline-block",
2784
- width: "100%",
2785
- position: "relative",
2786
- "&::after": {
2787
- position: "absolute",
2788
- inset: 0,
2789
- content: '""'
2573
+ var skipSpaces = (pos, doc, dir, limit) => {
2574
+ const line = doc.lineAt(pos);
2575
+ while (pos !== limit && line.text[pos - line.from - (dir < 0 ? 1 : 0)] === " ") {
2576
+ pos += dir;
2577
+ }
2578
+ return pos;
2579
+ };
2580
+ var skipMarkers = (pos, tree, dir, limit) => {
2581
+ for (; ; ) {
2582
+ const next = tree.resolve(pos, dir);
2583
+ if (!IgnoreInline.has(next.name)) {
2584
+ return pos;
2790
2585
  }
2791
- },
2792
- "& .cm-codeblock-first": {
2793
- borderTopLeftRadius: ".5rem",
2794
- borderTopRightRadius: ".5rem"
2795
- },
2796
- "& .cm-codeblock-last": {
2797
- borderBottomLeftRadius: ".5rem",
2798
- borderBottomRightRadius: ".5rem"
2799
- },
2800
- "&light .cm-codeblock-line, &light .cm-activeLine.cm-codeblock-line": {
2801
- background: getToken("extend.semanticColors.input.light"),
2802
- mixBlendMode: "darken"
2803
- },
2804
- "&dark .cm-codeblock-line, &dark .cm-activeLine.cm-codeblock-line": {
2805
- background: getToken("extend.semanticColors.input.dark"),
2806
- mixBlendMode: "lighten"
2807
- },
2808
- "& .cm-hr": {
2809
- display: "inline-block",
2810
- width: "100%",
2811
- height: "0",
2812
- verticalAlign: "middle",
2813
- borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
2814
- },
2815
- "& .cm-task": {
2816
- color: getToken("extend.colors.blue.500")
2817
- },
2818
- "& .cm-task-checkbox": {
2819
- marginLeft: "4px",
2820
- marginRight: "4px"
2586
+ const moveTo = dir < 0 ? next.from : next.to;
2587
+ if (limit != null && (dir < 0 ? moveTo < limit : moveTo > limit)) {
2588
+ return pos;
2589
+ }
2590
+ pos = moveTo;
2821
2591
  }
2822
- });
2823
-
2824
- // packages/ui/react-ui-editor/src/extensions/markdown/formatting.ts
2825
- import { snippet } from "@codemirror/autocomplete";
2826
- import { syntaxTree as syntaxTree2 } from "@codemirror/language";
2827
- import { EditorSelection } from "@codemirror/state";
2828
- import { EditorView as EditorView13, keymap as keymap7 } from "@codemirror/view";
2829
- import { useMemo, useState } from "react";
2830
- 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;
2831
- var Inline;
2832
- (function(Inline2) {
2833
- Inline2[Inline2["Strong"] = 0] = "Strong";
2834
- Inline2[Inline2["Emphasis"] = 1] = "Emphasis";
2835
- Inline2[Inline2["Strikethrough"] = 2] = "Strikethrough";
2836
- Inline2[Inline2["Code"] = 3] = "Code";
2837
- })(Inline || (Inline = {}));
2838
- var List;
2839
- (function(List2) {
2840
- List2[List2["Ordered"] = 0] = "Ordered";
2841
- List2[List2["Bullet"] = 1] = "Bullet";
2842
- List2[List2["Task"] = 2] = "Task";
2843
- })(List || (List = {}));
2844
- var setHeading = (level) => ({ state: state2, dispatch }) => {
2845
- const { selection: { ranges }, doc } = state2;
2846
- const changes = [];
2847
- let prevBlock = -1;
2848
- for (const range of ranges) {
2849
- let sawBlock = false;
2850
- syntaxTree2(state2).iterate({
2851
- from: range.from,
2852
- to: range.to,
2853
- enter: (node) => {
2854
- if (!Object.hasOwn(Textblocks, node.name) || prevBlock === node.from) {
2855
- return;
2856
- }
2857
- sawBlock = true;
2858
- prevBlock = node.from;
2859
- const blockType = Textblocks[node.name];
2860
- const isHeading = /heading(\d)/.exec(blockType);
2861
- const curLevel = isHeading ? +isHeading[1] : node.name === "Paragraph" ? 0 : -1;
2862
- if (curLevel < 0 || curLevel === level) {
2863
- return;
2864
- }
2865
- if (curLevel === 0) {
2866
- changes.push({
2867
- from: node.from,
2868
- insert: "#".repeat(level) + " "
2869
- });
2870
- } else if (node.name === "SetextHeading1" || node.name === "SetextHeading2") {
2871
- const nextLine = doc.lineAt(node.to);
2872
- if (level) {
2873
- changes.push({
2874
- from: node.from,
2875
- insert: "#".repeat(level) + " "
2876
- });
2877
- }
2878
- changes.push({
2879
- from: nextLine.from - 1,
2880
- to: nextLine.to
2881
- });
2882
- } else {
2883
- if (level === 0) {
2884
- changes.push({
2885
- from: node.from,
2886
- to: Math.min(node.to, node.from + curLevel + 1)
2887
- });
2888
- } else if (level < curLevel) {
2592
+ };
2593
+ var snippets = {
2594
+ codeblock: snippet([
2595
+ //
2596
+ "```#{}",
2597
+ "",
2598
+ "```"
2599
+ ].join("\n")),
2600
+ table: snippet([
2601
+ //
2602
+ "| #{col1} | #{col2} |",
2603
+ "| ---- | ---- |",
2604
+ "| #{val1} | #{val2} |",
2605
+ "| #{val3} | #{val4} |",
2606
+ ""
2607
+ ].join("\n"))
2608
+ };
2609
+ var insertTable = (view) => {
2610
+ const { selection: { main }, doc } = view.state;
2611
+ const { number } = doc.lineAt(main.anchor);
2612
+ const { from } = doc.line(number);
2613
+ snippets.table(view, null, from, from);
2614
+ };
2615
+ var removeLinkInner = (from, to, changes, state2) => {
2616
+ syntaxTree(state2).iterate({
2617
+ from,
2618
+ to,
2619
+ enter: (node) => {
2620
+ if (node.name === "Link" && node.from < to && node.to > from) {
2621
+ node.node.cursor().iterate((node2) => {
2622
+ const { name } = node2;
2623
+ if (name === "LinkMark" || name === "LinkLabel") {
2889
2624
  changes.push({
2890
- from: node.from,
2891
- to: node.from + (curLevel - level)
2625
+ from: node2.from,
2626
+ to: node2.to
2892
2627
  });
2893
- } else {
2628
+ } else if (name === "LinkTitle" || name === "URL") {
2894
2629
  changes.push({
2895
- from: node.from,
2896
- insert: "#".repeat(level - curLevel)
2630
+ from: skipSpaces(node2.from, state2.doc, -1),
2631
+ to: skipSpaces(node2.to, state2.doc, 1)
2897
2632
  });
2898
2633
  }
2899
- }
2634
+ });
2635
+ return false;
2900
2636
  }
2901
- });
2902
- let line;
2903
- if (!sawBlock && range.empty && level > 0 && !/\S/.test((line = state2.doc.lineAt(range.from)).text)) {
2904
- changes.push({
2905
- from: line.from,
2906
- to: line.to,
2907
- insert: "#".repeat(level) + " "
2908
- });
2909
2637
  }
2638
+ });
2639
+ };
2640
+ var removeLink = ({ state: state2, dispatch }) => {
2641
+ const changes = [];
2642
+ for (const { from, to } of state2.selection.ranges) {
2643
+ removeLinkInner(from, to, changes, state2);
2910
2644
  }
2911
- if (!changes.length) {
2645
+ if (!changes) {
2912
2646
  return false;
2913
2647
  }
2914
- const changeSet = state2.changes(changes);
2915
2648
  dispatch(state2.update({
2916
- changes: changeSet,
2917
- selection: state2.selection.map(changeSet, 1),
2918
- userEvent: "format.setHeading",
2649
+ changes,
2650
+ userEvent: "format.link.remove",
2919
2651
  scrollIntoView: true
2920
2652
  }));
2921
2653
  return true;
2922
2654
  };
2923
- var setStyle = (type, enable) => ({ state: state2, dispatch }) => {
2924
- const marker = inlineMarkerText(type);
2655
+ var addLink = ({ url, image: image2 } = {}) => ({ state: state2, dispatch }) => {
2925
2656
  const changes = state2.changeByRange((range) => {
2926
- if (!enable && range.empty) {
2927
- const after = state2.doc.sliceString(range.head, range.head + 6);
2928
- const found = after.indexOf(marker);
2929
- if (found >= 0 && /^[*~`]*$/.test(after.slice(0, found))) {
2930
- const before = state2.doc.sliceString(range.head - 6, range.head);
2931
- if (before.slice(before.length - found - marker.length, before.length - found) === marker && [
2932
- ...before.slice(before.length - found)
2933
- ].reverse().join("") === after.slice(0, found)) {
2934
- return {
2935
- changes: [
2936
- {
2937
- from: range.head - marker.length - found,
2938
- to: range.head - found
2939
- },
2940
- {
2941
- from: range.head + found,
2942
- to: range.head + found + marker.length
2943
- }
2944
- ],
2945
- range: EditorSelection.cursor(range.from - marker.length)
2946
- };
2947
- }
2948
- }
2949
- }
2950
- const changes2 = [];
2951
- const changesAtEnd = [];
2952
- let blockStart = -1;
2953
- let blockEnd = -1;
2954
- let startCovered = false;
2955
- let endCovered = false;
2956
2657
  let { from, to } = range;
2957
- syntaxTree2(state2).iterate({
2658
+ const cutStyles = [];
2659
+ let okay = null;
2660
+ syntaxTree(state2).iterate({
2958
2661
  from,
2959
2662
  to,
2960
2663
  enter: (node) => {
2961
- const { name } = node;
2962
- if (Object.hasOwn(Textblocks, name) && Textblocks[name] !== "codeblock") {
2963
- blockStart = blockContentStart(node);
2964
- blockEnd = blockContentEnd(node, state2.doc);
2965
- startCovered = endCovered = false;
2966
- } else if (name === "Link" || name === "Image" && enable) {
2967
- if (from < node.from && to > node.from && to <= node.to) {
2968
- to = node.to;
2969
- } else if (to > node.to && from >= node.from && from < node.to) {
2970
- from = node.from;
2971
- }
2972
- } else if (IgnoreInline.has(name) && enable) {
2973
- if (node.from < from && node.to > from) {
2974
- if (to === from) {
2975
- to = node.to;
2976
- }
2977
- from = node.to;
2978
- }
2979
- if (node.from < to && node.to > to) {
2980
- to = node.from;
2981
- }
2982
- } else if (Object.hasOwn(InlineMarker, name)) {
2983
- const markType = InlineMarker[name];
2984
- const size = inlineMarkerText(markType).length;
2985
- const openEnd = node.from + size;
2986
- const closeStart = node.to - size;
2987
- if (markType === type) {
2988
- if (openEnd <= from && closeStart >= from) {
2989
- startCovered = !enable && openEnd === skipMarkers(from, node.node, -1, openEnd) ? {
2990
- from: node.from,
2991
- to: openEnd
2992
- } : true;
2664
+ if (Object.hasOwn(Textblocks, node.name)) {
2665
+ okay = Textblocks[node.name] !== "codeblock" && from >= blockContentStart(node) && to <= blockContentEnd(node, state2.doc);
2666
+ } else if (Object.hasOwn(InlineMarker, node.name)) {
2667
+ const sNode = node.node;
2668
+ if (node.from < from && node.to <= to) {
2669
+ if (sNode.firstChild.to === from) {
2670
+ from = node.from;
2671
+ } else {
2672
+ cutStyles.push(sNode);
2993
2673
  }
2994
- if (openEnd <= to && closeStart >= to) {
2995
- endCovered = !enable && closeStart === skipMarkers(to, node.node, 1, closeStart) ? {
2996
- from: closeStart,
2997
- to: node.to
2998
- } : true;
2999
- }
3000
- }
3001
- if (markType === type || type === 3 && enable) {
3002
- if (node.from >= from && openEnd <= to) {
3003
- changes2.push({
3004
- from: node.from,
3005
- to: openEnd
3006
- });
3007
- if (markType !== type && closeStart >= to) {
3008
- changesAtEnd.push({
3009
- from: skipSpaces(Math.min(to, blockEnd), state2.doc, 1, blockEnd),
3010
- insert: inlineMarkerText(markType)
3011
- });
3012
- }
3013
- }
3014
- if (closeStart >= from && node.to <= to) {
3015
- changes2.push({
3016
- from: closeStart,
3017
- to: node.to
3018
- });
3019
- if (markType !== type && openEnd <= from) {
3020
- changes2.push({
3021
- from: skipSpaces(Math.max(from, blockStart), state2.doc, -1, blockStart),
3022
- insert: inlineMarkerText(markType)
3023
- });
3024
- }
3025
- }
3026
- }
3027
- }
3028
- },
3029
- leave: (node) => {
3030
- if (Object.hasOwn(Textblocks, node.name) && Textblocks[node.name] !== "codeblock") {
3031
- const rangeStart = Math.max(from, blockStart);
3032
- const rangeEnd = Math.min(to, blockEnd);
3033
- if (enable) {
3034
- if (!startCovered) {
3035
- changes2.push({
3036
- from: rangeStart,
3037
- insert: marker
3038
- });
3039
- }
3040
- if (!endCovered) {
3041
- changes2.push({
3042
- from: rangeEnd,
3043
- insert: marker
3044
- });
3045
- }
3046
- } else {
3047
- if (typeof startCovered === "object") {
3048
- changes2.push(startCovered);
3049
- } else if (startCovered) {
3050
- changes2.push({
3051
- from: skipSpaces(rangeStart, state2.doc, -1, blockStart),
3052
- insert: marker
3053
- });
3054
- }
3055
- if (typeof endCovered === "object") {
3056
- changes2.push(endCovered);
3057
- } else if (endCovered) {
3058
- changes2.push({
3059
- from: skipSpaces(rangeEnd, state2.doc, 1, blockEnd),
3060
- insert: marker
3061
- });
3062
- }
3063
- }
3064
- }
3065
- }
3066
- });
3067
- if (blockStart < 0 && range.empty && enable && !/\S/.test(state2.doc.lineAt(range.from).text)) {
3068
- return {
3069
- changes: {
3070
- from: range.head,
3071
- insert: marker + marker
3072
- },
3073
- range: EditorSelection.cursor(range.head + marker.length)
3074
- };
3075
- }
3076
- const changeSet = state2.changes(changes2.concat(changesAtEnd));
3077
- return {
3078
- changes: changeSet,
3079
- range: range.empty && !changeSet.empty ? EditorSelection.cursor(range.head + marker.length) : EditorSelection.range(changeSet.mapPos(range.from, 1), changeSet.mapPos(range.to, -1))
3080
- };
3081
- });
3082
- dispatch(state2.update(changes, {
3083
- userEvent: enable ? "format.style.add" : "format.style.remove",
3084
- scrollIntoView: true
3085
- }));
3086
- return true;
3087
- };
3088
- var addStyle = (style) => setStyle(style, true);
3089
- var removeStyle = (style) => setStyle(style, false);
3090
- var toggleStyle = (style) => (arg) => {
3091
- const form = getFormatting(arg.state);
3092
- return setStyle(style, style === 0 ? !form.strong : style === 1 ? !form.emphasis : style === 2 ? !form.strikethrough : !form.code)(arg);
3093
- };
3094
- var toggleStrong = toggleStyle(0);
3095
- var toggleEmphasis = toggleStyle(1);
3096
- var toggleStrikethrough = toggleStyle(2);
3097
- var toggleInlineCode = toggleStyle(3);
3098
- var inlineMarkerText = (type) => type === 0 ? "**" : type === 2 ? "~~" : type === 1 ? "*" : "`";
3099
- var blockContentStart = (node) => {
3100
- const atx = /^ATXHeading(\d)/.exec(node.name);
3101
- if (atx) {
3102
- return Math.min(node.to, node.from + +atx[1] + 1);
3103
- }
3104
- return node.from;
3105
- };
3106
- var blockContentEnd = (node, doc) => {
3107
- const setext = /^SetextHeading(\d)/.exec(node.name);
3108
- const lastLine = doc.lineAt(node.to);
3109
- if (setext || /^[\s>]*$/.exec(lastLine.text)) {
3110
- return lastLine.from - 1;
3111
- }
3112
- return node.to;
3113
- };
3114
- var skipSpaces = (pos, doc, dir, limit) => {
3115
- const line = doc.lineAt(pos);
3116
- while (pos !== limit && line.text[pos - line.from - (dir < 0 ? 1 : 0)] === " ") {
3117
- pos += dir;
3118
- }
3119
- return pos;
3120
- };
3121
- var skipMarkers = (pos, tree, dir, limit) => {
3122
- for (; ; ) {
3123
- const next = tree.resolve(pos, dir);
3124
- if (!IgnoreInline.has(next.name)) {
3125
- return pos;
3126
- }
3127
- const moveTo = dir < 0 ? next.from : next.to;
3128
- if (limit != null && (dir < 0 ? moveTo < limit : moveTo > limit)) {
3129
- return pos;
3130
- }
3131
- pos = moveTo;
3132
- }
3133
- };
3134
- var snippets = {
3135
- codeblock: snippet([
3136
- //
3137
- "```#{}",
3138
- "",
3139
- "```"
3140
- ].join("\n")),
3141
- table: snippet([
3142
- //
3143
- "| #{col1} | #{col2} |",
3144
- "| ---- | ---- |",
3145
- "| #{val1} | #{val2} |",
3146
- "| #{val3} | #{val4} |",
3147
- ""
3148
- ].join("\n"))
3149
- };
3150
- var insertTable = (view) => {
3151
- const { selection: { main }, doc } = view.state;
3152
- const { number } = doc.lineAt(main.anchor);
3153
- const { from } = doc.line(number);
3154
- snippets.table(view, null, from, from);
3155
- };
3156
- var removeLinkInner = (from, to, changes, state2) => {
3157
- syntaxTree2(state2).iterate({
3158
- from,
3159
- to,
3160
- enter: (node) => {
3161
- if (node.name === "Link" && node.from < to && node.to > from) {
3162
- node.node.cursor().iterate((node2) => {
3163
- const { name } = node2;
3164
- if (name === "LinkMark" || name === "LinkLabel") {
3165
- changes.push({
3166
- from: node2.from,
3167
- to: node2.to
3168
- });
3169
- } else if (name === "LinkTitle" || name === "URL") {
3170
- changes.push({
3171
- from: skipSpaces(node2.from, state2.doc, -1),
3172
- to: skipSpaces(node2.to, state2.doc, 1)
3173
- });
3174
- }
3175
- });
3176
- return false;
3177
- }
3178
- }
3179
- });
3180
- };
3181
- var removeLink = ({ state: state2, dispatch }) => {
3182
- const changes = [];
3183
- for (const { from, to } of state2.selection.ranges) {
3184
- removeLinkInner(from, to, changes, state2);
3185
- }
3186
- if (!changes) {
3187
- return false;
3188
- }
3189
- dispatch(state2.update({
3190
- changes,
3191
- userEvent: "format.link.remove",
3192
- scrollIntoView: true
3193
- }));
3194
- return true;
3195
- };
3196
- var addLink = ({ url, image: image2 } = {}) => ({ state: state2, dispatch }) => {
3197
- const changes = state2.changeByRange((range) => {
3198
- let { from, to } = range;
3199
- const cutStyles = [];
3200
- let okay = null;
3201
- syntaxTree2(state2).iterate({
3202
- from,
3203
- to,
3204
- enter: (node) => {
3205
- if (Object.hasOwn(Textblocks, node.name)) {
3206
- okay = Textblocks[node.name] !== "codeblock" && from >= blockContentStart(node) && to <= blockContentEnd(node, state2.doc);
3207
- } else if (Object.hasOwn(InlineMarker, node.name)) {
3208
- const sNode = node.node;
3209
- if (node.from < from && node.to <= to) {
3210
- if (sNode.firstChild.to === from) {
3211
- from = node.from;
3212
- } else {
3213
- cutStyles.push(sNode);
3214
- }
3215
- } else if (node.from >= from && node.to > to) {
3216
- if (sNode.lastChild.from === to) {
3217
- to = node.to;
3218
- } else {
3219
- cutStyles.push(sNode);
2674
+ } else if (node.from >= from && node.to > to) {
2675
+ if (sNode.lastChild.from === to) {
2676
+ to = node.to;
2677
+ } else {
2678
+ cutStyles.push(sNode);
3220
2679
  }
3221
2680
  }
3222
2681
  }
@@ -3291,7 +2750,7 @@ var addList = (type) => ({ state: state2, dispatch }) => {
3291
2750
  let parentColumn = null;
3292
2751
  const blocks = [];
3293
2752
  for (const { from, to } of state2.selection.ranges) {
3294
- syntaxTree2(state2).iterate({
2753
+ syntaxTree(state2).iterate({
3295
2754
  from,
3296
2755
  to,
3297
2756
  enter: (node) => {
@@ -3424,7 +2883,7 @@ var removeList = (type) => ({ state: state2, dispatch }) => {
3424
2883
  const stack = [];
3425
2884
  const targetNodeType = type === 0 ? "OrderedList" : type === 1 ? "BulletList" : "TaskList";
3426
2885
  for (const { from, to } of state2.selection.ranges) {
3427
- syntaxTree2(state2).iterate({
2886
+ syntaxTree(state2).iterate({
3428
2887
  from,
3429
2888
  to,
3430
2889
  enter: (node) => {
@@ -3507,7 +2966,7 @@ var setBlockquote = (enable) => ({ state: state2, dispatch }) => {
3507
2966
  let lastBlock = -1;
3508
2967
  for (const { from, to } of state2.selection.ranges) {
3509
2968
  const sawBlock = false;
3510
- syntaxTree2(state2).iterate({
2969
+ syntaxTree(state2).iterate({
3511
2970
  from,
3512
2971
  to,
3513
2972
  enter: (node) => {
@@ -3596,7 +3055,7 @@ var addCodeblock = (target) => {
3596
3055
  for (const { from, to } of selection.ranges) {
3597
3056
  let blockFrom = from;
3598
3057
  let blockTo = to;
3599
- syntaxTree2(state2).iterate({
3058
+ syntaxTree(state2).iterate({
3600
3059
  from,
3601
3060
  to,
3602
3061
  enter: (node) => {
@@ -3620,304 +3079,855 @@ var addCodeblock = (target) => {
3620
3079
  });
3621
3080
  }
3622
3081
  }
3623
- if (!ranges.length) {
3624
- return false;
3082
+ if (!ranges.length) {
3083
+ return false;
3084
+ }
3085
+ const changes = ranges.map(({ from, to }) => {
3086
+ const column = from - state2.doc.lineAt(from).from;
3087
+ return [
3088
+ {
3089
+ from,
3090
+ insert: "```\n" + " ".repeat(column)
3091
+ },
3092
+ {
3093
+ from: to,
3094
+ insert: "\n" + " ".repeat(column) + "```"
3095
+ }
3096
+ ];
3097
+ });
3098
+ dispatch(state2.update({
3099
+ changes,
3100
+ userEvent: "format.codeblock.add",
3101
+ scrollIntoView: true
3102
+ }));
3103
+ return true;
3104
+ };
3105
+ var removeCodeblock = ({ state: state2, dispatch }) => {
3106
+ const changes = [];
3107
+ let lastBlock = -1;
3108
+ for (const { from, to } of state2.selection.ranges) {
3109
+ syntaxTree(state2).iterate({
3110
+ from,
3111
+ to,
3112
+ enter: (node) => {
3113
+ if (Textblocks[node.name] === "codeblock" && lastBlock !== node.from) {
3114
+ lastBlock = node.from;
3115
+ const firstLine = state2.doc.lineAt(node.from);
3116
+ if (node.name === "FencedCode") {
3117
+ changes.push({
3118
+ from: node.from,
3119
+ to: firstLine.to + 1 + node.from - firstLine.from
3120
+ });
3121
+ const lastLine = state2.doc.lineAt(node.to);
3122
+ if (/^([\s>]|[-*+] |\d+[).])*`+$/.test(lastLine.text)) {
3123
+ changes.push({
3124
+ from: lastLine.from - (lastLine.number === firstLine.number + 1 ? 0 : 1),
3125
+ to: lastLine.to
3126
+ });
3127
+ }
3128
+ } else {
3129
+ const column = node.from - firstLine.from;
3130
+ for (let line = firstLine; ; line = state2.doc.line(line.number + 1)) {
3131
+ changes.push({
3132
+ from: line.from + column - 4,
3133
+ to: line.from + column
3134
+ });
3135
+ if (line.to >= node.to) {
3136
+ break;
3137
+ }
3138
+ }
3139
+ }
3140
+ }
3141
+ }
3142
+ });
3143
+ }
3144
+ if (!changes.length) {
3145
+ return false;
3146
+ }
3147
+ dispatch(state2.update({
3148
+ changes,
3149
+ userEvent: "format.codeblock.remove",
3150
+ scrollIntoView: true
3151
+ }));
3152
+ return true;
3153
+ };
3154
+ var toggleCodeblock = (target) => {
3155
+ return (getFormatting(target.state).blockType === "codeblock" ? removeCodeblock : addCodeblock)(target);
3156
+ };
3157
+ var formattingKeymap = (options = {}) => {
3158
+ return [
3159
+ keymap6.of([
3160
+ {
3161
+ key: "meta-b",
3162
+ run: toggleStrong
3163
+ }
3164
+ ])
3165
+ ];
3166
+ };
3167
+ var InlineMarker = {
3168
+ Emphasis: 1,
3169
+ StrongEmphasis: 0,
3170
+ InlineCode: 3,
3171
+ Strikethrough: 2
3172
+ };
3173
+ var IgnoreInline = /* @__PURE__ */ new Set([
3174
+ "Autolink",
3175
+ "CodeMark",
3176
+ "CodeText",
3177
+ "Comment",
3178
+ "EmphasisMark",
3179
+ "Hardbreak",
3180
+ "HeaderMark",
3181
+ "HTMLTag",
3182
+ "LinkMark",
3183
+ "ListMark",
3184
+ "ProcessingInstruction",
3185
+ "QuoteMark",
3186
+ "StrikethroughMark",
3187
+ "SubscriptMark",
3188
+ "SuperscriptMark",
3189
+ "TaskMarker"
3190
+ ]);
3191
+ var Textblocks = {
3192
+ ATXHeading1: "heading1",
3193
+ ATXHeading2: "heading2",
3194
+ ATXHeading3: "heading3",
3195
+ ATXHeading4: "heading4",
3196
+ ATXHeading5: "heading5",
3197
+ ATXHeading6: "heading6",
3198
+ CodeBlock: "codeblock",
3199
+ FencedCode: "codeblock",
3200
+ Paragraph: "paragraph",
3201
+ SetextHeading1: "heading1",
3202
+ SetextHeading2: "heading2",
3203
+ TableCell: "tablecell",
3204
+ Task: "paragraph"
3205
+ };
3206
+ var getFormatting = (state2) => {
3207
+ let blockType = null;
3208
+ const inline = [
3209
+ null,
3210
+ null,
3211
+ null,
3212
+ null
3213
+ ];
3214
+ let link = false;
3215
+ let blockQuote = null;
3216
+ let listStyle = null;
3217
+ const stack = [];
3218
+ let currentBlock = null;
3219
+ const advanceInline = (upto) => {
3220
+ if (!currentBlock) {
3221
+ return;
3222
+ }
3223
+ upto = Math.min(upto, currentBlock.end);
3224
+ if (upto <= currentBlock.pos) {
3225
+ return;
3226
+ }
3227
+ for (let i = 0; i < currentBlock.active.length; i++) {
3228
+ if (inline[i] === false) {
3229
+ continue;
3230
+ } else if (currentBlock.active[i]) {
3231
+ inline[i] = true;
3232
+ } else if (/\S/.test(state2.doc.sliceString(currentBlock.pos, upto))) {
3233
+ inline[i] = false;
3234
+ }
3235
+ }
3236
+ currentBlock.pos = upto;
3237
+ };
3238
+ const skipInline = (upto) => {
3239
+ if (currentBlock && upto > currentBlock.pos) {
3240
+ currentBlock.pos = Math.min(upto, currentBlock.end);
3241
+ }
3242
+ };
3243
+ const { selection } = state2;
3244
+ for (const range of selection.ranges) {
3245
+ if (range.empty && inline.some((v) => v === null)) {
3246
+ const contextSize = Math.min(range.head, 6);
3247
+ const contextBefore = state2.doc.sliceString(range.head - contextSize, range.head);
3248
+ let contextAfter = state2.doc.sliceString(range.head, range.head + contextSize);
3249
+ for (let i = 0; i < contextSize; i++) {
3250
+ const ch = contextAfter[i];
3251
+ if (ch !== contextBefore[contextBefore.length - 1 - i] || !/[~`*]/.test(ch)) {
3252
+ contextAfter = contextAfter.slice(0, i);
3253
+ break;
3254
+ }
3255
+ }
3256
+ for (let i = 0; i < inline.length; i++) {
3257
+ const mark2 = inlineMarkerText(i);
3258
+ const found = contextAfter.indexOf(mark2);
3259
+ if (found > -1) {
3260
+ contextAfter = contextAfter.slice(0, found) + contextAfter.slice(found + mark2.length);
3261
+ if (inline[i] === null) {
3262
+ inline[i] = true;
3263
+ }
3264
+ }
3265
+ }
3266
+ }
3267
+ syntaxTree(state2).iterate({
3268
+ from: range.from,
3269
+ to: range.to,
3270
+ enter: (node) => {
3271
+ advanceInline(node.from);
3272
+ const { name } = node;
3273
+ if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
3274
+ stack.push(name);
3275
+ } else if (name === "Link") {
3276
+ link = true;
3277
+ } else if (Object.hasOwn(Textblocks, name) && (range.empty || node.to > range.from || node.from < range.to)) {
3278
+ if (name === "Task" && stack[stack.length - 1] === "BulletList") {
3279
+ stack[stack.length - 1] = "TaskList";
3280
+ }
3281
+ const blockCode = Textblocks[name];
3282
+ if (blockType === null) {
3283
+ blockType = blockCode;
3284
+ } else if (blockType !== blockCode) {
3285
+ blockType = false;
3286
+ }
3287
+ if (blockCode !== "codeblock" && inline.some((i) => i !== false)) {
3288
+ currentBlock = {
3289
+ pos: Math.max(range.from, node.from),
3290
+ end: Math.min(range.to, node.to),
3291
+ active: [
3292
+ false,
3293
+ false,
3294
+ false,
3295
+ false
3296
+ ]
3297
+ };
3298
+ }
3299
+ } else if (Object.hasOwn(InlineMarker, name) && currentBlock) {
3300
+ const index = InlineMarker[name];
3301
+ if (range.empty && inline[index] === null) {
3302
+ inline[index] = true;
3303
+ }
3304
+ currentBlock.active[index] = true;
3305
+ } else if (IgnoreInline.has(name)) {
3306
+ skipInline(node.to);
3307
+ }
3308
+ },
3309
+ leave: (node) => {
3310
+ advanceInline(node.to);
3311
+ const { name } = node;
3312
+ if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
3313
+ stack.pop();
3314
+ } else if (Object.hasOwn(Textblocks, name)) {
3315
+ let hasList = false;
3316
+ let hasQuote = false;
3317
+ for (let i = stack.length - 1; i >= 0; i--) {
3318
+ if (stack[i] === "Blockquote") {
3319
+ hasQuote = true;
3320
+ } else if (!hasList) {
3321
+ hasList = stack[i] === "TaskList" ? "task" : stack[i] === "BulletList" ? "bullet" : "ordered";
3322
+ }
3323
+ }
3324
+ if (blockQuote === null) {
3325
+ blockQuote = hasQuote;
3326
+ } else if (!hasQuote && blockQuote) {
3327
+ blockQuote = false;
3328
+ }
3329
+ if (listStyle === null) {
3330
+ listStyle = hasList;
3331
+ } else if (listStyle !== hasList) {
3332
+ listStyle = false;
3333
+ }
3334
+ currentBlock = null;
3335
+ } else if (Object.hasOwn(InlineMarker, name) && currentBlock) {
3336
+ currentBlock.active[InlineMarker[name]] = false;
3337
+ }
3338
+ }
3339
+ });
3340
+ }
3341
+ const { from, to } = state2.doc.lineAt(selection.main.anchor);
3342
+ const blankLine = from === to;
3343
+ return {
3344
+ blankLine,
3345
+ blockType: blockType || null,
3346
+ blockQuote: blockQuote ?? false,
3347
+ code: inline[3] ?? false,
3348
+ emphasis: inline[1] ?? false,
3349
+ strong: inline[0] ?? false,
3350
+ strikethrough: inline[2] ?? false,
3351
+ link,
3352
+ listStyle: listStyle || null
3353
+ };
3354
+ };
3355
+ var useFormattingState = () => {
3356
+ const [state2, setState] = useState();
3357
+ const observer = useMemo(() => EditorView11.updateListener.of((update2) => {
3358
+ if (update2.docChanged || update2.selectionSet) {
3359
+ setState((prevState) => {
3360
+ const newState = getFormatting(update2.state);
3361
+ if (!prevState || !formattingEquals(prevState, newState)) {
3362
+ return newState;
3363
+ }
3364
+ return prevState;
3365
+ });
3366
+ }
3367
+ }), [
3368
+ setState
3369
+ ]);
3370
+ return [
3371
+ state2,
3372
+ observer
3373
+ ];
3374
+ };
3375
+
3376
+ // packages/ui/react-ui-editor/src/extensions/markdown/action.ts
3377
+ var processAction = (view, action) => {
3378
+ let inlineType, listType;
3379
+ switch (action.type) {
3380
+ case "heading":
3381
+ setHeading(parseInt(action.data))(view);
3382
+ break;
3383
+ case "strong":
3384
+ case "emphasis":
3385
+ case "strikethrough":
3386
+ case "code":
3387
+ inlineType = action.type === "strong" ? Inline.Strong : action.type === "emphasis" ? Inline.Emphasis : action.type === "strikethrough" ? Inline.Strikethrough : Inline.Code;
3388
+ (typeof action.data === "boolean" ? setStyle(inlineType, action.data) : toggleStyle(inlineType))(view);
3389
+ break;
3390
+ case "list-ordered":
3391
+ case "list-bullet":
3392
+ case "list-task":
3393
+ listType = action.type === "list-ordered" ? List.Ordered : action.type === "list-bullet" ? List.Bullet : List.Task;
3394
+ (action.data === false ? removeList(listType) : action.data === true ? addList(listType) : toggleList(listType))(view);
3395
+ break;
3396
+ case "blockquote":
3397
+ (action.data === false ? removeBlockquote : action.data === true ? addBlockquote : toggleBlockquote)(view);
3398
+ break;
3399
+ case "codeblock":
3400
+ (action.data === false ? removeCodeblock : addCodeblock)(view);
3401
+ break;
3402
+ case "table":
3403
+ insertTable(view);
3404
+ break;
3405
+ case "link":
3406
+ (action.data === false ? removeLink : addLink())(view);
3407
+ break;
3408
+ case "image":
3409
+ addLink({
3410
+ url: action.data,
3411
+ image: true
3412
+ })(view);
3413
+ break;
3414
+ case "comment":
3415
+ createComment(view);
3416
+ break;
3417
+ }
3418
+ requestAnimationFrame(() => {
3419
+ if (!view.hasFocus) {
3420
+ view.focus();
3421
+ }
3422
+ });
3423
+ };
3424
+
3425
+ // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
3426
+ import { completionKeymap as completionKeymap2 } from "@codemirror/autocomplete";
3427
+ import { defaultKeymap as defaultKeymap2, indentWithTab as indentWithTab2 } from "@codemirror/commands";
3428
+ import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
3429
+ import { defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
3430
+ import { languages } from "@codemirror/language-data";
3431
+ import { lintKeymap } from "@codemirror/lint";
3432
+ import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
3433
+ import { keymap as keymap7 } from "@codemirror/view";
3434
+
3435
+ // packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
3436
+ import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
3437
+ import { HighlightStyle } from "@codemirror/language";
3438
+ import { tags, styleTags, Tag } from "@lezer/highlight";
3439
+ import { Table } from "@lezer/markdown";
3440
+ var markdownTags = {
3441
+ Blockquote: Tag.define(),
3442
+ CodeMark: Tag.define(),
3443
+ CodeText: Tag.define(),
3444
+ EmphasisMark: Tag.define(),
3445
+ HeaderMark: Tag.define(),
3446
+ InlineCode: Tag.define(),
3447
+ LinkLabel: Tag.define(),
3448
+ LinkReference: Tag.define(),
3449
+ ListMark: Tag.define(),
3450
+ QuoteMark: Tag.define(),
3451
+ URL: Tag.define(),
3452
+ // Custom.
3453
+ TableCell: Tag.define()
3454
+ };
3455
+ Table.defineNodes?.forEach((node) => {
3456
+ switch (node?.name) {
3457
+ case "TableCell": {
3458
+ node.style = markdownTags.TableCell;
3459
+ break;
3460
+ }
3461
+ }
3462
+ });
3463
+ var markdownTagsExtensions = [
3464
+ Table,
3465
+ {
3466
+ props: [
3467
+ styleTags(markdownTags)
3468
+ ]
3469
+ }
3470
+ ];
3471
+ var markdownHighlightStyle = (readonly) => {
3472
+ return HighlightStyle.define([
3473
+ {
3474
+ tag: [
3475
+ tags.keyword,
3476
+ tags.name,
3477
+ tags.deleted,
3478
+ tags.character,
3479
+ tags.propertyName,
3480
+ tags.macroName,
3481
+ tags.color,
3482
+ tags.constant(tags.name),
3483
+ tags.standard(tags.name),
3484
+ tags.definition(tags.name),
3485
+ tags.separator,
3486
+ tags.typeName,
3487
+ tags.className,
3488
+ tags.number,
3489
+ tags.changed,
3490
+ tags.annotation,
3491
+ tags.modifier,
3492
+ tags.self,
3493
+ tags.namespace,
3494
+ tags.operator,
3495
+ tags.operatorKeyword,
3496
+ tags.escape,
3497
+ tags.regexp,
3498
+ tags.special(tags.string),
3499
+ tags.meta,
3500
+ tags.comment,
3501
+ tags.atom,
3502
+ tags.bool,
3503
+ tags.special(tags.variableName),
3504
+ tags.processingInstruction,
3505
+ tags.string,
3506
+ tags.inserted,
3507
+ tags.invalid
3508
+ ],
3509
+ color: "inherit !important"
3510
+ },
3511
+ // Markdown marks.
3512
+ {
3513
+ tag: [
3514
+ tags.meta,
3515
+ tags.processingInstruction,
3516
+ markdownTags.LinkLabel,
3517
+ markdownTags.LinkReference,
3518
+ markdownTags.ListMark
3519
+ ],
3520
+ class: mark
3521
+ },
3522
+ // Markdown marks.
3523
+ {
3524
+ tag: [
3525
+ markdownTags.CodeMark,
3526
+ markdownTags.HeaderMark,
3527
+ markdownTags.QuoteMark,
3528
+ markdownTags.EmphasisMark
3529
+ ],
3530
+ class: mark
3531
+ },
3532
+ // E.g., code block language (after ```).
3533
+ {
3534
+ tag: [
3535
+ tags.function(tags.variableName),
3536
+ tags.labelName
3537
+ ],
3538
+ class: codeMark
3539
+ },
3540
+ {
3541
+ tag: [
3542
+ tags.monospace
3543
+ ],
3544
+ class: "font-mono"
3545
+ },
3546
+ // Headings.
3547
+ {
3548
+ tag: tags.heading1,
3549
+ class: heading(1)
3550
+ },
3551
+ {
3552
+ tag: tags.heading2,
3553
+ class: heading(2)
3554
+ },
3555
+ {
3556
+ tag: tags.heading3,
3557
+ class: heading(3)
3558
+ },
3559
+ {
3560
+ tag: tags.heading4,
3561
+ class: heading(4)
3562
+ },
3563
+ {
3564
+ tag: tags.heading5,
3565
+ class: heading(5)
3566
+ },
3567
+ {
3568
+ tag: tags.heading6,
3569
+ class: heading(6)
3570
+ },
3571
+ // Emphasis.
3572
+ {
3573
+ tag: tags.emphasis,
3574
+ class: italic
3575
+ },
3576
+ {
3577
+ tag: tags.strong,
3578
+ class: bold
3579
+ },
3580
+ {
3581
+ tag: tags.strikethrough,
3582
+ class: strikethrough
3583
+ },
3584
+ // Naked URLs.
3585
+ {
3586
+ tag: [
3587
+ markdownTags.URL
3588
+ ],
3589
+ class: inlineUrl
3590
+ },
3591
+ // NOTE: The `markdown` extension configures extensions for `lezer` to parse markdown tokens (incl. below).
3592
+ // However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
3593
+ // when a language is specified. In this case, the syntax highlighting extensions will colorize
3594
+ // the code, but all other CSS properties will be inherited.
3595
+ // IMPORTANT: Therefore, the fenced code block will use the base editor font unless changed by an extension.
3596
+ {
3597
+ tag: [
3598
+ markdownTags.CodeText,
3599
+ markdownTags.InlineCode
3600
+ ],
3601
+ class: code
3602
+ },
3603
+ {
3604
+ tag: [
3605
+ markdownTags.QuoteMark
3606
+ ],
3607
+ class: blockquote
3608
+ },
3609
+ {
3610
+ tag: [
3611
+ markdownTags.TableCell
3612
+ ],
3613
+ class: "font-mono"
3614
+ }
3615
+ ], {
3616
+ scope: markdownLanguage2,
3617
+ all: {
3618
+ fontFamily: getToken("fontFamily.body", []).join(",")
3619
+ }
3620
+ });
3621
+ };
3622
+
3623
+ // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
3624
+ var createMarkdownExtensions = ({ themeMode } = {}) => {
3625
+ return [
3626
+ // Main extension.
3627
+ // https://github.com/codemirror/lang-markdown
3628
+ // https://codemirror.net/5/mode/markdown/index.html (demo).
3629
+ markdown({
3630
+ // GRM by default (vs strict CommonMark):
3631
+ // Table, TaskList, Strikethrough, and Autolink.
3632
+ // NOTE: This extends the parser; it doesn't affect rendering.
3633
+ // https://github.github.com/gfm
3634
+ // https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
3635
+ base: markdownLanguage3,
3636
+ // Languages for syntax highlighting fenced code blocks.
3637
+ codeLanguages: languages,
3638
+ // Parser extensions.
3639
+ extensions: [
3640
+ // GFM provided by default.
3641
+ markdownTagsExtensions
3642
+ ]
3643
+ }),
3644
+ // https://github.com/codemirror/theme-one-dark
3645
+ themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle),
3646
+ // Custom styles.
3647
+ syntaxHighlighting(markdownHighlightStyle()),
3648
+ keymap7.of([
3649
+ // https://codemirror.net/docs/ref/#commands.indentWithTab
3650
+ indentWithTab2,
3651
+ // https://codemirror.net/docs/ref/#commands.defaultKeymap
3652
+ ...defaultKeymap2,
3653
+ ...completionKeymap2,
3654
+ ...lintKeymap
3655
+ ])
3656
+ ];
3657
+ };
3658
+
3659
+ // packages/ui/react-ui-editor/src/extensions/markdown/decorate.ts
3660
+ import { syntaxTree as syntaxTree2 } from "@codemirror/language";
3661
+ import { RangeSetBuilder as RangeSetBuilder2, StateEffect as StateEffect4 } from "@codemirror/state";
3662
+ import { EditorView as EditorView12, Decoration as Decoration5, WidgetType as WidgetType3, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
3663
+ import { mx as mx2 } from "@dxos/react-ui-theme";
3664
+ var HorizontalRuleWidget = class extends WidgetType3 {
3665
+ toDOM() {
3666
+ const el = document.createElement("span");
3667
+ el.className = "cm-hr";
3668
+ return el;
3669
+ }
3670
+ };
3671
+ var LinkButton = class extends WidgetType3 {
3672
+ constructor(url, render) {
3673
+ super();
3674
+ this.url = url;
3675
+ this.render = render;
3676
+ }
3677
+ eq(other) {
3678
+ return this.url === other.url;
3679
+ }
3680
+ toDOM(view) {
3681
+ const el = document.createElement("span");
3682
+ this.render(el, this.url);
3683
+ return el;
3625
3684
  }
3626
- const changes = ranges.map(({ from, to }) => {
3627
- const column = from - state2.doc.lineAt(from).from;
3628
- return [
3629
- {
3630
- from,
3631
- insert: "```\n" + " ".repeat(column)
3632
- },
3633
- {
3634
- from: to,
3635
- insert: "\n" + " ".repeat(column) + "```"
3636
- }
3637
- ];
3638
- });
3639
- dispatch(state2.update({
3640
- changes,
3641
- userEvent: "format.codeblock.add",
3642
- scrollIntoView: true
3643
- }));
3644
- return true;
3645
3685
  };
3646
- var removeCodeblock = ({ state: state2, dispatch }) => {
3647
- const changes = [];
3648
- let lastBlock = -1;
3649
- for (const { from, to } of state2.selection.ranges) {
3650
- syntaxTree2(state2).iterate({
3651
- from,
3652
- to,
3653
- enter: (node) => {
3654
- if (Textblocks[node.name] === "codeblock" && lastBlock !== node.from) {
3655
- lastBlock = node.from;
3656
- const firstLine = state2.doc.lineAt(node.from);
3657
- if (node.name === "FencedCode") {
3658
- changes.push({
3659
- from: node.from,
3660
- to: firstLine.to + 1 + node.from - firstLine.from
3661
- });
3662
- const lastLine = state2.doc.lineAt(node.to);
3663
- if (/^([\s>]|[-*+] |\d+[).])*`+$/.test(lastLine.text)) {
3664
- changes.push({
3665
- from: lastLine.from - (lastLine.number === firstLine.number + 1 ? 0 : 1),
3666
- to: lastLine.to
3667
- });
3668
- }
3669
- } else {
3670
- const column = node.from - firstLine.from;
3671
- for (let line = firstLine; ; line = state2.doc.line(line.number + 1)) {
3672
- changes.push({
3673
- from: line.from + column - 4,
3674
- to: line.from + column
3675
- });
3676
- if (line.to >= node.to) {
3677
- break;
3678
- }
3686
+ var CheckboxWidget = class extends WidgetType3 {
3687
+ constructor(_checked) {
3688
+ super();
3689
+ this._checked = _checked;
3690
+ }
3691
+ eq(other) {
3692
+ return this._checked === other._checked;
3693
+ }
3694
+ toDOM(view) {
3695
+ const input = document.createElement("input");
3696
+ input.className = "cm-task-checkbox ch-checkbox ch-focus-ring -mbs-0.5";
3697
+ input.type = "checkbox";
3698
+ input.checked = this._checked;
3699
+ if (view.state.readOnly) {
3700
+ input.setAttribute("disabled", "true");
3701
+ } else {
3702
+ input.onmousedown = (event) => {
3703
+ const pos = view.posAtDOM(input);
3704
+ const text = view.state.sliceDoc(pos, pos + 3);
3705
+ if (text === (this._checked ? "[x]" : "[ ]")) {
3706
+ view.dispatch({
3707
+ changes: {
3708
+ from: pos + 1,
3709
+ to: pos + 2,
3710
+ insert: this._checked ? " " : "x"
3679
3711
  }
3680
- }
3712
+ });
3713
+ event.preventDefault();
3681
3714
  }
3682
- }
3683
- });
3715
+ };
3716
+ }
3717
+ return input;
3684
3718
  }
3685
- if (!changes.length) {
3719
+ ignoreEvent() {
3686
3720
  return false;
3687
3721
  }
3688
- dispatch(state2.update({
3689
- changes,
3690
- userEvent: "format.codeblock.remove",
3691
- scrollIntoView: true
3692
- }));
3693
- return true;
3694
- };
3695
- var toggleCodeblock = (target) => {
3696
- return (getFormatting(target.state).blockType === "codeblock" ? removeCodeblock : addCodeblock)(target);
3697
- };
3698
- var formattingKeymap = (options = {}) => {
3699
- return [
3700
- keymap7.of([
3701
- {
3702
- key: "meta-b",
3703
- run: toggleStrong
3704
- }
3705
- ])
3706
- ];
3707
3722
  };
3708
- var InlineMarker = {
3709
- Emphasis: 1,
3710
- StrongEmphasis: 0,
3711
- InlineCode: 3,
3712
- Strikethrough: 2
3723
+ var hide = Decoration5.replace({});
3724
+ var fencedCodeLine = Decoration5.line({
3725
+ class: mx2("cm-code cm-codeblock-line")
3726
+ });
3727
+ var fencedCodeLineFirst = Decoration5.line({
3728
+ class: mx2("cm-code cm-codeblock-line", "cm-codeblock-first")
3729
+ });
3730
+ var fencedCodeLineLast = Decoration5.line({
3731
+ class: mx2("cm-code cm-codeblock-line", "cm-codeblock-last")
3732
+ });
3733
+ var horizontalRule = Decoration5.replace({
3734
+ widget: new HorizontalRuleWidget()
3735
+ });
3736
+ var checkedTask = Decoration5.replace({
3737
+ widget: new CheckboxWidget(true)
3738
+ });
3739
+ var uncheckedTask = Decoration5.replace({
3740
+ widget: new CheckboxWidget(false)
3741
+ });
3742
+ var editingRange = (state2, range, focus) => {
3743
+ const { readOnly, selection: { main: { head } } } = state2;
3744
+ return focus && !readOnly && head >= range.from && head <= range.to;
3713
3745
  };
3714
- var IgnoreInline = /* @__PURE__ */ new Set([
3715
- "Autolink",
3746
+ var MarksByParent = /* @__PURE__ */ new Set([
3716
3747
  "CodeMark",
3717
- "CodeText",
3718
- "Comment",
3719
3748
  "EmphasisMark",
3720
- "Hardbreak",
3721
- "HeaderMark",
3722
- "HTMLTag",
3723
- "LinkMark",
3724
- "ListMark",
3725
- "ProcessingInstruction",
3726
- "QuoteMark",
3727
- "StrikethroughMark",
3728
- "SubscriptMark",
3729
- "SuperscriptMark",
3730
- "TaskMarker"
3731
- ]);
3732
- var Textblocks = {
3733
- ATXHeading1: "heading1",
3734
- ATXHeading2: "heading2",
3735
- ATXHeading3: "heading3",
3736
- ATXHeading4: "heading4",
3737
- ATXHeading5: "heading5",
3738
- ATXHeading6: "heading6",
3739
- CodeBlock: "codeblock",
3740
- FencedCode: "codeblock",
3741
- Paragraph: "paragraph",
3742
- SetextHeading1: "heading1",
3743
- SetextHeading2: "heading2",
3744
- TableCell: "tablecell",
3745
- Task: "paragraph"
3746
- };
3747
- var getFormatting = (state2) => {
3748
- let blockType = null;
3749
- const inline = [
3750
- null,
3751
- null,
3752
- null,
3753
- null
3754
- ];
3755
- let link = false;
3756
- let blockQuote = null;
3757
- let listStyle = null;
3758
- const stack = [];
3759
- let currentBlock = null;
3760
- const advanceInline = (upto) => {
3761
- if (!currentBlock) {
3762
- return;
3763
- }
3764
- upto = Math.min(upto, currentBlock.end);
3765
- if (upto <= currentBlock.pos) {
3766
- return;
3767
- }
3768
- for (let i = 0; i < currentBlock.active.length; i++) {
3769
- if (inline[i] === false) {
3770
- continue;
3771
- } else if (currentBlock.active[i]) {
3772
- inline[i] = true;
3773
- } else if (/\S/.test(state2.doc.sliceString(currentBlock.pos, upto))) {
3774
- inline[i] = false;
3775
- }
3776
- }
3777
- currentBlock.pos = upto;
3778
- };
3779
- const skipInline = (upto) => {
3780
- if (currentBlock && upto > currentBlock.pos) {
3781
- currentBlock.pos = Math.min(upto, currentBlock.end);
3782
- }
3783
- };
3784
- const { selection } = state2;
3785
- for (const range of selection.ranges) {
3786
- if (range.empty && inline.some((v) => v === null)) {
3787
- const contextSize = Math.min(range.head, 6);
3788
- const contextBefore = state2.doc.sliceString(range.head - contextSize, range.head);
3789
- let contextAfter = state2.doc.sliceString(range.head, range.head + contextSize);
3790
- for (let i = 0; i < contextSize; i++) {
3791
- const ch = contextAfter[i];
3792
- if (ch !== contextBefore[contextBefore.length - 1 - i] || !/[~`*]/.test(ch)) {
3793
- contextAfter = contextAfter.slice(0, i);
3794
- break;
3795
- }
3796
- }
3797
- for (let i = 0; i < inline.length; i++) {
3798
- const mark2 = inlineMarkerText(i);
3799
- const found = contextAfter.indexOf(mark2);
3800
- if (found > -1) {
3801
- contextAfter = contextAfter.slice(0, found) + contextAfter.slice(found + mark2.length);
3802
- if (inline[i] === null) {
3803
- inline[i] = true;
3804
- }
3805
- }
3806
- }
3807
- }
3808
- syntaxTree2(state2).iterate({
3809
- from: range.from,
3810
- to: range.to,
3811
- enter: (node) => {
3812
- advanceInline(node.from);
3813
- const { name } = node;
3814
- if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
3815
- stack.push(name);
3816
- } else if (name === "Link") {
3817
- link = true;
3818
- } else if (Object.hasOwn(Textblocks, name) && (range.empty || node.to > range.from || node.from < range.to)) {
3819
- if (name === "Task" && stack[stack.length - 1] === "BulletList") {
3820
- stack[stack.length - 1] = "TaskList";
3821
- }
3822
- const blockCode = Textblocks[name];
3823
- if (blockType === null) {
3824
- blockType = blockCode;
3825
- } else if (blockType !== blockCode) {
3826
- blockType = false;
3749
+ "StrikethroughMark",
3750
+ "SubscriptMark",
3751
+ "SuperscriptMark"
3752
+ ]);
3753
+ var buildDecorations = (view, options, focus) => {
3754
+ const deco = new RangeSetBuilder2();
3755
+ const atomicDeco = new RangeSetBuilder2();
3756
+ const { state: state2 } = view;
3757
+ for (const { from, to } of view.visibleRanges) {
3758
+ syntaxTree2(state2).iterate({
3759
+ from,
3760
+ to,
3761
+ enter: (node) => {
3762
+ if (node.name === "FencedCode") {
3763
+ const editing = editingRange(state2, node, focus);
3764
+ for (const block of view.viewportLineBlocks) {
3765
+ if (block.to < node.from) {
3766
+ continue;
3767
+ }
3768
+ if (block.from > node.to) {
3769
+ break;
3770
+ }
3771
+ const first = block.from <= node.from;
3772
+ const last = block.to >= node.to && /^(\s>)*```$/.test(state2.doc.sliceString(block.from, block.to));
3773
+ deco.add(block.from, block.from, first ? fencedCodeLineFirst : last ? fencedCodeLineLast : fencedCodeLine);
3774
+ if (!editing && (first || last)) {
3775
+ atomicDeco.add(block.from, block.to, hide);
3776
+ }
3827
3777
  }
3828
- if (blockCode !== "codeblock" && inline.some((i) => i !== false)) {
3829
- currentBlock = {
3830
- pos: Math.max(range.from, node.from),
3831
- end: Math.min(range.to, node.to),
3832
- active: [
3833
- false,
3834
- false,
3835
- false,
3836
- false
3837
- ]
3838
- };
3778
+ return false;
3779
+ } else if (node.name === "Link") {
3780
+ const marks = node.node.getChildren("LinkMark");
3781
+ const urlNode = node.node.getChild("URL");
3782
+ const editing = editingRange(state2, node, focus);
3783
+ if (urlNode && marks.length >= 2) {
3784
+ const url = state2.sliceDoc(urlNode.from, urlNode.to);
3785
+ if (!editing) {
3786
+ atomicDeco.add(node.from, marks[0].to, hide);
3787
+ }
3788
+ deco.add(marks[0].to, marks[1].from, Decoration5.mark({
3789
+ tagName: "a",
3790
+ attributes: {
3791
+ class: "cm-link",
3792
+ href: url,
3793
+ rel: "noreferrer",
3794
+ target: "_blank"
3795
+ }
3796
+ }));
3797
+ if (!editing) {
3798
+ atomicDeco.add(marks[1].from, node.to, options.renderLinkButton ? Decoration5.replace({
3799
+ widget: new LinkButton(url, options.renderLinkButton)
3800
+ }) : hide);
3801
+ }
3839
3802
  }
3840
- } else if (Object.hasOwn(InlineMarker, name) && currentBlock) {
3841
- const index = InlineMarker[name];
3842
- if (range.empty && inline[index] === null) {
3843
- inline[index] = true;
3803
+ } else if (node.name === "HeaderMark") {
3804
+ const parent = node.node.parent;
3805
+ if (/^ATX/.test(parent.name) && !editingRange(state2, state2.doc.lineAt(node.from), focus)) {
3806
+ const next = state2.doc.sliceString(node.to, node.to + 1);
3807
+ atomicDeco.add(node.from, node.to + (next === " " ? 1 : 0), hide);
3844
3808
  }
3845
- currentBlock.active[index] = true;
3846
- } else if (IgnoreInline.has(name)) {
3847
- skipInline(node.to);
3848
- }
3849
- },
3850
- leave: (node) => {
3851
- advanceInline(node.to);
3852
- const { name } = node;
3853
- if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
3854
- stack.pop();
3855
- } else if (Object.hasOwn(Textblocks, name)) {
3856
- let hasList = false;
3857
- let hasQuote = false;
3858
- for (let i = stack.length - 1; i >= 0; i--) {
3859
- if (stack[i] === "Blockquote") {
3860
- hasQuote = true;
3861
- } else if (!hasList) {
3862
- hasList = stack[i] === "TaskList" ? "task" : stack[i] === "BulletList" ? "bullet" : "ordered";
3863
- }
3809
+ } else if (node.name === "HorizontalRule") {
3810
+ if (!editingRange(state2, node, focus)) {
3811
+ deco.add(node.from, node.to, horizontalRule);
3864
3812
  }
3865
- if (blockQuote === null) {
3866
- blockQuote = hasQuote;
3867
- } else if (!hasQuote && blockQuote) {
3868
- blockQuote = false;
3813
+ } else if (node.name === "TaskMarker") {
3814
+ if (!editingRange(state2, node, focus)) {
3815
+ const checked = state2.doc.sliceString(node.from + 1, node.to - 1) === "x";
3816
+ atomicDeco.add(node.from - 2, node.from - 1, Decoration5.mark({
3817
+ class: "cm-task"
3818
+ }));
3819
+ atomicDeco.add(node.from, node.to, checked ? checkedTask : uncheckedTask);
3869
3820
  }
3870
- if (listStyle === null) {
3871
- listStyle = hasList;
3872
- } else if (listStyle !== hasList) {
3873
- listStyle = false;
3821
+ } else if (MarksByParent.has(node.name)) {
3822
+ if (!editingRange(state2, node.node.parent, focus)) {
3823
+ atomicDeco.add(node.from, node.to, hide);
3874
3824
  }
3875
- currentBlock = null;
3876
- } else if (Object.hasOwn(InlineMarker, name) && currentBlock) {
3877
- currentBlock.active[InlineMarker[name]] = false;
3878
3825
  }
3879
3826
  }
3880
3827
  });
3881
3828
  }
3882
- const { from, to } = state2.doc.lineAt(selection.main.anchor);
3883
- const blankLine = from === to;
3884
3829
  return {
3885
- blankLine,
3886
- blockType: blockType || null,
3887
- blockQuote: blockQuote ?? false,
3888
- code: inline[3] ?? false,
3889
- emphasis: inline[1] ?? false,
3890
- strong: inline[0] ?? false,
3891
- strikethrough: inline[2] ?? false,
3892
- link,
3893
- listStyle: listStyle || null
3830
+ deco: deco.finish(),
3831
+ atomicDeco: atomicDeco.finish()
3894
3832
  };
3895
3833
  };
3896
- var useFormattingState = () => {
3897
- const [state2, setState] = useState();
3898
- const observer = useMemo(() => EditorView13.updateListener.of((update2) => {
3899
- if (update2.docChanged || update2.selectionSet) {
3900
- setState((prevState) => {
3901
- const newState = getFormatting(update2.state);
3902
- if (!prevState || !formattingEquals(prevState, newState)) {
3903
- return newState;
3904
- }
3905
- return prevState;
3906
- });
3907
- }
3908
- }), [
3909
- setState
3910
- ]);
3834
+ var forceUpdate = StateEffect4.define();
3835
+ var decorateMarkdown = (options = {}) => {
3911
3836
  return [
3912
- state2,
3913
- observer
3837
+ ViewPlugin4.fromClass(class {
3838
+ constructor(view) {
3839
+ ({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations(view, options, view.hasFocus));
3840
+ }
3841
+ update(update2) {
3842
+ if (update2.docChanged || update2.viewportChanged || update2.focusChanged || update2.transactions.some((tr) => tr.effects.some((e) => e.is(forceUpdate))) || update2.selectionSet && !options.selectionChangeDelay) {
3843
+ ({ deco: this.deco, atomicDeco: this.atomicDeco } = buildDecorations(update2.view, options, update2.view.hasFocus));
3844
+ this.clearUpdate();
3845
+ } else if (update2.selectionSet) {
3846
+ this.scheduleUpdate(update2.view);
3847
+ }
3848
+ }
3849
+ // TODO(burdon): BUG: If the cursor is at the end of a link at the end of a line,
3850
+ // the cursor will float in space or be in the wrong position after the decoration is applied.
3851
+ scheduleUpdate(view) {
3852
+ this.clearUpdate();
3853
+ this.pendingUpdate = setTimeout(() => {
3854
+ view.dispatch({
3855
+ effects: forceUpdate.of(null)
3856
+ });
3857
+ }, options.selectionChangeDelay);
3858
+ }
3859
+ clearUpdate() {
3860
+ if (this.pendingUpdate) {
3861
+ clearTimeout(this.pendingUpdate);
3862
+ this.pendingUpdate = void 0;
3863
+ }
3864
+ }
3865
+ destroy() {
3866
+ this.clearUpdate();
3867
+ }
3868
+ }, {
3869
+ provide: (plugin) => [
3870
+ EditorView12.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration5.none),
3871
+ EditorView12.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration5.none),
3872
+ EditorView12.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration5.none)
3873
+ ]
3874
+ }),
3875
+ formattingStyles
3914
3876
  ];
3915
3877
  };
3878
+ var formattingStyles = EditorView12.baseTheme({
3879
+ "& .cm-code": {
3880
+ fontFamily: getToken("fontFamily.mono", []).join(",")
3881
+ },
3882
+ "& .cm-codeblock-line": {
3883
+ paddingInline: "1rem !important"
3884
+ },
3885
+ "& .cm-codeblock-end": {
3886
+ display: "inline-block",
3887
+ width: "100%",
3888
+ position: "relative",
3889
+ "&::after": {
3890
+ position: "absolute",
3891
+ inset: 0,
3892
+ content: '""'
3893
+ }
3894
+ },
3895
+ "& .cm-codeblock-first": {
3896
+ borderTopLeftRadius: ".5rem",
3897
+ borderTopRightRadius: ".5rem"
3898
+ },
3899
+ "& .cm-codeblock-last": {
3900
+ borderBottomLeftRadius: ".5rem",
3901
+ borderBottomRightRadius: ".5rem"
3902
+ },
3903
+ "&light .cm-codeblock-line, &light .cm-activeLine.cm-codeblock-line": {
3904
+ background: getToken("extend.semanticColors.input.light"),
3905
+ mixBlendMode: "darken"
3906
+ },
3907
+ "&dark .cm-codeblock-line, &dark .cm-activeLine.cm-codeblock-line": {
3908
+ background: getToken("extend.semanticColors.input.dark"),
3909
+ mixBlendMode: "lighten"
3910
+ },
3911
+ "& .cm-hr": {
3912
+ display: "inline-block",
3913
+ width: "100%",
3914
+ height: "0",
3915
+ verticalAlign: "middle",
3916
+ borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
3917
+ },
3918
+ "& .cm-task": {
3919
+ color: getToken("extend.colors.blue.500")
3920
+ },
3921
+ "& .cm-task-checkbox": {
3922
+ marginLeft: "4px",
3923
+ marginRight: "4px"
3924
+ }
3925
+ });
3916
3926
 
3917
3927
  // packages/ui/react-ui-editor/src/extensions/markdown/image.ts
3918
3928
  import { syntaxTree as syntaxTree3 } from "@codemirror/language";
3919
3929
  import { StateField as StateField5 } from "@codemirror/state";
3920
- import { Decoration as Decoration6, EditorView as EditorView14, WidgetType as WidgetType4 } from "@codemirror/view";
3930
+ import { Decoration as Decoration6, EditorView as EditorView13, WidgetType as WidgetType4 } from "@codemirror/view";
3921
3931
  var image = (options = {}) => {
3922
3932
  return StateField5.define({
3923
3933
  create: (state2) => {
@@ -3944,7 +3954,7 @@ var image = (options = {}) => {
3944
3954
  add: buildDecorations2(from, to, tr.state)
3945
3955
  });
3946
3956
  },
3947
- provide: (field) => EditorView14.decorations.from(field)
3957
+ provide: (field) => EditorView13.decorations.from(field)
3948
3958
  });
3949
3959
  };
3950
3960
  var preloaded = /* @__PURE__ */ new Set();
@@ -4034,12 +4044,12 @@ var linkTooltip = (render) => hoverTooltip2((view, pos, side) => {
4034
4044
  // packages/ui/react-ui-editor/src/extensions/markdown/table.ts
4035
4045
  import { syntaxTree as syntaxTree5 } from "@codemirror/language";
4036
4046
  import { RangeSetBuilder as RangeSetBuilder3, StateField as StateField6 } from "@codemirror/state";
4037
- import { Decoration as Decoration7, EditorView as EditorView15, WidgetType as WidgetType5 } from "@codemirror/view";
4047
+ import { Decoration as Decoration7, EditorView as EditorView14, WidgetType as WidgetType5 } from "@codemirror/view";
4038
4048
  var table = (options = {}) => {
4039
4049
  return StateField6.define({
4040
4050
  create: (state2) => update(state2, options),
4041
4051
  update: (_, tr) => update(tr.state, options),
4042
- provide: (field) => EditorView15.decorations.from(field)
4052
+ provide: (field) => EditorView14.decorations.from(field)
4043
4053
  });
4044
4054
  };
4045
4055
  var update = (state2, options) => {
@@ -4133,8 +4143,8 @@ var TableWidget = class extends WidgetType5 {
4133
4143
 
4134
4144
  // packages/ui/react-ui-editor/src/extensions/mention.ts
4135
4145
  import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
4136
- import { log as log8 } from "@dxos/log";
4137
- var __dxlog_file10 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/mention.ts";
4146
+ import { log as log6 } from "@dxos/log";
4147
+ var __dxlog_file8 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/mention.ts";
4138
4148
  var mention = ({ onSearch }) => {
4139
4149
  return autocompletion2({
4140
4150
  // TODO(burdon): Not working.
@@ -4146,10 +4156,10 @@ var mention = ({ onSearch }) => {
4146
4156
  icons: false,
4147
4157
  override: [
4148
4158
  (context) => {
4149
- log8.info("completion context", {
4159
+ log6.info("completion context", {
4150
4160
  context
4151
4161
  }, {
4152
- F: __dxlog_file10,
4162
+ F: __dxlog_file8,
4153
4163
  L: 26,
4154
4164
  S: void 0,
4155
4165
  C: (f, a) => f(...a)
@@ -4209,18 +4219,18 @@ var EditorModes = {
4209
4219
  };
4210
4220
 
4211
4221
  // packages/ui/react-ui-editor/src/extensions/state.ts
4212
- import { Transaction as Transaction2 } from "@codemirror/state";
4213
- import { EditorView as EditorView16, keymap as keymap9 } from "@codemirror/view";
4222
+ import { Transaction } from "@codemirror/state";
4223
+ import { EditorView as EditorView15, keymap as keymap9 } from "@codemirror/view";
4214
4224
  import { debounce as debounce2 } from "@dxos/async";
4215
4225
  import { invariant as invariant4 } from "@dxos/invariant";
4216
4226
  import { isNotFalsy as isNotFalsy3 } from "@dxos/util";
4217
- var __dxlog_file11 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/state.ts";
4227
+ var __dxlog_file9 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/state.ts";
4218
4228
  var scrollAnnotation = "dxos.org/cm/scrolling";
4219
4229
  var keyPrefix = "dxos.org/react-ui-editor/state";
4220
4230
  var localStorageStateStoreAdapter = {
4221
4231
  setState: (id, state2) => {
4222
4232
  invariant4(id, void 0, {
4223
- F: __dxlog_file11,
4233
+ F: __dxlog_file9,
4224
4234
  L: 35,
4225
4235
  S: void 0,
4226
4236
  A: [
@@ -4232,7 +4242,7 @@ var localStorageStateStoreAdapter = {
4232
4242
  },
4233
4243
  getState: (id) => {
4234
4244
  invariant4(id, void 0, {
4235
- F: __dxlog_file11,
4245
+ F: __dxlog_file9,
4236
4246
  L: 39,
4237
4247
  S: void 0,
4238
4248
  A: [
@@ -4248,7 +4258,7 @@ var state = ({ getState, setState } = {}) => {
4248
4258
  const setStateDebounced = debounce2(setState, 1e3);
4249
4259
  return [
4250
4260
  // TODO(burdon): Track scrolling (currently only updates when cursor moves).
4251
- EditorView16.updateListener.of(({ view, changes, transactions }) => {
4261
+ EditorView15.updateListener.of(({ view, changes, transactions }) => {
4252
4262
  const id = view.state.facet(documentId2);
4253
4263
  if (!id || transactions.some((tr) => tr.isUserEvent(scrollAnnotation))) {
4254
4264
  return;
@@ -4281,11 +4291,11 @@ var state = ({ getState, setState } = {}) => {
4281
4291
  const state2 = getState(view.state.facet(documentId2));
4282
4292
  if (state2) {
4283
4293
  view.dispatch({
4284
- effects: EditorView16.scrollIntoView(state2.scrollTo.from, {
4294
+ effects: EditorView15.scrollIntoView(state2.scrollTo.from, {
4285
4295
  yMargin: 0
4286
4296
  }),
4287
4297
  selection: state2.selection,
4288
- annotations: Transaction2.userEvent.of(scrollAnnotation)
4298
+ annotations: Transaction.userEvent.of(scrollAnnotation)
4289
4299
  });
4290
4300
  }
4291
4301
  return true;
@@ -4353,9 +4363,9 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
4353
4363
  };
4354
4364
 
4355
4365
  // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
4356
- var __dxlog_file12 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
4366
+ var __dxlog_file10 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
4357
4367
  var instanceCount = 0;
4358
- var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, className, autoFocus, scrollTo = EditorView17.scrollIntoView(0, {
4368
+ var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, className, autoFocus, scrollTo = EditorView16.scrollIntoView(0, {
4359
4369
  yMargin: 0
4360
4370
  }), moveToEndOfLine, debug, dataTestId }, forwardedRef) => {
4361
4371
  const [instanceId] = useState2(() => `text-editor-${++instanceCount}`);
@@ -4376,11 +4386,11 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, c
4376
4386
  autoFocus
4377
4387
  ]);
4378
4388
  useEffect2(() => {
4379
- log9("create", {
4389
+ log7("create", {
4380
4390
  id,
4381
4391
  instanceId
4382
4392
  }, {
4383
- F: __dxlog_file12,
4393
+ F: __dxlog_file10,
4384
4394
  L: 88,
4385
4395
  S: void 0,
4386
4396
  C: (f, a) => f(...a)
@@ -4391,16 +4401,16 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, c
4391
4401
  extensions: [
4392
4402
  id && documentId2.of(id),
4393
4403
  // TODO(burdon): NOTE: Doesn't catch errors in keymap functions.
4394
- EditorView17.exceptionSink.of((err) => {
4395
- log9.catch(err, void 0, {
4396
- F: __dxlog_file12,
4404
+ EditorView16.exceptionSink.of((err) => {
4405
+ log7.catch(err, void 0, {
4406
+ F: __dxlog_file10,
4397
4407
  L: 101,
4398
4408
  S: void 0,
4399
4409
  C: (f, a) => f(...a)
4400
4410
  });
4401
4411
  }),
4402
4412
  // Focus.
4403
- EditorView17.updateListener.of((update2) => {
4413
+ EditorView16.updateListener.of((update2) => {
4404
4414
  update2.transactions.forEach((transaction) => {
4405
4415
  if (transaction.isUserEvent(focusEvent)) {
4406
4416
  rootRef.current?.focus();
@@ -4410,7 +4420,7 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, c
4410
4420
  extensions
4411
4421
  ].filter(isNotFalsy4)
4412
4422
  });
4413
- const view2 = new EditorView17({
4423
+ const view2 = new EditorView16({
4414
4424
  state: state2,
4415
4425
  parent: rootRef.current,
4416
4426
  scrollTo,
@@ -4436,11 +4446,11 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ id, doc, selection, extensions, c
4436
4446
  }
4437
4447
  setView(view2);
4438
4448
  return () => {
4439
- log9("destroy", {
4449
+ log7("destroy", {
4440
4450
  id,
4441
4451
  instanceId
4442
4452
  }, {
4443
- F: __dxlog_file12,
4453
+ F: __dxlog_file10,
4444
4454
  L: 150,
4445
4455
  S: void 0,
4446
4456
  C: (f, a) => f(...a)
@@ -4746,7 +4756,7 @@ var MarkdownCustom = ({ onUpload } = {}) => {
4746
4756
  });
4747
4757
  useEffect3(() => {
4748
4758
  if (onUpload && acceptedFiles.length) {
4749
- setTimeout(async () => {
4759
+ requestAnimationFrame(async () => {
4750
4760
  const f = acceptedFiles[0];
4751
4761
  const file = new File([
4752
4762
  f
@@ -4795,56 +4805,7 @@ var Toolbar = {
4795
4805
 
4796
4806
  // packages/ui/react-ui-editor/src/hooks/useActionHandler.ts
4797
4807
  var useActionHandler = (view) => {
4798
- return (action) => {
4799
- if (!view) {
4800
- return;
4801
- }
4802
- let inlineType, listType;
4803
- switch (action.type) {
4804
- case "heading":
4805
- setHeading(parseInt(action.data))(view);
4806
- break;
4807
- case "strong":
4808
- case "emphasis":
4809
- case "strikethrough":
4810
- case "code":
4811
- inlineType = action.type === "strong" ? Inline.Strong : action.type === "emphasis" ? Inline.Emphasis : action.type === "strikethrough" ? Inline.Strikethrough : Inline.Code;
4812
- (typeof action.data === "boolean" ? setStyle(inlineType, action.data) : toggleStyle(inlineType))(view);
4813
- break;
4814
- case "list-ordered":
4815
- case "list-bullet":
4816
- case "list-task":
4817
- listType = action.type === "list-ordered" ? List.Ordered : action.type === "list-bullet" ? List.Bullet : List.Task;
4818
- (action.data === false ? removeList(listType) : action.data === true ? addList(listType) : toggleList(listType))(view);
4819
- break;
4820
- case "blockquote":
4821
- (action.data === false ? removeBlockquote : action.data === true ? addBlockquote : toggleBlockquote)(view);
4822
- break;
4823
- case "codeblock":
4824
- (action.data === false ? removeCodeblock : addCodeblock)(view);
4825
- break;
4826
- case "table":
4827
- insertTable(view);
4828
- break;
4829
- case "link":
4830
- (action.data === false ? removeLink : addLink())(view);
4831
- break;
4832
- case "image":
4833
- addLink({
4834
- url: action.data,
4835
- image: true
4836
- })(view);
4837
- break;
4838
- case "comment":
4839
- createComment(view);
4840
- break;
4841
- }
4842
- setTimeout(() => {
4843
- if (!view.hasFocus) {
4844
- view.focus();
4845
- }
4846
- });
4847
- };
4808
+ return (action) => view && processAction(view, action);
4848
4809
  };
4849
4810
 
4850
4811
  // packages/ui/react-ui-editor/src/hooks/useDocAccessor.ts
@@ -4862,11 +4823,11 @@ var useDocAccessor = (text) => {
4862
4823
 
4863
4824
  // packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
4864
4825
  import { EditorSelection as EditorSelection2, EditorState as EditorState3 } from "@codemirror/state";
4865
- import { EditorView as EditorView18 } from "@codemirror/view";
4826
+ import { EditorView as EditorView17 } from "@codemirror/view";
4866
4827
  import { useEffect as useEffect4, useMemo as useMemo3, useRef as useRef3, useState as useState4 } from "react";
4867
- import { log as log10 } from "@dxos/log";
4828
+ import { log as log8 } from "@dxos/log";
4868
4829
  import { isNotFalsy as isNotFalsy5 } from "@dxos/util";
4869
- var __dxlog_file13 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
4830
+ var __dxlog_file11 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
4870
4831
  var useTextEditor = (cb = () => ({}), deps = []) => {
4871
4832
  let { id, doc, selection, extensions, autoFocus, scrollTo, debug } = useMemo3(cb, deps ?? []);
4872
4833
  const onUpdate = useRef3();
@@ -4875,10 +4836,10 @@ var useTextEditor = (cb = () => ({}), deps = []) => {
4875
4836
  useEffect4(() => {
4876
4837
  let view2;
4877
4838
  if (parentRef.current) {
4878
- log10("create", {
4839
+ log8("create", {
4879
4840
  id
4880
4841
  }, {
4881
- F: __dxlog_file13,
4842
+ F: __dxlog_file11,
4882
4843
  L: 36,
4883
4844
  S: void 0,
4884
4845
  C: (f, a) => f(...a)
@@ -4889,21 +4850,21 @@ var useTextEditor = (cb = () => ({}), deps = []) => {
4889
4850
  extensions: [
4890
4851
  id && documentId2.of(id),
4891
4852
  // TODO(burdon): Doesn't catch errors in keymap functions.
4892
- EditorView18.exceptionSink.of((err) => {
4893
- log10.catch(err, void 0, {
4894
- F: __dxlog_file13,
4853
+ EditorView17.exceptionSink.of((err) => {
4854
+ log8.catch(err, void 0, {
4855
+ F: __dxlog_file11,
4895
4856
  L: 46,
4896
4857
  S: void 0,
4897
4858
  C: (f, a) => f(...a)
4898
4859
  });
4899
4860
  }),
4900
4861
  extensions,
4901
- EditorView18.updateListener.of(() => {
4862
+ EditorView17.updateListener.of(() => {
4902
4863
  onUpdate.current?.();
4903
4864
  })
4904
4865
  ].filter(isNotFalsy5)
4905
4866
  });
4906
- view2 = new EditorView18({
4867
+ view2 = new EditorView17({
4907
4868
  parent: parentRef.current,
4908
4869
  scrollTo,
4909
4870
  state: state2,
@@ -4919,10 +4880,10 @@ var useTextEditor = (cb = () => ({}), deps = []) => {
4919
4880
  setView(view2);
4920
4881
  }
4921
4882
  return () => {
4922
- log10("destroy", {
4883
+ log8("destroy", {
4923
4884
  id
4924
4885
  }, {
4925
- F: __dxlog_file13,
4886
+ F: __dxlog_file11,
4926
4887
  L: 74,
4927
4888
  S: void 0,
4928
4889
  C: (f, a) => f(...a)
@@ -4994,12 +4955,11 @@ export {
4994
4955
  createDataExtensions,
4995
4956
  createMarkdownExtensions,
4996
4957
  createThemeExtensions,
4997
- cursorLineMargin,
4998
4958
  decorateMarkdown,
4999
4959
  defaultOptions,
5000
4960
  defaultTheme,
5001
- dnd,
5002
4961
  documentId2 as documentId,
4962
+ dropFile,
5003
4963
  editorFillLayoutEditor,
5004
4964
  editorFillLayoutRoot,
5005
4965
  editorMode,
@@ -5022,6 +4982,7 @@ export {
5022
4982
  markdownTags,
5023
4983
  markdownTagsExtensions,
5024
4984
  mention,
4985
+ processAction,
5025
4986
  removeBlockquote,
5026
4987
  removeCodeblock,
5027
4988
  removeLink,