@dxos/react-ui-editor 0.4.5-main.7620b9e → 0.4.5-main.8fa80ca

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 (37) hide show
  1. package/dist/lib/browser/index.mjs +358 -530
  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/MarkdownEditor.stories.d.ts +5 -5
  5. package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
  6. package/dist/types/src/components/TextEditor/hooks.stories.d.ts.map +1 -1
  7. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
  8. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -1
  9. package/dist/types/src/extensions/markdown/decorate.d.ts +5 -0
  10. package/dist/types/src/extensions/markdown/decorate.d.ts.map +1 -0
  11. package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -1
  12. package/dist/types/src/extensions/markdown/index.d.ts +1 -4
  13. package/dist/types/src/extensions/markdown/index.d.ts.map +1 -1
  14. package/dist/types/src/extensions/markdown/link.d.ts +1 -11
  15. package/dist/types/src/extensions/markdown/link.d.ts.map +1 -1
  16. package/package.json +28 -25
  17. package/src/components/TextEditor/MarkdownEditor.stories.tsx +29 -37
  18. package/src/components/TextEditor/hooks.stories.tsx +2 -10
  19. package/src/components/Toolbar/Toolbar.stories.tsx +2 -6
  20. package/src/components/Toolbar/Toolbar.tsx +0 -1
  21. package/src/extensions/markdown/decorate.ts +301 -0
  22. package/src/extensions/markdown/formatting.test.ts +17 -0
  23. package/src/extensions/markdown/formatting.ts +67 -76
  24. package/src/extensions/markdown/index.ts +1 -4
  25. package/src/extensions/markdown/link.ts +23 -185
  26. package/dist/types/src/extensions/markdown/code.d.ts +0 -2
  27. package/dist/types/src/extensions/markdown/code.d.ts.map +0 -1
  28. package/dist/types/src/extensions/markdown/heading.d.ts +0 -6
  29. package/dist/types/src/extensions/markdown/heading.d.ts.map +0 -1
  30. package/dist/types/src/extensions/markdown/hr.d.ts +0 -2
  31. package/dist/types/src/extensions/markdown/hr.d.ts.map +0 -1
  32. package/dist/types/src/extensions/markdown/tasklist.d.ts +0 -3
  33. package/dist/types/src/extensions/markdown/tasklist.d.ts.map +0 -1
  34. package/src/extensions/markdown/code.ts +0 -162
  35. package/src/extensions/markdown/heading.ts +0 -59
  36. package/src/extensions/markdown/hr.ts +0 -71
  37. package/src/extensions/markdown/tasklist.ts +0 -110
@@ -8,7 +8,7 @@ import { tags as tags2 } from "@lezer/highlight";
8
8
 
9
9
  // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
10
10
  import { EditorState as EditorState2 } from "@codemirror/state";
11
- import { EditorView as EditorView16 } from "@codemirror/view";
11
+ import { EditorView as EditorView14 } from "@codemirror/view";
12
12
  import { useFocusableGroup } from "@fluentui/react-tabster";
13
13
  import defaultsDeep2 from "lodash.defaultsdeep";
14
14
  import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useRef, useState as useState2, useMemo as useMemo2 } from "react";
@@ -765,10 +765,10 @@ var blast = (options = defaultOptions) => {
765
765
  const getPoint = (view, pos) => {
766
766
  const { left: x = 0, top: y = 0 } = view.coordsForChar(pos) ?? {};
767
767
  const element = document.elementFromPoint(x, y);
768
- const { offsetLeft: left = 0, offsetTop: top2 = 0 } = view.scrollDOM.parentElement ?? {};
768
+ const { offsetLeft: left = 0, offsetTop: top = 0 } = view.scrollDOM.parentElement ?? {};
769
769
  const point = {
770
770
  x: x - left,
771
- y: y - top2
771
+ y: y - top
772
772
  };
773
773
  return {
774
774
  element,
@@ -1871,12 +1871,207 @@ var createMarkdownExtensions = ({ themeMode, placeholder: _placeholder, lineWrap
1871
1871
  ].filter(isNotFalsy3);
1872
1872
  };
1873
1873
 
1874
- // packages/ui/react-ui-editor/src/extensions/markdown/code.ts
1874
+ // packages/ui/react-ui-editor/src/extensions/markdown/decorate.ts
1875
1875
  import { syntaxTree } from "@codemirror/language";
1876
1876
  import { RangeSetBuilder } from "@codemirror/state";
1877
- import { ViewPlugin as ViewPlugin3, EditorView as EditorView10, Decoration as Decoration4, WidgetType as WidgetType2 } from "@codemirror/view";
1877
+ import { EditorView as EditorView10, Decoration as Decoration4, WidgetType as WidgetType2, ViewPlugin as ViewPlugin3 } from "@codemirror/view";
1878
1878
  import { mx as mx2 } from "@dxos/react-ui-theme";
1879
- var styles4 = EditorView10.baseTheme({
1879
+ var FencedCodeBoundary = class extends WidgetType2 {
1880
+ constructor(_className) {
1881
+ super();
1882
+ this._className = _className;
1883
+ }
1884
+ toDOM() {
1885
+ const el = document.createElement("span");
1886
+ el.innerHTML = " ";
1887
+ el.className = mx2("cm-code cm-codeblock", this._className);
1888
+ return el;
1889
+ }
1890
+ };
1891
+ var HorizontalRuleWidget = class extends WidgetType2 {
1892
+ toDOM() {
1893
+ const el = document.createElement("span");
1894
+ el.className = "cm-hr";
1895
+ return el;
1896
+ }
1897
+ };
1898
+ var LinkButton = class extends WidgetType2 {
1899
+ constructor(url, render) {
1900
+ super();
1901
+ this.url = url;
1902
+ this.render = render;
1903
+ }
1904
+ eq(other) {
1905
+ return this.url === other.url;
1906
+ }
1907
+ toDOM(view) {
1908
+ const el = document.createElement("span");
1909
+ this.render(el, this.url);
1910
+ return el;
1911
+ }
1912
+ };
1913
+ var CheckboxWidget = class extends WidgetType2 {
1914
+ constructor(_checked) {
1915
+ super();
1916
+ this._checked = _checked;
1917
+ }
1918
+ eq(other) {
1919
+ return this._checked === other._checked;
1920
+ }
1921
+ toDOM(view) {
1922
+ const input = document.createElement("input");
1923
+ input.className = "cm-task-checkbox";
1924
+ input.type = "checkbox";
1925
+ input.checked = this._checked;
1926
+ if (view.state.readOnly) {
1927
+ input.setAttribute("disabled", "true");
1928
+ } else {
1929
+ input.onmousedown = (event) => {
1930
+ const pos = view.posAtDOM(input);
1931
+ const text = view.state.sliceDoc(pos, pos + 3);
1932
+ if (text === (this._checked ? "[x]" : "[ ]")) {
1933
+ view.dispatch({
1934
+ changes: {
1935
+ from: pos + 1,
1936
+ to: pos + 2,
1937
+ insert: this._checked ? " " : "x"
1938
+ }
1939
+ });
1940
+ event.preventDefault();
1941
+ }
1942
+ };
1943
+ }
1944
+ return input;
1945
+ }
1946
+ ignoreEvent() {
1947
+ return false;
1948
+ }
1949
+ };
1950
+ var hide = Decoration4.replace({});
1951
+ var fencedCodeTop = Decoration4.replace({
1952
+ widget: new FencedCodeBoundary("cm-codeblock-end cm-codeblock-first")
1953
+ });
1954
+ var fencedCodeBottom = Decoration4.replace({
1955
+ widget: new FencedCodeBoundary("cm-codeblock-end cm-codeblock-last")
1956
+ });
1957
+ var horizontalRule = Decoration4.replace({
1958
+ widget: new HorizontalRuleWidget()
1959
+ });
1960
+ var checkedTask = Decoration4.replace({
1961
+ widget: new CheckboxWidget(true)
1962
+ });
1963
+ var uncheckedTask = Decoration4.replace({
1964
+ widget: new CheckboxWidget(false)
1965
+ });
1966
+ var editingRange = (state, range) => {
1967
+ const { readOnly, selection: { main: { head } } } = state;
1968
+ return !readOnly && head >= range.from && head <= range.to;
1969
+ };
1970
+ var MarksByParent = /* @__PURE__ */ new Set([
1971
+ "CodeMark",
1972
+ "EmphasisMark",
1973
+ "StrikethroughMark",
1974
+ "SubscriptMark",
1975
+ "SuperscriptMark"
1976
+ ]);
1977
+ var buildDecorations = (view, options) => {
1978
+ const builder = new RangeSetBuilder();
1979
+ const { state } = view;
1980
+ for (const { from, to } of view.visibleRanges) {
1981
+ syntaxTree(state).iterate({
1982
+ from,
1983
+ to,
1984
+ enter: (node) => {
1985
+ if (node.name === "FencedCode") {
1986
+ const editing = editingRange(state, node);
1987
+ for (const block of view.viewportLineBlocks) {
1988
+ if (block.to < node.from) {
1989
+ continue;
1990
+ }
1991
+ if (block.from > node.to) {
1992
+ break;
1993
+ }
1994
+ const first = block.from <= node.from;
1995
+ const last = block.to >= node.to;
1996
+ if (!editing && (first || last)) {
1997
+ builder.add(block.from, block.to, first ? fencedCodeTop : fencedCodeBottom);
1998
+ } else {
1999
+ builder.add(block.from, block.from, Decoration4.line({
2000
+ class: mx2("cm-code cm-codeblock-line", first && "cm-codeblock-first", last && "cm-codeblock-last")
2001
+ }));
2002
+ }
2003
+ }
2004
+ return false;
2005
+ } else if (node.name === "Link") {
2006
+ const marks = node.node.getChildren("LinkMark");
2007
+ const urlNode = node.node.getChild("URL");
2008
+ const editing = editingRange(state, node);
2009
+ if (urlNode && marks.length >= 2) {
2010
+ const url = state.sliceDoc(urlNode.from, urlNode.to);
2011
+ if (!editing) {
2012
+ builder.add(node.from, marks[0].to, hide);
2013
+ }
2014
+ builder.add(marks[0].to, marks[1].from, Decoration4.mark({
2015
+ tagName: "a",
2016
+ attributes: {
2017
+ class: "cm-link",
2018
+ href: url,
2019
+ rel: "noreferrer",
2020
+ target: "_blank"
2021
+ }
2022
+ }));
2023
+ if (!editing) {
2024
+ builder.add(marks[1].from, node.to, options.renderLinkButton ? Decoration4.replace({
2025
+ widget: new LinkButton(url, options.renderLinkButton)
2026
+ }) : hide);
2027
+ }
2028
+ }
2029
+ } else if (node.name === "HeaderMark") {
2030
+ const parent = node.node.parent;
2031
+ if (/^ATX/.test(parent.name) && !editingRange(state, state.doc.lineAt(node.from))) {
2032
+ const next = state.doc.sliceString(node.to, node.to + 1);
2033
+ builder.add(node.from, node.to + (next === " " ? 1 : 0), hide);
2034
+ }
2035
+ } else if (node.name === "HorizontalRule") {
2036
+ if (!editingRange(state, node)) {
2037
+ builder.add(node.from, node.to, horizontalRule);
2038
+ }
2039
+ } else if (node.name === "TaskMarker") {
2040
+ if (!editingRange(state, node)) {
2041
+ const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
2042
+ builder.add(node.from - 2, node.from - 1, Decoration4.mark({
2043
+ class: "cm-task"
2044
+ }));
2045
+ builder.add(node.from, node.to, checked ? checkedTask : uncheckedTask);
2046
+ }
2047
+ } else if (MarksByParent.has(node.name)) {
2048
+ if (!editingRange(state, node.node.parent)) {
2049
+ builder.add(node.from, node.to, hide);
2050
+ }
2051
+ }
2052
+ }
2053
+ });
2054
+ }
2055
+ return builder.finish();
2056
+ };
2057
+ var decorateMarkdown = (options = {}) => {
2058
+ return [
2059
+ ViewPlugin3.fromClass(class {
2060
+ constructor(view) {
2061
+ this.decorations = buildDecorations(view, options);
2062
+ }
2063
+ update(update2) {
2064
+ if (update2.docChanged || update2.selectionSet || update2.viewportChanged) {
2065
+ this.decorations = buildDecorations(update2.view, options);
2066
+ }
2067
+ }
2068
+ }, {
2069
+ decorations: (value) => value.decorations
2070
+ }),
2071
+ formattingStyles
2072
+ ];
2073
+ };
2074
+ var formattingStyles = EditorView10.baseTheme({
1880
2075
  "& .cm-code": {
1881
2076
  fontFamily: getToken("fontFamily.mono", []).join(",")
1882
2077
  },
@@ -1924,82 +2119,28 @@ var styles4 = EditorView10.baseTheme({
1924
2119
  "&::after": {
1925
2120
  background: getToken("extend.semanticColors.input.dark")
1926
2121
  }
2122
+ },
2123
+ "& .cm-hr": {
2124
+ display: "inline-block",
2125
+ width: "100%",
2126
+ height: "0",
2127
+ verticalAlign: "middle",
2128
+ borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
2129
+ },
2130
+ "& .cm-task": {
2131
+ color: getToken("extend.colors.blue.500")
2132
+ },
2133
+ "& .cm-task-checkbox": {
2134
+ marginLeft: "4px",
2135
+ marginRight: "4px"
1927
2136
  }
1928
2137
  });
1929
- var getLineRange = (lines, from, to) => {
1930
- const start = lines.findIndex((line) => line.from >= from);
1931
- const end = lines.findIndex((line) => line.to >= to);
1932
- return [
1933
- start,
1934
- end
1935
- ];
1936
- };
1937
- var LineWidget = class extends WidgetType2 {
1938
- constructor(_className) {
1939
- super();
1940
- this._className = _className;
1941
- }
1942
- toDOM() {
1943
- const el = document.createElement("span");
1944
- el.innerHTML = "&nbsp;";
1945
- el.className = mx2("cm-code cm-codeblock", this._className);
1946
- return el;
1947
- }
1948
- };
1949
- var top = new LineWidget("cm-codeblock-end cm-codeblock-first");
1950
- var bottom = new LineWidget("cm-codeblock-end cm-codeblock-last");
1951
- var buildDecorations = (view) => {
1952
- const builder = new RangeSetBuilder();
1953
- const { state } = view;
1954
- const blocks = view.viewportLineBlocks;
1955
- const cursor = state.selection.main.head;
1956
- for (const { from, to } of view.visibleRanges) {
1957
- syntaxTree(state).iterate({
1958
- enter: (node) => {
1959
- if (node.name === "FencedCode") {
1960
- const editing = !view.state.readOnly && cursor >= node.from && cursor <= node.to;
1961
- const range = getLineRange(blocks, node.from, node.to);
1962
- for (let i = range[0]; i <= range[1]; i++) {
1963
- const block = blocks[i];
1964
- if (!editing && (i === range[0] || i === range[1])) {
1965
- builder.add(block.from, block.to, Decoration4.replace({
1966
- widget: i === range[0] ? top : bottom
1967
- }));
1968
- } else {
1969
- builder.add(block.from, block.from, Decoration4.line({
1970
- class: mx2("cm-code cm-codeblock-line", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
1971
- }));
1972
- }
1973
- }
1974
- }
1975
- },
1976
- from,
1977
- to
1978
- });
1979
- }
1980
- return builder.finish();
1981
- };
1982
- var code2 = () => {
1983
- return [
1984
- ViewPlugin3.fromClass(class {
1985
- constructor(view) {
1986
- this.decorations = buildDecorations(view);
1987
- }
1988
- update(update2) {
1989
- this.decorations = buildDecorations(update2.view);
1990
- }
1991
- }, {
1992
- decorations: (value) => value.decorations
1993
- }),
1994
- styles4
1995
- ];
1996
- };
1997
2138
 
1998
2139
  // packages/ui/react-ui-editor/src/extensions/markdown/formatting.ts
1999
2140
  import { snippet } from "@codemirror/autocomplete";
2000
2141
  import { syntaxTree as syntaxTree2 } from "@codemirror/language";
2001
- import { RangeSetBuilder as RangeSetBuilder2, EditorSelection } from "@codemirror/state";
2002
- import { Decoration as Decoration5, EditorView as EditorView11, keymap as keymap5, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
2142
+ import { EditorSelection } from "@codemirror/state";
2143
+ import { EditorView as EditorView11, keymap as keymap5 } from "@codemirror/view";
2003
2144
  import { useState, useMemo } from "react";
2004
2145
  var compareFormatting = (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;
2005
2146
  var Inline;
@@ -2020,6 +2161,7 @@ var setHeading = (level) => ({ state, dispatch }) => {
2020
2161
  const changes = [];
2021
2162
  let prevBlock = -1;
2022
2163
  for (const range of ranges) {
2164
+ let sawBlock = false;
2023
2165
  syntaxTree2(state).iterate({
2024
2166
  from: range.from,
2025
2167
  to: range.to,
@@ -2027,6 +2169,7 @@ var setHeading = (level) => ({ state, dispatch }) => {
2027
2169
  if (!Object.hasOwn(Textblocks, node.name) || prevBlock === node.from) {
2028
2170
  return;
2029
2171
  }
2172
+ sawBlock = true;
2030
2173
  prevBlock = node.from;
2031
2174
  const blockType = Textblocks[node.name];
2032
2175
  const isHeading = /heading(\d)/.exec(blockType);
@@ -2071,12 +2214,22 @@ var setHeading = (level) => ({ state, dispatch }) => {
2071
2214
  }
2072
2215
  }
2073
2216
  });
2217
+ let line;
2218
+ if (!sawBlock && range.empty && level > 0 && !/\S/.test((line = state.doc.lineAt(range.from)).text)) {
2219
+ changes.push({
2220
+ from: line.from,
2221
+ to: line.to,
2222
+ insert: "#".repeat(level) + " "
2223
+ });
2224
+ }
2074
2225
  }
2075
2226
  if (!changes.length) {
2076
2227
  return false;
2077
2228
  }
2229
+ const changeSet = state.changes(changes);
2078
2230
  dispatch(state.update({
2079
- changes,
2231
+ changes: changeSet,
2232
+ selection: state.selection.map(changeSet, 1),
2080
2233
  userEvent: "format.setHeading",
2081
2234
  scrollIntoView: true
2082
2235
  }));
@@ -2148,10 +2301,16 @@ var setStyle = (type, enable) => ({ state, dispatch }) => {
2148
2301
  const closeStart = node.to - size;
2149
2302
  if (markType === type) {
2150
2303
  if (openEnd <= from && closeStart >= from) {
2151
- startCovered = openEnd === from ? "adjacent" : true;
2304
+ startCovered = !enable && openEnd === skipMarkers(from, node.node, -1, openEnd) ? {
2305
+ from: node.from,
2306
+ to: openEnd
2307
+ } : true;
2152
2308
  }
2153
2309
  if (openEnd <= to && closeStart >= to) {
2154
- endCovered = closeStart === to ? "adjacent" : true;
2310
+ endCovered = !enable && closeStart === skipMarkers(to, node.node, 1, closeStart) ? {
2311
+ from: closeStart,
2312
+ to: node.to
2313
+ } : true;
2155
2314
  }
2156
2315
  }
2157
2316
  if (markType === type || type === 3 && enable) {
@@ -2200,22 +2359,16 @@ var setStyle = (type, enable) => ({ state, dispatch }) => {
2200
2359
  });
2201
2360
  }
2202
2361
  } else {
2203
- if (startCovered === "adjacent") {
2204
- changes2.push({
2205
- from: from - marker.length,
2206
- to: from
2207
- });
2362
+ if (typeof startCovered === "object") {
2363
+ changes2.push(startCovered);
2208
2364
  } else if (startCovered) {
2209
2365
  changes2.push({
2210
2366
  from: skipSpaces(rangeStart, state.doc, -1, blockStart),
2211
2367
  insert: marker
2212
2368
  });
2213
2369
  }
2214
- if (endCovered === "adjacent") {
2215
- changes2.push({
2216
- from: to,
2217
- to: to + marker.length
2218
- });
2370
+ if (typeof endCovered === "object") {
2371
+ changes2.push(endCovered);
2219
2372
  } else if (endCovered) {
2220
2373
  changes2.push({
2221
2374
  from: skipSpaces(rangeEnd, state.doc, 1, blockEnd),
@@ -2226,6 +2379,15 @@ var setStyle = (type, enable) => ({ state, dispatch }) => {
2226
2379
  }
2227
2380
  }
2228
2381
  });
2382
+ if (blockStart < 0 && range.empty && enable && !/\S/.test(state.doc.lineAt(range.from).text)) {
2383
+ return {
2384
+ changes: {
2385
+ from: range.head,
2386
+ insert: marker + marker
2387
+ },
2388
+ range: EditorSelection.cursor(range.head + marker.length)
2389
+ };
2390
+ }
2229
2391
  const changeSet = state.changes(changes2.concat(changesAtEnd));
2230
2392
  return {
2231
2393
  changes: changeSet,
@@ -2271,6 +2433,19 @@ var skipSpaces = (pos, doc, dir, limit) => {
2271
2433
  }
2272
2434
  return pos;
2273
2435
  };
2436
+ var skipMarkers = (pos, tree, dir, limit) => {
2437
+ for (; ; ) {
2438
+ const next = tree.resolve(pos, dir);
2439
+ if (!IgnoreInline.has(next.name)) {
2440
+ return pos;
2441
+ }
2442
+ const moveTo = dir < 0 ? next.from : next.to;
2443
+ if (limit != null && (dir < 0 ? moveTo < limit : moveTo > limit)) {
2444
+ return pos;
2445
+ }
2446
+ pos = moveTo;
2447
+ }
2448
+ };
2274
2449
  var snippets = {
2275
2450
  codeblock: snippet([
2276
2451
  //
@@ -2549,8 +2724,10 @@ var addList = (type) => ({ state, dispatch }) => {
2549
2724
  renumberListItems(next.firstChild, last.counter + 1, changes, state.doc);
2550
2725
  }
2551
2726
  }
2727
+ const changeSet = state.changes(changes);
2552
2728
  dispatch(state.update({
2553
- changes,
2729
+ changes: changeSet,
2730
+ selection: state.selection.map(changeSet, 1),
2554
2731
  userEvent: "format.list.add",
2555
2732
  scrollIntoView: true
2556
2733
  }));
@@ -2644,6 +2821,7 @@ var setBlockquote = (enable) => ({ state, dispatch }) => {
2644
2821
  const lines = [];
2645
2822
  let lastBlock = -1;
2646
2823
  for (const { from, to } of state.selection.ranges) {
2824
+ const sawBlock = false;
2647
2825
  syntaxTree2(state).iterate({
2648
2826
  from,
2649
2827
  to,
@@ -2653,9 +2831,9 @@ var setBlockquote = (enable) => ({ state, dispatch }) => {
2653
2831
  return false;
2654
2832
  }
2655
2833
  lastBlock = node.from;
2656
- let line = state.doc.lineAt(node.from);
2657
- if (line.number > 1) {
2658
- const prevLine = state.doc.line(line.number - 1);
2834
+ let line2 = state.doc.lineAt(node.from);
2835
+ if (line2.number > 1) {
2836
+ const prevLine = state.doc.line(line2.number - 1);
2659
2837
  if (/^[>\s]*$/.test(prevLine.text)) {
2660
2838
  if (!enable || lines.length && lines[lines.length - 1].number === prevLine.number - 1) {
2661
2839
  lines.push(prevLine);
@@ -2663,14 +2841,14 @@ var setBlockquote = (enable) => ({ state, dispatch }) => {
2663
2841
  }
2664
2842
  }
2665
2843
  for (; ; ) {
2666
- lines.push(line);
2667
- if (line.to >= node.to) {
2844
+ lines.push(line2);
2845
+ if (line2.to >= node.to) {
2668
2846
  break;
2669
2847
  }
2670
- line = state.doc.line(line.number + 1);
2848
+ line2 = state.doc.line(line2.number + 1);
2671
2849
  }
2672
- if (!enable && line.number < state.doc.lines) {
2673
- const nextLine = state.doc.line(line.number + 1);
2850
+ if (!enable && line2.number < state.doc.lines) {
2851
+ const nextLine = state.doc.line(line2.number + 1);
2674
2852
  if (/^[>\s]*$/.test(nextLine.text)) {
2675
2853
  lines.push(nextLine);
2676
2854
  }
@@ -2679,6 +2857,10 @@ var setBlockquote = (enable) => ({ state, dispatch }) => {
2679
2857
  }
2680
2858
  }
2681
2859
  });
2860
+ let line;
2861
+ if (!sawBlock && enable && from === to && !/\S/.test((line = state.doc.lineAt(from)).text)) {
2862
+ lines.push(line);
2863
+ }
2682
2864
  }
2683
2865
  const changes = [];
2684
2866
  for (const line of lines) {
@@ -2700,8 +2882,10 @@ var setBlockquote = (enable) => ({ state, dispatch }) => {
2700
2882
  if (!changes.length) {
2701
2883
  return false;
2702
2884
  }
2885
+ const changeSet = state.changes(changes);
2703
2886
  dispatch(state.update({
2704
- changes,
2887
+ changes: changeSet,
2888
+ selection: state.selection.map(changeSet, 1),
2705
2889
  userEvent: enable ? "format.blockquote.add" : "format.blockquote.remove",
2706
2890
  scrollIntoView: true
2707
2891
  }));
@@ -2833,56 +3017,7 @@ var formatting = (options = {}) => {
2833
3017
  key: "meta-b",
2834
3018
  run: toggleStrong
2835
3019
  }
2836
- ]),
2837
- styling()
2838
- ];
2839
- };
2840
- var styling = () => {
2841
- const buildDecorations7 = (view) => {
2842
- const builder = new RangeSetBuilder2();
2843
- const { state } = view;
2844
- const cursor = state.selection.main.head;
2845
- const replace = (node, marks) => {
2846
- if (cursor <= node.from || cursor >= node.to) {
2847
- for (const mark2 of marks) {
2848
- builder.add(mark2.from, mark2.to, Decoration5.replace({}));
2849
- }
2850
- }
2851
- };
2852
- for (const { from, to } of view.visibleRanges) {
2853
- syntaxTree2(state).iterate({
2854
- enter: (node) => {
2855
- switch (node.name) {
2856
- case "Emphasis":
2857
- case "StrongEmphasis": {
2858
- const marks = node.node.getChildren("EmphasisMark");
2859
- replace(node, marks);
2860
- break;
2861
- }
2862
- case "Strikethrough": {
2863
- const marks = node.node.getChildren("StrikethroughMark");
2864
- replace(node, marks);
2865
- break;
2866
- }
2867
- }
2868
- },
2869
- from,
2870
- to
2871
- });
2872
- }
2873
- return builder.finish();
2874
- };
2875
- return [
2876
- ViewPlugin4.fromClass(class {
2877
- constructor(view) {
2878
- this.decorations = buildDecorations7(view);
2879
- }
2880
- update(update2) {
2881
- this.decorations = buildDecorations7(update2.view);
2882
- }
2883
- }, {
2884
- decorations: (value) => value.decorations
2885
- })
3020
+ ])
2886
3021
  ];
2887
3022
  };
2888
3023
  var InlineMarker = {
@@ -2932,7 +3067,7 @@ var getFormatting = (state) => {
2932
3067
  null,
2933
3068
  null
2934
3069
  ];
2935
- let link2 = false;
3070
+ let link = false;
2936
3071
  let blockQuote = null;
2937
3072
  let listStyle = null;
2938
3073
  const stack = [];
@@ -2994,7 +3129,7 @@ var getFormatting = (state) => {
2994
3129
  if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
2995
3130
  stack.push(name);
2996
3131
  } else if (name === "Link") {
2997
- link2 = true;
3132
+ link = true;
2998
3133
  } else if (Object.hasOwn(Textblocks, name) && (range.empty || node.to > range.from || node.from < range.to)) {
2999
3134
  if (name === "Task" && stack[stack.length - 1] === "BulletList") {
3000
3135
  stack[stack.length - 1] = "TaskList";
@@ -3069,7 +3204,7 @@ var getFormatting = (state) => {
3069
3204
  emphasis: inline[1] ?? false,
3070
3205
  strong: inline[0] ?? false,
3071
3206
  strikethrough: inline[2] ?? false,
3072
- link: link2,
3207
+ link,
3073
3208
  listStyle: listStyle || null
3074
3209
  };
3075
3210
  };
@@ -3089,117 +3224,14 @@ var useFormattingState = () => {
3089
3224
  ];
3090
3225
  };
3091
3226
 
3092
- // packages/ui/react-ui-editor/src/extensions/markdown/heading.ts
3093
- import { syntaxTree as syntaxTree3 } from "@codemirror/language";
3094
- import { RangeSetBuilder as RangeSetBuilder3 } from "@codemirror/state";
3095
- import { Decoration as Decoration6, ViewPlugin as ViewPlugin5 } from "@codemirror/view";
3096
- var buildDecorations2 = (view) => {
3097
- const builder = new RangeSetBuilder3();
3098
- const { state } = view;
3099
- const cursor = state.selection.main.head;
3100
- for (const { from, to } of view.visibleRanges) {
3101
- syntaxTree3(state).iterate({
3102
- enter: (node) => {
3103
- switch (node.name) {
3104
- case "ATXHeading1":
3105
- case "ATXHeading2":
3106
- case "ATXHeading3":
3107
- case "ATXHeading4":
3108
- case "ATXHeading5":
3109
- case "ATXHeading6": {
3110
- const mark2 = node.node.getChild("HeaderMark");
3111
- if (mark2) {
3112
- if (!view.hasFocus || view.state.readOnly || cursor < node.from || cursor > node.to) {
3113
- builder.add(mark2.from, mark2.to + 1, Decoration6.replace({}));
3114
- }
3115
- }
3116
- }
3117
- }
3118
- },
3119
- from,
3120
- to
3121
- });
3122
- }
3123
- return builder.finish();
3124
- };
3125
- var heading2 = () => {
3126
- return [
3127
- ViewPlugin5.fromClass(class {
3128
- constructor(view) {
3129
- this.decorations = buildDecorations2(view);
3130
- }
3131
- update(update2) {
3132
- this.decorations = buildDecorations2(update2.view);
3133
- }
3134
- }, {
3135
- decorations: (value) => value.decorations
3136
- })
3137
- ];
3138
- };
3139
-
3140
- // packages/ui/react-ui-editor/src/extensions/markdown/hr.ts
3141
- import { syntaxTree as syntaxTree4 } from "@codemirror/language";
3142
- import { RangeSetBuilder as RangeSetBuilder4 } from "@codemirror/state";
3143
- import { Decoration as Decoration7, EditorView as EditorView12, ViewPlugin as ViewPlugin6, WidgetType as WidgetType3 } from "@codemirror/view";
3144
- var styles5 = EditorView12.baseTheme({
3145
- "& .cm-hr": {
3146
- // Note that block-level decorations should not have vertical margins,
3147
- borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
3148
- }
3149
- });
3150
- var HorizontalRuleWidget = class extends WidgetType3 {
3151
- toDOM() {
3152
- const el = document.createElement("div");
3153
- el.className = "cm-hr";
3154
- return el;
3155
- }
3156
- };
3157
- var decoration = Decoration7.replace({
3158
- widget: new HorizontalRuleWidget()
3159
- });
3160
- var buildDecorations3 = (view) => {
3161
- const builder = new RangeSetBuilder4();
3162
- const { state } = view;
3163
- const cursor = state.selection.main.head;
3164
- for (const { from, to } of view.visibleRanges) {
3165
- syntaxTree4(state).iterate({
3166
- enter: (node) => {
3167
- if (node.name === "HorizontalRule") {
3168
- if (cursor <= node.from || cursor >= node.to) {
3169
- builder.add(node.from, node.to, decoration);
3170
- }
3171
- }
3172
- },
3173
- from,
3174
- to
3175
- });
3176
- }
3177
- return builder.finish();
3178
- };
3179
- var hr = () => {
3180
- return [
3181
- ViewPlugin6.fromClass(class {
3182
- constructor(view) {
3183
- this.decorations = buildDecorations3(view);
3184
- }
3185
- update(update2) {
3186
- this.decorations = buildDecorations3(update2.view);
3187
- }
3188
- }, {
3189
- decorations: (value) => value.decorations
3190
- }),
3191
- styles5
3192
- ];
3193
- };
3194
-
3195
3227
  // packages/ui/react-ui-editor/src/extensions/markdown/image.ts
3196
- import { syntaxTree as syntaxTree5 } from "@codemirror/language";
3228
+ import { syntaxTree as syntaxTree3 } from "@codemirror/language";
3197
3229
  import { StateField as StateField4 } from "@codemirror/state";
3198
- import { Decoration as Decoration8, EditorView as EditorView13, WidgetType as WidgetType4 } from "@codemirror/view";
3230
+ import { Decoration as Decoration5, EditorView as EditorView12, WidgetType as WidgetType3 } from "@codemirror/view";
3199
3231
  var image = (options = {}) => {
3200
3232
  return StateField4.define({
3201
3233
  create: (state) => {
3202
- return Decoration8.set(buildDecorations4(0, state.doc.length, state));
3234
+ return Decoration5.set(buildDecorations2(0, state.doc.length, state));
3203
3235
  },
3204
3236
  update: (value, tr) => {
3205
3237
  if (!tr.docChanged && !tr.selection) {
@@ -3219,26 +3251,26 @@ var image = (options = {}) => {
3219
3251
  filterFrom: from,
3220
3252
  filterTo: to,
3221
3253
  filter: () => false,
3222
- add: buildDecorations4(from, to, tr.state)
3254
+ add: buildDecorations2(from, to, tr.state)
3223
3255
  });
3224
3256
  },
3225
- provide: (field) => EditorView13.decorations.from(field)
3257
+ provide: (field) => EditorView12.decorations.from(field)
3226
3258
  });
3227
3259
  };
3228
- var buildDecorations4 = (from, to, state) => {
3260
+ var buildDecorations2 = (from, to, state) => {
3229
3261
  const decorations = [];
3230
3262
  const cursor = state.selection.main.head;
3231
- syntaxTree5(state).iterate({
3263
+ syntaxTree3(state).iterate({
3232
3264
  enter: (node) => {
3233
3265
  if (node.name === "Image") {
3234
3266
  const urlNode = node.node.getChild("URL");
3235
3267
  if (urlNode) {
3236
- const hide = state.readOnly || cursor < node.from || cursor > node.to;
3268
+ const hide2 = state.readOnly || cursor < node.from || cursor > node.to;
3237
3269
  const url = state.sliceDoc(urlNode.from, urlNode.to);
3238
- decorations.push(Decoration8.replace({
3270
+ decorations.push(Decoration5.replace({
3239
3271
  block: true,
3240
3272
  widget: new ImageWidget(url)
3241
- }).range(hide ? node.from : node.to, node.to));
3273
+ }).range(hide2 ? node.from : node.to, node.to));
3242
3274
  }
3243
3275
  }
3244
3276
  },
@@ -3247,7 +3279,7 @@ var buildDecorations4 = (from, to, state) => {
3247
3279
  });
3248
3280
  return decorations;
3249
3281
  };
3250
- var ImageWidget = class extends WidgetType4 {
3282
+ var ImageWidget = class extends WidgetType3 {
3251
3283
  constructor(_url) {
3252
3284
  super();
3253
3285
  this._url = _url;
@@ -3265,155 +3297,52 @@ var ImageWidget = class extends WidgetType4 {
3265
3297
  };
3266
3298
 
3267
3299
  // packages/ui/react-ui-editor/src/extensions/markdown/link.ts
3268
- import { syntaxTree as syntaxTree6 } from "@codemirror/language";
3269
- import { RangeSetBuilder as RangeSetBuilder5 } from "@codemirror/state";
3270
- import { hoverTooltip as hoverTooltip2, Decoration as Decoration9, ViewPlugin as ViewPlugin7, WidgetType as WidgetType5 } from "@codemirror/view";
3300
+ import { syntaxTree as syntaxTree4 } from "@codemirror/language";
3301
+ import { hoverTooltip as hoverTooltip2 } from "@codemirror/view";
3271
3302
  import { tooltipContent } from "@dxos/react-ui-theme";
3272
- var link = (options = {}) => {
3273
- const extensions = [
3274
- ViewPlugin7.fromClass(class {
3275
- constructor(view) {
3276
- this.decorations = buildDecorations5(view, options);
3277
- }
3278
- update(update2) {
3279
- if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
3280
- this.decorations = buildDecorations5(update2.view, options);
3281
- }
3282
- }
3283
- }, {
3284
- decorations: (value) => value.decorations
3285
- })
3286
- ];
3287
- if (options.onHover) {
3288
- extensions.push(
3289
- // https://codemirror.net/examples/tooltip
3290
- // https://codemirror.net/docs/ref/#view.hoverTooltip
3291
- // https://github.com/codemirror/view/blob/main/src/tooltip.ts
3292
- hoverTooltip2((view, pos, side) => {
3293
- const syntax = syntaxTree6(view.state).resolveInner(pos, side);
3294
- let link2 = null;
3295
- for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
3296
- link2 = node.name === "Link" ? node : null;
3297
- }
3298
- const url = link2 && link2.getChild("URL");
3299
- if (!url || !link2) {
3300
- return null;
3301
- }
3302
- const urlText = view.state.sliceDoc(url.from, url.to);
3303
- return {
3304
- pos: link2.from,
3305
- end: link2.to,
3306
- above: true,
3307
- create: () => {
3308
- const el = document.createElement("div");
3309
- el.className = tooltipContent({}, "pli-2 plb-1");
3310
- options.onHover(el, urlText);
3311
- return {
3312
- dom: el,
3313
- offset: {
3314
- x: 0,
3315
- y: 4
3316
- }
3317
- };
3318
- }
3319
- };
3320
- })
3321
- );
3322
- }
3323
- return extensions;
3324
- };
3325
- var LinkButton = class extends WidgetType5 {
3326
- constructor(_url, _onAttach) {
3327
- super();
3328
- this._url = _url;
3329
- this._onAttach = _onAttach;
3330
- }
3331
- eq(other) {
3332
- return this._url === other._url;
3333
- }
3334
- toDOM(view) {
3335
- const el = document.createElement("span");
3336
- this._onAttach(el, this._url);
3337
- return el;
3338
- }
3339
- };
3340
- var LinkText = class extends WidgetType5 {
3341
- constructor(_text, _url) {
3342
- super();
3343
- this._text = _text;
3344
- this._url = _url;
3345
- }
3346
- eq(other) {
3347
- return this._url === other._url;
3303
+ var linkTooltip = (render) => hoverTooltip2((view, pos, side) => {
3304
+ const syntax = syntaxTree4(view.state).resolveInner(pos, side);
3305
+ let link = null;
3306
+ for (let i = 0, node = syntax; !link && node && i < 5; node = node.parent, i++) {
3307
+ link = node.name === "Link" ? node : null;
3308
+ }
3309
+ const url = link && link.getChild("URL");
3310
+ if (!url || !link) {
3311
+ return null;
3348
3312
  }
3349
- toDOM(view) {
3350
- const link2 = document.createElement("a");
3351
- link2.setAttribute("class", "cm-link");
3352
- link2.textContent = this._text;
3353
- if (this._url) {
3354
- link2.setAttribute("rel", "noreferrer");
3355
- link2.setAttribute("target", "_blank");
3356
- link2.href = this._url;
3357
- } else {
3358
- link2.onclick = () => {
3359
- view.dispatch({
3360
- selection: {
3361
- anchor: view.posAtDOM(link2)
3362
- }
3363
- });
3313
+ const urlText = view.state.sliceDoc(url.from, url.to);
3314
+ return {
3315
+ pos: link.from,
3316
+ end: link.to,
3317
+ above: true,
3318
+ create: () => {
3319
+ const el = document.createElement("div");
3320
+ el.className = tooltipContent({}, "pli-2 plb-1");
3321
+ render(el, urlText);
3322
+ return {
3323
+ dom: el,
3324
+ offset: {
3325
+ x: 0,
3326
+ y: 4
3327
+ }
3364
3328
  };
3365
3329
  }
3366
- return link2;
3367
- }
3368
- };
3369
- var buildDecorations5 = (view, options) => {
3370
- const builder = new RangeSetBuilder5();
3371
- const { state } = view;
3372
- const cursor = state.selection.main.head;
3373
- for (const { from, to } of view.visibleRanges) {
3374
- syntaxTree6(state).iterate({
3375
- enter: (node) => {
3376
- if (node.name === "Link") {
3377
- const marks = node.node.getChildren("LinkMark");
3378
- const text = marks.length >= 2 ? state.sliceDoc(marks[0].to, marks[1].from) : "";
3379
- const urlNode = node.node.getChild("URL");
3380
- const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
3381
- if (!url) {
3382
- return false;
3383
- }
3384
- if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
3385
- builder.add(node.from, node.to, Decoration9.replace({
3386
- widget: new LinkText(text, options.link ? url : void 0)
3387
- }));
3388
- }
3389
- if (options.onRender) {
3390
- builder.add(node.to, node.to, Decoration9.replace({
3391
- widget: new LinkButton(url, options.onRender)
3392
- }));
3393
- }
3394
- return false;
3395
- }
3396
- },
3397
- from,
3398
- to
3399
- });
3400
- }
3401
- return builder.finish();
3402
- };
3330
+ };
3331
+ });
3403
3332
 
3404
3333
  // packages/ui/react-ui-editor/src/extensions/markdown/table.ts
3405
- import { syntaxTree as syntaxTree7 } from "@codemirror/language";
3406
- import { RangeSetBuilder as RangeSetBuilder6, StateField as StateField5 } from "@codemirror/state";
3407
- import { Decoration as Decoration10, EditorView as EditorView14, WidgetType as WidgetType6 } from "@codemirror/view";
3334
+ import { syntaxTree as syntaxTree5 } from "@codemirror/language";
3335
+ import { RangeSetBuilder as RangeSetBuilder2, StateField as StateField5 } from "@codemirror/state";
3336
+ import { Decoration as Decoration6, EditorView as EditorView13, WidgetType as WidgetType4 } from "@codemirror/view";
3408
3337
  var table = (options = {}) => {
3409
3338
  return StateField5.define({
3410
3339
  create: (state) => update(state, options),
3411
3340
  update: (_, tr) => update(tr.state, options),
3412
- provide: (field) => EditorView14.decorations.from(field)
3341
+ provide: (field) => EditorView13.decorations.from(field)
3413
3342
  });
3414
3343
  };
3415
3344
  var update = (state, options) => {
3416
- const builder = new RangeSetBuilder6();
3345
+ const builder = new RangeSetBuilder2();
3417
3346
  const cursor = state.selection.main.head;
3418
3347
  const tables = [];
3419
3348
  const getTable = () => tables[tables.length - 1];
@@ -3421,7 +3350,7 @@ var update = (state, options) => {
3421
3350
  const table2 = getTable();
3422
3351
  return table2.rows?.[table2.rows.length - 1];
3423
3352
  };
3424
- syntaxTree7(state).iterate({
3353
+ syntaxTree5(state).iterate({
3425
3354
  enter: (node) => {
3426
3355
  switch (node.name) {
3427
3356
  case "Table": {
@@ -3452,17 +3381,17 @@ var update = (state, options) => {
3452
3381
  }
3453
3382
  });
3454
3383
  tables.forEach((table2) => {
3455
- const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
3456
- hide && builder.add(table2.from, table2.to, Decoration10.replace({
3384
+ const hide2 = state.readOnly || cursor < table2.from || cursor > table2.to;
3385
+ hide2 && builder.add(table2.from, table2.to, Decoration6.replace({
3457
3386
  widget: new TableWidget(table2)
3458
3387
  }));
3459
- builder.add(table2.from, table2.to, Decoration10.mark({
3388
+ builder.add(table2.from, table2.to, Decoration6.mark({
3460
3389
  class: "cm-table"
3461
3390
  }));
3462
3391
  });
3463
3392
  return builder.finish();
3464
3393
  };
3465
- var TableWidget = class extends WidgetType6 {
3394
+ var TableWidget = class extends WidgetType4 {
3466
3395
  constructor(_table) {
3467
3396
  super();
3468
3397
  this._table = _table;
@@ -3499,103 +3428,6 @@ var TableWidget = class extends WidgetType6 {
3499
3428
  }
3500
3429
  };
3501
3430
 
3502
- // packages/ui/react-ui-editor/src/extensions/markdown/tasklist.ts
3503
- import { syntaxTree as syntaxTree8 } from "@codemirror/language";
3504
- import { RangeSetBuilder as RangeSetBuilder7 } from "@codemirror/state";
3505
- import { EditorView as EditorView15, Decoration as Decoration11, WidgetType as WidgetType7, ViewPlugin as ViewPlugin8 } from "@codemirror/view";
3506
- var styles6 = EditorView15.baseTheme({
3507
- "& .cm-task": {
3508
- color: getToken("extend.colors.blue.500")
3509
- },
3510
- "& .cm-task-checkbox": {
3511
- marginLeft: "4px",
3512
- marginRight: "4px"
3513
- }
3514
- });
3515
- var CheckboxWidget = class extends WidgetType7 {
3516
- constructor(_checked) {
3517
- super();
3518
- this._checked = _checked;
3519
- }
3520
- eq(other) {
3521
- return this._checked === other._checked;
3522
- }
3523
- toDOM(view) {
3524
- const input = document.createElement("input");
3525
- input.className = "cm-task-checkbox";
3526
- input.type = "checkbox";
3527
- input.checked = this._checked;
3528
- if (view.state.readOnly) {
3529
- input.setAttribute("disabled", "true");
3530
- } else {
3531
- input.onmousedown = (event) => {
3532
- const pos = view.posAtDOM(input);
3533
- const text = view.state.sliceDoc(pos, pos + 3);
3534
- if (text === (this._checked ? "[x]" : "[ ]")) {
3535
- view.dispatch({
3536
- changes: {
3537
- from: pos + 1,
3538
- to: pos + 2,
3539
- insert: this._checked ? " " : "x"
3540
- }
3541
- });
3542
- event.preventDefault();
3543
- }
3544
- };
3545
- }
3546
- return input;
3547
- }
3548
- ignoreEvent() {
3549
- return false;
3550
- }
3551
- };
3552
- var checkedDecoration = Decoration11.replace({
3553
- widget: new CheckboxWidget(true)
3554
- });
3555
- var uncheckedDecoration = Decoration11.replace({
3556
- widget: new CheckboxWidget(false)
3557
- });
3558
- var buildDecorations6 = (view) => {
3559
- const builder = new RangeSetBuilder7();
3560
- const { state } = view;
3561
- const cursor = state.selection.main.head;
3562
- for (const { from, to } of view.visibleRanges) {
3563
- syntaxTree8(state).iterate({
3564
- enter: (node) => {
3565
- if (node.name === "TaskMarker") {
3566
- if (cursor < node.from || cursor > node.to) {
3567
- const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
3568
- builder.add(node.from - 2, node.from - 1, Decoration11.mark({
3569
- class: "cm-task"
3570
- }));
3571
- builder.add(node.from, node.to, checked ? checkedDecoration : uncheckedDecoration);
3572
- }
3573
- }
3574
- },
3575
- from,
3576
- to
3577
- });
3578
- }
3579
- return builder.finish();
3580
- };
3581
- var tasklist = (options = {}) => {
3582
- return [
3583
- ViewPlugin8.fromClass(class {
3584
- constructor(view) {
3585
- this.decorations = buildDecorations6(view);
3586
- }
3587
- update(update2) {
3588
- if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
3589
- this.decorations = buildDecorations6(update2.view);
3590
- }
3591
- }
3592
- }, {
3593
- decorations: (value) => value.decorations
3594
- }),
3595
- styles6
3596
- ];
3597
- };
3598
-
3599
3431
  // packages/ui/react-ui-editor/src/extensions/mention.ts
3600
3432
  import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
3601
3433
  var mention = ({ onSearch }) => {
@@ -3993,7 +3825,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
3993
3825
  selection,
3994
3826
  extensions: [
3995
3827
  // TODO(burdon): Doesn't catch errors in keymap functions.
3996
- EditorView16.exceptionSink.of((err) => {
3828
+ EditorView14.exceptionSink.of((err) => {
3997
3829
  log3.catch(err, void 0, {
3998
3830
  F: __dxlog_file4,
3999
3831
  L: 113,
@@ -4003,17 +3835,17 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
4003
3835
  }),
4004
3836
  // Theme.
4005
3837
  // TODO(burdon): Make configurable.
4006
- EditorView16.baseTheme(defaultTheme),
4007
- EditorView16.theme(theme ?? {}),
4008
- EditorView16.darkTheme.of(themeMode === "dark"),
4009
- EditorView16.editorAttributes.of({
3838
+ EditorView14.baseTheme(defaultTheme),
3839
+ EditorView14.theme(theme ?? {}),
3840
+ EditorView14.darkTheme.of(themeMode === "dark"),
3841
+ EditorView14.editorAttributes.of({
4010
3842
  class: slots.editor?.className ?? ""
4011
3843
  }),
4012
- EditorView16.contentAttributes.of({
3844
+ EditorView14.contentAttributes.of({
4013
3845
  class: slots.content?.className ?? ""
4014
3846
  }),
4015
3847
  // Focus.
4016
- EditorView16.updateListener.of((update2) => {
3848
+ EditorView14.updateListener.of((update2) => {
4017
3849
  update2.transactions.forEach((transaction) => {
4018
3850
  if (transaction.isUserEvent("focus.container")) {
4019
3851
  rootRef.current?.focus();
@@ -4021,7 +3853,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
4021
3853
  });
4022
3854
  }),
4023
3855
  // State.
4024
- EditorView16.editable.of(!readonly),
3856
+ EditorView14.editable.of(!readonly),
4025
3857
  EditorState2.readOnly.of(!!readonly),
4026
3858
  // Storage and replication.
4027
3859
  // NOTE: This must come before user extensions.
@@ -4030,7 +3862,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
4030
3862
  ...extensions
4031
3863
  ].filter(isNotFalsy4)
4032
3864
  });
4033
- const newView = new EditorView16({
3865
+ const newView = new EditorView14({
4034
3866
  state,
4035
3867
  parent: rootRef.current,
4036
3868
  scrollTo,
@@ -4352,8 +4184,7 @@ var markdownBlocks = [
4352
4184
  {
4353
4185
  type: "codeblock",
4354
4186
  Icon: CodeBlock,
4355
- getState: (state) => state.blockType === "codeblock",
4356
- disabled: (state) => !state.blankLine
4187
+ getState: (state) => state.blockType === "codeblock"
4357
4188
  },
4358
4189
  {
4359
4190
  type: "table",
@@ -4586,7 +4417,7 @@ var useEditorView = (id) => {
4586
4417
 
4587
4418
  // packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
4588
4419
  import { EditorSelection as EditorSelection2, EditorState as EditorState3 } from "@codemirror/state";
4589
- import { EditorView as EditorView17 } from "@codemirror/view";
4420
+ import { EditorView as EditorView15 } from "@codemirror/view";
4590
4421
  import { useEffect as useEffect3, useRef as useRef3, useState as useState4 } from "react";
4591
4422
  import { log as log5 } from "@dxos/log";
4592
4423
  import { isNotFalsy as isNotFalsy5 } from "@dxos/util";
@@ -4603,7 +4434,7 @@ var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions }
4603
4434
  selection,
4604
4435
  extensions: [
4605
4436
  // TODO(burdon): Doesn't catch errors in keymap functions.
4606
- EditorView17.exceptionSink.of((err) => {
4437
+ EditorView15.exceptionSink.of((err) => {
4607
4438
  log5.catch(err, void 0, {
4608
4439
  F: __dxlog_file6,
4609
4440
  L: 60,
@@ -4612,12 +4443,12 @@ var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions }
4612
4443
  });
4613
4444
  }),
4614
4445
  extensions,
4615
- EditorView17.updateListener.of(() => {
4446
+ EditorView15.updateListener.of(() => {
4616
4447
  onUpdate.current?.();
4617
4448
  })
4618
4449
  ].filter(isNotFalsy5)
4619
4450
  });
4620
- view2 = new EditorView17({
4451
+ view2 = new EditorView15({
4621
4452
  parent: parentRef.current,
4622
4453
  scrollTo,
4623
4454
  state,
@@ -4675,19 +4506,19 @@ var createDataExtensions = ({ readonly = false } = {}) => {
4675
4506
  return [
4676
4507
  //
4677
4508
  EditorState3.readOnly.of(readonly),
4678
- EditorView17.editable.of(!readonly)
4509
+ EditorView15.editable.of(!readonly)
4679
4510
  ];
4680
4511
  };
4681
4512
  var createThemeExtensions = ({ theme, themeMode, slots } = {}) => {
4682
4513
  return [
4683
4514
  //
4684
- EditorView17.baseTheme(defaultTheme),
4685
- theme && EditorView17.theme(theme),
4686
- EditorView17.darkTheme.of(themeMode === "dark"),
4687
- EditorView17.editorAttributes.of({
4515
+ EditorView15.baseTheme(defaultTheme),
4516
+ theme && EditorView15.theme(theme),
4517
+ EditorView15.darkTheme.of(themeMode === "dark"),
4518
+ EditorView15.editorAttributes.of({
4688
4519
  class: slots?.editor?.className ?? ""
4689
4520
  }),
4690
- EditorView17.contentAttributes.of({
4521
+ EditorView15.contentAttributes.of({
4691
4522
  class: slots?.content?.className ?? ""
4692
4523
  })
4693
4524
  ].filter(isNotFalsy5);
@@ -4787,7 +4618,6 @@ export {
4787
4618
  awarenessProvider,
4788
4619
  blast,
4789
4620
  callbackWrapper,
4790
- code2 as code,
4791
4621
  codeTheme,
4792
4622
  comments,
4793
4623
  compareFormatting,
@@ -4798,6 +4628,7 @@ export {
4798
4628
  createThemeExtensions,
4799
4629
  cursorLineMargin,
4800
4630
  cursorLineMarginFacet,
4631
+ decorateMarkdown,
4801
4632
  defaultMarkdownSlots,
4802
4633
  defaultOptions,
4803
4634
  defaultSlots,
@@ -4812,12 +4643,10 @@ export {
4812
4643
  formatting,
4813
4644
  getFormatting,
4814
4645
  getToken,
4815
- heading2 as heading,
4816
- hr,
4817
4646
  image,
4818
4647
  insertTable,
4819
4648
  keymap8 as keymap,
4820
- link,
4649
+ linkTooltip,
4821
4650
  listener,
4822
4651
  logChanges,
4823
4652
  markdownHighlightStyle,
@@ -4839,7 +4668,6 @@ export {
4839
4668
  setStyle,
4840
4669
  table,
4841
4670
  tags2 as tags,
4842
- tasklist,
4843
4671
  textTheme,
4844
4672
  toggleBlockquote,
4845
4673
  toggleCodeblock,