@ctzhian/tiptap 2.0.0 → 2.1.1

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 (68) hide show
  1. package/dist/Editor/demo.js +151 -123
  2. package/dist/EditorToolbar/index.js +11 -9
  3. package/dist/asset/css/index.css +7 -9
  4. package/dist/component/ActionDropdown/index.d.ts +5 -0
  5. package/dist/component/ActionDropdown/index.js +8 -3
  6. package/dist/component/FloatingPopover/index.d.ts +2 -2
  7. package/dist/component/HoverPopover/index.d.ts +2 -0
  8. package/dist/component/HoverPopover/index.js +22 -3
  9. package/dist/component/Icons/{expand-horizontal-line.js → expand-horizontal-line-icon.js} +1 -1
  10. package/dist/component/Icons/index.d.ts +8 -2
  11. package/dist/component/Icons/index.js +9 -3
  12. package/dist/component/Icons/skip-down-icon.d.ts +6 -0
  13. package/dist/component/Icons/skip-down-icon.js +13 -0
  14. package/dist/component/Icons/skip-left-icon.d.ts +6 -0
  15. package/dist/component/Icons/skip-left-icon.js +13 -0
  16. package/dist/component/Icons/skip-right-icon.d.ts +6 -0
  17. package/dist/component/Icons/skip-right-icon.js +13 -0
  18. package/dist/component/Icons/skip-up-icon.d.ts +6 -0
  19. package/dist/component/Icons/skip-up-icon.js +13 -0
  20. package/dist/component/Icons/volume-down-line-icon.d.ts +6 -0
  21. package/dist/component/Icons/volume-down-line-icon.js +13 -0
  22. package/dist/extension/component/Alert/index.js +141 -137
  23. package/dist/extension/component/Attachment/AttachmentContent.d.ts +0 -1
  24. package/dist/extension/component/Attachment/AttachmentContent.js +33 -8
  25. package/dist/extension/component/Attachment/index.js +21 -12
  26. package/dist/extension/component/Audio/AudioPlayer.d.ts +8 -0
  27. package/dist/extension/component/Audio/{Readonly.js → AudioPlayer.js} +129 -175
  28. package/dist/extension/component/Audio/index.js +93 -462
  29. package/dist/extension/component/Flow/Edit.d.ts +1 -1
  30. package/dist/extension/component/Flow/Edit.js +3 -31
  31. package/dist/extension/component/Flow/index.js +20 -19
  32. package/dist/extension/component/Image/index.d.ts +1 -0
  33. package/dist/extension/component/Image/index.js +16 -2
  34. package/dist/extension/component/Link/LinkContent.js +2 -0
  35. package/dist/extension/component/Link/index.js +1 -1
  36. package/dist/extension/component/TableCellHandleMenu/index.js +60 -3
  37. package/dist/extension/component/TableHandle/TableHandleAddButton.d.ts +14 -0
  38. package/dist/extension/component/TableHandle/TableHandleAddButton.js +87 -0
  39. package/dist/extension/component/TableHandle/TableHandleMenu.css +0 -1
  40. package/dist/extension/component/TableHandle/TableHandleMenu.js +7 -6
  41. package/dist/extension/component/TableHandle/index.js +53 -3
  42. package/dist/extension/component/TableSelectionOverlay/index.js +4 -12
  43. package/dist/extension/component/UploadProgress/index.d.ts +1 -1
  44. package/dist/extension/component/Video/Insert.js +4 -2
  45. package/dist/extension/component/Video/Readonly.js +4 -11
  46. package/dist/extension/component/Video/index.d.ts +2 -1
  47. package/dist/extension/component/Video/index.js +456 -65
  48. package/dist/extension/extension/ImeComposition.d.ts +2 -0
  49. package/dist/extension/extension/ImeComposition.js +145 -0
  50. package/dist/extension/extension/index.d.ts +1 -0
  51. package/dist/extension/extension/index.js +1 -0
  52. package/dist/extension/index.js +2 -2
  53. package/dist/extension/node/CodeBlockLowlight.js +3 -2
  54. package/dist/extension/node/Flow/index.d.ts +0 -3
  55. package/dist/extension/node/Flow/index.js +7 -4
  56. package/dist/extension/node/Link/index.js +4 -3
  57. package/dist/extension/node/Table.js +18 -82
  58. package/dist/extension/node/TableOfContents/index.d.ts +5 -3
  59. package/dist/extension/node/TableOfContents/index.js +22 -2
  60. package/dist/extension/node/Video.d.ts +1 -0
  61. package/dist/extension/node/Video.js +38 -6
  62. package/dist/hook/index.js +1 -1
  63. package/dist/index.css +17 -20
  64. package/dist/util/index.d.ts +9 -0
  65. package/dist/util/index.js +26 -0
  66. package/package.json +1 -1
  67. package/dist/extension/component/Audio/Readonly.d.ts +0 -8
  68. /package/dist/component/Icons/{expand-horizontal-line.d.ts → expand-horizontal-line-icon.d.ts} +0 -0
@@ -0,0 +1,145 @@
1
+ function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
2
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
3
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
4
+ import { Extension } from '@tiptap/core';
5
+ import { Plugin, PluginKey } from '@tiptap/pm/state';
6
+
7
+ /**
8
+ * Extension to fix IME (Input Method Editor) composition issues
9
+ *
10
+ * This extension provides basic IME composition support by tracking composition state
11
+ * and preventing keyboard handlers from interrupting IME input.
12
+ *
13
+ * Also fixes Safari-specific issue where composition text is deleted after composition ends.
14
+ * This Safari bug occurs at any input position (not just in tables), so this extension
15
+ * provides a global fix for all editor instances.
16
+ */
17
+ var imeCompositionPluginKey = new PluginKey('imeComposition');
18
+ export var ImeComposition = Extension.create({
19
+ name: 'imeComposition',
20
+ addProseMirrorPlugins: function addProseMirrorPlugins() {
21
+ var ZERO_WIDTH_SPACE = "\u200B";
22
+
23
+ // 检测是否为 Safari 浏览器
24
+ var isSafari = function () {
25
+ if (typeof navigator === 'undefined') return false;
26
+ var ua = navigator.userAgent;
27
+ var isAppleMobile = /iP(ad|hone|od)/.test(ua);
28
+ var isMacSafari = /Safari\//.test(ua) && !/Chrome\//.test(ua);
29
+ return isAppleMobile || isMacSafari;
30
+ }();
31
+
32
+ // 判断是否为文本节点
33
+ var isTextNode = function isTextNode(node) {
34
+ return !!node && node.nodeType === 3;
35
+ };
36
+ return [new Plugin({
37
+ key: imeCompositionPluginKey,
38
+ state: {
39
+ init: function init() {
40
+ return {
41
+ isComposing: false
42
+ };
43
+ },
44
+ apply: function apply(tr, value) {
45
+ // 从 transaction meta 中获取组合状态
46
+ var meta = tr.getMeta(imeCompositionPluginKey);
47
+ if (meta) {
48
+ return {
49
+ isComposing: meta.isComposing
50
+ };
51
+ }
52
+ return value;
53
+ }
54
+ },
55
+ props: {
56
+ handleKeyDown: function handleKeyDown(view, event) {
57
+ var pluginState = imeCompositionPluginKey.getState(view.state);
58
+ // 如果正在输入法组合中,不处理键盘事件
59
+ // 检查 event.isComposing 和插件状态,确保 IME 输入不被键盘处理器打断
60
+ if (event.isComposing || pluginState !== null && pluginState !== void 0 && pluginState.isComposing) {
61
+ return false;
62
+ }
63
+ return false;
64
+ },
65
+ handleDOMEvents: {
66
+ // 监听输入法组合开始事件
67
+ compositionstart: function compositionstart(view, event) {
68
+ var state = view.state,
69
+ dispatch = view.dispatch;
70
+ var tr = state.tr.setMeta(imeCompositionPluginKey, {
71
+ isComposing: true
72
+ }).setMeta('composition', true);
73
+ dispatch(tr);
74
+ return false;
75
+ },
76
+ // 监听输入法组合结束事件
77
+ compositionend: function compositionend(view, event) {
78
+ var state = view.state,
79
+ dispatch = view.dispatch;
80
+ var tr = state.tr.setMeta(imeCompositionPluginKey, {
81
+ isComposing: false
82
+ }).setMeta('composition', false);
83
+ dispatch(tr);
84
+ return false;
85
+ },
86
+ // Safari 特定的修复:处理中文合成结束后触发的删除合成文本行为
87
+ // 这个问题在 Safari 中会在任意输入位置出现,不仅仅是 table
88
+ beforeinput: isSafari ? function (view, event) {
89
+ // 仅处理 Safari 在中文合成结束后触发的删除合成文本行为
90
+ var inputEvent = event;
91
+ if (inputEvent.inputType !== 'deleteCompositionText') {
92
+ return false;
93
+ }
94
+ var selection = window.getSelection();
95
+ if (!selection || selection.rangeCount === 0) return false;
96
+ var range = selection.getRangeAt(0);
97
+ var startContainer = range.startContainer,
98
+ endContainer = range.endContainer,
99
+ startOffset = range.startOffset,
100
+ endOffset = range.endOffset;
101
+
102
+ // 如果选中的是整个文本节点,在节点前插入零宽空格防止被删除
103
+ if (isTextNode(startContainer) && startContainer === endContainer && startOffset === 0 && endOffset === startContainer.length) {
104
+ var _startContainer$paren;
105
+ (_startContainer$paren = startContainer.parentElement) === null || _startContainer$paren === void 0 || _startContainer$paren.insertBefore(document.createTextNode(ZERO_WIDTH_SPACE), startContainer);
106
+ }
107
+ // 让 ProseMirror 照常处理
108
+ return false;
109
+ } : undefined,
110
+ // Safari 特定的修复:清理零宽空格
111
+ input: isSafari ? function (view, event) {
112
+ var inputEvent = event;
113
+ if (inputEvent.inputType !== 'deleteCompositionText') {
114
+ return false;
115
+ }
116
+ var selection = window.getSelection();
117
+ if (!selection || selection.rangeCount === 0) return false;
118
+ var range = selection.getRangeAt(0);
119
+ var node = range.startContainer;
120
+ var parentEl = (node === null || node === void 0 ? void 0 : node.parentElement) || null;
121
+ if (!parentEl) return false;
122
+ var textNodes = Array.from(parentEl.childNodes).filter(isTextNode);
123
+ var _iterator = _createForOfIteratorHelper(textNodes),
124
+ _step;
125
+ try {
126
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
127
+ var textNode = _step.value;
128
+ if (textNode.textContent === ZERO_WIDTH_SPACE) {
129
+ textNode.remove();
130
+ } else if (textNode.textContent && textNode.textContent.includes(ZERO_WIDTH_SPACE)) {
131
+ textNode.textContent = textNode.textContent.split(ZERO_WIDTH_SPACE).join('');
132
+ }
133
+ }
134
+ } catch (err) {
135
+ _iterator.e(err);
136
+ } finally {
137
+ _iterator.f();
138
+ }
139
+ return false;
140
+ } : undefined
141
+ }
142
+ }
143
+ })];
144
+ }
145
+ });
@@ -1,3 +1,4 @@
1
1
  export * from './AiWriting';
2
+ export * from './ImeComposition';
2
3
  export * from './SlashCommands';
3
4
  export * from './StructuredDiff';
@@ -1,3 +1,4 @@
1
1
  export * from "./AiWriting";
2
+ export * from "./ImeComposition";
2
3
  export * from "./SlashCommands";
3
4
  export * from "./StructuredDiff";
@@ -12,7 +12,7 @@ import { CharacterCount, Placeholder } from '@tiptap/extensions';
12
12
  import { Markdown } from '@tiptap/markdown';
13
13
  import StarterKit from '@tiptap/starter-kit';
14
14
  import { PLACEHOLDER } from "../contants/placeholder";
15
- import { AiWritingExtension, SlashCommands, StructuredDiffExtension } from "./extension";
15
+ import { AiWritingExtension, ImeComposition, SlashCommands, StructuredDiffExtension } from "./extension";
16
16
  import { CodeExtension } from "./mark/Code";
17
17
  import { AlertExtension, AudioExtension, BlockAttachmentExtension, BlockLinkExtension, CodeBlockLowlightExtension, CustomBlockMathExtension, CustomHorizontalRule, CustomInlineMathExtension, CustomSubscript, CustomSuperscript, DetailsContentExtension, DetailsExtension, DetailsSummaryExtension, EmojiExtension, FileHandlerExtension, FlowExtension, IframeExtension, ImageExtension, Indent, InlineAttachmentExtension, InlineLinkExtension, InlineUploadProgressExtension, ListExtension, MentionExtension, TableExtension, TableOfContentsExtension, UploadProgressExtension, VerticalAlign, VideoExtension, YamlFormat, YoutubeExtension } from "./node";
18
18
  export var getExtensions = function getExtensions(_ref) {
@@ -30,7 +30,7 @@ export var getExtensions = function getExtensions(_ref) {
30
30
  onAiWritingGetSuggestion = _ref.onAiWritingGetSuggestion,
31
31
  onValidateUrl = _ref.onValidateUrl,
32
32
  _placeholder = _ref.placeholder;
33
- var defaultExtensions = [StarterKit.configure({
33
+ var defaultExtensions = [ImeComposition, StarterKit.configure({
34
34
  link: false,
35
35
  code: false,
36
36
  codeBlock: false,
@@ -36,8 +36,9 @@ var CustomCodeBlock = CodeBlockLowlight.configure({
36
36
  });
37
37
  },
38
38
  parseMarkdown: function parseMarkdown(token, helpers) {
39
- var _token$raw;
40
- if (((_token$raw = token.raw) === null || _token$raw === void 0 ? void 0 : _token$raw.startsWith('```')) === false && token.codeBlockStyle !== 'indented') {
39
+ var isFenced = token.codeBlockStyle === 'fenced' || token.raw && /^\s*```/.test(token.raw);
40
+ var isIndented = token.codeBlockStyle === 'indented';
41
+ if (!isFenced && !isIndented) {
41
42
  return [];
42
43
  }
43
44
  if (token.lang === 'mermaid') {
@@ -3,9 +3,6 @@ import { Node } from '@tiptap/core';
3
3
  declare module '@tiptap/core' {
4
4
  interface Commands<ReturnType> {
5
5
  flow: {
6
- /**
7
- * Insert a flow diagram
8
- */
9
6
  setFlow: (options: {
10
7
  code?: string;
11
8
  width?: string | number;
@@ -16,6 +16,9 @@ export var FlowExtension = function FlowExtension(props) {
16
16
  draggable: true,
17
17
  addAttributes: function addAttributes() {
18
18
  return {
19
+ class: {
20
+ default: 'flow-wrapper'
21
+ },
19
22
  code: {
20
23
  default: '',
21
24
  parseHTML: function parseHTML(element) {
@@ -29,9 +32,9 @@ export var FlowExtension = function FlowExtension(props) {
29
32
  }
30
33
  },
31
34
  width: {
32
- default: '100%',
35
+ default: null,
33
36
  parseHTML: function parseHTML(element) {
34
- return element.getAttribute('data-width') || '100%';
37
+ return element.getAttribute('data-width') || null;
35
38
  },
36
39
  renderHTML: function renderHTML(attributes) {
37
40
  if (!attributes.width) return {};
@@ -48,7 +51,7 @@ export var FlowExtension = function FlowExtension(props) {
48
51
  getAttrs: function getAttrs(dom) {
49
52
  if (!(dom instanceof HTMLElement)) return false;
50
53
  var code = dom.getAttribute('data-code') || '';
51
- var width = dom.getAttribute('data-width') || '100%';
54
+ var width = dom.getAttribute('data-width') || null;
52
55
  return {
53
56
  code: code,
54
57
  width: width
@@ -84,7 +87,7 @@ export var FlowExtension = function FlowExtension(props) {
84
87
  type: _this.name,
85
88
  attrs: {
86
89
  code: options.code || '',
87
- width: options.width || '100%'
90
+ width: options.width || null
88
91
  }
89
92
  });
90
93
  };
@@ -4,7 +4,7 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
4
4
  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; }
5
5
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
6
6
  function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
7
- import { getLinkTitle } from "../../../util";
7
+ import { getLinkAttributesWithSelectedText, getLinkTitle } from "../../../util";
8
8
  import { mergeAttributes, Node, nodePasteRule } from '@tiptap/core';
9
9
  import { Plugin, PluginKey } from '@tiptap/pm/state';
10
10
  import { ReactNodeViewRenderer } from '@tiptap/react';
@@ -361,10 +361,11 @@ export var InlineLinkExtension = Node.create({
361
361
  var _this6 = this;
362
362
  return {
363
363
  'Mod-1': function Mod1() {
364
- return _this6.editor.commands.setInlineLink({
364
+ var linkAttributes = getLinkAttributesWithSelectedText(_this6.editor);
365
+ return _this6.editor.commands.setInlineLink(_objectSpread({
365
366
  href: '',
366
367
  type: 'icon'
367
- });
368
+ }, linkAttributes));
368
369
  }
369
370
  };
370
371
  },
@@ -1,5 +1,4 @@
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
- function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
3
2
  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
3
  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
4
  function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
@@ -27,7 +26,7 @@ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e
27
26
 
28
27
  import { Extension } from '@tiptap/core';
29
28
  import { Table, TableCell, TableHeader, TableRow } from '@tiptap/extension-table';
30
- import { Plugin, TextSelection } from '@tiptap/pm/state';
29
+ import { TextSelection } from '@tiptap/pm/state';
31
30
  import { TableView } from '@tiptap/pm/tables';
32
31
  import { TableHandleExtension } from "./TableHandler";
33
32
  export var TableExtension = function TableExtension(_ref) {
@@ -48,11 +47,13 @@ export var TableExtension = function TableExtension(_ref) {
48
47
  _defineProperty(_assertThisInitialized(_this2), "tableWrapper", void 0);
49
48
  _defineProperty(_assertThisInitialized(_this2), "innerTableContainer", void 0);
50
49
  _defineProperty(_assertThisInitialized(_this2), "widgetsContainer", void 0);
50
+ _defineProperty(_assertThisInitialized(_this2), "selectionOverlayContainer", void 0);
51
51
  _defineProperty(_assertThisInitialized(_this2), "containerAttributes", void 0);
52
52
  _this2.containerAttributes = containerAttributes !== null && containerAttributes !== void 0 ? containerAttributes : {};
53
53
  _this2.tableWrapper = _this2.createTableWrapper();
54
54
  _this2.innerTableContainer = _this2.createInnerTableContainer();
55
55
  _this2.widgetsContainer = _this2.createWidgetsContainer();
56
+ _this2.selectionOverlayContainer = _this2.createSelectionOverlayContainer();
56
57
  _this2.setupDOMStructure();
57
58
  return _this2;
58
59
  }
@@ -60,7 +61,7 @@ export var TableExtension = function TableExtension(_ref) {
60
61
  key: "createTableWrapper",
61
62
  value: function createTableWrapper() {
62
63
  var container = document.createElement('div');
63
- container.className = 'tableWrapper';
64
+ container.setAttribute("data-content-type", "table");
64
65
  this.applyContainerAttributes(container);
65
66
  return container;
66
67
  }
@@ -79,6 +80,14 @@ export var TableExtension = function TableExtension(_ref) {
79
80
  container.style.position = 'relative';
80
81
  return container;
81
82
  }
83
+ }, {
84
+ key: "createSelectionOverlayContainer",
85
+ value: function createSelectionOverlayContainer() {
86
+ var container = document.createElement('div');
87
+ container.className = 'table-selection-overlay-container';
88
+ container.style.position = 'relative';
89
+ return container;
90
+ }
82
91
  }, {
83
92
  key: "applyContainerAttributes",
84
93
  value: function applyContainerAttributes(element) {
@@ -96,13 +105,11 @@ export var TableExtension = function TableExtension(_ref) {
96
105
  value: function setupDOMStructure() {
97
106
  var originalTable = this.dom;
98
107
  var tableElement = originalTable.firstChild;
99
-
100
- // Move table into inner container
101
108
  this.innerTableContainer.appendChild(tableElement);
102
-
103
- // Build the hierarchy: tableWrapper > innerContainer + widgetsContainer
104
- this.tableWrapper.appendChild(this.innerTableContainer);
105
- this.tableWrapper.appendChild(this.widgetsContainer);
109
+ originalTable.appendChild(this.innerTableContainer);
110
+ originalTable.appendChild(this.widgetsContainer);
111
+ originalTable.appendChild(this.selectionOverlayContainer);
112
+ this.tableWrapper.appendChild(originalTable);
106
113
  this.dom = this.tableWrapper;
107
114
  }
108
115
  }, {
@@ -133,6 +140,8 @@ export var TableExtension = function TableExtension(_ref) {
133
140
  class: 'table-container'
134
141
  }, originalRender], ['div', {
135
142
  class: 'table-controls'
143
+ }], ['div', {
144
+ class: 'table-selection-overlay-container'
136
145
  }]];
137
146
  return wrapper;
138
147
  },
@@ -357,79 +366,6 @@ export var TableExtension = function TableExtension(_ref) {
357
366
  }
358
367
  }), editable ? TableHandleExtension : Extension.create({
359
368
  name: 'tableHandleExtension'
360
- }), Extension.create({
361
- name: 'safariCompositionDeleteFix',
362
- addProseMirrorPlugins: function addProseMirrorPlugins() {
363
- if (!editable) return [];
364
- var ZERO_WIDTH_SPACE = "\u200B";
365
- var isSafari = function () {
366
- if (typeof navigator === 'undefined') return false;
367
- var ua = navigator.userAgent;
368
- var isAppleMobile = /iP(ad|hone|od)/.test(ua);
369
- var isMacSafari = /Safari\//.test(ua) && !/Chrome\//.test(ua);
370
- return isAppleMobile || isMacSafari;
371
- }();
372
- if (!isSafari) return [];
373
-
374
- // 注意:这里不能使用上面从 ProseMirror 导入的 Node 类型,需判断 DOM 文本节点
375
- var isTextNode = function isTextNode(node) {
376
- return !!node && node.nodeType === 3;
377
- };
378
- return [new Plugin({
379
- props: {
380
- handleDOMEvents: {
381
- beforeinput: function beforeinput(_view, event) {
382
- // 仅处理 Safari 在中文合成结束后触发的删除合成文本行为
383
- if (event.inputType !== 'deleteCompositionText') {
384
- return false;
385
- }
386
- var selection = window.getSelection();
387
- if (!selection || selection.rangeCount === 0) return false;
388
- var range = selection.getRangeAt(0);
389
- var startContainer = range.startContainer,
390
- endContainer = range.endContainer,
391
- startOffset = range.startOffset,
392
- endOffset = range.endOffset;
393
- if (isTextNode(startContainer) && startContainer === endContainer && startOffset === 0 && endOffset === startContainer.length) {
394
- var _startContainer$paren;
395
- (_startContainer$paren = startContainer.parentElement) === null || _startContainer$paren === void 0 || _startContainer$paren.insertBefore(document.createTextNode(ZERO_WIDTH_SPACE), startContainer);
396
- }
397
- // 让 ProseMirror 照常处理
398
- return false;
399
- },
400
- input: function input(_view, event) {
401
- if (event.inputType !== 'deleteCompositionText') {
402
- return false;
403
- }
404
- var selection = window.getSelection();
405
- if (!selection || selection.rangeCount === 0) return false;
406
- var range = selection.getRangeAt(0);
407
- var node = range.startContainer;
408
- var parentEl = (node === null || node === void 0 ? void 0 : node.parentElement) || null;
409
- if (!parentEl) return false;
410
- var textNodes = Array.from(parentEl.childNodes).filter(isTextNode);
411
- var _iterator = _createForOfIteratorHelper(textNodes),
412
- _step;
413
- try {
414
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
415
- var textNode = _step.value;
416
- if (textNode.textContent === ZERO_WIDTH_SPACE) {
417
- textNode.remove();
418
- } else if (textNode.textContent && textNode.textContent.includes(ZERO_WIDTH_SPACE)) {
419
- textNode.textContent = textNode.textContent.split(ZERO_WIDTH_SPACE).join('');
420
- }
421
- }
422
- } catch (err) {
423
- _iterator.e(err);
424
- } finally {
425
- _iterator.f();
426
- }
427
- return false;
428
- }
429
- }
430
- }
431
- })];
432
- }
433
369
  })];
434
370
  };
435
371
  export default TableExtension;
@@ -1,4 +1,6 @@
1
1
  import { TocList } from "../../../type";
2
- export declare const TableOfContentsExtension: ({ onTocUpdate }: {
3
- onTocUpdate?: ((toc: TocList) => void) | undefined;
4
- }) => import("@tiptap/core").Extension<import("@tiptap/extension-table-of-contents").TableOfContentsOptions, import("@tiptap/extension-table-of-contents").TableOfContentsStorage>;
2
+ interface TableOfContentsOptions {
3
+ onTocUpdate?: (toc: TocList) => void;
4
+ }
5
+ export declare const TableOfContentsExtension: ({ onTocUpdate }: TableOfContentsOptions) => import("@tiptap/core").Extension<import("@tiptap/extension-table-of-contents").TableOfContentsOptions, import("@tiptap/extension-table-of-contents").TableOfContentsStorage>;
6
+ export {};
@@ -1,7 +1,27 @@
1
1
  import { getHierarchicalIndexes, TableOfContents } from '@tiptap/extension-table-of-contents';
2
+ import { Plugin, PluginKey } from '@tiptap/pm/state';
2
3
  export var TableOfContentsExtension = function TableOfContentsExtension(_ref) {
3
4
  var onTocUpdate = _ref.onTocUpdate;
4
- return TableOfContents.configure({
5
+ return TableOfContents.extend({
6
+ addProseMirrorPlugins: function addProseMirrorPlugins() {
7
+ var imeCompositionPluginKey = new PluginKey('imeComposition');
8
+ return [new Plugin({
9
+ key: new PluginKey('tableOfContentImeFix'),
10
+ appendTransaction: function appendTransaction(transactions, _oldState, newState) {
11
+ if (transactions.some(function (tr) {
12
+ return tr.getMeta('composition');
13
+ })) {
14
+ return null;
15
+ }
16
+ var imePluginState = imeCompositionPluginKey.getState(newState);
17
+ if (imePluginState !== null && imePluginState !== void 0 && imePluginState.isComposing) {
18
+ return null;
19
+ }
20
+ return null;
21
+ }
22
+ })];
23
+ }
24
+ }).configure({
5
25
  getIndex: getHierarchicalIndexes,
6
26
  onUpdate: function onUpdate(data) {
7
27
  setTimeout(function () {
@@ -17,7 +37,7 @@ export var TableOfContentsExtension = function TableOfContentsExtension(_ref) {
17
37
  textContent: content.textContent
18
38
  };
19
39
  }));
20
- }, 0);
40
+ }, 60);
21
41
  }
22
42
  });
23
43
  };
@@ -9,6 +9,7 @@ declare module '@tiptap/core' {
9
9
  setVideo: (options: {
10
10
  src: string;
11
11
  width?: number;
12
+ align?: 'left' | 'center' | 'right';
12
13
  controls?: boolean;
13
14
  autoplay?: boolean;
14
15
  loop?: boolean;
@@ -107,16 +107,33 @@ export var VideoExtension = function VideoExtension(props) {
107
107
  }
108
108
  },
109
109
  width: {
110
- default: 760,
110
+ default: null,
111
111
  parseHTML: function parseHTML(element) {
112
112
  var width = element.getAttribute('width');
113
- return width ? parseInt(width, 10) : 760;
113
+ if (width) {
114
+ if (width.endsWith('%')) return width;
115
+ var numWidth = parseInt(width, 10);
116
+ return isNaN(numWidth) ? null : numWidth;
117
+ }
118
+ return null;
114
119
  },
115
120
  renderHTML: function renderHTML(attributes) {
116
121
  return {
117
122
  width: attributes.width
118
123
  };
119
124
  }
125
+ },
126
+ align: {
127
+ default: null,
128
+ parseHTML: function parseHTML(element) {
129
+ return element.getAttribute('data-align');
130
+ },
131
+ renderHTML: function renderHTML(attributes) {
132
+ if (!attributes.align) return {};
133
+ return {
134
+ 'data-align': attributes.align
135
+ };
136
+ }
120
137
  }
121
138
  };
122
139
  },
@@ -127,6 +144,18 @@ export var VideoExtension = function VideoExtension(props) {
127
144
  if (!(dom instanceof HTMLElement)) return false;
128
145
  var src = dom.getAttribute('src');
129
146
  if (!src) return false;
147
+ var widthAttr = dom.getAttribute('width');
148
+ var width = 760;
149
+ if (widthAttr) {
150
+ // 如果是百分比,保留字符串格式
151
+ if (widthAttr.endsWith('%')) {
152
+ width = widthAttr;
153
+ } else {
154
+ // 否则解析为数字
155
+ var numWidth = parseInt(widthAttr, 10);
156
+ width = isNaN(numWidth) ? 760 : numWidth;
157
+ }
158
+ }
130
159
  return {
131
160
  src: src,
132
161
  controls: dom.hasAttribute('controls'),
@@ -134,7 +163,8 @@ export var VideoExtension = function VideoExtension(props) {
134
163
  loop: dom.hasAttribute('loop'),
135
164
  muted: dom.hasAttribute('muted'),
136
165
  poster: dom.getAttribute('poster'),
137
- width: dom.getAttribute('width') ? parseInt(dom.getAttribute('width'), 10) : 760
166
+ width: width,
167
+ align: dom.getAttribute('data-align') || dom.getAttribute('align')
138
168
  };
139
169
  }
140
170
  }];
@@ -151,9 +181,10 @@ export var VideoExtension = function VideoExtension(props) {
151
181
  autoplay = _ref2.autoplay,
152
182
  loop = _ref2.loop,
153
183
  muted = _ref2.muted,
154
- poster = _ref2.poster;
184
+ poster = _ref2.poster,
185
+ align = _ref2['data-align'];
155
186
  if (!src) return '';
156
- return "<video src=\"".concat(src, "\" ").concat(width ? "width=\"".concat(width, "\"") : '', " ").concat(controls ? 'controls' : '', " ").concat(autoplay ? 'autoplay' : '', " ").concat(loop ? 'loop' : '', " ").concat(muted ? 'muted' : '', " ").concat(poster ? "poster=\"".concat(poster, "\"") : '', "></video>");
187
+ return "<video src=\"".concat(src, "\" ").concat(width ? "width=\"".concat(width, "\"") : '', " ").concat(controls ? 'controls' : '', " ").concat(autoplay ? 'autoplay' : '', " ").concat(loop ? 'loop' : '', " ").concat(muted ? 'muted' : '', " ").concat(poster ? "poster=\"".concat(poster, "\"") : '', " ").concat(align ? "data-align=\"".concat(align, "\"") : '', "></video>");
157
188
  },
158
189
  addCommands: function addCommands() {
159
190
  var _this2 = this;
@@ -170,7 +201,8 @@ export var VideoExtension = function VideoExtension(props) {
170
201
  autoplay: options.autoplay || false,
171
202
  loop: options.loop || false,
172
203
  muted: options.muted || false,
173
- poster: options.poster || null
204
+ poster: options.poster || null,
205
+ align: options.align || null
174
206
  }
175
207
  });
176
208
  };
@@ -50,7 +50,7 @@ var useTiptap = function useTiptap(_ref) {
50
50
  editorProps: {
51
51
  handleKeyDown: function handleKeyDown(view, event) {
52
52
  // 编辑模式下保存
53
- if (event.key === 's' && (event.metaKey || event.ctrlKey) && editable) {
53
+ if (event.key === 's' && (event.metaKey || event.ctrlKey) && editable && onSave) {
54
54
  event.preventDefault();
55
55
  onSave === null || onSave === void 0 || onSave(editor);
56
56
  return true;