@kaitify/core 0.0.1-beta.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 (119) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +3 -0
  3. package/examples/App.vue +342 -0
  4. package/examples/content.js +1 -0
  5. package/examples/main.ts +4 -0
  6. package/examples/test.html +23 -0
  7. package/lib/extensions/Extension.d.ts +172 -0
  8. package/lib/extensions/align/index.d.ts +10 -0
  9. package/lib/extensions/attachment/index.d.ts +29 -0
  10. package/lib/extensions/back-color/index.d.ts +9 -0
  11. package/lib/extensions/blockquote/index.d.ts +12 -0
  12. package/lib/extensions/bold/index.d.ts +9 -0
  13. package/lib/extensions/code/index.d.ts +12 -0
  14. package/lib/extensions/code-block/hljs.d.ts +12 -0
  15. package/lib/extensions/code-block/index.d.ts +15 -0
  16. package/lib/extensions/color/index.d.ts +9 -0
  17. package/lib/extensions/font-family/index.d.ts +9 -0
  18. package/lib/extensions/font-size/index.d.ts +9 -0
  19. package/lib/extensions/heading/index.d.ts +13 -0
  20. package/lib/extensions/history/index.d.ts +10 -0
  21. package/lib/extensions/horizontal/index.d.ts +7 -0
  22. package/lib/extensions/image/index.d.ts +26 -0
  23. package/lib/extensions/indent/index.d.ts +8 -0
  24. package/lib/extensions/index.d.ts +29 -0
  25. package/lib/extensions/italic/index.d.ts +9 -0
  26. package/lib/extensions/line-height/index.d.ts +9 -0
  27. package/lib/extensions/link/index.d.ts +27 -0
  28. package/lib/extensions/list/index.d.ts +18 -0
  29. package/lib/extensions/math/index.d.ts +11 -0
  30. package/lib/extensions/strikethrough/index.d.ts +9 -0
  31. package/lib/extensions/subscript/index.d.ts +9 -0
  32. package/lib/extensions/superscript/index.d.ts +9 -0
  33. package/lib/extensions/table/index.d.ts +21 -0
  34. package/lib/extensions/task/index.d.ts +12 -0
  35. package/lib/extensions/text/index.d.ts +14 -0
  36. package/lib/extensions/underline/index.d.ts +9 -0
  37. package/lib/extensions/video/index.d.ts +27 -0
  38. package/lib/index.d.ts +3 -0
  39. package/lib/kaitify-core.es.js +38337 -0
  40. package/lib/kaitify-core.umd.js +2 -0
  41. package/lib/model/Editor.d.ts +504 -0
  42. package/lib/model/History.d.ts +42 -0
  43. package/lib/model/KNode.d.ts +258 -0
  44. package/lib/model/Selection.d.ts +29 -0
  45. package/lib/model/config/dom-observe.d.ts +10 -0
  46. package/lib/model/config/event-handler.d.ts +33 -0
  47. package/lib/model/config/format-patch.d.ts +25 -0
  48. package/lib/model/config/format-rules.d.ts +37 -0
  49. package/lib/model/config/function.d.ts +84 -0
  50. package/lib/model/index.d.ts +6 -0
  51. package/lib/tools/index.d.ts +49 -0
  52. package/lib/view/index.d.ts +21 -0
  53. package/lib/view/js-render/dom-patch.d.ts +65 -0
  54. package/lib/view/js-render/index.d.ts +5 -0
  55. package/package.json +52 -0
  56. package/src/css/style.less +56 -0
  57. package/src/css/var.less +45 -0
  58. package/src/extensions/Extension.ts +200 -0
  59. package/src/extensions/align/index.ts +115 -0
  60. package/src/extensions/attachment/icon.svg +1 -0
  61. package/src/extensions/attachment/index.ts +293 -0
  62. package/src/extensions/attachment/style.less +25 -0
  63. package/src/extensions/back-color/index.ts +56 -0
  64. package/src/extensions/blockquote/index.ts +144 -0
  65. package/src/extensions/blockquote/style.less +16 -0
  66. package/src/extensions/bold/index.ts +77 -0
  67. package/src/extensions/code/index.ts +295 -0
  68. package/src/extensions/code/style.less +14 -0
  69. package/src/extensions/code-block/hljs.less +183 -0
  70. package/src/extensions/code-block/hljs.ts +95 -0
  71. package/src/extensions/code-block/index.ts +308 -0
  72. package/src/extensions/code-block/style.less +20 -0
  73. package/src/extensions/color/index.ts +56 -0
  74. package/src/extensions/font-family/index.ts +80 -0
  75. package/src/extensions/font-size/index.ts +56 -0
  76. package/src/extensions/heading/index.ts +164 -0
  77. package/src/extensions/heading/style.less +42 -0
  78. package/src/extensions/history/index.ts +96 -0
  79. package/src/extensions/horizontal/index.ts +45 -0
  80. package/src/extensions/horizontal/style.less +13 -0
  81. package/src/extensions/image/index.ts +242 -0
  82. package/src/extensions/image/style.less +8 -0
  83. package/src/extensions/indent/index.ts +98 -0
  84. package/src/extensions/index.ts +29 -0
  85. package/src/extensions/italic/index.ts +77 -0
  86. package/src/extensions/line-height/index.ts +113 -0
  87. package/src/extensions/link/index.ts +184 -0
  88. package/src/extensions/link/style.less +19 -0
  89. package/src/extensions/list/index.ts +410 -0
  90. package/src/extensions/list/style.less +19 -0
  91. package/src/extensions/math/index.ts +233 -0
  92. package/src/extensions/math/style.less +21 -0
  93. package/src/extensions/strikethrough/index.ts +78 -0
  94. package/src/extensions/subscript/index.ts +77 -0
  95. package/src/extensions/superscript/index.ts +77 -0
  96. package/src/extensions/table/index.ts +1148 -0
  97. package/src/extensions/table/style.less +71 -0
  98. package/src/extensions/task/index.ts +243 -0
  99. package/src/extensions/task/style.less +59 -0
  100. package/src/extensions/text/index.ts +359 -0
  101. package/src/extensions/underline/index.ts +78 -0
  102. package/src/extensions/video/index.ts +273 -0
  103. package/src/extensions/video/style.less +8 -0
  104. package/src/index.ts +9 -0
  105. package/src/model/Editor.ts +1963 -0
  106. package/src/model/History.ts +115 -0
  107. package/src/model/KNode.ts +677 -0
  108. package/src/model/Selection.ts +39 -0
  109. package/src/model/config/dom-observe.ts +184 -0
  110. package/src/model/config/event-handler.ts +237 -0
  111. package/src/model/config/format-patch.ts +215 -0
  112. package/src/model/config/format-rules.ts +218 -0
  113. package/src/model/config/function.ts +1018 -0
  114. package/src/model/index.ts +6 -0
  115. package/src/tools/index.ts +156 -0
  116. package/src/view/index.ts +46 -0
  117. package/src/view/js-render/dom-patch.ts +324 -0
  118. package/src/view/js-render/index.ts +210 -0
  119. package/vite-env.d.ts +2 -0
@@ -0,0 +1,42 @@
1
+ .Kaitify {
2
+ h1,
3
+ h2,
4
+ h3,
5
+ h4,
6
+ h5,
7
+ h6,
8
+ p {
9
+ line-height: var(--kaitify-line-height);
10
+ margin: 0 0 var(--kaitify-large-margin) 0 !important;
11
+
12
+ &:last-child {
13
+ margin-bottom: 0 !important;
14
+ }
15
+ }
16
+
17
+ //段落和标题
18
+ h1 {
19
+ font-size: 48px;
20
+ font-weight: bold;
21
+ }
22
+ h2 {
23
+ font-size: 36px;
24
+ font-weight: bold;
25
+ }
26
+ h3 {
27
+ font-size: 28px;
28
+ font-weight: bold;
29
+ }
30
+ h4 {
31
+ font-size: 24px;
32
+ font-weight: bold;
33
+ }
34
+ h5 {
35
+ font-size: 18px;
36
+ font-weight: bold;
37
+ }
38
+ h6 {
39
+ font-size: 16px;
40
+ font-weight: bold;
41
+ }
42
+ }
@@ -0,0 +1,96 @@
1
+ import { platform } from 'dap-util'
2
+ import { Extension } from '../Extension'
3
+
4
+ declare module '../../model' {
5
+ interface EditorCommandsType {
6
+ canUndo?: () => boolean
7
+ canRedo?: () => boolean
8
+ undo?: () => Promise<void>
9
+ redo?: () => Promise<void>
10
+ }
11
+ }
12
+
13
+ /**
14
+ * 键盘是否执行撤销操作
15
+ */
16
+ const isUndo = function (e: KeyboardEvent) {
17
+ const { Mac } = platform.os()
18
+ if (Mac) {
19
+ return e.key.toLocaleLowerCase() == 'z' && e.metaKey && !e.shiftKey && !e.altKey && !e.ctrlKey
20
+ }
21
+ return e.key.toLocaleLowerCase() == 'z' && e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey
22
+ }
23
+
24
+ /**
25
+ * 键盘是否执行重做操作
26
+ */
27
+ const isRedo = function (e: KeyboardEvent) {
28
+ const { Mac } = platform.os()
29
+ if (Mac) {
30
+ return e.key.toLocaleLowerCase() == 'z' && e.metaKey && e.shiftKey && !e.altKey && !e.ctrlKey
31
+ }
32
+ return e.key.toLocaleLowerCase() == 'y' && e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey
33
+ }
34
+
35
+ export const HistoryExtension = () =>
36
+ Extension.create({
37
+ name: 'history',
38
+ onKeydown(event) {
39
+ //撤销
40
+ if (isUndo(event)) {
41
+ event.preventDefault()
42
+ this.commands.undo?.()
43
+ }
44
+ //重做
45
+ else if (isRedo(event)) {
46
+ event.preventDefault()
47
+ this.commands.redo?.()
48
+ }
49
+ },
50
+ addCommands() {
51
+ /**
52
+ * 是否可以撤销
53
+ */
54
+ const canUndo = () => {
55
+ return this.history.records.length > 1
56
+ }
57
+
58
+ /**
59
+ * 是否可以重做
60
+ */
61
+ const canRedo = () => {
62
+ return this.history.redoRecords.length > 0
63
+ }
64
+
65
+ /**
66
+ * 撤销
67
+ */
68
+ const undo = async () => {
69
+ const record = this.history.setUndo()
70
+ if (record) {
71
+ this.stackNodes = record.nodes
72
+ this.selection = record.selection
73
+ await this.updateView(true, true)
74
+ }
75
+ }
76
+
77
+ /**
78
+ * 重做
79
+ */
80
+ const redo = async () => {
81
+ const record = this.history.setRedo()
82
+ if (record) {
83
+ this.stackNodes = record.nodes
84
+ this.selection = record.selection
85
+ await this.updateView(true, true)
86
+ }
87
+ }
88
+
89
+ return {
90
+ canUndo,
91
+ canRedo,
92
+ redo,
93
+ undo
94
+ }
95
+ }
96
+ })
@@ -0,0 +1,45 @@
1
+ import { KNode } from '@/model'
2
+ import { Extension } from '../Extension'
3
+ import './style.less'
4
+
5
+ declare module '../../model' {
6
+ interface EditorCommandsType {
7
+ setHorizontal?: () => Promise<void>
8
+ }
9
+ }
10
+
11
+ export const HorizontalExtension = () =>
12
+ Extension.create({
13
+ name: 'horizontal',
14
+ extraKeepTags: ['hr'],
15
+ domParseNodeCallback(node) {
16
+ if (node.isMatch({ tag: 'hr' })) {
17
+ node.type = 'closed'
18
+ }
19
+ return node
20
+ },
21
+ formatRules: [
22
+ ({ node }) => {
23
+ if (node.isMatch({ tag: 'hr' })) {
24
+ node.type = 'closed'
25
+ }
26
+ }
27
+ ],
28
+ addCommands() {
29
+ /**
30
+ * 设置分隔线
31
+ */
32
+ const setHorizontal = async () => {
33
+ const node = KNode.create({
34
+ type: 'closed',
35
+ tag: 'hr'
36
+ })
37
+ this.insertNode(node)
38
+ await this.updateView()
39
+ }
40
+
41
+ return {
42
+ setHorizontal
43
+ }
44
+ }
45
+ })
@@ -0,0 +1,13 @@
1
+ .Kaitify hr {
2
+ appearance: none;
3
+ display: block;
4
+ width: 100%;
5
+ height: 2px;
6
+ background: fade(#000, 20);
7
+ border: none;
8
+ margin: var(--kaitify-large-margin) 0;
9
+ }
10
+
11
+ :root[kaitify-dark] .Kaitify hr {
12
+ background: fade(#fff, 20);
13
+ }
@@ -0,0 +1,242 @@
1
+ import interact from 'interactjs'
2
+ import { event as DapEvent, data as DapData } from 'dap-util'
3
+ import { Editor, KNode, KNodeMarksType, KNodeStylesType } from '@/model'
4
+ import { Extension } from '../Extension'
5
+ import './style.less'
6
+ import { deleteProperty } from '@/tools'
7
+
8
+ /**
9
+ * 插入图片方法入参类型
10
+ */
11
+ export type SetImageOptionType = {
12
+ src: string
13
+ alt?: string
14
+ width?: string
15
+ }
16
+
17
+ /**
18
+ * 更新图片方法入参类型
19
+ */
20
+ export type UpdateImageOptionType = {
21
+ src?: string
22
+ alt?: string
23
+ }
24
+
25
+ declare module '../../model' {
26
+ interface EditorCommandsType {
27
+ getImage?: () => KNode | null
28
+ hasImage?: () => boolean
29
+ setImage?: (options: SetImageOptionType) => Promise<void>
30
+ updateImage?: (options: UpdateImageOptionType) => Promise<void>
31
+ }
32
+ }
33
+
34
+ /**
35
+ * 设置图片选中
36
+ */
37
+ const imageFocus = (editor: Editor) => {
38
+ DapEvent.off(editor.$el!, 'click.image_focus')
39
+ DapEvent.on(editor.$el!, 'click.image_focus', e => {
40
+ //编辑器不可编辑状态下不设置
41
+ if (!editor.isEditable()) {
42
+ return
43
+ }
44
+ const event = e as MouseEvent
45
+ const elm = event.target as HTMLElement
46
+ if (elm === editor.$el) {
47
+ return
48
+ }
49
+ const node = editor.findNode(elm)
50
+ const matchNode = node.getMatchNode({
51
+ tag: 'img'
52
+ })
53
+ if (matchNode) {
54
+ editor.setSelectionBefore(matchNode, 'start')
55
+ editor.setSelectionAfter(matchNode, 'end')
56
+ editor.updateRealSelection()
57
+ }
58
+ })
59
+ }
60
+ /**
61
+ * 设置图片拖拽
62
+ */
63
+ const imageResizable = (editor: Editor) => {
64
+ //设置拖拽改变大小的功能
65
+ interact('.Kaitify img').unset()
66
+ interact('.Kaitify img').resizable({
67
+ //是否启用
68
+ enabled: true,
69
+ //指定可以调整大小的边缘
70
+ edges: { left: false, right: true, bottom: false, top: false },
71
+ //设置鼠标样式
72
+ cursorChecker() {
73
+ return editor.isEditable() ? 'ew-resize' : 'default'
74
+ },
75
+ //启用惯性效果
76
+ inertia: false,
77
+ //调整大小时的自动滚动功能
78
+ autoScroll: true,
79
+ //保持图片的宽高比
80
+ preserveAspectRatio: true,
81
+ //水平调整
82
+ axis: 'x',
83
+ //事件
84
+ listeners: {
85
+ start(event) {
86
+ //不可编辑状态下不能拖拽
87
+ if (!editor.isEditable()) {
88
+ event.interaction.stop()
89
+ return
90
+ }
91
+ //禁用dragstart
92
+ DapEvent.on(event.target, 'dragstart', e => e.preventDefault())
93
+ //获取图片节点
94
+ const node = editor.findNode(event.target)
95
+ //暂存
96
+ DapData.set(event.target, 'node', node)
97
+ },
98
+ //拖拽
99
+ move(event) {
100
+ //获取宽度
101
+ const { width } = event.rect
102
+ //设置dom的宽度
103
+ event.target.style.width = `${width}px`
104
+ },
105
+ //结束拖拽
106
+ end(event) {
107
+ //恢复dragstart
108
+ DapEvent.off(event.target, 'dragstart')
109
+ //获取宽度
110
+ const { width } = event.rect
111
+ //设置百分比宽度
112
+ const percentWidth = Number(((width / event.target.parentElement.offsetWidth) * 100).toFixed(2))
113
+ //获取图片节点
114
+ const node = DapData.get(event.target, 'node')
115
+ //设置节点的styles
116
+ if (node.hasStyles()) {
117
+ node.styles!.width = `${percentWidth}%`
118
+ } else {
119
+ node.styles = {
120
+ width: `${percentWidth}%`
121
+ }
122
+ }
123
+ //更新视图
124
+ editor.updateView()
125
+ }
126
+ }
127
+ })
128
+ }
129
+
130
+ export const ImageExtension = () =>
131
+ Extension.create({
132
+ name: 'image',
133
+ extraKeepTags: ['img'],
134
+ domParseNodeCallback(node) {
135
+ if (node.isMatch({ tag: 'img' })) {
136
+ node.type = 'closed'
137
+ }
138
+ return node
139
+ },
140
+ formatRules: [
141
+ ({ node }) => {
142
+ if (node.isMatch({ tag: 'img' })) {
143
+ node.type = 'closed'
144
+ }
145
+ }
146
+ ],
147
+ pasteKeepMarks(node) {
148
+ const marks: KNodeMarksType = {}
149
+ if (node.isMatch({ tag: 'img' }) && node.hasMarks()) {
150
+ if (node.marks!.hasOwnProperty('alt')) marks['alt'] = node.marks!['alt']
151
+ if (node.marks!.hasOwnProperty('src')) marks['src'] = node.marks!['src']
152
+ }
153
+ return marks
154
+ },
155
+ pasteKeepStyles(node) {
156
+ const styles: KNodeStylesType = {}
157
+ if (node.isMatch({ tag: 'img' }) && node.hasStyles()) {
158
+ styles['width'] = node.styles!['width'] || 'auto'
159
+ }
160
+ return styles
161
+ },
162
+ afterUpdateView() {
163
+ //图片选中
164
+ imageFocus(this)
165
+ //图片拖拽改变大小
166
+ imageResizable(this)
167
+ },
168
+ addCommands() {
169
+ /**
170
+ * 获取光标所在的图片,如果光标不在一张图片内,返回null
171
+ */
172
+ const getImage = () => {
173
+ return this.getMatchNodeBySelection({
174
+ tag: 'img'
175
+ })
176
+ }
177
+
178
+ /**
179
+ * 判断光标范围内是否有图片
180
+ */
181
+ const hasImage = () => {
182
+ return this.isSelectionNodesSomeMatch({
183
+ tag: 'img'
184
+ })
185
+ }
186
+
187
+ /**
188
+ * 插入图片
189
+ */
190
+ const setImage = async (options: SetImageOptionType) => {
191
+ if (!this.selection.focused()) {
192
+ return
193
+ }
194
+ if (!options.src) {
195
+ return
196
+ }
197
+ const imageNode = KNode.create({
198
+ type: 'closed',
199
+ tag: 'img',
200
+ marks: {
201
+ src: options.src,
202
+ alt: options.alt || ''
203
+ },
204
+ styles: {
205
+ width: options.width || 'auto'
206
+ }
207
+ })
208
+ this.insertNode(imageNode)
209
+ this.setSelectionAfter(imageNode)
210
+ await this.updateView()
211
+ }
212
+
213
+ /**
214
+ * 更新图片
215
+ */
216
+ const updateImage = async (options: UpdateImageOptionType) => {
217
+ if (!this.selection.focused()) {
218
+ return
219
+ }
220
+ if (!options.src && !options.alt) {
221
+ return
222
+ }
223
+ const imageNode = getImage()
224
+ if (!imageNode) {
225
+ return
226
+ }
227
+ //更新url
228
+ if (options.src) {
229
+ imageNode.marks!.src = options.src
230
+ }
231
+ //更新alt
232
+ if (options.alt) {
233
+ imageNode.marks!.alt = options.alt
234
+ } else {
235
+ imageNode.marks = deleteProperty(imageNode.marks!, 'alt')
236
+ }
237
+ await this.updateView()
238
+ }
239
+
240
+ return { getImage, hasImage, setImage, updateImage }
241
+ }
242
+ })
@@ -0,0 +1,8 @@
1
+ .Kaitify img {
2
+ display: inline-block;
3
+ position: relative;
4
+ width: auto;
5
+ min-width: 20px;
6
+ max-width: 100%;
7
+ padding: 0 var(--kaitify-sides-between);
8
+ }
@@ -0,0 +1,98 @@
1
+ import { KNodeStylesType } from '@/model'
2
+ import { getSelectionBlockNodes } from '@/model/config/function'
3
+ import { Extension } from '../Extension'
4
+
5
+ declare module '../../model' {
6
+ interface EditorCommandsType {
7
+ setIncreaseIndent?: () => Promise<void>
8
+ setDecreaseIndent?: () => Promise<void>
9
+ }
10
+ }
11
+
12
+ export const IndentExtension = () =>
13
+ Extension.create({
14
+ name: 'indent',
15
+ pasteKeepStyles(node) {
16
+ const styles: KNodeStylesType = {}
17
+ if (node.isBlock() && node.hasStyles()) {
18
+ if (node.styles!.hasOwnProperty('textIndent')) styles.textIndent = node.styles!.textIndent
19
+ }
20
+ return styles
21
+ },
22
+ addCommands() {
23
+ /**
24
+ * 增加缩进
25
+ */
26
+ const setIncreaseIndent = async () => {
27
+ //起点和终点在一起
28
+ if (this.selection.collapsed()) {
29
+ const blockNode = this.selection.start!.node.getBlock()
30
+ const styles: KNodeStylesType = blockNode.hasStyles() ? blockNode.styles! : {}
31
+ let oldVal = 0
32
+ if (styles.textIndent && typeof styles.textIndent == 'string' && styles.textIndent.endsWith('em')) {
33
+ oldVal = parseFloat(styles.textIndent)
34
+ }
35
+ blockNode.styles = {
36
+ ...styles,
37
+ textIndent: `${oldVal + 2}em`
38
+ }
39
+ }
40
+ //起点和终点不在一起
41
+ else {
42
+ const blockNodes = getSelectionBlockNodes.apply(this)
43
+ blockNodes.forEach(item => {
44
+ const styles: KNodeStylesType = item.hasStyles() ? item.styles! : {}
45
+ let oldVal = 0
46
+ if (styles.textIndent && typeof styles.textIndent == 'string' && styles.textIndent.endsWith('em')) {
47
+ oldVal = parseFloat(styles.textIndent)
48
+ }
49
+ item.styles = {
50
+ ...styles,
51
+ textIndent: `${oldVal + 2}em`
52
+ }
53
+ })
54
+ }
55
+ await this.updateView()
56
+ }
57
+
58
+ /**
59
+ * 减少缩进
60
+ */
61
+ const setDecreaseIndent = async () => {
62
+ //起点和终点在一起
63
+ if (this.selection.collapsed()) {
64
+ const blockNode = this.selection.start!.node.getBlock()
65
+ const styles: KNodeStylesType = blockNode.hasStyles() ? blockNode.styles! : {}
66
+ let oldVal = 0
67
+ if (styles.textIndent && typeof styles.textIndent == 'string' && styles.textIndent.endsWith('em')) {
68
+ oldVal = parseFloat(styles.textIndent)
69
+ }
70
+ blockNode.styles = {
71
+ ...styles,
72
+ textIndent: `${oldVal - 2 > 0 ? oldVal - 2 : 0}em`
73
+ }
74
+ }
75
+ //起点和终点不在一起
76
+ else {
77
+ const blockNodes = getSelectionBlockNodes.apply(this)
78
+ blockNodes.forEach(item => {
79
+ const styles: KNodeStylesType = item.hasStyles() ? item.styles! : {}
80
+ let oldVal = 0
81
+ if (styles.textIndent && typeof styles.textIndent == 'string' && styles.textIndent.endsWith('em')) {
82
+ oldVal = parseFloat(styles.textIndent)
83
+ }
84
+ item.styles = {
85
+ ...styles,
86
+ textIndent: `${oldVal - 2 > 0 ? oldVal - 2 : 0}em`
87
+ }
88
+ })
89
+ }
90
+ await this.updateView()
91
+ }
92
+
93
+ return {
94
+ setDecreaseIndent,
95
+ setIncreaseIndent
96
+ }
97
+ }
98
+ })
@@ -0,0 +1,29 @@
1
+ export * from './Extension'
2
+ export * from './text'
3
+ export * from './history'
4
+ export * from './image'
5
+ export * from './video'
6
+ export * from './bold'
7
+ export * from './italic'
8
+ export * from './strikethrough'
9
+ export * from './underline'
10
+ export * from './superscript'
11
+ export * from './subscript'
12
+ export * from './code'
13
+ export * from './font-size'
14
+ export * from './font-family'
15
+ export * from './color'
16
+ export * from './back-color'
17
+ export * from './link'
18
+ export * from './align'
19
+ export * from './line-height'
20
+ export * from './indent'
21
+ export * from './horizontal'
22
+ export * from './blockquote'
23
+ export * from './heading'
24
+ export * from './list'
25
+ export * from './task'
26
+ export * from './math'
27
+ export * from './code-block'
28
+ export * from './attachment'
29
+ export * from './table'
@@ -0,0 +1,77 @@
1
+ import { KNodeStylesType } from '@/model'
2
+ import { splitNodeToNodes } from '@/model/config/function'
3
+ import { Extension } from '../Extension'
4
+
5
+ declare module '../../model' {
6
+ interface EditorCommandsType {
7
+ isItalic?: () => boolean
8
+ setItalic?: () => Promise<void>
9
+ unsetItalic?: () => Promise<void>
10
+ }
11
+ }
12
+
13
+ export const ItalicExtension = () =>
14
+ Extension.create({
15
+ name: 'italic',
16
+ pasteKeepStyles(node) {
17
+ const styles: KNodeStylesType = {}
18
+ if (node.isText() && node.hasStyles()) {
19
+ if (node.styles!.hasOwnProperty('fontStyle')) styles.fontStyle = node.styles!.fontStyle
20
+ }
21
+ return styles
22
+ },
23
+ extraKeepTags: ['i'],
24
+ domParseNodeCallback(node) {
25
+ if (node.isMatch({ tag: 'i' })) {
26
+ node.type = 'inline'
27
+ }
28
+ return node
29
+ },
30
+ formatRules: [
31
+ ({ editor, node }) => {
32
+ if (!node.isEmpty() && node.isMatch({ tag: 'i' })) {
33
+ const styles: KNodeStylesType = node.styles || {}
34
+ node.styles = {
35
+ ...styles,
36
+ fontStyle: 'italic'
37
+ }
38
+ node.tag = editor.textRenderTag
39
+ splitNodeToNodes.apply(editor, [node])
40
+ }
41
+ }
42
+ ],
43
+ addCommands() {
44
+ /**
45
+ * 光标所在文本是否斜体
46
+ */
47
+ const isItalic = () => {
48
+ return this.commands.isTextStyle!('fontStyle', 'italic')
49
+ }
50
+ /**
51
+ * 设置斜体
52
+ */
53
+ const setItalic = async () => {
54
+ if (isItalic()) {
55
+ return
56
+ }
57
+ await this.commands.setTextStyle!({
58
+ fontStyle: 'italic'
59
+ })
60
+ }
61
+ /**
62
+ * 取消斜体
63
+ */
64
+ const unsetItalic = async () => {
65
+ if (!isItalic()) {
66
+ return
67
+ }
68
+ await this.commands.removeTextStyle!(['fontStyle'])
69
+ }
70
+
71
+ return {
72
+ isItalic,
73
+ setItalic,
74
+ unsetItalic
75
+ }
76
+ }
77
+ })