@milkdown/preset-commonmark 6.5.4 → 7.0.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/lib/composed/commands.d.ts +3 -0
  2. package/lib/composed/commands.d.ts.map +1 -0
  3. package/lib/composed/index.d.ts +6 -0
  4. package/lib/composed/index.d.ts.map +1 -0
  5. package/lib/composed/inputrules.d.ts +3 -0
  6. package/lib/composed/inputrules.d.ts.map +1 -0
  7. package/lib/composed/keymap.d.ts +3 -0
  8. package/lib/composed/keymap.d.ts.map +1 -0
  9. package/lib/composed/plugins.d.ts +2 -0
  10. package/lib/composed/plugins.d.ts.map +1 -0
  11. package/lib/composed/schema.d.ts +3 -0
  12. package/lib/composed/schema.d.ts.map +1 -0
  13. package/lib/index.d.ts +4 -29
  14. package/lib/index.d.ts.map +1 -1
  15. package/lib/index.es.js +1101 -1386
  16. package/lib/index.es.js.map +1 -1
  17. package/lib/mark/emphasis.d.ts +5 -0
  18. package/lib/mark/emphasis.d.ts.map +1 -0
  19. package/lib/mark/index.d.ts +3 -4
  20. package/lib/mark/index.d.ts.map +1 -1
  21. package/lib/mark/inline-code.d.ts +5 -0
  22. package/lib/mark/inline-code.d.ts.map +1 -0
  23. package/lib/mark/link.d.ts +8 -10
  24. package/lib/mark/link.d.ts.map +1 -1
  25. package/lib/mark/strong.d.ts +4 -2
  26. package/lib/mark/strong.d.ts.map +1 -1
  27. package/lib/node/blockquote.d.ts +6 -2
  28. package/lib/node/blockquote.d.ts.map +1 -1
  29. package/lib/node/bullet-list.d.ts +5 -2
  30. package/lib/node/bullet-list.d.ts.map +1 -1
  31. package/lib/node/code-block.d.ts +10 -0
  32. package/lib/node/code-block.d.ts.map +1 -0
  33. package/lib/node/doc.d.ts +1 -1
  34. package/lib/node/doc.d.ts.map +1 -1
  35. package/lib/node/hardbreak.d.ts +4 -6
  36. package/lib/node/hardbreak.d.ts.map +1 -1
  37. package/lib/node/heading.d.ts +7 -12
  38. package/lib/node/heading.d.ts.map +1 -1
  39. package/lib/node/hr.d.ts +4 -2
  40. package/lib/node/hr.d.ts.map +1 -1
  41. package/lib/node/image.d.ts +10 -11
  42. package/lib/node/image.d.ts.map +1 -1
  43. package/lib/node/index.d.ts +6 -8
  44. package/lib/node/index.d.ts.map +1 -1
  45. package/lib/node/list-item.d.ts +6 -7
  46. package/lib/node/list-item.d.ts.map +1 -1
  47. package/lib/node/ordered-list.d.ts +5 -2
  48. package/lib/node/ordered-list.d.ts.map +1 -1
  49. package/lib/node/paragraph.d.ts +4 -2
  50. package/lib/node/paragraph.d.ts.map +1 -1
  51. package/lib/node/text.d.ts +1 -1
  52. package/lib/node/text.d.ts.map +1 -1
  53. package/lib/plugin/hardbreak-clear-mark-plugin.d.ts +2 -0
  54. package/lib/plugin/hardbreak-clear-mark-plugin.d.ts.map +1 -0
  55. package/lib/plugin/hardbreak-filter-plugin.d.ts +3 -0
  56. package/lib/plugin/hardbreak-filter-plugin.d.ts.map +1 -0
  57. package/lib/plugin/index.d.ts +9 -3
  58. package/lib/plugin/index.d.ts.map +1 -1
  59. package/lib/plugin/{inline-nodes-cursor.d.ts → inline-nodes-cursor-plugin.d.ts} +2 -3
  60. package/lib/plugin/inline-nodes-cursor-plugin.d.ts.map +1 -0
  61. package/lib/plugin/{inline-sync → inline-sync-plugin}/config.d.ts +2 -2
  62. package/lib/plugin/inline-sync-plugin/config.d.ts.map +1 -0
  63. package/lib/plugin/{inline-sync → inline-sync-plugin}/context.d.ts +1 -2
  64. package/lib/plugin/inline-sync-plugin/context.d.ts.map +1 -0
  65. package/lib/plugin/inline-sync-plugin/index.d.ts +3 -0
  66. package/lib/plugin/inline-sync-plugin/index.d.ts.map +1 -0
  67. package/lib/plugin/inline-sync-plugin/inline-sync-plugin.d.ts +2 -0
  68. package/lib/plugin/inline-sync-plugin/inline-sync-plugin.d.ts.map +1 -0
  69. package/lib/plugin/{inline-sync → inline-sync-plugin}/regexp.d.ts +0 -0
  70. package/lib/plugin/inline-sync-plugin/regexp.d.ts.map +1 -0
  71. package/lib/plugin/{inline-sync → inline-sync-plugin}/replacer.d.ts +1 -1
  72. package/lib/plugin/inline-sync-plugin/replacer.d.ts.map +1 -0
  73. package/lib/plugin/{inline-sync → inline-sync-plugin}/utils.d.ts +0 -0
  74. package/lib/plugin/inline-sync-plugin/utils.d.ts.map +1 -0
  75. package/lib/plugin/remark-add-order-in-list-plugin.d.ts +2 -0
  76. package/lib/plugin/remark-add-order-in-list-plugin.d.ts.map +1 -0
  77. package/lib/plugin/remark-inline-link-plugin.d.ts +2 -0
  78. package/lib/plugin/remark-inline-link-plugin.d.ts.map +1 -0
  79. package/lib/plugin/remark-line-break.d.ts +2 -0
  80. package/lib/plugin/remark-line-break.d.ts.map +1 -0
  81. package/lib/plugin/sync-heading-id-plugin.d.ts +2 -0
  82. package/lib/plugin/sync-heading-id-plugin.d.ts.map +1 -0
  83. package/lib/plugin/sync-list-order-plugin.d.ts +2 -0
  84. package/lib/plugin/sync-list-order-plugin.d.ts.map +1 -0
  85. package/package.json +9 -7
  86. package/src/composed/commands.ts +30 -0
  87. package/src/composed/index.ts +6 -0
  88. package/src/composed/inputrules.ts +12 -0
  89. package/src/composed/keymap.ts +19 -0
  90. package/src/composed/plugins.ts +21 -0
  91. package/src/composed/schema.ts +54 -0
  92. package/src/index.ts +5 -52
  93. package/src/mark/emphasis.ts +42 -0
  94. package/src/mark/index.ts +3 -10
  95. package/src/mark/inline-code.ts +64 -0
  96. package/src/mark/link.ts +87 -247
  97. package/src/mark/strong.ts +35 -36
  98. package/src/node/blockquote.ts +32 -33
  99. package/src/node/bullet-list.ts +56 -56
  100. package/src/node/code-block.ts +93 -0
  101. package/src/node/doc.ts +17 -22
  102. package/src/node/hardbreak.ts +60 -117
  103. package/src/node/heading.ts +158 -281
  104. package/src/node/hr.ts +51 -57
  105. package/src/node/image.ts +102 -209
  106. package/src/node/index.ts +6 -35
  107. package/src/node/list-item.ts +81 -142
  108. package/src/node/ordered-list.ts +64 -65
  109. package/src/node/paragraph.ts +48 -50
  110. package/src/node/text.ts +13 -16
  111. package/src/plugin/hardbreak-clear-mark-plugin.ts +44 -0
  112. package/src/plugin/hardbreak-filter-plugin.ts +31 -0
  113. package/src/plugin/index.ts +12 -14
  114. package/src/plugin/{inline-nodes-cursor.ts → inline-nodes-cursor-plugin.ts} +4 -4
  115. package/src/plugin/{inline-sync → inline-sync-plugin}/config.ts +4 -3
  116. package/src/plugin/{inline-sync → inline-sync-plugin}/context.ts +4 -6
  117. package/src/plugin/inline-sync-plugin/index.ts +4 -0
  118. package/src/plugin/{inline-sync/index.ts → inline-sync-plugin/inline-sync-plugin.ts} +9 -11
  119. package/src/plugin/{inline-sync → inline-sync-plugin}/regexp.ts +0 -0
  120. package/src/plugin/{inline-sync → inline-sync-plugin}/replacer.ts +3 -3
  121. package/src/plugin/{inline-sync → inline-sync-plugin}/utils.ts +0 -0
  122. package/src/plugin/remark-add-order-in-list-plugin.ts +15 -0
  123. package/src/plugin/remark-inline-link-plugin.ts +5 -0
  124. package/src/plugin/remark-line-break.ts +41 -0
  125. package/src/plugin/sync-heading-id-plugin.ts +53 -0
  126. package/src/plugin/sync-list-order-plugin.ts +57 -0
  127. package/lib/mark/code-inline.d.ts +0 -3
  128. package/lib/mark/code-inline.d.ts.map +0 -1
  129. package/lib/mark/em.d.ts +0 -3
  130. package/lib/mark/em.d.ts.map +0 -1
  131. package/lib/node/code-fence.d.ts +0 -7
  132. package/lib/node/code-fence.d.ts.map +0 -1
  133. package/lib/plugin/add-order-in-list.d.ts +0 -3
  134. package/lib/plugin/add-order-in-list.d.ts.map +0 -1
  135. package/lib/plugin/filter-html.d.ts +0 -3
  136. package/lib/plugin/filter-html.d.ts.map +0 -1
  137. package/lib/plugin/inline-nodes-cursor.d.ts.map +0 -1
  138. package/lib/plugin/inline-sync/config.d.ts.map +0 -1
  139. package/lib/plugin/inline-sync/context.d.ts.map +0 -1
  140. package/lib/plugin/inline-sync/index.d.ts +0 -6
  141. package/lib/plugin/inline-sync/index.d.ts.map +0 -1
  142. package/lib/plugin/inline-sync/regexp.d.ts.map +0 -1
  143. package/lib/plugin/inline-sync/replacer.d.ts.map +0 -1
  144. package/lib/plugin/inline-sync/utils.d.ts.map +0 -1
  145. package/lib/supported-keys.d.ts +0 -23
  146. package/lib/supported-keys.d.ts.map +0 -1
  147. package/src/mark/code-inline.ts +0 -66
  148. package/src/mark/em.ts +0 -42
  149. package/src/node/code-fence.ts +0 -245
  150. package/src/plugin/add-order-in-list.ts +0 -19
  151. package/src/plugin/filter-html.ts +0 -43
  152. package/src/supported-keys.ts +0 -25
  153. package/src/types.d.ts +0 -5
package/src/node/image.ts CHANGED
@@ -1,224 +1,117 @@
1
1
  /* Copyright 2021, Milkdown by Mirone. */
2
- import type { ThemeImageType, ThemeInputChipType } from '@milkdown/core'
3
- import { commandsCtx, createCmd, createCmdKey } from '@milkdown/core'
4
2
  import { expectDomTypeError } from '@milkdown/exception'
5
3
  import { findSelectedNodeOfType } from '@milkdown/prose'
6
4
  import { InputRule } from '@milkdown/prose/inputrules'
7
- import { Plugin, PluginKey } from '@milkdown/prose/state'
8
- import type { EditorView, NodeView } from '@milkdown/prose/view'
9
- import { createNode } from '@milkdown/utils'
5
+ import { $command, $inputRule, $nodeAttr, $nodeSchema } from '@milkdown/utils'
10
6
 
11
- export const ModifyImage = createCmdKey<string>('ModifyImage')
12
- export const InsertImage = createCmdKey<string>('InsertImage')
13
- const id = 'image'
14
- export interface ImageOptions {
15
- isBlock: boolean
16
- placeholder: string
17
- input: {
18
- placeholder: string
19
- buttonText?: string
20
- }
21
- }
22
- const key = new PluginKey('MILKDOWN_IMAGE_INPUT')
7
+ export const imageAttr = $nodeAttr('image')
23
8
 
24
- export const image = createNode<string, ImageOptions>((utils, options) => {
9
+ export const imageSchema = $nodeSchema('image', (ctx) => {
25
10
  return {
26
- id: 'image',
27
- schema: () => ({
28
- inline: true,
29
- group: 'inline',
30
- selectable: true,
31
- draggable: true,
32
- marks: '',
33
- atom: true,
34
- defining: true,
35
- isolating: true,
36
- attrs: {
37
- src: { default: '' },
38
- alt: { default: '' },
39
- title: { default: '' },
40
- },
41
- parseDOM: [
42
- {
43
- tag: 'img[src]',
44
- getAttrs: (dom) => {
45
- if (!(dom instanceof HTMLElement))
46
- throw expectDomTypeError(dom)
47
-
48
- return {
49
- src: dom.getAttribute('src') || '',
50
- alt: dom.getAttribute('alt') || '',
51
- title: dom.getAttribute('title') || dom.getAttribute('alt') || '',
52
- }
53
- },
11
+ inline: true,
12
+ group: 'inline',
13
+ selectable: true,
14
+ draggable: true,
15
+ marks: '',
16
+ atom: true,
17
+ defining: true,
18
+ isolating: true,
19
+ attrs: {
20
+ src: { default: '' },
21
+ alt: { default: '' },
22
+ title: { default: '' },
23
+ },
24
+ parseDOM: [
25
+ {
26
+ tag: 'img[src]',
27
+ getAttrs: (dom) => {
28
+ if (!(dom instanceof HTMLElement))
29
+ throw expectDomTypeError(dom)
30
+
31
+ return {
32
+ src: dom.getAttribute('src') || '',
33
+ alt: dom.getAttribute('alt') || '',
34
+ title: dom.getAttribute('title') || dom.getAttribute('alt') || '',
35
+ }
54
36
  },
55
- ],
56
- toDOM: (node) => {
57
- return [
58
- 'img',
59
- {
60
- ...node.attrs,
61
- class: utils.getClassName(node.attrs, id),
62
- },
63
- ]
64
37
  },
65
- parseMarkdown: {
66
- match: ({ type }) => type === id,
67
- runner: (state, node, type) => {
68
- const url = node.url as string
69
- const alt = node.alt as string
70
- const title = node.title as string
71
- state.addNode(type, {
72
- src: url,
73
- alt,
74
- title,
75
- })
76
- },
38
+ ],
39
+ toDOM: (node) => {
40
+ return ['img', { ...ctx.get(imageAttr.key)(node), ...node.attrs }]
41
+ },
42
+ parseMarkdown: {
43
+ match: ({ type }) => type === 'image',
44
+ runner: (state, node, type) => {
45
+ const url = node.url as string
46
+ const alt = node.alt as string
47
+ const title = node.title as string
48
+ state.addNode(type, {
49
+ src: url,
50
+ alt,
51
+ title,
52
+ })
77
53
  },
78
- toMarkdown: {
79
- match: node => node.type.name === id,
80
- runner: (state, node) => {
81
- state.addNode('image', undefined, undefined, {
82
- title: node.attrs.title,
83
- url: node.attrs.src,
84
- alt: node.attrs.alt,
85
- })
86
- },
54
+ },
55
+ toMarkdown: {
56
+ match: node => node.type.name === 'image',
57
+ runner: (state, node) => {
58
+ state.addNode('image', undefined, undefined, {
59
+ title: node.attrs.title,
60
+ url: node.attrs.src,
61
+ alt: node.attrs.alt,
62
+ })
87
63
  },
88
- }),
89
- commands: type => [
90
- createCmd(InsertImage, (src = '') => (state, dispatch) => {
91
- if (!dispatch)
92
- return true
93
- const { tr } = state
94
- const node = type.create({ src })
95
- if (!node)
96
- return true
97
-
98
- const _tr = tr.replaceSelectionWith(node)
99
- dispatch(_tr.scrollIntoView())
100
- return true
101
- }),
102
- createCmd(ModifyImage, (src = '') => (state, dispatch) => {
103
- const node = findSelectedNodeOfType(state.selection, type)
104
- if (!node)
105
- return false
106
-
107
- const { tr } = state
108
- dispatch?.(
109
- tr.setNodeMarkup(node.pos, undefined, { ...node.node.attrs, loading: true, src }).scrollIntoView(),
110
- )
111
-
112
- return true
113
- }),
114
- ],
115
- inputRules: type => [
116
- new InputRule(
117
- /!\[(?<alt>.*?)]\((?<filename>.*?)\s*(?="|\))"?(?<title>[^"]+)?"?\)/,
118
- (state, match, start, end) => {
119
- const [okay, alt, src = '', title] = match
120
- const { tr } = state
121
- if (okay)
122
- tr.replaceWith(start, end, type.create({ src, alt, title }))
123
-
124
- return tr
125
- },
126
- ),
127
- ],
128
- view: () => (node) => {
129
- let currNode = node
130
-
131
- const placeholder = options?.placeholder ?? 'Add an Image'
132
- const isBlock = options?.isBlock ?? false
133
- const renderer = utils.themeManager.get<ThemeImageType>('image', {
134
- placeholder,
135
- isBlock,
136
- })
137
-
138
- if (!renderer)
139
- return {} as NodeView
140
-
141
- const { dom, onUpdate } = renderer
142
- onUpdate(currNode)
143
-
144
- return {
145
- dom,
146
- update: (updatedNode) => {
147
- if (updatedNode.type.name !== id)
148
- return false
149
-
150
- currNode = updatedNode
151
- onUpdate(currNode)
152
-
153
- return true
154
- },
155
- selectNode: () => {
156
- dom.classList.add('ProseMirror-selectednode')
157
- },
158
- deselectNode: () => {
159
- dom.classList.remove('ProseMirror-selectednode')
160
- },
161
- }
162
64
  },
163
- prosePlugins: (type, ctx) => {
164
- return [
165
- new Plugin({
166
- key,
167
- view: (editorView) => {
168
- const inputChipRenderer = utils.themeManager.get<ThemeInputChipType>('input-chip', {
169
- placeholder: options?.input?.placeholder ?? 'Input Image Link',
170
- buttonText: options?.input?.buttonText,
171
- onUpdate: (value) => {
172
- ctx.get(commandsCtx).call(ModifyImage, value)
173
- },
174
- })
175
- if (!inputChipRenderer)
176
- return {}
177
- const shouldDisplay = (view: EditorView) => {
178
- return Boolean(
179
- view.hasFocus() && type && findSelectedNodeOfType(view.state.selection, type),
180
- )
181
- }
182
- const getCurrentLink = (view: EditorView) => {
183
- const result = findSelectedNodeOfType(view.state.selection, type)
184
- if (!result)
185
- return
186
-
187
- const value = result.node.attrs.src
188
- return value
189
- }
190
- const renderByView = (view: EditorView) => {
191
- if (!view.editable)
192
- return
65
+ }
66
+ })
193
67
 
194
- const display = shouldDisplay(view)
195
- if (display) {
196
- inputChipRenderer.show(view)
197
- inputChipRenderer.update(getCurrentLink(view))
198
- }
199
- else {
200
- inputChipRenderer.hide()
201
- }
202
- }
203
- inputChipRenderer.init(editorView)
204
- renderByView(editorView)
68
+ export type UpdateImageCommandPayload = {
69
+ src?: string
70
+ title?: string
71
+ alt?: string
72
+ }
73
+ export const insertImageCommand = $command('InsertImage', () => (payload: UpdateImageCommandPayload = {}) =>
74
+ (state, dispatch) => {
75
+ if (!dispatch)
76
+ return true
77
+
78
+ const { src = '', alt = '', title = '' } = payload
79
+
80
+ const node = imageSchema.type().create({ src, alt, title })
81
+ if (!node)
82
+ return true
83
+
84
+ dispatch(state.tr.replaceSelectionWith(node).scrollIntoView())
85
+ return true
86
+ })
87
+
88
+ export const updateImageCommand = $command('UpdateImage', () => (payload: UpdateImageCommandPayload = {}) => (state, dispatch) => {
89
+ const nodeWithPos = findSelectedNodeOfType(state.selection, imageSchema.type())
90
+ if (!nodeWithPos)
91
+ return false
92
+
93
+ const { node, pos } = nodeWithPos
94
+
95
+ const newAttrs = { ...node.attrs }
96
+ const { src, alt, title } = payload
97
+ if (src !== undefined)
98
+ newAttrs.src = src
99
+ if (alt !== undefined)
100
+ newAttrs.alt = alt
101
+ if (title !== undefined)
102
+ newAttrs.title = title
103
+
104
+ dispatch?.(state.tr.setNodeMarkup(pos, undefined, newAttrs).scrollIntoView())
105
+ return true
106
+ })
205
107
 
206
- return {
207
- update: (view, prevState) => {
208
- const isEqualSelection
209
- = prevState?.doc.eq(view.state.doc) && prevState.selection.eq(view.state.selection)
210
- if (isEqualSelection)
211
- return
108
+ export const insertImageInputRule = $inputRule(() => new InputRule(
109
+ /!\[(?<alt>.*?)]\((?<filename>.*?)\s*(?="|\))"?(?<title>[^"]+)?"?\)/,
110
+ (state, match, start, end) => {
111
+ const [matched, alt, src = '', title] = match
112
+ if (matched)
113
+ return state.tr.replaceWith(start, end, imageSchema.type().create({ src, alt, title }))
212
114
 
213
- renderByView(view)
214
- },
215
- destroy: () => {
216
- inputChipRenderer.destroy()
217
- },
218
- }
219
- },
220
- }),
221
- ]
222
- },
223
- }
224
- })
115
+ return null
116
+ },
117
+ ))
package/src/node/index.ts CHANGED
@@ -1,43 +1,14 @@
1
1
  /* Copyright 2021, Milkdown by Mirone. */
2
- import type { AtomPlugin } from '@milkdown/utils'
3
2
 
4
- import { blockquote } from './blockquote'
5
- import { bulletList } from './bullet-list'
6
- import { codeFence } from './code-fence'
7
- import { doc } from './doc'
8
- import { hardbreak } from './hardbreak'
9
- import { heading } from './heading'
10
- import { hr } from './hr'
11
- import { image } from './image'
12
- import { listItem } from './list-item'
13
- import { orderedList } from './ordered-list'
14
- import { paragraph } from './paragraph'
15
- import { text } from './text'
16
-
17
- export const nodes: AtomPlugin[] = [
18
- doc(),
19
- paragraph(),
20
- hardbreak(),
21
- blockquote(),
22
- codeFence(),
23
- bulletList(),
24
- orderedList(),
25
- listItem(),
26
- heading(),
27
- hr(),
28
- image(),
29
- text(),
30
- ]
31
-
32
- export * from './blockquote'
33
- export * from './bullet-list'
34
- export * from './code-fence'
35
3
  export * from './doc'
36
- export * from './hardbreak'
37
4
  export * from './heading'
38
- export * from './hr'
5
+ export * from './blockquote'
6
+ export * from './code-block'
39
7
  export * from './image'
40
- export * from './list-item'
8
+ export * from './hardbreak'
9
+ export * from './hr'
10
+ export * from './bullet-list'
41
11
  export * from './ordered-list'
12
+ export * from './list-item'
42
13
  export * from './paragraph'
43
14
  export * from './text'
@@ -1,157 +1,96 @@
1
1
  /* Copyright 2021, Milkdown by Mirone. */
2
- import { createCmd, createCmdKey } from '@milkdown/core'
2
+ import { commandsCtx } from '@milkdown/core'
3
3
  import { expectDomTypeError } from '@milkdown/exception'
4
- import { getNodeFromSchema } from '@milkdown/prose'
5
- import { wrappingInputRule } from '@milkdown/prose/inputrules'
6
- import type { NodeType } from '@milkdown/prose/model'
7
4
  import { liftListItem, sinkListItem, splitListItem } from '@milkdown/prose/schema-list'
8
- import type { EditorState, Transaction } from '@milkdown/prose/state'
9
- import { Plugin, PluginKey } from '@milkdown/prose/state'
10
- import { createNode, createShortcut } from '@milkdown/utils'
5
+ import { $command, $nodeAttr, $nodeSchema, $useKeymap } from '@milkdown/utils'
11
6
 
12
- import { SupportedKeys } from '../supported-keys'
7
+ export const listItemAttr = $nodeAttr('listItem')
13
8
 
14
- type Keys = SupportedKeys['SinkListItem'] | SupportedKeys['LiftListItem'] | SupportedKeys['NextListItem']
15
-
16
- const id = 'list_item'
17
-
18
- export const SplitListItem = createCmdKey('SplitListItem')
19
- export const SinkListItem = createCmdKey('SinkListItem')
20
- export const LiftListItem = createCmdKey('LiftListItem')
21
-
22
- const keepListOrderPluginKey = new PluginKey('MILKDOWN_KEEP_LIST_ORDER')
23
-
24
- const createKeepListOrderPlugin = (type: NodeType) => {
25
- const walkThrough = (state: EditorState, callback: (tr: Transaction) => void) => {
26
- const orderedListType = getNodeFromSchema('ordered_list', state.schema)
27
- let tr = state.tr
28
- state.doc.descendants((node, pos, parent, index) => {
29
- if (node.type === type && parent?.type === orderedListType) {
30
- let changed = false
31
- const attrs = { ...node.attrs }
32
- if (node.attrs.listType !== 'ordered') {
33
- attrs.listType = 'ordered'
34
- changed = true
35
- }
36
-
37
- const base = parent?.maybeChild(0)
38
- if (base && base.type === type && base.attrs.listType === 'ordered') {
39
- attrs.label = `${index + 1}.`
40
- changed = true
41
- }
42
-
43
- if (node.attrs.label === '•') {
44
- attrs.label = `${index + 1}.`
45
- changed = true
46
- }
47
-
48
- if (changed)
49
- tr = tr.setNodeMarkup(pos, undefined, attrs)
50
- }
51
- })
52
- callback(tr)
53
- }
54
- return new Plugin({
55
- key: keepListOrderPluginKey,
56
- appendTransaction: (transactions, _oldState, nextState) => {
57
- let tr: Transaction | null = null
58
- if (transactions.some(transaction => transaction.docChanged)) {
59
- walkThrough(nextState, (t) => {
60
- tr = t
61
- })
62
- }
63
-
64
- return tr
9
+ export const listItemSchema = $nodeSchema('list_item', ctx => ({
10
+ group: 'listItem',
11
+ content: 'paragraph block*',
12
+ attrs: {
13
+ label: {
14
+ default: '',
15
+ },
16
+ listType: {
17
+ default: 'bullet',
18
+ },
19
+ spread: {
20
+ default: 'true',
65
21
  },
66
- })
67
- }
22
+ },
23
+ defining: true,
24
+ parseDOM: [
25
+ {
26
+ tag: 'li',
27
+ getAttrs: (dom) => {
28
+ if (!(dom instanceof HTMLElement))
29
+ throw expectDomTypeError(dom)
68
30
 
69
- export const listItem = createNode<Keys>(utils => ({
70
- id,
71
- schema: () => ({
72
- group: 'listItem',
73
- content: 'paragraph block*',
74
- attrs: {
75
- label: {
76
- default: '•',
77
- },
78
- listType: {
79
- default: 'bullet',
80
- },
81
- spread: {
82
- default: 'true',
31
+ return {
32
+ label: dom.dataset.label,
33
+ listType: dom.dataset['list-type'],
34
+ spread: dom.dataset.spread,
35
+ }
83
36
  },
84
37
  },
85
- defining: true,
86
- parseDOM: [
87
- {
88
- tag: 'li.list-item',
89
- getAttrs: (dom) => {
90
- if (!(dom instanceof HTMLElement))
91
- throw expectDomTypeError(dom)
92
-
93
- return {
94
- label: dom.dataset.label,
95
- listType: dom.dataset['list-type'],
96
- spread: dom.dataset.spread,
97
- }
98
- },
99
- contentElement: (dom) => {
100
- if (!(dom instanceof HTMLElement))
101
- throw expectDomTypeError(dom)
38
+ ],
39
+ toDOM: node => [
40
+ 'li',
41
+ {
42
+ ...ctx.get(listItemAttr.key)(node),
43
+ 'data-label': node.attrs.label,
44
+ 'data-list-type': node.attrs.listType,
45
+ 'data-spread': node.attrs.spread,
46
+ },
47
+ 0,
48
+ ],
49
+ parseMarkdown: {
50
+ match: ({ type }) => type === 'listItem',
51
+ runner: (state, node, type) => {
52
+ const label = node.label != null ? `${node.label}.` : '•'
53
+ const listType = node.label != null ? 'ordered' : 'bullet'
54
+ const spread = node.spread != null ? `${node.spread}` : 'true'
55
+ state.openNode(type, { label, listType, spread })
56
+ state.next(node.children)
57
+ state.closeNode()
58
+ },
59
+ },
60
+ toMarkdown: {
61
+ match: node => node.type.name === 'list_item',
62
+ runner: (state, node) => {
63
+ state.openNode('listItem', undefined, { spread: node.attrs.spread === 'true' })
64
+ state.next(node.content)
65
+ state.closeNode()
66
+ },
67
+ },
68
+ }))
102
69
 
103
- const body = dom.querySelector<HTMLElement>('.list-item_body')
104
- if (!body)
105
- return dom
70
+ export const sinkListItemCommand = $command('SinkListItem', () => () => sinkListItem(listItemSchema.type()))
71
+ export const splitListItemCommand = $command('SplitListItem', () => () => splitListItem(listItemSchema.type()))
72
+ export const liftListItemCommand = $command('SplitListItem', () => () => liftListItem(listItemSchema.type()))
106
73
 
107
- return body
108
- },
109
- },
110
- { tag: 'li' },
111
- ],
112
- toDOM: (node) => {
113
- return [
114
- 'li',
115
- {
116
- 'class': utils.getClassName(node.attrs, 'list-item'),
117
- 'data-label': node.attrs.label,
118
- 'data-list-type': node.attrs.listType,
119
- 'data-spread': node.attrs.spread,
120
- },
121
- ['div', { class: utils.getClassName(node.attrs, 'list-item_label') }, node.attrs.label],
122
- ['div', { class: utils.getClassName(node.attrs, 'list-item_body') }, 0],
123
- ]
74
+ export const listItemKeymap = $useKeymap('listItemKeymap', {
75
+ NextListItem: {
76
+ shortcuts: 'Enter',
77
+ command: (ctx) => {
78
+ const commands = ctx.get(commandsCtx)
79
+ return () => commands.call(splitListItemCommand.key)
124
80
  },
125
- parseMarkdown: {
126
- match: ({ type, checked }) => type === 'listItem' && checked === null,
127
- runner: (state, node, type) => {
128
- const label = node.label != null ? `${node.label}.` : '•'
129
- const listType = node.label != null ? 'ordered' : 'bullet'
130
- const spread = node.spread != null ? `${node.spread}` : 'true'
131
- state.openNode(type, { label, listType, spread })
132
- state.next(node.children)
133
- state.closeNode()
134
- },
81
+ },
82
+ SinkListItem: {
83
+ shortcuts: ['Tab', 'Mod-]'],
84
+ command: (ctx) => {
85
+ const commands = ctx.get(commandsCtx)
86
+ return () => commands.call(sinkListItemCommand.key)
135
87
  },
136
- toMarkdown: {
137
- match: node => node.type.name === id,
138
- runner: (state, node) => {
139
- state.openNode('listItem', undefined, { spread: node.attrs.spread === 'true' })
140
- state.next(node.content)
141
- state.closeNode()
142
- },
88
+ },
89
+ LiftListItem: {
90
+ shortcuts: ['Shift-Tab', 'Mod-['],
91
+ command: (ctx) => {
92
+ const commands = ctx.get(commandsCtx)
93
+ return () => commands.call(liftListItemCommand.key)
143
94
  },
144
- }),
145
- inputRules: nodeType => [wrappingInputRule(/^\s*([-+*])\s$/, nodeType)],
146
- commands: nodeType => [
147
- createCmd(SplitListItem, () => splitListItem(nodeType)),
148
- createCmd(SinkListItem, () => sinkListItem(nodeType)),
149
- createCmd(LiftListItem, () => liftListItem(nodeType)),
150
- ],
151
- shortcuts: {
152
- [SupportedKeys.NextListItem]: createShortcut(SplitListItem, 'Enter'),
153
- [SupportedKeys.SinkListItem]: createShortcut(SinkListItem, 'Mod-]'),
154
- [SupportedKeys.LiftListItem]: createShortcut(LiftListItem, 'Mod-['),
155
95
  },
156
- prosePlugins: nodeType => [createKeepListOrderPlugin(nodeType)],
157
- }))
96
+ })