@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.
Files changed (147) hide show
  1. package/dist/chunk-2U5CQUZH.mjs +91 -0
  2. package/dist/chunk-2V6VOAPI.mjs +139 -0
  3. package/dist/chunk-32SUXCAQ.mjs +115 -0
  4. package/dist/chunk-3VRQUYYW.mjs +169 -0
  5. package/dist/chunk-4CDZ547I.mjs +185 -0
  6. package/dist/chunk-5GFFTVMZ.mjs +62 -0
  7. package/dist/{chunk-FJAGUXEO.mjs → chunk-7SRL3P4B.mjs} +32 -19
  8. package/dist/{chunk-WHJ4B43N.mjs → chunk-7VGROP26.mjs} +69 -25
  9. package/dist/chunk-7VW67NVL.mjs +80 -0
  10. package/dist/chunk-BXHPO3T7.mjs +152 -0
  11. package/dist/{chunk-QF3YHPWM.mjs → chunk-E5NW3MJZ.mjs} +4 -4
  12. package/dist/chunk-FRJX2F4T.mjs +55 -0
  13. package/dist/chunk-IFXRPGIJ.mjs +98 -0
  14. package/dist/chunk-JCV5SEKN.mjs +65 -0
  15. package/dist/chunk-LMCQMSW2.mjs +345 -0
  16. package/dist/chunk-N4CT5RNC.mjs +123 -0
  17. package/dist/{chunk-B2DHYFSH.mjs → chunk-NEHW62L7.mjs} +56 -3
  18. package/dist/chunk-NSYSECKW.mjs +53 -0
  19. package/dist/{chunk-3IKIIRV3.mjs → chunk-QAE2D4KV.mjs} +39 -16
  20. package/dist/chunk-TAM3VMJT.mjs +80 -0
  21. package/dist/chunk-UU6JK5HX.mjs +257 -0
  22. package/dist/chunk-UVHVCION.mjs +168 -0
  23. package/dist/chunk-VF3G2URZ.mjs +83 -0
  24. package/dist/chunk-VRQ6OSAZ.mjs +76 -0
  25. package/dist/chunk-WAAH3NLG.mjs +77 -0
  26. package/dist/chunk-XNDXYI2N.mjs +158 -0
  27. package/dist/context/editor-file-context.d.mts +70 -0
  28. package/dist/context/editor-file-context.d.ts +70 -0
  29. package/dist/context/editor-file-context.js +96 -0
  30. package/dist/context/editor-file-context.mjs +12 -0
  31. package/dist/extensions/callout/callout-settings.d.mts +13 -0
  32. package/dist/extensions/callout/callout-settings.d.ts +13 -0
  33. package/dist/extensions/callout/callout-settings.js +206 -0
  34. package/dist/extensions/callout/callout-settings.mjs +9 -0
  35. package/dist/extensions/callout/callout-view.d.mts +12 -0
  36. package/dist/extensions/callout/callout-view.d.ts +12 -0
  37. package/dist/extensions/callout/callout-view.js +273 -0
  38. package/dist/extensions/callout/callout-view.mjs +12 -0
  39. package/dist/extensions/callout/index.d.mts +44 -0
  40. package/dist/extensions/callout/index.d.ts +44 -0
  41. package/dist/extensions/callout/index.js +380 -0
  42. package/dist/extensions/callout/index.mjs +13 -0
  43. package/dist/extensions/callout/messages.d.mts +59 -0
  44. package/dist/extensions/callout/messages.d.ts +59 -0
  45. package/dist/extensions/callout/messages.js +88 -0
  46. package/dist/extensions/callout/messages.mjs +7 -0
  47. package/dist/extensions/image/image-view.d.mts +15 -0
  48. package/dist/extensions/image/image-view.d.ts +15 -0
  49. package/dist/extensions/image/image-view.js +423 -0
  50. package/dist/extensions/image/image-view.mjs +12 -0
  51. package/dist/extensions/image/index.d.mts +66 -0
  52. package/dist/extensions/image/index.d.ts +66 -0
  53. package/dist/extensions/image/index.js +495 -0
  54. package/dist/extensions/image/index.mjs +16 -0
  55. package/dist/extensions/image/messages.d.mts +56 -0
  56. package/dist/extensions/image/messages.d.ts +56 -0
  57. package/dist/extensions/image/messages.js +85 -0
  58. package/dist/extensions/image/messages.mjs +7 -0
  59. package/dist/extensions/math/index.d.mts +38 -0
  60. package/dist/extensions/math/index.d.ts +38 -0
  61. package/dist/extensions/math/index.js +544 -0
  62. package/dist/extensions/math/index.mjs +17 -0
  63. package/dist/extensions/math/inline-math-view.d.mts +12 -0
  64. package/dist/extensions/math/inline-math-view.d.ts +12 -0
  65. package/dist/extensions/math/inline-math-view.js +232 -0
  66. package/dist/extensions/math/inline-math-view.mjs +11 -0
  67. package/dist/extensions/math/inline-math.d.mts +32 -0
  68. package/dist/extensions/math/inline-math.d.ts +32 -0
  69. package/dist/extensions/math/inline-math.js +304 -0
  70. package/dist/extensions/math/inline-math.mjs +12 -0
  71. package/dist/extensions/math/math-block-view.d.mts +11 -0
  72. package/dist/extensions/math/math-block-view.d.ts +11 -0
  73. package/dist/extensions/math/math-block-view.js +248 -0
  74. package/dist/extensions/math/math-block-view.mjs +11 -0
  75. package/dist/extensions/math/messages.d.mts +49 -0
  76. package/dist/extensions/math/messages.d.ts +49 -0
  77. package/dist/extensions/math/messages.js +78 -0
  78. package/dist/extensions/math/messages.mjs +7 -0
  79. package/dist/extensions/toc/index.d.mts +53 -0
  80. package/dist/extensions/toc/index.d.ts +53 -0
  81. package/dist/extensions/toc/index.js +501 -0
  82. package/dist/extensions/toc/index.mjs +13 -0
  83. package/dist/extensions/toc/messages.d.mts +74 -0
  84. package/dist/extensions/toc/messages.d.ts +74 -0
  85. package/dist/extensions/toc/messages.js +103 -0
  86. package/dist/extensions/toc/messages.mjs +7 -0
  87. package/dist/extensions/toc/toc-settings.d.mts +13 -0
  88. package/dist/extensions/toc/toc-settings.d.ts +13 -0
  89. package/dist/extensions/toc/toc-settings.js +283 -0
  90. package/dist/extensions/toc/toc-settings.mjs +9 -0
  91. package/dist/extensions/toc/toc-view.d.mts +12 -0
  92. package/dist/extensions/toc/toc-view.d.ts +12 -0
  93. package/dist/extensions/toc/toc-view.js +411 -0
  94. package/dist/extensions/toc/toc-view.mjs +12 -0
  95. package/dist/hooks/use-create-editor.d.mts +20 -2
  96. package/dist/hooks/use-create-editor.d.ts +20 -2
  97. package/dist/hooks/use-create-editor.js +2020 -20
  98. package/dist/hooks/use-create-editor.mjs +20 -3
  99. package/dist/index.d.mts +11 -2
  100. package/dist/index.d.ts +11 -2
  101. package/dist/index.js +3948 -1563
  102. package/dist/index.mjs +64 -23
  103. package/dist/presets/basic/editor-header.d.mts +3 -2
  104. package/dist/presets/basic/editor-header.d.ts +3 -2
  105. package/dist/presets/basic/editor-header.js +91 -25
  106. package/dist/presets/basic/editor-header.mjs +14 -14
  107. package/dist/presets/basic/index.d.mts +3 -1
  108. package/dist/presets/basic/index.d.ts +3 -1
  109. package/dist/presets/basic/index.js +3833 -1517
  110. package/dist/presets/basic/index.mjs +41 -22
  111. package/dist/ui/bubble-menu/index.d.mts +13 -0
  112. package/dist/ui/bubble-menu/index.d.ts +13 -0
  113. package/dist/ui/bubble-menu/index.js +671 -0
  114. package/dist/ui/bubble-menu/index.mjs +16 -0
  115. package/dist/ui/color-highlight-popover/color-highlight-popover.mjs +2 -2
  116. package/dist/ui/color-highlight-popover/index.mjs +2 -2
  117. package/dist/ui/copy-anchor-link-button/use-scroll-to-hash.mjs +2 -2
  118. package/dist/ui/link-bubble/index.d.mts +13 -0
  119. package/dist/ui/link-bubble/index.d.ts +13 -0
  120. package/dist/ui/link-bubble/index.js +182 -0
  121. package/dist/ui/link-bubble/index.mjs +10 -0
  122. package/dist/ui/link-popover/index.js +66 -23
  123. package/dist/ui/link-popover/index.mjs +3 -3
  124. package/dist/ui/link-popover/link-popover.d.mts +7 -2
  125. package/dist/ui/link-popover/link-popover.d.ts +7 -2
  126. package/dist/ui/link-popover/link-popover.js +66 -23
  127. package/dist/ui/link-popover/link-popover.mjs +3 -3
  128. package/dist/ui/link-popover/use-link-popover.mjs +2 -2
  129. package/dist/ui/slash-dropdown-menu/index.js +53 -3
  130. package/dist/ui/slash-dropdown-menu/index.mjs +6 -6
  131. package/dist/ui/slash-dropdown-menu/slash-dropdown-menu.js +53 -3
  132. package/dist/ui/slash-dropdown-menu/slash-dropdown-menu.mjs +4 -4
  133. package/dist/ui/slash-dropdown-menu/use-slash-dropdown-menu.d.mts +28 -0
  134. package/dist/ui/slash-dropdown-menu/use-slash-dropdown-menu.d.ts +28 -0
  135. package/dist/ui/slash-dropdown-menu/use-slash-dropdown-menu.js +53 -3
  136. package/dist/ui/slash-dropdown-menu/use-slash-dropdown-menu.mjs +1 -1
  137. package/dist/ui/suggestion-menu/index.mjs +2 -2
  138. package/dist/ui/suggestion-menu/suggestion-menu.mjs +2 -2
  139. package/dist/utils/safe-parse.js +113 -4
  140. package/dist/utils/safe-parse.mjs +1 -1
  141. package/package.json +48 -39
  142. package/dist/chunk-7LHOYNVF.mjs +0 -60
  143. package/dist/chunk-LXOLVGLW.mjs +0 -131
  144. package/dist/{chunk-XL5FS7LN.mjs → chunk-C5RQWJKE.mjs} +3 -3
  145. package/dist/{chunk-JNL4KY45.mjs → chunk-DZLGLP7R.mjs} +3 -3
  146. package/dist/{chunk-LHXRE26G.mjs → chunk-VTKJPVNM.mjs} +3 -3
  147. 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 };