@kopexa/tiptap 17.2.0 → 17.2.2

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 (53) hide show
  1. package/dist/{chunk-E5NW3MJZ.mjs → chunk-3ZPLSXTZ.mjs} +3 -3
  2. package/dist/{chunk-7SRL3P4B.mjs → chunk-5QFCLKHL.mjs} +7 -7
  3. package/dist/{chunk-NEHW62L7.mjs → chunk-6552DQWB.mjs} +2 -2
  4. package/dist/{chunk-5GFFTVMZ.mjs → chunk-DSBJFMHK.mjs} +4 -28
  5. package/dist/chunk-EAAQE5ZV.mjs +283 -0
  6. package/dist/chunk-HTJ2RXOG.mjs +32 -0
  7. package/dist/{chunk-LMCQMSW2.mjs → chunk-KYLBKQ2E.mjs} +12 -154
  8. package/dist/chunk-N3JE67CS.mjs +81 -0
  9. package/dist/{chunk-UU6JK5HX.mjs → chunk-SSJMKQ5G.mjs} +33 -20
  10. package/dist/chunk-Z365KVQY.mjs +34 -0
  11. package/dist/extensions/image/image-view.d.mts +3 -3
  12. package/dist/extensions/image/image-view.d.ts +3 -3
  13. package/dist/extensions/image/image-view.js +13 -181
  14. package/dist/extensions/image/image-view.mjs +2 -2
  15. package/dist/extensions/image/index.d.mts +12 -49
  16. package/dist/extensions/image/index.d.ts +12 -49
  17. package/dist/extensions/image/index.js +18 -231
  18. package/dist/extensions/image/index.mjs +3 -3
  19. package/dist/extensions/image/messages.d.mts +2 -30
  20. package/dist/extensions/image/messages.d.ts +2 -30
  21. package/dist/extensions/image/messages.js +4 -32
  22. package/dist/extensions/image/messages.mjs +1 -1
  23. package/dist/extensions/image-upload/image-upload-view.d.mts +12 -0
  24. package/dist/extensions/image-upload/image-upload-view.d.ts +12 -0
  25. package/dist/extensions/image-upload/image-upload-view.js +338 -0
  26. package/dist/extensions/image-upload/image-upload-view.mjs +12 -0
  27. package/dist/extensions/image-upload/index.d.mts +46 -0
  28. package/dist/extensions/image-upload/index.d.ts +46 -0
  29. package/dist/extensions/image-upload/index.js +414 -0
  30. package/dist/extensions/image-upload/index.mjs +16 -0
  31. package/dist/extensions/image-upload/messages.d.mts +32 -0
  32. package/dist/extensions/image-upload/messages.d.ts +32 -0
  33. package/dist/extensions/image-upload/messages.js +61 -0
  34. package/dist/extensions/image-upload/messages.mjs +7 -0
  35. package/dist/extensions/math/index.mjs +1 -1
  36. package/dist/hooks/use-create-editor.js +562 -393
  37. package/dist/hooks/use-create-editor.mjs +13 -10
  38. package/dist/index.d.mts +4 -1
  39. package/dist/index.d.ts +4 -1
  40. package/dist/index.js +956 -785
  41. package/dist/index.mjs +39 -33
  42. package/dist/presets/basic/editor-header.mjs +14 -14
  43. package/dist/presets/basic/index.js +953 -784
  44. package/dist/presets/basic/index.mjs +32 -29
  45. package/dist/ui/slash-dropdown-menu/index.js +2 -2
  46. package/dist/ui/slash-dropdown-menu/index.mjs +4 -4
  47. package/dist/ui/slash-dropdown-menu/slash-dropdown-menu.js +2 -2
  48. package/dist/ui/slash-dropdown-menu/slash-dropdown-menu.mjs +2 -2
  49. package/dist/ui/slash-dropdown-menu/use-slash-dropdown-menu.js +2 -2
  50. package/dist/ui/slash-dropdown-menu/use-slash-dropdown-menu.mjs +1 -1
  51. package/package.json +25 -24
  52. package/dist/chunk-WAAH3NLG.mjs +0 -77
  53. package/dist/{chunk-QAE2D4KV.mjs → chunk-FDPXD6VC.mjs} +11 -11
@@ -0,0 +1,338 @@
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/extensions/image-upload/image-upload-view.tsx
23
+ var image_upload_view_exports = {};
24
+ __export(image_upload_view_exports, {
25
+ ImageUploadNodeView: () => ImageUploadNodeView,
26
+ default: () => image_upload_view_default
27
+ });
28
+ module.exports = __toCommonJS(image_upload_view_exports);
29
+ var import_button = require("@kopexa/button");
30
+ var import_icons = require("@kopexa/icons");
31
+ var import_theme = require("@kopexa/theme");
32
+ var import_react2 = require("@tiptap/react");
33
+ var import_react3 = require("react");
34
+ var import_react_intl2 = require("react-intl");
35
+
36
+ // src/context/editor-file-context.tsx
37
+ var import_react = require("react");
38
+ var import_jsx_runtime = require("react/jsx-runtime");
39
+ var EditorFileContext = (0, import_react.createContext)(null);
40
+ var DEFAULT_CACHE_BUFFER = 2 * 60 * 1e3;
41
+ var DEFAULT_CACHE_TTL = 10 * 60 * 1e3;
42
+ function useEditorFile() {
43
+ return (0, import_react.useContext)(EditorFileContext);
44
+ }
45
+
46
+ // src/extensions/image-upload/messages.ts
47
+ var import_react_intl = require("react-intl");
48
+ var messages = (0, import_react_intl.defineMessages)({
49
+ upload_error: {
50
+ id: "editor.image.upload_error",
51
+ defaultMessage: "Failed to upload image"
52
+ },
53
+ uploading: {
54
+ id: "editor.image.uploading",
55
+ defaultMessage: "Uploading..."
56
+ },
57
+ upload_placeholder: {
58
+ id: "editor.image.upload_placeholder",
59
+ defaultMessage: "Click to upload or drag & drop"
60
+ },
61
+ upload_hint: {
62
+ id: "editor.image.upload_hint",
63
+ defaultMessage: "PNG, JPG, GIF, WebP, SVG"
64
+ },
65
+ click_to_retry: {
66
+ id: "editor.image.click_to_retry",
67
+ defaultMessage: "Click to try again"
68
+ },
69
+ files_not_supported: {
70
+ id: "editor.image.files_not_supported",
71
+ defaultMessage: "File upload is not configured"
72
+ },
73
+ remove: {
74
+ id: "editor.image.remove",
75
+ defaultMessage: "Remove"
76
+ }
77
+ });
78
+
79
+ // src/extensions/image-upload/image-upload-view.tsx
80
+ var import_jsx_runtime2 = require("react/jsx-runtime");
81
+ function ImageUploadNodeView({ editor, node, getPos }) {
82
+ const intl = (0, import_react_intl2.useIntl)();
83
+ const fileHandler = useEditorFile();
84
+ const isEditable = (0, import_react2.useEditorState)({
85
+ editor,
86
+ selector: ({ editor: e }) => {
87
+ var _a;
88
+ return (_a = e == null ? void 0 : e.isEditable) != null ? _a : false;
89
+ }
90
+ });
91
+ const [uploadState, setUploadState] = (0, import_react3.useState)("idle");
92
+ const [uploadProgress, setUploadProgress] = (0, import_react3.useState)(0);
93
+ const [isDragOver, setIsDragOver] = (0, import_react3.useState)(false);
94
+ const fileInputRef = (0, import_react3.useRef)(null);
95
+ const handleRemove = (0, import_react3.useCallback)(() => {
96
+ const pos = getPos();
97
+ if (pos === void 0) return;
98
+ editor.commands.deleteRange({
99
+ from: pos,
100
+ to: pos + node.nodeSize
101
+ });
102
+ }, [editor, getPos, node.nodeSize]);
103
+ const handleFileSelect = (0, import_react3.useCallback)(
104
+ async (file) => {
105
+ if (!fileHandler) return;
106
+ const pos = getPos();
107
+ if (pos === void 0) return;
108
+ setUploadState("uploading");
109
+ setUploadProgress(0);
110
+ try {
111
+ const ref = await fileHandler.upload(file, (percent) => {
112
+ setUploadProgress(percent);
113
+ });
114
+ const currentPos = getPos();
115
+ if (currentPos === void 0) return;
116
+ editor.chain().focus().deleteRange({ from: currentPos, to: currentPos + node.nodeSize }).insertContentAt(currentPos, {
117
+ type: "image",
118
+ attrs: {
119
+ src: ref,
120
+ alt: file.name.replace(/\.[^/.]+$/, ""),
121
+ title: file.name.replace(/\.[^/.]+$/, "")
122
+ }
123
+ }).run();
124
+ } catch (error) {
125
+ console.error("[ImageUpload] Upload failed:", error);
126
+ setUploadState("error");
127
+ setUploadProgress(0);
128
+ }
129
+ },
130
+ [fileHandler, editor, getPos, node.nodeSize]
131
+ );
132
+ const handleInputChange = (0, import_react3.useCallback)(
133
+ (e) => {
134
+ var _a;
135
+ const file = (_a = e.target.files) == null ? void 0 : _a[0];
136
+ if (file) {
137
+ handleFileSelect(file);
138
+ }
139
+ e.target.value = "";
140
+ },
141
+ [handleFileSelect]
142
+ );
143
+ const handleDrop = (0, import_react3.useCallback)(
144
+ (e) => {
145
+ e.preventDefault();
146
+ e.stopPropagation();
147
+ setIsDragOver(false);
148
+ const file = e.dataTransfer.files[0];
149
+ if (file == null ? void 0 : file.type.startsWith("image/")) {
150
+ handleFileSelect(file);
151
+ }
152
+ },
153
+ [handleFileSelect]
154
+ );
155
+ const handleDragOver = (0, import_react3.useCallback)((e) => {
156
+ e.preventDefault();
157
+ e.stopPropagation();
158
+ }, []);
159
+ const handleDragEnter = (0, import_react3.useCallback)((e) => {
160
+ e.preventDefault();
161
+ e.stopPropagation();
162
+ setIsDragOver(true);
163
+ }, []);
164
+ const handleDragLeave = (0, import_react3.useCallback)((e) => {
165
+ e.preventDefault();
166
+ e.stopPropagation();
167
+ if (!e.currentTarget.contains(e.relatedTarget)) {
168
+ setIsDragOver(false);
169
+ }
170
+ }, []);
171
+ const handleClick = (0, import_react3.useCallback)(() => {
172
+ var _a;
173
+ if (uploadState === "idle" || uploadState === "error") {
174
+ (_a = fileInputRef.current) == null ? void 0 : _a.click();
175
+ }
176
+ }, [uploadState]);
177
+ const styles = (0, import_react3.useMemo)(
178
+ () => (0, import_theme.imagePlaceholder)({
179
+ size: "md",
180
+ variant: isDragOver ? "default" : void 0
181
+ }),
182
+ [isDragOver]
183
+ );
184
+ const errorStyles = (0, import_react3.useMemo)(
185
+ () => (0, import_theme.imagePlaceholder)({ size: "md", variant: "error" }),
186
+ []
187
+ );
188
+ const uploadingStyles = (0, import_react3.useMemo)(
189
+ () => (0, import_theme.imagePlaceholder)({ size: "md", variant: "uploading" }),
190
+ []
191
+ );
192
+ const disabledStyles = (0, import_react3.useMemo)(
193
+ () => (0, import_theme.imagePlaceholder)({ size: "md", variant: "disabled" }),
194
+ []
195
+ );
196
+ if (!fileHandler) {
197
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react2.NodeViewWrapper, { className: "my-4", "data-type": "image-upload", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: disabledStyles.root(), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: disabledStyles.content(), children: [
198
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_icons.ImageIcon, { className: disabledStyles.icon() }),
199
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: disabledStyles.text(), children: intl.formatMessage(messages.files_not_supported) }),
200
+ isEditable && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
201
+ import_button.IconButton,
202
+ {
203
+ size: "sm",
204
+ variant: "ghost",
205
+ onClick: handleRemove,
206
+ "aria-label": intl.formatMessage(messages.remove),
207
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_icons.TrashIcon, { className: "size-4" })
208
+ }
209
+ )
210
+ ] }) }) });
211
+ }
212
+ if (uploadState === "uploading") {
213
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react2.NodeViewWrapper, { className: "my-4", "data-type": "image-upload", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: uploadingStyles.root(), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: uploadingStyles.content(), children: [
214
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "relative size-12", children: [
215
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
216
+ "svg",
217
+ {
218
+ className: "size-12 -rotate-90",
219
+ viewBox: "0 0 36 36",
220
+ "aria-hidden": "true",
221
+ children: [
222
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
223
+ "circle",
224
+ {
225
+ cx: "18",
226
+ cy: "18",
227
+ r: "16",
228
+ fill: "none",
229
+ className: "stroke-muted",
230
+ strokeWidth: "2"
231
+ }
232
+ ),
233
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
234
+ "circle",
235
+ {
236
+ cx: "18",
237
+ cy: "18",
238
+ r: "16",
239
+ fill: "none",
240
+ className: "stroke-primary",
241
+ strokeWidth: "2",
242
+ strokeDasharray: 100,
243
+ strokeDashoffset: 100 - uploadProgress,
244
+ strokeLinecap: "round"
245
+ }
246
+ )
247
+ ]
248
+ }
249
+ ),
250
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "absolute inset-0 flex items-center justify-center text-xs font-medium", children: [
251
+ uploadProgress,
252
+ "%"
253
+ ] })
254
+ ] }),
255
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: uploadingStyles.text(), children: intl.formatMessage(messages.uploading) })
256
+ ] }) }) });
257
+ }
258
+ if (uploadState === "error") {
259
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react2.NodeViewWrapper, { className: "my-4", "data-type": "image-upload", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: errorStyles.root(), onClick: handleClick, children: [
260
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: errorStyles.content(), children: [
261
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_icons.AlertCircleIcon, { className: errorStyles.icon() }),
262
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: errorStyles.text(), children: intl.formatMessage(messages.upload_error) }),
263
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: errorStyles.hint(), children: intl.formatMessage(messages.click_to_retry) })
264
+ ] }),
265
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
266
+ "input",
267
+ {
268
+ ref: fileInputRef,
269
+ type: "file",
270
+ accept: "image/*",
271
+ className: "hidden",
272
+ onChange: handleInputChange
273
+ }
274
+ ),
275
+ isEditable && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
276
+ import_button.IconButton,
277
+ {
278
+ size: "sm",
279
+ variant: "ghost",
280
+ className: errorStyles.removeButton(),
281
+ onClick: (e) => {
282
+ e.stopPropagation();
283
+ handleRemove();
284
+ },
285
+ "aria-label": intl.formatMessage(messages.remove),
286
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_icons.TrashIcon, { className: "size-3.5" })
287
+ }
288
+ )
289
+ ] }) });
290
+ }
291
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react2.NodeViewWrapper, { className: "my-4", "data-type": "image-upload", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
292
+ "div",
293
+ {
294
+ className: `${styles.root()} ${isDragOver ? "border-primary bg-primary/10" : ""}`,
295
+ onClick: handleClick,
296
+ onDrop: handleDrop,
297
+ onDragOver: handleDragOver,
298
+ onDragEnter: handleDragEnter,
299
+ onDragLeave: handleDragLeave,
300
+ children: [
301
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: styles.content(), children: [
302
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_icons.UploadIcon, { className: styles.icon() }),
303
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: styles.text(), children: intl.formatMessage(messages.upload_placeholder) }),
304
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: styles.hint(), children: intl.formatMessage(messages.upload_hint) })
305
+ ] }),
306
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
307
+ "input",
308
+ {
309
+ ref: fileInputRef,
310
+ type: "file",
311
+ accept: "image/*",
312
+ className: "hidden",
313
+ onChange: handleInputChange
314
+ }
315
+ ),
316
+ isEditable && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
317
+ import_button.IconButton,
318
+ {
319
+ size: "sm",
320
+ variant: "ghost",
321
+ className: styles.removeButton(),
322
+ onClick: (e) => {
323
+ e.stopPropagation();
324
+ handleRemove();
325
+ },
326
+ "aria-label": intl.formatMessage(messages.remove),
327
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_icons.TrashIcon, { className: "size-3.5" })
328
+ }
329
+ )
330
+ ]
331
+ }
332
+ ) });
333
+ }
334
+ var image_upload_view_default = ImageUploadNodeView;
335
+ // Annotate the CommonJS export names for ESM import in node:
336
+ 0 && (module.exports = {
337
+ ImageUploadNodeView
338
+ });
@@ -0,0 +1,12 @@
1
+ "use client";
2
+ "use client";
3
+ import {
4
+ ImageUploadNodeView,
5
+ image_upload_view_default
6
+ } from "../../chunk-EAAQE5ZV.mjs";
7
+ import "../../chunk-DSBJFMHK.mjs";
8
+ import "../../chunk-VRQ6OSAZ.mjs";
9
+ export {
10
+ ImageUploadNodeView,
11
+ image_upload_view_default as default
12
+ };
@@ -0,0 +1,46 @@
1
+ import { Node } from '@tiptap/core';
2
+ export { default as ImageUploadNodeView } from './image-upload-view.mjs';
3
+ export { messages as imageUploadMessages } from './messages.mjs';
4
+ import 'react/jsx-runtime';
5
+ import '@tiptap/react';
6
+
7
+ interface ImageUploadNodeOptions {
8
+ /**
9
+ * Allowed MIME types for upload
10
+ * @default ["image/*"]
11
+ */
12
+ accept: string;
13
+ /**
14
+ * Maximum file size in bytes (0 = unlimited)
15
+ * @default 0
16
+ */
17
+ maxSize: number;
18
+ /**
19
+ * HTML attributes to add to the wrapper element
20
+ */
21
+ HTMLAttributes: Record<string, unknown>;
22
+ }
23
+ declare module "@tiptap/core" {
24
+ interface Commands<ReturnType> {
25
+ imageUpload: {
26
+ /**
27
+ * Insert an image upload placeholder
28
+ */
29
+ setImageUpload: () => ReturnType;
30
+ };
31
+ }
32
+ }
33
+ /**
34
+ * ImageUploadNode - Upload placeholder that converts to a regular image node
35
+ *
36
+ * This extension provides a file upload UI that, after successful upload,
37
+ * replaces itself with a standard `image` node from @tiptap/extension-image.
38
+ *
39
+ * This separation allows:
40
+ * - Clean coexistence with the standard image extension
41
+ * - Upload UI only when needed
42
+ * - Standard image handling for display
43
+ */
44
+ declare const ImageUploadNode: Node<ImageUploadNodeOptions, any>;
45
+
46
+ export { ImageUploadNode, type ImageUploadNodeOptions };
@@ -0,0 +1,46 @@
1
+ import { Node } from '@tiptap/core';
2
+ export { default as ImageUploadNodeView } from './image-upload-view.js';
3
+ export { messages as imageUploadMessages } from './messages.js';
4
+ import 'react/jsx-runtime';
5
+ import '@tiptap/react';
6
+
7
+ interface ImageUploadNodeOptions {
8
+ /**
9
+ * Allowed MIME types for upload
10
+ * @default ["image/*"]
11
+ */
12
+ accept: string;
13
+ /**
14
+ * Maximum file size in bytes (0 = unlimited)
15
+ * @default 0
16
+ */
17
+ maxSize: number;
18
+ /**
19
+ * HTML attributes to add to the wrapper element
20
+ */
21
+ HTMLAttributes: Record<string, unknown>;
22
+ }
23
+ declare module "@tiptap/core" {
24
+ interface Commands<ReturnType> {
25
+ imageUpload: {
26
+ /**
27
+ * Insert an image upload placeholder
28
+ */
29
+ setImageUpload: () => ReturnType;
30
+ };
31
+ }
32
+ }
33
+ /**
34
+ * ImageUploadNode - Upload placeholder that converts to a regular image node
35
+ *
36
+ * This extension provides a file upload UI that, after successful upload,
37
+ * replaces itself with a standard `image` node from @tiptap/extension-image.
38
+ *
39
+ * This separation allows:
40
+ * - Clean coexistence with the standard image extension
41
+ * - Upload UI only when needed
42
+ * - Standard image handling for display
43
+ */
44
+ declare const ImageUploadNode: Node<ImageUploadNodeOptions, any>;
45
+
46
+ export { ImageUploadNode, type ImageUploadNodeOptions };