@dxos/react-ui-editor 0.4.4-next.e0df51e → 0.4.5-main.181e1ed
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 +201 -92
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/automerge.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/hooks.stories.d.ts.map +1 -1
- package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
- package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -1
- package/dist/types/src/extensions/cursor-line-margin.d.ts +8 -0
- package/dist/types/src/extensions/cursor-line-margin.d.ts.map +1 -0
- package/dist/types/src/extensions/index.d.ts +1 -0
- package/dist/types/src/extensions/index.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -1
- package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
- package/dist/types/src/styles/layout.d.ts +2 -2
- package/dist/types/src/styles/layout.d.ts.map +1 -1
- package/package.json +31 -28
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +6 -0
- package/src/components/TextEditor/TextEditor.tsx +18 -5
- package/src/components/TextEditor/automerge.stories.tsx +9 -6
- package/src/components/TextEditor/hooks.stories.tsx +47 -17
- package/src/components/Toolbar/Toolbar.stories.tsx +2 -1
- package/src/components/Toolbar/Toolbar.tsx +0 -1
- package/src/extensions/cursor-line-margin.ts +92 -0
- package/src/extensions/index.ts +1 -0
- package/src/extensions/markdown/formatting.test.ts +17 -0
- package/src/extensions/markdown/formatting.ts +66 -12
- package/src/hooks/useTextEditor.ts +6 -2
- package/src/styles/layout.ts +3 -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
|
|
11
|
+
import { EditorView as EditorView16 } from "@codemirror/view";
|
|
12
12
|
import { useFocusableGroup } from "@fluentui/react-tabster";
|
|
13
13
|
import defaultsDeep2 from "lodash.defaultsdeep";
|
|
14
|
-
import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useRef, useState as useState2 } from "react";
|
|
14
|
+
import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useRef, useState as useState2, useMemo as useMemo2 } from "react";
|
|
15
15
|
import { log as log3 } from "@dxos/log";
|
|
16
16
|
import { useThemeContext } from "@dxos/react-ui";
|
|
17
17
|
import { focusRing } from "@dxos/react-ui-theme";
|
|
@@ -102,8 +102,8 @@ var annotations = (options = {}) => {
|
|
|
102
102
|
annotationsState
|
|
103
103
|
], (state) => {
|
|
104
104
|
const annotations2 = state.field(annotationsState);
|
|
105
|
-
const decorations = annotations2.map((
|
|
106
|
-
const range = Cursor.getRangeFromCursor(state,
|
|
105
|
+
const decorations = annotations2.map((annotation2) => {
|
|
106
|
+
const range = Cursor.getRangeFromCursor(state, annotation2.cursor);
|
|
107
107
|
return range && annotationMark.range(range.from, range.to);
|
|
108
108
|
}).filter(isNotFalsy);
|
|
109
109
|
return Decoration.set(decorations);
|
|
@@ -1116,8 +1116,8 @@ var getToken = (path, defaultValue = void 0) => get2(tokens, path, defaultValue)
|
|
|
1116
1116
|
|
|
1117
1117
|
// packages/ui/react-ui-editor/src/styles/layout.ts
|
|
1118
1118
|
var editorWithToolbarLayout = "grid grid-cols-1 grid-rows-[min-content_1fr] data-[toolbar=disabled]:grid-rows-[1fr] justify-center content-start overflow-hidden";
|
|
1119
|
-
var editorFillLayoutRoot = "
|
|
1120
|
-
var editorFillLayoutEditor = "
|
|
1119
|
+
var editorFillLayoutRoot = "bs-full overflow-hidden grid";
|
|
1120
|
+
var editorFillLayoutEditor = "bs-full overflow-hidden [&>.cm-scroller]:bs-full [&>.cm-scroller]:overflow-y-auto";
|
|
1121
1121
|
var editorHalfViewportOverscrollContent = "after:block after:min-bs-[50dvh] after:pointer-events-none";
|
|
1122
1122
|
|
|
1123
1123
|
// packages/ui/react-ui-editor/src/util.ts
|
|
@@ -1553,15 +1553,66 @@ var useComments = (view, id, comments2 = []) => {
|
|
|
1553
1553
|
]);
|
|
1554
1554
|
};
|
|
1555
1555
|
|
|
1556
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
1556
|
+
// packages/ui/react-ui-editor/src/extensions/cursor-line-margin.ts
|
|
1557
|
+
import { Facet as Facet4, Transaction } from "@codemirror/state";
|
|
1557
1558
|
import { EditorView as EditorView7 } from "@codemirror/view";
|
|
1559
|
+
var cursorLineMarginFacet = Facet4.define({
|
|
1560
|
+
combine: (input) => input[0] ?? 3
|
|
1561
|
+
});
|
|
1562
|
+
var annotation = "cursorLineMargin";
|
|
1563
|
+
var lineAtPos = (s, pos) => s.doc.lineAt(pos).number;
|
|
1564
|
+
var cursorLineMargin = EditorView7.updateListener.of(({ transactions, state, selectionSet, startState, view }) => {
|
|
1565
|
+
if (transactions.length < 1 || transactions.some((tr) => tr.isUserEvent(annotation))) {
|
|
1566
|
+
return;
|
|
1567
|
+
}
|
|
1568
|
+
const s = state;
|
|
1569
|
+
const { main } = s.selection;
|
|
1570
|
+
const cursorLineMargin2 = s.facet(cursorLineMarginFacet);
|
|
1571
|
+
const rect = view.dom.getBoundingClientRect();
|
|
1572
|
+
const viewportTop = rect.top - view.documentTop;
|
|
1573
|
+
const viewportBottom = rect.bottom - view.documentTop;
|
|
1574
|
+
const mainLine = lineAtPos(s, main.head);
|
|
1575
|
+
const _visTopLine = lineAtPos(s, view.lineBlockAtHeight(viewportTop).from);
|
|
1576
|
+
const botLineBlk = view.lineBlockAtHeight(viewportBottom);
|
|
1577
|
+
const visBotLineDoc = lineAtPos(s, Math.min(botLineBlk.to, s.doc.length));
|
|
1578
|
+
const visBotLine = botLineBlk.bottom >= viewportBottom ? visBotLineDoc : visBotLineDoc + Math.floor((viewportBottom - botLineBlk.bottom) / view.defaultLineHeight);
|
|
1579
|
+
const needsScrollTop = false;
|
|
1580
|
+
const needsScrollBot = mainLine >= visBotLine - cursorLineMargin2;
|
|
1581
|
+
if (needsScrollTop && needsScrollBot) {
|
|
1582
|
+
console.warn("is cursorScrollMargin too large for the editor size?");
|
|
1583
|
+
return;
|
|
1584
|
+
}
|
|
1585
|
+
if (!needsScrollTop && !needsScrollBot) {
|
|
1586
|
+
return;
|
|
1587
|
+
}
|
|
1588
|
+
if (selectionSet) {
|
|
1589
|
+
const { head } = startState.selection.main;
|
|
1590
|
+
const oldMainLine = lineAtPos(startState, head);
|
|
1591
|
+
if (needsScrollTop && oldMainLine < mainLine) {
|
|
1592
|
+
return;
|
|
1593
|
+
}
|
|
1594
|
+
if (needsScrollBot && oldMainLine > mainLine) {
|
|
1595
|
+
return;
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
view.dispatch({
|
|
1599
|
+
annotations: Transaction.userEvent.of(annotation),
|
|
1600
|
+
effects: EditorView7.scrollIntoView(s.selection.main.head, {
|
|
1601
|
+
y: needsScrollTop ? "start" : "end",
|
|
1602
|
+
yMargin: view.defaultLineHeight * cursorLineMargin2
|
|
1603
|
+
})
|
|
1604
|
+
});
|
|
1605
|
+
});
|
|
1606
|
+
|
|
1607
|
+
// packages/ui/react-ui-editor/src/extensions/listener.ts
|
|
1608
|
+
import { EditorView as EditorView8 } from "@codemirror/view";
|
|
1558
1609
|
var listener = ({ onFocus, onChange }) => {
|
|
1559
1610
|
const extensions = [];
|
|
1560
|
-
onFocus && extensions.push(
|
|
1611
|
+
onFocus && extensions.push(EditorView8.focusChangeEffect.of((_, focused) => {
|
|
1561
1612
|
onFocus(focused);
|
|
1562
1613
|
return null;
|
|
1563
1614
|
}));
|
|
1564
|
-
onChange && extensions.push(
|
|
1615
|
+
onChange && extensions.push(EditorView8.updateListener.of((update2) => {
|
|
1565
1616
|
onChange(update2.state.doc.toString());
|
|
1566
1617
|
}));
|
|
1567
1618
|
return extensions;
|
|
@@ -1576,7 +1627,7 @@ import { languages } from "@codemirror/language-data";
|
|
|
1576
1627
|
import { searchKeymap } from "@codemirror/search";
|
|
1577
1628
|
import { EditorState } from "@codemirror/state";
|
|
1578
1629
|
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
1579
|
-
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as
|
|
1630
|
+
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView9, highlightActiveLine as highlightActiveLine2, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
|
|
1580
1631
|
import { isNotFalsy as isNotFalsy3 } from "@dxos/util";
|
|
1581
1632
|
|
|
1582
1633
|
// packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
|
|
@@ -1770,7 +1821,7 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1770
1821
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1771
1822
|
var createMarkdownExtensions = ({ themeMode, placeholder: _placeholder, lineWrapping = true } = {}) => {
|
|
1772
1823
|
return [
|
|
1773
|
-
lineWrapping &&
|
|
1824
|
+
lineWrapping && EditorView9.lineWrapping,
|
|
1774
1825
|
EditorState.allowMultipleSelections.of(true),
|
|
1775
1826
|
EditorState.tabSize.of(2),
|
|
1776
1827
|
// https://github.com/codemirror/basic-setup
|
|
@@ -1823,9 +1874,9 @@ var createMarkdownExtensions = ({ themeMode, placeholder: _placeholder, lineWrap
|
|
|
1823
1874
|
// packages/ui/react-ui-editor/src/extensions/markdown/code.ts
|
|
1824
1875
|
import { syntaxTree } from "@codemirror/language";
|
|
1825
1876
|
import { RangeSetBuilder } from "@codemirror/state";
|
|
1826
|
-
import { ViewPlugin as ViewPlugin3, EditorView as
|
|
1877
|
+
import { ViewPlugin as ViewPlugin3, EditorView as EditorView10, Decoration as Decoration4, WidgetType as WidgetType2 } from "@codemirror/view";
|
|
1827
1878
|
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
1828
|
-
var styles4 =
|
|
1879
|
+
var styles4 = EditorView10.baseTheme({
|
|
1829
1880
|
"& .cm-code": {
|
|
1830
1881
|
fontFamily: getToken("fontFamily.mono", []).join(",")
|
|
1831
1882
|
},
|
|
@@ -1948,7 +1999,7 @@ var code2 = () => {
|
|
|
1948
1999
|
import { snippet } from "@codemirror/autocomplete";
|
|
1949
2000
|
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1950
2001
|
import { RangeSetBuilder as RangeSetBuilder2, EditorSelection } from "@codemirror/state";
|
|
1951
|
-
import { Decoration as Decoration5, EditorView as
|
|
2002
|
+
import { Decoration as Decoration5, EditorView as EditorView11, keymap as keymap5, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
|
|
1952
2003
|
import { useState, useMemo } from "react";
|
|
1953
2004
|
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;
|
|
1954
2005
|
var Inline;
|
|
@@ -1969,6 +2020,7 @@ var setHeading = (level) => ({ state, dispatch }) => {
|
|
|
1969
2020
|
const changes = [];
|
|
1970
2021
|
let prevBlock = -1;
|
|
1971
2022
|
for (const range of ranges) {
|
|
2023
|
+
let sawBlock = false;
|
|
1972
2024
|
syntaxTree2(state).iterate({
|
|
1973
2025
|
from: range.from,
|
|
1974
2026
|
to: range.to,
|
|
@@ -1976,6 +2028,7 @@ var setHeading = (level) => ({ state, dispatch }) => {
|
|
|
1976
2028
|
if (!Object.hasOwn(Textblocks, node.name) || prevBlock === node.from) {
|
|
1977
2029
|
return;
|
|
1978
2030
|
}
|
|
2031
|
+
sawBlock = true;
|
|
1979
2032
|
prevBlock = node.from;
|
|
1980
2033
|
const blockType = Textblocks[node.name];
|
|
1981
2034
|
const isHeading = /heading(\d)/.exec(blockType);
|
|
@@ -2020,12 +2073,22 @@ var setHeading = (level) => ({ state, dispatch }) => {
|
|
|
2020
2073
|
}
|
|
2021
2074
|
}
|
|
2022
2075
|
});
|
|
2076
|
+
let line;
|
|
2077
|
+
if (!sawBlock && range.empty && level > 0 && !/\S/.test((line = state.doc.lineAt(range.from)).text)) {
|
|
2078
|
+
changes.push({
|
|
2079
|
+
from: line.from,
|
|
2080
|
+
to: line.to,
|
|
2081
|
+
insert: "#".repeat(level) + " "
|
|
2082
|
+
});
|
|
2083
|
+
}
|
|
2023
2084
|
}
|
|
2024
2085
|
if (!changes.length) {
|
|
2025
2086
|
return false;
|
|
2026
2087
|
}
|
|
2088
|
+
const changeSet = state.changes(changes);
|
|
2027
2089
|
dispatch(state.update({
|
|
2028
|
-
changes,
|
|
2090
|
+
changes: changeSet,
|
|
2091
|
+
selection: state.selection.map(changeSet, 1),
|
|
2029
2092
|
userEvent: "format.setHeading",
|
|
2030
2093
|
scrollIntoView: true
|
|
2031
2094
|
}));
|
|
@@ -2097,10 +2160,16 @@ var setStyle = (type, enable) => ({ state, dispatch }) => {
|
|
|
2097
2160
|
const closeStart = node.to - size;
|
|
2098
2161
|
if (markType === type) {
|
|
2099
2162
|
if (openEnd <= from && closeStart >= from) {
|
|
2100
|
-
startCovered = openEnd === from
|
|
2163
|
+
startCovered = !enable && openEnd === skipMarkers(from, node.node, -1, openEnd) ? {
|
|
2164
|
+
from: node.from,
|
|
2165
|
+
to: openEnd
|
|
2166
|
+
} : true;
|
|
2101
2167
|
}
|
|
2102
2168
|
if (openEnd <= to && closeStart >= to) {
|
|
2103
|
-
endCovered = closeStart === to
|
|
2169
|
+
endCovered = !enable && closeStart === skipMarkers(to, node.node, 1, closeStart) ? {
|
|
2170
|
+
from: closeStart,
|
|
2171
|
+
to: node.to
|
|
2172
|
+
} : true;
|
|
2104
2173
|
}
|
|
2105
2174
|
}
|
|
2106
2175
|
if (markType === type || type === 3 && enable) {
|
|
@@ -2149,22 +2218,16 @@ var setStyle = (type, enable) => ({ state, dispatch }) => {
|
|
|
2149
2218
|
});
|
|
2150
2219
|
}
|
|
2151
2220
|
} else {
|
|
2152
|
-
if (startCovered === "
|
|
2153
|
-
changes2.push(
|
|
2154
|
-
from: from - marker.length,
|
|
2155
|
-
to: from
|
|
2156
|
-
});
|
|
2221
|
+
if (typeof startCovered === "object") {
|
|
2222
|
+
changes2.push(startCovered);
|
|
2157
2223
|
} else if (startCovered) {
|
|
2158
2224
|
changes2.push({
|
|
2159
2225
|
from: skipSpaces(rangeStart, state.doc, -1, blockStart),
|
|
2160
2226
|
insert: marker
|
|
2161
2227
|
});
|
|
2162
2228
|
}
|
|
2163
|
-
if (endCovered === "
|
|
2164
|
-
changes2.push(
|
|
2165
|
-
from: to,
|
|
2166
|
-
to: to + marker.length
|
|
2167
|
-
});
|
|
2229
|
+
if (typeof endCovered === "object") {
|
|
2230
|
+
changes2.push(endCovered);
|
|
2168
2231
|
} else if (endCovered) {
|
|
2169
2232
|
changes2.push({
|
|
2170
2233
|
from: skipSpaces(rangeEnd, state.doc, 1, blockEnd),
|
|
@@ -2175,6 +2238,15 @@ var setStyle = (type, enable) => ({ state, dispatch }) => {
|
|
|
2175
2238
|
}
|
|
2176
2239
|
}
|
|
2177
2240
|
});
|
|
2241
|
+
if (blockStart < 0 && range.empty && enable && !/\S/.test(state.doc.lineAt(range.from).text)) {
|
|
2242
|
+
return {
|
|
2243
|
+
changes: {
|
|
2244
|
+
from: range.head,
|
|
2245
|
+
insert: marker + marker
|
|
2246
|
+
},
|
|
2247
|
+
range: EditorSelection.cursor(range.head + marker.length)
|
|
2248
|
+
};
|
|
2249
|
+
}
|
|
2178
2250
|
const changeSet = state.changes(changes2.concat(changesAtEnd));
|
|
2179
2251
|
return {
|
|
2180
2252
|
changes: changeSet,
|
|
@@ -2220,6 +2292,19 @@ var skipSpaces = (pos, doc, dir, limit) => {
|
|
|
2220
2292
|
}
|
|
2221
2293
|
return pos;
|
|
2222
2294
|
};
|
|
2295
|
+
var skipMarkers = (pos, tree, dir, limit) => {
|
|
2296
|
+
for (; ; ) {
|
|
2297
|
+
const next = tree.resolve(pos, dir);
|
|
2298
|
+
if (!IgnoreInline.has(next.name)) {
|
|
2299
|
+
return pos;
|
|
2300
|
+
}
|
|
2301
|
+
const moveTo = dir < 0 ? next.from : next.to;
|
|
2302
|
+
if (limit != null && (dir < 0 ? moveTo < limit : moveTo > limit)) {
|
|
2303
|
+
return pos;
|
|
2304
|
+
}
|
|
2305
|
+
pos = moveTo;
|
|
2306
|
+
}
|
|
2307
|
+
};
|
|
2223
2308
|
var snippets = {
|
|
2224
2309
|
codeblock: snippet([
|
|
2225
2310
|
//
|
|
@@ -2498,8 +2583,10 @@ var addList = (type) => ({ state, dispatch }) => {
|
|
|
2498
2583
|
renumberListItems(next.firstChild, last.counter + 1, changes, state.doc);
|
|
2499
2584
|
}
|
|
2500
2585
|
}
|
|
2586
|
+
const changeSet = state.changes(changes);
|
|
2501
2587
|
dispatch(state.update({
|
|
2502
|
-
changes,
|
|
2588
|
+
changes: changeSet,
|
|
2589
|
+
selection: state.selection.map(changeSet, 1),
|
|
2503
2590
|
userEvent: "format.list.add",
|
|
2504
2591
|
scrollIntoView: true
|
|
2505
2592
|
}));
|
|
@@ -2593,6 +2680,7 @@ var setBlockquote = (enable) => ({ state, dispatch }) => {
|
|
|
2593
2680
|
const lines = [];
|
|
2594
2681
|
let lastBlock = -1;
|
|
2595
2682
|
for (const { from, to } of state.selection.ranges) {
|
|
2683
|
+
const sawBlock = false;
|
|
2596
2684
|
syntaxTree2(state).iterate({
|
|
2597
2685
|
from,
|
|
2598
2686
|
to,
|
|
@@ -2602,9 +2690,9 @@ var setBlockquote = (enable) => ({ state, dispatch }) => {
|
|
|
2602
2690
|
return false;
|
|
2603
2691
|
}
|
|
2604
2692
|
lastBlock = node.from;
|
|
2605
|
-
let
|
|
2606
|
-
if (
|
|
2607
|
-
const prevLine = state.doc.line(
|
|
2693
|
+
let line2 = state.doc.lineAt(node.from);
|
|
2694
|
+
if (line2.number > 1) {
|
|
2695
|
+
const prevLine = state.doc.line(line2.number - 1);
|
|
2608
2696
|
if (/^[>\s]*$/.test(prevLine.text)) {
|
|
2609
2697
|
if (!enable || lines.length && lines[lines.length - 1].number === prevLine.number - 1) {
|
|
2610
2698
|
lines.push(prevLine);
|
|
@@ -2612,14 +2700,14 @@ var setBlockquote = (enable) => ({ state, dispatch }) => {
|
|
|
2612
2700
|
}
|
|
2613
2701
|
}
|
|
2614
2702
|
for (; ; ) {
|
|
2615
|
-
lines.push(
|
|
2616
|
-
if (
|
|
2703
|
+
lines.push(line2);
|
|
2704
|
+
if (line2.to >= node.to) {
|
|
2617
2705
|
break;
|
|
2618
2706
|
}
|
|
2619
|
-
|
|
2707
|
+
line2 = state.doc.line(line2.number + 1);
|
|
2620
2708
|
}
|
|
2621
|
-
if (!enable &&
|
|
2622
|
-
const nextLine = state.doc.line(
|
|
2709
|
+
if (!enable && line2.number < state.doc.lines) {
|
|
2710
|
+
const nextLine = state.doc.line(line2.number + 1);
|
|
2623
2711
|
if (/^[>\s]*$/.test(nextLine.text)) {
|
|
2624
2712
|
lines.push(nextLine);
|
|
2625
2713
|
}
|
|
@@ -2628,6 +2716,10 @@ var setBlockquote = (enable) => ({ state, dispatch }) => {
|
|
|
2628
2716
|
}
|
|
2629
2717
|
}
|
|
2630
2718
|
});
|
|
2719
|
+
let line;
|
|
2720
|
+
if (!sawBlock && enable && from === to && !/\S/.test((line = state.doc.lineAt(from)).text)) {
|
|
2721
|
+
lines.push(line);
|
|
2722
|
+
}
|
|
2631
2723
|
}
|
|
2632
2724
|
const changes = [];
|
|
2633
2725
|
for (const line of lines) {
|
|
@@ -2649,8 +2741,10 @@ var setBlockquote = (enable) => ({ state, dispatch }) => {
|
|
|
2649
2741
|
if (!changes.length) {
|
|
2650
2742
|
return false;
|
|
2651
2743
|
}
|
|
2744
|
+
const changeSet = state.changes(changes);
|
|
2652
2745
|
dispatch(state.update({
|
|
2653
|
-
changes,
|
|
2746
|
+
changes: changeSet,
|
|
2747
|
+
selection: state.selection.map(changeSet, 1),
|
|
2654
2748
|
userEvent: enable ? "format.blockquote.add" : "format.blockquote.remove",
|
|
2655
2749
|
scrollIntoView: true
|
|
2656
2750
|
}));
|
|
@@ -3024,7 +3118,7 @@ var getFormatting = (state) => {
|
|
|
3024
3118
|
};
|
|
3025
3119
|
var useFormattingState = () => {
|
|
3026
3120
|
const [state, setState] = useState(null);
|
|
3027
|
-
const observer = useMemo(() =>
|
|
3121
|
+
const observer = useMemo(() => EditorView11.updateListener.of((update2) => {
|
|
3028
3122
|
if (update2.docChanged || update2.selectionSet) {
|
|
3029
3123
|
const newState = getFormatting(update2.state);
|
|
3030
3124
|
if (!state || !compareFormatting(state, newState)) {
|
|
@@ -3089,8 +3183,8 @@ var heading2 = () => {
|
|
|
3089
3183
|
// packages/ui/react-ui-editor/src/extensions/markdown/hr.ts
|
|
3090
3184
|
import { syntaxTree as syntaxTree4 } from "@codemirror/language";
|
|
3091
3185
|
import { RangeSetBuilder as RangeSetBuilder4 } from "@codemirror/state";
|
|
3092
|
-
import { Decoration as Decoration7, EditorView as
|
|
3093
|
-
var styles5 =
|
|
3186
|
+
import { Decoration as Decoration7, EditorView as EditorView12, ViewPlugin as ViewPlugin6, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
3187
|
+
var styles5 = EditorView12.baseTheme({
|
|
3094
3188
|
"& .cm-hr": {
|
|
3095
3189
|
// Note that block-level decorations should not have vertical margins,
|
|
3096
3190
|
borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
|
|
@@ -3144,7 +3238,7 @@ var hr = () => {
|
|
|
3144
3238
|
// packages/ui/react-ui-editor/src/extensions/markdown/image.ts
|
|
3145
3239
|
import { syntaxTree as syntaxTree5 } from "@codemirror/language";
|
|
3146
3240
|
import { StateField as StateField4 } from "@codemirror/state";
|
|
3147
|
-
import { Decoration as Decoration8, EditorView as
|
|
3241
|
+
import { Decoration as Decoration8, EditorView as EditorView13, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
3148
3242
|
var image = (options = {}) => {
|
|
3149
3243
|
return StateField4.define({
|
|
3150
3244
|
create: (state) => {
|
|
@@ -3171,7 +3265,7 @@ var image = (options = {}) => {
|
|
|
3171
3265
|
add: buildDecorations4(from, to, tr.state)
|
|
3172
3266
|
});
|
|
3173
3267
|
},
|
|
3174
|
-
provide: (field) =>
|
|
3268
|
+
provide: (field) => EditorView13.decorations.from(field)
|
|
3175
3269
|
});
|
|
3176
3270
|
};
|
|
3177
3271
|
var buildDecorations4 = (from, to, state) => {
|
|
@@ -3353,12 +3447,12 @@ var buildDecorations5 = (view, options) => {
|
|
|
3353
3447
|
// packages/ui/react-ui-editor/src/extensions/markdown/table.ts
|
|
3354
3448
|
import { syntaxTree as syntaxTree7 } from "@codemirror/language";
|
|
3355
3449
|
import { RangeSetBuilder as RangeSetBuilder6, StateField as StateField5 } from "@codemirror/state";
|
|
3356
|
-
import { Decoration as Decoration10, EditorView as
|
|
3450
|
+
import { Decoration as Decoration10, EditorView as EditorView14, WidgetType as WidgetType6 } from "@codemirror/view";
|
|
3357
3451
|
var table = (options = {}) => {
|
|
3358
3452
|
return StateField5.define({
|
|
3359
3453
|
create: (state) => update(state, options),
|
|
3360
3454
|
update: (_, tr) => update(tr.state, options),
|
|
3361
|
-
provide: (field) =>
|
|
3455
|
+
provide: (field) => EditorView14.decorations.from(field)
|
|
3362
3456
|
});
|
|
3363
3457
|
};
|
|
3364
3458
|
var update = (state, options) => {
|
|
@@ -3451,8 +3545,8 @@ var TableWidget = class extends WidgetType6 {
|
|
|
3451
3545
|
// packages/ui/react-ui-editor/src/extensions/markdown/tasklist.ts
|
|
3452
3546
|
import { syntaxTree as syntaxTree8 } from "@codemirror/language";
|
|
3453
3547
|
import { RangeSetBuilder as RangeSetBuilder7 } from "@codemirror/state";
|
|
3454
|
-
import { EditorView as
|
|
3455
|
-
var styles6 =
|
|
3548
|
+
import { EditorView as EditorView15, Decoration as Decoration11, WidgetType as WidgetType7, ViewPlugin as ViewPlugin8 } from "@codemirror/view";
|
|
3549
|
+
var styles6 = EditorView15.baseTheme({
|
|
3456
3550
|
"& .cm-task": {
|
|
3457
3551
|
color: getToken("extend.colors.blue.500")
|
|
3458
3552
|
},
|
|
@@ -3575,10 +3669,10 @@ var mention = ({ onSearch }) => {
|
|
|
3575
3669
|
};
|
|
3576
3670
|
|
|
3577
3671
|
// packages/ui/react-ui-editor/src/extensions/modes.ts
|
|
3578
|
-
import { Facet as
|
|
3672
|
+
import { Facet as Facet5 } from "@codemirror/state";
|
|
3579
3673
|
import { keymap as keymap6 } from "@codemirror/view";
|
|
3580
3674
|
import { vim } from "@replit/codemirror-vim";
|
|
3581
|
-
var editorMode =
|
|
3675
|
+
var editorMode = Facet5.define({
|
|
3582
3676
|
combine: (modes) => modes[0] ?? {}
|
|
3583
3677
|
});
|
|
3584
3678
|
var EditorModes = {
|
|
@@ -3942,27 +4036,27 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
|
|
|
3942
4036
|
selection,
|
|
3943
4037
|
extensions: [
|
|
3944
4038
|
// TODO(burdon): Doesn't catch errors in keymap functions.
|
|
3945
|
-
|
|
4039
|
+
EditorView16.exceptionSink.of((err) => {
|
|
3946
4040
|
log3.catch(err, void 0, {
|
|
3947
4041
|
F: __dxlog_file4,
|
|
3948
|
-
L:
|
|
4042
|
+
L: 113,
|
|
3949
4043
|
S: void 0,
|
|
3950
4044
|
C: (f, a) => f(...a)
|
|
3951
4045
|
});
|
|
3952
4046
|
}),
|
|
3953
4047
|
// Theme.
|
|
3954
4048
|
// TODO(burdon): Make configurable.
|
|
3955
|
-
|
|
3956
|
-
|
|
3957
|
-
|
|
3958
|
-
|
|
4049
|
+
EditorView16.baseTheme(defaultTheme),
|
|
4050
|
+
EditorView16.theme(theme ?? {}),
|
|
4051
|
+
EditorView16.darkTheme.of(themeMode === "dark"),
|
|
4052
|
+
EditorView16.editorAttributes.of({
|
|
3959
4053
|
class: slots.editor?.className ?? ""
|
|
3960
4054
|
}),
|
|
3961
|
-
|
|
4055
|
+
EditorView16.contentAttributes.of({
|
|
3962
4056
|
class: slots.content?.className ?? ""
|
|
3963
4057
|
}),
|
|
3964
4058
|
// Focus.
|
|
3965
|
-
|
|
4059
|
+
EditorView16.updateListener.of((update2) => {
|
|
3966
4060
|
update2.transactions.forEach((transaction) => {
|
|
3967
4061
|
if (transaction.isUserEvent("focus.container")) {
|
|
3968
4062
|
rootRef.current?.focus();
|
|
@@ -3970,7 +4064,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
|
|
|
3970
4064
|
});
|
|
3971
4065
|
}),
|
|
3972
4066
|
// State.
|
|
3973
|
-
|
|
4067
|
+
EditorView16.editable.of(!readonly),
|
|
3974
4068
|
EditorState2.readOnly.of(!!readonly),
|
|
3975
4069
|
// Storage and replication.
|
|
3976
4070
|
// NOTE: This must come before user extensions.
|
|
@@ -3979,7 +4073,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
|
|
|
3979
4073
|
...extensions
|
|
3980
4074
|
].filter(isNotFalsy4)
|
|
3981
4075
|
});
|
|
3982
|
-
const newView = new
|
|
4076
|
+
const newView = new EditorView16({
|
|
3983
4077
|
state,
|
|
3984
4078
|
parent: rootRef.current,
|
|
3985
4079
|
scrollTo,
|
|
@@ -4003,6 +4097,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
|
|
|
4003
4097
|
};
|
|
4004
4098
|
}, [
|
|
4005
4099
|
rootRef,
|
|
4100
|
+
extensions,
|
|
4006
4101
|
model,
|
|
4007
4102
|
readonly,
|
|
4008
4103
|
themeMode
|
|
@@ -4028,38 +4123,49 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
|
|
|
4028
4123
|
...tabsterDOMAttribute
|
|
4029
4124
|
});
|
|
4030
4125
|
});
|
|
4031
|
-
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, lineWrapping, theme = textTheme, slots, extensions
|
|
4126
|
+
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, lineWrapping, theme = textTheme, slots, extensions: _extensions, ...props }, forwardedRef) => {
|
|
4032
4127
|
const { themeMode } = useThemeContext();
|
|
4033
4128
|
const updatedSlots = defaultsDeep2({}, slots, defaultTextSlots);
|
|
4129
|
+
const extensions = useMemo2(() => [
|
|
4130
|
+
createBasicBundle({
|
|
4131
|
+
themeMode,
|
|
4132
|
+
placeholder: placeholder3,
|
|
4133
|
+
lineWrapping
|
|
4134
|
+
}),
|
|
4135
|
+
..._extensions ?? []
|
|
4136
|
+
], [
|
|
4137
|
+
themeMode,
|
|
4138
|
+
placeholder3,
|
|
4139
|
+
lineWrapping,
|
|
4140
|
+
_extensions
|
|
4141
|
+
]);
|
|
4034
4142
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
4035
4143
|
ref: forwardedRef,
|
|
4036
4144
|
readonly,
|
|
4037
|
-
extensions
|
|
4038
|
-
createBasicBundle({
|
|
4039
|
-
themeMode,
|
|
4040
|
-
placeholder: placeholder3,
|
|
4041
|
-
lineWrapping
|
|
4042
|
-
}),
|
|
4043
|
-
...extensions
|
|
4044
|
-
],
|
|
4145
|
+
extensions,
|
|
4045
4146
|
theme,
|
|
4046
4147
|
slots: updatedSlots,
|
|
4047
4148
|
...props
|
|
4048
4149
|
});
|
|
4049
4150
|
});
|
|
4050
|
-
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, theme = markdownTheme, slots, extensions
|
|
4151
|
+
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, theme = markdownTheme, slots, extensions: _extensions, ...props }, forwardedRef) => {
|
|
4051
4152
|
const { themeMode } = useThemeContext();
|
|
4052
4153
|
const updatedSlots = defaultsDeep2({}, slots, defaultMarkdownSlots);
|
|
4154
|
+
const extensions = useMemo2(() => [
|
|
4155
|
+
createMarkdownExtensions({
|
|
4156
|
+
themeMode,
|
|
4157
|
+
placeholder: placeholder3
|
|
4158
|
+
}),
|
|
4159
|
+
..._extensions ?? []
|
|
4160
|
+
], [
|
|
4161
|
+
themeMode,
|
|
4162
|
+
placeholder3,
|
|
4163
|
+
_extensions
|
|
4164
|
+
]);
|
|
4053
4165
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
4054
4166
|
ref: forwardedRef,
|
|
4055
4167
|
readonly,
|
|
4056
|
-
extensions
|
|
4057
|
-
createMarkdownExtensions({
|
|
4058
|
-
themeMode,
|
|
4059
|
-
placeholder: placeholder3
|
|
4060
|
-
}),
|
|
4061
|
-
...extensions
|
|
4062
|
-
],
|
|
4168
|
+
extensions,
|
|
4063
4169
|
theme,
|
|
4064
4170
|
slots: updatedSlots,
|
|
4065
4171
|
...props
|
|
@@ -4289,8 +4395,7 @@ var markdownBlocks = [
|
|
|
4289
4395
|
{
|
|
4290
4396
|
type: "codeblock",
|
|
4291
4397
|
Icon: CodeBlock,
|
|
4292
|
-
getState: (state) => state.blockType === "codeblock"
|
|
4293
|
-
disabled: (state) => !state.blankLine
|
|
4398
|
+
getState: (state) => state.blockType === "codeblock"
|
|
4294
4399
|
},
|
|
4295
4400
|
{
|
|
4296
4401
|
type: "table",
|
|
@@ -4523,7 +4628,7 @@ var useEditorView = (id) => {
|
|
|
4523
4628
|
|
|
4524
4629
|
// packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
|
|
4525
4630
|
import { EditorSelection as EditorSelection2, EditorState as EditorState3 } from "@codemirror/state";
|
|
4526
|
-
import { EditorView as
|
|
4631
|
+
import { EditorView as EditorView17 } from "@codemirror/view";
|
|
4527
4632
|
import { useEffect as useEffect3, useRef as useRef3, useState as useState4 } from "react";
|
|
4528
4633
|
import { log as log5 } from "@dxos/log";
|
|
4529
4634
|
import { isNotFalsy as isNotFalsy5 } from "@dxos/util";
|
|
@@ -4533,27 +4638,28 @@ var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions }
|
|
|
4533
4638
|
const [view, setView] = useState4();
|
|
4534
4639
|
const parentRef = useRef3(null);
|
|
4535
4640
|
useEffect3(() => {
|
|
4641
|
+
let view2;
|
|
4536
4642
|
if (parentRef.current) {
|
|
4537
4643
|
const state = EditorState3.create({
|
|
4538
4644
|
doc,
|
|
4539
4645
|
selection,
|
|
4540
4646
|
extensions: [
|
|
4541
4647
|
// TODO(burdon): Doesn't catch errors in keymap functions.
|
|
4542
|
-
|
|
4648
|
+
EditorView17.exceptionSink.of((err) => {
|
|
4543
4649
|
log5.catch(err, void 0, {
|
|
4544
4650
|
F: __dxlog_file6,
|
|
4545
|
-
L:
|
|
4651
|
+
L: 60,
|
|
4546
4652
|
S: void 0,
|
|
4547
4653
|
C: (f, a) => f(...a)
|
|
4548
4654
|
});
|
|
4549
4655
|
}),
|
|
4550
4656
|
extensions,
|
|
4551
|
-
|
|
4657
|
+
EditorView17.updateListener.of(() => {
|
|
4552
4658
|
onUpdate.current?.();
|
|
4553
4659
|
})
|
|
4554
4660
|
].filter(isNotFalsy5)
|
|
4555
4661
|
});
|
|
4556
|
-
|
|
4662
|
+
view2 = new EditorView17({
|
|
4557
4663
|
parent: parentRef.current,
|
|
4558
4664
|
scrollTo,
|
|
4559
4665
|
state,
|
|
@@ -4569,10 +4675,11 @@ var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions }
|
|
|
4569
4675
|
setView(view2);
|
|
4570
4676
|
}
|
|
4571
4677
|
return () => {
|
|
4572
|
-
|
|
4678
|
+
view2?.destroy();
|
|
4573
4679
|
};
|
|
4574
4680
|
}, [
|
|
4575
|
-
parentRef
|
|
4681
|
+
parentRef,
|
|
4682
|
+
extensions
|
|
4576
4683
|
]);
|
|
4577
4684
|
useEffect3(() => {
|
|
4578
4685
|
if (view) {
|
|
@@ -4610,19 +4717,19 @@ var createDataExtensions = ({ readonly = false } = {}) => {
|
|
|
4610
4717
|
return [
|
|
4611
4718
|
//
|
|
4612
4719
|
EditorState3.readOnly.of(readonly),
|
|
4613
|
-
|
|
4720
|
+
EditorView17.editable.of(!readonly)
|
|
4614
4721
|
];
|
|
4615
4722
|
};
|
|
4616
4723
|
var createThemeExtensions = ({ theme, themeMode, slots } = {}) => {
|
|
4617
4724
|
return [
|
|
4618
4725
|
//
|
|
4619
|
-
|
|
4620
|
-
theme &&
|
|
4621
|
-
|
|
4622
|
-
|
|
4726
|
+
EditorView17.baseTheme(defaultTheme),
|
|
4727
|
+
theme && EditorView17.theme(theme),
|
|
4728
|
+
EditorView17.darkTheme.of(themeMode === "dark"),
|
|
4729
|
+
EditorView17.editorAttributes.of({
|
|
4623
4730
|
class: slots?.editor?.className ?? ""
|
|
4624
4731
|
}),
|
|
4625
|
-
|
|
4732
|
+
EditorView17.contentAttributes.of({
|
|
4626
4733
|
class: slots?.content?.className ?? ""
|
|
4627
4734
|
})
|
|
4628
4735
|
].filter(isNotFalsy5);
|
|
@@ -4630,13 +4737,13 @@ var createThemeExtensions = ({ theme, themeMode, slots } = {}) => {
|
|
|
4630
4737
|
|
|
4631
4738
|
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
4632
4739
|
import get4 from "lodash.get";
|
|
4633
|
-
import { useState as useState5, useMemo as
|
|
4740
|
+
import { useState as useState5, useMemo as useMemo3 } from "react";
|
|
4634
4741
|
import { generateName } from "@dxos/display-name";
|
|
4635
4742
|
import { getRawDoc } from "@dxos/echo-schema";
|
|
4636
4743
|
import { invariant as invariant3 } from "@dxos/invariant";
|
|
4637
4744
|
import { isAutomergeObject } from "@dxos/react-client/echo";
|
|
4638
4745
|
var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
|
|
4639
|
-
var useTextModel = (props) =>
|
|
4746
|
+
var useTextModel = (props) => useMemo3(() => createModel(props), Object.values(props));
|
|
4640
4747
|
var useInMemoryTextModel = ({ id, defaultContent }) => {
|
|
4641
4748
|
const [content, setContent] = useState5(defaultContent ?? "");
|
|
4642
4749
|
return {
|
|
@@ -4731,6 +4838,8 @@ export {
|
|
|
4731
4838
|
createDataExtensions,
|
|
4732
4839
|
createMarkdownExtensions,
|
|
4733
4840
|
createThemeExtensions,
|
|
4841
|
+
cursorLineMargin,
|
|
4842
|
+
cursorLineMarginFacet,
|
|
4734
4843
|
defaultMarkdownSlots,
|
|
4735
4844
|
defaultOptions,
|
|
4736
4845
|
defaultSlots,
|