@ctzhian/tiptap 1.6.5 → 1.6.7

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.
package/README.md CHANGED
@@ -3,39 +3,148 @@
3
3
  [![NPM version](https://img.shields.io/npm/v/@ctzhian/tiptap.svg?style=flat)](https://npmjs.org/package/@ctzhian/tiptap)
4
4
  [![NPM downloads](http://img.shields.io/npm/dm/@ctzhian/tiptap.svg?style=flat)](https://npmjs.org/package/@ctzhian/tiptap)
5
5
 
6
- A react library developed with dumi
6
+ 基于 Tiptap v3 二次开发的 React 富文本编辑器组件集,内置工具栏、主题、结构化 Diff、高亮、表格、附件/音视频/数学等常用扩展,开箱即用。
7
7
 
8
- ## Usage
8
+ - 核心能力:`useTiptap`、`Editor`、`EditorToolbar`、`EditorDiff`
9
+ - 技术栈:React 18、Tiptap v3、MUI v7、Emotion 11
9
10
 
10
- TODO
11
+ ## 安装
11
12
 
12
- ## Options
13
+ ```bash
14
+ pnpm add @ctzhian/tiptap
15
+ # 同时安装 peer 依赖
16
+ pnpm add @mui/material @mui/icons-material @emotion/react @emotion/styled
17
+ ```
18
+
19
+ 样式(必须):
20
+
21
+ ```ts
22
+ import '@ctzhian/tiptap/dist/index.css';
23
+ ```
24
+
25
+ ## 快速开始
26
+
27
+ ```tsx
28
+ import React from 'react';
29
+ import {
30
+ EditorThemeProvider,
31
+ EditorToolbar,
32
+ Editor,
33
+ useTiptap,
34
+ } from '@ctzhian/tiptap';
35
+ import '@ctzhian/tiptap/dist/index.css';
36
+
37
+ export default function Demo() {
38
+ const { editor } = useTiptap({
39
+ editable: true,
40
+ content: '<p>Hello Tiptap</p>',
41
+ exclude: ['invisibleCharacters'],
42
+ onSave: (ed) => console.log('save:', ed.getHTML()),
43
+ });
44
+
45
+ return (
46
+ <EditorThemeProvider mode="light">
47
+ <div
48
+ style={{
49
+ border: '1px solid #eee',
50
+ borderRadius: 10,
51
+ padding: '0 10px 10px',
52
+ }}
53
+ >
54
+ <div style={{ borderBottom: '1px solid #eee', marginBottom: 30 }}>
55
+ <EditorToolbar editor={editor} />
56
+ </div>
57
+ <Editor editor={editor} />
58
+ </div>
59
+ </EditorThemeProvider>
60
+ );
61
+ }
62
+ ```
63
+
64
+ ## 模块说明
65
+
66
+ ### useTiptap(核心 Hook)
67
+
68
+ 创建并管理 Tiptap 实例,统一扩展与回调。
69
+
70
+ - 常用入参:
71
+ - `editable?: boolean` 是否可编辑(默认 true)
72
+ - `content?: string | JSON` 初始内容
73
+ - `exclude?: string[]` 需要禁用的内置扩展名
74
+ - `extensions?: Extension[]` 自定义扩展
75
+ - `mentionItems?: string[]`、`onMentionFilter?: ({ query }) => Promise<string[]>`
76
+ - `onSave?(editor)`、`onError?(error)`
77
+ - `onUpload?(file, onProgress)` 自定义上传,返回可访问地址
78
+ - `onTocUpdate?(toc)`、`onAiWritingGetSuggestion?({ prefix, suffix }) => Promise<string>`
79
+ - 返回:`{ editor, getText, getHTML, getJSON, getMarkdownByJSON }`
80
+
81
+ ```tsx
82
+ const { editor } = useTiptap({
83
+ editable: true,
84
+ onSave: (ed) => console.log(ed.getHTML()),
85
+ onUpload: async (file, onProgress) => {
86
+ onProgress?.({ progress: 1 });
87
+ return 'https://example.com/file/url';
88
+ },
89
+ });
90
+ ```
91
+
92
+ ### EditorToolbar(工具栏)
93
+
94
+ 与 `editor` 绑定的可视化工具栏:撤销/重做、标题/字号、加粗/斜体/上下标、颜色、列表、对齐、链接、更多菜单,以及 AI 伴写开关。
95
+
96
+ - Props:`{ editor: Editor; menuInToolbarMore?: ToolbarItemType[] }`
13
97
 
14
- TODO
98
+ ```tsx
99
+ <EditorToolbar
100
+ editor={editor}
101
+ menuInToolbarMore={[{ id: 'my-action', label: '自定义' }]}
102
+ />
103
+ ```
104
+
105
+ ### Editor(编辑区)
106
+
107
+ 渲染编辑区域,包含文字选择气泡菜单与拖拽锚点菜单。
108
+
109
+ - Props:`{ editor: Editor; menuInDragHandle?: MenuItem[]; menuInBubbleMenu?: MenuItem[]; onTip?: (type, tip) => void }`
110
+
111
+ ```tsx
112
+ <Editor editor={editor} />
113
+ ```
114
+
115
+ ### EditorDiff(结构化对比)
116
+
117
+ 以只读方式展示两段 HTML 的结构化差异。
118
+
119
+ - Props:`{ oldHtml: string; newHtml: string }`
120
+
121
+ ```tsx
122
+ <EditorDiff oldHtml={'<p>old</p>'} newHtml={'<p><strong>new</strong></p>'} />
123
+ ```
15
124
 
16
125
  ## Development
17
126
 
18
127
  ```bash
19
128
  # install dependencies
20
- $ pnpm install
129
+ pnpm install
21
130
 
22
131
  # develop library by docs demo
23
- $ pnpm start
132
+ pnpm start
24
133
 
25
134
  # build library source code
26
- $ pnpm run build
135
+ pnpm run build
27
136
 
28
137
  # build library source code in watch mode
29
- $ pnpm run build:watch
138
+ pnpm run build:watch
30
139
 
31
140
  # build docs
32
- $ pnpm run docs:build
141
+ pnpm run docs:build
33
142
 
34
143
  # Locally preview the production build.
35
- $ pnpm run docs:preview
144
+ pnpm run docs:preview
36
145
 
37
146
  # check your project for potential problems
38
- $ pnpm run doctor
147
+ pnpm run doctor
39
148
  ```
40
149
 
41
150
  ## LICENSE
@@ -102,7 +102,7 @@ var Reader = function Reader() {
102
102
  }
103
103
  return onUpload;
104
104
  }(),
105
- content: ""
105
+ content: "<p>Hello Tiptap</p><p></p>"
106
106
  }),
107
107
  editor = _useTiptap.editor;
108
108
  return /*#__PURE__*/React.createElement(EditorThemeProvider, {
@@ -370,10 +370,7 @@ var CustomDragHandle = function CustomDragHandle(_ref3) {
370
370
  key: 'insert-divider',
371
371
  onClick: function onClick() {
372
372
  if (current.node && current.pos !== undefined) {
373
- var afterPos = current.pos + current.node.nodeSize;
374
- current.editor.chain().focus().insertContentAt(afterPos, {
375
- type: 'horizontalRule'
376
- }).run();
373
+ current.editor.chain().focus().setHorizontalRule().run();
377
374
  }
378
375
  },
379
376
  icon: /*#__PURE__*/React.createElement(SeparatorIcon, {
@@ -1066,7 +1063,7 @@ var CustomDragHandle = function CustomDragHandle(_ref3) {
1066
1063
  }),
1067
1064
  key: 'divider3'
1068
1065
  }, {
1069
- label: '引用块',
1066
+ label: '引用',
1070
1067
  selected: ((_current$node13 = current.node) === null || _current$node13 === void 0 ? void 0 : _current$node13.type.name) === 'blockquote',
1071
1068
  key: 'convert-to-blockquote',
1072
1069
  icon: /*#__PURE__*/React.createElement(QuoteTextIcon, {
@@ -120,6 +120,7 @@ export { TitleIcon } from './title-icon';
120
120
  export { UnderlineIcon } from './underline-icon';
121
121
  export { UploadCloud2LineIcon } from './upload-cloud-2-line-icon';
122
122
  export { UploadIcon } from './upload-icon';
123
+ export { UserSmileFillIcon } from './user-smile-fill-icon';
123
124
  export { VolumeMuteLineIcon } from './volume-mute-line-icon';
124
125
  export { VolumeUpLineIcon } from './volume-up-line-icon';
125
126
  export { WindowFillIcon } from './window-fill-icon';
@@ -123,6 +123,7 @@ export { TitleIcon } from "./title-icon";
123
123
  export { UnderlineIcon } from "./underline-icon";
124
124
  export { UploadCloud2LineIcon } from "./upload-cloud-2-line-icon";
125
125
  export { UploadIcon } from "./upload-icon";
126
+ export { UserSmileFillIcon } from "./user-smile-fill-icon";
126
127
  export { VolumeMuteLineIcon } from "./volume-mute-line-icon";
127
128
  export { VolumeUpLineIcon } from "./volume-up-line-icon";
128
129
  export { WindowFillIcon } from "./window-fill-icon";
@@ -0,0 +1,6 @@
1
+ import { SvgIconProps } from "@mui/material";
2
+ import * as React from "react";
3
+ export declare const UserSmileFillIcon: {
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 UserSmileFillIcon = function UserSmileFillIcon(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: "M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM7 12C7 14.7614 9.23858 17 12 17C14.7614 17 17 14.7614 17 12H15C15 13.6569 13.6569 15 12 15C10.3431 15 9 13.6569 9 12H7Z"
11
+ }));
12
+ };
13
+ UserSmileFillIcon.displayName = 'icon-user-smile-fill';
@@ -1,7 +1,7 @@
1
1
  import { getShortcutKeyText } from "../../../util";
2
2
  import { Typography } from '@mui/material';
3
3
  import React from 'react';
4
- import { AddCircleFillIcon, ArrowDownSLineIcon, AttachmentLineIcon, CheckboxCircleFillIcon, CloseCircleFillIcon, CodeBoxLineIcon, CodeLineIcon, CodeSSlashLineIcon, DoubleQuotesLIcon, ErrorWarningFillIcon, Folder2LineIcon, FormulaIcon, FunctionsIcon, ImageLineIcon, Information2FillIcon, Information2LineIcon, MenuFold2FillIcon, MovieLineIcon, Music2LineIcon, SeparatorIcon, SquareRootIcon, Table2Icon, WindowFillIcon } from "../../Icons";
4
+ import { AddCircleFillIcon, ArrowDownSLineIcon, AttachmentLineIcon, CheckboxCircleFillIcon, CloseCircleFillIcon, CodeBoxLineIcon, CodeLineIcon, CodeSSlashLineIcon, DoubleQuotesLIcon, ErrorWarningFillIcon, Folder2LineIcon, FormulaIcon, FunctionsIcon, ImageLineIcon, Information2FillIcon, Information2LineIcon, MenuFold2FillIcon, MovieLineIcon, Music2LineIcon, SeparatorIcon, SquareRootIcon, Table2Icon, UserSmileFillIcon, WindowFillIcon } from "../../Icons";
5
5
  import Menu from "../../Menu";
6
6
  import ToolbarItem from "../Item";
7
7
  import TableSizePicker from "../TableSizePicker";
@@ -180,12 +180,10 @@ var EditorInsert = function EditorInsert(_ref) {
180
180
  }
181
181
  }),
182
182
  onClick: function onClick() {
183
- return editor.commands.insertContentAt(editor.state.selection.from, {
184
- type: 'horizontalRule'
185
- });
183
+ return editor.chain().focus().setHorizontalRule().run();
186
184
  }
187
185
  }, {
188
- label: '引用块',
186
+ label: '引用',
189
187
  key: 'blockquote',
190
188
  icon: /*#__PURE__*/React.createElement(DoubleQuotesLIcon, {
191
189
  sx: {
@@ -202,7 +200,7 @@ var EditorInsert = function EditorInsert(_ref) {
202
200
  return editor.chain().focus().toggleBlockquote().run();
203
201
  }
204
202
  }, {
205
- label: '折叠块',
203
+ label: '折叠面板',
206
204
  key: 'details',
207
205
  icon: /*#__PURE__*/React.createElement(MenuFold2FillIcon, {
208
206
  sx: {
@@ -236,10 +234,10 @@ var EditorInsert = function EditorInsert(_ref) {
236
234
  }
237
235
  }),
238
236
  onClick: function onClick() {
239
- editor.commands.setAlert({
237
+ editor.chain().focus().setAlert({
240
238
  type: 'icon',
241
239
  variant: 'info'
242
- });
240
+ }).run();
243
241
  }
244
242
  }, {
245
243
  label: '警告 Warning',
@@ -251,10 +249,10 @@ var EditorInsert = function EditorInsert(_ref) {
251
249
  }
252
250
  }),
253
251
  onClick: function onClick() {
254
- editor.commands.setAlert({
252
+ editor.chain().focus().setAlert({
255
253
  type: 'icon',
256
254
  variant: 'warning'
257
- });
255
+ }).run();
258
256
  }
259
257
  }, {
260
258
  label: '错误 Error',
@@ -266,10 +264,10 @@ var EditorInsert = function EditorInsert(_ref) {
266
264
  }
267
265
  }),
268
266
  onClick: function onClick() {
269
- editor.commands.setAlert({
267
+ editor.chain().focus().setAlert({
270
268
  type: 'icon',
271
269
  variant: 'error'
272
- });
270
+ }).run();
273
271
  }
274
272
  }, {
275
273
  label: '成功 Success',
@@ -281,10 +279,25 @@ var EditorInsert = function EditorInsert(_ref) {
281
279
  }
282
280
  }),
283
281
  onClick: function onClick() {
284
- editor.commands.setAlert({
282
+ editor.chain().focus().setAlert({
285
283
  type: 'icon',
286
284
  variant: 'success'
287
- });
285
+ }).run();
286
+ }
287
+ }, {
288
+ label: '默认 Default',
289
+ key: 'default',
290
+ icon: /*#__PURE__*/React.createElement(UserSmileFillIcon, {
291
+ sx: {
292
+ fontSize: '1rem',
293
+ color: 'text.disabled'
294
+ }
295
+ }),
296
+ onClick: function onClick() {
297
+ editor.chain().focus().setAlert({
298
+ type: 'icon',
299
+ variant: 'default'
300
+ }).run();
288
301
  }
289
302
  }]
290
303
  }, {
@@ -320,7 +333,7 @@ var EditorInsert = function EditorInsert(_ref) {
320
333
  }
321
334
  }, getShortcutKeyText(['ctrl', 'E'], '+')),
322
335
  onClick: function onClick() {
323
- return editor.commands.toggleCode();
336
+ return editor.chain().focus().toggleCode().run();
324
337
  }
325
338
  }, {
326
339
  label: '代码块',
@@ -337,7 +350,7 @@ var EditorInsert = function EditorInsert(_ref) {
337
350
  }
338
351
  }, getShortcutKeyText(['ctrl', 'alt', 'C'], '+')),
339
352
  onClick: function onClick() {
340
- return editor.commands.toggleCodeBlock();
353
+ return editor.chain().focus().toggleCodeBlock().run();
341
354
  }
342
355
  }]
343
356
  }, {
@@ -64,7 +64,7 @@ export var NODE_TYPE_LABEL = (_NODE_TYPE_LABEL = {}, _defineProperty(_defineProp
64
64
  align: true,
65
65
  convert: true
66
66
  }), NodeTypeEnum.Blockquote, {
67
- label: '引用块',
67
+ label: '引用',
68
68
  color: true,
69
69
  fontSize: true,
70
70
  align: true,
@@ -73,7 +73,7 @@ export var NODE_TYPE_LABEL = (_NODE_TYPE_LABEL = {}, _defineProperty(_defineProp
73
73
  label: '代码块',
74
74
  convert: true
75
75
  }), NodeTypeEnum.Details, {
76
- label: '折叠块',
76
+ label: '折叠面板',
77
77
  align: true
78
78
  }), NodeTypeEnum.BlockMath, {
79
79
  label: '块公式'
@@ -7,10 +7,10 @@ export declare const PLACEHOLDER: {
7
7
  5: string;
8
8
  6: string;
9
9
  };
10
+ detailsSummary: string;
10
11
  orderedList: string;
11
12
  bulletList: string;
12
13
  taskList: string;
13
- blockquote: string;
14
14
  paragraph: string;
15
15
  default: string;
16
16
  };
@@ -7,10 +7,10 @@ export var PLACEHOLDER = {
7
7
  5: '五级标题',
8
8
  6: '六级标题'
9
9
  },
10
+ detailsSummary: '输入面板标题',
10
11
  orderedList: '列表',
11
12
  bulletList: '列表',
12
13
  taskList: '列表',
13
- blockquote: '引用',
14
14
  paragraph: '输入 "/" 插入内容',
15
15
  default: '写点什么吧,输入 "/" 插入内容'
16
16
  };
@@ -72,7 +72,7 @@ export var SHORTCUT_KEYS = {
72
72
  value: 'Block Math',
73
73
  keys: ['ctrl', '7']
74
74
  }, {
75
- label: '折叠块',
75
+ label: '折叠面板',
76
76
  value: 'Details',
77
77
  keys: ['ctrl', '8']
78
78
  }, {
@@ -152,7 +152,7 @@ export var SHORTCUT_KEYS = {
152
152
  value: 'Task list',
153
153
  keys: ['ctrl', 'shift', '9']
154
154
  }, {
155
- label: '引用块',
155
+ label: '引用',
156
156
  value: 'Blockquote',
157
157
  keys: ['ctrl', 'shift', 'B']
158
158
  }, {
@@ -154,7 +154,7 @@ export var slashCommands = [{
154
154
  editor.chain().focus().deleteRange(range).setHorizontalRule().run();
155
155
  }
156
156
  }, {
157
- title: '引用块',
157
+ title: '引用',
158
158
  shortcutKey: ['ctrl', 'shift', 'B'],
159
159
  icon: /*#__PURE__*/React.createElement(DoubleQuotesLIcon, {
160
160
  sx: {
@@ -208,7 +208,7 @@ export var slashCommands = [{
208
208
  }).run();
209
209
  }
210
210
  }, {
211
- title: '折叠块',
211
+ title: '折叠面板',
212
212
  shortcutKey: ['ctrl', '8'],
213
213
  icon: /*#__PURE__*/React.createElement(MenuFold2FillIcon, {
214
214
  sx: {
@@ -271,7 +271,7 @@ export var slashCommands = [{
271
271
  }).run();
272
272
  }
273
273
  }, {
274
- title: '折叠块',
274
+ title: '折叠面板',
275
275
  icon: /*#__PURE__*/React.createElement(MenuFold2FillIcon, {
276
276
  sx: {
277
277
  fontSize: '1rem'
@@ -2,7 +2,7 @@ import { NodeViewProps } from '@tiptap/react';
2
2
  import React from 'react';
3
3
  export interface AlertAttributes {
4
4
  id?: string;
5
- variant?: 'info' | 'warning' | 'error' | 'success';
5
+ variant?: 'info' | 'warning' | 'error' | 'success' | 'default';
6
6
  type?: 'text' | 'icon';
7
7
  }
8
8
  declare const AlertView: React.FC<NodeViewProps>;
@@ -5,7 +5,7 @@ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len
5
5
  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; } }
6
6
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
7
7
  import { FloatingPopover } from "../../../component";
8
- import { CheckboxCircleFillIcon, CloseCircleFillIcon, ErrorWarningFillIcon, Information2FillIcon, ScrollToBottomLineIcon, TextIcon } from "../../../component/Icons";
8
+ import { CheckboxCircleFillIcon, CloseCircleFillIcon, ErrorWarningFillIcon, Information2FillIcon, ScrollToBottomLineIcon, TextIcon, UserSmileFillIcon } from "../../../component/Icons";
9
9
  import { ToolbarItem } from "../../../component/Toolbar";
10
10
  import { Box, Divider, Stack } from '@mui/material';
11
11
  import { NodeViewContent, NodeViewWrapper } from '@tiptap/react';
@@ -42,6 +42,14 @@ var VARIANT_DATA = {
42
42
  }
43
43
  }),
44
44
  color: 'var(--mui-palette-success-main)'
45
+ },
46
+ default: {
47
+ icon: /*#__PURE__*/React.createElement(UserSmileFillIcon, {
48
+ sx: {
49
+ fontSize: '1.25rem'
50
+ }
51
+ }),
52
+ color: 'var(--mui-palette-divider)'
45
53
  }
46
54
  };
47
55
  var AlertView = function AlertView(_ref) {
@@ -75,20 +83,21 @@ var AlertView = function AlertView(_ref) {
75
83
  marginLeft: (_node$attrs = node.attrs) !== null && _node$attrs !== void 0 && _node$attrs.indent ? node.attrs.indent * 32 : undefined,
76
84
  border: '1px solid',
77
85
  borderColor: variantData.color,
78
- color: variantData.color,
86
+ color: attrs.variant === 'default' ? 'var(--mui-palette-text-primary)' : variantData.color,
79
87
  borderRadius: '10px',
80
88
  padding: '12px 16px',
81
89
  lineHeight: 1.625,
82
90
  display: 'flex',
83
91
  alignItems: 'flex-start',
84
92
  gap: '16px',
85
- background: "color-mix(in srgb, ".concat(variantData.color, " 10%, transparent)")
93
+ background: attrs.variant === 'default' ? 'var(--mui-palette-background-paper3)' : "color-mix(in srgb, ".concat(variantData.color, " 10%, transparent)")
86
94
  },
87
95
  onClick: handleShowOperationPopover
88
96
  }, showIcon && /*#__PURE__*/React.createElement(Box, {
89
97
  sx: {
90
98
  pt: '2px',
91
- lineHeight: 1
99
+ lineHeight: 1,
100
+ color: attrs.variant === 'default' ? 'text.disabled' : variantData.color
92
101
  }
93
102
  }, variantData.icon), /*#__PURE__*/React.createElement(Box, {
94
103
  sx: {
@@ -163,6 +172,20 @@ var AlertView = function AlertView(_ref) {
163
172
  });
164
173
  },
165
174
  className: attrs.variant === 'success' ? 'tool-active' : ''
175
+ }), /*#__PURE__*/React.createElement(ToolbarItem, {
176
+ icon: /*#__PURE__*/React.createElement(UserSmileFillIcon, {
177
+ sx: {
178
+ fontSize: '1rem',
179
+ color: 'text.disabled'
180
+ }
181
+ }),
182
+ tip: "\u9ED8\u8BA4",
183
+ onClick: function onClick() {
184
+ return updateAttributes({
185
+ variant: 'default'
186
+ });
187
+ },
188
+ className: attrs.variant === 'default' ? 'tool-active' : ''
166
189
  }), /*#__PURE__*/React.createElement(Divider, {
167
190
  orientation: "vertical",
168
191
  flexItem: true,
@@ -222,12 +222,12 @@ var ImageViewWrapper = function ImageViewWrapper(_ref) {
222
222
  }
223
223
  return /*#__PURE__*/React.createElement(NodeViewWrapper, {
224
224
  className: "image-wrapper ".concat(selected ? 'ProseMirror-selectednode' : ''),
225
- "data-drag-handle": true
225
+ "data-drag-handle": true,
226
+ as: 'span'
226
227
  }, /*#__PURE__*/React.createElement(Box, {
227
228
  component: 'span',
228
229
  sx: {
229
230
  position: 'relative',
230
- display: 'inline-block',
231
231
  border: '1px solid',
232
232
  borderColor: 'divider',
233
233
  borderRadius: 'var(--mui-shape-borderRadius)',
@@ -63,6 +63,8 @@ export var getExtensions = function getExtensions(_ref) {
63
63
  }), Placeholder.configure({
64
64
  emptyNodeClass: 'custom-placeholder-node',
65
65
  showOnlyWhenEditable: true,
66
+ showOnlyCurrent: true,
67
+ includeChildren: true,
66
68
  placeholder: function placeholder(_ref2) {
67
69
  var _storage;
68
70
  var editor = _ref2.editor,
@@ -70,7 +72,7 @@ export var getExtensions = function getExtensions(_ref) {
70
72
  pos = _ref2.pos;
71
73
  var type = node.type,
72
74
  attrs = node.attrs;
73
- if (pos === 0) {
75
+ if (pos === 0 && editor.isEmpty) {
74
76
  return PLACEHOLDER.default;
75
77
  }
76
78
  var aiWritingEnabled = !!(editor !== null && editor !== void 0 && (_storage = editor.storage) !== null && _storage !== void 0 && (_storage = _storage.aiWriting) !== null && _storage !== void 0 && _storage.enabled);
@@ -1,9 +1,9 @@
1
1
  import { Node } from '@tiptap/core';
2
- export type AlertVariant = 'info' | 'warning' | 'error' | 'success';
2
+ export type AlertVariant = 'info' | 'warning' | 'error' | 'success' | 'default';
3
3
  export type AlertType = 'text' | 'icon';
4
4
  export interface AlertOptions {
5
5
  /**
6
- * HTML attributes to add to the blockquote element
6
+ * HTML attributes to add to the alert element
7
7
  * @default {}
8
8
  * @example { class: 'foo' }
9
9
  */
@@ -35,5 +35,13 @@ export var DetailsExtension = CustomDetails.configure({
35
35
  class: 'cq-details'
36
36
  }
37
37
  });
38
- export var DetailsSummaryExtension = DetailsSummary.configure({});
39
- export var DetailsContentExtension = DetailsContent.configure({});
38
+ export var DetailsSummaryExtension = DetailsSummary.configure({
39
+ HTMLAttributes: {
40
+ class: 'cq-details-summary'
41
+ }
42
+ });
43
+ export var DetailsContentExtension = DetailsContent.configure({
44
+ HTMLAttributes: {
45
+ class: 'cq-details-content'
46
+ }
47
+ });
package/dist/index.css CHANGED
@@ -3,7 +3,7 @@
3
3
  .tiptap.ProseMirror {
4
4
  overflow-y: auto;
5
5
  outline: none;
6
- color: var(--mui-palette-text-secondary);
6
+ color: var(--mui-palette-text-primary);
7
7
  }
8
8
 
9
9
  /* 节点缩进(依赖 data-indent 属性) */
@@ -74,7 +74,6 @@
74
74
  margin: 0 0 20px;
75
75
  border-radius: 10px;
76
76
  border: 1px solid var(--mui-palette-divider);
77
- color: var(--mui-palette-text-secondary);
78
77
  background-color: var(--mui-palette-background-paper3);
79
78
  }
80
79
 
@@ -225,7 +224,7 @@
225
224
  font-size: 0.625rem;
226
225
  border: none;
227
226
  width: 1.25rem;
228
- height: 1.25rem;
227
+ height: 1.5rem;
229
228
  margin-top: 0.1rem;
230
229
  padding: 0;
231
230
  }
@@ -291,7 +290,6 @@
291
290
  position: relative;
292
291
  color: inherit;
293
292
  font-style: inherit;
294
- color: var(--mui-palette-text-primary);
295
293
  }
296
294
 
297
295
  .tiptap.ProseMirror h1 {
@@ -389,7 +387,6 @@
389
387
  .tiptap.ProseMirror table th {
390
388
  background-color: var(--mui-palette-background-paper3);
391
389
  font-weight: 600;
392
- color: var(--mui-palette-text-primary);
393
390
  text-transform: uppercase;
394
391
  letter-spacing: 0.5px;
395
392
  text-align: left;
@@ -556,8 +553,18 @@
556
553
 
557
554
  /* AI 续写建议样式 */
558
555
  .tiptap.ProseMirror .ai-writing-suggestion {
559
- color: var(--mui-palette-text-disabled);
556
+ color: color-mix(in srgb, var(--mui-palette-text-primary) 15%, transparent);
560
557
  pointer-events: none;
561
558
  user-select: none;
562
559
  white-space: pre-wrap;
560
+ }
561
+
562
+ /* placeholder */
563
+ .tiptap.ProseMirror .cq-details[data-placeholder]::before,
564
+ .tiptap.ProseMirror .table-row[data-placeholder]::before {
565
+ display: none;
566
+ }
567
+
568
+ .tiptap.ProseMirror li p[data-placeholder]::before {
569
+ display: none;
563
570
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ctzhian/tiptap",
3
- "version": "1.6.5",
3
+ "version": "1.6.7",
4
4
  "description": "基于 Tiptap 二次开发的编辑器组件",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",