@dxos/react-ui-editor 0.4.5-main.dd6795b → 0.4.5-main.ea4f804

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 (49) hide show
  1. package/dist/lib/browser/index.mjs +401 -562
  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 +7 -5
  5. package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
  6. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +2 -0
  7. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
  8. package/dist/types/src/components/TextEditor/automerge.stories.d.ts +2 -0
  9. package/dist/types/src/components/TextEditor/automerge.stories.d.ts.map +1 -1
  10. package/dist/types/src/components/TextEditor/hooks.stories.d.ts +2 -0
  11. package/dist/types/src/components/TextEditor/hooks.stories.d.ts.map +1 -1
  12. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
  13. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts +2 -0
  14. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -1
  15. package/dist/types/src/extensions/markdown/decorate.d.ts +5 -0
  16. package/dist/types/src/extensions/markdown/decorate.d.ts.map +1 -0
  17. package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -1
  18. package/dist/types/src/extensions/markdown/index.d.ts +1 -4
  19. package/dist/types/src/extensions/markdown/index.d.ts.map +1 -1
  20. package/dist/types/src/extensions/markdown/link.d.ts +1 -11
  21. package/dist/types/src/extensions/markdown/link.d.ts.map +1 -1
  22. package/dist/types/src/index.d.ts +2 -0
  23. package/dist/types/src/index.d.ts.map +1 -1
  24. package/dist/types/src/translations.d.ts +2 -0
  25. package/dist/types/src/translations.d.ts.map +1 -1
  26. package/package.json +28 -25
  27. package/src/components/TextEditor/MarkdownEditor.stories.tsx +29 -37
  28. package/src/components/TextEditor/hooks.stories.tsx +2 -10
  29. package/src/components/Toolbar/Toolbar.stories.tsx +2 -6
  30. package/src/components/Toolbar/Toolbar.tsx +79 -47
  31. package/src/extensions/markdown/decorate.ts +301 -0
  32. package/src/extensions/markdown/formatting.test.ts +17 -0
  33. package/src/extensions/markdown/formatting.ts +67 -76
  34. package/src/extensions/markdown/index.ts +1 -4
  35. package/src/extensions/markdown/link.ts +23 -185
  36. package/src/index.ts +2 -0
  37. package/src/translations.ts +5 -3
  38. package/dist/types/src/extensions/markdown/code.d.ts +0 -2
  39. package/dist/types/src/extensions/markdown/code.d.ts.map +0 -1
  40. package/dist/types/src/extensions/markdown/heading.d.ts +0 -6
  41. package/dist/types/src/extensions/markdown/heading.d.ts.map +0 -1
  42. package/dist/types/src/extensions/markdown/hr.d.ts +0 -2
  43. package/dist/types/src/extensions/markdown/hr.d.ts.map +0 -1
  44. package/dist/types/src/extensions/markdown/tasklist.d.ts +0 -3
  45. package/dist/types/src/extensions/markdown/tasklist.d.ts.map +0 -1
  46. package/src/extensions/markdown/code.ts +0 -162
  47. package/src/extensions/markdown/heading.ts +0 -59
  48. package/src/extensions/markdown/hr.ts +0 -71
  49. package/src/extensions/markdown/tasklist.ts +0 -110
@@ -1,3 +1,27 @@
1
+ // packages/ui/react-ui-editor/src/translations.ts
2
+ var translationKey = "react-ui-editor";
3
+ var translations_default = [
4
+ {
5
+ "en-US": {
6
+ [translationKey]: {
7
+ "strong label": "Bold",
8
+ "emphasis label": "Italics",
9
+ "strikethrough label": "Strikethrough",
10
+ "code label": "Code",
11
+ "link label": "Link",
12
+ "list-bullet label": "Bullet list",
13
+ "list-ordered label": "Numbered list",
14
+ "list-task label": "Task list",
15
+ "blockquote label": "Block quote",
16
+ "codeblock label": "Code block",
17
+ "comment label": "Create comment",
18
+ "heading label": "Heading level",
19
+ "table label": "Create table"
20
+ }
21
+ }
22
+ }
23
+ ];
24
+
1
25
  // packages/ui/react-ui-editor/src/index.ts
2
26
  import { keymap as keymap8 } from "@codemirror/view";
3
27
  import { TextKind } from "@dxos/protocols/proto/dxos/echo/model/text";
@@ -8,7 +32,7 @@ import { tags as tags2 } from "@lezer/highlight";
8
32
 
9
33
  // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
10
34
  import { EditorState as EditorState2 } from "@codemirror/state";
11
- import { EditorView as EditorView16 } from "@codemirror/view";
35
+ import { EditorView as EditorView14 } from "@codemirror/view";
12
36
  import { useFocusableGroup } from "@fluentui/react-tabster";
13
37
  import defaultsDeep2 from "lodash.defaultsdeep";
14
38
  import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useRef, useState as useState2, useMemo as useMemo2 } from "react";
@@ -765,10 +789,10 @@ var blast = (options = defaultOptions) => {
765
789
  const getPoint = (view, pos) => {
766
790
  const { left: x = 0, top: y = 0 } = view.coordsForChar(pos) ?? {};
767
791
  const element = document.elementFromPoint(x, y);
768
- const { offsetLeft: left = 0, offsetTop: top2 = 0 } = view.scrollDOM.parentElement ?? {};
792
+ const { offsetLeft: left = 0, offsetTop: top = 0 } = view.scrollDOM.parentElement ?? {};
769
793
  const point = {
770
794
  x: x - left,
771
- y: y - top2
795
+ y: y - top
772
796
  };
773
797
  return {
774
798
  element,
@@ -1871,12 +1895,207 @@ var createMarkdownExtensions = ({ themeMode, placeholder: _placeholder, lineWrap
1871
1895
  ].filter(isNotFalsy3);
1872
1896
  };
1873
1897
 
1874
- // packages/ui/react-ui-editor/src/extensions/markdown/code.ts
1898
+ // packages/ui/react-ui-editor/src/extensions/markdown/decorate.ts
1875
1899
  import { syntaxTree } from "@codemirror/language";
1876
1900
  import { RangeSetBuilder } from "@codemirror/state";
1877
- import { ViewPlugin as ViewPlugin3, EditorView as EditorView10, Decoration as Decoration4, WidgetType as WidgetType2 } from "@codemirror/view";
1901
+ import { EditorView as EditorView10, Decoration as Decoration4, WidgetType as WidgetType2, ViewPlugin as ViewPlugin3 } from "@codemirror/view";
1878
1902
  import { mx as mx2 } from "@dxos/react-ui-theme";
1879
- var styles4 = EditorView10.baseTheme({
1903
+ var FencedCodeBoundary = class extends WidgetType2 {
1904
+ constructor(_className) {
1905
+ super();
1906
+ this._className = _className;
1907
+ }
1908
+ toDOM() {
1909
+ const el = document.createElement("span");
1910
+ el.innerHTML = " ";
1911
+ el.className = mx2("cm-code cm-codeblock", this._className);
1912
+ return el;
1913
+ }
1914
+ };
1915
+ var HorizontalRuleWidget = class extends WidgetType2 {
1916
+ toDOM() {
1917
+ const el = document.createElement("span");
1918
+ el.className = "cm-hr";
1919
+ return el;
1920
+ }
1921
+ };
1922
+ var LinkButton = class extends WidgetType2 {
1923
+ constructor(url, render) {
1924
+ super();
1925
+ this.url = url;
1926
+ this.render = render;
1927
+ }
1928
+ eq(other) {
1929
+ return this.url === other.url;
1930
+ }
1931
+ toDOM(view) {
1932
+ const el = document.createElement("span");
1933
+ this.render(el, this.url);
1934
+ return el;
1935
+ }
1936
+ };
1937
+ var CheckboxWidget = class extends WidgetType2 {
1938
+ constructor(_checked) {
1939
+ super();
1940
+ this._checked = _checked;
1941
+ }
1942
+ eq(other) {
1943
+ return this._checked === other._checked;
1944
+ }
1945
+ toDOM(view) {
1946
+ const input = document.createElement("input");
1947
+ input.className = "cm-task-checkbox";
1948
+ input.type = "checkbox";
1949
+ input.checked = this._checked;
1950
+ if (view.state.readOnly) {
1951
+ input.setAttribute("disabled", "true");
1952
+ } else {
1953
+ input.onmousedown = (event) => {
1954
+ const pos = view.posAtDOM(input);
1955
+ const text = view.state.sliceDoc(pos, pos + 3);
1956
+ if (text === (this._checked ? "[x]" : "[ ]")) {
1957
+ view.dispatch({
1958
+ changes: {
1959
+ from: pos + 1,
1960
+ to: pos + 2,
1961
+ insert: this._checked ? " " : "x"
1962
+ }
1963
+ });
1964
+ event.preventDefault();
1965
+ }
1966
+ };
1967
+ }
1968
+ return input;
1969
+ }
1970
+ ignoreEvent() {
1971
+ return false;
1972
+ }
1973
+ };
1974
+ var hide = Decoration4.replace({});
1975
+ var fencedCodeTop = Decoration4.replace({
1976
+ widget: new FencedCodeBoundary("cm-codeblock-end cm-codeblock-first")
1977
+ });
1978
+ var fencedCodeBottom = Decoration4.replace({
1979
+ widget: new FencedCodeBoundary("cm-codeblock-end cm-codeblock-last")
1980
+ });
1981
+ var horizontalRule = Decoration4.replace({
1982
+ widget: new HorizontalRuleWidget()
1983
+ });
1984
+ var checkedTask = Decoration4.replace({
1985
+ widget: new CheckboxWidget(true)
1986
+ });
1987
+ var uncheckedTask = Decoration4.replace({
1988
+ widget: new CheckboxWidget(false)
1989
+ });
1990
+ var editingRange = (state, range) => {
1991
+ const { readOnly, selection: { main: { head } } } = state;
1992
+ return !readOnly && head >= range.from && head <= range.to;
1993
+ };
1994
+ var MarksByParent = /* @__PURE__ */ new Set([
1995
+ "CodeMark",
1996
+ "EmphasisMark",
1997
+ "StrikethroughMark",
1998
+ "SubscriptMark",
1999
+ "SuperscriptMark"
2000
+ ]);
2001
+ var buildDecorations = (view, options) => {
2002
+ const builder = new RangeSetBuilder();
2003
+ const { state } = view;
2004
+ for (const { from, to } of view.visibleRanges) {
2005
+ syntaxTree(state).iterate({
2006
+ from,
2007
+ to,
2008
+ enter: (node) => {
2009
+ if (node.name === "FencedCode") {
2010
+ const editing = editingRange(state, node);
2011
+ for (const block of view.viewportLineBlocks) {
2012
+ if (block.to < node.from) {
2013
+ continue;
2014
+ }
2015
+ if (block.from > node.to) {
2016
+ break;
2017
+ }
2018
+ const first = block.from <= node.from;
2019
+ const last = block.to >= node.to;
2020
+ if (!editing && (first || last)) {
2021
+ builder.add(block.from, block.to, first ? fencedCodeTop : fencedCodeBottom);
2022
+ } else {
2023
+ builder.add(block.from, block.from, Decoration4.line({
2024
+ class: mx2("cm-code cm-codeblock-line", first && "cm-codeblock-first", last && "cm-codeblock-last")
2025
+ }));
2026
+ }
2027
+ }
2028
+ return false;
2029
+ } else if (node.name === "Link") {
2030
+ const marks = node.node.getChildren("LinkMark");
2031
+ const urlNode = node.node.getChild("URL");
2032
+ const editing = editingRange(state, node);
2033
+ if (urlNode && marks.length >= 2) {
2034
+ const url = state.sliceDoc(urlNode.from, urlNode.to);
2035
+ if (!editing) {
2036
+ builder.add(node.from, marks[0].to, hide);
2037
+ }
2038
+ builder.add(marks[0].to, marks[1].from, Decoration4.mark({
2039
+ tagName: "a",
2040
+ attributes: {
2041
+ class: "cm-link",
2042
+ href: url,
2043
+ rel: "noreferrer",
2044
+ target: "_blank"
2045
+ }
2046
+ }));
2047
+ if (!editing) {
2048
+ builder.add(marks[1].from, node.to, options.renderLinkButton ? Decoration4.replace({
2049
+ widget: new LinkButton(url, options.renderLinkButton)
2050
+ }) : hide);
2051
+ }
2052
+ }
2053
+ } else if (node.name === "HeaderMark") {
2054
+ const parent = node.node.parent;
2055
+ if (/^ATX/.test(parent.name) && !editingRange(state, state.doc.lineAt(node.from))) {
2056
+ const next = state.doc.sliceString(node.to, node.to + 1);
2057
+ builder.add(node.from, node.to + (next === " " ? 1 : 0), hide);
2058
+ }
2059
+ } else if (node.name === "HorizontalRule") {
2060
+ if (!editingRange(state, node)) {
2061
+ builder.add(node.from, node.to, horizontalRule);
2062
+ }
2063
+ } else if (node.name === "TaskMarker") {
2064
+ if (!editingRange(state, node)) {
2065
+ const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
2066
+ builder.add(node.from - 2, node.from - 1, Decoration4.mark({
2067
+ class: "cm-task"
2068
+ }));
2069
+ builder.add(node.from, node.to, checked ? checkedTask : uncheckedTask);
2070
+ }
2071
+ } else if (MarksByParent.has(node.name)) {
2072
+ if (!editingRange(state, node.node.parent)) {
2073
+ builder.add(node.from, node.to, hide);
2074
+ }
2075
+ }
2076
+ }
2077
+ });
2078
+ }
2079
+ return builder.finish();
2080
+ };
2081
+ var decorateMarkdown = (options = {}) => {
2082
+ return [
2083
+ ViewPlugin3.fromClass(class {
2084
+ constructor(view) {
2085
+ this.decorations = buildDecorations(view, options);
2086
+ }
2087
+ update(update2) {
2088
+ if (update2.docChanged || update2.selectionSet || update2.viewportChanged) {
2089
+ this.decorations = buildDecorations(update2.view, options);
2090
+ }
2091
+ }
2092
+ }, {
2093
+ decorations: (value) => value.decorations
2094
+ }),
2095
+ formattingStyles
2096
+ ];
2097
+ };
2098
+ var formattingStyles = EditorView10.baseTheme({
1880
2099
  "& .cm-code": {
1881
2100
  fontFamily: getToken("fontFamily.mono", []).join(",")
1882
2101
  },
@@ -1924,82 +2143,28 @@ var styles4 = EditorView10.baseTheme({
1924
2143
  "&::after": {
1925
2144
  background: getToken("extend.semanticColors.input.dark")
1926
2145
  }
2146
+ },
2147
+ "& .cm-hr": {
2148
+ display: "inline-block",
2149
+ width: "100%",
2150
+ height: "0",
2151
+ verticalAlign: "middle",
2152
+ borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
2153
+ },
2154
+ "& .cm-task": {
2155
+ color: getToken("extend.colors.blue.500")
2156
+ },
2157
+ "& .cm-task-checkbox": {
2158
+ marginLeft: "4px",
2159
+ marginRight: "4px"
1927
2160
  }
1928
2161
  });
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
2162
 
1998
2163
  // packages/ui/react-ui-editor/src/extensions/markdown/formatting.ts
1999
2164
  import { snippet } from "@codemirror/autocomplete";
2000
2165
  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";
2166
+ import { EditorSelection } from "@codemirror/state";
2167
+ import { EditorView as EditorView11, keymap as keymap5 } from "@codemirror/view";
2003
2168
  import { useState, useMemo } from "react";
2004
2169
  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
2170
  var Inline;
@@ -2020,6 +2185,7 @@ var setHeading = (level) => ({ state, dispatch }) => {
2020
2185
  const changes = [];
2021
2186
  let prevBlock = -1;
2022
2187
  for (const range of ranges) {
2188
+ let sawBlock = false;
2023
2189
  syntaxTree2(state).iterate({
2024
2190
  from: range.from,
2025
2191
  to: range.to,
@@ -2027,6 +2193,7 @@ var setHeading = (level) => ({ state, dispatch }) => {
2027
2193
  if (!Object.hasOwn(Textblocks, node.name) || prevBlock === node.from) {
2028
2194
  return;
2029
2195
  }
2196
+ sawBlock = true;
2030
2197
  prevBlock = node.from;
2031
2198
  const blockType = Textblocks[node.name];
2032
2199
  const isHeading = /heading(\d)/.exec(blockType);
@@ -2071,12 +2238,22 @@ var setHeading = (level) => ({ state, dispatch }) => {
2071
2238
  }
2072
2239
  }
2073
2240
  });
2241
+ let line;
2242
+ if (!sawBlock && range.empty && level > 0 && !/\S/.test((line = state.doc.lineAt(range.from)).text)) {
2243
+ changes.push({
2244
+ from: line.from,
2245
+ to: line.to,
2246
+ insert: "#".repeat(level) + " "
2247
+ });
2248
+ }
2074
2249
  }
2075
2250
  if (!changes.length) {
2076
2251
  return false;
2077
2252
  }
2253
+ const changeSet = state.changes(changes);
2078
2254
  dispatch(state.update({
2079
- changes,
2255
+ changes: changeSet,
2256
+ selection: state.selection.map(changeSet, 1),
2080
2257
  userEvent: "format.setHeading",
2081
2258
  scrollIntoView: true
2082
2259
  }));
@@ -2148,10 +2325,16 @@ var setStyle = (type, enable) => ({ state, dispatch }) => {
2148
2325
  const closeStart = node.to - size;
2149
2326
  if (markType === type) {
2150
2327
  if (openEnd <= from && closeStart >= from) {
2151
- startCovered = openEnd === from ? "adjacent" : true;
2328
+ startCovered = !enable && openEnd === skipMarkers(from, node.node, -1, openEnd) ? {
2329
+ from: node.from,
2330
+ to: openEnd
2331
+ } : true;
2152
2332
  }
2153
2333
  if (openEnd <= to && closeStart >= to) {
2154
- endCovered = closeStart === to ? "adjacent" : true;
2334
+ endCovered = !enable && closeStart === skipMarkers(to, node.node, 1, closeStart) ? {
2335
+ from: closeStart,
2336
+ to: node.to
2337
+ } : true;
2155
2338
  }
2156
2339
  }
2157
2340
  if (markType === type || type === 3 && enable) {
@@ -2200,22 +2383,16 @@ var setStyle = (type, enable) => ({ state, dispatch }) => {
2200
2383
  });
2201
2384
  }
2202
2385
  } else {
2203
- if (startCovered === "adjacent") {
2204
- changes2.push({
2205
- from: from - marker.length,
2206
- to: from
2207
- });
2386
+ if (typeof startCovered === "object") {
2387
+ changes2.push(startCovered);
2208
2388
  } else if (startCovered) {
2209
2389
  changes2.push({
2210
2390
  from: skipSpaces(rangeStart, state.doc, -1, blockStart),
2211
2391
  insert: marker
2212
2392
  });
2213
2393
  }
2214
- if (endCovered === "adjacent") {
2215
- changes2.push({
2216
- from: to,
2217
- to: to + marker.length
2218
- });
2394
+ if (typeof endCovered === "object") {
2395
+ changes2.push(endCovered);
2219
2396
  } else if (endCovered) {
2220
2397
  changes2.push({
2221
2398
  from: skipSpaces(rangeEnd, state.doc, 1, blockEnd),
@@ -2226,6 +2403,15 @@ var setStyle = (type, enable) => ({ state, dispatch }) => {
2226
2403
  }
2227
2404
  }
2228
2405
  });
2406
+ if (blockStart < 0 && range.empty && enable && !/\S/.test(state.doc.lineAt(range.from).text)) {
2407
+ return {
2408
+ changes: {
2409
+ from: range.head,
2410
+ insert: marker + marker
2411
+ },
2412
+ range: EditorSelection.cursor(range.head + marker.length)
2413
+ };
2414
+ }
2229
2415
  const changeSet = state.changes(changes2.concat(changesAtEnd));
2230
2416
  return {
2231
2417
  changes: changeSet,
@@ -2271,6 +2457,19 @@ var skipSpaces = (pos, doc, dir, limit) => {
2271
2457
  }
2272
2458
  return pos;
2273
2459
  };
2460
+ var skipMarkers = (pos, tree, dir, limit) => {
2461
+ for (; ; ) {
2462
+ const next = tree.resolve(pos, dir);
2463
+ if (!IgnoreInline.has(next.name)) {
2464
+ return pos;
2465
+ }
2466
+ const moveTo = dir < 0 ? next.from : next.to;
2467
+ if (limit != null && (dir < 0 ? moveTo < limit : moveTo > limit)) {
2468
+ return pos;
2469
+ }
2470
+ pos = moveTo;
2471
+ }
2472
+ };
2274
2473
  var snippets = {
2275
2474
  codeblock: snippet([
2276
2475
  //
@@ -2549,8 +2748,10 @@ var addList = (type) => ({ state, dispatch }) => {
2549
2748
  renumberListItems(next.firstChild, last.counter + 1, changes, state.doc);
2550
2749
  }
2551
2750
  }
2751
+ const changeSet = state.changes(changes);
2552
2752
  dispatch(state.update({
2553
- changes,
2753
+ changes: changeSet,
2754
+ selection: state.selection.map(changeSet, 1),
2554
2755
  userEvent: "format.list.add",
2555
2756
  scrollIntoView: true
2556
2757
  }));
@@ -2644,6 +2845,7 @@ var setBlockquote = (enable) => ({ state, dispatch }) => {
2644
2845
  const lines = [];
2645
2846
  let lastBlock = -1;
2646
2847
  for (const { from, to } of state.selection.ranges) {
2848
+ const sawBlock = false;
2647
2849
  syntaxTree2(state).iterate({
2648
2850
  from,
2649
2851
  to,
@@ -2653,9 +2855,9 @@ var setBlockquote = (enable) => ({ state, dispatch }) => {
2653
2855
  return false;
2654
2856
  }
2655
2857
  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);
2858
+ let line2 = state.doc.lineAt(node.from);
2859
+ if (line2.number > 1) {
2860
+ const prevLine = state.doc.line(line2.number - 1);
2659
2861
  if (/^[>\s]*$/.test(prevLine.text)) {
2660
2862
  if (!enable || lines.length && lines[lines.length - 1].number === prevLine.number - 1) {
2661
2863
  lines.push(prevLine);
@@ -2663,14 +2865,14 @@ var setBlockquote = (enable) => ({ state, dispatch }) => {
2663
2865
  }
2664
2866
  }
2665
2867
  for (; ; ) {
2666
- lines.push(line);
2667
- if (line.to >= node.to) {
2868
+ lines.push(line2);
2869
+ if (line2.to >= node.to) {
2668
2870
  break;
2669
2871
  }
2670
- line = state.doc.line(line.number + 1);
2872
+ line2 = state.doc.line(line2.number + 1);
2671
2873
  }
2672
- if (!enable && line.number < state.doc.lines) {
2673
- const nextLine = state.doc.line(line.number + 1);
2874
+ if (!enable && line2.number < state.doc.lines) {
2875
+ const nextLine = state.doc.line(line2.number + 1);
2674
2876
  if (/^[>\s]*$/.test(nextLine.text)) {
2675
2877
  lines.push(nextLine);
2676
2878
  }
@@ -2679,6 +2881,10 @@ var setBlockquote = (enable) => ({ state, dispatch }) => {
2679
2881
  }
2680
2882
  }
2681
2883
  });
2884
+ let line;
2885
+ if (!sawBlock && enable && from === to && !/\S/.test((line = state.doc.lineAt(from)).text)) {
2886
+ lines.push(line);
2887
+ }
2682
2888
  }
2683
2889
  const changes = [];
2684
2890
  for (const line of lines) {
@@ -2700,8 +2906,10 @@ var setBlockquote = (enable) => ({ state, dispatch }) => {
2700
2906
  if (!changes.length) {
2701
2907
  return false;
2702
2908
  }
2909
+ const changeSet = state.changes(changes);
2703
2910
  dispatch(state.update({
2704
- changes,
2911
+ changes: changeSet,
2912
+ selection: state.selection.map(changeSet, 1),
2705
2913
  userEvent: enable ? "format.blockquote.add" : "format.blockquote.remove",
2706
2914
  scrollIntoView: true
2707
2915
  }));
@@ -2833,56 +3041,7 @@ var formatting = (options = {}) => {
2833
3041
  key: "meta-b",
2834
3042
  run: toggleStrong
2835
3043
  }
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
- })
3044
+ ])
2886
3045
  ];
2887
3046
  };
2888
3047
  var InlineMarker = {
@@ -2932,7 +3091,7 @@ var getFormatting = (state) => {
2932
3091
  null,
2933
3092
  null
2934
3093
  ];
2935
- let link2 = false;
3094
+ let link = false;
2936
3095
  let blockQuote = null;
2937
3096
  let listStyle = null;
2938
3097
  const stack = [];
@@ -2994,7 +3153,7 @@ var getFormatting = (state) => {
2994
3153
  if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
2995
3154
  stack.push(name);
2996
3155
  } else if (name === "Link") {
2997
- link2 = true;
3156
+ link = true;
2998
3157
  } else if (Object.hasOwn(Textblocks, name) && (range.empty || node.to > range.from || node.from < range.to)) {
2999
3158
  if (name === "Task" && stack[stack.length - 1] === "BulletList") {
3000
3159
  stack[stack.length - 1] = "TaskList";
@@ -3069,7 +3228,7 @@ var getFormatting = (state) => {
3069
3228
  emphasis: inline[1] ?? false,
3070
3229
  strong: inline[0] ?? false,
3071
3230
  strikethrough: inline[2] ?? false,
3072
- link: link2,
3231
+ link,
3073
3232
  listStyle: listStyle || null
3074
3233
  };
3075
3234
  };
@@ -3089,117 +3248,14 @@ var useFormattingState = () => {
3089
3248
  ];
3090
3249
  };
3091
3250
 
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
3251
  // packages/ui/react-ui-editor/src/extensions/markdown/image.ts
3196
- import { syntaxTree as syntaxTree5 } from "@codemirror/language";
3252
+ import { syntaxTree as syntaxTree3 } from "@codemirror/language";
3197
3253
  import { StateField as StateField4 } from "@codemirror/state";
3198
- import { Decoration as Decoration8, EditorView as EditorView13, WidgetType as WidgetType4 } from "@codemirror/view";
3254
+ import { Decoration as Decoration5, EditorView as EditorView12, WidgetType as WidgetType3 } from "@codemirror/view";
3199
3255
  var image = (options = {}) => {
3200
3256
  return StateField4.define({
3201
3257
  create: (state) => {
3202
- return Decoration8.set(buildDecorations4(0, state.doc.length, state));
3258
+ return Decoration5.set(buildDecorations2(0, state.doc.length, state));
3203
3259
  },
3204
3260
  update: (value, tr) => {
3205
3261
  if (!tr.docChanged && !tr.selection) {
@@ -3219,26 +3275,26 @@ var image = (options = {}) => {
3219
3275
  filterFrom: from,
3220
3276
  filterTo: to,
3221
3277
  filter: () => false,
3222
- add: buildDecorations4(from, to, tr.state)
3278
+ add: buildDecorations2(from, to, tr.state)
3223
3279
  });
3224
3280
  },
3225
- provide: (field) => EditorView13.decorations.from(field)
3281
+ provide: (field) => EditorView12.decorations.from(field)
3226
3282
  });
3227
3283
  };
3228
- var buildDecorations4 = (from, to, state) => {
3284
+ var buildDecorations2 = (from, to, state) => {
3229
3285
  const decorations = [];
3230
3286
  const cursor = state.selection.main.head;
3231
- syntaxTree5(state).iterate({
3287
+ syntaxTree3(state).iterate({
3232
3288
  enter: (node) => {
3233
3289
  if (node.name === "Image") {
3234
3290
  const urlNode = node.node.getChild("URL");
3235
3291
  if (urlNode) {
3236
- const hide = state.readOnly || cursor < node.from || cursor > node.to;
3292
+ const hide2 = state.readOnly || cursor < node.from || cursor > node.to;
3237
3293
  const url = state.sliceDoc(urlNode.from, urlNode.to);
3238
- decorations.push(Decoration8.replace({
3294
+ decorations.push(Decoration5.replace({
3239
3295
  block: true,
3240
3296
  widget: new ImageWidget(url)
3241
- }).range(hide ? node.from : node.to, node.to));
3297
+ }).range(hide2 ? node.from : node.to, node.to));
3242
3298
  }
3243
3299
  }
3244
3300
  },
@@ -3247,7 +3303,7 @@ var buildDecorations4 = (from, to, state) => {
3247
3303
  });
3248
3304
  return decorations;
3249
3305
  };
3250
- var ImageWidget = class extends WidgetType4 {
3306
+ var ImageWidget = class extends WidgetType3 {
3251
3307
  constructor(_url) {
3252
3308
  super();
3253
3309
  this._url = _url;
@@ -3265,155 +3321,52 @@ var ImageWidget = class extends WidgetType4 {
3265
3321
  };
3266
3322
 
3267
3323
  // 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";
3324
+ import { syntaxTree as syntaxTree4 } from "@codemirror/language";
3325
+ import { hoverTooltip as hoverTooltip2 } from "@codemirror/view";
3271
3326
  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;
3327
+ var linkTooltip = (render) => hoverTooltip2((view, pos, side) => {
3328
+ const syntax = syntaxTree4(view.state).resolveInner(pos, side);
3329
+ let link = null;
3330
+ for (let i = 0, node = syntax; !link && node && i < 5; node = node.parent, i++) {
3331
+ link = node.name === "Link" ? node : null;
3332
+ }
3333
+ const url = link && link.getChild("URL");
3334
+ if (!url || !link) {
3335
+ return null;
3348
3336
  }
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
- });
3337
+ const urlText = view.state.sliceDoc(url.from, url.to);
3338
+ return {
3339
+ pos: link.from,
3340
+ end: link.to,
3341
+ above: true,
3342
+ create: () => {
3343
+ const el = document.createElement("div");
3344
+ el.className = tooltipContent({}, "pli-2 plb-1");
3345
+ render(el, urlText);
3346
+ return {
3347
+ dom: el,
3348
+ offset: {
3349
+ x: 0,
3350
+ y: 4
3351
+ }
3364
3352
  };
3365
3353
  }
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
- };
3354
+ };
3355
+ });
3403
3356
 
3404
3357
  // 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";
3358
+ import { syntaxTree as syntaxTree5 } from "@codemirror/language";
3359
+ import { RangeSetBuilder as RangeSetBuilder2, StateField as StateField5 } from "@codemirror/state";
3360
+ import { Decoration as Decoration6, EditorView as EditorView13, WidgetType as WidgetType4 } from "@codemirror/view";
3408
3361
  var table = (options = {}) => {
3409
3362
  return StateField5.define({
3410
3363
  create: (state) => update(state, options),
3411
3364
  update: (_, tr) => update(tr.state, options),
3412
- provide: (field) => EditorView14.decorations.from(field)
3365
+ provide: (field) => EditorView13.decorations.from(field)
3413
3366
  });
3414
3367
  };
3415
3368
  var update = (state, options) => {
3416
- const builder = new RangeSetBuilder6();
3369
+ const builder = new RangeSetBuilder2();
3417
3370
  const cursor = state.selection.main.head;
3418
3371
  const tables = [];
3419
3372
  const getTable = () => tables[tables.length - 1];
@@ -3421,7 +3374,7 @@ var update = (state, options) => {
3421
3374
  const table2 = getTable();
3422
3375
  return table2.rows?.[table2.rows.length - 1];
3423
3376
  };
3424
- syntaxTree7(state).iterate({
3377
+ syntaxTree5(state).iterate({
3425
3378
  enter: (node) => {
3426
3379
  switch (node.name) {
3427
3380
  case "Table": {
@@ -3452,17 +3405,17 @@ var update = (state, options) => {
3452
3405
  }
3453
3406
  });
3454
3407
  tables.forEach((table2) => {
3455
- const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
3456
- hide && builder.add(table2.from, table2.to, Decoration10.replace({
3408
+ const hide2 = state.readOnly || cursor < table2.from || cursor > table2.to;
3409
+ hide2 && builder.add(table2.from, table2.to, Decoration6.replace({
3457
3410
  widget: new TableWidget(table2)
3458
3411
  }));
3459
- builder.add(table2.from, table2.to, Decoration10.mark({
3412
+ builder.add(table2.from, table2.to, Decoration6.mark({
3460
3413
  class: "cm-table"
3461
3414
  }));
3462
3415
  });
3463
3416
  return builder.finish();
3464
3417
  };
3465
- var TableWidget = class extends WidgetType6 {
3418
+ var TableWidget = class extends WidgetType4 {
3466
3419
  constructor(_table) {
3467
3420
  super();
3468
3421
  this._table = _table;
@@ -3499,103 +3452,6 @@ var TableWidget = class extends WidgetType6 {
3499
3452
  }
3500
3453
  };
3501
3454
 
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
3455
  // packages/ui/react-ui-editor/src/extensions/mention.ts
3600
3456
  import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
3601
3457
  var mention = ({ onSearch }) => {
@@ -3993,7 +3849,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
3993
3849
  selection,
3994
3850
  extensions: [
3995
3851
  // TODO(burdon): Doesn't catch errors in keymap functions.
3996
- EditorView16.exceptionSink.of((err) => {
3852
+ EditorView14.exceptionSink.of((err) => {
3997
3853
  log3.catch(err, void 0, {
3998
3854
  F: __dxlog_file4,
3999
3855
  L: 113,
@@ -4003,17 +3859,17 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
4003
3859
  }),
4004
3860
  // Theme.
4005
3861
  // TODO(burdon): Make configurable.
4006
- EditorView16.baseTheme(defaultTheme),
4007
- EditorView16.theme(theme ?? {}),
4008
- EditorView16.darkTheme.of(themeMode === "dark"),
4009
- EditorView16.editorAttributes.of({
3862
+ EditorView14.baseTheme(defaultTheme),
3863
+ EditorView14.theme(theme ?? {}),
3864
+ EditorView14.darkTheme.of(themeMode === "dark"),
3865
+ EditorView14.editorAttributes.of({
4010
3866
  class: slots.editor?.className ?? ""
4011
3867
  }),
4012
- EditorView16.contentAttributes.of({
3868
+ EditorView14.contentAttributes.of({
4013
3869
  class: slots.content?.className ?? ""
4014
3870
  }),
4015
3871
  // Focus.
4016
- EditorView16.updateListener.of((update2) => {
3872
+ EditorView14.updateListener.of((update2) => {
4017
3873
  update2.transactions.forEach((transaction) => {
4018
3874
  if (transaction.isUserEvent("focus.container")) {
4019
3875
  rootRef.current?.focus();
@@ -4021,7 +3877,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
4021
3877
  });
4022
3878
  }),
4023
3879
  // State.
4024
- EditorView16.editable.of(!readonly),
3880
+ EditorView14.editable.of(!readonly),
4025
3881
  EditorState2.readOnly.of(!!readonly),
4026
3882
  // Storage and replication.
4027
3883
  // NOTE: This must come before user extensions.
@@ -4030,7 +3886,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
4030
3886
  ...extensions
4031
3887
  ].filter(isNotFalsy4)
4032
3888
  });
4033
- const newView = new EditorView16({
3889
+ const newView = new EditorView14({
4034
3890
  state,
4035
3891
  parent: rootRef.current,
4036
3892
  scrollTo,
@@ -4147,32 +4003,12 @@ var defaultMarkdownSlots = {
4147
4003
  import { ChatText, Code, CodeBlock, Link, ListBullets, ListChecks, ListNumbers, Paragraph, TextStrikethrough, Table as Table2, TextB, TextHOne, TextHTwo, TextHThree, TextHFour, TextHFive, TextHSix, TextItalic, Quotes } from "@phosphor-icons/react";
4148
4004
  import { createContext } from "@radix-ui/react-context";
4149
4005
  import React2 from "react";
4150
- import { DensityProvider, ElevationProvider, Select, Toolbar as NaturalToolbar, useTranslation } from "@dxos/react-ui";
4006
+ import { DensityProvider, ElevationProvider, Select, Toolbar as NaturalToolbar, Tooltip, useTranslation } from "@dxos/react-ui";
4151
4007
  import { getSize } from "@dxos/react-ui-theme";
4152
-
4153
- // packages/ui/react-ui-editor/src/translations.ts
4154
- var translationKey = "react-ui-editor";
4155
- var translations_default = [
4156
- {
4157
- "en-US": {
4158
- [translationKey]: {
4159
- "strong label": "Strong",
4160
- "emphasis label": "Emphasis",
4161
- "strikethrough label": "Strike-through",
4162
- "code label": "Code",
4163
- "list-bullet label": "Bullet list",
4164
- "list-ordered label": "Numbered list",
4165
- "list-task label": "Task list",
4166
- "blockquote label": "Block quote",
4167
- "codeblock label": "Code block",
4168
- "comment label": "Create comment",
4169
- "heading label": "Heading level"
4170
- }
4171
- }
4172
- }
4173
- ];
4174
-
4175
- // packages/ui/react-ui-editor/src/components/Toolbar/Toolbar.tsx
4008
+ var tooltipProps = {
4009
+ side: "top",
4010
+ classNames: "z-10"
4011
+ };
4176
4012
  var HeadingIcons = {
4177
4013
  "0": Paragraph,
4178
4014
  "1": TextHOne,
@@ -4201,7 +4037,9 @@ var ToolbarRoot = ({ children, onAction, classNames, state }) => {
4201
4037
  var buttonStyles = "min-bs-0 p-2";
4202
4038
  var iconStyles = getSize(5);
4203
4039
  var ToolbarButton = ({ Icon, children, ...props }) => {
4204
- return /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroupItem, {
4040
+ return /* @__PURE__ */ React2.createElement(Tooltip.Root, null, /* @__PURE__ */ React2.createElement(Tooltip.Trigger, {
4041
+ asChild: true
4042
+ }, /* @__PURE__ */ React2.createElement(NaturalToolbar.ToggleGroupItem, {
4205
4043
  variant: "ghost",
4206
4044
  ...props,
4207
4045
  classNames: buttonStyles
@@ -4209,7 +4047,7 @@ var ToolbarButton = ({ Icon, children, ...props }) => {
4209
4047
  className: iconStyles
4210
4048
  }), /* @__PURE__ */ React2.createElement("span", {
4211
4049
  className: "sr-only"
4212
- }, children));
4050
+ }, children))), /* @__PURE__ */ React2.createElement(Tooltip.Portal, null, /* @__PURE__ */ React2.createElement(Tooltip.Content, tooltipProps, children, /* @__PURE__ */ React2.createElement(Tooltip.Arrow, null))));
4213
4051
  };
4214
4052
  var ToolbarSeparator = () => /* @__PURE__ */ React2.createElement("div", {
4215
4053
  role: "separator",
@@ -4222,13 +4060,15 @@ var MarkdownHeading = () => {
4222
4060
  const header = blockType && /heading(\d)/.exec(blockType);
4223
4061
  const value = header ? header[1] : blockType === "paragraph" || !blockType ? "0" : void 0;
4224
4062
  const HeadingIcon = HeadingIcons[value ?? "0"];
4225
- return /* @__PURE__ */ React2.createElement(Select.Root, {
4063
+ return /* @__PURE__ */ React2.createElement(Tooltip.Root, null, /* @__PURE__ */ React2.createElement(Select.Root, {
4226
4064
  disabled: value === null,
4227
4065
  value: value ?? "0",
4228
4066
  onValueChange: (value2) => onAction?.({
4229
4067
  type: "heading",
4230
4068
  data: parseInt(value2)
4231
4069
  })
4070
+ }, /* @__PURE__ */ React2.createElement(Tooltip.Trigger, {
4071
+ asChild: true
4232
4072
  }, /* @__PURE__ */ React2.createElement(NaturalToolbar.Button, {
4233
4073
  asChild: true
4234
4074
  }, /* @__PURE__ */ React2.createElement(Select.TriggerButton, {
@@ -4238,7 +4078,7 @@ var MarkdownHeading = () => {
4238
4078
  className: "sr-only"
4239
4079
  }, t("heading label")), /* @__PURE__ */ React2.createElement(HeadingIcon, {
4240
4080
  className: iconStyles
4241
- }))), /* @__PURE__ */ React2.createElement(Select.Portal, null, /* @__PURE__ */ React2.createElement(Select.Content, null, /* @__PURE__ */ React2.createElement(Select.ScrollUpButton, null), /* @__PURE__ */ React2.createElement(Select.Viewport, null, /* @__PURE__ */ React2.createElement(Select.Option, {
4081
+ })))), /* @__PURE__ */ React2.createElement(Select.Portal, null, /* @__PURE__ */ React2.createElement(Select.Content, null, /* @__PURE__ */ React2.createElement(Select.ScrollUpButton, null), /* @__PURE__ */ React2.createElement(Select.Viewport, null, /* @__PURE__ */ React2.createElement(Select.Option, {
4242
4082
  value: "0"
4243
4083
  }, /* @__PURE__ */ React2.createElement(Paragraph, {
4244
4084
  className: iconStyles
@@ -4264,7 +4104,7 @@ var MarkdownHeading = () => {
4264
4104
  className: iconStyles
4265
4105
  }), level === 6 && /* @__PURE__ */ React2.createElement(TextHSix, {
4266
4106
  className: iconStyles
4267
- })))), /* @__PURE__ */ React2.createElement(Select.ScrollDownButton, null), /* @__PURE__ */ React2.createElement(Select.Arrow, null))));
4107
+ })))), /* @__PURE__ */ React2.createElement(Select.ScrollDownButton, null), /* @__PURE__ */ React2.createElement(Select.Arrow, null)))), /* @__PURE__ */ React2.createElement(Tooltip.Portal, null, /* @__PURE__ */ React2.createElement(Tooltip.Content, tooltipProps, t("heading label"), /* @__PURE__ */ React2.createElement(Tooltip.Arrow, null))));
4268
4108
  };
4269
4109
  var markdownStyles = [
4270
4110
  {
@@ -4352,8 +4192,7 @@ var markdownBlocks = [
4352
4192
  {
4353
4193
  type: "codeblock",
4354
4194
  Icon: CodeBlock,
4355
- getState: (state) => state.blockType === "codeblock",
4356
- disabled: (state) => !state.blankLine
4195
+ getState: (state) => state.blockType === "codeblock"
4357
4196
  },
4358
4197
  {
4359
4198
  type: "table",
@@ -4384,7 +4223,9 @@ var MarkdownStandard = () => /* @__PURE__ */ React2.createElement(React2.Fragmen
4384
4223
  var MarkdownExtended = () => {
4385
4224
  const { onAction } = useToolbarContext("MarkdownStyles");
4386
4225
  const { t } = useTranslation(translationKey);
4387
- return /* @__PURE__ */ React2.createElement(NaturalToolbar.Button, {
4226
+ return /* @__PURE__ */ React2.createElement(Tooltip.Root, null, /* @__PURE__ */ React2.createElement(Tooltip.Trigger, {
4227
+ asChild: true
4228
+ }, /* @__PURE__ */ React2.createElement(NaturalToolbar.Button, {
4388
4229
  variant: "ghost",
4389
4230
  "data-testid": "editor.toolbar.comment",
4390
4231
  onClick: () => onAction?.({
@@ -4395,7 +4236,7 @@ var MarkdownExtended = () => {
4395
4236
  className: iconStyles
4396
4237
  }), /* @__PURE__ */ React2.createElement("span", {
4397
4238
  className: "sr-only"
4398
- }, t("comment label")));
4239
+ }, t("comment label")))), /* @__PURE__ */ React2.createElement(Tooltip.Portal, null, /* @__PURE__ */ React2.createElement(Tooltip.Content, tooltipProps, t("comment label"), /* @__PURE__ */ React2.createElement(Tooltip.Arrow, null))));
4399
4240
  };
4400
4241
  var Toolbar = {
4401
4242
  Root: ToolbarRoot,
@@ -4586,7 +4427,7 @@ var useEditorView = (id) => {
4586
4427
 
4587
4428
  // packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
4588
4429
  import { EditorSelection as EditorSelection2, EditorState as EditorState3 } from "@codemirror/state";
4589
- import { EditorView as EditorView17 } from "@codemirror/view";
4430
+ import { EditorView as EditorView15 } from "@codemirror/view";
4590
4431
  import { useEffect as useEffect3, useRef as useRef3, useState as useState4 } from "react";
4591
4432
  import { log as log5 } from "@dxos/log";
4592
4433
  import { isNotFalsy as isNotFalsy5 } from "@dxos/util";
@@ -4603,7 +4444,7 @@ var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions }
4603
4444
  selection,
4604
4445
  extensions: [
4605
4446
  // TODO(burdon): Doesn't catch errors in keymap functions.
4606
- EditorView17.exceptionSink.of((err) => {
4447
+ EditorView15.exceptionSink.of((err) => {
4607
4448
  log5.catch(err, void 0, {
4608
4449
  F: __dxlog_file6,
4609
4450
  L: 60,
@@ -4612,12 +4453,12 @@ var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions }
4612
4453
  });
4613
4454
  }),
4614
4455
  extensions,
4615
- EditorView17.updateListener.of(() => {
4456
+ EditorView15.updateListener.of(() => {
4616
4457
  onUpdate.current?.();
4617
4458
  })
4618
4459
  ].filter(isNotFalsy5)
4619
4460
  });
4620
- view2 = new EditorView17({
4461
+ view2 = new EditorView15({
4621
4462
  parent: parentRef.current,
4622
4463
  scrollTo,
4623
4464
  state,
@@ -4675,19 +4516,19 @@ var createDataExtensions = ({ readonly = false } = {}) => {
4675
4516
  return [
4676
4517
  //
4677
4518
  EditorState3.readOnly.of(readonly),
4678
- EditorView17.editable.of(!readonly)
4519
+ EditorView15.editable.of(!readonly)
4679
4520
  ];
4680
4521
  };
4681
4522
  var createThemeExtensions = ({ theme, themeMode, slots } = {}) => {
4682
4523
  return [
4683
4524
  //
4684
- EditorView17.baseTheme(defaultTheme),
4685
- theme && EditorView17.theme(theme),
4686
- EditorView17.darkTheme.of(themeMode === "dark"),
4687
- EditorView17.editorAttributes.of({
4525
+ EditorView15.baseTheme(defaultTheme),
4526
+ theme && EditorView15.theme(theme),
4527
+ EditorView15.darkTheme.of(themeMode === "dark"),
4528
+ EditorView15.editorAttributes.of({
4688
4529
  class: slots?.editor?.className ?? ""
4689
4530
  }),
4690
- EditorView17.contentAttributes.of({
4531
+ EditorView15.contentAttributes.of({
4691
4532
  class: slots?.content?.className ?? ""
4692
4533
  })
4693
4534
  ].filter(isNotFalsy5);
@@ -4787,7 +4628,6 @@ export {
4787
4628
  awarenessProvider,
4788
4629
  blast,
4789
4630
  callbackWrapper,
4790
- code2 as code,
4791
4631
  codeTheme,
4792
4632
  comments,
4793
4633
  compareFormatting,
@@ -4798,6 +4638,7 @@ export {
4798
4638
  createThemeExtensions,
4799
4639
  cursorLineMargin,
4800
4640
  cursorLineMarginFacet,
4641
+ decorateMarkdown,
4801
4642
  defaultMarkdownSlots,
4802
4643
  defaultOptions,
4803
4644
  defaultSlots,
@@ -4812,12 +4653,10 @@ export {
4812
4653
  formatting,
4813
4654
  getFormatting,
4814
4655
  getToken,
4815
- heading2 as heading,
4816
- hr,
4817
4656
  image,
4818
4657
  insertTable,
4819
4658
  keymap8 as keymap,
4820
- link,
4659
+ linkTooltip,
4821
4660
  listener,
4822
4661
  logChanges,
4823
4662
  markdownHighlightStyle,
@@ -4839,7 +4678,6 @@ export {
4839
4678
  setStyle,
4840
4679
  table,
4841
4680
  tags2 as tags,
4842
- tasklist,
4843
4681
  textTheme,
4844
4682
  toggleBlockquote,
4845
4683
  toggleCodeblock,
@@ -4849,6 +4687,7 @@ export {
4849
4687
  toggleStrikethrough,
4850
4688
  toggleStrong,
4851
4689
  toggleStyle,
4690
+ translations_default as translations,
4852
4691
  typewriter,
4853
4692
  useActionHandler,
4854
4693
  useComments,