@kopexa/tiptap 17.1.0 → 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 (78) hide show
  1. package/dist/{chunk-SFG45HEU.mjs → chunk-2U5CQUZH.mjs} +1 -1
  2. package/dist/{chunk-QCRK7XVV.mjs → chunk-32SUXCAQ.mjs} +1 -1
  3. package/dist/chunk-5GFFTVMZ.mjs +62 -0
  4. package/dist/{chunk-B6SP3ADV.mjs → chunk-7SRL3P4B.mjs} +8 -8
  5. package/dist/{chunk-WKJGDCGA.mjs → chunk-7VGROP26.mjs} +1 -1
  6. package/dist/{chunk-6YGMTHOY.mjs → chunk-7VW67NVL.mjs} +1 -1
  7. package/dist/{chunk-SCL22AGK.mjs → chunk-BXHPO3T7.mjs} +14 -4
  8. package/dist/{chunk-EBFGDPWY.mjs → chunk-E5NW3MJZ.mjs} +4 -4
  9. package/dist/chunk-LMCQMSW2.mjs +345 -0
  10. package/dist/{chunk-EH2JHHGJ.mjs → chunk-NEHW62L7.mjs} +1 -3
  11. package/dist/{chunk-KTIMXK5V.mjs → chunk-NSYSECKW.mjs} +3 -3
  12. package/dist/{chunk-Z6GJ2GKW.mjs → chunk-QAE2D4KV.mjs} +13 -13
  13. package/dist/{chunk-IY4SCXZN.mjs → chunk-UU6JK5HX.mjs} +105 -11
  14. package/dist/{chunk-DSK3HK5D.mjs → chunk-UVHVCION.mjs} +14 -4
  15. package/dist/{chunk-MYO2CUDR.mjs → chunk-VF3G2URZ.mjs} +10 -2
  16. package/dist/chunk-VRQ6OSAZ.mjs +76 -0
  17. package/dist/chunk-WAAH3NLG.mjs +77 -0
  18. package/dist/context/editor-file-context.d.mts +70 -0
  19. package/dist/context/editor-file-context.d.ts +70 -0
  20. package/dist/context/editor-file-context.js +96 -0
  21. package/dist/context/editor-file-context.mjs +12 -0
  22. package/dist/extensions/callout/callout-view.js +8 -1
  23. package/dist/extensions/callout/callout-view.mjs +1 -1
  24. package/dist/extensions/callout/index.js +8 -1
  25. package/dist/extensions/callout/index.mjs +2 -2
  26. package/dist/extensions/image/image-view.d.mts +15 -0
  27. package/dist/extensions/image/image-view.d.ts +15 -0
  28. package/dist/extensions/image/image-view.js +423 -0
  29. package/dist/extensions/image/image-view.mjs +12 -0
  30. package/dist/extensions/image/index.d.mts +66 -0
  31. package/dist/extensions/image/index.d.ts +66 -0
  32. package/dist/extensions/image/index.js +495 -0
  33. package/dist/extensions/image/index.mjs +16 -0
  34. package/dist/extensions/image/messages.d.mts +56 -0
  35. package/dist/extensions/image/messages.d.ts +56 -0
  36. package/dist/extensions/image/messages.js +85 -0
  37. package/dist/extensions/image/messages.mjs +7 -0
  38. package/dist/extensions/math/index.js +20 -6
  39. package/dist/extensions/math/index.mjs +4 -4
  40. package/dist/extensions/math/inline-math-view.js +10 -3
  41. package/dist/extensions/math/inline-math-view.mjs +1 -1
  42. package/dist/extensions/math/inline-math.js +10 -3
  43. package/dist/extensions/math/inline-math.mjs +2 -2
  44. package/dist/extensions/math/math-block-view.js +10 -3
  45. package/dist/extensions/math/math-block-view.mjs +1 -1
  46. package/dist/hooks/use-create-editor.d.mts +12 -2
  47. package/dist/hooks/use-create-editor.d.ts +12 -2
  48. package/dist/hooks/use-create-editor.js +809 -237
  49. package/dist/hooks/use-create-editor.mjs +14 -10
  50. package/dist/index.d.mts +7 -2
  51. package/dist/index.d.ts +7 -2
  52. package/dist/index.js +1261 -630
  53. package/dist/index.mjs +51 -37
  54. package/dist/presets/basic/editor-header.mjs +16 -16
  55. package/dist/presets/basic/index.d.mts +2 -0
  56. package/dist/presets/basic/index.d.ts +2 -0
  57. package/dist/presets/basic/index.js +1198 -628
  58. package/dist/presets/basic/index.mjs +36 -32
  59. package/dist/ui/bubble-menu/index.mjs +5 -5
  60. package/dist/ui/color-highlight-popover/color-highlight-popover.mjs +2 -2
  61. package/dist/ui/color-highlight-popover/index.mjs +2 -2
  62. package/dist/ui/copy-anchor-link-button/use-scroll-to-hash.mjs +2 -2
  63. package/dist/ui/link-popover/index.mjs +3 -3
  64. package/dist/ui/link-popover/link-popover.mjs +3 -3
  65. package/dist/ui/link-popover/use-link-popover.mjs +2 -2
  66. package/dist/ui/slash-dropdown-menu/index.js +1 -3
  67. package/dist/ui/slash-dropdown-menu/index.mjs +6 -6
  68. package/dist/ui/slash-dropdown-menu/slash-dropdown-menu.js +1 -3
  69. package/dist/ui/slash-dropdown-menu/slash-dropdown-menu.mjs +4 -4
  70. package/dist/ui/slash-dropdown-menu/use-slash-dropdown-menu.js +1 -3
  71. package/dist/ui/slash-dropdown-menu/use-slash-dropdown-menu.mjs +1 -1
  72. package/dist/ui/suggestion-menu/index.mjs +2 -2
  73. package/dist/ui/suggestion-menu/suggestion-menu.mjs +2 -2
  74. package/package.json +25 -24
  75. package/dist/{chunk-XL5FS7LN.mjs → chunk-C5RQWJKE.mjs} +3 -3
  76. package/dist/{chunk-JNL4KY45.mjs → chunk-DZLGLP7R.mjs} +3 -3
  77. package/dist/{chunk-LHXRE26G.mjs → chunk-VTKJPVNM.mjs} +3 -3
  78. package/dist/{chunk-XLSZK3WJ.mjs → chunk-ZYFCSR3E.mjs} +3 -3
@@ -1,22 +1,25 @@
1
1
  "use client";
2
+ import {
3
+ Selection
4
+ } from "./chunk-U5XAL46P.mjs";
5
+ import {
6
+ TocNode
7
+ } from "./chunk-IFXRPGIJ.mjs";
2
8
  import {
3
9
  TrailingNode
4
10
  } from "./chunk-H6LC4LDQ.mjs";
11
+ import {
12
+ ImageNode
13
+ } from "./chunk-WAAH3NLG.mjs";
5
14
  import {
6
15
  Link
7
16
  } from "./chunk-YLDL3VYY.mjs";
8
17
  import {
9
18
  MathBlock
10
- } from "./chunk-SFG45HEU.mjs";
19
+ } from "./chunk-2U5CQUZH.mjs";
11
20
  import {
12
21
  InlineMath
13
- } from "./chunk-6YGMTHOY.mjs";
14
- import {
15
- Selection
16
- } from "./chunk-U5XAL46P.mjs";
17
- import {
18
- TocNode
19
- } from "./chunk-IFXRPGIJ.mjs";
22
+ } from "./chunk-7VW67NVL.mjs";
20
23
  import {
21
24
  UiState
22
25
  } from "./chunk-KR42JAVB.mjs";
@@ -25,12 +28,16 @@ import {
25
28
  } from "./chunk-3VRQUYYW.mjs";
26
29
  import {
27
30
  CalloutNode
28
- } from "./chunk-QCRK7XVV.mjs";
31
+ } from "./chunk-32SUXCAQ.mjs";
32
+ import {
33
+ useEditorFile
34
+ } from "./chunk-VRQ6OSAZ.mjs";
29
35
 
30
36
  // src/hooks/use-create-editor.ts
31
37
  import { CodeKit } from "@kopexa/extension-code";
32
38
  import { ControlKit } from "@kopexa/extension-controlref";
33
39
  import { TableKit } from "@kopexa/extension-table";
40
+ import { FileHandler } from "@tiptap/extension-file-handler";
34
41
  import { Highlight } from "@tiptap/extension-highlight";
35
42
  import InvisibleCharacters from "@tiptap/extension-invisible-characters";
36
43
  import { TaskItem, TaskList } from "@tiptap/extension-list";
@@ -57,8 +64,11 @@ var useCreateEditor = ({
57
64
  onChange,
58
65
  enableControls = false,
59
66
  controlResolver,
67
+ fileHandler: fileHandlerProp,
60
68
  ...options
61
69
  }) => {
70
+ const fileHandlerFromContext = useEditorFile();
71
+ const fileHandler = fileHandlerProp != null ? fileHandlerProp : fileHandlerFromContext;
62
72
  const editor = useEditor({
63
73
  editorProps: {
64
74
  attributes: {
@@ -74,7 +84,8 @@ var useCreateEditor = ({
74
84
  editable,
75
85
  placeholder,
76
86
  enableControls,
77
- controlResolver
87
+ controlResolver,
88
+ fileHandler
78
89
  }),
79
90
  editable,
80
91
  onUpdate: ({ editor: editor2 }) => {
@@ -94,7 +105,8 @@ function getExtensions({
94
105
  editable,
95
106
  placeholder,
96
107
  enableControls = false,
97
- controlResolver
108
+ controlResolver,
109
+ fileHandler
98
110
  }) {
99
111
  const extensions = [
100
112
  StarterKit.configure({
@@ -146,6 +158,8 @@ function getExtensions({
146
158
  CalloutNode,
147
159
  MathBlock,
148
160
  InlineMath,
161
+ // Image support - always include for display
162
+ ImageNode,
149
163
  Placeholder.configure({
150
164
  placeholder,
151
165
  emptyNodeClass: "is-empty with-slash"
@@ -154,8 +168,88 @@ function getExtensions({
154
168
  if (enableControls) {
155
169
  extensions.push(ControlKit.configure({ resolver: controlResolver }));
156
170
  }
171
+ if (fileHandler) {
172
+ extensions.push(
173
+ FileHandler.configure({
174
+ allowedMimeTypes: [
175
+ "image/jpeg",
176
+ "image/png",
177
+ "image/gif",
178
+ "image/webp",
179
+ "image/svg+xml"
180
+ ],
181
+ onDrop: (editor, files, pos) => {
182
+ for (const file of files) {
183
+ handleFileUpload(editor, file, fileHandler, pos);
184
+ }
185
+ },
186
+ onPaste: (editor, files) => {
187
+ for (const file of files) {
188
+ handleFileUpload(editor, file, fileHandler);
189
+ }
190
+ }
191
+ })
192
+ );
193
+ }
157
194
  return extensions;
158
195
  }
196
+ async function handleFileUpload(editor, file, fileHandler, pos) {
197
+ if (!editor) return;
198
+ const tempId = `uploading-${Date.now()}-${Math.random().toString(36).slice(2)}`;
199
+ const insertPos = pos != null ? pos : editor.state.selection.anchor;
200
+ editor.chain().focus().insertContentAt(insertPos, {
201
+ type: "image",
202
+ attrs: {
203
+ src: tempId,
204
+ uploadState: "uploading",
205
+ uploadProgress: 0
206
+ }
207
+ }).run();
208
+ try {
209
+ const ref = await fileHandler.upload(file, (percent) => {
210
+ editor.state.doc.descendants((node, nodePos) => {
211
+ if (node.type.name === "image" && node.attrs.src === tempId) {
212
+ editor.view.dispatch(
213
+ editor.state.tr.setNodeMarkup(nodePos, void 0, {
214
+ ...node.attrs,
215
+ uploadProgress: percent
216
+ })
217
+ );
218
+ return false;
219
+ }
220
+ return true;
221
+ });
222
+ });
223
+ editor.state.doc.descendants((node, nodePos) => {
224
+ if (node.type.name === "image" && node.attrs.src === tempId) {
225
+ editor.view.dispatch(
226
+ editor.state.tr.setNodeMarkup(nodePos, void 0, {
227
+ src: ref,
228
+ uploadState: null,
229
+ uploadProgress: null
230
+ })
231
+ );
232
+ return false;
233
+ }
234
+ return true;
235
+ });
236
+ } catch (error) {
237
+ editor.state.doc.descendants((node, nodePos) => {
238
+ if (node.type.name === "image" && node.attrs.src === tempId) {
239
+ editor.view.dispatch(
240
+ editor.state.tr.setNodeMarkup(nodePos, void 0, {
241
+ ...node.attrs,
242
+ uploadState: "error",
243
+ uploadProgress: null
244
+ })
245
+ );
246
+ return false;
247
+ }
248
+ return true;
249
+ });
250
+ console.error("[FileHandler] Upload failed:", error);
251
+ }
252
+ }
159
253
 
160
254
  export {
161
255
  useCreateEditor,
@@ -8,7 +8,10 @@ import { Button, IconButton } from "@kopexa/button";
8
8
  import { Dialog } from "@kopexa/dialog";
9
9
  import { EditIcon } from "@kopexa/icons";
10
10
  import { Label } from "@kopexa/label";
11
- import { NodeViewWrapper } from "@tiptap/react";
11
+ import {
12
+ NodeViewWrapper,
13
+ useEditorState
14
+ } from "@tiptap/react";
12
15
  import katex from "katex";
13
16
  import "katex/dist/katex.min.css";
14
17
  import { useCallback, useEffect, useMemo, useState } from "react";
@@ -18,6 +21,13 @@ function MathBlockView({ editor, node, getPos }) {
18
21
  const intl = useIntl();
19
22
  const attrs = node.attrs;
20
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
+ });
21
31
  const [isOpen, setIsOpen] = useState(false);
22
32
  const [localLatex, setLocalLatex] = useState(latex);
23
33
  const [error, setError] = useState(null);
@@ -70,11 +80,11 @@ function MathBlockView({ editor, node, getPos }) {
70
80
  (e) => {
71
81
  e.stopPropagation();
72
82
  e.preventDefault();
73
- if (editor.isEditable) {
83
+ if (isEditable) {
74
84
  setIsOpen(true);
75
85
  }
76
86
  },
77
- [editor.isEditable]
87
+ [isEditable]
78
88
  );
79
89
  const isEmpty = !latex;
80
90
  return /* @__PURE__ */ jsxs(
@@ -102,7 +112,7 @@ function MathBlockView({ editor, node, getPos }) {
102
112
  ) : /* @__PURE__ */ jsx("div", { className: "text-destructive text-sm", children: intl.formatMessage(messages.invalid_latex) })
103
113
  }
104
114
  ),
105
- editor.isEditable && !isEmpty && /* @__PURE__ */ jsx(
115
+ isEditable && !isEmpty && /* @__PURE__ */ jsx(
106
116
  IconButton,
107
117
  {
108
118
  size: "sm",
@@ -14,7 +14,8 @@ import {
14
14
  import { callout } from "@kopexa/theme";
15
15
  import {
16
16
  NodeViewContent,
17
- NodeViewWrapper
17
+ NodeViewWrapper,
18
+ useEditorState
18
19
  } from "@tiptap/react";
19
20
  import { useMemo } from "react";
20
21
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -35,6 +36,13 @@ function getVariantIcon(variant, iconClass) {
35
36
  function CalloutNodeView({ editor, node, getPos }) {
36
37
  const attrs = node.attrs;
37
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
+ });
38
46
  const styles = useMemo(
39
47
  () => callout({
40
48
  variant,
@@ -55,7 +63,7 @@ function CalloutNodeView({ editor, node, getPos }) {
55
63
  title && /* @__PURE__ */ jsx("div", { className: styles.title(), children: title }),
56
64
  /* @__PURE__ */ jsx(NodeViewContent, { className: "callout-content" })
57
65
  ] }),
58
- editor.isEditable && /* @__PURE__ */ jsx("div", { className: "absolute top-2 right-2", children: /* @__PURE__ */ jsx(
66
+ isEditable && /* @__PURE__ */ jsx("div", { className: "absolute top-2 right-2", children: /* @__PURE__ */ jsx(
59
67
  CalloutSettings,
60
68
  {
61
69
  editor,
@@ -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,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 };
@@ -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 };
@@ -0,0 +1,96 @@
1
+ "use client";
2
+ "use strict";
3
+ "use client";
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
21
+
22
+ // src/context/editor-file-context.tsx
23
+ var editor_file_context_exports = {};
24
+ __export(editor_file_context_exports, {
25
+ EditorFileProvider: () => EditorFileProvider,
26
+ useEditorFile: () => useEditorFile,
27
+ useEditorFileRequired: () => useEditorFileRequired
28
+ });
29
+ module.exports = __toCommonJS(editor_file_context_exports);
30
+ var import_react = require("react");
31
+ var import_jsx_runtime = require("react/jsx-runtime");
32
+ var EditorFileContext = (0, import_react.createContext)(null);
33
+ var DEFAULT_CACHE_BUFFER = 2 * 60 * 1e3;
34
+ var DEFAULT_CACHE_TTL = 10 * 60 * 1e3;
35
+ var defaultIsReference = (src) => {
36
+ if (!src) return false;
37
+ if (src.startsWith("http://") || src.startsWith("https://")) return false;
38
+ if (src.startsWith("data:")) return false;
39
+ if (src.startsWith("blob:")) return false;
40
+ return true;
41
+ };
42
+ function EditorFileProvider({
43
+ children,
44
+ onUpload,
45
+ onResolve,
46
+ isReference = defaultIsReference,
47
+ cacheBuffer = DEFAULT_CACHE_BUFFER,
48
+ defaultCacheTtl = DEFAULT_CACHE_TTL
49
+ }) {
50
+ const cacheRef = (0, import_react.useRef)(/* @__PURE__ */ new Map());
51
+ const resolve = (0, import_react.useCallback)(
52
+ async (ref) => {
53
+ const cache = cacheRef.current;
54
+ const now = Date.now();
55
+ const cached = cache.get(ref);
56
+ if (cached && cached.expiresAt > now + cacheBuffer) {
57
+ return cached.url;
58
+ }
59
+ const url = await onResolve(ref);
60
+ cache.set(ref, {
61
+ url,
62
+ expiresAt: now + defaultCacheTtl
63
+ });
64
+ return url;
65
+ },
66
+ [onResolve, cacheBuffer, defaultCacheTtl]
67
+ );
68
+ const value = (0, import_react.useMemo)(
69
+ () => ({
70
+ isAvailable: true,
71
+ upload: onUpload,
72
+ resolve,
73
+ isReference
74
+ }),
75
+ [onUpload, resolve, isReference]
76
+ );
77
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EditorFileContext.Provider, { value, children });
78
+ }
79
+ function useEditorFile() {
80
+ return (0, import_react.useContext)(EditorFileContext);
81
+ }
82
+ function useEditorFileRequired() {
83
+ const context = (0, import_react.useContext)(EditorFileContext);
84
+ if (!context) {
85
+ throw new Error(
86
+ "useEditorFileRequired must be used within an EditorFileProvider"
87
+ );
88
+ }
89
+ return context;
90
+ }
91
+ // Annotate the CommonJS export names for ESM import in node:
92
+ 0 && (module.exports = {
93
+ EditorFileProvider,
94
+ useEditorFile,
95
+ useEditorFileRequired
96
+ });
@@ -0,0 +1,12 @@
1
+ "use client";
2
+ "use client";
3
+ import {
4
+ EditorFileProvider,
5
+ useEditorFile,
6
+ useEditorFileRequired
7
+ } from "../chunk-VRQ6OSAZ.mjs";
8
+ export {
9
+ EditorFileProvider,
10
+ useEditorFile,
11
+ useEditorFileRequired
12
+ };
@@ -227,6 +227,13 @@ function getVariantIcon(variant, iconClass) {
227
227
  function CalloutNodeView({ editor, node, getPos }) {
228
228
  const attrs = node.attrs;
229
229
  const { variant = "info", title } = attrs;
230
+ const isEditable = (0, import_react2.useEditorState)({
231
+ editor,
232
+ selector: ({ editor: e }) => {
233
+ var _a;
234
+ return (_a = e == null ? void 0 : e.isEditable) != null ? _a : false;
235
+ }
236
+ });
230
237
  const styles = (0, import_react3.useMemo)(
231
238
  () => (0, import_theme.callout)({
232
239
  variant,
@@ -247,7 +254,7 @@ function CalloutNodeView({ editor, node, getPos }) {
247
254
  title && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: styles.title(), children: title }),
248
255
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react2.NodeViewContent, { className: "callout-content" })
249
256
  ] }),
250
- editor.isEditable && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "absolute top-2 right-2", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
257
+ isEditable && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "absolute top-2 right-2", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
251
258
  CalloutSettings,
252
259
  {
253
260
  editor,
@@ -3,7 +3,7 @@
3
3
  import {
4
4
  CalloutNodeView,
5
5
  callout_view_default
6
- } from "../../chunk-MYO2CUDR.mjs";
6
+ } from "../../chunk-VF3G2URZ.mjs";
7
7
  import "../../chunk-N4CT5RNC.mjs";
8
8
  import "../../chunk-JCV5SEKN.mjs";
9
9
  export {