@kopexa/tiptap 17.0.17 → 17.2.0
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/chunk-2U5CQUZH.mjs +91 -0
- package/dist/chunk-2V6VOAPI.mjs +139 -0
- package/dist/chunk-32SUXCAQ.mjs +115 -0
- package/dist/chunk-3VRQUYYW.mjs +169 -0
- package/dist/chunk-4CDZ547I.mjs +185 -0
- package/dist/chunk-5GFFTVMZ.mjs +62 -0
- package/dist/{chunk-FJAGUXEO.mjs → chunk-7SRL3P4B.mjs} +32 -19
- package/dist/{chunk-WHJ4B43N.mjs → chunk-7VGROP26.mjs} +69 -25
- package/dist/chunk-7VW67NVL.mjs +80 -0
- package/dist/chunk-BXHPO3T7.mjs +152 -0
- package/dist/{chunk-QF3YHPWM.mjs → chunk-E5NW3MJZ.mjs} +4 -4
- package/dist/chunk-FRJX2F4T.mjs +55 -0
- package/dist/chunk-IFXRPGIJ.mjs +98 -0
- package/dist/chunk-JCV5SEKN.mjs +65 -0
- package/dist/chunk-LMCQMSW2.mjs +345 -0
- package/dist/chunk-N4CT5RNC.mjs +123 -0
- package/dist/{chunk-B2DHYFSH.mjs → chunk-NEHW62L7.mjs} +56 -3
- package/dist/chunk-NSYSECKW.mjs +53 -0
- package/dist/{chunk-3IKIIRV3.mjs → chunk-QAE2D4KV.mjs} +39 -16
- package/dist/chunk-TAM3VMJT.mjs +80 -0
- package/dist/chunk-UU6JK5HX.mjs +257 -0
- package/dist/chunk-UVHVCION.mjs +168 -0
- package/dist/chunk-VF3G2URZ.mjs +83 -0
- package/dist/chunk-VRQ6OSAZ.mjs +76 -0
- package/dist/chunk-WAAH3NLG.mjs +77 -0
- package/dist/chunk-XNDXYI2N.mjs +158 -0
- package/dist/context/editor-file-context.d.mts +70 -0
- package/dist/context/editor-file-context.d.ts +70 -0
- package/dist/context/editor-file-context.js +96 -0
- package/dist/context/editor-file-context.mjs +12 -0
- package/dist/extensions/callout/callout-settings.d.mts +13 -0
- package/dist/extensions/callout/callout-settings.d.ts +13 -0
- package/dist/extensions/callout/callout-settings.js +206 -0
- package/dist/extensions/callout/callout-settings.mjs +9 -0
- package/dist/extensions/callout/callout-view.d.mts +12 -0
- package/dist/extensions/callout/callout-view.d.ts +12 -0
- package/dist/extensions/callout/callout-view.js +273 -0
- package/dist/extensions/callout/callout-view.mjs +12 -0
- package/dist/extensions/callout/index.d.mts +44 -0
- package/dist/extensions/callout/index.d.ts +44 -0
- package/dist/extensions/callout/index.js +380 -0
- package/dist/extensions/callout/index.mjs +13 -0
- package/dist/extensions/callout/messages.d.mts +59 -0
- package/dist/extensions/callout/messages.d.ts +59 -0
- package/dist/extensions/callout/messages.js +88 -0
- package/dist/extensions/callout/messages.mjs +7 -0
- package/dist/extensions/image/image-view.d.mts +15 -0
- package/dist/extensions/image/image-view.d.ts +15 -0
- package/dist/extensions/image/image-view.js +423 -0
- package/dist/extensions/image/image-view.mjs +12 -0
- package/dist/extensions/image/index.d.mts +66 -0
- package/dist/extensions/image/index.d.ts +66 -0
- package/dist/extensions/image/index.js +495 -0
- package/dist/extensions/image/index.mjs +16 -0
- package/dist/extensions/image/messages.d.mts +56 -0
- package/dist/extensions/image/messages.d.ts +56 -0
- package/dist/extensions/image/messages.js +85 -0
- package/dist/extensions/image/messages.mjs +7 -0
- package/dist/extensions/math/index.d.mts +38 -0
- package/dist/extensions/math/index.d.ts +38 -0
- package/dist/extensions/math/index.js +544 -0
- package/dist/extensions/math/index.mjs +17 -0
- package/dist/extensions/math/inline-math-view.d.mts +12 -0
- package/dist/extensions/math/inline-math-view.d.ts +12 -0
- package/dist/extensions/math/inline-math-view.js +232 -0
- package/dist/extensions/math/inline-math-view.mjs +11 -0
- package/dist/extensions/math/inline-math.d.mts +32 -0
- package/dist/extensions/math/inline-math.d.ts +32 -0
- package/dist/extensions/math/inline-math.js +304 -0
- package/dist/extensions/math/inline-math.mjs +12 -0
- package/dist/extensions/math/math-block-view.d.mts +11 -0
- package/dist/extensions/math/math-block-view.d.ts +11 -0
- package/dist/extensions/math/math-block-view.js +248 -0
- package/dist/extensions/math/math-block-view.mjs +11 -0
- package/dist/extensions/math/messages.d.mts +49 -0
- package/dist/extensions/math/messages.d.ts +49 -0
- package/dist/extensions/math/messages.js +78 -0
- package/dist/extensions/math/messages.mjs +7 -0
- package/dist/extensions/toc/index.d.mts +53 -0
- package/dist/extensions/toc/index.d.ts +53 -0
- package/dist/extensions/toc/index.js +501 -0
- package/dist/extensions/toc/index.mjs +13 -0
- package/dist/extensions/toc/messages.d.mts +74 -0
- package/dist/extensions/toc/messages.d.ts +74 -0
- package/dist/extensions/toc/messages.js +103 -0
- package/dist/extensions/toc/messages.mjs +7 -0
- package/dist/extensions/toc/toc-settings.d.mts +13 -0
- package/dist/extensions/toc/toc-settings.d.ts +13 -0
- package/dist/extensions/toc/toc-settings.js +283 -0
- package/dist/extensions/toc/toc-settings.mjs +9 -0
- package/dist/extensions/toc/toc-view.d.mts +12 -0
- package/dist/extensions/toc/toc-view.d.ts +12 -0
- package/dist/extensions/toc/toc-view.js +411 -0
- package/dist/extensions/toc/toc-view.mjs +12 -0
- package/dist/hooks/use-create-editor.d.mts +20 -2
- package/dist/hooks/use-create-editor.d.ts +20 -2
- package/dist/hooks/use-create-editor.js +2020 -20
- package/dist/hooks/use-create-editor.mjs +20 -3
- package/dist/index.d.mts +11 -2
- package/dist/index.d.ts +11 -2
- package/dist/index.js +3948 -1563
- package/dist/index.mjs +64 -23
- package/dist/presets/basic/editor-header.d.mts +3 -2
- package/dist/presets/basic/editor-header.d.ts +3 -2
- package/dist/presets/basic/editor-header.js +91 -25
- package/dist/presets/basic/editor-header.mjs +14 -14
- package/dist/presets/basic/index.d.mts +3 -1
- package/dist/presets/basic/index.d.ts +3 -1
- package/dist/presets/basic/index.js +3833 -1517
- package/dist/presets/basic/index.mjs +41 -22
- package/dist/ui/bubble-menu/index.d.mts +13 -0
- package/dist/ui/bubble-menu/index.d.ts +13 -0
- package/dist/ui/bubble-menu/index.js +671 -0
- package/dist/ui/bubble-menu/index.mjs +16 -0
- package/dist/ui/color-highlight-popover/color-highlight-popover.mjs +2 -2
- package/dist/ui/color-highlight-popover/index.mjs +2 -2
- package/dist/ui/copy-anchor-link-button/use-scroll-to-hash.mjs +2 -2
- package/dist/ui/link-bubble/index.d.mts +13 -0
- package/dist/ui/link-bubble/index.d.ts +13 -0
- package/dist/ui/link-bubble/index.js +182 -0
- package/dist/ui/link-bubble/index.mjs +10 -0
- package/dist/ui/link-popover/index.js +66 -23
- package/dist/ui/link-popover/index.mjs +3 -3
- package/dist/ui/link-popover/link-popover.d.mts +7 -2
- package/dist/ui/link-popover/link-popover.d.ts +7 -2
- package/dist/ui/link-popover/link-popover.js +66 -23
- package/dist/ui/link-popover/link-popover.mjs +3 -3
- package/dist/ui/link-popover/use-link-popover.mjs +2 -2
- package/dist/ui/slash-dropdown-menu/index.js +53 -3
- package/dist/ui/slash-dropdown-menu/index.mjs +6 -6
- package/dist/ui/slash-dropdown-menu/slash-dropdown-menu.js +53 -3
- package/dist/ui/slash-dropdown-menu/slash-dropdown-menu.mjs +4 -4
- package/dist/ui/slash-dropdown-menu/use-slash-dropdown-menu.d.mts +28 -0
- package/dist/ui/slash-dropdown-menu/use-slash-dropdown-menu.d.ts +28 -0
- package/dist/ui/slash-dropdown-menu/use-slash-dropdown-menu.js +53 -3
- package/dist/ui/slash-dropdown-menu/use-slash-dropdown-menu.mjs +1 -1
- package/dist/ui/suggestion-menu/index.mjs +2 -2
- package/dist/ui/suggestion-menu/suggestion-menu.mjs +2 -2
- package/dist/utils/safe-parse.js +113 -4
- package/dist/utils/safe-parse.mjs +1 -1
- package/package.json +48 -39
- package/dist/chunk-7LHOYNVF.mjs +0 -60
- package/dist/chunk-LXOLVGLW.mjs +0 -131
- package/dist/{chunk-XL5FS7LN.mjs → chunk-C5RQWJKE.mjs} +3 -3
- package/dist/{chunk-JNL4KY45.mjs → chunk-DZLGLP7R.mjs} +3 -3
- package/dist/{chunk-LHXRE26G.mjs → chunk-VTKJPVNM.mjs} +3 -3
- package/dist/{chunk-XLSZK3WJ.mjs → chunk-ZYFCSR3E.mjs} +3 -3
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
MathBlockView
|
|
4
|
+
} from "./chunk-UVHVCION.mjs";
|
|
5
|
+
|
|
6
|
+
// src/extensions/math/index.ts
|
|
7
|
+
import { InputRule, mergeAttributes, Node } from "@tiptap/core";
|
|
8
|
+
import { ReactNodeViewRenderer } from "@tiptap/react";
|
|
9
|
+
var MathBlock = Node.create({
|
|
10
|
+
name: "mathBlock",
|
|
11
|
+
group: "block",
|
|
12
|
+
atom: true,
|
|
13
|
+
draggable: true,
|
|
14
|
+
addOptions() {
|
|
15
|
+
return {
|
|
16
|
+
HTMLAttributes: {}
|
|
17
|
+
};
|
|
18
|
+
},
|
|
19
|
+
addAttributes() {
|
|
20
|
+
return {
|
|
21
|
+
latex: {
|
|
22
|
+
default: "",
|
|
23
|
+
parseHTML: (element) => element.getAttribute("data-latex") || "",
|
|
24
|
+
renderHTML: (attributes) => ({
|
|
25
|
+
"data-latex": attributes.latex
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
parseHTML() {
|
|
31
|
+
return [
|
|
32
|
+
{
|
|
33
|
+
tag: 'div[data-type="math-block"]'
|
|
34
|
+
}
|
|
35
|
+
];
|
|
36
|
+
},
|
|
37
|
+
renderHTML({ HTMLAttributes }) {
|
|
38
|
+
return [
|
|
39
|
+
"div",
|
|
40
|
+
mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {
|
|
41
|
+
"data-type": "math-block"
|
|
42
|
+
})
|
|
43
|
+
];
|
|
44
|
+
},
|
|
45
|
+
addNodeView() {
|
|
46
|
+
return ReactNodeViewRenderer(MathBlockView);
|
|
47
|
+
},
|
|
48
|
+
addCommands() {
|
|
49
|
+
return {
|
|
50
|
+
insertMathBlock: (latex = "") => ({ commands }) => {
|
|
51
|
+
return commands.insertContent({
|
|
52
|
+
type: this.name,
|
|
53
|
+
attrs: { latex }
|
|
54
|
+
});
|
|
55
|
+
},
|
|
56
|
+
updateMathBlock: (latex) => ({ tr, state, dispatch }) => {
|
|
57
|
+
const { selection } = state;
|
|
58
|
+
const node = state.doc.nodeAt(selection.from);
|
|
59
|
+
if ((node == null ? void 0 : node.type.name) !== this.name) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
if (dispatch) {
|
|
63
|
+
tr.setNodeMarkup(selection.from, void 0, {
|
|
64
|
+
...node.attrs,
|
|
65
|
+
latex
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
},
|
|
72
|
+
addInputRules() {
|
|
73
|
+
return [
|
|
74
|
+
// Block math with $$...$$
|
|
75
|
+
new InputRule({
|
|
76
|
+
find: /^\$\$(.+)\$\$$/,
|
|
77
|
+
handler: ({ state, range, match }) => {
|
|
78
|
+
const latex = match[1];
|
|
79
|
+
const { tr } = state;
|
|
80
|
+
tr.replaceWith(range.from, range.to, this.type.create({ latex }));
|
|
81
|
+
}
|
|
82
|
+
})
|
|
83
|
+
];
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
var math_default = MathBlock;
|
|
87
|
+
|
|
88
|
+
export {
|
|
89
|
+
MathBlock,
|
|
90
|
+
math_default
|
|
91
|
+
};
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
TocSettings
|
|
4
|
+
} from "./chunk-4CDZ547I.mjs";
|
|
5
|
+
import {
|
|
6
|
+
messages
|
|
7
|
+
} from "./chunk-TAM3VMJT.mjs";
|
|
8
|
+
|
|
9
|
+
// src/extensions/toc/toc-view.tsx
|
|
10
|
+
import { ListIcon } from "@kopexa/icons";
|
|
11
|
+
import { toc } from "@kopexa/theme";
|
|
12
|
+
import { NodeViewWrapper } from "@tiptap/react";
|
|
13
|
+
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
14
|
+
import { useIntl } from "react-intl";
|
|
15
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
16
|
+
function generateHeadingNumbers(headings, minLevel) {
|
|
17
|
+
const counters = [0, 0, 0, 0, 0, 0];
|
|
18
|
+
return headings.map((heading) => {
|
|
19
|
+
const levelIndex = heading.level - 1;
|
|
20
|
+
counters[levelIndex]++;
|
|
21
|
+
for (let i = levelIndex + 1; i < 6; i++) {
|
|
22
|
+
counters[i] = 0;
|
|
23
|
+
}
|
|
24
|
+
const numberParts = [];
|
|
25
|
+
for (let i = minLevel - 1; i <= levelIndex; i++) {
|
|
26
|
+
if (counters[i] > 0) {
|
|
27
|
+
numberParts.push(counters[i]);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
...heading,
|
|
32
|
+
number: numberParts.join(".")
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function TocNodeView({ editor, node, getPos }) {
|
|
37
|
+
const [headings, setHeadings] = useState([]);
|
|
38
|
+
const intl = useIntl();
|
|
39
|
+
const attrs = node.attrs;
|
|
40
|
+
const {
|
|
41
|
+
minLevel = 1,
|
|
42
|
+
maxLevel = 6,
|
|
43
|
+
numbered = false,
|
|
44
|
+
style = "default"
|
|
45
|
+
} = attrs;
|
|
46
|
+
const styles = useMemo(() => toc({ style }), [style]);
|
|
47
|
+
const updateHeadings = useCallback(() => {
|
|
48
|
+
const items = [];
|
|
49
|
+
const { doc } = editor.state;
|
|
50
|
+
doc.descendants((docNode, pos) => {
|
|
51
|
+
if (docNode.type.name === "heading") {
|
|
52
|
+
const level = docNode.attrs.level;
|
|
53
|
+
if (level >= minLevel && level <= maxLevel) {
|
|
54
|
+
const id = docNode.attrs.id || `heading-${pos}`;
|
|
55
|
+
items.push({
|
|
56
|
+
id,
|
|
57
|
+
level,
|
|
58
|
+
text: docNode.textContent,
|
|
59
|
+
pos
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
const numberedHeadings = generateHeadingNumbers(items, minLevel);
|
|
65
|
+
setHeadings(numberedHeadings);
|
|
66
|
+
}, [editor, minLevel, maxLevel]);
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
updateHeadings();
|
|
69
|
+
editor.on("update", updateHeadings);
|
|
70
|
+
return () => {
|
|
71
|
+
editor.off("update", updateHeadings);
|
|
72
|
+
};
|
|
73
|
+
}, [editor, updateHeadings]);
|
|
74
|
+
const handleClick = useCallback(
|
|
75
|
+
(pos, id) => {
|
|
76
|
+
var _a;
|
|
77
|
+
editor.chain().focus().setTextSelection(pos).run();
|
|
78
|
+
let element = document.querySelector(`[data-id="${id}"]`);
|
|
79
|
+
if (!element) {
|
|
80
|
+
const { view } = editor;
|
|
81
|
+
const coords = view.coordsAtPos(pos);
|
|
82
|
+
const domNode = document.elementFromPoint(coords.left, coords.top);
|
|
83
|
+
element = (_a = domNode == null ? void 0 : domNode.closest("h1, h2, h3, h4, h5, h6")) != null ? _a : null;
|
|
84
|
+
}
|
|
85
|
+
if (element) {
|
|
86
|
+
element.scrollIntoView({ behavior: "smooth", block: "start" });
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
[editor]
|
|
90
|
+
);
|
|
91
|
+
const isEmpty = headings.length === 0;
|
|
92
|
+
const getIndent = (level) => {
|
|
93
|
+
return (level - minLevel) * 16;
|
|
94
|
+
};
|
|
95
|
+
return /* @__PURE__ */ jsxs(NodeViewWrapper, { className: styles.root(), "data-type": "toc", children: [
|
|
96
|
+
/* @__PURE__ */ jsxs("div", { className: styles.header(), children: [
|
|
97
|
+
/* @__PURE__ */ jsxs("div", { className: styles.headerContent(), children: [
|
|
98
|
+
/* @__PURE__ */ jsx(ListIcon, { className: styles.headerIcon() }),
|
|
99
|
+
/* @__PURE__ */ jsx("span", { className: styles.headerTitle(), children: intl.formatMessage(messages.title) })
|
|
100
|
+
] }),
|
|
101
|
+
/* @__PURE__ */ jsx("div", { className: styles.headerActions(), children: /* @__PURE__ */ jsx(
|
|
102
|
+
TocSettings,
|
|
103
|
+
{
|
|
104
|
+
editor,
|
|
105
|
+
attrs,
|
|
106
|
+
getPos
|
|
107
|
+
}
|
|
108
|
+
) })
|
|
109
|
+
] }),
|
|
110
|
+
isEmpty ? /* @__PURE__ */ jsx("p", { className: styles.emptyState(), children: intl.formatMessage(messages.empty_state) }) : /* @__PURE__ */ jsx("nav", { className: styles.nav(), children: /* @__PURE__ */ jsx("ul", { className: styles.list(), children: headings.map((heading) => /* @__PURE__ */ jsxs(
|
|
111
|
+
"li",
|
|
112
|
+
{
|
|
113
|
+
className: styles.item(),
|
|
114
|
+
style: {
|
|
115
|
+
paddingLeft: `${getIndent(heading.level)}px`
|
|
116
|
+
},
|
|
117
|
+
children: [
|
|
118
|
+
numbered && heading.number && /* @__PURE__ */ jsx("span", { className: styles.itemNumber(), children: heading.number }),
|
|
119
|
+
/* @__PURE__ */ jsx(
|
|
120
|
+
"button",
|
|
121
|
+
{
|
|
122
|
+
type: "button",
|
|
123
|
+
onClick: () => handleClick(heading.pos, heading.id),
|
|
124
|
+
className: styles.itemButton(),
|
|
125
|
+
children: heading.text || intl.formatMessage(messages.empty_heading)
|
|
126
|
+
}
|
|
127
|
+
)
|
|
128
|
+
]
|
|
129
|
+
},
|
|
130
|
+
heading.id
|
|
131
|
+
)) }) })
|
|
132
|
+
] });
|
|
133
|
+
}
|
|
134
|
+
var toc_view_default = TocNodeView;
|
|
135
|
+
|
|
136
|
+
export {
|
|
137
|
+
TocNodeView,
|
|
138
|
+
toc_view_default
|
|
139
|
+
};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
CalloutNodeView
|
|
4
|
+
} from "./chunk-VF3G2URZ.mjs";
|
|
5
|
+
|
|
6
|
+
// src/extensions/callout/index.ts
|
|
7
|
+
import { mergeAttributes, Node } from "@tiptap/core";
|
|
8
|
+
import { ReactNodeViewRenderer } from "@tiptap/react";
|
|
9
|
+
var CalloutNode = Node.create({
|
|
10
|
+
name: "calloutNode",
|
|
11
|
+
group: "block",
|
|
12
|
+
content: "block+",
|
|
13
|
+
defining: true,
|
|
14
|
+
draggable: true,
|
|
15
|
+
addOptions() {
|
|
16
|
+
return {
|
|
17
|
+
HTMLAttributes: {}
|
|
18
|
+
};
|
|
19
|
+
},
|
|
20
|
+
addAttributes() {
|
|
21
|
+
return {
|
|
22
|
+
variant: {
|
|
23
|
+
default: "info",
|
|
24
|
+
parseHTML: (element) => element.getAttribute("data-variant") || "info",
|
|
25
|
+
renderHTML: (attributes) => ({
|
|
26
|
+
"data-variant": attributes.variant
|
|
27
|
+
})
|
|
28
|
+
},
|
|
29
|
+
title: {
|
|
30
|
+
default: null,
|
|
31
|
+
parseHTML: (element) => element.getAttribute("data-title") || null,
|
|
32
|
+
renderHTML: (attributes) => {
|
|
33
|
+
if (!attributes.title) return {};
|
|
34
|
+
return {
|
|
35
|
+
"data-title": attributes.title
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
},
|
|
41
|
+
parseHTML() {
|
|
42
|
+
return [
|
|
43
|
+
{
|
|
44
|
+
tag: 'div[data-type="callout"]'
|
|
45
|
+
}
|
|
46
|
+
];
|
|
47
|
+
},
|
|
48
|
+
renderHTML({ HTMLAttributes }) {
|
|
49
|
+
return [
|
|
50
|
+
"div",
|
|
51
|
+
mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {
|
|
52
|
+
"data-type": "callout"
|
|
53
|
+
}),
|
|
54
|
+
0
|
|
55
|
+
];
|
|
56
|
+
},
|
|
57
|
+
addNodeView() {
|
|
58
|
+
return ReactNodeViewRenderer(CalloutNodeView);
|
|
59
|
+
},
|
|
60
|
+
addCommands() {
|
|
61
|
+
return {
|
|
62
|
+
insertCallout: (variant = "info") => ({ commands }) => {
|
|
63
|
+
return commands.insertContent({
|
|
64
|
+
type: this.name,
|
|
65
|
+
attrs: { variant },
|
|
66
|
+
content: [
|
|
67
|
+
{
|
|
68
|
+
type: "paragraph"
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
});
|
|
72
|
+
},
|
|
73
|
+
updateCalloutSettings: (attrs) => ({ tr, state, dispatch }) => {
|
|
74
|
+
const { selection } = state;
|
|
75
|
+
const node = state.doc.nodeAt(selection.from);
|
|
76
|
+
if ((node == null ? void 0 : node.type.name) !== this.name) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
if (dispatch) {
|
|
80
|
+
tr.setNodeMarkup(selection.from, void 0, {
|
|
81
|
+
...node.attrs,
|
|
82
|
+
...attrs
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
},
|
|
89
|
+
addKeyboardShortcuts() {
|
|
90
|
+
return {
|
|
91
|
+
// Allow backspace at start to lift content out of callout
|
|
92
|
+
Backspace: ({ editor }) => {
|
|
93
|
+
var _a;
|
|
94
|
+
const { state } = editor;
|
|
95
|
+
const { selection } = state;
|
|
96
|
+
const { $from } = selection;
|
|
97
|
+
if ($from.parent.type.name === "paragraph" && $from.parentOffset === 0) {
|
|
98
|
+
const calloutNode = $from.node(-1);
|
|
99
|
+
if ((calloutNode == null ? void 0 : calloutNode.type.name) === this.name) {
|
|
100
|
+
if (calloutNode.childCount === 1 && ((_a = calloutNode.firstChild) == null ? void 0 : _a.textContent) === "") {
|
|
101
|
+
return editor.commands.deleteNode(this.name);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
var callout_default = CalloutNode;
|
|
111
|
+
|
|
112
|
+
export {
|
|
113
|
+
CalloutNode,
|
|
114
|
+
callout_default
|
|
115
|
+
};
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/utils/safe-parse.ts
|
|
4
|
+
import DOMPurify from "dompurify";
|
|
5
|
+
import MarkdownIt from "markdown-it";
|
|
6
|
+
var md = new MarkdownIt({
|
|
7
|
+
html: false,
|
|
8
|
+
// keep it safe
|
|
9
|
+
linkify: true,
|
|
10
|
+
typographer: true
|
|
11
|
+
});
|
|
12
|
+
var DOMPURIFY_CONFIG = {
|
|
13
|
+
// Allowed tags (safe subset for rich text)
|
|
14
|
+
ALLOWED_TAGS: [
|
|
15
|
+
"p",
|
|
16
|
+
"br",
|
|
17
|
+
"span",
|
|
18
|
+
"div",
|
|
19
|
+
"h1",
|
|
20
|
+
"h2",
|
|
21
|
+
"h3",
|
|
22
|
+
"h4",
|
|
23
|
+
"h5",
|
|
24
|
+
"h6",
|
|
25
|
+
"strong",
|
|
26
|
+
"b",
|
|
27
|
+
"em",
|
|
28
|
+
"i",
|
|
29
|
+
"u",
|
|
30
|
+
"s",
|
|
31
|
+
"strike",
|
|
32
|
+
"del",
|
|
33
|
+
"ul",
|
|
34
|
+
"ol",
|
|
35
|
+
"li",
|
|
36
|
+
"blockquote",
|
|
37
|
+
"pre",
|
|
38
|
+
"code",
|
|
39
|
+
"a",
|
|
40
|
+
"img",
|
|
41
|
+
"table",
|
|
42
|
+
"thead",
|
|
43
|
+
"tbody",
|
|
44
|
+
"tr",
|
|
45
|
+
"th",
|
|
46
|
+
"td",
|
|
47
|
+
"hr",
|
|
48
|
+
"sub",
|
|
49
|
+
"sup",
|
|
50
|
+
"mark"
|
|
51
|
+
],
|
|
52
|
+
// Allowed attributes
|
|
53
|
+
ALLOWED_ATTR: [
|
|
54
|
+
"href",
|
|
55
|
+
"src",
|
|
56
|
+
"alt",
|
|
57
|
+
"title",
|
|
58
|
+
"class",
|
|
59
|
+
"id",
|
|
60
|
+
"target",
|
|
61
|
+
"rel",
|
|
62
|
+
"colspan",
|
|
63
|
+
"rowspan",
|
|
64
|
+
"width",
|
|
65
|
+
"height"
|
|
66
|
+
],
|
|
67
|
+
// Allow all data-* attributes (needed for Tiptap extensions like controlBlock)
|
|
68
|
+
ALLOW_DATA_ATTR: true,
|
|
69
|
+
// Forbid all event handlers and javascript: URLs
|
|
70
|
+
FORBID_ATTR: [
|
|
71
|
+
"onerror",
|
|
72
|
+
"onload",
|
|
73
|
+
"onclick",
|
|
74
|
+
"onmouseover",
|
|
75
|
+
"onmouseout",
|
|
76
|
+
"onfocus",
|
|
77
|
+
"onblur",
|
|
78
|
+
"onchange",
|
|
79
|
+
"onsubmit",
|
|
80
|
+
"onkeydown",
|
|
81
|
+
"onkeyup",
|
|
82
|
+
"onkeypress",
|
|
83
|
+
"ondblclick",
|
|
84
|
+
"oncontextmenu"
|
|
85
|
+
],
|
|
86
|
+
// Forbid dangerous tags completely
|
|
87
|
+
FORBID_TAGS: [
|
|
88
|
+
"script",
|
|
89
|
+
"style",
|
|
90
|
+
"iframe",
|
|
91
|
+
"object",
|
|
92
|
+
"embed",
|
|
93
|
+
"form",
|
|
94
|
+
"input",
|
|
95
|
+
"button",
|
|
96
|
+
"textarea",
|
|
97
|
+
"select"
|
|
98
|
+
],
|
|
99
|
+
// Block javascript: and data: URLs
|
|
100
|
+
ALLOWED_URI_REGEXP: /^(?:(?:https?|mailto|tel):|[^a-z]|[a-z+.-]+(?:[^a-z+.\-:]|$))/i
|
|
101
|
+
};
|
|
102
|
+
function sanitizeHtml(html) {
|
|
103
|
+
if (typeof window === "undefined") {
|
|
104
|
+
return html;
|
|
105
|
+
}
|
|
106
|
+
return DOMPurify.sanitize(html, DOMPURIFY_CONFIG);
|
|
107
|
+
}
|
|
108
|
+
function toPlainTextDoc(s) {
|
|
109
|
+
return {
|
|
110
|
+
type: "doc",
|
|
111
|
+
content: [
|
|
112
|
+
{
|
|
113
|
+
type: "paragraph",
|
|
114
|
+
content: s ? [{ type: "text", text: s }] : []
|
|
115
|
+
}
|
|
116
|
+
]
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function safeParseContent(content) {
|
|
120
|
+
if (!content || content === "") return { type: "doc", content: [] };
|
|
121
|
+
if (typeof content === "object") {
|
|
122
|
+
return content;
|
|
123
|
+
}
|
|
124
|
+
if (typeof content === "string") {
|
|
125
|
+
const trimmed = content.trim();
|
|
126
|
+
if (looksLikeJsonString(trimmed)) {
|
|
127
|
+
try {
|
|
128
|
+
const parsed = JSON.parse(trimmed);
|
|
129
|
+
if (isTiptapDoc(parsed)) return parsed;
|
|
130
|
+
} catch {
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (looksLikeHtml(trimmed)) {
|
|
134
|
+
return sanitizeHtml(trimmed);
|
|
135
|
+
}
|
|
136
|
+
const raw = normalizeNewlines(trimmed);
|
|
137
|
+
try {
|
|
138
|
+
const html = md.render(raw);
|
|
139
|
+
return sanitizeHtml(html);
|
|
140
|
+
} catch {
|
|
141
|
+
}
|
|
142
|
+
return toPlainTextDoc(raw);
|
|
143
|
+
}
|
|
144
|
+
return { type: "doc", content: [] };
|
|
145
|
+
}
|
|
146
|
+
function looksLikeJsonString(s) {
|
|
147
|
+
const c = s.trim().charCodeAt(0);
|
|
148
|
+
return c === 123 || c === 91;
|
|
149
|
+
}
|
|
150
|
+
function looksLikeHtml(s) {
|
|
151
|
+
const trimmed = s.trim();
|
|
152
|
+
if (trimmed.charCodeAt(0) !== 60) return false;
|
|
153
|
+
const secondChar = trimmed.charCodeAt(1);
|
|
154
|
+
return secondChar >= 65 && secondChar <= 90 || // A-Z
|
|
155
|
+
secondChar >= 97 && secondChar <= 122 || // a-z
|
|
156
|
+
secondChar === 33;
|
|
157
|
+
}
|
|
158
|
+
function isTiptapDoc(value) {
|
|
159
|
+
return Boolean(
|
|
160
|
+
value && typeof value === "object" && value.type === "doc" && Array.isArray(value.content)
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
function normalizeNewlines(raw) {
|
|
164
|
+
return raw.replace(/\r\n?/g, "\n").replace(/\\n/g, "\n");
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export {
|
|
168
|
+
safeParseContent
|
|
169
|
+
};
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
messages
|
|
4
|
+
} from "./chunk-TAM3VMJT.mjs";
|
|
5
|
+
|
|
6
|
+
// src/extensions/toc/toc-settings.tsx
|
|
7
|
+
import { Button, IconButton } from "@kopexa/button";
|
|
8
|
+
import { Dialog } from "@kopexa/dialog";
|
|
9
|
+
import { SettingsIcon } from "@kopexa/icons";
|
|
10
|
+
import { Label } from "@kopexa/label";
|
|
11
|
+
import { Select } from "@kopexa/select";
|
|
12
|
+
import { Switch } from "@kopexa/switch";
|
|
13
|
+
import { useCallback, useEffect, useState } from "react";
|
|
14
|
+
import { useIntl } from "react-intl";
|
|
15
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
16
|
+
var HEADING_LEVELS = [
|
|
17
|
+
{ value: "1", label: "H1" },
|
|
18
|
+
{ value: "2", label: "H2" },
|
|
19
|
+
{ value: "3", label: "H3" },
|
|
20
|
+
{ value: "4", label: "H4" },
|
|
21
|
+
{ value: "5", label: "H5" },
|
|
22
|
+
{ value: "6", label: "H6" }
|
|
23
|
+
];
|
|
24
|
+
function TocSettings({ editor, attrs, getPos }) {
|
|
25
|
+
const intl = useIntl();
|
|
26
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
27
|
+
const [localAttrs, setLocalAttrs] = useState(attrs);
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
if (isOpen) {
|
|
30
|
+
setLocalAttrs(attrs);
|
|
31
|
+
}
|
|
32
|
+
}, [isOpen, attrs]);
|
|
33
|
+
const handleSave = useCallback(() => {
|
|
34
|
+
const pos = getPos();
|
|
35
|
+
if (pos === void 0) return;
|
|
36
|
+
editor.view.dispatch(
|
|
37
|
+
editor.state.tr.setNodeMarkup(pos, void 0, localAttrs)
|
|
38
|
+
);
|
|
39
|
+
setIsOpen(false);
|
|
40
|
+
}, [editor, localAttrs, getPos]);
|
|
41
|
+
const handleCancel = useCallback(() => {
|
|
42
|
+
setLocalAttrs(attrs);
|
|
43
|
+
setIsOpen(false);
|
|
44
|
+
}, [attrs]);
|
|
45
|
+
const handleMinLevelChange = useCallback((value) => {
|
|
46
|
+
const minLevel = Number.parseInt(String(value), 10);
|
|
47
|
+
setLocalAttrs((prev) => ({
|
|
48
|
+
...prev,
|
|
49
|
+
minLevel,
|
|
50
|
+
// Ensure maxLevel is not less than minLevel
|
|
51
|
+
maxLevel: Math.max(prev.maxLevel, minLevel)
|
|
52
|
+
}));
|
|
53
|
+
}, []);
|
|
54
|
+
const handleMaxLevelChange = useCallback((value) => {
|
|
55
|
+
const maxLevel = Number.parseInt(String(value), 10);
|
|
56
|
+
setLocalAttrs((prev) => ({
|
|
57
|
+
...prev,
|
|
58
|
+
maxLevel,
|
|
59
|
+
// Ensure minLevel is not greater than maxLevel
|
|
60
|
+
minLevel: Math.min(prev.minLevel, maxLevel)
|
|
61
|
+
}));
|
|
62
|
+
}, []);
|
|
63
|
+
const handleNumberedChange = useCallback((checked) => {
|
|
64
|
+
setLocalAttrs((prev) => ({ ...prev, numbered: checked }));
|
|
65
|
+
}, []);
|
|
66
|
+
const handleStyleChange = useCallback((value) => {
|
|
67
|
+
setLocalAttrs((prev) => ({
|
|
68
|
+
...prev,
|
|
69
|
+
style: String(value)
|
|
70
|
+
}));
|
|
71
|
+
}, []);
|
|
72
|
+
if (!editor.isEditable) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
76
|
+
/* @__PURE__ */ jsx(
|
|
77
|
+
IconButton,
|
|
78
|
+
{
|
|
79
|
+
size: "sm",
|
|
80
|
+
variant: "ghost",
|
|
81
|
+
"aria-label": intl.formatMessage(messages.settings),
|
|
82
|
+
onClick: (e) => {
|
|
83
|
+
e.stopPropagation();
|
|
84
|
+
e.preventDefault();
|
|
85
|
+
setIsOpen(true);
|
|
86
|
+
},
|
|
87
|
+
children: /* @__PURE__ */ jsx(SettingsIcon, { className: "size-3.5" })
|
|
88
|
+
}
|
|
89
|
+
),
|
|
90
|
+
/* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: setIsOpen, size: "sm", children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
|
91
|
+
/* @__PURE__ */ jsx(Dialog.Header, { children: /* @__PURE__ */ jsx(Dialog.Title, { children: intl.formatMessage(messages.settings) }) }),
|
|
92
|
+
/* @__PURE__ */ jsx(Dialog.Body, { children: /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
93
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-3", children: [
|
|
94
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
95
|
+
/* @__PURE__ */ jsx(Label, { className: "text-sm", children: intl.formatMessage(messages.min_level) }),
|
|
96
|
+
/* @__PURE__ */ jsxs(
|
|
97
|
+
Select,
|
|
98
|
+
{
|
|
99
|
+
size: "sm",
|
|
100
|
+
value: String(localAttrs.minLevel),
|
|
101
|
+
onValueChange: handleMinLevelChange,
|
|
102
|
+
children: [
|
|
103
|
+
/* @__PURE__ */ jsx(Select.Trigger, { children: /* @__PURE__ */ jsx(Select.Value, {}) }),
|
|
104
|
+
/* @__PURE__ */ jsx(Select.Content, { children: HEADING_LEVELS.map((level) => /* @__PURE__ */ jsx(
|
|
105
|
+
Select.Item,
|
|
106
|
+
{
|
|
107
|
+
value: level.value,
|
|
108
|
+
disabled: Number.parseInt(level.value, 10) > localAttrs.maxLevel,
|
|
109
|
+
children: level.label
|
|
110
|
+
},
|
|
111
|
+
level.value
|
|
112
|
+
)) })
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
)
|
|
116
|
+
] }),
|
|
117
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
118
|
+
/* @__PURE__ */ jsx(Label, { className: "text-sm", children: intl.formatMessage(messages.max_level) }),
|
|
119
|
+
/* @__PURE__ */ jsxs(
|
|
120
|
+
Select,
|
|
121
|
+
{
|
|
122
|
+
size: "sm",
|
|
123
|
+
value: String(localAttrs.maxLevel),
|
|
124
|
+
onValueChange: handleMaxLevelChange,
|
|
125
|
+
children: [
|
|
126
|
+
/* @__PURE__ */ jsx(Select.Trigger, { children: /* @__PURE__ */ jsx(Select.Value, {}) }),
|
|
127
|
+
/* @__PURE__ */ jsx(Select.Content, { children: HEADING_LEVELS.map((level) => /* @__PURE__ */ jsx(
|
|
128
|
+
Select.Item,
|
|
129
|
+
{
|
|
130
|
+
value: level.value,
|
|
131
|
+
disabled: Number.parseInt(level.value, 10) < localAttrs.minLevel,
|
|
132
|
+
children: level.label
|
|
133
|
+
},
|
|
134
|
+
level.value
|
|
135
|
+
)) })
|
|
136
|
+
]
|
|
137
|
+
}
|
|
138
|
+
)
|
|
139
|
+
] })
|
|
140
|
+
] }),
|
|
141
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
142
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-0.5", children: [
|
|
143
|
+
/* @__PURE__ */ jsx(Label, { className: "text-sm", children: intl.formatMessage(messages.numbered) }),
|
|
144
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: intl.formatMessage(messages.numbered_hint) })
|
|
145
|
+
] }),
|
|
146
|
+
/* @__PURE__ */ jsx(
|
|
147
|
+
Switch,
|
|
148
|
+
{
|
|
149
|
+
size: "sm",
|
|
150
|
+
checked: localAttrs.numbered,
|
|
151
|
+
onCheckedChange: handleNumberedChange
|
|
152
|
+
}
|
|
153
|
+
)
|
|
154
|
+
] }),
|
|
155
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
156
|
+
/* @__PURE__ */ jsx(Label, { className: "text-sm", children: intl.formatMessage(messages.style) }),
|
|
157
|
+
/* @__PURE__ */ jsxs(
|
|
158
|
+
Select,
|
|
159
|
+
{
|
|
160
|
+
size: "sm",
|
|
161
|
+
value: localAttrs.style,
|
|
162
|
+
onValueChange: handleStyleChange,
|
|
163
|
+
children: [
|
|
164
|
+
/* @__PURE__ */ jsx(Select.Trigger, { children: /* @__PURE__ */ jsx(Select.Value, {}) }),
|
|
165
|
+
/* @__PURE__ */ jsxs(Select.Content, { children: [
|
|
166
|
+
/* @__PURE__ */ jsx(Select.Item, { value: "default", children: intl.formatMessage(messages.style_default) }),
|
|
167
|
+
/* @__PURE__ */ jsx(Select.Item, { value: "flat", children: intl.formatMessage(messages.style_flat) }),
|
|
168
|
+
/* @__PURE__ */ jsx(Select.Item, { value: "compact", children: intl.formatMessage(messages.style_compact) })
|
|
169
|
+
] })
|
|
170
|
+
]
|
|
171
|
+
}
|
|
172
|
+
)
|
|
173
|
+
] })
|
|
174
|
+
] }) }),
|
|
175
|
+
/* @__PURE__ */ jsxs(Dialog.Footer, { children: [
|
|
176
|
+
/* @__PURE__ */ jsx(Button, { variant: "ghost", onClick: handleCancel, children: intl.formatMessage(messages.cancel) }),
|
|
177
|
+
/* @__PURE__ */ jsx(Button, { onClick: handleSave, children: intl.formatMessage(messages.save) })
|
|
178
|
+
] })
|
|
179
|
+
] }) })
|
|
180
|
+
] });
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export {
|
|
184
|
+
TocSettings
|
|
185
|
+
};
|