@dxos/react-ui-editor 0.3.11-main.463e5cd → 0.3.11-main.474ad53

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 (26) hide show
  1. package/dist/lib/browser/index.mjs +1196 -163
  2. package/dist/lib/browser/index.mjs.map +3 -3
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
  5. package/dist/types/src/components/TextEditor/hooks.stories.d.ts.map +1 -1
  6. package/dist/types/src/components/Toolbar/Toolbar.d.ts +8 -4
  7. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
  8. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts +5 -3
  9. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -1
  10. package/dist/types/src/extensions/comments.d.ts +5 -1
  11. package/dist/types/src/extensions/comments.d.ts.map +1 -1
  12. package/dist/types/src/extensions/markdown/formatting.d.ts +55 -10
  13. package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -1
  14. package/dist/types/src/extensions/markdown/formatting.test.d.ts +3 -0
  15. package/dist/types/src/extensions/markdown/formatting.test.d.ts.map +1 -0
  16. package/dist/types/src/hooks/useActionHandler.d.ts.map +1 -1
  17. package/package.json +25 -25
  18. package/src/components/TextEditor/MarkdownEditor.stories.tsx +3 -3
  19. package/src/components/TextEditor/hooks.stories.tsx +6 -1
  20. package/src/components/Toolbar/Toolbar.stories.tsx +16 -4
  21. package/src/components/Toolbar/Toolbar.tsx +128 -30
  22. package/src/extensions/comments.ts +14 -4
  23. package/src/extensions/markdown/formatting.test.ts +482 -0
  24. package/src/extensions/markdown/formatting.ts +1118 -69
  25. package/src/hooks/useActionHandler.ts +47 -16
  26. package/src/themes/default.ts +2 -2
@@ -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 EditorView13 } from "@codemirror/view";
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";
@@ -1074,11 +1074,25 @@ var logChanges = (trs) => {
1074
1074
 
1075
1075
  // packages/ui/react-ui-editor/src/extensions/comments.ts
1076
1076
  var styles2 = EditorView5.baseTheme({
1077
- "& .cm-comment": {
1077
+ "&light .cm-comment, &light .cm-comment-current": {
1078
+ mixBlendMode: "darken"
1079
+ },
1080
+ "&dark .cm-comment, &dark .cm-comment-current": {
1081
+ mixBlendMode: "plus-lighter"
1082
+ },
1083
+ "&light .cm-comment": {
1078
1084
  backgroundColor: getToken("extend.colors.yellow.50")
1079
1085
  },
1080
- "& .cm-comment-current": {
1086
+ "&light .cm-comment-current": {
1081
1087
  backgroundColor: getToken("extend.colors.yellow.100")
1088
+ },
1089
+ "&dark .cm-comment": {
1090
+ color: getToken("extend.colors.yellow.50"),
1091
+ backgroundColor: getToken("extend.colors.yellow.900")
1092
+ },
1093
+ "&dark .cm-comment-current": {
1094
+ color: getToken("extend.colors.yellow.100"),
1095
+ backgroundColor: getToken("extend.colors.yellow.950")
1082
1096
  }
1083
1097
  });
1084
1098
  var commentMark = Decoration2.mark({
@@ -1287,7 +1301,11 @@ var createComment = (view) => {
1287
1301
  to
1288
1302
  });
1289
1303
  if (cursor) {
1290
- const id = options.onCreate?.(cursor, view.coordsAtPos(from));
1304
+ const id = options.onCreate?.({
1305
+ cursor,
1306
+ from,
1307
+ location: view.coordsAtPos(from)
1308
+ });
1291
1309
  if (id) {
1292
1310
  view.dispatch({
1293
1311
  effects: setSelection.of({
@@ -1815,89 +1833,836 @@ var code2 = () => {
1815
1833
  // packages/ui/react-ui-editor/src/extensions/markdown/formatting.ts
1816
1834
  import { snippet } from "@codemirror/autocomplete";
1817
1835
  import { syntaxTree as syntaxTree2 } from "@codemirror/language";
1818
- import { RangeSetBuilder as RangeSetBuilder2 } from "@codemirror/state";
1819
- import { Decoration as Decoration4, keymap as keymap5, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
1820
- var setHeading = (level) => (view) => {
1821
- const { selection: { ranges }, doc } = view.state;
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;
1822
1855
  const changes = [];
1856
+ let prevBlock = -1;
1823
1857
  for (const range of ranges) {
1824
- const { number } = doc.lineAt(range.anchor);
1825
- const { from, to } = doc.line(number);
1826
- const line = doc.sliceString(from, to);
1827
- const [_, marks, spaces] = line.match(/(#+)(\s+)/) ?? [];
1828
- const current = marks?.length ?? 0;
1829
- if (level !== current) {
1830
- changes.push({
1831
- from,
1832
- to: from + current + (spaces?.length ?? 0),
1833
- insert: "#".repeat(level) + (level > 0 ? " " : "")
1834
- });
1835
- }
1836
- }
1837
- if (changes.length) {
1838
- view.dispatch({
1839
- changes
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
+ }
1840
1908
  });
1841
1909
  }
1910
+ if (!changes.length) {
1911
+ return false;
1912
+ }
1913
+ dispatch(state.update({
1914
+ changes,
1915
+ userEvent: "format.setHeading",
1916
+ scrollIntoView: true
1917
+ }));
1842
1918
  return true;
1843
1919
  };
1844
- var toggleStyle = (mark2) => (view) => {
1845
- const { ranges } = view.state.selection;
1846
- for (const range of ranges) {
1847
- if (range.from === range.to) {
1848
- return false;
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
+ }
1849
1946
  }
1850
- view.dispatch({
1851
- changes: [
1852
- {
1853
- from: range.from,
1854
- insert: mark2
1855
- },
1856
- {
1857
- from: range.to,
1858
- insert: mark2
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
+ }
1859
2018
  }
1860
- ]
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
+ }
1861
2063
  });
1862
- }
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
+ }));
1863
2074
  return true;
1864
2075
  };
2076
+ var addStyle = (style) => setStyle(style, true);
2077
+ var removeStyle = (style) => setStyle(style, false);
2078
+ var toggleStyle = (style) => (arg) => {
2079
+ const form = getFormatting(arg.state);
2080
+ return setStyle(style, style === 0 ? !form.strong : style === 1 ? !form.emphasis : style === 2 ? !form.strikethrough : !form.code)(arg);
2081
+ };
2082
+ var toggleStrong = toggleStyle(0);
2083
+ var toggleEmphasis = toggleStyle(1);
2084
+ var toggleStrikethrough = toggleStyle(2);
2085
+ var toggleInlineCode = toggleStyle(3);
2086
+ var inlineMarkerText = (type) => type === 0 ? "**" : type === 2 ? "~~" : type === 1 ? "*" : "`";
2087
+ var blockContentStart = (node) => {
2088
+ const atx = /^ATXHeading(\d)/.exec(node.name);
2089
+ if (atx) {
2090
+ return Math.min(node.to, node.from + +atx[1] + 1);
2091
+ }
2092
+ return node.from;
2093
+ };
2094
+ var blockContentEnd = (node, doc) => {
2095
+ const setext = /^SetextHeading(\d)/.exec(node.name);
2096
+ const lastLine = doc.lineAt(node.to);
2097
+ if (setext || /^[\s>]*$/.exec(lastLine.text)) {
2098
+ return lastLine.from - 1;
2099
+ }
2100
+ return node.to;
2101
+ };
2102
+ var skipSpaces = (pos, doc, dir, limit) => {
2103
+ const line = doc.lineAt(pos);
2104
+ while (pos !== limit && line.text[pos - line.from - (dir < 0 ? 1 : 0)] === " ") {
2105
+ pos += dir;
2106
+ }
2107
+ return pos;
2108
+ };
1865
2109
  var snippets = {
1866
2110
  codeblock: snippet([
1867
- "```#{lang}",
1868
- " #{}",
2111
+ //
2112
+ "```#{}",
2113
+ "#{}",
1869
2114
  "```"
1870
2115
  ].join("\n")),
1871
2116
  table: snippet([
2117
+ //
1872
2118
  "| #{col1} | #{col2} |",
1873
2119
  "| ---- | ---- |",
1874
2120
  "| #{val1} | #{val2} |",
1875
- "| #{val3} | #{val4} |"
2121
+ "| #{val3} | #{val4} |",
2122
+ ""
1876
2123
  ].join("\n"))
1877
2124
  };
1878
- var insertCodeblock = (view) => {
1879
- const { selection: { main }, doc } = view.state;
1880
- const { number } = doc.lineAt(main.anchor);
1881
- const { from } = doc.line(number);
1882
- snippets.codeblock(view, null, from, from);
1883
- };
1884
2125
  var insertTable = (view) => {
1885
2126
  const { selection: { main }, doc } = view.state;
1886
2127
  const { number } = doc.lineAt(main.anchor);
1887
2128
  const { from } = doc.line(number);
1888
2129
  snippets.table(view, null, from, from);
1889
2130
  };
1890
- var toggleBold = toggleStyle("**");
1891
- var toggleItalic = toggleStyle("_");
1892
- var toggleStrikethrough = toggleStyle("~~");
1893
- var toggleList = (view) => {
2131
+ var removeLinkInner = (from, to, changes, state) => {
2132
+ syntaxTree2(state).iterate({
2133
+ from,
2134
+ to,
2135
+ enter: (node) => {
2136
+ if (node.name === "Link" && node.from < to && node.to > from) {
2137
+ node.node.cursor().iterate((node2) => {
2138
+ const { name } = node2;
2139
+ if (name === "LinkMark" || name === "LinkLabel") {
2140
+ changes.push({
2141
+ from: node2.from,
2142
+ to: node2.to
2143
+ });
2144
+ } else if (name === "LinkTitle" || name === "URL") {
2145
+ changes.push({
2146
+ from: skipSpaces(node2.from, state.doc, -1),
2147
+ to: skipSpaces(node2.to, state.doc, 1)
2148
+ });
2149
+ }
2150
+ });
2151
+ return false;
2152
+ }
2153
+ }
2154
+ });
2155
+ };
2156
+ var removeLink = ({ state, dispatch }) => {
2157
+ const changes = [];
2158
+ for (const { from, to } of state.selection.ranges) {
2159
+ removeLinkInner(from, to, changes, state);
2160
+ }
2161
+ if (!changes) {
2162
+ return false;
2163
+ }
2164
+ dispatch(state.update({
2165
+ changes,
2166
+ userEvent: "format.link.remove",
2167
+ scrollIntoView: true
2168
+ }));
2169
+ return true;
2170
+ };
2171
+ var addLink = ({ state, dispatch }) => {
2172
+ const changes = state.changeByRange((range) => {
2173
+ let { from, to } = range;
2174
+ const cutStyles = [];
2175
+ let okay = null;
2176
+ syntaxTree2(state).iterate({
2177
+ from,
2178
+ to,
2179
+ enter: (node) => {
2180
+ if (Object.hasOwn(Textblocks, node.name)) {
2181
+ okay = Textblocks[node.name] !== "codeblock" && from >= blockContentStart(node) && to <= blockContentEnd(node, state.doc);
2182
+ } else if (Object.hasOwn(InlineMarker, node.name)) {
2183
+ const sNode = node.node;
2184
+ if (node.from < from && node.to <= to) {
2185
+ if (sNode.firstChild.to === from) {
2186
+ from = node.from;
2187
+ } else {
2188
+ cutStyles.push(sNode);
2189
+ }
2190
+ } else if (node.from >= from && node.to > to) {
2191
+ if (sNode.lastChild.from === to) {
2192
+ to = node.to;
2193
+ } else {
2194
+ cutStyles.push(sNode);
2195
+ }
2196
+ }
2197
+ }
2198
+ }
2199
+ });
2200
+ if (okay === null) {
2201
+ const line = state.doc.lineAt(from);
2202
+ okay = to <= line.to && !/\S/.test(line.text.slice(from - line.from));
2203
+ }
2204
+ if (!okay) {
2205
+ return {
2206
+ range
2207
+ };
2208
+ }
2209
+ const changes2 = [];
2210
+ const changesAfter = [];
2211
+ removeLinkInner(from, to, changesAfter, state);
2212
+ let cursorOffset = 1;
2213
+ for (const style of cutStyles) {
2214
+ const type = InlineMarker[style.name];
2215
+ const mark2 = inlineMarkerText(type);
2216
+ if (style.from < from) {
2217
+ changes2.push({
2218
+ from: skipSpaces(from, state.doc, -1),
2219
+ insert: mark2
2220
+ });
2221
+ changesAfter.push({
2222
+ from: skipSpaces(from, state.doc, 1, to),
2223
+ insert: mark2
2224
+ });
2225
+ } else {
2226
+ changes2.push({
2227
+ from: skipSpaces(to, state.doc, -1, from),
2228
+ insert: mark2
2229
+ });
2230
+ const after = skipSpaces(to, state.doc, 1);
2231
+ if (after === to) {
2232
+ cursorOffset += mark2.length;
2233
+ }
2234
+ changesAfter.push({
2235
+ from: after,
2236
+ insert: mark2
2237
+ });
2238
+ }
2239
+ }
2240
+ changes2.push({
2241
+ from,
2242
+ insert: "["
2243
+ }, {
2244
+ from: to,
2245
+ insert: "]()"
2246
+ });
2247
+ const changeSet = state.changes(changes2.concat(changesAfter));
2248
+ return {
2249
+ changes: changeSet,
2250
+ range: EditorSelection.cursor(changeSet.mapPos(to, 1) - cursorOffset)
2251
+ };
2252
+ });
2253
+ if (changes.changes.empty) {
2254
+ return false;
2255
+ }
2256
+ dispatch(state.update(changes, {
2257
+ userEvent: "format.link.add",
2258
+ scrollIntoView: true
2259
+ }));
2260
+ return true;
2261
+ };
2262
+ var addList = (type) => ({ state, dispatch }) => {
2263
+ let lastBlock = -1;
2264
+ let counter = 1;
2265
+ let first = true;
2266
+ let parentColumn = null;
2267
+ const blocks = [];
2268
+ for (const { from, to } of state.selection.ranges) {
2269
+ syntaxTree2(state).iterate({
2270
+ from,
2271
+ to,
2272
+ enter: (node) => {
2273
+ if (Object.hasOwn(Textblocks, node.name) && node.name !== "TableCell" || node.name === "Table") {
2274
+ if (first) {
2275
+ let before = node.node.prevSibling;
2276
+ while (before && /Mark$/.test(before.name)) {
2277
+ before = before.prevSibling;
2278
+ }
2279
+ if (before?.name === (type === 0 ? "OrderedList" : "BulletList")) {
2280
+ const item = before.lastChild;
2281
+ const itemLine = state.doc.lineAt(item.from);
2282
+ const itemText = itemLine.text.slice(item.from - itemLine.from);
2283
+ parentColumn = item.from - itemLine.from + /^\s*/.exec(itemText)[0].length;
2284
+ if (type === 0) {
2285
+ const mark2 = /^\s*(\d+)[.)]/.exec(itemText);
2286
+ if (mark2) {
2287
+ parentColumn += mark2[1].length;
2288
+ counter = +mark2[1] + 1;
2289
+ }
2290
+ }
2291
+ }
2292
+ first = false;
2293
+ }
2294
+ if (node.from === lastBlock) {
2295
+ return;
2296
+ }
2297
+ lastBlock = node.from;
2298
+ blocks.push({
2299
+ node: node.node,
2300
+ counter,
2301
+ parentColumn
2302
+ });
2303
+ counter++;
2304
+ return false;
2305
+ }
2306
+ },
2307
+ leave: (node) => {
2308
+ if (node.name === "BulletList" || node.name === "OrderedList" || node.name === "Blockquote") {
2309
+ counter = 1;
2310
+ parentColumn = null;
2311
+ }
2312
+ }
2313
+ });
2314
+ }
2315
+ if (!blocks.length) {
2316
+ const { from, to } = state.doc.lineAt(state.selection.main.anchor);
2317
+ if (from === to) {
2318
+ dispatch(state.update({
2319
+ changes: [
2320
+ {
2321
+ from,
2322
+ insert: type === 1 ? "- " : type === 0 ? "1. " : "- [ ] "
2323
+ }
2324
+ ],
2325
+ userEvent: "format.list.add",
2326
+ scrollIntoView: true
2327
+ }));
2328
+ return true;
2329
+ }
2330
+ return false;
2331
+ }
2332
+ const changes = [];
2333
+ for (let i = 0; i < blocks.length; i++) {
2334
+ const { node, counter: counter2, parentColumn: parentColumn2 } = blocks[i];
2335
+ const nodeFrom = node.name === "CodeBlock" ? node.from - 4 : node.from;
2336
+ let padding = nodeFrom > 0 && !/\s/.test(state.doc.sliceString(nodeFrom - 1, nodeFrom)) ? 1 : 0;
2337
+ if (type === 0) {
2338
+ padding += String(counter2).length;
2339
+ }
2340
+ let line = state.doc.lineAt(nodeFrom);
2341
+ const column = nodeFrom - line.from;
2342
+ if (parentColumn2 !== null && parentColumn2 > column) {
2343
+ padding = Math.max(padding, parentColumn2 - column);
2344
+ }
2345
+ let mark2;
2346
+ if (type === 0) {
2347
+ let max = counter2;
2348
+ for (let j = i + 1; j < blocks.length; j++) {
2349
+ if (blocks[j].counter !== max + 1) {
2350
+ break;
2351
+ }
2352
+ max++;
2353
+ }
2354
+ const num = String(counter2);
2355
+ padding = Math.max(String(max).length, padding);
2356
+ mark2 = " ".repeat(Math.max(0, padding - num.length)) + num + ". ";
2357
+ } else {
2358
+ mark2 = " ".repeat(padding) + "- " + (type === 2 ? "[ ] " : "");
2359
+ }
2360
+ changes.push({
2361
+ from: nodeFrom,
2362
+ insert: mark2
2363
+ });
2364
+ while (line.to < node.to) {
2365
+ line = state.doc.lineAt(line.to + 1);
2366
+ const open = /^[\s>]*/.exec(line.text)[0].length;
2367
+ changes.push({
2368
+ from: line.from + Math.min(open, column),
2369
+ insert: " ".repeat(mark2.length)
2370
+ });
2371
+ }
2372
+ }
2373
+ if (type === 0) {
2374
+ const last = blocks[blocks.length - 1];
2375
+ let next = last.node.nextSibling;
2376
+ while (next && /Mark$/.test(next.name)) {
2377
+ next = next.nextSibling;
2378
+ }
2379
+ if (next?.name === "OrderedList") {
2380
+ renumberListItems(next.firstChild, last.counter + 1, changes, state.doc);
2381
+ }
2382
+ }
2383
+ dispatch(state.update({
2384
+ changes,
2385
+ userEvent: "format.list.add",
2386
+ scrollIntoView: true
2387
+ }));
2388
+ return true;
2389
+ };
2390
+ var removeList = (type) => ({ state, dispatch }) => {
2391
+ let lastBlock = -1;
2392
+ const changes = [];
2393
+ const stack = [];
2394
+ const targetNodeType = type === 0 ? "OrderedList" : type === 1 ? "BulletList" : "TaskList";
2395
+ for (const { from, to } of state.selection.ranges) {
2396
+ syntaxTree2(state).iterate({
2397
+ from,
2398
+ to,
2399
+ enter: (node) => {
2400
+ const { name } = node;
2401
+ if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
2402
+ stack.push(name);
2403
+ } else if (name === "Task" && stack[stack.length - 1] === "BulletList") {
2404
+ stack[stack.length - 1] = "TaskList";
2405
+ }
2406
+ },
2407
+ leave: (node) => {
2408
+ const { name } = node;
2409
+ if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
2410
+ stack.pop();
2411
+ } else if (name === "ListItem" && stack[stack.length - 1] === targetNodeType && node.from !== lastBlock) {
2412
+ lastBlock = node.from;
2413
+ let line = state.doc.lineAt(node.from);
2414
+ const mark2 = /^\s*(\d+[.)] |[-*+] (\[[ x]\] )?)/.exec(line.text.slice(node.from - line.from));
2415
+ if (!mark2) {
2416
+ return false;
2417
+ }
2418
+ const column = node.from - line.from;
2419
+ changes.push({
2420
+ from: node.from,
2421
+ to: node.from + mark2[0].length
2422
+ });
2423
+ while (line.to < node.to) {
2424
+ line = state.doc.lineAt(line.to + 1);
2425
+ const open = /^[\s>]*/.exec(line.text)[0].length;
2426
+ if (open > column) {
2427
+ changes.push({
2428
+ from: line.from + column,
2429
+ to: line.from + Math.min(column + mark2[0].length, open)
2430
+ });
2431
+ }
2432
+ }
2433
+ if (node.to >= to) {
2434
+ renumberListItems(node.node.nextSibling, 1, changes, state.doc);
2435
+ }
2436
+ return false;
2437
+ }
2438
+ }
2439
+ });
2440
+ }
2441
+ if (!changes.length) {
2442
+ return false;
2443
+ }
2444
+ dispatch(state.update({
2445
+ changes,
2446
+ userEvent: "format.list.remove",
2447
+ scrollIntoView: true
2448
+ }));
2449
+ return true;
2450
+ };
2451
+ var toggleList = (type) => (target) => {
2452
+ const formatting2 = getFormatting(target.state);
2453
+ const active = formatting2.listStyle === (type === 1 ? "bullet" : type === 0 ? "ordered" : "task");
2454
+ return (active ? removeList(type) : addList(type))(target);
2455
+ };
2456
+ var renumberListItems = (item, counter, changes, doc) => {
2457
+ for (; item; item = item.nextSibling) {
2458
+ if (item.name === "ListItem") {
2459
+ const number = /(\s*)(\d+)[.)]/.exec(doc.sliceString(item.from, item.from + 10));
2460
+ if (!number || +number[2] === counter) {
2461
+ break;
2462
+ }
2463
+ const size = number[1].length + number[2].length;
2464
+ const newNum = String(counter);
2465
+ changes.push({
2466
+ from: item.from + Math.max(0, size - newNum.length),
2467
+ to: item.from + size,
2468
+ insert: newNum
2469
+ });
2470
+ counter++;
2471
+ }
2472
+ }
2473
+ };
2474
+ var setBlockquote = (enable) => ({ state, dispatch }) => {
2475
+ const lines = [];
2476
+ let lastBlock = -1;
2477
+ for (const { from, to } of state.selection.ranges) {
2478
+ syntaxTree2(state).iterate({
2479
+ from,
2480
+ to,
2481
+ enter: (node) => {
2482
+ if (Object.hasOwn(Textblocks, node.name) || node.name === "Table") {
2483
+ if (node.from === lastBlock) {
2484
+ return false;
2485
+ }
2486
+ lastBlock = node.from;
2487
+ let line = state.doc.lineAt(node.from);
2488
+ if (line.number > 1) {
2489
+ const prevLine = state.doc.line(line.number - 1);
2490
+ if (/^[>\s]*$/.test(prevLine.text)) {
2491
+ if (!enable || lines.length && lines[lines.length - 1].number === prevLine.number - 1) {
2492
+ lines.push(prevLine);
2493
+ }
2494
+ }
2495
+ }
2496
+ for (; ; ) {
2497
+ lines.push(line);
2498
+ if (line.to >= node.to) {
2499
+ break;
2500
+ }
2501
+ line = state.doc.line(line.number + 1);
2502
+ }
2503
+ if (!enable && line.number < state.doc.lines) {
2504
+ const nextLine = state.doc.line(line.number + 1);
2505
+ if (/^[>\s]*$/.test(nextLine.text)) {
2506
+ lines.push(nextLine);
2507
+ }
2508
+ }
2509
+ return false;
2510
+ }
2511
+ }
2512
+ });
2513
+ }
2514
+ const changes = [];
2515
+ for (const line of lines) {
2516
+ if (enable) {
2517
+ changes.push({
2518
+ from: line.from,
2519
+ insert: /\S/.test(line.text) ? "> " : ">"
2520
+ });
2521
+ } else {
2522
+ const quote = /((?:[\s>\-+*]|\d+[.)])*?)> ?/.exec(line.text);
2523
+ if (quote) {
2524
+ changes.push({
2525
+ from: line.from + quote[1].length,
2526
+ to: line.from + quote[0].length
2527
+ });
2528
+ }
2529
+ }
2530
+ }
2531
+ if (!changes.length) {
2532
+ return false;
2533
+ }
2534
+ dispatch(state.update({
2535
+ changes,
2536
+ userEvent: enable ? "format.blockquote.add" : "format.blockquote.remove",
2537
+ scrollIntoView: true
2538
+ }));
2539
+ return true;
2540
+ };
2541
+ var addBlockquote = setBlockquote(true);
2542
+ var removeBlockquote = setBlockquote(false);
2543
+ var toggleBlockquote = (target) => {
2544
+ return (getFormatting(target.state).blockQuote ? removeBlockquote : addBlockquote)(target);
2545
+ };
2546
+ var addCodeblock = (target) => {
2547
+ const { state, dispatch } = target;
2548
+ const { selection } = state;
2549
+ if (selection.ranges.length === 1 && selection.main.empty) {
2550
+ const { head } = selection.main;
2551
+ const line = state.doc.lineAt(head);
2552
+ if (!/\S/.test(line.text) && head === line.from) {
2553
+ snippets.codeblock(target, null, line.from, line.to);
2554
+ return true;
2555
+ }
2556
+ }
2557
+ const ranges = [];
2558
+ for (const { from, to } of selection.ranges) {
2559
+ let blockFrom = from;
2560
+ let blockTo = to;
2561
+ syntaxTree2(state).iterate({
2562
+ from,
2563
+ to,
2564
+ enter: (node) => {
2565
+ if (Object.hasOwn(Textblocks, node.name)) {
2566
+ if (from >= node.from && to <= node.to) {
2567
+ blockFrom = node.from;
2568
+ blockTo = node.to;
2569
+ } else {
2570
+ blockFrom = Math.min(blockFrom, state.doc.lineAt(node.from).from);
2571
+ blockTo = Math.max(blockTo, state.doc.lineAt(node.to).to);
2572
+ }
2573
+ }
2574
+ }
2575
+ });
2576
+ if (ranges.length && ranges[ranges.length - 1].to >= blockFrom - 1) {
2577
+ ranges[ranges.length - 1].to = blockTo;
2578
+ } else {
2579
+ ranges.push({
2580
+ from: blockFrom,
2581
+ to: blockTo
2582
+ });
2583
+ }
2584
+ }
2585
+ if (!ranges.length) {
2586
+ return false;
2587
+ }
2588
+ const changes = ranges.map(({ from, to }) => {
2589
+ const column = from - state.doc.lineAt(from).from;
2590
+ return [
2591
+ {
2592
+ from,
2593
+ insert: "```\n" + " ".repeat(column)
2594
+ },
2595
+ {
2596
+ from: to,
2597
+ insert: "\n" + " ".repeat(column) + "```"
2598
+ }
2599
+ ];
2600
+ });
2601
+ dispatch(state.update({
2602
+ changes,
2603
+ userEvent: "format.codeblock.add",
2604
+ scrollIntoView: true
2605
+ }));
2606
+ return true;
2607
+ };
2608
+ var removeCodeblock = ({ state, dispatch }) => {
2609
+ const changes = [];
2610
+ let lastBlock = -1;
2611
+ for (const { from, to } of state.selection.ranges) {
2612
+ syntaxTree2(state).iterate({
2613
+ from,
2614
+ to,
2615
+ enter: (node) => {
2616
+ if (Textblocks[node.name] === "codeblock" && lastBlock !== node.from) {
2617
+ lastBlock = node.from;
2618
+ const firstLine = state.doc.lineAt(node.from);
2619
+ if (node.name === "FencedCode") {
2620
+ changes.push({
2621
+ from: node.from,
2622
+ to: firstLine.to + 1 + node.from - firstLine.from
2623
+ });
2624
+ const lastLine = state.doc.lineAt(node.to);
2625
+ if (/^([\s>]|[-*+] |\d+[).])*`+$/.test(lastLine.text)) {
2626
+ changes.push({
2627
+ from: lastLine.from - (lastLine.number === firstLine.number + 1 ? 0 : 1),
2628
+ to: lastLine.to
2629
+ });
2630
+ }
2631
+ } else {
2632
+ const column = node.from - firstLine.from;
2633
+ for (let line = firstLine; ; line = state.doc.line(line.number + 1)) {
2634
+ changes.push({
2635
+ from: line.from + column - 4,
2636
+ to: line.from + column
2637
+ });
2638
+ if (line.to >= node.to) {
2639
+ break;
2640
+ }
2641
+ }
2642
+ }
2643
+ }
2644
+ }
2645
+ });
2646
+ }
2647
+ if (!changes.length) {
2648
+ return false;
2649
+ }
2650
+ dispatch(state.update({
2651
+ changes,
2652
+ userEvent: "format.codeblock.remove",
2653
+ scrollIntoView: true
2654
+ }));
2655
+ return true;
2656
+ };
2657
+ var toggleCodeblock = (target) => {
2658
+ return (getFormatting(target.state).blockType === "codeblock" ? removeCodeblock : addCodeblock)(target);
1894
2659
  };
1895
2660
  var formatting = (options = {}) => {
1896
2661
  return [
1897
2662
  keymap5.of([
1898
2663
  {
1899
2664
  key: "meta-b",
1900
- run: toggleBold
2665
+ run: toggleStrong
1901
2666
  }
1902
2667
  ]),
1903
2668
  styling()
@@ -1951,6 +2716,209 @@ var styling = () => {
1951
2716
  })
1952
2717
  ];
1953
2718
  };
2719
+ var InlineMarker = {
2720
+ Emphasis: 1,
2721
+ StrongEmphasis: 0,
2722
+ InlineCode: 3,
2723
+ Strikethrough: 2
2724
+ };
2725
+ var IgnoreInline = /* @__PURE__ */ new Set([
2726
+ "Autolink",
2727
+ "CodeMark",
2728
+ "CodeText",
2729
+ "Comment",
2730
+ "EmphasisMark",
2731
+ "Hardbreak",
2732
+ "HeaderMark",
2733
+ "HTMLTag",
2734
+ "LinkMark",
2735
+ "ListMark",
2736
+ "ProcessingInstruction",
2737
+ "QuoteMark",
2738
+ "StrikethroughMark",
2739
+ "SubscriptMark",
2740
+ "SuperscriptMark",
2741
+ "TaskMarker"
2742
+ ]);
2743
+ var Textblocks = {
2744
+ ATXHeading1: "heading1",
2745
+ ATXHeading2: "heading2",
2746
+ ATXHeading3: "heading3",
2747
+ ATXHeading4: "heading4",
2748
+ ATXHeading5: "heading5",
2749
+ ATXHeading6: "heading6",
2750
+ CodeBlock: "codeblock",
2751
+ FencedCode: "codeblock",
2752
+ Paragraph: "paragraph",
2753
+ SetextHeading1: "heading1",
2754
+ SetextHeading2: "heading2",
2755
+ TableCell: "tablecell",
2756
+ Task: "paragraph"
2757
+ };
2758
+ var getFormatting = (state) => {
2759
+ let blockType = null;
2760
+ const inline = [
2761
+ null,
2762
+ null,
2763
+ null,
2764
+ null
2765
+ ];
2766
+ let link2 = false;
2767
+ let blockQuote = null;
2768
+ let listStyle = null;
2769
+ const stack = [];
2770
+ let currentBlock = null;
2771
+ const advanceInline = (upto) => {
2772
+ if (!currentBlock) {
2773
+ return;
2774
+ }
2775
+ upto = Math.min(upto, currentBlock.end);
2776
+ if (upto <= currentBlock.pos) {
2777
+ return;
2778
+ }
2779
+ for (let i = 0; i < currentBlock.active.length; i++) {
2780
+ if (inline[i] === false) {
2781
+ continue;
2782
+ } else if (currentBlock.active[i]) {
2783
+ inline[i] = true;
2784
+ } else if (/\S/.test(state.doc.sliceString(currentBlock.pos, upto))) {
2785
+ inline[i] = false;
2786
+ }
2787
+ }
2788
+ currentBlock.pos = upto;
2789
+ };
2790
+ const skipInline = (upto) => {
2791
+ if (currentBlock && upto > currentBlock.pos) {
2792
+ currentBlock.pos = Math.min(upto, currentBlock.end);
2793
+ }
2794
+ };
2795
+ const { selection } = state;
2796
+ for (const range of selection.ranges) {
2797
+ if (range.empty && inline.some((v) => v === null)) {
2798
+ const contextSize = Math.min(range.head, 6);
2799
+ const contextBefore = state.doc.sliceString(range.head - contextSize, range.head);
2800
+ let contextAfter = state.doc.sliceString(range.head, range.head + contextSize);
2801
+ for (let i = 0; i < contextSize; i++) {
2802
+ const ch = contextAfter[i];
2803
+ if (ch !== contextBefore[contextBefore.length - 1 - i] || !/[~`*]/.test(ch)) {
2804
+ contextAfter = contextAfter.slice(0, i);
2805
+ break;
2806
+ }
2807
+ }
2808
+ for (let i = 0; i < inline.length; i++) {
2809
+ const mark2 = inlineMarkerText(i);
2810
+ const found = contextAfter.indexOf(mark2);
2811
+ if (found > -1) {
2812
+ contextAfter = contextAfter.slice(0, found) + contextAfter.slice(found + mark2.length);
2813
+ if (inline[i] === null) {
2814
+ inline[i] = true;
2815
+ }
2816
+ }
2817
+ }
2818
+ }
2819
+ syntaxTree2(state).iterate({
2820
+ from: range.from,
2821
+ to: range.to,
2822
+ enter: (node) => {
2823
+ advanceInline(node.from);
2824
+ const { name } = node;
2825
+ if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
2826
+ stack.push(name);
2827
+ } else if (name === "Link") {
2828
+ link2 = true;
2829
+ } else if (Object.hasOwn(Textblocks, name) && (range.empty || node.to > range.from || node.from < range.to)) {
2830
+ if (name === "Task" && stack[stack.length - 1] === "BulletList") {
2831
+ stack[stack.length - 1] = "TaskList";
2832
+ }
2833
+ const blockCode = Textblocks[name];
2834
+ if (blockType === null) {
2835
+ blockType = blockCode;
2836
+ } else if (blockType !== blockCode) {
2837
+ blockType = false;
2838
+ }
2839
+ if (blockCode !== "codeblock" && inline.some((i) => i !== false)) {
2840
+ currentBlock = {
2841
+ pos: Math.max(range.from, node.from),
2842
+ end: Math.min(range.to, node.to),
2843
+ active: [
2844
+ false,
2845
+ false,
2846
+ false,
2847
+ false
2848
+ ]
2849
+ };
2850
+ }
2851
+ } else if (Object.hasOwn(InlineMarker, name) && currentBlock) {
2852
+ const index = InlineMarker[name];
2853
+ if (range.empty && inline[index] === null) {
2854
+ inline[index] = true;
2855
+ }
2856
+ currentBlock.active[index] = true;
2857
+ } else if (IgnoreInline.has(name)) {
2858
+ skipInline(node.to);
2859
+ }
2860
+ },
2861
+ leave: (node) => {
2862
+ advanceInline(node.to);
2863
+ const { name } = node;
2864
+ if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
2865
+ stack.pop();
2866
+ } else if (Object.hasOwn(Textblocks, name)) {
2867
+ let hasList = false;
2868
+ let hasQuote = false;
2869
+ for (let i = stack.length - 1; i >= 0; i--) {
2870
+ if (stack[i] === "Blockquote") {
2871
+ hasQuote = true;
2872
+ } else if (!hasList) {
2873
+ hasList = stack[i] === "TaskList" ? "task" : stack[i] === "BulletList" ? "bullet" : "ordered";
2874
+ }
2875
+ }
2876
+ if (blockQuote === null) {
2877
+ blockQuote = hasQuote;
2878
+ } else if (!hasQuote && blockQuote) {
2879
+ blockQuote = false;
2880
+ }
2881
+ if (listStyle === null) {
2882
+ listStyle = hasList;
2883
+ } else if (listStyle !== hasList) {
2884
+ listStyle = false;
2885
+ }
2886
+ currentBlock = null;
2887
+ } else if (Object.hasOwn(InlineMarker, name) && currentBlock) {
2888
+ currentBlock.active[InlineMarker[name]] = false;
2889
+ }
2890
+ }
2891
+ });
2892
+ }
2893
+ const { from, to } = state.doc.lineAt(selection.main.anchor);
2894
+ const blankLine = from === to;
2895
+ return {
2896
+ blankLine,
2897
+ blockType: blockType || null,
2898
+ blockQuote: blockQuote ?? false,
2899
+ code: inline[3] ?? false,
2900
+ emphasis: inline[1] ?? false,
2901
+ strong: inline[0] ?? false,
2902
+ strikethrough: inline[2] ?? false,
2903
+ link: link2,
2904
+ listStyle: listStyle || null
2905
+ };
2906
+ };
2907
+ var useFormattingState = () => {
2908
+ const [state, setState] = useState(null);
2909
+ const observer = useMemo(() => EditorView9.updateListener.of((update2) => {
2910
+ if (update2.docChanged || update2.selectionSet) {
2911
+ const newState = getFormatting(update2.state);
2912
+ if (!state || !compareFormatting(state, newState)) {
2913
+ setState(newState);
2914
+ }
2915
+ }
2916
+ }), []);
2917
+ return [
2918
+ state,
2919
+ observer
2920
+ ];
2921
+ };
1954
2922
 
1955
2923
  // packages/ui/react-ui-editor/src/extensions/markdown/heading.ts
1956
2924
  import { syntaxTree as syntaxTree3 } from "@codemirror/language";
@@ -2003,8 +2971,8 @@ var heading2 = () => {
2003
2971
  // packages/ui/react-ui-editor/src/extensions/markdown/hr.ts
2004
2972
  import { syntaxTree as syntaxTree4 } from "@codemirror/language";
2005
2973
  import { RangeSetBuilder as RangeSetBuilder4 } from "@codemirror/state";
2006
- import { Decoration as Decoration6, EditorView as EditorView9, ViewPlugin as ViewPlugin6, WidgetType as WidgetType3 } from "@codemirror/view";
2007
- var styles4 = EditorView9.baseTheme({
2974
+ import { Decoration as Decoration6, EditorView as EditorView10, ViewPlugin as ViewPlugin6, WidgetType as WidgetType3 } from "@codemirror/view";
2975
+ var styles4 = EditorView10.baseTheme({
2008
2976
  "& .cm-hr": {
2009
2977
  // Note that block-level decorations should not have vertical margins,
2010
2978
  borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
@@ -2058,7 +3026,7 @@ var hr = () => {
2058
3026
  // packages/ui/react-ui-editor/src/extensions/markdown/image.ts
2059
3027
  import { syntaxTree as syntaxTree5 } from "@codemirror/language";
2060
3028
  import { StateField as StateField3 } from "@codemirror/state";
2061
- import { Decoration as Decoration7, EditorView as EditorView10, WidgetType as WidgetType4 } from "@codemirror/view";
3029
+ import { Decoration as Decoration7, EditorView as EditorView11, WidgetType as WidgetType4 } from "@codemirror/view";
2062
3030
  var image = (options = {}) => {
2063
3031
  return StateField3.define({
2064
3032
  create: (state) => {
@@ -2085,7 +3053,7 @@ var image = (options = {}) => {
2085
3053
  add: buildDecorations4(from, to, tr.state)
2086
3054
  });
2087
3055
  },
2088
- provide: (field) => EditorView10.decorations.from(field)
3056
+ provide: (field) => EditorView11.decorations.from(field)
2089
3057
  });
2090
3058
  };
2091
3059
  var buildDecorations4 = (from, to, state) => {
@@ -2267,12 +3235,12 @@ var buildDecorations5 = (view, options) => {
2267
3235
  // packages/ui/react-ui-editor/src/extensions/markdown/table.ts
2268
3236
  import { syntaxTree as syntaxTree7 } from "@codemirror/language";
2269
3237
  import { RangeSetBuilder as RangeSetBuilder6, StateField as StateField4 } from "@codemirror/state";
2270
- import { Decoration as Decoration9, EditorView as EditorView11, WidgetType as WidgetType6 } from "@codemirror/view";
3238
+ import { Decoration as Decoration9, EditorView as EditorView12, WidgetType as WidgetType6 } from "@codemirror/view";
2271
3239
  var table = (options = {}) => {
2272
3240
  return StateField4.define({
2273
3241
  create: (state) => update(state, options),
2274
3242
  update: (_, tr) => update(tr.state, options),
2275
- provide: (field) => EditorView11.decorations.from(field)
3243
+ provide: (field) => EditorView12.decorations.from(field)
2276
3244
  });
2277
3245
  };
2278
3246
  var update = (state, options) => {
@@ -2365,8 +3333,8 @@ var TableWidget = class extends WidgetType6 {
2365
3333
  // packages/ui/react-ui-editor/src/extensions/markdown/tasklist.ts
2366
3334
  import { syntaxTree as syntaxTree8 } from "@codemirror/language";
2367
3335
  import { RangeSetBuilder as RangeSetBuilder7 } from "@codemirror/state";
2368
- import { EditorView as EditorView12, Decoration as Decoration10, WidgetType as WidgetType7, ViewPlugin as ViewPlugin8 } from "@codemirror/view";
2369
- var styles5 = EditorView12.baseTheme({
3336
+ import { EditorView as EditorView13, Decoration as Decoration10, WidgetType as WidgetType7, ViewPlugin as ViewPlugin8 } from "@codemirror/view";
3337
+ var styles5 = EditorView13.baseTheme({
2370
3338
  "& .cm-task": {
2371
3339
  color: getToken("extend.colors.blue.500")
2372
3340
  },
@@ -2591,11 +3559,11 @@ var defaultTheme = {
2591
3559
  fontSize: "16px"
2592
3560
  },
2593
3561
  "&light .cm-content": {
2594
- color: get3(tokens, "extend.colors.neutral.900", "black"),
3562
+ color: get3(tokens, "extend.semanticColors.base.fg.light", "black"),
2595
3563
  caretColor: "black"
2596
3564
  },
2597
3565
  "&dark .cm-content": {
2598
- color: get3(tokens, "extend.colors.neutral.100", "white"),
3566
+ color: get3(tokens, "extend.semanticColors.base.fg.dark", "white"),
2599
3567
  caretColor: "white"
2600
3568
  },
2601
3569
  //
@@ -2799,7 +3767,7 @@ var EditorModes = [
2799
3767
  var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo, selection, editorMode, theme, slots = defaultSlots, extensions = [], debug }, forwardedRef) => {
2800
3768
  const { themeMode } = useThemeContext();
2801
3769
  const rootRef = useRef(null);
2802
- const [view, setView] = useState(null);
3770
+ const [view, setView] = useState2(null);
2803
3771
  useImperativeHandle(forwardedRef, () => view, [
2804
3772
  view
2805
3773
  ]);
@@ -2828,7 +3796,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
2828
3796
  selection,
2829
3797
  extensions: [
2830
3798
  // TODO(burdon): Doesn't catch errors in keymap functions.
2831
- EditorView13.exceptionSink.of((err) => {
3799
+ EditorView14.exceptionSink.of((err) => {
2832
3800
  log2.catch(err, void 0, {
2833
3801
  F: __dxlog_file3,
2834
3802
  L: 134,
@@ -2838,17 +3806,17 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
2838
3806
  }),
2839
3807
  // Theme.
2840
3808
  // TODO(burdon): Make configurable.
2841
- EditorView13.baseTheme(defaultTheme),
2842
- EditorView13.theme(theme ?? {}),
2843
- EditorView13.darkTheme.of(themeMode === "dark"),
2844
- EditorView13.editorAttributes.of({
3809
+ EditorView14.baseTheme(defaultTheme),
3810
+ EditorView14.theme(theme ?? {}),
3811
+ EditorView14.darkTheme.of(themeMode === "dark"),
3812
+ EditorView14.editorAttributes.of({
2845
3813
  class: slots.editor?.className ?? ""
2846
3814
  }),
2847
- EditorView13.contentAttributes.of({
3815
+ EditorView14.contentAttributes.of({
2848
3816
  class: slots.content?.className ?? ""
2849
3817
  }),
2850
3818
  // State.
2851
- EditorView13.editable.of(!readonly),
3819
+ EditorView14.editable.of(!readonly),
2852
3820
  EditorState2.readOnly.of(!!readonly),
2853
3821
  // Storage and replication.
2854
3822
  // NOTE: This must come before user extensions.
@@ -2859,7 +3827,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
2859
3827
  ...extensions
2860
3828
  ].filter(isNotFalsy3)
2861
3829
  });
2862
- const newView = new EditorView13({
3830
+ const newView = new EditorView14({
2863
3831
  state,
2864
3832
  parent: rootRef.current,
2865
3833
  scrollTo,
@@ -2966,35 +3934,49 @@ var defaultMarkdownSlots = {
2966
3934
  };
2967
3935
 
2968
3936
  // packages/ui/react-ui-editor/src/components/Toolbar/Toolbar.tsx
2969
- import { At, CaretRight, ChatText, Code, Image, Link, ListBullets, ListChecks, ListNumbers, TextStrikethrough, Table as Table2, TextB, TextItalic } from "@phosphor-icons/react";
3937
+ import { CaretRight, ChatText, Code, CodeBlock, Link, ListBullets, ListChecks, ListNumbers, Paragraph, TextStrikethrough, Table as Table2, TextB, TextHOne, TextHTwo, TextHThree, TextHFour, TextHFive, TextHSix, TextItalic } from "@phosphor-icons/react";
2970
3938
  import { createContext } from "@radix-ui/react-context";
2971
3939
  import React2 from "react";
2972
3940
  import { Button, DensityProvider, Select } from "@dxos/react-ui";
2973
- import { getSize } from "@dxos/react-ui-theme";
3941
+ import { getSize, mx as mx4 } from "@dxos/react-ui-theme";
3942
+ var HeadingIcons = {
3943
+ "0": Paragraph,
3944
+ "1": TextHOne,
3945
+ "2": TextHTwo,
3946
+ "3": TextHThree,
3947
+ "4": TextHFour,
3948
+ "5": TextHFive,
3949
+ "6": TextHSix
3950
+ };
2974
3951
  var [ToolbarContextProvider, useToolbarContext] = createContext("Toolbar");
2975
- var ToolbarRoot = ({ children, onAction }) => {
3952
+ var ToolbarRoot = ({ children, onAction, state }) => {
2976
3953
  return /* @__PURE__ */ React2.createElement(ToolbarContextProvider, {
2977
- onAction
3954
+ onAction,
3955
+ state
2978
3956
  }, /* @__PURE__ */ React2.createElement(DensityProvider, {
2979
3957
  density: "fine"
2980
3958
  }, /* @__PURE__ */ React2.createElement("div", {
2981
3959
  role: "toolbar",
2982
- className: "flex w-full shrink-0 p-2 gap-4 items-center whitespace-nowrap overflow-hidden"
3960
+ className: "flex w-full shrink-0 p-1 gap-4 items-center whitespace-nowrap overflow-hidden"
2983
3961
  }, children)));
2984
3962
  };
2985
- var ToolbarButton = ({ Icon, onClick, title }) => {
2986
- const { onAction } = useToolbarContext("ToolbarButton");
2987
- const handleClick = () => {
2988
- const action = onClick();
3963
+ var ToolbarButton = ({ Icon, onClick, title, getState, disable }) => {
3964
+ const { onAction, state } = useToolbarContext("ToolbarButton");
3965
+ const active = getState && state ? getState(state) : false;
3966
+ const disabled = disable && state ? disable(state) : false;
3967
+ const handleClick = (event) => {
3968
+ const action = onClick(state);
2989
3969
  if (action) {
2990
3970
  onAction?.(action);
3971
+ event.preventDefault();
2991
3972
  }
2992
3973
  };
2993
3974
  return /* @__PURE__ */ React2.createElement(Button, {
2994
3975
  variant: "ghost",
2995
- classNames: "p-2",
2996
- onClick: handleClick,
2997
- title
3976
+ classNames: mx4("p-2", active && "ring-[1px]"),
3977
+ onMouseDown: handleClick,
3978
+ title,
3979
+ disabled
2998
3980
  }, /* @__PURE__ */ React2.createElement(Icon, {
2999
3981
  className: getSize(5)
3000
3982
  }));
@@ -3003,16 +3985,21 @@ var ToolbarSeparator = () => /* @__PURE__ */ React2.createElement("div", {
3003
3985
  className: "grow"
3004
3986
  });
3005
3987
  var MarkdownHeading = () => {
3006
- const { onAction } = useToolbarContext("MarkdownFormatting");
3988
+ const { onAction, state } = useToolbarContext("MarkdownFormatting");
3989
+ const blockType = state ? state.blockType : "paragraph";
3990
+ const header = blockType && /heading(\d)/.exec(blockType);
3991
+ const value = header ? header[1] : blockType === "paragraph" || !blockType ? "0" : void 0;
3992
+ const HeadingIcon = HeadingIcons[value ?? "0"];
3007
3993
  return /* @__PURE__ */ React2.createElement(Select.Root, {
3008
- defaultValue: "0",
3009
- onValueChange: (value) => onAction?.({
3994
+ disabled: value === null,
3995
+ value: value ?? "0",
3996
+ onValueChange: (value2) => onAction?.({
3010
3997
  type: "heading",
3011
- data: parseInt(value)
3998
+ data: parseInt(value2)
3012
3999
  })
3013
- }, /* @__PURE__ */ React2.createElement(Select.TriggerButton, {
3014
- classNames: "w-[8rem]"
3015
- }), /* @__PURE__ */ React2.createElement(Select.Portal, null, /* @__PURE__ */ React2.createElement(Select.Content, null, /* @__PURE__ */ React2.createElement(Select.Viewport, null, /* @__PURE__ */ React2.createElement(Select.Option, {
4000
+ }, /* @__PURE__ */ React2.createElement(Select.TriggerButton, null, /* @__PURE__ */ React2.createElement(HeadingIcon, {
4001
+ className: getSize(5)
4002
+ })), /* @__PURE__ */ React2.createElement(Select.Portal, null, /* @__PURE__ */ React2.createElement(Select.Content, null, /* @__PURE__ */ React2.createElement(Select.Viewport, null, /* @__PURE__ */ React2.createElement(Select.Option, {
3016
4003
  value: "0"
3017
4004
  }, "Paragraph"), [
3018
4005
  1,
@@ -3030,21 +4017,39 @@ var MarkdownStyles = () => /* @__PURE__ */ React2.createElement("div", {
3030
4017
  role: "none"
3031
4018
  }, /* @__PURE__ */ React2.createElement(ToolbarButton, {
3032
4019
  Icon: TextB,
3033
- title: "Bold",
3034
- onClick: () => ({
3035
- type: "bold"
4020
+ title: "String",
4021
+ disable: (s) => s.blockType === "codeblock",
4022
+ getState: (s) => s.strong,
4023
+ onClick: (s) => ({
4024
+ type: "strong",
4025
+ data: s ? !s.strong : null
3036
4026
  })
3037
4027
  }), /* @__PURE__ */ React2.createElement(ToolbarButton, {
3038
4028
  Icon: TextItalic,
3039
- title: "Italic",
3040
- onClick: () => ({
3041
- type: "italic"
4029
+ title: "Emphasis",
4030
+ disable: (s) => s.blockType === "codeblock",
4031
+ getState: (s) => s.emphasis,
4032
+ onClick: (s) => ({
4033
+ type: "emphasis",
4034
+ data: s ? !s.emphasis : null
3042
4035
  })
3043
4036
  }), /* @__PURE__ */ React2.createElement(ToolbarButton, {
3044
4037
  Icon: TextStrikethrough,
3045
4038
  title: "Strike-through",
3046
- onClick: () => ({
3047
- type: "strikethrough"
4039
+ disable: (s) => s.blockType === "codeblock",
4040
+ getState: (s) => s.strikethrough,
4041
+ onClick: (s) => ({
4042
+ type: "strikethrough",
4043
+ data: s ? !s.strikethrough : null
4044
+ })
4045
+ }), /* @__PURE__ */ React2.createElement(ToolbarButton, {
4046
+ Icon: Code,
4047
+ title: "Inline code",
4048
+ disable: (s) => s.blockType === "codeblock",
4049
+ getState: (s) => s.code,
4050
+ onClick: (s) => ({
4051
+ type: "code",
4052
+ data: s ? !s.code : null
3048
4053
  })
3049
4054
  }));
3050
4055
  var MarkdownLists = () => /* @__PURE__ */ React2.createElement("div", {
@@ -3052,39 +4057,51 @@ var MarkdownLists = () => /* @__PURE__ */ React2.createElement("div", {
3052
4057
  }, /* @__PURE__ */ React2.createElement(ToolbarButton, {
3053
4058
  Icon: ListBullets,
3054
4059
  title: "Bullet list",
3055
- onClick: () => ({
3056
- type: "list"
4060
+ getState: (s) => s.listStyle === "bullet",
4061
+ onClick: (s) => ({
4062
+ type: "list-bullet",
4063
+ data: s ? s.listStyle !== "bullet" : null
3057
4064
  })
3058
4065
  }), /* @__PURE__ */ React2.createElement(ToolbarButton, {
3059
4066
  Icon: ListNumbers,
3060
4067
  title: "Numbered list",
3061
- onClick: () => ({
3062
- type: "list-ordered"
4068
+ getState: (s) => s.listStyle === "ordered",
4069
+ onClick: (s) => ({
4070
+ type: "list-ordered",
4071
+ data: s ? s.listStyle !== "ordered" : null
3063
4072
  })
3064
4073
  }), /* @__PURE__ */ React2.createElement(ToolbarButton, {
3065
4074
  Icon: ListChecks,
3066
4075
  title: "Task list",
3067
- onClick: () => ({
3068
- type: "list-tasks"
4076
+ getState: (s) => s.listStyle === "task",
4077
+ onClick: (s) => ({
4078
+ type: "list-tasks",
4079
+ data: s ? s.listStyle !== "task" : null
3069
4080
  })
3070
4081
  }));
3071
4082
  var MarkdownBlocks = () => /* @__PURE__ */ React2.createElement("div", {
3072
4083
  role: "none"
3073
4084
  }, /* @__PURE__ */ React2.createElement(ToolbarButton, {
3074
4085
  Icon: CaretRight,
3075
- title: "Block quite",
3076
- onClick: () => ({
3077
- type: "blockquote"
4086
+ title: "Block quote",
4087
+ getState: (s) => s.blockQuote,
4088
+ onClick: (s) => ({
4089
+ type: "blockquote",
4090
+ data: s ? !s.blockQuote : null
3078
4091
  })
3079
4092
  }), /* @__PURE__ */ React2.createElement(ToolbarButton, {
3080
- Icon: Code,
4093
+ Icon: CodeBlock,
3081
4094
  title: "Code block",
3082
- onClick: () => ({
3083
- type: "codeblock"
4095
+ disable: (s) => !s.blankLine,
4096
+ getState: (s) => s.blockType === "codeblock",
4097
+ onClick: (s) => ({
4098
+ type: "codeblock",
4099
+ data: s ? s.blockType !== "codeblock" : null
3084
4100
  })
3085
4101
  }), /* @__PURE__ */ React2.createElement(ToolbarButton, {
3086
4102
  Icon: Table2,
3087
4103
  title: "Table",
4104
+ disable: (s) => !s.blankLine,
3088
4105
  onClick: () => ({
3089
4106
  type: "table"
3090
4107
  })
@@ -3094,20 +4111,10 @@ var MarkdownLinks = () => /* @__PURE__ */ React2.createElement("div", {
3094
4111
  }, /* @__PURE__ */ React2.createElement(ToolbarButton, {
3095
4112
  Icon: Link,
3096
4113
  title: "Link",
3097
- onClick: () => ({
3098
- type: "link"
3099
- })
3100
- }), /* @__PURE__ */ React2.createElement(ToolbarButton, {
3101
- Icon: At,
3102
- title: "Mention",
3103
- onClick: () => ({
3104
- type: "mention"
3105
- })
3106
- }), /* @__PURE__ */ React2.createElement(ToolbarButton, {
3107
- Icon: Image,
3108
- title: "Image",
3109
- onClick: () => ({
3110
- type: "image"
4114
+ getState: (s) => s.link,
4115
+ onClick: (s) => ({
4116
+ type: "link",
4117
+ data: s ? !s.link : null
3111
4118
  })
3112
4119
  }));
3113
4120
  var MarkdownStandard = () => /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(MarkdownHeading, null), /* @__PURE__ */ React2.createElement(MarkdownStyles, null), /* @__PURE__ */ React2.createElement(MarkdownLists, null), /* @__PURE__ */ React2.createElement(MarkdownBlocks, null), /* @__PURE__ */ React2.createElement(MarkdownLinks, null));
@@ -3243,45 +4250,52 @@ var useActionHandler = (view) => {
3243
4250
  if (!view) {
3244
4251
  return;
3245
4252
  }
4253
+ let inlineType, listType;
3246
4254
  switch (action.type) {
3247
4255
  case "heading":
3248
4256
  setHeading(parseInt(action.data))(view);
3249
4257
  break;
3250
- case "bold":
3251
- toggleBold(view);
3252
- break;
3253
- case "italic":
3254
- toggleItalic(view);
3255
- break;
4258
+ case "strong":
4259
+ case "emphasis":
3256
4260
  case "strikethrough":
3257
- toggleStrikethrough(view);
4261
+ case "code":
4262
+ inlineType = action.type === "strong" ? Inline.Strong : action.type === "emphasis" ? Inline.Emphasis : action.type === "strikethrough" ? Inline.Strikethrough : Inline.Code;
4263
+ (typeof action.data === "boolean" ? setStyle(inlineType, action.data) : toggleStyle(inlineType))(view);
3258
4264
  break;
3259
- case "list":
3260
- toggleList(view);
4265
+ case "list-ordered":
4266
+ case "list-bullet":
4267
+ case "list-tasks":
4268
+ listType = action.type === "list-ordered" ? List.Ordered : action.type === "list-bullet" ? List.Bullet : List.Task;
4269
+ (action.data === false ? removeList(listType) : action.data === true ? addList(listType) : toggleList(listType))(view);
4270
+ break;
4271
+ case "blockquote":
4272
+ (action.data === false ? removeBlockquote : action.data === true ? addBlockquote : toggleBlockquote)(view);
3261
4273
  break;
3262
4274
  case "codeblock":
3263
- insertCodeblock(view);
4275
+ (action.data === false ? removeCodeblock : addCodeblock)(view);
3264
4276
  break;
3265
4277
  case "table":
3266
4278
  insertTable(view);
3267
4279
  break;
4280
+ case "link":
4281
+ (action.data === false ? removeLink : addLink)(view);
4282
+ break;
3268
4283
  case "comment":
3269
4284
  createComment(view);
3270
4285
  break;
3271
4286
  }
3272
4287
  setTimeout(() => {
3273
- view.focus();
3274
- view.dispatch({
3275
- selection: view.state.selection
3276
- });
4288
+ if (!view.hasFocus) {
4289
+ view.focus();
4290
+ }
3277
4291
  });
3278
4292
  };
3279
4293
  };
3280
4294
 
3281
4295
  // packages/ui/react-ui-editor/src/hooks/useEditorView.ts
3282
- import { useState as useState2 } from "react";
4296
+ import { useState as useState3 } from "react";
3283
4297
  var useEditorView = () => {
3284
- const [view, setView] = useState2(null);
4298
+ const [view, setView] = useState3(null);
3285
4299
  return [
3286
4300
  (ref) => {
3287
4301
  setView(ref);
@@ -3291,15 +4305,15 @@ var useEditorView = () => {
3291
4305
  };
3292
4306
 
3293
4307
  // packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
3294
- import { EditorSelection, EditorState as EditorState3 } from "@codemirror/state";
3295
- import { EditorView as EditorView14 } from "@codemirror/view";
3296
- import { useEffect as useEffect3, useRef as useRef2, useState as useState3 } from "react";
4308
+ import { EditorSelection as EditorSelection2, EditorState as EditorState3 } from "@codemirror/state";
4309
+ import { EditorView as EditorView15 } from "@codemirror/view";
4310
+ import { useEffect as useEffect3, useRef as useRef2, useState as useState4 } from "react";
3297
4311
  import { log as log4 } from "@dxos/log";
3298
4312
  import { isNotFalsy as isNotFalsy4 } from "@dxos/util";
3299
4313
  var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
3300
4314
  var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions } = {}) => {
3301
4315
  const onUpdate = useRef2();
3302
- const [view, setView] = useState3();
4316
+ const [view, setView] = useState4();
3303
4317
  const parentRef = useRef2(null);
3304
4318
  useEffect3(() => {
3305
4319
  if (parentRef.current) {
@@ -3308,7 +4322,7 @@ var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions }
3308
4322
  selection,
3309
4323
  extensions: [
3310
4324
  // TODO(burdon): Doesn't catch errors in keymap functions.
3311
- EditorView14.exceptionSink.of((err) => {
4325
+ EditorView15.exceptionSink.of((err) => {
3312
4326
  log4.catch(err, void 0, {
3313
4327
  F: __dxlog_file5,
3314
4328
  L: 57,
@@ -3317,12 +4331,12 @@ var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions }
3317
4331
  });
3318
4332
  }),
3319
4333
  extensions,
3320
- EditorView14.updateListener.of(() => {
4334
+ EditorView15.updateListener.of(() => {
3321
4335
  onUpdate.current?.();
3322
4336
  })
3323
4337
  ].filter(isNotFalsy4)
3324
4338
  });
3325
- const view2 = new EditorView14({
4339
+ const view2 = new EditorView15({
3326
4340
  parent: parentRef.current,
3327
4341
  scrollTo,
3328
4342
  state,
@@ -3346,7 +4360,7 @@ var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions }
3346
4360
  useEffect3(() => {
3347
4361
  if (view) {
3348
4362
  if (!selection && !view.state.selection.main.anchor) {
3349
- selection = EditorSelection.single(view.state.doc.line(1).to);
4363
+ selection = EditorSelection2.single(view.state.doc.line(1).to);
3350
4364
  }
3351
4365
  if (selection || scrollTo) {
3352
4366
  onUpdate.current = () => {
@@ -3379,19 +4393,19 @@ var createDataExtensions = ({ readonly = false } = {}) => {
3379
4393
  return [
3380
4394
  //
3381
4395
  EditorState3.readOnly.of(readonly),
3382
- EditorView14.editable.of(!readonly)
4396
+ EditorView15.editable.of(!readonly)
3383
4397
  ];
3384
4398
  };
3385
4399
  var createThemeExtensions = ({ theme, themeMode, slots } = {}) => {
3386
4400
  return [
3387
4401
  //
3388
- EditorView14.baseTheme(defaultTheme),
3389
- theme && EditorView14.theme(theme),
3390
- EditorView14.darkTheme.of(themeMode === "dark"),
3391
- EditorView14.editorAttributes.of({
4402
+ EditorView15.baseTheme(defaultTheme),
4403
+ theme && EditorView15.theme(theme),
4404
+ EditorView15.darkTheme.of(themeMode === "dark"),
4405
+ EditorView15.editorAttributes.of({
3392
4406
  class: slots?.editor?.className ?? ""
3393
4407
  }),
3394
- EditorView14.contentAttributes.of({
4408
+ EditorView15.contentAttributes.of({
3395
4409
  class: slots?.content?.className ?? ""
3396
4410
  })
3397
4411
  ].filter(isNotFalsy4);
@@ -3399,7 +4413,7 @@ var createThemeExtensions = ({ theme, themeMode, slots } = {}) => {
3399
4413
 
3400
4414
  // packages/ui/react-ui-editor/src/hooks/useTextModel.ts
3401
4415
  import get4 from "lodash.get";
3402
- import { useEffect as useEffect4, useState as useState4 } from "react";
4416
+ import { useEffect as useEffect4, useState as useState5 } from "react";
3403
4417
  import { generateName } from "@dxos/display-name";
3404
4418
  import { getRawDoc } from "@dxos/echo-schema";
3405
4419
  import { invariant as invariant3 } from "@dxos/invariant";
@@ -3407,7 +4421,7 @@ import { isAutomergeObject } from "@dxos/react-client/echo";
3407
4421
  var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
3408
4422
  var useTextModel = (props) => {
3409
4423
  const { identity, space, text } = props;
3410
- const [model, setModel] = useState4();
4424
+ const [model, setModel] = useState5();
3411
4425
  useEffect4(() => setModel(createModel(props)), [
3412
4426
  identity,
3413
4427
  space,
@@ -3416,7 +4430,7 @@ var useTextModel = (props) => {
3416
4430
  return model;
3417
4431
  };
3418
4432
  var useInMemoryTextModel = ({ id, defaultContent }) => {
3419
- const [content, setContent] = useState4(defaultContent ?? "");
4433
+ const [content, setContent] = useState5(defaultContent ?? "");
3420
4434
  return {
3421
4435
  id,
3422
4436
  content,
@@ -3476,6 +4490,8 @@ export {
3476
4490
  Cursor,
3477
4491
  Doc,
3478
4492
  EditorModes,
4493
+ Inline,
4494
+ List,
3479
4495
  MarkdownEditor,
3480
4496
  RemoteSelectionsDecorator,
3481
4497
  SpaceAwarenessProvider,
@@ -3484,6 +4500,11 @@ export {
3484
4500
  Toolbar,
3485
4501
  YText,
3486
4502
  YXmlFragment,
4503
+ addBlockquote,
4504
+ addCodeblock,
4505
+ addLink,
4506
+ addList,
4507
+ addStyle,
3487
4508
  autocomplete,
3488
4509
  automerge,
3489
4510
  awareness,
@@ -3493,6 +4514,7 @@ export {
3493
4514
  code2 as code,
3494
4515
  codeTheme,
3495
4516
  comments,
4517
+ compareFormatting,
3496
4518
  createBasicBundle,
3497
4519
  createComment,
3498
4520
  createDataExtensions,
@@ -3505,11 +4527,11 @@ export {
3505
4527
  defaultTheme,
3506
4528
  focusComment,
3507
4529
  formatting,
4530
+ getFormatting,
3508
4531
  getToken,
3509
4532
  heading2 as heading,
3510
4533
  hr,
3511
4534
  image,
3512
- insertCodeblock,
3513
4535
  insertTable,
3514
4536
  keymap7 as keymap,
3515
4537
  link,
@@ -3522,22 +4544,33 @@ export {
3522
4544
  mention,
3523
4545
  modelState,
3524
4546
  outliner,
4547
+ removeBlockquote,
4548
+ removeCodeblock,
4549
+ removeLink,
4550
+ removeList,
4551
+ removeStyle,
4552
+ setBlockquote,
3525
4553
  setComments,
3526
4554
  setHeading,
3527
4555
  setSelection,
4556
+ setStyle,
3528
4557
  table,
3529
4558
  tags2 as tags,
3530
4559
  tasklist,
3531
4560
  textTheme,
3532
- toggleBold,
3533
- toggleItalic,
4561
+ toggleBlockquote,
4562
+ toggleCodeblock,
4563
+ toggleEmphasis,
4564
+ toggleInlineCode,
3534
4565
  toggleList,
3535
4566
  toggleStrikethrough,
4567
+ toggleStrong,
3536
4568
  toggleStyle,
3537
4569
  typewriter,
3538
4570
  useActionHandler,
3539
4571
  useComments,
3540
4572
  useEditorView,
4573
+ useFormattingState,
3541
4574
  useInMemoryTextModel,
3542
4575
  useTextEditor,
3543
4576
  useTextModel,