@dxos/react-ui-editor 0.3.11-main.5cbcf4e → 0.3.11-main.5e05862
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.
- package/dist/lib/browser/index.mjs +1141 -146
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/types/src/components/TextEditor/hooks.stories.d.ts.map +1 -1
- package/dist/types/src/components/Toolbar/Toolbar.d.ts +8 -4
- package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts +5 -3
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/formatting.d.ts +47 -9
- package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/formatting.test.d.ts +3 -0
- package/dist/types/src/extensions/markdown/formatting.test.d.ts.map +1 -0
- package/dist/types/src/hooks/useActionHandler.d.ts.map +1 -1
- package/package.json +23 -23
- package/src/components/TextEditor/hooks.stories.tsx +6 -1
- package/src/components/Toolbar/Toolbar.stories.tsx +14 -2
- package/src/components/Toolbar/Toolbar.tsx +100 -23
- package/src/extensions/markdown/formatting.test.ts +481 -0
- package/src/extensions/markdown/formatting.ts +1036 -67
- package/src/hooks/useActionHandler.ts +48 -15
|
@@ -8,10 +8,10 @@ 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
|
|
11
|
+
import { EditorView as EditorView14 } from "@codemirror/view";
|
|
12
12
|
import { vim } from "@replit/codemirror-vim";
|
|
13
13
|
import defaultsDeep2 from "lodash.defaultsdeep";
|
|
14
|
-
import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useRef, useState } from "react";
|
|
14
|
+
import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useRef, useState as useState2 } from "react";
|
|
15
15
|
import { log as log2 } from "@dxos/log";
|
|
16
16
|
import { useThemeContext } from "@dxos/react-ui";
|
|
17
17
|
import { focusRing, mx as mx3 } from "@dxos/react-ui-theme";
|
|
@@ -1833,57 +1833,279 @@ var code2 = () => {
|
|
|
1833
1833
|
// packages/ui/react-ui-editor/src/extensions/markdown/formatting.ts
|
|
1834
1834
|
import { snippet } from "@codemirror/autocomplete";
|
|
1835
1835
|
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1836
|
-
import { RangeSetBuilder as RangeSetBuilder2 } from "@codemirror/state";
|
|
1837
|
-
import { Decoration as Decoration4, keymap as keymap5, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
|
|
1838
|
-
|
|
1839
|
-
|
|
1836
|
+
import { RangeSetBuilder as RangeSetBuilder2, EditorSelection } from "@codemirror/state";
|
|
1837
|
+
import { Decoration as Decoration4, EditorView as EditorView9, keymap as keymap5, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
|
|
1838
|
+
import { useState, useMemo } from "react";
|
|
1839
|
+
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;
|
|
1840
|
+
var Inline;
|
|
1841
|
+
(function(Inline2) {
|
|
1842
|
+
Inline2[Inline2["Strong"] = 0] = "Strong";
|
|
1843
|
+
Inline2[Inline2["Emphasis"] = 1] = "Emphasis";
|
|
1844
|
+
Inline2[Inline2["Strikethrough"] = 2] = "Strikethrough";
|
|
1845
|
+
Inline2[Inline2["Code"] = 3] = "Code";
|
|
1846
|
+
})(Inline || (Inline = {}));
|
|
1847
|
+
var List;
|
|
1848
|
+
(function(List2) {
|
|
1849
|
+
List2[List2["Ordered"] = 0] = "Ordered";
|
|
1850
|
+
List2[List2["Bullet"] = 1] = "Bullet";
|
|
1851
|
+
List2[List2["Task"] = 2] = "Task";
|
|
1852
|
+
})(List || (List = {}));
|
|
1853
|
+
var setHeading = (level) => ({ state, dispatch }) => {
|
|
1854
|
+
const { selection: { ranges }, doc } = state;
|
|
1840
1855
|
const changes = [];
|
|
1856
|
+
let prevBlock = -1;
|
|
1841
1857
|
for (const range of ranges) {
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
from
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
+
syntaxTree2(state).iterate({
|
|
1859
|
+
from: range.from,
|
|
1860
|
+
to: range.to,
|
|
1861
|
+
enter: (node) => {
|
|
1862
|
+
if (!Object.hasOwn(Textblocks, node.name) || prevBlock === node.from) {
|
|
1863
|
+
return;
|
|
1864
|
+
}
|
|
1865
|
+
prevBlock = node.from;
|
|
1866
|
+
const blockType = Textblocks[node.name];
|
|
1867
|
+
const isHeading = /heading(\d)/.exec(blockType);
|
|
1868
|
+
const curLevel = isHeading ? +isHeading[1] : node.name === "Paragraph" ? 0 : -1;
|
|
1869
|
+
if (curLevel < 0 || curLevel === level) {
|
|
1870
|
+
return;
|
|
1871
|
+
}
|
|
1872
|
+
if (curLevel === 0) {
|
|
1873
|
+
changes.push({
|
|
1874
|
+
from: node.from,
|
|
1875
|
+
insert: "#".repeat(level) + " "
|
|
1876
|
+
});
|
|
1877
|
+
} else if (node.name === "SetextHeading1" || node.name === "SetextHeading2") {
|
|
1878
|
+
const nextLine = doc.lineAt(node.to);
|
|
1879
|
+
if (level) {
|
|
1880
|
+
changes.push({
|
|
1881
|
+
from: node.from,
|
|
1882
|
+
insert: "#".repeat(level) + " "
|
|
1883
|
+
});
|
|
1884
|
+
}
|
|
1885
|
+
changes.push({
|
|
1886
|
+
from: nextLine.from - 1,
|
|
1887
|
+
to: nextLine.to
|
|
1888
|
+
});
|
|
1889
|
+
} else {
|
|
1890
|
+
if (level === 0) {
|
|
1891
|
+
changes.push({
|
|
1892
|
+
from: node.from,
|
|
1893
|
+
to: Math.min(node.to, node.from + curLevel + 1)
|
|
1894
|
+
});
|
|
1895
|
+
} else if (level < curLevel) {
|
|
1896
|
+
changes.push({
|
|
1897
|
+
from: node.from,
|
|
1898
|
+
to: node.from + (curLevel - level)
|
|
1899
|
+
});
|
|
1900
|
+
} else {
|
|
1901
|
+
changes.push({
|
|
1902
|
+
from: node.from,
|
|
1903
|
+
insert: "#".repeat(level - curLevel)
|
|
1904
|
+
});
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1858
1908
|
});
|
|
1859
1909
|
}
|
|
1910
|
+
if (!changes.length) {
|
|
1911
|
+
return false;
|
|
1912
|
+
}
|
|
1913
|
+
dispatch(state.update({
|
|
1914
|
+
changes,
|
|
1915
|
+
userEvent: "format.setHeading",
|
|
1916
|
+
scrollIntoView: true
|
|
1917
|
+
}));
|
|
1860
1918
|
return true;
|
|
1861
1919
|
};
|
|
1862
|
-
var
|
|
1863
|
-
const
|
|
1864
|
-
|
|
1865
|
-
if (
|
|
1866
|
-
|
|
1920
|
+
var setStyle = (type, enable) => ({ state, dispatch }) => {
|
|
1921
|
+
const marker = inlineMarkerText(type);
|
|
1922
|
+
const changes = state.changeByRange((range) => {
|
|
1923
|
+
if (!enable && range.empty) {
|
|
1924
|
+
const after = state.doc.sliceString(range.head, range.head + 6);
|
|
1925
|
+
const found = after.indexOf(marker);
|
|
1926
|
+
if (found >= 0 && /^[*~`]*$/.test(after.slice(0, found))) {
|
|
1927
|
+
const before = state.doc.sliceString(range.head - 6, range.head);
|
|
1928
|
+
if (before.slice(before.length - found - marker.length, before.length - found) === marker && [
|
|
1929
|
+
...before.slice(before.length - found)
|
|
1930
|
+
].reverse().join("") === after.slice(0, found)) {
|
|
1931
|
+
return {
|
|
1932
|
+
changes: [
|
|
1933
|
+
{
|
|
1934
|
+
from: range.head - marker.length - found,
|
|
1935
|
+
to: range.head - found
|
|
1936
|
+
},
|
|
1937
|
+
{
|
|
1938
|
+
from: range.head + found,
|
|
1939
|
+
to: range.head + found + marker.length
|
|
1940
|
+
}
|
|
1941
|
+
],
|
|
1942
|
+
range: EditorSelection.cursor(range.from - marker.length)
|
|
1943
|
+
};
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1867
1946
|
}
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1947
|
+
const changes2 = [];
|
|
1948
|
+
const changesAtEnd = [];
|
|
1949
|
+
let blockStart = -1;
|
|
1950
|
+
let blockEnd = -1;
|
|
1951
|
+
let startCovered = false;
|
|
1952
|
+
let endCovered = false;
|
|
1953
|
+
let { from, to } = range;
|
|
1954
|
+
syntaxTree2(state).iterate({
|
|
1955
|
+
from,
|
|
1956
|
+
to,
|
|
1957
|
+
enter: (node) => {
|
|
1958
|
+
const { name } = node;
|
|
1959
|
+
if (Object.hasOwn(Textblocks, name) && Textblocks[name] !== "codeblock") {
|
|
1960
|
+
blockStart = blockContentStart(node);
|
|
1961
|
+
blockEnd = blockContentEnd(node, state.doc);
|
|
1962
|
+
startCovered = endCovered = false;
|
|
1963
|
+
} else if (name === "Link" || name === "Image" && enable) {
|
|
1964
|
+
if (from < node.from && to > node.from && to <= node.to) {
|
|
1965
|
+
to = node.to;
|
|
1966
|
+
} else if (to > node.to && from >= node.from && from < node.to) {
|
|
1967
|
+
from = node.from;
|
|
1968
|
+
}
|
|
1969
|
+
} else if (IgnoreInline.has(name) && enable) {
|
|
1970
|
+
if (node.from < from && node.to > from) {
|
|
1971
|
+
if (to === from) {
|
|
1972
|
+
to = node.to;
|
|
1973
|
+
}
|
|
1974
|
+
from = node.to;
|
|
1975
|
+
}
|
|
1976
|
+
if (node.from < to && node.to > to) {
|
|
1977
|
+
to = node.from;
|
|
1978
|
+
}
|
|
1979
|
+
} else if (Object.hasOwn(InlineMarker, name)) {
|
|
1980
|
+
const markType = InlineMarker[name];
|
|
1981
|
+
const size = inlineMarkerText(markType).length;
|
|
1982
|
+
const openEnd = node.from + size;
|
|
1983
|
+
const closeStart = node.to - size;
|
|
1984
|
+
if (markType === type) {
|
|
1985
|
+
if (openEnd <= from && closeStart >= from) {
|
|
1986
|
+
startCovered = openEnd === from ? "adjacent" : true;
|
|
1987
|
+
}
|
|
1988
|
+
if (openEnd <= to && closeStart >= to) {
|
|
1989
|
+
endCovered = closeStart === to ? "adjacent" : true;
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
if (markType === type || type === 3 && enable) {
|
|
1993
|
+
if (node.from >= from && openEnd <= to) {
|
|
1994
|
+
changes2.push({
|
|
1995
|
+
from: node.from,
|
|
1996
|
+
to: openEnd
|
|
1997
|
+
});
|
|
1998
|
+
if (markType !== type && closeStart >= to) {
|
|
1999
|
+
changesAtEnd.push({
|
|
2000
|
+
from: skipSpaces(Math.min(to, blockEnd), state.doc, 1, blockEnd),
|
|
2001
|
+
insert: inlineMarkerText(markType)
|
|
2002
|
+
});
|
|
2003
|
+
}
|
|
2004
|
+
}
|
|
2005
|
+
if (closeStart >= from && node.to <= to) {
|
|
2006
|
+
changes2.push({
|
|
2007
|
+
from: closeStart,
|
|
2008
|
+
to: node.to
|
|
2009
|
+
});
|
|
2010
|
+
if (markType !== type && openEnd <= from) {
|
|
2011
|
+
changes2.push({
|
|
2012
|
+
from: skipSpaces(Math.max(from, blockStart), state.doc, -1, blockStart),
|
|
2013
|
+
insert: inlineMarkerText(markType)
|
|
2014
|
+
});
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
1877
2018
|
}
|
|
1878
|
-
|
|
2019
|
+
},
|
|
2020
|
+
leave: (node) => {
|
|
2021
|
+
if (Object.hasOwn(Textblocks, node.name) && Textblocks[node.name] !== "codeblock") {
|
|
2022
|
+
const rangeStart = Math.max(from, blockStart);
|
|
2023
|
+
const rangeEnd = Math.min(to, blockEnd);
|
|
2024
|
+
if (enable) {
|
|
2025
|
+
if (!startCovered) {
|
|
2026
|
+
changes2.push({
|
|
2027
|
+
from: rangeStart,
|
|
2028
|
+
insert: marker
|
|
2029
|
+
});
|
|
2030
|
+
}
|
|
2031
|
+
if (!endCovered) {
|
|
2032
|
+
changes2.push({
|
|
2033
|
+
from: rangeEnd,
|
|
2034
|
+
insert: marker
|
|
2035
|
+
});
|
|
2036
|
+
}
|
|
2037
|
+
} else {
|
|
2038
|
+
if (startCovered === "adjacent") {
|
|
2039
|
+
changes2.push({
|
|
2040
|
+
from: from - marker.length,
|
|
2041
|
+
to: from
|
|
2042
|
+
});
|
|
2043
|
+
} else if (startCovered) {
|
|
2044
|
+
changes2.push({
|
|
2045
|
+
from: skipSpaces(rangeStart, state.doc, -1, blockStart),
|
|
2046
|
+
insert: marker
|
|
2047
|
+
});
|
|
2048
|
+
}
|
|
2049
|
+
if (endCovered === "adjacent") {
|
|
2050
|
+
changes2.push({
|
|
2051
|
+
from: to,
|
|
2052
|
+
to: to + marker.length
|
|
2053
|
+
});
|
|
2054
|
+
} else if (endCovered) {
|
|
2055
|
+
changes2.push({
|
|
2056
|
+
from: skipSpaces(rangeEnd, state.doc, 1, blockEnd),
|
|
2057
|
+
insert: marker
|
|
2058
|
+
});
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
}
|
|
1879
2063
|
});
|
|
1880
|
-
|
|
2064
|
+
const changeSet = state.changes(changes2.concat(changesAtEnd));
|
|
2065
|
+
return {
|
|
2066
|
+
changes: changeSet,
|
|
2067
|
+
range: range.empty && !changeSet.empty ? EditorSelection.cursor(range.head + marker.length) : EditorSelection.range(changeSet.mapPos(range.from, 1), changeSet.mapPos(range.to, -1))
|
|
2068
|
+
};
|
|
2069
|
+
});
|
|
2070
|
+
dispatch(state.update(changes, {
|
|
2071
|
+
userEvent: enable ? "format.style.add" : "format.style.remove",
|
|
2072
|
+
scrollIntoView: true
|
|
2073
|
+
}));
|
|
1881
2074
|
return true;
|
|
1882
2075
|
};
|
|
2076
|
+
var blockContentStart = (node) => {
|
|
2077
|
+
const atx = /^ATXHeading(\d)/.exec(node.name);
|
|
2078
|
+
if (atx) {
|
|
2079
|
+
return Math.min(node.to, node.from + +atx[1] + 1);
|
|
2080
|
+
}
|
|
2081
|
+
return node.from;
|
|
2082
|
+
};
|
|
2083
|
+
var blockContentEnd = (node, doc) => {
|
|
2084
|
+
const setext = /^SetextHeading(\d)/.exec(node.name);
|
|
2085
|
+
const lastLine = doc.lineAt(node.to);
|
|
2086
|
+
if (setext || /^[\s>]*$/.exec(lastLine.text)) {
|
|
2087
|
+
return lastLine.from - 1;
|
|
2088
|
+
}
|
|
2089
|
+
return node.to;
|
|
2090
|
+
};
|
|
2091
|
+
var inlineMarkerText = (type) => type === 0 ? "**" : type === 2 ? "~~" : type === 1 ? "*" : "`";
|
|
2092
|
+
var skipSpaces = (pos, doc, dir, limit) => {
|
|
2093
|
+
const line = doc.lineAt(pos);
|
|
2094
|
+
while (pos !== limit && line.text[pos - line.from - (dir < 0 ? 1 : 0)] === " ") {
|
|
2095
|
+
pos += dir;
|
|
2096
|
+
}
|
|
2097
|
+
return pos;
|
|
2098
|
+
};
|
|
2099
|
+
var addStyle = (style) => setStyle(style, true);
|
|
2100
|
+
var removeStyle = (style) => setStyle(style, false);
|
|
2101
|
+
var toggleStyle = (style) => (arg) => {
|
|
2102
|
+
const form = getFormatting(arg.state);
|
|
2103
|
+
return setStyle(style, style === 0 ? !form.strong : style === 1 ? !form.emphasis : style === 2 ? !form.strikethrough : !form.code)(arg);
|
|
2104
|
+
};
|
|
1883
2105
|
var snippets = {
|
|
1884
2106
|
codeblock: snippet([
|
|
1885
2107
|
"```#{lang}",
|
|
1886
|
-
"
|
|
2108
|
+
"#{}",
|
|
1887
2109
|
"```"
|
|
1888
2110
|
].join("\n")),
|
|
1889
2111
|
table: snippet([
|
|
@@ -1893,29 +2115,537 @@ var snippets = {
|
|
|
1893
2115
|
"| #{val3} | #{val4} |"
|
|
1894
2116
|
].join("\n"))
|
|
1895
2117
|
};
|
|
1896
|
-
var insertCodeblock = (view) => {
|
|
1897
|
-
const { selection: { main }, doc } = view.state;
|
|
1898
|
-
const { number } = doc.lineAt(main.anchor);
|
|
1899
|
-
const { from } = doc.line(number);
|
|
1900
|
-
snippets.codeblock(view, null, from, from);
|
|
1901
|
-
};
|
|
1902
2118
|
var insertTable = (view) => {
|
|
1903
2119
|
const { selection: { main }, doc } = view.state;
|
|
1904
2120
|
const { number } = doc.lineAt(main.anchor);
|
|
1905
2121
|
const { from } = doc.line(number);
|
|
1906
2122
|
snippets.table(view, null, from, from);
|
|
1907
2123
|
};
|
|
1908
|
-
var
|
|
1909
|
-
var
|
|
1910
|
-
var toggleStrikethrough = toggleStyle(
|
|
1911
|
-
var
|
|
2124
|
+
var toggleStrong = toggleStyle(0);
|
|
2125
|
+
var toggleEmphasis = toggleStyle(1);
|
|
2126
|
+
var toggleStrikethrough = toggleStyle(2);
|
|
2127
|
+
var toggleInlineCode = toggleStyle(3);
|
|
2128
|
+
var removeLinkInner = (from, to, changes, state) => {
|
|
2129
|
+
syntaxTree2(state).iterate({
|
|
2130
|
+
from,
|
|
2131
|
+
to,
|
|
2132
|
+
enter: (node) => {
|
|
2133
|
+
if (node.name === "Link" && node.from < to && node.to > from) {
|
|
2134
|
+
node.node.cursor().iterate((node2) => {
|
|
2135
|
+
const { name } = node2;
|
|
2136
|
+
if (name === "LinkMark" || name === "LinkLabel") {
|
|
2137
|
+
changes.push({
|
|
2138
|
+
from: node2.from,
|
|
2139
|
+
to: node2.to
|
|
2140
|
+
});
|
|
2141
|
+
} else if (name === "LinkTitle" || name === "URL") {
|
|
2142
|
+
changes.push({
|
|
2143
|
+
from: skipSpaces(node2.from, state.doc, -1),
|
|
2144
|
+
to: skipSpaces(node2.to, state.doc, 1)
|
|
2145
|
+
});
|
|
2146
|
+
}
|
|
2147
|
+
});
|
|
2148
|
+
return false;
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2151
|
+
});
|
|
2152
|
+
};
|
|
2153
|
+
var removeLink = ({ state, dispatch }) => {
|
|
2154
|
+
const changes = [];
|
|
2155
|
+
for (const { from, to } of state.selection.ranges) {
|
|
2156
|
+
removeLinkInner(from, to, changes, state);
|
|
2157
|
+
}
|
|
2158
|
+
if (!changes) {
|
|
2159
|
+
return false;
|
|
2160
|
+
}
|
|
2161
|
+
dispatch(state.update({
|
|
2162
|
+
changes,
|
|
2163
|
+
userEvent: "format.link.remove",
|
|
2164
|
+
scrollIntoView: true
|
|
2165
|
+
}));
|
|
2166
|
+
return true;
|
|
2167
|
+
};
|
|
2168
|
+
var addLink = ({ state, dispatch }) => {
|
|
2169
|
+
const changes = state.changeByRange((range) => {
|
|
2170
|
+
let { from, to } = range;
|
|
2171
|
+
const cutStyles = [];
|
|
2172
|
+
let okay = null;
|
|
2173
|
+
syntaxTree2(state).iterate({
|
|
2174
|
+
from,
|
|
2175
|
+
to,
|
|
2176
|
+
enter: (node) => {
|
|
2177
|
+
if (Object.hasOwn(Textblocks, node.name)) {
|
|
2178
|
+
okay = Textblocks[node.name] !== "codeblock" && from >= blockContentStart(node) && to <= blockContentEnd(node, state.doc);
|
|
2179
|
+
} else if (Object.hasOwn(InlineMarker, node.name)) {
|
|
2180
|
+
const sNode = node.node;
|
|
2181
|
+
if (node.from < from && node.to <= to) {
|
|
2182
|
+
if (sNode.firstChild.to === from) {
|
|
2183
|
+
from = node.from;
|
|
2184
|
+
} else {
|
|
2185
|
+
cutStyles.push(sNode);
|
|
2186
|
+
}
|
|
2187
|
+
} else if (node.from >= from && node.to > to) {
|
|
2188
|
+
if (sNode.lastChild.from === to) {
|
|
2189
|
+
to = node.to;
|
|
2190
|
+
} else {
|
|
2191
|
+
cutStyles.push(sNode);
|
|
2192
|
+
}
|
|
2193
|
+
}
|
|
2194
|
+
}
|
|
2195
|
+
}
|
|
2196
|
+
});
|
|
2197
|
+
if (okay === null) {
|
|
2198
|
+
const line = state.doc.lineAt(from);
|
|
2199
|
+
okay = to <= line.to && !/\S/.test(line.text.slice(from - line.from));
|
|
2200
|
+
}
|
|
2201
|
+
if (!okay) {
|
|
2202
|
+
return {
|
|
2203
|
+
range
|
|
2204
|
+
};
|
|
2205
|
+
}
|
|
2206
|
+
const changes2 = [];
|
|
2207
|
+
const changesAfter = [];
|
|
2208
|
+
removeLinkInner(from, to, changesAfter, state);
|
|
2209
|
+
let cursorOffset = 1;
|
|
2210
|
+
for (const style of cutStyles) {
|
|
2211
|
+
const type = InlineMarker[style.name];
|
|
2212
|
+
const mark2 = inlineMarkerText(type);
|
|
2213
|
+
if (style.from < from) {
|
|
2214
|
+
changes2.push({
|
|
2215
|
+
from: skipSpaces(from, state.doc, -1),
|
|
2216
|
+
insert: mark2
|
|
2217
|
+
});
|
|
2218
|
+
changesAfter.push({
|
|
2219
|
+
from: skipSpaces(from, state.doc, 1, to),
|
|
2220
|
+
insert: mark2
|
|
2221
|
+
});
|
|
2222
|
+
} else {
|
|
2223
|
+
changes2.push({
|
|
2224
|
+
from: skipSpaces(to, state.doc, -1, from),
|
|
2225
|
+
insert: mark2
|
|
2226
|
+
});
|
|
2227
|
+
const after = skipSpaces(to, state.doc, 1);
|
|
2228
|
+
if (after === to) {
|
|
2229
|
+
cursorOffset += mark2.length;
|
|
2230
|
+
}
|
|
2231
|
+
changesAfter.push({
|
|
2232
|
+
from: after,
|
|
2233
|
+
insert: mark2
|
|
2234
|
+
});
|
|
2235
|
+
}
|
|
2236
|
+
}
|
|
2237
|
+
changes2.push({
|
|
2238
|
+
from,
|
|
2239
|
+
insert: "["
|
|
2240
|
+
}, {
|
|
2241
|
+
from: to,
|
|
2242
|
+
insert: "]()"
|
|
2243
|
+
});
|
|
2244
|
+
const changeSet = state.changes(changes2.concat(changesAfter));
|
|
2245
|
+
return {
|
|
2246
|
+
changes: changeSet,
|
|
2247
|
+
range: EditorSelection.cursor(changeSet.mapPos(to, 1) - cursorOffset)
|
|
2248
|
+
};
|
|
2249
|
+
});
|
|
2250
|
+
if (changes.changes.empty) {
|
|
2251
|
+
return false;
|
|
2252
|
+
}
|
|
2253
|
+
dispatch(state.update(changes, {
|
|
2254
|
+
userEvent: "format.link.add",
|
|
2255
|
+
scrollIntoView: true
|
|
2256
|
+
}));
|
|
2257
|
+
return true;
|
|
2258
|
+
};
|
|
2259
|
+
var addList = (type) => ({ state, dispatch }) => {
|
|
2260
|
+
let lastBlock = -1;
|
|
2261
|
+
let counter = 1;
|
|
2262
|
+
let first = true;
|
|
2263
|
+
let parentColumn = null;
|
|
2264
|
+
const blocks = [];
|
|
2265
|
+
for (const { from, to } of state.selection.ranges) {
|
|
2266
|
+
syntaxTree2(state).iterate({
|
|
2267
|
+
from,
|
|
2268
|
+
to,
|
|
2269
|
+
enter: (node) => {
|
|
2270
|
+
if (Object.hasOwn(Textblocks, node.name) && node.name !== "TableCell" || node.name === "Table") {
|
|
2271
|
+
if (first) {
|
|
2272
|
+
let before = node.node.prevSibling;
|
|
2273
|
+
while (before && /Mark$/.test(before.name)) {
|
|
2274
|
+
before = before.prevSibling;
|
|
2275
|
+
}
|
|
2276
|
+
if (before?.name === (type === 0 ? "OrderedList" : "BulletList")) {
|
|
2277
|
+
const item = before.lastChild;
|
|
2278
|
+
const itemLine = state.doc.lineAt(item.from);
|
|
2279
|
+
const itemText = itemLine.text.slice(item.from - itemLine.from);
|
|
2280
|
+
parentColumn = item.from - itemLine.from + /^\s*/.exec(itemText)[0].length;
|
|
2281
|
+
if (type === 0) {
|
|
2282
|
+
const mark2 = /^\s*(\d+)[.)]/.exec(itemText);
|
|
2283
|
+
if (mark2) {
|
|
2284
|
+
parentColumn += mark2[1].length;
|
|
2285
|
+
counter = +mark2[1] + 1;
|
|
2286
|
+
}
|
|
2287
|
+
}
|
|
2288
|
+
}
|
|
2289
|
+
first = false;
|
|
2290
|
+
}
|
|
2291
|
+
if (node.from === lastBlock) {
|
|
2292
|
+
return;
|
|
2293
|
+
}
|
|
2294
|
+
lastBlock = node.from;
|
|
2295
|
+
blocks.push({
|
|
2296
|
+
node: node.node,
|
|
2297
|
+
counter,
|
|
2298
|
+
parentColumn
|
|
2299
|
+
});
|
|
2300
|
+
counter++;
|
|
2301
|
+
return false;
|
|
2302
|
+
}
|
|
2303
|
+
},
|
|
2304
|
+
leave: (node) => {
|
|
2305
|
+
if (node.name === "BulletList" || node.name === "OrderedList" || node.name === "Blockquote") {
|
|
2306
|
+
counter = 1;
|
|
2307
|
+
parentColumn = null;
|
|
2308
|
+
}
|
|
2309
|
+
}
|
|
2310
|
+
});
|
|
2311
|
+
}
|
|
2312
|
+
if (!blocks.length) {
|
|
2313
|
+
return false;
|
|
2314
|
+
}
|
|
2315
|
+
const changes = [];
|
|
2316
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
2317
|
+
const { node, counter: counter2, parentColumn: parentColumn2 } = blocks[i];
|
|
2318
|
+
const nodeFrom = node.name === "CodeBlock" ? node.from - 4 : node.from;
|
|
2319
|
+
let padding = nodeFrom > 0 && !/\s/.test(state.doc.sliceString(nodeFrom - 1, nodeFrom)) ? 1 : 0;
|
|
2320
|
+
if (type === 0) {
|
|
2321
|
+
padding += String(counter2).length;
|
|
2322
|
+
}
|
|
2323
|
+
let line = state.doc.lineAt(nodeFrom);
|
|
2324
|
+
const column = nodeFrom - line.from;
|
|
2325
|
+
if (parentColumn2 !== null && parentColumn2 > column) {
|
|
2326
|
+
padding = Math.max(padding, parentColumn2 - column);
|
|
2327
|
+
}
|
|
2328
|
+
let mark2;
|
|
2329
|
+
if (type === 0) {
|
|
2330
|
+
let max = counter2;
|
|
2331
|
+
for (let j = i + 1; j < blocks.length; j++) {
|
|
2332
|
+
if (blocks[j].counter !== max + 1) {
|
|
2333
|
+
break;
|
|
2334
|
+
}
|
|
2335
|
+
max++;
|
|
2336
|
+
}
|
|
2337
|
+
const num = String(counter2);
|
|
2338
|
+
padding = Math.max(String(max).length, padding);
|
|
2339
|
+
mark2 = " ".repeat(Math.max(0, padding - num.length)) + num + ". ";
|
|
2340
|
+
} else {
|
|
2341
|
+
mark2 = " ".repeat(padding) + "- " + (type === 2 ? "[ ] " : "");
|
|
2342
|
+
}
|
|
2343
|
+
changes.push({
|
|
2344
|
+
from: nodeFrom,
|
|
2345
|
+
insert: mark2
|
|
2346
|
+
});
|
|
2347
|
+
while (line.to < node.to) {
|
|
2348
|
+
line = state.doc.lineAt(line.to + 1);
|
|
2349
|
+
const open = /^[\s>]*/.exec(line.text)[0].length;
|
|
2350
|
+
changes.push({
|
|
2351
|
+
from: line.from + Math.min(open, column),
|
|
2352
|
+
insert: " ".repeat(mark2.length)
|
|
2353
|
+
});
|
|
2354
|
+
}
|
|
2355
|
+
}
|
|
2356
|
+
if (type === 0) {
|
|
2357
|
+
const last = blocks[blocks.length - 1];
|
|
2358
|
+
let next = last.node.nextSibling;
|
|
2359
|
+
while (next && /Mark$/.test(next.name)) {
|
|
2360
|
+
next = next.nextSibling;
|
|
2361
|
+
}
|
|
2362
|
+
if (next?.name === "OrderedList") {
|
|
2363
|
+
renumberListItems(next.firstChild, last.counter + 1, changes, state.doc);
|
|
2364
|
+
}
|
|
2365
|
+
}
|
|
2366
|
+
dispatch(state.update({
|
|
2367
|
+
changes,
|
|
2368
|
+
userEvent: "format.list.add",
|
|
2369
|
+
scrollIntoView: true
|
|
2370
|
+
}));
|
|
2371
|
+
return true;
|
|
2372
|
+
};
|
|
2373
|
+
var removeList = (type) => ({ state, dispatch }) => {
|
|
2374
|
+
let lastBlock = -1;
|
|
2375
|
+
const changes = [];
|
|
2376
|
+
const stack = [];
|
|
2377
|
+
const targetNodeType = type === 0 ? "OrderedList" : type === 1 ? "BulletList" : "TaskList";
|
|
2378
|
+
for (const { from, to } of state.selection.ranges) {
|
|
2379
|
+
syntaxTree2(state).iterate({
|
|
2380
|
+
from,
|
|
2381
|
+
to,
|
|
2382
|
+
enter: (node) => {
|
|
2383
|
+
const { name } = node;
|
|
2384
|
+
if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
|
|
2385
|
+
stack.push(name);
|
|
2386
|
+
} else if (name === "Task" && stack[stack.length - 1] === "BulletList") {
|
|
2387
|
+
stack[stack.length - 1] = "TaskList";
|
|
2388
|
+
}
|
|
2389
|
+
},
|
|
2390
|
+
leave: (node) => {
|
|
2391
|
+
const { name } = node;
|
|
2392
|
+
if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
|
|
2393
|
+
stack.pop();
|
|
2394
|
+
} else if (name === "ListItem" && stack[stack.length - 1] === targetNodeType && node.from !== lastBlock) {
|
|
2395
|
+
lastBlock = node.from;
|
|
2396
|
+
let line = state.doc.lineAt(node.from);
|
|
2397
|
+
const mark2 = /^\s*(\d+[.)] |[-*+] (\[[ x]\] )?)/.exec(line.text.slice(node.from - line.from));
|
|
2398
|
+
if (!mark2) {
|
|
2399
|
+
return false;
|
|
2400
|
+
}
|
|
2401
|
+
const column = node.from - line.from;
|
|
2402
|
+
changes.push({
|
|
2403
|
+
from: node.from,
|
|
2404
|
+
to: node.from + mark2[0].length
|
|
2405
|
+
});
|
|
2406
|
+
while (line.to < node.to) {
|
|
2407
|
+
line = state.doc.lineAt(line.to + 1);
|
|
2408
|
+
const open = /^[\s>]*/.exec(line.text)[0].length;
|
|
2409
|
+
if (open > column) {
|
|
2410
|
+
changes.push({
|
|
2411
|
+
from: line.from + column,
|
|
2412
|
+
to: line.from + Math.min(column + mark2[0].length, open)
|
|
2413
|
+
});
|
|
2414
|
+
}
|
|
2415
|
+
}
|
|
2416
|
+
if (node.to >= to) {
|
|
2417
|
+
renumberListItems(node.node.nextSibling, 1, changes, state.doc);
|
|
2418
|
+
}
|
|
2419
|
+
return false;
|
|
2420
|
+
}
|
|
2421
|
+
}
|
|
2422
|
+
});
|
|
2423
|
+
}
|
|
2424
|
+
if (!changes.length) {
|
|
2425
|
+
return false;
|
|
2426
|
+
}
|
|
2427
|
+
dispatch(state.update({
|
|
2428
|
+
changes,
|
|
2429
|
+
userEvent: "format.list.remove",
|
|
2430
|
+
scrollIntoView: true
|
|
2431
|
+
}));
|
|
2432
|
+
return true;
|
|
2433
|
+
};
|
|
2434
|
+
var toggleList = (type) => (target) => {
|
|
2435
|
+
const formatting2 = getFormatting(target.state);
|
|
2436
|
+
const active = formatting2.listStyle === (type === 1 ? "bullet" : type === 0 ? "ordered" : "task");
|
|
2437
|
+
return (active ? removeList(type) : addList(type))(target);
|
|
2438
|
+
};
|
|
2439
|
+
var renumberListItems = (item, counter, changes, doc) => {
|
|
2440
|
+
for (; item; item = item.nextSibling) {
|
|
2441
|
+
if (item.name === "ListItem") {
|
|
2442
|
+
const number = /(\s*)(\d+)[.)]/.exec(doc.sliceString(item.from, item.from + 10));
|
|
2443
|
+
if (!number || +number[2] === counter) {
|
|
2444
|
+
break;
|
|
2445
|
+
}
|
|
2446
|
+
const size = number[1].length + number[2].length;
|
|
2447
|
+
const newNum = String(counter);
|
|
2448
|
+
changes.push({
|
|
2449
|
+
from: item.from + Math.max(0, size - newNum.length),
|
|
2450
|
+
to: item.from + size,
|
|
2451
|
+
insert: newNum
|
|
2452
|
+
});
|
|
2453
|
+
counter++;
|
|
2454
|
+
}
|
|
2455
|
+
}
|
|
2456
|
+
};
|
|
2457
|
+
var setBlockquote = (enable) => ({ state, dispatch }) => {
|
|
2458
|
+
const lines = [];
|
|
2459
|
+
let lastBlock = -1;
|
|
2460
|
+
for (const { from, to } of state.selection.ranges) {
|
|
2461
|
+
syntaxTree2(state).iterate({
|
|
2462
|
+
from,
|
|
2463
|
+
to,
|
|
2464
|
+
enter: (node) => {
|
|
2465
|
+
if (Object.hasOwn(Textblocks, node.name) || node.name === "Table") {
|
|
2466
|
+
if (node.from === lastBlock) {
|
|
2467
|
+
return false;
|
|
2468
|
+
}
|
|
2469
|
+
lastBlock = node.from;
|
|
2470
|
+
let line = state.doc.lineAt(node.from);
|
|
2471
|
+
if (line.number > 1) {
|
|
2472
|
+
const prevLine = state.doc.line(line.number - 1);
|
|
2473
|
+
if (/^[>\s]*$/.test(prevLine.text)) {
|
|
2474
|
+
if (!enable || lines.length && lines[lines.length - 1].number === prevLine.number - 1) {
|
|
2475
|
+
lines.push(prevLine);
|
|
2476
|
+
}
|
|
2477
|
+
}
|
|
2478
|
+
}
|
|
2479
|
+
for (; ; ) {
|
|
2480
|
+
lines.push(line);
|
|
2481
|
+
if (line.to >= node.to) {
|
|
2482
|
+
break;
|
|
2483
|
+
}
|
|
2484
|
+
line = state.doc.line(line.number + 1);
|
|
2485
|
+
}
|
|
2486
|
+
if (!enable && line.number < state.doc.lines) {
|
|
2487
|
+
const nextLine = state.doc.line(line.number + 1);
|
|
2488
|
+
if (/^[>\s]*$/.test(nextLine.text)) {
|
|
2489
|
+
lines.push(nextLine);
|
|
2490
|
+
}
|
|
2491
|
+
}
|
|
2492
|
+
return false;
|
|
2493
|
+
}
|
|
2494
|
+
}
|
|
2495
|
+
});
|
|
2496
|
+
}
|
|
2497
|
+
const changes = [];
|
|
2498
|
+
for (const line of lines) {
|
|
2499
|
+
if (enable) {
|
|
2500
|
+
changes.push({
|
|
2501
|
+
from: line.from,
|
|
2502
|
+
insert: /\S/.test(line.text) ? "> " : ">"
|
|
2503
|
+
});
|
|
2504
|
+
} else {
|
|
2505
|
+
const quote = /((?:[\s>\-+*]|\d+[.)])*?)> ?/.exec(line.text);
|
|
2506
|
+
if (quote) {
|
|
2507
|
+
changes.push({
|
|
2508
|
+
from: line.from + quote[1].length,
|
|
2509
|
+
to: line.from + quote[0].length
|
|
2510
|
+
});
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
2513
|
+
}
|
|
2514
|
+
if (!changes.length) {
|
|
2515
|
+
return false;
|
|
2516
|
+
}
|
|
2517
|
+
dispatch(state.update({
|
|
2518
|
+
changes,
|
|
2519
|
+
userEvent: enable ? "format.blockquote.add" : "format.blockquote.remove",
|
|
2520
|
+
scrollIntoView: true
|
|
2521
|
+
}));
|
|
2522
|
+
return true;
|
|
2523
|
+
};
|
|
2524
|
+
var addBlockquote = setBlockquote(true);
|
|
2525
|
+
var removeBlockquote = setBlockquote(false);
|
|
2526
|
+
var toggleBlockquote = (target) => {
|
|
2527
|
+
return (getFormatting(target.state).blockquote ? removeBlockquote : addBlockquote)(target);
|
|
2528
|
+
};
|
|
2529
|
+
var addCodeblock = (target) => {
|
|
2530
|
+
const { state, dispatch } = target;
|
|
2531
|
+
const { selection } = state;
|
|
2532
|
+
if (selection.ranges.length === 1 && selection.main.empty) {
|
|
2533
|
+
const { head } = selection.main;
|
|
2534
|
+
const line = state.doc.lineAt(head);
|
|
2535
|
+
if (!/\S/.test(line.text) && head === line.from) {
|
|
2536
|
+
snippets.codeblock(target, null, line.from, line.to);
|
|
2537
|
+
return true;
|
|
2538
|
+
}
|
|
2539
|
+
}
|
|
2540
|
+
const ranges = [];
|
|
2541
|
+
for (const { from, to } of selection.ranges) {
|
|
2542
|
+
let blockFrom = from;
|
|
2543
|
+
let blockTo = to;
|
|
2544
|
+
syntaxTree2(state).iterate({
|
|
2545
|
+
from,
|
|
2546
|
+
to,
|
|
2547
|
+
enter: (node) => {
|
|
2548
|
+
if (Object.hasOwn(Textblocks, node.name)) {
|
|
2549
|
+
if (from >= node.from && to <= node.to) {
|
|
2550
|
+
blockFrom = node.from;
|
|
2551
|
+
blockTo = node.to;
|
|
2552
|
+
} else {
|
|
2553
|
+
blockFrom = Math.min(blockFrom, state.doc.lineAt(node.from).from);
|
|
2554
|
+
blockTo = Math.max(blockTo, state.doc.lineAt(node.to).to);
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2557
|
+
}
|
|
2558
|
+
});
|
|
2559
|
+
if (ranges.length && ranges[ranges.length - 1].to >= blockFrom - 1) {
|
|
2560
|
+
ranges[ranges.length - 1].to = blockTo;
|
|
2561
|
+
} else {
|
|
2562
|
+
ranges.push({
|
|
2563
|
+
from: blockFrom,
|
|
2564
|
+
to: blockTo
|
|
2565
|
+
});
|
|
2566
|
+
}
|
|
2567
|
+
}
|
|
2568
|
+
if (!ranges.length) {
|
|
2569
|
+
return false;
|
|
2570
|
+
}
|
|
2571
|
+
const changes = ranges.map(({ from, to }) => {
|
|
2572
|
+
const column = from - state.doc.lineAt(from).from;
|
|
2573
|
+
return [
|
|
2574
|
+
{
|
|
2575
|
+
from,
|
|
2576
|
+
insert: "```\n" + " ".repeat(column)
|
|
2577
|
+
},
|
|
2578
|
+
{
|
|
2579
|
+
from: to,
|
|
2580
|
+
insert: "\n" + " ".repeat(column) + "```"
|
|
2581
|
+
}
|
|
2582
|
+
];
|
|
2583
|
+
});
|
|
2584
|
+
dispatch(state.update({
|
|
2585
|
+
changes,
|
|
2586
|
+
userEvent: "format.codeblock.add",
|
|
2587
|
+
scrollIntoView: true
|
|
2588
|
+
}));
|
|
2589
|
+
return true;
|
|
2590
|
+
};
|
|
2591
|
+
var removeCodeblock = ({ state, dispatch }) => {
|
|
2592
|
+
const changes = [];
|
|
2593
|
+
let lastBlock = -1;
|
|
2594
|
+
for (const { from, to } of state.selection.ranges) {
|
|
2595
|
+
syntaxTree2(state).iterate({
|
|
2596
|
+
from,
|
|
2597
|
+
to,
|
|
2598
|
+
enter: (node) => {
|
|
2599
|
+
if (Textblocks[node.name] === "codeblock" && lastBlock !== node.from) {
|
|
2600
|
+
lastBlock = node.from;
|
|
2601
|
+
const firstLine = state.doc.lineAt(node.from);
|
|
2602
|
+
if (node.name === "FencedCode") {
|
|
2603
|
+
changes.push({
|
|
2604
|
+
from: node.from,
|
|
2605
|
+
to: firstLine.to + 1 + node.from - firstLine.from
|
|
2606
|
+
});
|
|
2607
|
+
const lastLine = state.doc.lineAt(node.to);
|
|
2608
|
+
if (/^([\s>]|[-*+] |\d+[).])*`+$/.test(lastLine.text)) {
|
|
2609
|
+
changes.push({
|
|
2610
|
+
from: lastLine.from - (lastLine.number === firstLine.number + 1 ? 0 : 1),
|
|
2611
|
+
to: lastLine.to
|
|
2612
|
+
});
|
|
2613
|
+
}
|
|
2614
|
+
} else {
|
|
2615
|
+
const column = node.from - firstLine.from;
|
|
2616
|
+
for (let line = firstLine; ; line = state.doc.line(line.number + 1)) {
|
|
2617
|
+
changes.push({
|
|
2618
|
+
from: line.from + column - 4,
|
|
2619
|
+
to: line.from + column
|
|
2620
|
+
});
|
|
2621
|
+
if (line.to >= node.to) {
|
|
2622
|
+
break;
|
|
2623
|
+
}
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2626
|
+
}
|
|
2627
|
+
}
|
|
2628
|
+
});
|
|
2629
|
+
}
|
|
2630
|
+
if (!changes.length) {
|
|
2631
|
+
return false;
|
|
2632
|
+
}
|
|
2633
|
+
dispatch(state.update({
|
|
2634
|
+
changes,
|
|
2635
|
+
userEvent: "format.codeblock.remove",
|
|
2636
|
+
scrollIntoView: true
|
|
2637
|
+
}));
|
|
2638
|
+
return true;
|
|
2639
|
+
};
|
|
2640
|
+
var toggleCodeblock = (target) => {
|
|
2641
|
+
return (getFormatting(target.state).blockType === "codeblock" ? removeCodeblock : addCodeblock)(target);
|
|
1912
2642
|
};
|
|
1913
2643
|
var formatting = (options = {}) => {
|
|
1914
2644
|
return [
|
|
1915
2645
|
keymap5.of([
|
|
1916
2646
|
{
|
|
1917
2647
|
key: "meta-b",
|
|
1918
|
-
run:
|
|
2648
|
+
run: toggleStrong
|
|
1919
2649
|
}
|
|
1920
2650
|
]),
|
|
1921
2651
|
styling()
|
|
@@ -1969,6 +2699,206 @@ var styling = () => {
|
|
|
1969
2699
|
})
|
|
1970
2700
|
];
|
|
1971
2701
|
};
|
|
2702
|
+
var InlineMarker = {
|
|
2703
|
+
Emphasis: 1,
|
|
2704
|
+
StrongEmphasis: 0,
|
|
2705
|
+
InlineCode: 3,
|
|
2706
|
+
Strikethrough: 2
|
|
2707
|
+
};
|
|
2708
|
+
var IgnoreInline = /* @__PURE__ */ new Set([
|
|
2709
|
+
"Hardbreak",
|
|
2710
|
+
"HTMLTag",
|
|
2711
|
+
"Comment",
|
|
2712
|
+
"ProcessingInstruction",
|
|
2713
|
+
"Autolink",
|
|
2714
|
+
"HeaderMark",
|
|
2715
|
+
"QuoteMark",
|
|
2716
|
+
"ListMark",
|
|
2717
|
+
"LinkMark",
|
|
2718
|
+
"EmphasisMark",
|
|
2719
|
+
"CodeMark",
|
|
2720
|
+
"CodeText",
|
|
2721
|
+
"StrikethroughMark",
|
|
2722
|
+
"TaskMarker",
|
|
2723
|
+
"SuperscriptMark",
|
|
2724
|
+
"SubscriptMark"
|
|
2725
|
+
]);
|
|
2726
|
+
var Textblocks = {
|
|
2727
|
+
Paragraph: "paragraph",
|
|
2728
|
+
Task: "paragraph",
|
|
2729
|
+
CodeBlock: "codeblock",
|
|
2730
|
+
FencedCode: "codeblock",
|
|
2731
|
+
ATXHeading1: "heading1",
|
|
2732
|
+
ATXHeading2: "heading2",
|
|
2733
|
+
ATXHeading3: "heading3",
|
|
2734
|
+
ATXHeading4: "heading4",
|
|
2735
|
+
ATXHeading5: "heading5",
|
|
2736
|
+
ATXHeading6: "heading6",
|
|
2737
|
+
SetextHeading1: "heading1",
|
|
2738
|
+
SetextHeading2: "heading2",
|
|
2739
|
+
TableCell: "tablecell"
|
|
2740
|
+
};
|
|
2741
|
+
var getFormatting = (state) => {
|
|
2742
|
+
let blockType = null;
|
|
2743
|
+
const inline = [
|
|
2744
|
+
null,
|
|
2745
|
+
null,
|
|
2746
|
+
null,
|
|
2747
|
+
null
|
|
2748
|
+
];
|
|
2749
|
+
let link2 = false;
|
|
2750
|
+
let blockquote2 = null;
|
|
2751
|
+
let listStyle = null;
|
|
2752
|
+
const stack = [];
|
|
2753
|
+
let currentBlock = null;
|
|
2754
|
+
const advanceInline = (upto) => {
|
|
2755
|
+
if (!currentBlock) {
|
|
2756
|
+
return;
|
|
2757
|
+
}
|
|
2758
|
+
upto = Math.min(upto, currentBlock.end);
|
|
2759
|
+
if (upto <= currentBlock.pos) {
|
|
2760
|
+
return;
|
|
2761
|
+
}
|
|
2762
|
+
for (let i = 0; i < currentBlock.active.length; i++) {
|
|
2763
|
+
if (inline[i] === false) {
|
|
2764
|
+
continue;
|
|
2765
|
+
} else if (currentBlock.active[i]) {
|
|
2766
|
+
inline[i] = true;
|
|
2767
|
+
} else if (/\S/.test(state.doc.sliceString(currentBlock.pos, upto))) {
|
|
2768
|
+
inline[i] = false;
|
|
2769
|
+
}
|
|
2770
|
+
}
|
|
2771
|
+
currentBlock.pos = upto;
|
|
2772
|
+
};
|
|
2773
|
+
const skipInline = (upto) => {
|
|
2774
|
+
if (currentBlock && upto > currentBlock.pos) {
|
|
2775
|
+
currentBlock.pos = Math.min(upto, currentBlock.end);
|
|
2776
|
+
}
|
|
2777
|
+
};
|
|
2778
|
+
const { selection } = state;
|
|
2779
|
+
for (const range of selection.ranges) {
|
|
2780
|
+
if (range.empty && inline.some((v) => v === null)) {
|
|
2781
|
+
const contextSize = Math.min(range.head, 6);
|
|
2782
|
+
const contextBefore = state.doc.sliceString(range.head - contextSize, range.head);
|
|
2783
|
+
let contextAfter = state.doc.sliceString(range.head, range.head + contextSize);
|
|
2784
|
+
for (let i = 0; i < contextSize; i++) {
|
|
2785
|
+
const ch = contextAfter[i];
|
|
2786
|
+
if (ch !== contextBefore[contextBefore.length - 1 - i] || !/[~`*]/.test(ch)) {
|
|
2787
|
+
contextAfter = contextAfter.slice(0, i);
|
|
2788
|
+
break;
|
|
2789
|
+
}
|
|
2790
|
+
}
|
|
2791
|
+
for (let i = 0; i < inline.length; i++) {
|
|
2792
|
+
const mark2 = inlineMarkerText(i);
|
|
2793
|
+
const found = contextAfter.indexOf(mark2);
|
|
2794
|
+
if (found > -1) {
|
|
2795
|
+
contextAfter = contextAfter.slice(0, found) + contextAfter.slice(found + mark2.length);
|
|
2796
|
+
if (inline[i] === null) {
|
|
2797
|
+
inline[i] = true;
|
|
2798
|
+
}
|
|
2799
|
+
}
|
|
2800
|
+
}
|
|
2801
|
+
}
|
|
2802
|
+
syntaxTree2(state).iterate({
|
|
2803
|
+
from: range.from,
|
|
2804
|
+
to: range.to,
|
|
2805
|
+
enter: (node) => {
|
|
2806
|
+
advanceInline(node.from);
|
|
2807
|
+
const { name } = node;
|
|
2808
|
+
if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
|
|
2809
|
+
stack.push(name);
|
|
2810
|
+
} else if (name === "Link") {
|
|
2811
|
+
link2 = true;
|
|
2812
|
+
} else if (Object.hasOwn(Textblocks, name) && (range.empty || node.to > range.from || node.from < range.to)) {
|
|
2813
|
+
if (name === "Task" && stack[stack.length - 1] === "BulletList") {
|
|
2814
|
+
stack[stack.length - 1] = "TaskList";
|
|
2815
|
+
}
|
|
2816
|
+
const blockCode = Textblocks[name];
|
|
2817
|
+
if (blockType === null) {
|
|
2818
|
+
blockType = blockCode;
|
|
2819
|
+
} else if (blockType !== blockCode) {
|
|
2820
|
+
blockType = false;
|
|
2821
|
+
}
|
|
2822
|
+
if (blockCode !== "codeblock" && inline.some((i) => i !== false)) {
|
|
2823
|
+
currentBlock = {
|
|
2824
|
+
pos: Math.max(range.from, node.from),
|
|
2825
|
+
end: Math.min(range.to, node.to),
|
|
2826
|
+
active: [
|
|
2827
|
+
false,
|
|
2828
|
+
false,
|
|
2829
|
+
false,
|
|
2830
|
+
false
|
|
2831
|
+
]
|
|
2832
|
+
};
|
|
2833
|
+
}
|
|
2834
|
+
} else if (Object.hasOwn(InlineMarker, name) && currentBlock) {
|
|
2835
|
+
const index = InlineMarker[name];
|
|
2836
|
+
if (range.empty && inline[index] === null) {
|
|
2837
|
+
inline[index] = true;
|
|
2838
|
+
}
|
|
2839
|
+
currentBlock.active[index] = true;
|
|
2840
|
+
} else if (IgnoreInline.has(name)) {
|
|
2841
|
+
skipInline(node.to);
|
|
2842
|
+
}
|
|
2843
|
+
},
|
|
2844
|
+
leave: (node) => {
|
|
2845
|
+
advanceInline(node.to);
|
|
2846
|
+
const { name } = node;
|
|
2847
|
+
if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
|
|
2848
|
+
stack.pop();
|
|
2849
|
+
} else if (Object.hasOwn(Textblocks, name)) {
|
|
2850
|
+
let hasList = false;
|
|
2851
|
+
let hasQuote = false;
|
|
2852
|
+
for (let i = stack.length - 1; i >= 0; i--) {
|
|
2853
|
+
if (stack[i] === "Blockquote") {
|
|
2854
|
+
hasQuote = true;
|
|
2855
|
+
} else if (!hasList) {
|
|
2856
|
+
hasList = stack[i] === "TaskList" ? "task" : stack[i] === "BulletList" ? "bullet" : "ordered";
|
|
2857
|
+
}
|
|
2858
|
+
}
|
|
2859
|
+
if (blockquote2 === null) {
|
|
2860
|
+
blockquote2 = hasQuote;
|
|
2861
|
+
} else if (!hasQuote && blockquote2) {
|
|
2862
|
+
blockquote2 = false;
|
|
2863
|
+
}
|
|
2864
|
+
if (listStyle === null) {
|
|
2865
|
+
listStyle = hasList;
|
|
2866
|
+
} else if (listStyle !== hasList) {
|
|
2867
|
+
listStyle = false;
|
|
2868
|
+
}
|
|
2869
|
+
currentBlock = null;
|
|
2870
|
+
} else if (Object.hasOwn(InlineMarker, name) && currentBlock) {
|
|
2871
|
+
currentBlock.active[InlineMarker[name]] = false;
|
|
2872
|
+
}
|
|
2873
|
+
}
|
|
2874
|
+
});
|
|
2875
|
+
}
|
|
2876
|
+
return {
|
|
2877
|
+
blockType: blockType || null,
|
|
2878
|
+
strong: inline[0] ?? false,
|
|
2879
|
+
emphasis: inline[1] ?? false,
|
|
2880
|
+
code: inline[3] ?? false,
|
|
2881
|
+
strikethrough: inline[2] ?? false,
|
|
2882
|
+
link: link2,
|
|
2883
|
+
blockquote: blockquote2 ?? false,
|
|
2884
|
+
listStyle: listStyle || null
|
|
2885
|
+
};
|
|
2886
|
+
};
|
|
2887
|
+
var useFormattingState = () => {
|
|
2888
|
+
const [state, setState] = useState(null);
|
|
2889
|
+
const observer = useMemo(() => EditorView9.updateListener.of((update2) => {
|
|
2890
|
+
if (update2.docChanged || update2.selectionSet) {
|
|
2891
|
+
const newState = getFormatting(update2.state);
|
|
2892
|
+
if (!state || !compareFormatting(state, newState)) {
|
|
2893
|
+
setState(newState);
|
|
2894
|
+
}
|
|
2895
|
+
}
|
|
2896
|
+
}), []);
|
|
2897
|
+
return [
|
|
2898
|
+
state,
|
|
2899
|
+
observer
|
|
2900
|
+
];
|
|
2901
|
+
};
|
|
1972
2902
|
|
|
1973
2903
|
// packages/ui/react-ui-editor/src/extensions/markdown/heading.ts
|
|
1974
2904
|
import { syntaxTree as syntaxTree3 } from "@codemirror/language";
|
|
@@ -2021,8 +2951,8 @@ var heading2 = () => {
|
|
|
2021
2951
|
// packages/ui/react-ui-editor/src/extensions/markdown/hr.ts
|
|
2022
2952
|
import { syntaxTree as syntaxTree4 } from "@codemirror/language";
|
|
2023
2953
|
import { RangeSetBuilder as RangeSetBuilder4 } from "@codemirror/state";
|
|
2024
|
-
import { Decoration as Decoration6, EditorView as
|
|
2025
|
-
var styles4 =
|
|
2954
|
+
import { Decoration as Decoration6, EditorView as EditorView10, ViewPlugin as ViewPlugin6, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
2955
|
+
var styles4 = EditorView10.baseTheme({
|
|
2026
2956
|
"& .cm-hr": {
|
|
2027
2957
|
// Note that block-level decorations should not have vertical margins,
|
|
2028
2958
|
borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
|
|
@@ -2076,7 +3006,7 @@ var hr = () => {
|
|
|
2076
3006
|
// packages/ui/react-ui-editor/src/extensions/markdown/image.ts
|
|
2077
3007
|
import { syntaxTree as syntaxTree5 } from "@codemirror/language";
|
|
2078
3008
|
import { StateField as StateField3 } from "@codemirror/state";
|
|
2079
|
-
import { Decoration as Decoration7, EditorView as
|
|
3009
|
+
import { Decoration as Decoration7, EditorView as EditorView11, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
2080
3010
|
var image = (options = {}) => {
|
|
2081
3011
|
return StateField3.define({
|
|
2082
3012
|
create: (state) => {
|
|
@@ -2103,7 +3033,7 @@ var image = (options = {}) => {
|
|
|
2103
3033
|
add: buildDecorations4(from, to, tr.state)
|
|
2104
3034
|
});
|
|
2105
3035
|
},
|
|
2106
|
-
provide: (field) =>
|
|
3036
|
+
provide: (field) => EditorView11.decorations.from(field)
|
|
2107
3037
|
});
|
|
2108
3038
|
};
|
|
2109
3039
|
var buildDecorations4 = (from, to, state) => {
|
|
@@ -2285,12 +3215,12 @@ var buildDecorations5 = (view, options) => {
|
|
|
2285
3215
|
// packages/ui/react-ui-editor/src/extensions/markdown/table.ts
|
|
2286
3216
|
import { syntaxTree as syntaxTree7 } from "@codemirror/language";
|
|
2287
3217
|
import { RangeSetBuilder as RangeSetBuilder6, StateField as StateField4 } from "@codemirror/state";
|
|
2288
|
-
import { Decoration as Decoration9, EditorView as
|
|
3218
|
+
import { Decoration as Decoration9, EditorView as EditorView12, WidgetType as WidgetType6 } from "@codemirror/view";
|
|
2289
3219
|
var table = (options = {}) => {
|
|
2290
3220
|
return StateField4.define({
|
|
2291
3221
|
create: (state) => update(state, options),
|
|
2292
3222
|
update: (_, tr) => update(tr.state, options),
|
|
2293
|
-
provide: (field) =>
|
|
3223
|
+
provide: (field) => EditorView12.decorations.from(field)
|
|
2294
3224
|
});
|
|
2295
3225
|
};
|
|
2296
3226
|
var update = (state, options) => {
|
|
@@ -2383,8 +3313,8 @@ var TableWidget = class extends WidgetType6 {
|
|
|
2383
3313
|
// packages/ui/react-ui-editor/src/extensions/markdown/tasklist.ts
|
|
2384
3314
|
import { syntaxTree as syntaxTree8 } from "@codemirror/language";
|
|
2385
3315
|
import { RangeSetBuilder as RangeSetBuilder7 } from "@codemirror/state";
|
|
2386
|
-
import { EditorView as
|
|
2387
|
-
var styles5 =
|
|
3316
|
+
import { EditorView as EditorView13, Decoration as Decoration10, WidgetType as WidgetType7, ViewPlugin as ViewPlugin8 } from "@codemirror/view";
|
|
3317
|
+
var styles5 = EditorView13.baseTheme({
|
|
2388
3318
|
"& .cm-task": {
|
|
2389
3319
|
color: getToken("extend.colors.blue.500")
|
|
2390
3320
|
},
|
|
@@ -2817,7 +3747,7 @@ var EditorModes = [
|
|
|
2817
3747
|
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo, selection, editorMode, theme, slots = defaultSlots, extensions = [], debug }, forwardedRef) => {
|
|
2818
3748
|
const { themeMode } = useThemeContext();
|
|
2819
3749
|
const rootRef = useRef(null);
|
|
2820
|
-
const [view, setView] =
|
|
3750
|
+
const [view, setView] = useState2(null);
|
|
2821
3751
|
useImperativeHandle(forwardedRef, () => view, [
|
|
2822
3752
|
view
|
|
2823
3753
|
]);
|
|
@@ -2846,7 +3776,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
|
|
|
2846
3776
|
selection,
|
|
2847
3777
|
extensions: [
|
|
2848
3778
|
// TODO(burdon): Doesn't catch errors in keymap functions.
|
|
2849
|
-
|
|
3779
|
+
EditorView14.exceptionSink.of((err) => {
|
|
2850
3780
|
log2.catch(err, void 0, {
|
|
2851
3781
|
F: __dxlog_file3,
|
|
2852
3782
|
L: 134,
|
|
@@ -2856,17 +3786,17 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
|
|
|
2856
3786
|
}),
|
|
2857
3787
|
// Theme.
|
|
2858
3788
|
// TODO(burdon): Make configurable.
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
3789
|
+
EditorView14.baseTheme(defaultTheme),
|
|
3790
|
+
EditorView14.theme(theme ?? {}),
|
|
3791
|
+
EditorView14.darkTheme.of(themeMode === "dark"),
|
|
3792
|
+
EditorView14.editorAttributes.of({
|
|
2863
3793
|
class: slots.editor?.className ?? ""
|
|
2864
3794
|
}),
|
|
2865
|
-
|
|
3795
|
+
EditorView14.contentAttributes.of({
|
|
2866
3796
|
class: slots.content?.className ?? ""
|
|
2867
3797
|
}),
|
|
2868
3798
|
// State.
|
|
2869
|
-
|
|
3799
|
+
EditorView14.editable.of(!readonly),
|
|
2870
3800
|
EditorState2.readOnly.of(!!readonly),
|
|
2871
3801
|
// Storage and replication.
|
|
2872
3802
|
// NOTE: This must come before user extensions.
|
|
@@ -2877,7 +3807,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
|
|
|
2877
3807
|
...extensions
|
|
2878
3808
|
].filter(isNotFalsy3)
|
|
2879
3809
|
});
|
|
2880
|
-
const newView = new
|
|
3810
|
+
const newView = new EditorView14({
|
|
2881
3811
|
state,
|
|
2882
3812
|
parent: rootRef.current,
|
|
2883
3813
|
scrollTo,
|
|
@@ -2988,11 +3918,12 @@ import { At, CaretRight, ChatText, Code, Image, Link, ListBullets, ListChecks, L
|
|
|
2988
3918
|
import { createContext } from "@radix-ui/react-context";
|
|
2989
3919
|
import React2 from "react";
|
|
2990
3920
|
import { Button, DensityProvider, Select } from "@dxos/react-ui";
|
|
2991
|
-
import { getSize } from "@dxos/react-ui-theme";
|
|
3921
|
+
import { getSize, mx as mx4 } from "@dxos/react-ui-theme";
|
|
2992
3922
|
var [ToolbarContextProvider, useToolbarContext] = createContext("Toolbar");
|
|
2993
|
-
var ToolbarRoot = ({ children, onAction }) => {
|
|
3923
|
+
var ToolbarRoot = ({ children, onAction, state }) => {
|
|
2994
3924
|
return /* @__PURE__ */ React2.createElement(ToolbarContextProvider, {
|
|
2995
|
-
onAction
|
|
3925
|
+
onAction,
|
|
3926
|
+
state
|
|
2996
3927
|
}, /* @__PURE__ */ React2.createElement(DensityProvider, {
|
|
2997
3928
|
density: "fine"
|
|
2998
3929
|
}, /* @__PURE__ */ React2.createElement("div", {
|
|
@@ -3000,19 +3931,23 @@ var ToolbarRoot = ({ children, onAction }) => {
|
|
|
3000
3931
|
className: "flex w-full shrink-0 p-2 gap-4 items-center whitespace-nowrap overflow-hidden"
|
|
3001
3932
|
}, children)));
|
|
3002
3933
|
};
|
|
3003
|
-
var ToolbarButton = ({ Icon, onClick, title }) => {
|
|
3004
|
-
const { onAction } = useToolbarContext("ToolbarButton");
|
|
3005
|
-
const handleClick = () => {
|
|
3006
|
-
const action = onClick();
|
|
3934
|
+
var ToolbarButton = ({ Icon, onClick, title, getState, disable }) => {
|
|
3935
|
+
const { onAction, state } = useToolbarContext("ToolbarButton");
|
|
3936
|
+
const handleClick = (event) => {
|
|
3937
|
+
const action = onClick(state);
|
|
3007
3938
|
if (action) {
|
|
3008
3939
|
onAction?.(action);
|
|
3940
|
+
event.preventDefault();
|
|
3009
3941
|
}
|
|
3010
3942
|
};
|
|
3943
|
+
const active = getState && state ? getState(state) : false;
|
|
3944
|
+
const disabled = disable && state ? disable(state) : false;
|
|
3011
3945
|
return /* @__PURE__ */ React2.createElement(Button, {
|
|
3012
3946
|
variant: "ghost",
|
|
3013
|
-
classNames: "p-2",
|
|
3014
|
-
|
|
3015
|
-
title
|
|
3947
|
+
classNames: mx4("p-2", active && "ring"),
|
|
3948
|
+
onMouseDown: handleClick,
|
|
3949
|
+
title,
|
|
3950
|
+
disabled
|
|
3016
3951
|
}, /* @__PURE__ */ React2.createElement(Icon, {
|
|
3017
3952
|
className: getSize(5)
|
|
3018
3953
|
}));
|
|
@@ -3021,12 +3956,16 @@ var ToolbarSeparator = () => /* @__PURE__ */ React2.createElement("div", {
|
|
|
3021
3956
|
className: "grow"
|
|
3022
3957
|
});
|
|
3023
3958
|
var MarkdownHeading = () => {
|
|
3024
|
-
const { onAction } = useToolbarContext("MarkdownFormatting");
|
|
3959
|
+
const { onAction, state } = useToolbarContext("MarkdownFormatting");
|
|
3960
|
+
const blockType = state ? state.blockType : "paragraph";
|
|
3961
|
+
const header = blockType && /heading(\d)/.exec(blockType);
|
|
3962
|
+
const value = header ? header[1] : blockType === "paragraph" || !blockType ? "0" : null;
|
|
3025
3963
|
return /* @__PURE__ */ React2.createElement(Select.Root, {
|
|
3026
|
-
|
|
3027
|
-
|
|
3964
|
+
disabled: value === null,
|
|
3965
|
+
value: value ?? "0",
|
|
3966
|
+
onValueChange: (value2) => onAction?.({
|
|
3028
3967
|
type: "heading",
|
|
3029
|
-
data: parseInt(
|
|
3968
|
+
data: parseInt(value2)
|
|
3030
3969
|
})
|
|
3031
3970
|
}, /* @__PURE__ */ React2.createElement(Select.TriggerButton, {
|
|
3032
3971
|
classNames: "w-[8rem]"
|
|
@@ -3048,58 +3987,86 @@ var MarkdownStyles = () => /* @__PURE__ */ React2.createElement("div", {
|
|
|
3048
3987
|
role: "none"
|
|
3049
3988
|
}, /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3050
3989
|
Icon: TextB,
|
|
3051
|
-
title: "
|
|
3052
|
-
onClick: () => ({
|
|
3053
|
-
type: "
|
|
3054
|
-
|
|
3990
|
+
title: "String",
|
|
3991
|
+
onClick: (s) => ({
|
|
3992
|
+
type: "strong",
|
|
3993
|
+
data: s ? !s.strong : null
|
|
3994
|
+
}),
|
|
3995
|
+
getState: (s) => s.strong,
|
|
3996
|
+
disable: (s) => s.blockType === "codeblock"
|
|
3055
3997
|
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3056
3998
|
Icon: TextItalic,
|
|
3057
|
-
title: "
|
|
3058
|
-
onClick: () => ({
|
|
3059
|
-
type: "
|
|
3060
|
-
|
|
3999
|
+
title: "Emphasis",
|
|
4000
|
+
onClick: (s) => ({
|
|
4001
|
+
type: "emphasis",
|
|
4002
|
+
data: s ? !s.emphasis : null
|
|
4003
|
+
}),
|
|
4004
|
+
getState: (s) => s.emphasis,
|
|
4005
|
+
disable: (s) => s.blockType === "codeblock"
|
|
3061
4006
|
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3062
4007
|
Icon: TextStrikethrough,
|
|
3063
4008
|
title: "Strike-through",
|
|
3064
|
-
onClick: () => ({
|
|
3065
|
-
type: "strikethrough"
|
|
3066
|
-
|
|
4009
|
+
onClick: (s) => ({
|
|
4010
|
+
type: "strikethrough",
|
|
4011
|
+
data: s ? !s.strikethrough : null
|
|
4012
|
+
}),
|
|
4013
|
+
getState: (s) => s.strikethrough,
|
|
4014
|
+
disable: (s) => s.blockType === "codeblock"
|
|
4015
|
+
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
4016
|
+
Icon: Code,
|
|
4017
|
+
title: "Inline code",
|
|
4018
|
+
onClick: (s) => ({
|
|
4019
|
+
type: "code",
|
|
4020
|
+
data: s ? !s.code : null
|
|
4021
|
+
}),
|
|
4022
|
+
getState: (s) => s.code,
|
|
4023
|
+
disable: (s) => s.blockType === "codeblock"
|
|
3067
4024
|
}));
|
|
3068
4025
|
var MarkdownLists = () => /* @__PURE__ */ React2.createElement("div", {
|
|
3069
4026
|
role: "none"
|
|
3070
4027
|
}, /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3071
4028
|
Icon: ListBullets,
|
|
3072
4029
|
title: "Bullet list",
|
|
3073
|
-
onClick: () => ({
|
|
3074
|
-
type: "list"
|
|
3075
|
-
|
|
4030
|
+
onClick: (s) => ({
|
|
4031
|
+
type: "list-bullet",
|
|
4032
|
+
data: s ? s.listStyle !== "bullet" : null
|
|
4033
|
+
}),
|
|
4034
|
+
getState: (s) => s.listStyle === "bullet"
|
|
3076
4035
|
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3077
4036
|
Icon: ListNumbers,
|
|
3078
4037
|
title: "Numbered list",
|
|
3079
|
-
onClick: () => ({
|
|
3080
|
-
type: "list-ordered"
|
|
3081
|
-
|
|
4038
|
+
onClick: (s) => ({
|
|
4039
|
+
type: "list-ordered",
|
|
4040
|
+
data: s ? s.listStyle !== "ordered" : null
|
|
4041
|
+
}),
|
|
4042
|
+
getState: (s) => s.listStyle === "ordered"
|
|
3082
4043
|
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3083
4044
|
Icon: ListChecks,
|
|
3084
4045
|
title: "Task list",
|
|
3085
|
-
onClick: () => ({
|
|
3086
|
-
type: "list-tasks"
|
|
3087
|
-
|
|
4046
|
+
onClick: (s) => ({
|
|
4047
|
+
type: "list-tasks",
|
|
4048
|
+
data: s ? s.listStyle !== "task" : null
|
|
4049
|
+
}),
|
|
4050
|
+
getState: (s) => s.listStyle === "task"
|
|
3088
4051
|
}));
|
|
3089
4052
|
var MarkdownBlocks = () => /* @__PURE__ */ React2.createElement("div", {
|
|
3090
4053
|
role: "none"
|
|
3091
4054
|
}, /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3092
4055
|
Icon: CaretRight,
|
|
3093
|
-
title: "Block
|
|
3094
|
-
onClick: () => ({
|
|
3095
|
-
type: "blockquote"
|
|
3096
|
-
|
|
4056
|
+
title: "Block quote",
|
|
4057
|
+
onClick: (s) => ({
|
|
4058
|
+
type: "blockquote",
|
|
4059
|
+
data: s ? !s.blockquote : null
|
|
4060
|
+
}),
|
|
4061
|
+
getState: (s) => s.blockquote
|
|
3097
4062
|
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3098
4063
|
Icon: Code,
|
|
3099
4064
|
title: "Code block",
|
|
3100
|
-
onClick: () => ({
|
|
3101
|
-
type: "codeblock"
|
|
3102
|
-
|
|
4065
|
+
onClick: (s) => ({
|
|
4066
|
+
type: "codeblock",
|
|
4067
|
+
data: s ? s.blockType !== "codeblock" : null
|
|
4068
|
+
}),
|
|
4069
|
+
getState: (s) => s.blockType === "codeblock"
|
|
3103
4070
|
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3104
4071
|
Icon: Table2,
|
|
3105
4072
|
title: "Table",
|
|
@@ -3112,9 +4079,11 @@ var MarkdownLinks = () => /* @__PURE__ */ React2.createElement("div", {
|
|
|
3112
4079
|
}, /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3113
4080
|
Icon: Link,
|
|
3114
4081
|
title: "Link",
|
|
3115
|
-
onClick: () => ({
|
|
3116
|
-
type: "link"
|
|
3117
|
-
|
|
4082
|
+
onClick: (s) => ({
|
|
4083
|
+
type: "link",
|
|
4084
|
+
data: s ? !s.link : null
|
|
4085
|
+
}),
|
|
4086
|
+
getState: (s) => s.link
|
|
3118
4087
|
}), /* @__PURE__ */ React2.createElement(ToolbarButton, {
|
|
3119
4088
|
Icon: At,
|
|
3120
4089
|
title: "Mention",
|
|
@@ -3261,24 +4230,32 @@ var useActionHandler = (view) => {
|
|
|
3261
4230
|
if (!view) {
|
|
3262
4231
|
return;
|
|
3263
4232
|
}
|
|
4233
|
+
let inlineType, listType;
|
|
3264
4234
|
switch (action.type) {
|
|
3265
4235
|
case "heading":
|
|
3266
4236
|
setHeading(parseInt(action.data))(view);
|
|
3267
4237
|
break;
|
|
3268
|
-
case "
|
|
3269
|
-
|
|
4238
|
+
case "strong":
|
|
4239
|
+
case "emphasis":
|
|
4240
|
+
case "strikethrough":
|
|
4241
|
+
case "code":
|
|
4242
|
+
inlineType = action.type === "strong" ? Inline.Strong : action.type === "emphasis" ? Inline.Emphasis : action.type === "strikethrough" ? Inline.Strikethrough : Inline.Code;
|
|
4243
|
+
(typeof action.data === "boolean" ? setStyle(inlineType, action.data) : toggleStyle(inlineType))(view);
|
|
3270
4244
|
break;
|
|
3271
|
-
case "
|
|
3272
|
-
|
|
4245
|
+
case "link":
|
|
4246
|
+
(action.data === false ? removeLink : addLink)(view);
|
|
3273
4247
|
break;
|
|
3274
|
-
case "
|
|
3275
|
-
|
|
4248
|
+
case "list-ordered":
|
|
4249
|
+
case "list-bullet":
|
|
4250
|
+
case "list-tasks":
|
|
4251
|
+
listType = action.type === "list-ordered" ? List.Ordered : action.type === "list-bullet" ? List.Bullet : List.Task;
|
|
4252
|
+
(action.data === false ? removeList(listType) : action.data === true ? addList(listType) : toggleList(listType))(view);
|
|
3276
4253
|
break;
|
|
3277
|
-
case "
|
|
3278
|
-
|
|
4254
|
+
case "blockquote":
|
|
4255
|
+
(action.data === false ? removeBlockquote : action.data === true ? addBlockquote : toggleBlockquote)(view);
|
|
3279
4256
|
break;
|
|
3280
4257
|
case "codeblock":
|
|
3281
|
-
|
|
4258
|
+
(action.data === false ? removeCodeblock : addCodeblock)(view);
|
|
3282
4259
|
break;
|
|
3283
4260
|
case "table":
|
|
3284
4261
|
insertTable(view);
|
|
@@ -3288,18 +4265,17 @@ var useActionHandler = (view) => {
|
|
|
3288
4265
|
break;
|
|
3289
4266
|
}
|
|
3290
4267
|
setTimeout(() => {
|
|
3291
|
-
view.
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
});
|
|
4268
|
+
if (!view.hasFocus) {
|
|
4269
|
+
view.focus();
|
|
4270
|
+
}
|
|
3295
4271
|
});
|
|
3296
4272
|
};
|
|
3297
4273
|
};
|
|
3298
4274
|
|
|
3299
4275
|
// packages/ui/react-ui-editor/src/hooks/useEditorView.ts
|
|
3300
|
-
import { useState as
|
|
4276
|
+
import { useState as useState3 } from "react";
|
|
3301
4277
|
var useEditorView = () => {
|
|
3302
|
-
const [view, setView] =
|
|
4278
|
+
const [view, setView] = useState3(null);
|
|
3303
4279
|
return [
|
|
3304
4280
|
(ref) => {
|
|
3305
4281
|
setView(ref);
|
|
@@ -3309,15 +4285,15 @@ var useEditorView = () => {
|
|
|
3309
4285
|
};
|
|
3310
4286
|
|
|
3311
4287
|
// packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
|
|
3312
|
-
import { EditorSelection, EditorState as EditorState3 } from "@codemirror/state";
|
|
3313
|
-
import { EditorView as
|
|
3314
|
-
import { useEffect as useEffect3, useRef as useRef2, useState as
|
|
4288
|
+
import { EditorSelection as EditorSelection2, EditorState as EditorState3 } from "@codemirror/state";
|
|
4289
|
+
import { EditorView as EditorView15 } from "@codemirror/view";
|
|
4290
|
+
import { useEffect as useEffect3, useRef as useRef2, useState as useState4 } from "react";
|
|
3315
4291
|
import { log as log4 } from "@dxos/log";
|
|
3316
4292
|
import { isNotFalsy as isNotFalsy4 } from "@dxos/util";
|
|
3317
4293
|
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
|
|
3318
4294
|
var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions } = {}) => {
|
|
3319
4295
|
const onUpdate = useRef2();
|
|
3320
|
-
const [view, setView] =
|
|
4296
|
+
const [view, setView] = useState4();
|
|
3321
4297
|
const parentRef = useRef2(null);
|
|
3322
4298
|
useEffect3(() => {
|
|
3323
4299
|
if (parentRef.current) {
|
|
@@ -3326,7 +4302,7 @@ var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions }
|
|
|
3326
4302
|
selection,
|
|
3327
4303
|
extensions: [
|
|
3328
4304
|
// TODO(burdon): Doesn't catch errors in keymap functions.
|
|
3329
|
-
|
|
4305
|
+
EditorView15.exceptionSink.of((err) => {
|
|
3330
4306
|
log4.catch(err, void 0, {
|
|
3331
4307
|
F: __dxlog_file5,
|
|
3332
4308
|
L: 57,
|
|
@@ -3335,12 +4311,12 @@ var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions }
|
|
|
3335
4311
|
});
|
|
3336
4312
|
}),
|
|
3337
4313
|
extensions,
|
|
3338
|
-
|
|
4314
|
+
EditorView15.updateListener.of(() => {
|
|
3339
4315
|
onUpdate.current?.();
|
|
3340
4316
|
})
|
|
3341
4317
|
].filter(isNotFalsy4)
|
|
3342
4318
|
});
|
|
3343
|
-
const view2 = new
|
|
4319
|
+
const view2 = new EditorView15({
|
|
3344
4320
|
parent: parentRef.current,
|
|
3345
4321
|
scrollTo,
|
|
3346
4322
|
state,
|
|
@@ -3364,7 +4340,7 @@ var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions }
|
|
|
3364
4340
|
useEffect3(() => {
|
|
3365
4341
|
if (view) {
|
|
3366
4342
|
if (!selection && !view.state.selection.main.anchor) {
|
|
3367
|
-
selection =
|
|
4343
|
+
selection = EditorSelection2.single(view.state.doc.line(1).to);
|
|
3368
4344
|
}
|
|
3369
4345
|
if (selection || scrollTo) {
|
|
3370
4346
|
onUpdate.current = () => {
|
|
@@ -3397,19 +4373,19 @@ var createDataExtensions = ({ readonly = false } = {}) => {
|
|
|
3397
4373
|
return [
|
|
3398
4374
|
//
|
|
3399
4375
|
EditorState3.readOnly.of(readonly),
|
|
3400
|
-
|
|
4376
|
+
EditorView15.editable.of(!readonly)
|
|
3401
4377
|
];
|
|
3402
4378
|
};
|
|
3403
4379
|
var createThemeExtensions = ({ theme, themeMode, slots } = {}) => {
|
|
3404
4380
|
return [
|
|
3405
4381
|
//
|
|
3406
|
-
|
|
3407
|
-
theme &&
|
|
3408
|
-
|
|
3409
|
-
|
|
4382
|
+
EditorView15.baseTheme(defaultTheme),
|
|
4383
|
+
theme && EditorView15.theme(theme),
|
|
4384
|
+
EditorView15.darkTheme.of(themeMode === "dark"),
|
|
4385
|
+
EditorView15.editorAttributes.of({
|
|
3410
4386
|
class: slots?.editor?.className ?? ""
|
|
3411
4387
|
}),
|
|
3412
|
-
|
|
4388
|
+
EditorView15.contentAttributes.of({
|
|
3413
4389
|
class: slots?.content?.className ?? ""
|
|
3414
4390
|
})
|
|
3415
4391
|
].filter(isNotFalsy4);
|
|
@@ -3417,7 +4393,7 @@ var createThemeExtensions = ({ theme, themeMode, slots } = {}) => {
|
|
|
3417
4393
|
|
|
3418
4394
|
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
3419
4395
|
import get4 from "lodash.get";
|
|
3420
|
-
import { useEffect as useEffect4, useState as
|
|
4396
|
+
import { useEffect as useEffect4, useState as useState5 } from "react";
|
|
3421
4397
|
import { generateName } from "@dxos/display-name";
|
|
3422
4398
|
import { getRawDoc } from "@dxos/echo-schema";
|
|
3423
4399
|
import { invariant as invariant3 } from "@dxos/invariant";
|
|
@@ -3425,7 +4401,7 @@ import { isAutomergeObject } from "@dxos/react-client/echo";
|
|
|
3425
4401
|
var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
|
|
3426
4402
|
var useTextModel = (props) => {
|
|
3427
4403
|
const { identity, space, text } = props;
|
|
3428
|
-
const [model, setModel] =
|
|
4404
|
+
const [model, setModel] = useState5();
|
|
3429
4405
|
useEffect4(() => setModel(createModel(props)), [
|
|
3430
4406
|
identity,
|
|
3431
4407
|
space,
|
|
@@ -3434,7 +4410,7 @@ var useTextModel = (props) => {
|
|
|
3434
4410
|
return model;
|
|
3435
4411
|
};
|
|
3436
4412
|
var useInMemoryTextModel = ({ id, defaultContent }) => {
|
|
3437
|
-
const [content, setContent] =
|
|
4413
|
+
const [content, setContent] = useState5(defaultContent ?? "");
|
|
3438
4414
|
return {
|
|
3439
4415
|
id,
|
|
3440
4416
|
content,
|
|
@@ -3494,6 +4470,8 @@ export {
|
|
|
3494
4470
|
Cursor,
|
|
3495
4471
|
Doc,
|
|
3496
4472
|
EditorModes,
|
|
4473
|
+
Inline,
|
|
4474
|
+
List,
|
|
3497
4475
|
MarkdownEditor,
|
|
3498
4476
|
RemoteSelectionsDecorator,
|
|
3499
4477
|
SpaceAwarenessProvider,
|
|
@@ -3502,6 +4480,11 @@ export {
|
|
|
3502
4480
|
Toolbar,
|
|
3503
4481
|
YText,
|
|
3504
4482
|
YXmlFragment,
|
|
4483
|
+
addBlockquote,
|
|
4484
|
+
addCodeblock,
|
|
4485
|
+
addLink,
|
|
4486
|
+
addList,
|
|
4487
|
+
addStyle,
|
|
3505
4488
|
autocomplete,
|
|
3506
4489
|
automerge,
|
|
3507
4490
|
awareness,
|
|
@@ -3511,6 +4494,7 @@ export {
|
|
|
3511
4494
|
code2 as code,
|
|
3512
4495
|
codeTheme,
|
|
3513
4496
|
comments,
|
|
4497
|
+
compareFormatting,
|
|
3514
4498
|
createBasicBundle,
|
|
3515
4499
|
createComment,
|
|
3516
4500
|
createDataExtensions,
|
|
@@ -3523,11 +4507,11 @@ export {
|
|
|
3523
4507
|
defaultTheme,
|
|
3524
4508
|
focusComment,
|
|
3525
4509
|
formatting,
|
|
4510
|
+
getFormatting,
|
|
3526
4511
|
getToken,
|
|
3527
4512
|
heading2 as heading,
|
|
3528
4513
|
hr,
|
|
3529
4514
|
image,
|
|
3530
|
-
insertCodeblock,
|
|
3531
4515
|
insertTable,
|
|
3532
4516
|
keymap7 as keymap,
|
|
3533
4517
|
link,
|
|
@@ -3540,22 +4524,33 @@ export {
|
|
|
3540
4524
|
mention,
|
|
3541
4525
|
modelState,
|
|
3542
4526
|
outliner,
|
|
4527
|
+
removeBlockquote,
|
|
4528
|
+
removeCodeblock,
|
|
4529
|
+
removeLink,
|
|
4530
|
+
removeList,
|
|
4531
|
+
removeStyle,
|
|
4532
|
+
setBlockquote,
|
|
3543
4533
|
setComments,
|
|
3544
4534
|
setHeading,
|
|
3545
4535
|
setSelection,
|
|
4536
|
+
setStyle,
|
|
3546
4537
|
table,
|
|
3547
4538
|
tags2 as tags,
|
|
3548
4539
|
tasklist,
|
|
3549
4540
|
textTheme,
|
|
3550
|
-
|
|
3551
|
-
|
|
4541
|
+
toggleBlockquote,
|
|
4542
|
+
toggleCodeblock,
|
|
4543
|
+
toggleEmphasis,
|
|
4544
|
+
toggleInlineCode,
|
|
3552
4545
|
toggleList,
|
|
3553
4546
|
toggleStrikethrough,
|
|
4547
|
+
toggleStrong,
|
|
3554
4548
|
toggleStyle,
|
|
3555
4549
|
typewriter,
|
|
3556
4550
|
useActionHandler,
|
|
3557
4551
|
useComments,
|
|
3558
4552
|
useEditorView,
|
|
4553
|
+
useFormattingState,
|
|
3559
4554
|
useInMemoryTextModel,
|
|
3560
4555
|
useTextEditor,
|
|
3561
4556
|
useTextModel,
|