@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,168 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
messages
|
|
4
|
+
} from "./chunk-FRJX2F4T.mjs";
|
|
5
|
+
|
|
6
|
+
// src/extensions/math/math-block-view.tsx
|
|
7
|
+
import { Button, IconButton } from "@kopexa/button";
|
|
8
|
+
import { Dialog } from "@kopexa/dialog";
|
|
9
|
+
import { EditIcon } from "@kopexa/icons";
|
|
10
|
+
import { Label } from "@kopexa/label";
|
|
11
|
+
import {
|
|
12
|
+
NodeViewWrapper,
|
|
13
|
+
useEditorState
|
|
14
|
+
} from "@tiptap/react";
|
|
15
|
+
import katex from "katex";
|
|
16
|
+
import "katex/dist/katex.min.css";
|
|
17
|
+
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
18
|
+
import { useIntl } from "react-intl";
|
|
19
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
20
|
+
function MathBlockView({ editor, node, getPos }) {
|
|
21
|
+
const intl = useIntl();
|
|
22
|
+
const attrs = node.attrs;
|
|
23
|
+
const { latex = "" } = attrs;
|
|
24
|
+
const isEditable = useEditorState({
|
|
25
|
+
editor,
|
|
26
|
+
selector: ({ editor: e }) => {
|
|
27
|
+
var _a;
|
|
28
|
+
return (_a = e == null ? void 0 : e.isEditable) != null ? _a : false;
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
32
|
+
const [localLatex, setLocalLatex] = useState(latex);
|
|
33
|
+
const [error, setError] = useState(null);
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (isOpen) {
|
|
36
|
+
setLocalLatex(latex);
|
|
37
|
+
setError(null);
|
|
38
|
+
}
|
|
39
|
+
}, [isOpen, latex]);
|
|
40
|
+
const renderedHtml = useMemo(() => {
|
|
41
|
+
if (!latex) return null;
|
|
42
|
+
try {
|
|
43
|
+
return katex.renderToString(latex, {
|
|
44
|
+
throwOnError: false,
|
|
45
|
+
displayMode: true,
|
|
46
|
+
output: "html"
|
|
47
|
+
});
|
|
48
|
+
} catch {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}, [latex]);
|
|
52
|
+
const previewHtml = useMemo(() => {
|
|
53
|
+
if (!localLatex) return null;
|
|
54
|
+
try {
|
|
55
|
+
setError(null);
|
|
56
|
+
return katex.renderToString(localLatex, {
|
|
57
|
+
throwOnError: true,
|
|
58
|
+
displayMode: true,
|
|
59
|
+
output: "html"
|
|
60
|
+
});
|
|
61
|
+
} catch (_e) {
|
|
62
|
+
setError(intl.formatMessage(messages.invalid_latex));
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}, [localLatex, intl]);
|
|
66
|
+
const handleSave = useCallback(() => {
|
|
67
|
+
const pos = getPos();
|
|
68
|
+
if (pos === void 0) return;
|
|
69
|
+
editor.view.dispatch(
|
|
70
|
+
editor.state.tr.setNodeMarkup(pos, void 0, { latex: localLatex })
|
|
71
|
+
);
|
|
72
|
+
setIsOpen(false);
|
|
73
|
+
}, [editor, localLatex, getPos]);
|
|
74
|
+
const handleCancel = useCallback(() => {
|
|
75
|
+
setLocalLatex(latex);
|
|
76
|
+
setError(null);
|
|
77
|
+
setIsOpen(false);
|
|
78
|
+
}, [latex]);
|
|
79
|
+
const handleOpenEditor = useCallback(
|
|
80
|
+
(e) => {
|
|
81
|
+
e.stopPropagation();
|
|
82
|
+
e.preventDefault();
|
|
83
|
+
if (isEditable) {
|
|
84
|
+
setIsOpen(true);
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
[isEditable]
|
|
88
|
+
);
|
|
89
|
+
const isEmpty = !latex;
|
|
90
|
+
return /* @__PURE__ */ jsxs(
|
|
91
|
+
NodeViewWrapper,
|
|
92
|
+
{
|
|
93
|
+
className: "my-4 relative group",
|
|
94
|
+
"data-type": "math-block",
|
|
95
|
+
"data-latex": latex,
|
|
96
|
+
children: [
|
|
97
|
+
/* @__PURE__ */ jsx(
|
|
98
|
+
"button",
|
|
99
|
+
{
|
|
100
|
+
type: "button",
|
|
101
|
+
className: "w-full flex items-center justify-center min-h-16 p-4 rounded-md border border-border bg-muted/30 cursor-pointer hover:bg-muted/50 transition-colors",
|
|
102
|
+
onClick: handleOpenEditor,
|
|
103
|
+
children: isEmpty ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-muted-foreground", children: [
|
|
104
|
+
/* @__PURE__ */ jsx("span", { className: "text-lg font-serif", children: "\u2211" }),
|
|
105
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm", children: intl.formatMessage(messages.empty_formula) })
|
|
106
|
+
] }) : renderedHtml ? /* @__PURE__ */ jsx(
|
|
107
|
+
"div",
|
|
108
|
+
{
|
|
109
|
+
className: "katex-display",
|
|
110
|
+
dangerouslySetInnerHTML: { __html: renderedHtml }
|
|
111
|
+
}
|
|
112
|
+
) : /* @__PURE__ */ jsx("div", { className: "text-destructive text-sm", children: intl.formatMessage(messages.invalid_latex) })
|
|
113
|
+
}
|
|
114
|
+
),
|
|
115
|
+
isEditable && !isEmpty && /* @__PURE__ */ jsx(
|
|
116
|
+
IconButton,
|
|
117
|
+
{
|
|
118
|
+
size: "sm",
|
|
119
|
+
variant: "ghost",
|
|
120
|
+
className: "absolute top-2 right-2 opacity-0 group-hover:opacity-100 transition-opacity",
|
|
121
|
+
"aria-label": intl.formatMessage(messages.edit),
|
|
122
|
+
onClick: handleOpenEditor,
|
|
123
|
+
children: /* @__PURE__ */ jsx(EditIcon, { className: "size-3.5" })
|
|
124
|
+
}
|
|
125
|
+
),
|
|
126
|
+
/* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: setIsOpen, size: "md", children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
|
127
|
+
/* @__PURE__ */ jsx(Dialog.Header, { children: /* @__PURE__ */ jsx(Dialog.Title, { children: intl.formatMessage(messages.title) }) }),
|
|
128
|
+
/* @__PURE__ */ jsx(Dialog.Body, { children: /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
129
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
130
|
+
/* @__PURE__ */ jsx(Label, { className: "text-sm", children: intl.formatMessage(messages.latex_input) }),
|
|
131
|
+
/* @__PURE__ */ jsx(
|
|
132
|
+
"textarea",
|
|
133
|
+
{
|
|
134
|
+
className: "w-full min-h-24 p-3 rounded-md border border-input bg-background font-mono text-sm resize-y focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
|
135
|
+
value: localLatex,
|
|
136
|
+
onChange: (e) => setLocalLatex(e.target.value),
|
|
137
|
+
placeholder: intl.formatMessage(messages.latex_placeholder),
|
|
138
|
+
spellCheck: false
|
|
139
|
+
}
|
|
140
|
+
),
|
|
141
|
+
error && /* @__PURE__ */ jsx("p", { className: "text-xs text-destructive", children: error })
|
|
142
|
+
] }),
|
|
143
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
144
|
+
/* @__PURE__ */ jsx(Label, { className: "text-sm", children: intl.formatMessage(messages.preview) }),
|
|
145
|
+
/* @__PURE__ */ jsx("div", { className: "min-h-16 p-4 rounded-md border border-border bg-muted/30 flex items-center justify-center", children: previewHtml ? /* @__PURE__ */ jsx(
|
|
146
|
+
"div",
|
|
147
|
+
{
|
|
148
|
+
className: "katex-display",
|
|
149
|
+
dangerouslySetInnerHTML: { __html: previewHtml }
|
|
150
|
+
}
|
|
151
|
+
) : localLatex ? /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-sm", children: intl.formatMessage(messages.invalid_latex) }) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-sm", children: intl.formatMessage(messages.latex_placeholder) }) })
|
|
152
|
+
] })
|
|
153
|
+
] }) }),
|
|
154
|
+
/* @__PURE__ */ jsxs(Dialog.Footer, { children: [
|
|
155
|
+
/* @__PURE__ */ jsx(Button, { variant: "ghost", onClick: handleCancel, children: intl.formatMessage(messages.cancel) }),
|
|
156
|
+
/* @__PURE__ */ jsx(Button, { onClick: handleSave, disabled: !!error && !!localLatex, children: intl.formatMessage(messages.save) })
|
|
157
|
+
] })
|
|
158
|
+
] }) })
|
|
159
|
+
]
|
|
160
|
+
}
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
var math_block_view_default = MathBlockView;
|
|
164
|
+
|
|
165
|
+
export {
|
|
166
|
+
MathBlockView,
|
|
167
|
+
math_block_view_default
|
|
168
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
CalloutSettings
|
|
4
|
+
} from "./chunk-N4CT5RNC.mjs";
|
|
5
|
+
|
|
6
|
+
// src/extensions/callout/callout-view.tsx
|
|
7
|
+
import {
|
|
8
|
+
AlertCircleIcon,
|
|
9
|
+
AlertIcon,
|
|
10
|
+
CheckCirleIcon,
|
|
11
|
+
InfoIcon,
|
|
12
|
+
ShellIcon
|
|
13
|
+
} from "@kopexa/icons";
|
|
14
|
+
import { callout } from "@kopexa/theme";
|
|
15
|
+
import {
|
|
16
|
+
NodeViewContent,
|
|
17
|
+
NodeViewWrapper,
|
|
18
|
+
useEditorState
|
|
19
|
+
} from "@tiptap/react";
|
|
20
|
+
import { useMemo } from "react";
|
|
21
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
22
|
+
function getVariantIcon(variant, iconClass) {
|
|
23
|
+
switch (variant) {
|
|
24
|
+
case "info":
|
|
25
|
+
return /* @__PURE__ */ jsx(InfoIcon, { className: iconClass });
|
|
26
|
+
case "success":
|
|
27
|
+
return /* @__PURE__ */ jsx(CheckCirleIcon, { className: iconClass });
|
|
28
|
+
case "warning":
|
|
29
|
+
return /* @__PURE__ */ jsx(AlertIcon, { className: iconClass });
|
|
30
|
+
case "destructive":
|
|
31
|
+
return /* @__PURE__ */ jsx(AlertCircleIcon, { className: iconClass });
|
|
32
|
+
default:
|
|
33
|
+
return /* @__PURE__ */ jsx(ShellIcon, { className: iconClass });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function CalloutNodeView({ editor, node, getPos }) {
|
|
37
|
+
const attrs = node.attrs;
|
|
38
|
+
const { variant = "info", title } = attrs;
|
|
39
|
+
const isEditable = useEditorState({
|
|
40
|
+
editor,
|
|
41
|
+
selector: ({ editor: e }) => {
|
|
42
|
+
var _a;
|
|
43
|
+
return (_a = e == null ? void 0 : e.isEditable) != null ? _a : false;
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
const styles = useMemo(
|
|
47
|
+
() => callout({
|
|
48
|
+
variant,
|
|
49
|
+
radius: "md",
|
|
50
|
+
size: "md"
|
|
51
|
+
}),
|
|
52
|
+
[variant]
|
|
53
|
+
);
|
|
54
|
+
return /* @__PURE__ */ jsxs(
|
|
55
|
+
NodeViewWrapper,
|
|
56
|
+
{
|
|
57
|
+
className: styles.root(),
|
|
58
|
+
"data-type": "callout",
|
|
59
|
+
"data-variant": variant,
|
|
60
|
+
children: [
|
|
61
|
+
/* @__PURE__ */ jsx("div", { className: styles.iconContainer(), children: getVariantIcon(variant, styles.icon()) }),
|
|
62
|
+
/* @__PURE__ */ jsxs("div", { className: styles.content(), children: [
|
|
63
|
+
title && /* @__PURE__ */ jsx("div", { className: styles.title(), children: title }),
|
|
64
|
+
/* @__PURE__ */ jsx(NodeViewContent, { className: "callout-content" })
|
|
65
|
+
] }),
|
|
66
|
+
isEditable && /* @__PURE__ */ jsx("div", { className: "absolute top-2 right-2", children: /* @__PURE__ */ jsx(
|
|
67
|
+
CalloutSettings,
|
|
68
|
+
{
|
|
69
|
+
editor,
|
|
70
|
+
attrs,
|
|
71
|
+
getPos
|
|
72
|
+
}
|
|
73
|
+
) })
|
|
74
|
+
]
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
var callout_view_default = CalloutNodeView;
|
|
79
|
+
|
|
80
|
+
export {
|
|
81
|
+
CalloutNodeView,
|
|
82
|
+
callout_view_default
|
|
83
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/context/editor-file-context.tsx
|
|
4
|
+
import {
|
|
5
|
+
createContext,
|
|
6
|
+
useCallback,
|
|
7
|
+
useContext,
|
|
8
|
+
useMemo,
|
|
9
|
+
useRef
|
|
10
|
+
} from "react";
|
|
11
|
+
import { jsx } from "react/jsx-runtime";
|
|
12
|
+
var EditorFileContext = createContext(null);
|
|
13
|
+
var DEFAULT_CACHE_BUFFER = 2 * 60 * 1e3;
|
|
14
|
+
var DEFAULT_CACHE_TTL = 10 * 60 * 1e3;
|
|
15
|
+
var defaultIsReference = (src) => {
|
|
16
|
+
if (!src) return false;
|
|
17
|
+
if (src.startsWith("http://") || src.startsWith("https://")) return false;
|
|
18
|
+
if (src.startsWith("data:")) return false;
|
|
19
|
+
if (src.startsWith("blob:")) return false;
|
|
20
|
+
return true;
|
|
21
|
+
};
|
|
22
|
+
function EditorFileProvider({
|
|
23
|
+
children,
|
|
24
|
+
onUpload,
|
|
25
|
+
onResolve,
|
|
26
|
+
isReference = defaultIsReference,
|
|
27
|
+
cacheBuffer = DEFAULT_CACHE_BUFFER,
|
|
28
|
+
defaultCacheTtl = DEFAULT_CACHE_TTL
|
|
29
|
+
}) {
|
|
30
|
+
const cacheRef = useRef(/* @__PURE__ */ new Map());
|
|
31
|
+
const resolve = useCallback(
|
|
32
|
+
async (ref) => {
|
|
33
|
+
const cache = cacheRef.current;
|
|
34
|
+
const now = Date.now();
|
|
35
|
+
const cached = cache.get(ref);
|
|
36
|
+
if (cached && cached.expiresAt > now + cacheBuffer) {
|
|
37
|
+
return cached.url;
|
|
38
|
+
}
|
|
39
|
+
const url = await onResolve(ref);
|
|
40
|
+
cache.set(ref, {
|
|
41
|
+
url,
|
|
42
|
+
expiresAt: now + defaultCacheTtl
|
|
43
|
+
});
|
|
44
|
+
return url;
|
|
45
|
+
},
|
|
46
|
+
[onResolve, cacheBuffer, defaultCacheTtl]
|
|
47
|
+
);
|
|
48
|
+
const value = useMemo(
|
|
49
|
+
() => ({
|
|
50
|
+
isAvailable: true,
|
|
51
|
+
upload: onUpload,
|
|
52
|
+
resolve,
|
|
53
|
+
isReference
|
|
54
|
+
}),
|
|
55
|
+
[onUpload, resolve, isReference]
|
|
56
|
+
);
|
|
57
|
+
return /* @__PURE__ */ jsx(EditorFileContext.Provider, { value, children });
|
|
58
|
+
}
|
|
59
|
+
function useEditorFile() {
|
|
60
|
+
return useContext(EditorFileContext);
|
|
61
|
+
}
|
|
62
|
+
function useEditorFileRequired() {
|
|
63
|
+
const context = useContext(EditorFileContext);
|
|
64
|
+
if (!context) {
|
|
65
|
+
throw new Error(
|
|
66
|
+
"useEditorFileRequired must be used within an EditorFileProvider"
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
return context;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export {
|
|
73
|
+
EditorFileProvider,
|
|
74
|
+
useEditorFile,
|
|
75
|
+
useEditorFileRequired
|
|
76
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
ImageNodeView
|
|
4
|
+
} from "./chunk-LMCQMSW2.mjs";
|
|
5
|
+
|
|
6
|
+
// src/extensions/image/index.ts
|
|
7
|
+
import { mergeAttributes, Node } from "@tiptap/core";
|
|
8
|
+
import { ReactNodeViewRenderer } from "@tiptap/react";
|
|
9
|
+
var ImageNode = Node.create({
|
|
10
|
+
name: "image",
|
|
11
|
+
group: "block",
|
|
12
|
+
atom: true,
|
|
13
|
+
draggable: true,
|
|
14
|
+
addOptions() {
|
|
15
|
+
return {
|
|
16
|
+
allowBase64: true,
|
|
17
|
+
HTMLAttributes: {}
|
|
18
|
+
};
|
|
19
|
+
},
|
|
20
|
+
addAttributes() {
|
|
21
|
+
return {
|
|
22
|
+
src: {
|
|
23
|
+
default: null
|
|
24
|
+
},
|
|
25
|
+
alt: {
|
|
26
|
+
default: null
|
|
27
|
+
},
|
|
28
|
+
title: {
|
|
29
|
+
default: null
|
|
30
|
+
},
|
|
31
|
+
width: {
|
|
32
|
+
default: null
|
|
33
|
+
},
|
|
34
|
+
height: {
|
|
35
|
+
default: null
|
|
36
|
+
},
|
|
37
|
+
uploadState: {
|
|
38
|
+
default: null,
|
|
39
|
+
rendered: false
|
|
40
|
+
},
|
|
41
|
+
uploadProgress: {
|
|
42
|
+
default: null,
|
|
43
|
+
rendered: false
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
},
|
|
47
|
+
parseHTML() {
|
|
48
|
+
return [
|
|
49
|
+
{
|
|
50
|
+
tag: "img[src]"
|
|
51
|
+
}
|
|
52
|
+
];
|
|
53
|
+
},
|
|
54
|
+
renderHTML({ HTMLAttributes }) {
|
|
55
|
+
return [
|
|
56
|
+
"img",
|
|
57
|
+
mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)
|
|
58
|
+
];
|
|
59
|
+
},
|
|
60
|
+
addNodeView() {
|
|
61
|
+
return ReactNodeViewRenderer(ImageNodeView);
|
|
62
|
+
},
|
|
63
|
+
addCommands() {
|
|
64
|
+
return {
|
|
65
|
+
setImage: (options) => ({ commands }) => {
|
|
66
|
+
return commands.insertContent({
|
|
67
|
+
type: this.name,
|
|
68
|
+
attrs: options
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
export {
|
|
76
|
+
ImageNode
|
|
77
|
+
};
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/ui/link-bubble/index.tsx
|
|
4
|
+
import { IconButton } from "@kopexa/button";
|
|
5
|
+
import { EditIcon, ExternalLinkIcon, TrashIcon } from "@kopexa/icons";
|
|
6
|
+
import { Input } from "@kopexa/input";
|
|
7
|
+
import { BubbleMenu as TiptapBubbleMenu } from "@tiptap/react/menus";
|
|
8
|
+
import { useCallback, useEffect, useState } from "react";
|
|
9
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
function LinkBubble({ editor }) {
|
|
11
|
+
const [isEditing, setIsEditing] = useState(false);
|
|
12
|
+
const [url, setUrl] = useState("");
|
|
13
|
+
const getCurrentUrl = useCallback(() => {
|
|
14
|
+
if (!editor) return "";
|
|
15
|
+
const attrs = editor.getAttributes("link");
|
|
16
|
+
return attrs.href || "";
|
|
17
|
+
}, [editor]);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
const isLinkActive = editor == null ? void 0 : editor.isActive("link");
|
|
20
|
+
if (isLinkActive) {
|
|
21
|
+
setUrl(getCurrentUrl());
|
|
22
|
+
setIsEditing(false);
|
|
23
|
+
}
|
|
24
|
+
}, [editor, getCurrentUrl]);
|
|
25
|
+
const handleOpenLink = useCallback(() => {
|
|
26
|
+
const href = getCurrentUrl();
|
|
27
|
+
if (href) {
|
|
28
|
+
window.open(href, "_blank", "noopener,noreferrer");
|
|
29
|
+
}
|
|
30
|
+
}, [getCurrentUrl]);
|
|
31
|
+
const handleRemoveLink = useCallback(() => {
|
|
32
|
+
editor == null ? void 0 : editor.chain().focus().unsetLink().run();
|
|
33
|
+
}, [editor]);
|
|
34
|
+
const handleEdit = useCallback(() => {
|
|
35
|
+
setUrl(getCurrentUrl());
|
|
36
|
+
setIsEditing(true);
|
|
37
|
+
}, [getCurrentUrl]);
|
|
38
|
+
const handleSave = useCallback(() => {
|
|
39
|
+
if (url) {
|
|
40
|
+
editor == null ? void 0 : editor.chain().focus().extendMarkRange("link").setLink({ href: url }).run();
|
|
41
|
+
} else {
|
|
42
|
+
editor == null ? void 0 : editor.chain().focus().unsetLink().run();
|
|
43
|
+
}
|
|
44
|
+
setIsEditing(false);
|
|
45
|
+
}, [editor, url]);
|
|
46
|
+
const handleKeyDown = useCallback(
|
|
47
|
+
(e) => {
|
|
48
|
+
if (e.key === "Enter") {
|
|
49
|
+
e.preventDefault();
|
|
50
|
+
handleSave();
|
|
51
|
+
} else if (e.key === "Escape") {
|
|
52
|
+
e.preventDefault();
|
|
53
|
+
setIsEditing(false);
|
|
54
|
+
setUrl(getCurrentUrl());
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
[handleSave, getCurrentUrl]
|
|
58
|
+
);
|
|
59
|
+
if (!editor) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
return /* @__PURE__ */ jsx(
|
|
63
|
+
TiptapBubbleMenu,
|
|
64
|
+
{
|
|
65
|
+
editor,
|
|
66
|
+
pluginKey: "linkBubbleMenu",
|
|
67
|
+
shouldShow: ({ editor: e }) => {
|
|
68
|
+
return e.isActive("link") && e.isEditable;
|
|
69
|
+
},
|
|
70
|
+
options: {
|
|
71
|
+
placement: "bottom-start",
|
|
72
|
+
offset: 8
|
|
73
|
+
},
|
|
74
|
+
className: "rounded-lg border bg-background shadow-md",
|
|
75
|
+
children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1 p-1.5 min-w-[280px]", children: isEditing ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
76
|
+
/* @__PURE__ */ jsx(
|
|
77
|
+
Input,
|
|
78
|
+
{
|
|
79
|
+
type: "url",
|
|
80
|
+
value: url,
|
|
81
|
+
onChange: (e) => setUrl(e.target.value),
|
|
82
|
+
onKeyDown: handleKeyDown,
|
|
83
|
+
placeholder: "Enter URL...",
|
|
84
|
+
className: "flex-1 h-8 text-sm",
|
|
85
|
+
autoFocus: true
|
|
86
|
+
}
|
|
87
|
+
),
|
|
88
|
+
/* @__PURE__ */ jsx(
|
|
89
|
+
IconButton,
|
|
90
|
+
{
|
|
91
|
+
type: "button",
|
|
92
|
+
size: "sm",
|
|
93
|
+
variant: "ghost",
|
|
94
|
+
onClick: handleSave,
|
|
95
|
+
"aria-label": "Save link",
|
|
96
|
+
children: /* @__PURE__ */ jsx(EditIcon, { className: "size-4" })
|
|
97
|
+
}
|
|
98
|
+
)
|
|
99
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
100
|
+
/* @__PURE__ */ jsx(
|
|
101
|
+
"a",
|
|
102
|
+
{
|
|
103
|
+
href: getCurrentUrl(),
|
|
104
|
+
target: "_blank",
|
|
105
|
+
rel: "noopener noreferrer",
|
|
106
|
+
className: "flex-1 text-sm text-primary truncate max-w-[200px] hover:underline px-2",
|
|
107
|
+
onClick: (e) => {
|
|
108
|
+
e.preventDefault();
|
|
109
|
+
handleOpenLink();
|
|
110
|
+
},
|
|
111
|
+
children: getCurrentUrl()
|
|
112
|
+
}
|
|
113
|
+
),
|
|
114
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5 border-l pl-1 ml-1", children: [
|
|
115
|
+
/* @__PURE__ */ jsx(
|
|
116
|
+
IconButton,
|
|
117
|
+
{
|
|
118
|
+
type: "button",
|
|
119
|
+
size: "sm",
|
|
120
|
+
variant: "ghost",
|
|
121
|
+
onClick: handleOpenLink,
|
|
122
|
+
"aria-label": "Open link in new tab",
|
|
123
|
+
children: /* @__PURE__ */ jsx(ExternalLinkIcon, { className: "size-4" })
|
|
124
|
+
}
|
|
125
|
+
),
|
|
126
|
+
/* @__PURE__ */ jsx(
|
|
127
|
+
IconButton,
|
|
128
|
+
{
|
|
129
|
+
type: "button",
|
|
130
|
+
size: "sm",
|
|
131
|
+
variant: "ghost",
|
|
132
|
+
onClick: handleEdit,
|
|
133
|
+
"aria-label": "Edit link",
|
|
134
|
+
children: /* @__PURE__ */ jsx(EditIcon, { className: "size-4" })
|
|
135
|
+
}
|
|
136
|
+
),
|
|
137
|
+
/* @__PURE__ */ jsx(
|
|
138
|
+
IconButton,
|
|
139
|
+
{
|
|
140
|
+
type: "button",
|
|
141
|
+
size: "sm",
|
|
142
|
+
variant: "ghost",
|
|
143
|
+
onClick: handleRemoveLink,
|
|
144
|
+
"aria-label": "Remove link",
|
|
145
|
+
children: /* @__PURE__ */ jsx(TrashIcon, { className: "size-4" })
|
|
146
|
+
}
|
|
147
|
+
)
|
|
148
|
+
] })
|
|
149
|
+
] }) })
|
|
150
|
+
}
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
var link_bubble_default = LinkBubble;
|
|
154
|
+
|
|
155
|
+
export {
|
|
156
|
+
LinkBubble,
|
|
157
|
+
link_bubble_default
|
|
158
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
interface EditorFileHandler {
|
|
5
|
+
/**
|
|
6
|
+
* Upload a file and return a reference string.
|
|
7
|
+
* The reference format is determined by the backend (e.g., UUID, custom scheme).
|
|
8
|
+
* @param file The file to upload
|
|
9
|
+
* @param onProgress Optional progress callback (0-100)
|
|
10
|
+
* @returns Promise resolving to a reference string
|
|
11
|
+
*/
|
|
12
|
+
upload: (file: File, onProgress?: (percent: number) => void) => Promise<string>;
|
|
13
|
+
/**
|
|
14
|
+
* Resolve a reference to a displayable URL.
|
|
15
|
+
* Typically returns a signed URL from your storage backend.
|
|
16
|
+
* @param ref The reference string from upload
|
|
17
|
+
* @returns Promise resolving to a displayable URL
|
|
18
|
+
*/
|
|
19
|
+
resolve: (ref: string) => Promise<string>;
|
|
20
|
+
/**
|
|
21
|
+
* Check if a src string is a reference that needs resolving.
|
|
22
|
+
* Returns false for already-valid URLs (https://, data:, etc.)
|
|
23
|
+
* @param src The src attribute value
|
|
24
|
+
* @returns true if this needs to be resolved
|
|
25
|
+
*/
|
|
26
|
+
isReference: (src: string) => boolean;
|
|
27
|
+
}
|
|
28
|
+
interface EditorFileContextValue extends EditorFileHandler {
|
|
29
|
+
/**
|
|
30
|
+
* Whether file handling is available
|
|
31
|
+
*/
|
|
32
|
+
isAvailable: true;
|
|
33
|
+
}
|
|
34
|
+
interface EditorFileProviderProps {
|
|
35
|
+
children: ReactNode;
|
|
36
|
+
/**
|
|
37
|
+
* Upload handler - called when user pastes/drops a file
|
|
38
|
+
*/
|
|
39
|
+
onUpload: EditorFileHandler["upload"];
|
|
40
|
+
/**
|
|
41
|
+
* Resolve handler - called to get displayable URL from reference
|
|
42
|
+
*/
|
|
43
|
+
onResolve: EditorFileHandler["resolve"];
|
|
44
|
+
/**
|
|
45
|
+
* Check if src needs resolving (default: not starting with http/https/data)
|
|
46
|
+
*/
|
|
47
|
+
isReference?: EditorFileHandler["isReference"];
|
|
48
|
+
/**
|
|
49
|
+
* Cache TTL buffer in ms (default: 2 minutes)
|
|
50
|
+
* URLs are refreshed this much before actual expiry
|
|
51
|
+
*/
|
|
52
|
+
cacheBuffer?: number;
|
|
53
|
+
/**
|
|
54
|
+
* Default cache TTL in ms if not determined from response (default: 10 minutes)
|
|
55
|
+
*/
|
|
56
|
+
defaultCacheTtl?: number;
|
|
57
|
+
}
|
|
58
|
+
declare function EditorFileProvider({ children, onUpload, onResolve, isReference, cacheBuffer, defaultCacheTtl, }: EditorFileProviderProps): react_jsx_runtime.JSX.Element;
|
|
59
|
+
/**
|
|
60
|
+
* Hook to access file handling capabilities.
|
|
61
|
+
* Returns null if no EditorFileProvider is present (files not supported).
|
|
62
|
+
*/
|
|
63
|
+
declare function useEditorFile(): EditorFileContextValue | null;
|
|
64
|
+
/**
|
|
65
|
+
* Hook that throws if file handling is not available.
|
|
66
|
+
* Use this in components that require file support.
|
|
67
|
+
*/
|
|
68
|
+
declare function useEditorFileRequired(): EditorFileContextValue;
|
|
69
|
+
|
|
70
|
+
export { type EditorFileHandler, EditorFileProvider, type EditorFileProviderProps, useEditorFile, useEditorFileRequired };
|