@ctzhian/tiptap 1.5.0 → 1.5.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.
@@ -17,7 +17,7 @@ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o =
17
17
  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; }
18
18
  function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
19
19
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
20
- import { AlignBottomIcon, AlignCenterIcon, AlignJustifyIcon, AlignLeftIcon, AlignRightIcon, AlignTopIcon, ArrowDownSLineIcon, AttachmentLineIcon, BrushLineIcon, DeleteLineIcon, DownloadLineIcon, DraggableIcon, FontSizeIcon, FormatClearIcon, H1Icon, H2Icon, H3Icon, ImageLineIcon, IndentDecreaseIcon, IndentIncreaseIcon, Information2LineIcon, ListCheck3Icon, ListOrdered2Icon, ListUnorderedIcon, MovieLineIcon, Music2LineIcon, QuoteTextIcon, Repeat2LineIcon, ScissorsCutLineIcon, SeparatorIcon, TextIcon, TextWrapIcon } from "../Icons";
20
+ import { AddLineIcon, AlignBottomIcon, AlignCenterIcon, AlignJustifyIcon, AlignLeftIcon, AlignRightIcon, AlignTopIcon, ArrowDownSLineIcon, AttachmentLineIcon, BrushLineIcon, DeleteLineIcon, DownloadLineIcon, DraggableIcon, FontSizeIcon, FormatClearIcon, H1Icon, H2Icon, H3Icon, ImageLineIcon, IndentDecreaseIcon, IndentIncreaseIcon, Information2LineIcon, ListCheck3Icon, ListOrdered2Icon, ListUnorderedIcon, MovieLineIcon, Music2LineIcon, QuoteTextIcon, Repeat2LineIcon, ScissorsCutLineIcon, SeparatorIcon, TextIcon, TextWrapIcon } from "../Icons";
21
21
  import { NODE_TYPE_LABEL, NodeTypeEnum } from "../../contants/enums";
22
22
  import { Box, Divider, Stack, Typography, useTheme } from '@mui/material';
23
23
  import DragHandle from '@tiptap/extension-drag-handle-react';
@@ -40,7 +40,6 @@ var DragIcon = function DragIcon(_ref) {
40
40
  display: 'flex',
41
41
  alignItems: 'center',
42
42
  justifyContent: 'center',
43
- mr: 1,
44
43
  color: 'text.tertiary',
45
44
  cursor: 'grab',
46
45
  borderColor: 'divider',
@@ -61,11 +60,43 @@ var DragIcon = function DragIcon(_ref) {
61
60
  }
62
61
  }));
63
62
  };
64
- var CustomDragHandle = function CustomDragHandle(_ref2) {
63
+ var AddIcon = function AddIcon(_ref2) {
64
+ var onClick = _ref2.onClick;
65
+ return /*#__PURE__*/React.createElement(Box, {
66
+ onClick: onClick,
67
+ sx: {
68
+ width: '1.25rem',
69
+ height: '1.25rem',
70
+ borderRadius: '0.25rem',
71
+ border: '1px solid',
72
+ display: 'flex',
73
+ alignItems: 'center',
74
+ justifyContent: 'center',
75
+ color: 'text.tertiary',
76
+ cursor: 'grab',
77
+ borderColor: 'divider',
78
+ bgcolor: 'background.paper',
79
+ transition: 'all 0.2s ease-in-out',
80
+ '&:hover': {
81
+ color: 'text.secondary',
82
+ bgcolor: 'divider'
83
+ },
84
+ '&:active': {
85
+ color: 'text.primary',
86
+ cursor: 'grabbing'
87
+ }
88
+ }
89
+ }, /*#__PURE__*/React.createElement(AddLineIcon, {
90
+ sx: {
91
+ fontSize: '1.25rem'
92
+ }
93
+ }));
94
+ };
95
+ var CustomDragHandle = function CustomDragHandle(_ref3) {
65
96
  var _current$node3, _current$node4, _current$node5, _current$node6, _current$node7, _current$node8, _current$node9, _current$node10, _current$node11, _current$node12, _current$node13, _current$node14, _current$node15, _current$node16;
66
- var editor = _ref2.editor,
67
- more = _ref2.more,
68
- onTip = _ref2.onTip;
97
+ var editor = _ref3.editor,
98
+ more = _ref3.more,
99
+ onTip = _ref3.onTip;
69
100
  var theme = useTheme();
70
101
  var _useState = useState(true),
71
102
  _useState2 = _slicedToArray(_useState, 2),
@@ -210,9 +241,9 @@ var CustomDragHandle = function CustomDragHandle(_ref2) {
210
241
  var attrs = current.editor.getAttributes(node.type.name);
211
242
  return Number(attrs.indent) || 0;
212
243
  };
213
- var shouldShowButton = function shouldShowButton(_ref3) {
214
- var editor = _ref3.editor,
215
- data = _ref3.data;
244
+ var shouldShowButton = function shouldShowButton(_ref4) {
245
+ var editor = _ref4.editor,
246
+ data = _ref4.data;
216
247
  if (!editor || !editor.isEditable) return false;
217
248
  var currentNode = data.node;
218
249
  var empty = (currentNode === null || currentNode === void 0 ? void 0 : currentNode.textContent) === '';
@@ -251,7 +282,38 @@ var CustomDragHandle = function CustomDragHandle(_ref2) {
251
282
  return /*#__PURE__*/React.createElement(DragHandle, {
252
283
  editor: editor,
253
284
  onNodeChange: updateNodeChange
254
- }, currentNode ? /*#__PURE__*/React.createElement(Menu, {
285
+ }, /*#__PURE__*/React.createElement(Stack, {
286
+ direction: 'row',
287
+ alignItems: 'center',
288
+ gap: 1,
289
+ sx: {
290
+ mr: 1,
291
+ height: '1.625rem'
292
+ }
293
+ }, /*#__PURE__*/React.createElement(AddIcon, {
294
+ onClick: function onClick(event) {
295
+ event.stopPropagation();
296
+ if (current.node && current.pos !== undefined) {
297
+ if (current.pos === 0) {
298
+ current.editor.chain().focus().insertContentAt(current.pos, {
299
+ type: 'paragraph',
300
+ content: [{
301
+ type: 'text',
302
+ text: '/'
303
+ }]
304
+ }).run();
305
+ } else {
306
+ current.editor.chain().focus().insertContentAt(current.pos + current.node.nodeSize, {
307
+ type: 'paragraph',
308
+ content: [{
309
+ type: 'text',
310
+ text: '/'
311
+ }]
312
+ }).run();
313
+ }
314
+ }
315
+ }
316
+ }), currentNode ? /*#__PURE__*/React.createElement(Menu, {
255
317
  context: /*#__PURE__*/React.createElement(DragIcon, null),
256
318
  anchorOrigin: {
257
319
  vertical: 'bottom',
@@ -1340,6 +1402,6 @@ var CustomDragHandle = function CustomDragHandle(_ref2) {
1340
1402
  return onClick;
1341
1403
  }()
1342
1404
  }] : []))
1343
- }) : /*#__PURE__*/React.createElement(DragIcon, null));
1405
+ }) : /*#__PURE__*/React.createElement(DragIcon, null)));
1344
1406
  };
1345
1407
  export default CustomDragHandle;
@@ -1,8 +1,8 @@
1
- import { Strategy } from '@floating-ui/dom';
1
+ import { Strategy, VirtualElement } from '@floating-ui/dom';
2
2
  import React from 'react';
3
3
  export interface FloatingPopoverProps {
4
4
  open: boolean;
5
- anchorEl: HTMLElement | null;
5
+ anchorEl: HTMLElement | VirtualElement | null;
6
6
  onClose: () => void;
7
7
  children: React.ReactNode;
8
8
  strategy?: Strategy;
@@ -70,8 +70,12 @@ export var FloatingPopover = function FloatingPopover(_ref) {
70
70
  }
71
71
  };
72
72
  var handleClickOutside = function handleClickOutside(event) {
73
- if (popoverRef.current && !popoverRef.current.contains(event.target) && anchorEl && !anchorEl.contains(event.target)) {
74
- onClose();
73
+ if (popoverRef.current && !popoverRef.current.contains(event.target)) {
74
+ // 仅当锚点为真实元素时,才检测是否点击在锚点上
75
+ var isHitAnchor = anchorEl instanceof HTMLElement && anchorEl.contains(event.target);
76
+ if (!isHitAnchor) {
77
+ onClose();
78
+ }
75
79
  }
76
80
  };
77
81
  document.addEventListener('keydown', handleEscape);
@@ -100,6 +104,7 @@ export var FloatingPopover = function FloatingPopover(_ref) {
100
104
  left: position.x,
101
105
  top: position.y,
102
106
  zIndex: 1300,
107
+ boxShadow: 'var(--mui-shadows-1)',
103
108
  borderRadius: 'var(--mui-shape-borderRadius)'
104
109
  }, style),
105
110
  elevation: 8
@@ -0,0 +1,6 @@
1
+ import { SvgIconProps } from "@mui/material";
2
+ import * as React from "react";
3
+ export declare const AddLineIcon: {
4
+ (props: SvgIconProps): React.JSX.Element;
5
+ displayName: string;
6
+ };
@@ -0,0 +1,13 @@
1
+ function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
2
+ import { SvgIcon } from "@mui/material";
3
+ import * as React from "react";
4
+ export var AddLineIcon = function AddLineIcon(props) {
5
+ return /*#__PURE__*/React.createElement(SvgIcon, _extends({
6
+ viewBox: "0 0 24 24",
7
+ version: "1.1",
8
+ xmlns: "http://www.w3.org/2000/svg"
9
+ }, props), /*#__PURE__*/React.createElement("path", {
10
+ d: "M11 11V5H13V11H19V13H13V19H11V13H5V11H11Z"
11
+ }));
12
+ };
13
+ AddLineIcon.displayName = 'icon-add-line';
@@ -1,3 +1,4 @@
1
+ export { AddLineIcon } from './add-line-icon';
1
2
  export { AiGenerate2Icon } from './ai-generate-2-icon';
2
3
  export { AiGenerateTextIcon } from './ai-generate-text-icon';
3
4
  export { AlignBottomIcon } from './align-bottom-icon';
@@ -1,6 +1,7 @@
1
1
  // 此文件由脚本自动生成
2
2
  // 导出所有图标组件
3
3
 
4
+ export { AddLineIcon } from "./add-line-icon";
4
5
  export { AiGenerate2Icon } from "./ai-generate-2-icon";
5
6
  export { AiGenerateTextIcon } from "./ai-generate-text-icon";
6
7
  export { AlignBottomIcon } from "./align-bottom-icon";
@@ -94,7 +94,7 @@ var LinkViewWrapper = function LinkViewWrapper(_ref) {
94
94
  };
95
95
  var handleDeleteLink = function handleDeleteLink() {
96
96
  editor.commands.deleteNode(node.type);
97
- editor.commands.insertContent(attrs.title || getLinkTitle(attrs.href));
97
+ editor.commands.insertContent(attrs.title || attrs.href);
98
98
  };
99
99
  var handleCopyLink = useCallback( /*#__PURE__*/function () {
100
100
  var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(event) {
@@ -0,0 +1,10 @@
1
+ import { SlashCommandsListRef } from "../../../type";
2
+ import { SuggestionProps } from '@tiptap/suggestion';
3
+ import React from 'react';
4
+ export type SlashCommandsOverlayProps = SuggestionProps<any> & {
5
+ open: boolean;
6
+ };
7
+ declare const SlashCommandsOverlay: React.ForwardRefExoticComponent<SuggestionProps<any, any> & {
8
+ open: boolean;
9
+ } & React.RefAttributes<SlashCommandsListRef>>;
10
+ export default SlashCommandsOverlay;
@@ -0,0 +1,26 @@
1
+ import { FloatingPopover } from "../../../component";
2
+ import React, { forwardRef, useMemo } from 'react';
3
+ import SlashCommandsList from "./index";
4
+ var SlashCommandsOverlay = /*#__PURE__*/forwardRef(function (props, ref) {
5
+ var anchorEl = useMemo(function () {
6
+ if (!props.clientRect) return null;
7
+ return {
8
+ getBoundingClientRect: function getBoundingClientRect() {
9
+ return props.clientRect();
10
+ }
11
+ };
12
+ }, [props.clientRect]);
13
+ return /*#__PURE__*/React.createElement(FloatingPopover, {
14
+ open: Boolean(props.open && anchorEl),
15
+ anchorEl: anchorEl,
16
+ onClose: function onClose() {/* 由外部生命周期控制关闭 */},
17
+ placement: "bottom"
18
+ }, /*#__PURE__*/React.createElement(SlashCommandsList, {
19
+ ref: ref,
20
+ items: props.items,
21
+ command: props.command,
22
+ editor: props.editor
23
+ }));
24
+ });
25
+ SlashCommandsOverlay.displayName = 'SlashCommandsOverlay';
26
+ export default SlashCommandsOverlay;
@@ -8,7 +8,7 @@ import { NestedList } from "../../../component";
8
8
  import { ArrowDownSLineIcon, AttachmentLineIcon, CheckboxCircleFillIcon, CloseCircleFillIcon, ErrorWarningFillIcon, FormulaIcon, FunctionsIcon, ImageLineIcon, Information2FillIcon, Information2LineIcon, MovieLineIcon, Music2LineIcon, SquareRootIcon, Table2Icon, UploadIcon } from "../../../component/Icons";
9
9
  import { ToolbarItem } from "../../../component/Toolbar";
10
10
  import TableSizePicker from "../../../component/Toolbar/TableSizePicker";
11
- import { Divider, Paper, Stack } from '@mui/material';
11
+ import { Box, Divider, Stack } from '@mui/material';
12
12
  import React, { forwardRef } from 'react';
13
13
  var SlashCommandsList = /*#__PURE__*/forwardRef(function (_ref, ref) {
14
14
  var items = _ref.items,
@@ -16,10 +16,8 @@ var SlashCommandsList = /*#__PURE__*/forwardRef(function (_ref, ref) {
16
16
  if (items.length === 0) {
17
17
  return null;
18
18
  }
19
- return /*#__PURE__*/React.createElement(Paper, {
20
- elevation: 8,
19
+ return /*#__PURE__*/React.createElement(Box, {
21
20
  sx: {
22
- borderRadius: 'var(--mui-shape-borderRadius)',
23
21
  width: '224px',
24
22
  p: 0.5
25
23
  }
@@ -1,4 +1,5 @@
1
1
  /// <reference types="react" />
2
+ import type { Editor } from "../../type";
2
3
  import { SuggestionProps } from '@tiptap/suggestion';
3
4
  export declare const slashSuggestion: () => {
4
5
  items: ({ query }: {
@@ -7,7 +8,7 @@ export declare const slashSuggestion: () => {
7
8
  title: string;
8
9
  icon: import("react").JSX.Element;
9
10
  command: ({ editor, range, attrs }: {
10
- editor: import("@tiptap/core").Editor;
11
+ editor: Editor;
11
12
  range: {
12
13
  from: number;
13
14
  to: number;
@@ -15,8 +16,11 @@ export declare const slashSuggestion: () => {
15
16
  attrs: any;
16
17
  }) => void;
17
18
  }[];
19
+ decorationTag: string;
20
+ decorationClass: string;
21
+ decorationContent: string;
18
22
  command: ({ editor, range, props }: {
19
- editor: any;
23
+ editor: Editor;
20
24
  range: {
21
25
  from: number;
22
26
  to: number;
@@ -25,11 +29,11 @@ export declare const slashSuggestion: () => {
25
29
  }) => void;
26
30
  render: () => {
27
31
  onStart: (props: SuggestionProps<any>) => void;
28
- onUpdate(props: SuggestionProps<any>): void;
32
+ onUpdate(props: SuggestionProps<any>): false | undefined;
29
33
  onKeyDown(props: {
30
34
  event: KeyboardEvent;
31
35
  }): boolean;
32
- onExit(): void;
36
+ onExit(): false | undefined;
33
37
  };
34
38
  };
35
39
  export default slashSuggestion;
@@ -1,17 +1,24 @@
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 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; }
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; }
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
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
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); }
1
7
  import { slashCommands } from "../../contants/slash-commands";
2
- import { updatePosition } from "../../util";
3
8
  import { ReactRenderer } from '@tiptap/react';
4
- import SlashCommandsList from "../component/SlashCommandsList/index";
9
+ import SlashCommandsOverlay from "../component/SlashCommandsList/Overlay";
5
10
  export var slashSuggestion = function slashSuggestion() {
6
11
  return {
7
12
  items: function items(_ref) {
8
13
  var query = _ref.query;
9
- var commands = slashCommands;
10
- if (!query) return commands;
11
- return commands.filter(function (item) {
12
- return item.title.toLowerCase().includes(query.toLowerCase());
13
- });
14
+ return slashCommands;
15
+ // const commands = slashCommands
16
+ // if (!query) return commands
17
+ // return commands.filter(item => item.title.toLowerCase().includes(query.toLowerCase()))
14
18
  },
19
+ decorationTag: 'span',
20
+ decorationClass: 'slash-decoration',
21
+ decorationContent: '插入',
15
22
  command: function command(_ref2) {
16
23
  var editor = _ref2.editor,
17
24
  range = _ref2.range,
@@ -24,23 +31,38 @@ export var slashSuggestion = function slashSuggestion() {
24
31
  },
25
32
  render: function render() {
26
33
  var component = null;
34
+ var lastProps = null;
35
+ var isCaretAfterSlash = function isCaretAfterSlash(editor) {
36
+ try {
37
+ var pos = editor.state.selection.from;
38
+ if (pos <= 1) return false;
39
+ var char = editor.state.doc.textBetween(pos - 1, pos, '\n', '\n');
40
+ return char === '/';
41
+ } catch (_unused) {
42
+ return false;
43
+ }
44
+ };
27
45
  return {
28
46
  onStart: function onStart(props) {
29
- component = new ReactRenderer(SlashCommandsList, {
30
- props: props,
47
+ lastProps = props;
48
+ var shouldOpen = !props.query || props.query.length === 0;
49
+ component = new ReactRenderer(SlashCommandsOverlay, {
50
+ props: _objectSpread(_objectSpread({}, props), {}, {
51
+ open: shouldOpen
52
+ }),
31
53
  editor: props.editor
32
54
  });
33
55
  if (!props.clientRect) return;
34
56
  var element = component.element;
35
- element.style.position = 'absolute';
36
57
  document.body.appendChild(element);
37
- updatePosition(props.editor, element);
38
58
  },
39
59
  onUpdate: function onUpdate(props) {
40
- if (!component) return;
41
- component.updateProps(props);
42
- if (!props.clientRect) return;
43
- updatePosition(props.editor, component.element);
60
+ if (!component) return false;
61
+ lastProps = props;
62
+ var shouldOpen = !props.query || props.query.length === 0;
63
+ component.updateProps(_objectSpread(_objectSpread({}, props), {}, {
64
+ open: shouldOpen
65
+ }));
44
66
  },
45
67
  onKeyDown: function onKeyDown(props) {
46
68
  var _component$ref;
@@ -53,7 +75,15 @@ export var slashSuggestion = function slashSuggestion() {
53
75
  return ((_component$ref = component.ref) === null || _component$ref === void 0 ? void 0 : _component$ref.onKeyDown(props)) || false;
54
76
  },
55
77
  onExit: function onExit() {
56
- if (!component) return;
78
+ var _lastProps;
79
+ if (!component) return false;
80
+ var editor = (_lastProps = lastProps) === null || _lastProps === void 0 ? void 0 : _lastProps.editor;
81
+ if (editor && isCaretAfterSlash(editor)) {
82
+ return false;
83
+ }
84
+ component.updateProps({
85
+ open: false
86
+ });
57
87
  component.destroy();
58
88
  component.element.remove();
59
89
  }
package/dist/index.css CHANGED
@@ -538,4 +538,18 @@
538
538
 
539
539
  .PhotoView-Slider__BannerWrap {
540
540
  background-color: rgba(33, 34, 45, 0.2) !important;
541
+ }
542
+
543
+ .slash-decoration[data-decoration-content].is-empty {
544
+ padding: 4px 8px;
545
+ background-color: var(--mui-palette-background-paper2);
546
+ border-radius: var(--mui-shape-borderRadius);
547
+ }
548
+
549
+ .slash-decoration[data-decoration-content].is-empty::after {
550
+ content: attr(data-decoration-content);
551
+ color: var(--mui-palette-text-disabled);
552
+ padding-left: 0.25rem;
553
+ font-size: 14px;
554
+ line-height: 24px;
541
555
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ctzhian/tiptap",
3
- "version": "1.5.0",
3
+ "version": "1.5.1",
4
4
  "description": "基于 Tiptap 二次开发的编辑器组件",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",