@firecms/editor 3.0.0-canary.113 → 3.0.0-canary.114
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/extensions/HighlightDecorationExtension.d.ts +35 -0
- package/dist/extensions/TextLoadingDecorationExtension.d.ts +18 -0
- package/dist/index.es.js +112 -100
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +111 -99
- package/dist/index.umd.js.map +1 -1
- package/package.json +3 -3
- package/dist/LoadingDecorator.d.ts +0 -10
- package/dist/extensions/AiContent.d.ts +0 -9
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Extension } from "@tiptap/core";
|
|
2
|
+
import { PluginKey } from "@tiptap/pm/state";
|
|
3
|
+
import { DecorationSet } from "@tiptap/pm/view";
|
|
4
|
+
declare module "@tiptap/core" {
|
|
5
|
+
interface Commands<ReturnType> {
|
|
6
|
+
highlightDecoration: {
|
|
7
|
+
toggleAutocompleteHighlight: (range?: {
|
|
8
|
+
from: number;
|
|
9
|
+
to: number;
|
|
10
|
+
}) => ReturnType;
|
|
11
|
+
removeAutocompleteHighlight: () => ReturnType;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export interface HighlightRange {
|
|
16
|
+
from: number;
|
|
17
|
+
to: number;
|
|
18
|
+
}
|
|
19
|
+
interface AutocompleteHighlightState {
|
|
20
|
+
highlight?: HighlightRange;
|
|
21
|
+
decorationSet?: DecorationSet;
|
|
22
|
+
}
|
|
23
|
+
export interface HighlightDecorationOptions {
|
|
24
|
+
pluginKey: PluginKey<AutocompleteHighlightState>;
|
|
25
|
+
highlight?: {
|
|
26
|
+
from: number;
|
|
27
|
+
to: number;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* This plugin is used to highlight the current autocomplete suggestion.
|
|
32
|
+
* It allows to set a range and remove it.
|
|
33
|
+
*/
|
|
34
|
+
export declare const HighlightDecorationExtension: (initialHighlight?: HighlightRange) => Extension<HighlightDecorationOptions, any>;
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { PluginKey } from "prosemirror-state";
|
|
2
|
+
import { DecorationSet } from "prosemirror-view";
|
|
3
|
+
import { Extension } from "@tiptap/core";
|
|
4
|
+
declare module "@tiptap/core" {
|
|
5
|
+
interface Commands<ReturnType> {
|
|
6
|
+
textLoadingDecoration: {
|
|
7
|
+
toggleLoadingDecoration: (loadingHtml?: string) => ReturnType;
|
|
8
|
+
removeLoadingDecoration: () => ReturnType;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export declare const loadingDecorationKey: PluginKey<LoadingDecorationState>;
|
|
13
|
+
interface LoadingDecorationState {
|
|
14
|
+
decorationSet: DecorationSet;
|
|
15
|
+
hasDecoration: boolean;
|
|
16
|
+
}
|
|
17
|
+
declare const TextLoadingDecorationExtension: Extension<any, any>;
|
|
18
|
+
export default TextLoadingDecorationExtension;
|
package/dist/index.es.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import React, { forwardRef, useRef, useEffect, useMemo, useState, useImperativeHandle, useDeferredValue } from "react";
|
|
3
|
-
import
|
|
3
|
+
import { Underline } from "@tiptap/extension-underline";
|
|
4
4
|
import TextStyle from "@tiptap/extension-text-style";
|
|
5
5
|
import { Color } from "@tiptap/extension-color";
|
|
6
6
|
import BulletList from "@tiptap/extension-bullet-list";
|
|
7
7
|
import Highlight from "@tiptap/extension-highlight";
|
|
8
8
|
import { useCurrentEditor, BubbleMenu, isNodeSelection, Node, mergeAttributes, ReactRenderer, EditorProvider } from "@tiptap/react";
|
|
9
9
|
import { Slot } from "@radix-ui/react-slot";
|
|
10
|
-
import { Popover, Button, ExpandMoreIcon, CheckIcon, TextFieldsIcon, LooksOneIcon, LooksTwoIcon, Looks3Icon, CheckBoxIcon, FormatListBulletedIcon, FormatListNumberedIcon, FormatQuoteIcon, CodeIcon, cls, DeleteIcon, FormatBoldIcon, FormatItalicIcon, FormatUnderlinedIcon, FormatStrikethroughIcon, defaultBorderMixin, AutoAwesomeIcon, ImageIcon, useInjectStyles, Separator } from "@firecms/ui";
|
|
10
|
+
import { Popover, Button, ExpandMoreIcon, CheckIcon, TextFieldsIcon, LooksOneIcon, LooksTwoIcon, Looks3Icon, CheckBoxIcon, FormatListBulletedIcon, FormatListNumberedIcon, FormatQuoteIcon, CodeIcon, cls, focusedDisabled, DeleteIcon, FormatBoldIcon, FormatItalicIcon, FormatUnderlinedIcon, FormatStrikethroughIcon, defaultBorderMixin, AutoAwesomeIcon, ImageIcon, useInjectStyles, Separator } from "@firecms/ui";
|
|
11
11
|
import StarterKit from "@tiptap/starter-kit";
|
|
12
12
|
import HorizontalRule from "@tiptap/extension-horizontal-rule";
|
|
13
13
|
import TiptapLink from "@tiptap/extension-link";
|
|
@@ -15,7 +15,7 @@ import TiptapImage from "@tiptap/extension-image";
|
|
|
15
15
|
import Placeholder from "@tiptap/extension-placeholder";
|
|
16
16
|
import { TaskItem } from "@tiptap/extension-task-item";
|
|
17
17
|
import { TaskList } from "@tiptap/extension-task-list";
|
|
18
|
-
import { Extension, InputRule
|
|
18
|
+
import { Extension, InputRule } from "@tiptap/core";
|
|
19
19
|
import { PluginKey, Plugin } from "prosemirror-state";
|
|
20
20
|
import { DecorationSet, Decoration } from "prosemirror-view";
|
|
21
21
|
import { Markdown } from "tiptap-markdown";
|
|
@@ -243,7 +243,7 @@ const LinkSelector = ({
|
|
|
243
243
|
autoFocus: open,
|
|
244
244
|
placeholder: "Paste a link",
|
|
245
245
|
defaultValue: editor.getAttributes("link").href || "",
|
|
246
|
-
className: "text-gray-900 dark:text-white flex-grow bg-transparent p-1 text-sm outline-none"
|
|
246
|
+
className: cls("text-gray-900 dark:text-white flex-grow bg-transparent p-1 text-sm outline-none", focusedDisabled)
|
|
247
247
|
}
|
|
248
248
|
),
|
|
249
249
|
editor.getAttributes("link").href ? /* @__PURE__ */ jsx(
|
|
@@ -350,7 +350,7 @@ function removeClassesFromJson(jsonObj) {
|
|
|
350
350
|
return jsonObj;
|
|
351
351
|
}
|
|
352
352
|
const loadingDecorationKey = new PluginKey("loadingDecoration");
|
|
353
|
-
const
|
|
353
|
+
const TextLoadingDecorationExtension = Extension.create({
|
|
354
354
|
name: "loadingDecoration",
|
|
355
355
|
addOptions() {
|
|
356
356
|
return {
|
|
@@ -410,7 +410,6 @@ const LoadingDecoration = Extension.create({
|
|
|
410
410
|
})
|
|
411
411
|
];
|
|
412
412
|
},
|
|
413
|
-
// @ts-ignore
|
|
414
413
|
addCommands() {
|
|
415
414
|
return {
|
|
416
415
|
toggleLoadingDecoration: (loadingHtml) => ({ state, dispatch }) => {
|
|
@@ -418,8 +417,6 @@ const LoadingDecoration = Extension.create({
|
|
|
418
417
|
const pos = selection.from;
|
|
419
418
|
if (!dispatch) return false;
|
|
420
419
|
const pluginKey = this.options.pluginKey;
|
|
421
|
-
const pluginState = pluginKey.get(state);
|
|
422
|
-
pluginState?.getState(state)?.hasDecoration ?? false;
|
|
423
420
|
const tr = state.tr.setMeta(pluginKey, {
|
|
424
421
|
pos,
|
|
425
422
|
type: "loadingDecoration",
|
|
@@ -1379,72 +1376,109 @@ const suggestionItems = [
|
|
|
1379
1376
|
}
|
|
1380
1377
|
}
|
|
1381
1378
|
];
|
|
1382
|
-
|
|
1383
|
-
const
|
|
1384
|
-
|
|
1379
|
+
function buildDecorationSet(highlight, doc) {
|
|
1380
|
+
const decorations = [];
|
|
1381
|
+
if (highlight) {
|
|
1382
|
+
decorations.push(
|
|
1383
|
+
Decoration$1.inline(highlight.from, highlight.to, {
|
|
1384
|
+
class: "dark:bg-slate-700 bg-slate-300"
|
|
1385
|
+
})
|
|
1386
|
+
);
|
|
1387
|
+
}
|
|
1388
|
+
const decorationSet = DecorationSet$1.create(doc, decorations);
|
|
1389
|
+
return decorationSet;
|
|
1390
|
+
}
|
|
1391
|
+
const HighlightDecorationExtension = (initialHighlight) => Extension.create({
|
|
1392
|
+
name: "highlightDecoration",
|
|
1393
|
+
addOptions() {
|
|
1394
|
+
return {
|
|
1395
|
+
pluginKey: new PluginKey$1("highlightDecoration"),
|
|
1396
|
+
highlight: initialHighlight
|
|
1397
|
+
};
|
|
1398
|
+
},
|
|
1385
1399
|
addProseMirrorPlugins() {
|
|
1386
|
-
const pluginKey =
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1400
|
+
const pluginKey = this.options.pluginKey;
|
|
1401
|
+
return [
|
|
1402
|
+
new Plugin$1({
|
|
1403
|
+
key: pluginKey,
|
|
1404
|
+
state: {
|
|
1405
|
+
init: (_, { doc }) => {
|
|
1406
|
+
const highlight = this.options.highlight;
|
|
1407
|
+
const decorationSet = highlight && doc ? buildDecorationSet(highlight, doc) : DecorationSet$1.empty;
|
|
1408
|
+
return {
|
|
1409
|
+
decorationSet,
|
|
1410
|
+
highlight
|
|
1411
|
+
};
|
|
1412
|
+
},
|
|
1413
|
+
apply(transaction, oldState) {
|
|
1414
|
+
const action = transaction.getMeta(pluginKey);
|
|
1415
|
+
const highlight = action?.range;
|
|
1416
|
+
if (action?.type === "highlightDecoration") {
|
|
1417
|
+
const doc = transaction.doc;
|
|
1418
|
+
const { remove } = action;
|
|
1419
|
+
if (remove) {
|
|
1420
|
+
return {
|
|
1421
|
+
decorationSet: DecorationSet$1.empty
|
|
1422
|
+
};
|
|
1423
|
+
}
|
|
1424
|
+
const decorationSet = buildDecorationSet(highlight, doc);
|
|
1425
|
+
return {
|
|
1426
|
+
decorationSet,
|
|
1427
|
+
highlight
|
|
1428
|
+
};
|
|
1429
|
+
} else {
|
|
1430
|
+
return oldState;
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1392
1433
|
},
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
const prevDecos = plugin.getState(prevState);
|
|
1401
|
-
const newDecos = plugin.getState(view.state);
|
|
1402
|
-
if (prevDecos !== newDecos) {
|
|
1403
|
-
view.updateState(view.state);
|
|
1434
|
+
props: {
|
|
1435
|
+
decorations(state) {
|
|
1436
|
+
const autocompleteState = this.getState(state);
|
|
1437
|
+
if (autocompleteState?.decorationSet) {
|
|
1438
|
+
return autocompleteState.decorationSet;
|
|
1439
|
+
} else {
|
|
1440
|
+
return DecorationSet$1.empty;
|
|
1404
1441
|
}
|
|
1405
1442
|
}
|
|
1406
|
-
}
|
|
1443
|
+
}
|
|
1444
|
+
})
|
|
1445
|
+
];
|
|
1446
|
+
},
|
|
1447
|
+
addCommands() {
|
|
1448
|
+
return {
|
|
1449
|
+
toggleAutocompleteHighlight: (range) => ({
|
|
1450
|
+
state,
|
|
1451
|
+
dispatch
|
|
1452
|
+
}) => {
|
|
1453
|
+
const { selection } = state;
|
|
1454
|
+
const pos = selection.from;
|
|
1455
|
+
if (!dispatch) return false;
|
|
1456
|
+
const pluginKey = this.options.pluginKey;
|
|
1457
|
+
const tr = state.tr.setMeta(pluginKey, {
|
|
1458
|
+
pos,
|
|
1459
|
+
type: "highlightDecoration",
|
|
1460
|
+
remove: false,
|
|
1461
|
+
range
|
|
1462
|
+
});
|
|
1463
|
+
dispatch(tr);
|
|
1464
|
+
return true;
|
|
1465
|
+
},
|
|
1466
|
+
removeAutocompleteHighlight: () => ({
|
|
1467
|
+
state,
|
|
1468
|
+
dispatch
|
|
1469
|
+
}) => {
|
|
1470
|
+
if (!dispatch) return false;
|
|
1471
|
+
const pluginKey = this.options.pluginKey;
|
|
1472
|
+
const tr = state.tr.setMeta(pluginKey, {
|
|
1473
|
+
pos: 0,
|
|
1474
|
+
// We can pass any position as it will remove the entire decoration set
|
|
1475
|
+
type: "highlightDecoration",
|
|
1476
|
+
remove: true
|
|
1477
|
+
});
|
|
1478
|
+
dispatch(tr);
|
|
1479
|
+
return true;
|
|
1407
1480
|
}
|
|
1408
|
-
|
|
1409
|
-
// decorations(editorState) {
|
|
1410
|
-
// return pluginKey.getState(editorState);
|
|
1411
|
-
// },
|
|
1412
|
-
// handleKeyDown(view, event) {
|
|
1413
|
-
// const pluginState = pluginKey.getState(view.state);
|
|
1414
|
-
// if (!pluginState) return false;
|
|
1415
|
-
//
|
|
1416
|
-
// if (event.key === "Tab") {
|
|
1417
|
-
// const selection = view.state.selection;
|
|
1418
|
-
// const cursorPos = selection.$head.pos;
|
|
1419
|
-
//
|
|
1420
|
-
// // Find the suggestion decoration
|
|
1421
|
-
// const decoration = pluginState.find(cursorPos)?.[0];
|
|
1422
|
-
// console.log(decoration);
|
|
1423
|
-
// // @ts-ignore
|
|
1424
|
-
// if (decoration && decoration.type?.spec?.suggestionText) {
|
|
1425
|
-
// // @ts-ignore
|
|
1426
|
-
// const suggestionText = decoration.type.spec.suggestionText;
|
|
1427
|
-
// const tr = view.state.tr;
|
|
1428
|
-
// tr.insertText(suggestionText, cursorPos);
|
|
1429
|
-
//
|
|
1430
|
-
// // Dispatch the transaction
|
|
1431
|
-
// view.dispatch(tr.setMeta("addToHistory", true));
|
|
1432
|
-
//
|
|
1433
|
-
// // Clear decorations after applying suggestion
|
|
1434
|
-
// const clearDecoTr = view.state.tr;
|
|
1435
|
-
// clearDecoTr.setMeta(pluginKey, { decorations: DecorationSet.empty });
|
|
1436
|
-
// view.dispatch(clearDecoTr);
|
|
1437
|
-
//
|
|
1438
|
-
// // Prevent default behavior of the keypress
|
|
1439
|
-
// event.preventDefault();
|
|
1440
|
-
// return true;
|
|
1441
|
-
// }
|
|
1442
|
-
// }
|
|
1443
|
-
// return false;
|
|
1444
|
-
// }
|
|
1445
|
-
// }
|
|
1446
|
-
});
|
|
1447
|
-
return [plugin];
|
|
1481
|
+
};
|
|
1448
1482
|
}
|
|
1449
1483
|
});
|
|
1450
1484
|
const CustomDocument = Document.extend({
|
|
@@ -1477,40 +1511,21 @@ const FireCMSEditor = ({
|
|
|
1477
1511
|
const deferredHighlight = useDeferredValue(highlight);
|
|
1478
1512
|
useEffect(() => {
|
|
1479
1513
|
if (version === void 0) return;
|
|
1480
|
-
if (version >
|
|
1514
|
+
if (version > -1 && editorRef.current) {
|
|
1481
1515
|
editorRef.current?.commands.setContent(content ?? "");
|
|
1482
1516
|
}
|
|
1483
1517
|
}, [version]);
|
|
1484
|
-
const currentHighlight = useRef(deferredHighlight);
|
|
1485
1518
|
useEffect(() => {
|
|
1486
1519
|
if (version === void 0) return;
|
|
1487
1520
|
if (editorRef.current && version > 0) {
|
|
1488
|
-
const {
|
|
1489
|
-
from: selectionFrom,
|
|
1490
|
-
to: selectionTo
|
|
1491
|
-
} = editorRef.current.state.selection;
|
|
1492
1521
|
const chain = editorRef.current.chain();
|
|
1493
|
-
const currentContent = editorRef.current.storage.markdown.getMarkdown();
|
|
1494
|
-
if (currentContent !== content) {
|
|
1495
|
-
chain.setContent(content ?? "");
|
|
1496
|
-
}
|
|
1497
1522
|
if (deferredHighlight) {
|
|
1498
|
-
|
|
1499
|
-
chain.focus().setTextSelection({
|
|
1500
|
-
from: deferredHighlight?.from,
|
|
1501
|
-
to: deferredHighlight?.to
|
|
1502
|
-
}).toggleHighlight({ color: "#64748B68" });
|
|
1503
|
-
}
|
|
1523
|
+
chain.focus().toggleAutocompleteHighlight(deferredHighlight).run();
|
|
1504
1524
|
} else {
|
|
1505
|
-
chain.focus().
|
|
1525
|
+
chain.focus().removeAutocompleteHighlight().run();
|
|
1506
1526
|
}
|
|
1507
|
-
currentHighlight.current = deferredHighlight;
|
|
1508
|
-
chain.focus().setTextSelection({
|
|
1509
|
-
from: selectionFrom,
|
|
1510
|
-
to: selectionTo
|
|
1511
|
-
}).run();
|
|
1512
1527
|
}
|
|
1513
|
-
}, [
|
|
1528
|
+
}, [deferredHighlight?.from, deferredHighlight?.to]);
|
|
1514
1529
|
const onEditorUpdate = (editor) => {
|
|
1515
1530
|
editorRef.current = editor;
|
|
1516
1531
|
if (onMarkdownContentChange) {
|
|
@@ -1527,19 +1542,19 @@ const FireCMSEditor = ({
|
|
|
1527
1542
|
};
|
|
1528
1543
|
const proseClass = proseClasses[textSize];
|
|
1529
1544
|
const extensions = useMemo(() => [
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1545
|
+
starterKit,
|
|
1546
|
+
CustomDocument,
|
|
1547
|
+
HighlightDecorationExtension(highlight),
|
|
1548
|
+
TextLoadingDecorationExtension,
|
|
1549
|
+
Underline,
|
|
1533
1550
|
TextStyle,
|
|
1534
1551
|
Color,
|
|
1535
1552
|
BulletList,
|
|
1536
|
-
CustomDocument,
|
|
1537
1553
|
Highlight.configure({
|
|
1538
1554
|
multicolor: true
|
|
1539
1555
|
}),
|
|
1540
1556
|
CustomKeymap,
|
|
1541
1557
|
DragAndDrop,
|
|
1542
|
-
starterKit,
|
|
1543
1558
|
placeholder,
|
|
1544
1559
|
tiptapLink,
|
|
1545
1560
|
imageExtension,
|
|
@@ -1547,9 +1562,6 @@ const FireCMSEditor = ({
|
|
|
1547
1562
|
taskItem,
|
|
1548
1563
|
markdownExtension,
|
|
1549
1564
|
horizontalRule,
|
|
1550
|
-
AiContentExtension.configure({
|
|
1551
|
-
aiController
|
|
1552
|
-
}),
|
|
1553
1565
|
SlashCommand.configure({
|
|
1554
1566
|
HTMLAttributes: {
|
|
1555
1567
|
class: "mention"
|