@ctzhian/tiptap 2.13.4 → 2.13.6-beta.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.
@@ -10,15 +10,16 @@ function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" !=
10
10
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
11
11
  import { FloatingPopover } from "../../../component/FloatingPopover";
12
12
  import { IframeTypeEnums } from "../../../contants/enums";
13
- import { extractSrcFromIframe } from "../../../util";
13
+ import { extractSrcFromIframe, normalizeBilibiliAutoplay } from "../../../util";
14
14
  import { Box, Button, Stack, TextField } from "@mui/material";
15
15
  import { NodeViewWrapper } from "@tiptap/react";
16
16
  import React, { useState } from "react";
17
17
  var InsertIframe = function InsertIframe(_ref) {
18
+ var _attrs$src;
18
19
  var attrs = _ref.attrs,
19
20
  updateAttributes = _ref.updateAttributes,
20
21
  onValidateUrl = _ref.onValidateUrl;
21
- var _useState = useState(attrs.src || ''),
22
+ var _useState = useState((_attrs$src = attrs.src) !== null && _attrs$src !== void 0 ? _attrs$src : ''),
22
23
  _useState2 = _slicedToArray(_useState, 2),
23
24
  editUrl = _useState2[0],
24
25
  setEditUrl = _useState2[1];
@@ -55,6 +56,9 @@ var InsertIframe = function InsertIframe(_ref) {
55
56
  case 7:
56
57
  validatedUrl = _context.sent;
57
58
  case 8:
59
+ if (attrs.type === 'bilibili') {
60
+ validatedUrl = normalizeBilibiliAutoplay(validatedUrl);
61
+ }
58
62
  updateAttributes({
59
63
  src: validatedUrl,
60
64
  width: attrs.width,
@@ -63,16 +67,16 @@ var InsertIframe = function InsertIframe(_ref) {
63
67
  type: attrs.type
64
68
  });
65
69
  handleClosePopover();
66
- _context.next = 14;
70
+ _context.next = 15;
67
71
  break;
68
- case 12:
69
- _context.prev = 12;
72
+ case 13:
73
+ _context.prev = 13;
70
74
  _context.t0 = _context["catch"](2);
71
- case 14:
75
+ case 15:
72
76
  case "end":
73
77
  return _context.stop();
74
78
  }
75
- }, _callee, null, [[2, 12]]);
79
+ }, _callee, null, [[2, 13]]);
76
80
  }));
77
81
  return function handleInsert() {
78
82
  return _ref2.apply(this, arguments);
@@ -16,13 +16,14 @@ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
16
16
  import { ActionDropdown, FloatingPopover, HoverPopover } from "../../../component";
17
17
  import { AlignCenterIcon, AlignLeftIcon, AlignRightIcon, DeleteLineIcon, EditLineIcon } from "../../../component/Icons";
18
18
  import { ToolbarItem } from "../../../component/Toolbar";
19
- import { extractSrcFromIframe } from "../../../util";
19
+ import { extractSrcFromIframe, normalizeBilibiliAutoplay } from "../../../util";
20
20
  import { alpha, Box, Button, Divider, Stack, TextField, useTheme } from "@mui/material";
21
21
  import { NodeViewWrapper } from '@tiptap/react';
22
22
  import React, { useCallback, useEffect, useRef, useState } from "react";
23
23
  import InsertIframe from "./Insert";
24
24
  import ReadonlyIframe from "./Readonly";
25
25
  var IframeViewWrapper = function IframeViewWrapper(_ref) {
26
+ var _attrs$src;
26
27
  var editor = _ref.editor,
27
28
  node = _ref.node,
28
29
  updateAttributes = _ref.updateAttributes,
@@ -51,7 +52,7 @@ var IframeViewWrapper = function IframeViewWrapper(_ref) {
51
52
  var dragStartWidthRef = useRef(0);
52
53
  var dragStartHeightRef = useRef(0);
53
54
  var maxWidthRef = useRef(0);
54
- var _useState7 = useState(attrs.src),
55
+ var _useState7 = useState((_attrs$src = attrs.src) !== null && _attrs$src !== void 0 ? _attrs$src : ''),
55
56
  _useState8 = _slicedToArray(_useState7, 2),
56
57
  editSrc = _useState8[0],
57
58
  setEditSrc = _useState8[1];
@@ -64,6 +65,8 @@ var IframeViewWrapper = function IframeViewWrapper(_ref) {
64
65
  keepHoverPopoverOpen = _useState12[0],
65
66
  setKeepHoverPopoverOpen = _useState12[1];
66
67
  var handleShowPopover = function handleShowPopover() {
68
+ var _attrs$src2;
69
+ setEditSrc((_attrs$src2 = attrs.src) !== null && _attrs$src2 !== void 0 ? _attrs$src2 : '');
67
70
  setKeepHoverPopoverOpen(true);
68
71
  setAnchorEl(editButtonRef.current);
69
72
  };
@@ -179,7 +182,8 @@ var IframeViewWrapper = function IframeViewWrapper(_ref) {
179
182
  setDragCorner(null);
180
183
  }, []);
181
184
  useEffect(function () {
182
- setEditSrc(attrs.src);
185
+ var _attrs$src3;
186
+ setEditSrc((_attrs$src3 = attrs.src) !== null && _attrs$src3 !== void 0 ? _attrs$src3 : '');
183
187
  }, [attrs.src]);
184
188
  useEffect(function () {
185
189
  if (isDragging) {
@@ -212,13 +216,15 @@ var IframeViewWrapper = function IframeViewWrapper(_ref) {
212
216
  case 6:
213
217
  validatedUrl = _context.sent;
214
218
  case 7:
219
+ if (attrs.type === 'bilibili') {
220
+ validatedUrl = normalizeBilibiliAutoplay(validatedUrl);
221
+ }
215
222
  updateAttributes({
216
223
  src: validatedUrl,
217
224
  width: attrs.width,
218
225
  height: attrs.height,
219
226
  align: attrs.align
220
227
  });
221
- setEditSrc(validatedUrl);
222
228
  _context.next = 13;
223
229
  break;
224
230
  case 11:
@@ -6,5 +6,5 @@ type InsertImageProps = {
6
6
  attrs: ImageAttributes;
7
7
  updateAttributes: (attrs: ImageAttributes) => void;
8
8
  } & EditorFnProps;
9
- declare const InsertImage: ({ selected, attrs, updateAttributes, onUpload, onError, onValidateUrl }: InsertImageProps) => React.JSX.Element;
9
+ declare const InsertImage: ({ selected, attrs, updateAttributes, onUpload, onUploadImgUrl, onError, onValidateUrl }: InsertImageProps) => React.JSX.Element;
10
10
  export default InsertImage;
@@ -24,6 +24,7 @@ var InsertImage = function InsertImage(_ref) {
24
24
  attrs = _ref.attrs,
25
25
  updateAttributes = _ref.updateAttributes,
26
26
  onUpload = _ref.onUpload,
27
+ onUploadImgUrl = _ref.onUploadImgUrl,
27
28
  onError = _ref.onError,
28
29
  onValidateUrl = _ref.onValidateUrl;
29
30
  var _useState = useState(attrs.src || ''),
@@ -155,7 +156,7 @@ var InsertImage = function InsertImage(_ref) {
155
156
  }();
156
157
  var handleInsertLink = /*#__PURE__*/function () {
157
158
  var _ref4 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3() {
158
- var validatedUrl;
159
+ var finalUrl, abortController;
159
160
  return _regeneratorRuntime().wrap(function _callee3$(_context3) {
160
161
  while (1) switch (_context3.prev = _context3.next) {
161
162
  case 0:
@@ -166,31 +167,54 @@ var InsertImage = function InsertImage(_ref) {
166
167
  return _context3.abrupt("return");
167
168
  case 2:
168
169
  _context3.prev = 2;
169
- validatedUrl = editSrc.trim();
170
+ finalUrl = editSrc.trim();
170
171
  if (!onValidateUrl) {
171
172
  _context3.next = 8;
172
173
  break;
173
174
  }
174
175
  _context3.next = 7;
175
- return Promise.resolve(onValidateUrl(validatedUrl, 'image'));
176
+ return Promise.resolve(onValidateUrl(finalUrl, 'image'));
176
177
  case 7:
177
- validatedUrl = _context3.sent;
178
+ finalUrl = _context3.sent;
178
179
  case 8:
179
- _context3.next = 10;
180
- return updateImageAttributes(validatedUrl, editTitle.trim());
181
- case 10:
180
+ if (!(onUploadImgUrl && (finalUrl.startsWith('http://') || finalUrl.startsWith('https://') || finalUrl.startsWith('//')))) {
181
+ _context3.next = 23;
182
+ break;
183
+ }
184
+ setUploading(true);
182
185
  handleClosePopover();
183
- _context3.next = 16;
186
+ _context3.prev = 11;
187
+ abortController = new AbortController();
188
+ _context3.next = 15;
189
+ return onUploadImgUrl(finalUrl, abortController.signal);
190
+ case 15:
191
+ finalUrl = _context3.sent;
192
+ _context3.next = 18;
193
+ return updateImageAttributes(finalUrl, editTitle.trim());
194
+ case 18:
195
+ _context3.prev = 18;
196
+ setUploading(false);
197
+ return _context3.finish(18);
198
+ case 21:
199
+ _context3.next = 26;
184
200
  break;
185
- case 13:
186
- _context3.prev = 13;
201
+ case 23:
202
+ _context3.next = 25;
203
+ return updateImageAttributes(finalUrl, editTitle.trim());
204
+ case 25:
205
+ handleClosePopover();
206
+ case 26:
207
+ _context3.next = 31;
208
+ break;
209
+ case 28:
210
+ _context3.prev = 28;
187
211
  _context3.t0 = _context3["catch"](2);
188
212
  onError === null || onError === void 0 || onError(_context3.t0);
189
- case 16:
213
+ case 31:
190
214
  case "end":
191
215
  return _context3.stop();
192
216
  }
193
- }, _callee3, null, [[2, 13]]);
217
+ }, _callee3, null, [[2, 28], [11,, 18, 21]]);
194
218
  }));
195
219
  return function handleInsertLink() {
196
220
  return _ref4.apply(this, arguments);
@@ -77,6 +77,7 @@ var ImageViewWrapper = function ImageViewWrapper(_ref) {
77
77
  deleteNode = _ref.deleteNode,
78
78
  selected = _ref.selected,
79
79
  onUpload = _ref.onUpload,
80
+ onUploadImgUrl = _ref.onUploadImgUrl,
80
81
  _onError = _ref.onError,
81
82
  onValidateUrl = _ref.onValidateUrl,
82
83
  getPos = _ref.getPos;
@@ -304,6 +305,7 @@ var ImageViewWrapper = function ImageViewWrapper(_ref) {
304
305
  selected: selected,
305
306
  attrs: attrs,
306
307
  onUpload: onUpload,
308
+ onUploadImgUrl: onUploadImgUrl,
307
309
  updateAttributes: updateAttributes,
308
310
  onError: _onError,
309
311
  onValidateUrl: onValidateUrl
@@ -7,6 +7,6 @@ export interface UploadProgressAttributes {
7
7
  tempId: string;
8
8
  }
9
9
  export declare const getFileIcon: (fileType: string) => React.JSX.Element;
10
- export declare const getFileTypeText: (fileType: string) => "图片" | "视频" | "音频" | "文件";
10
+ export declare const getFileTypeText: (fileType: string) => "音频" | "图片" | "视频" | "文件";
11
11
  declare const UploadProgressView: React.FC<NodeViewProps>;
12
12
  export default UploadProgressView;
@@ -1,2 +1,2 @@
1
1
  import { GetExtensionsProps } from '../type';
2
- export declare const getExtensions: ({ limit, exclude, extensions: extensionsProps, editable, mentionItems, baseUrl, onMentionFilter, onUpload, onError, onTocUpdate, onAiWritingGetSuggestion, onValidateUrl, placeholder, mermaidOptions, youtubeOptions, tableOfContentsOptions, }: GetExtensionsProps) => any;
2
+ export declare const getExtensions: ({ limit, exclude, extensions: extensionsProps, editable, mentionItems, baseUrl, onMentionFilter, onUpload, onUploadImgUrl, onError, onTocUpdate, onAiWritingGetSuggestion, onValidateUrl, placeholder, mermaidOptions, youtubeOptions, tableOfContentsOptions, }: GetExtensionsProps) => any;
@@ -26,6 +26,7 @@ export var getExtensions = function getExtensions(_ref) {
26
26
  baseUrl = _ref$baseUrl === void 0 ? '' : _ref$baseUrl,
27
27
  onMentionFilter = _ref.onMentionFilter,
28
28
  onUpload = _ref.onUpload,
29
+ onUploadImgUrl = _ref.onUploadImgUrl,
29
30
  onError = _ref.onError,
30
31
  onTocUpdate = _ref.onTocUpdate,
31
32
  onAiWritingGetSuggestion = _ref.onAiWritingGetSuggestion,
@@ -76,6 +77,7 @@ export var getExtensions = function getExtensions(_ref) {
76
77
  }), ImageExtension({
77
78
  baseUrl: baseUrl,
78
79
  onUpload: onUpload,
80
+ onUploadImgUrl: onUploadImgUrl,
79
81
  onError: onError,
80
82
  onValidateUrl: onValidateUrl
81
83
  }), InlineAttachmentExtension({
@@ -190,6 +190,7 @@ var customImage = function customImage(props) {
190
190
  return ReactNodeViewRenderer(function (renderProps) {
191
191
  return ImageViewWrapper(_objectSpread(_objectSpread({}, renderProps), {}, {
192
192
  onUpload: props.onUpload,
193
+ onUploadImgUrl: props.onUploadImgUrl,
193
194
  onError: props.onError,
194
195
  onValidateUrl: props.onValidateUrl
195
196
  }));
@@ -202,7 +203,7 @@ var customImage = function customImage(props) {
202
203
  props: {
203
204
  handlePaste: function handlePaste(view, event) {
204
205
  var _event$clipboardData, _event$clipboardData2, _event$clipboardData3;
205
- if (!props.onUpload) return false;
206
+ if (!props.onUpload && !props.onUploadImgUrl) return false;
206
207
  var items = Array.from(((_event$clipboardData = event.clipboardData) === null || _event$clipboardData === void 0 ? void 0 : _event$clipboardData.items) || []);
207
208
  var imageFiles = items.map(function (item) {
208
209
  return item.getAsFile();
@@ -434,36 +435,99 @@ var customImage = function customImage(props) {
434
435
  }
435
436
  var imageUrls = extractImageUrls(htmlData);
436
437
 
437
- // 如果找到图片 URL,下载并处理图片
438
+ // 如果找到图片 URL,优先通过 onUploadImgUrl 走后端上传,否则前端下载再上传
438
439
  if (imageUrls.length > 0) {
439
440
  event.preventDefault();
440
441
  _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3() {
441
- var downloadedFiles, validFiles;
442
+ var abortController, newUrls, modifiedHtml, _parsed$content2, extensions, parsed, _props$onError, _props$onError2, _parsed$content3, _extensions, _parsed, downloadedFiles, validFiles, _parsed2$content, _extensions2, _parsed2;
442
443
  return _regeneratorRuntime().wrap(function _callee3$(_context3) {
443
444
  while (1) switch (_context3.prev = _context3.next) {
444
445
  case 0:
445
- _context3.next = 2;
446
+ if (!props.onUploadImgUrl) {
447
+ _context3.next = 17;
448
+ break;
449
+ }
450
+ abortController = new AbortController();
451
+ _context3.prev = 2;
452
+ _context3.next = 5;
453
+ return Promise.all(imageUrls.map(function (url) {
454
+ return props.onUploadImgUrl(url, abortController.signal);
455
+ }));
456
+ case 5:
457
+ newUrls = _context3.sent;
458
+ modifiedHtml = htmlData;
459
+ imageUrls.forEach(function (oldUrl, i) {
460
+ modifiedHtml = modifiedHtml.split(oldUrl).join(newUrls[i]);
461
+ });
462
+ try {
463
+ extensions = editor.extensionManager.extensions;
464
+ parsed = generateJSON(modifiedHtml, extensions);
465
+ if (parsed !== null && parsed !== void 0 && (_parsed$content2 = parsed.content) !== null && _parsed$content2 !== void 0 && _parsed$content2.length) {
466
+ editor.chain().insertContentAt({
467
+ from: from,
468
+ to: to
469
+ }, parsed).focus().run();
470
+ }
471
+ } catch (parseError) {
472
+ console.error('[图片粘贴] 解析上传后的 HTML 失败:', parseError);
473
+ (_props$onError = props.onError) === null || _props$onError === void 0 || _props$onError.call(props, parseError);
474
+ }
475
+ _context3.next = 16;
476
+ break;
477
+ case 11:
478
+ _context3.prev = 11;
479
+ _context3.t0 = _context3["catch"](2);
480
+ console.error('[图片粘贴] URL 上传失败:', _context3.t0);
481
+ (_props$onError2 = props.onError) === null || _props$onError2 === void 0 || _props$onError2.call(props, _context3.t0);
482
+ try {
483
+ _extensions = editor.extensionManager.extensions;
484
+ _parsed = generateJSON(htmlData, _extensions);
485
+ if (_parsed !== null && _parsed !== void 0 && (_parsed$content3 = _parsed.content) !== null && _parsed$content3 !== void 0 && _parsed$content3.length) {
486
+ editor.chain().insertContentAt({
487
+ from: from,
488
+ to: to
489
+ }, _parsed).focus().run();
490
+ }
491
+ } catch (fallbackError) {
492
+ // 解析失败则不再处理
493
+ }
494
+ case 16:
495
+ return _context3.abrupt("return");
496
+ case 17:
497
+ _context3.next = 19;
446
498
  return Promise.all(imageUrls.map(function (url, i) {
447
499
  return downloadImageAsFile(url, i);
448
500
  }));
449
- case 2:
501
+ case 19:
450
502
  downloadedFiles = _context3.sent;
451
503
  validFiles = downloadedFiles.filter(function (f) {
452
504
  return f !== null;
453
505
  });
454
506
  if (!(validFiles.length === 0)) {
455
- _context3.next = 6;
507
+ _context3.next = 24;
456
508
  break;
457
509
  }
510
+ try {
511
+ _extensions2 = editor.extensionManager.extensions;
512
+ _parsed2 = generateJSON(htmlData, _extensions2);
513
+ if (_parsed2 !== null && _parsed2 !== void 0 && (_parsed2$content = _parsed2.content) !== null && _parsed2$content !== void 0 && _parsed2$content.length) {
514
+ editor.chain().insertContentAt({
515
+ from: from,
516
+ to: to
517
+ }, _parsed2).focus().run();
518
+ }
519
+ } catch (err) {
520
+ // 解析失败则不再处理
521
+ }
458
522
  return _context3.abrupt("return");
459
- case 6:
460
- _context3.next = 8;
523
+ case 24:
524
+ _context3.next = 26;
461
525
  return processImagePaste(validFiles, htmlData, from, to);
462
- case 8:
526
+ case 26:
463
527
  case "end":
464
528
  return _context3.stop();
465
529
  }
466
- }, _callee3);
530
+ }, _callee3, null, [[2, 11]]);
467
531
  }))();
468
532
  return true;
469
533
  }
@@ -471,12 +535,12 @@ var customImage = function customImage(props) {
471
535
  // 没有图片 URL,尝试处理 HTML 或纯文本
472
536
  // 先尝试使用 generateJSON 解析 HTML
473
537
  try {
474
- var _parsed$content2;
538
+ var _parsed$content4;
475
539
  var extensions = editor.extensionManager.extensions;
476
540
  var parsed = generateJSON(htmlData, extensions);
477
541
 
478
542
  // 检查解析后的内容是否包含有效文本
479
- if (parsed !== null && parsed !== void 0 && (_parsed$content2 = parsed.content) !== null && _parsed$content2 !== void 0 && _parsed$content2.length && hasValidTextContent(parsed.content)) {
543
+ if (parsed !== null && parsed !== void 0 && (_parsed$content4 = parsed.content) !== null && _parsed$content4 !== void 0 && _parsed$content4.length && hasValidTextContent(parsed.content)) {
480
544
  event.preventDefault();
481
545
  editor.chain().insertContentAt({
482
546
  from: from,
@@ -496,7 +560,9 @@ var customImage = function customImage(props) {
496
560
  return false; // 让默认粘贴处理
497
561
  }
498
562
 
499
- // 有图片文件,直接处理
563
+ // 有图片文件,直接处理(需要 onUpload)
564
+ if (imageFiles.length > 0 && !props.onUpload) return false;
565
+
500
566
  // 如果包含表格,让默认粘贴处理
501
567
  if (htmlData !== null && htmlData !== void 0 && htmlData.trim()) {
502
568
  var htmlLower = htmlData.toLowerCase();
@@ -1,4 +1,4 @@
1
1
  import { UseTiptapProps, UseTiptapReturn } from "../type";
2
2
  import { UseEditorOptions } from '@tiptap/react';
3
- declare const useTiptap: ({ editable, contentType, onSave, onError, onUpload, baseUrl, ...options }: UseTiptapProps & UseEditorOptions) => UseTiptapReturn;
3
+ declare const useTiptap: ({ editable, contentType, onSave, onError, onUpload, onUploadImgUrl, baseUrl, ...options }: UseTiptapProps & UseEditorOptions) => UseTiptapReturn;
4
4
  export default useTiptap;
@@ -1,5 +1,5 @@
1
1
  function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
2
- var _excluded = ["editable", "contentType", "onSave", "onError", "onUpload", "baseUrl"];
2
+ var _excluded = ["editable", "contentType", "onSave", "onError", "onUpload", "onUploadImgUrl", "baseUrl"];
3
3
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
4
4
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
5
5
  function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
@@ -19,6 +19,7 @@ var useTiptap = function useTiptap(_ref) {
19
19
  onSave = _ref.onSave,
20
20
  onError = _ref.onError,
21
21
  onUpload = _ref.onUpload,
22
+ onUploadImgUrl = _ref.onUploadImgUrl,
22
23
  _ref$baseUrl = _ref.baseUrl,
23
24
  baseUrl = _ref$baseUrl === void 0 ? '' : _ref$baseUrl,
24
25
  options = _objectWithoutProperties(_ref, _excluded);
@@ -27,11 +28,17 @@ var useTiptap = function useTiptap(_ref) {
27
28
  return withBaseUrl(url, baseUrl);
28
29
  });
29
30
  } : undefined;
31
+ var handleUploadImgUrl = onUploadImgUrl ? function (url, abortSignal) {
32
+ return onUploadImgUrl(url, abortSignal).then(function (newUrl) {
33
+ return withBaseUrl(newUrl, baseUrl);
34
+ });
35
+ } : undefined;
30
36
  var extensions = getExtensions(_objectSpread({
31
37
  editable: editable,
32
38
  onError: onError,
33
39
  baseUrl: baseUrl,
34
- onUpload: handleUpload
40
+ onUpload: handleUpload,
41
+ onUploadImgUrl: handleUploadImgUrl
35
42
  }, options));
36
43
  var editor = useEditor(_objectSpread(_objectSpread(_objectSpread({
37
44
  editable: editable,
@@ -55,6 +55,8 @@ export type ToolbarItemType = {
55
55
  export type UploadFunction = (file: File, onProgress?: (event: {
56
56
  progress: number;
57
57
  }) => void, abortSignal?: AbortSignal) => Promise<string>;
58
+ /** 图片 URL 上传:将图片链接交由后端处理并返回新 URL,可随时通过 abortSignal 中止请求 */
59
+ export type UploadImgUrlFunction = (url: string, abortSignal?: AbortSignal) => Promise<string>;
58
60
  export type TipType = 'error' | 'success' | 'info' | 'warning';
59
61
  export type OnTipFunction = (type: TipType, tip: string) => void;
60
62
  export type EditorProps = {
@@ -85,6 +87,10 @@ export type EditorFnProps = {
85
87
  * 上传处理
86
88
  */
87
89
  onUpload?: UploadFunction;
90
+ /**
91
+ * 图片链接上传:当为图片 URL 时,直接交由后端处理而非前端下载再上传
92
+ */
93
+ onUploadImgUrl?: UploadImgUrlFunction;
88
94
  /**
89
95
  * 目录更新
90
96
  */
@@ -25,3 +25,11 @@ export declare const getLinkAttributesWithSelectedText: (editor: Editor) => {
25
25
  title?: string;
26
26
  };
27
27
  export declare const extractSrcFromIframe: (input: string) => string;
28
+ /**
29
+ * 将 B 站链接的 autoplay 统一为 0,避免默认自动播放
30
+ * - autoplay=1 改为 0
31
+ * - autoplay=0 不处理
32
+ * - 无 autoplay 参数则添加 &autoplay=0
33
+ * 支持协议相对地址(//player.bilibili.com/...),会先转为 https: 再解析
34
+ */
35
+ export declare const normalizeBilibiliAutoplay: (url: string) => string;
@@ -134,4 +134,32 @@ export var extractSrcFromIframe = function extractSrcFromIframe(input) {
134
134
  return iframeMatch[1].trim();
135
135
  }
136
136
  return trimmed;
137
+ };
138
+
139
+ /**
140
+ * 将 B 站链接的 autoplay 统一为 0,避免默认自动播放
141
+ * - autoplay=1 改为 0
142
+ * - autoplay=0 不处理
143
+ * - 无 autoplay 参数则添加 &autoplay=0
144
+ * 支持协议相对地址(//player.bilibili.com/...),会先转为 https: 再解析
145
+ */
146
+ export var normalizeBilibiliAutoplay = function normalizeBilibiliAutoplay(url) {
147
+ var trimmed = url.trim();
148
+ if (!trimmed) return trimmed;
149
+ try {
150
+ // 处理协议相对地址(//player.bilibili.com/...)和相对路径
151
+ var urlToParse = trimmed.startsWith('//') ? 'https:' + trimmed : /^https?:\/\//i.test(trimmed) ? trimmed : 'https://' + trimmed;
152
+ var u = new URL(urlToParse);
153
+ var host = u.hostname.toLowerCase();
154
+ if (!host.includes('bilibili.com') && !host.includes('b23.tv')) {
155
+ return trimmed;
156
+ }
157
+ var autoplay = u.searchParams.get('autoplay');
158
+ if (autoplay !== '0') {
159
+ u.searchParams.set('autoplay', '0');
160
+ }
161
+ return u.toString();
162
+ } catch (_unused) {
163
+ return trimmed;
164
+ }
137
165
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ctzhian/tiptap",
3
- "version": "2.13.4",
3
+ "version": "2.13.6-beta.0",
4
4
  "description": "基于 Tiptap 二次开发的编辑器组件",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",