@milkdown/preset-commonmark 6.5.4 → 7.0.0-next.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 (154) 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 +3 -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 +1099 -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-plugin.d.ts +2 -0
  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 +31 -0
  87. package/src/composed/index.ts +6 -0
  88. package/src/composed/inputrules.ts +13 -0
  89. package/src/composed/keymap.ts +20 -0
  90. package/src/composed/plugins.ts +23 -0
  91. package/src/composed/schema.ts +55 -0
  92. package/src/index.ts +6 -52
  93. package/src/mark/emphasis.ts +47 -0
  94. package/src/mark/index.ts +3 -10
  95. package/src/mark/inline-code.ts +70 -0
  96. package/src/mark/link.ts +96 -247
  97. package/src/mark/strong.ts +41 -36
  98. package/src/node/blockquote.ts +39 -33
  99. package/src/node/bullet-list.ts +62 -55
  100. package/src/node/code-block.ts +103 -0
  101. package/src/node/doc.ts +18 -22
  102. package/src/node/hardbreak.ts +68 -117
  103. package/src/node/heading.ts +175 -284
  104. package/src/node/hr.ts +57 -57
  105. package/src/node/image.ts +113 -209
  106. package/src/node/index.ts +6 -35
  107. package/src/node/list-item.ts +125 -141
  108. package/src/node/ordered-list.ts +70 -65
  109. package/src/node/paragraph.ts +54 -50
  110. package/src/node/text.ts +14 -16
  111. package/src/plugin/hardbreak-clear-mark-plugin.ts +45 -0
  112. package/src/plugin/hardbreak-filter-plugin.ts +33 -0
  113. package/src/plugin/index.ts +12 -14
  114. package/src/plugin/{inline-nodes-cursor.ts → inline-nodes-cursor-plugin.ts} +5 -8
  115. package/src/plugin/{inline-sync → inline-sync-plugin}/config.ts +18 -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} +14 -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 +16 -0
  123. package/src/plugin/remark-inline-link-plugin.ts +6 -0
  124. package/src/plugin/remark-line-break.ts +44 -0
  125. package/src/plugin/sync-heading-id-plugin.ts +55 -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 +0 -7
  138. package/lib/plugin/inline-nodes-cursor.d.ts.map +0 -1
  139. package/lib/plugin/inline-sync/config.d.ts.map +0 -1
  140. package/lib/plugin/inline-sync/context.d.ts.map +0 -1
  141. package/lib/plugin/inline-sync/index.d.ts +0 -6
  142. package/lib/plugin/inline-sync/index.d.ts.map +0 -1
  143. package/lib/plugin/inline-sync/regexp.d.ts.map +0 -1
  144. package/lib/plugin/inline-sync/replacer.d.ts.map +0 -1
  145. package/lib/plugin/inline-sync/utils.d.ts.map +0 -1
  146. package/lib/supported-keys.d.ts +0 -23
  147. package/lib/supported-keys.d.ts.map +0 -1
  148. package/src/mark/code-inline.ts +0 -66
  149. package/src/mark/em.ts +0 -42
  150. package/src/node/code-fence.ts +0 -245
  151. package/src/plugin/add-order-in-list.ts +0 -19
  152. package/src/plugin/filter-html.ts +0 -43
  153. package/src/supported-keys.ts +0 -25
  154. package/src/types.d.ts +0 -5
@@ -1,42 +1,47 @@
1
1
  /* Copyright 2021, Milkdown by Mirone. */
2
- import { createCmd, createCmdKey } from '@milkdown/core'
2
+ import { commandsCtx } from '@milkdown/core'
3
3
  import { toggleMark } from '@milkdown/prose/commands'
4
- import { createMark, createShortcut } from '@milkdown/utils'
4
+ import { $command, $markAttr, $markSchema, $useKeymap } from '@milkdown/utils'
5
5
 
6
- import { SupportedKeys } from '../supported-keys'
6
+ /// HTML attributes for the strong mark.
7
+ export const strongAttr = $markAttr('strong')
7
8
 
8
- type Keys = SupportedKeys['Bold']
9
- const id = 'strong'
10
- export const ToggleBold = createCmdKey('ToggleBold')
11
- export const strong = createMark<Keys>((utils) => {
12
- return {
13
- id,
14
- schema: () => ({
15
- inclusive: false,
16
- parseDOM: [
17
- { tag: 'b' },
18
- { tag: 'strong' },
19
- { style: 'font-style', getAttrs: value => (value === 'bold') as false },
20
- ],
21
- toDOM: mark => ['strong', { class: utils.getClassName(mark.attrs, id) }],
22
- parseMarkdown: {
23
- match: node => node.type === 'strong',
24
- runner: (state, node, markType) => {
25
- state.openMark(markType)
26
- state.next(node.children)
27
- state.closeMark(markType)
28
- },
29
- },
30
- toMarkdown: {
31
- match: mark => mark.type.name === id,
32
- runner: (state, mark) => {
33
- state.withMark(mark, 'strong')
34
- },
35
- },
36
- }),
37
- commands: markType => [createCmd(ToggleBold, () => toggleMark(markType))],
38
- shortcuts: {
39
- [SupportedKeys.Bold]: createShortcut(ToggleBold, 'Mod-b'),
9
+ /// Strong mark schema.
10
+ export const strongSchema = $markSchema('strong', ctx => ({
11
+ inclusive: false,
12
+ parseDOM: [
13
+ { tag: 'b' },
14
+ { tag: 'strong' },
15
+ { style: 'font-style', getAttrs: value => (value === 'bold') as false },
16
+ ],
17
+ toDOM: mark => ['strong', ctx.get(strongAttr.key)(mark)],
18
+ parseMarkdown: {
19
+ match: node => node.type === 'strong',
20
+ runner: (state, node, markType) => {
21
+ state.openMark(markType)
22
+ state.next(node.children)
23
+ state.closeMark(markType)
40
24
  },
41
- }
25
+ },
26
+ toMarkdown: {
27
+ match: mark => mark.type.name === 'strong',
28
+ runner: (state, mark) => {
29
+ state.withMark(mark, 'strong')
30
+ },
31
+ },
32
+ }))
33
+
34
+ /// A command to toggle the strong mark.
35
+ export const toggleStrongCommand = $command('ToggleStrong', () => () => toggleMark(strongSchema.type()))
36
+
37
+ /// Keymap for the strong mark.
38
+ /// - `Mod-b` - Toggle the strong mark.
39
+ export const strongKeymap = $useKeymap('strongKeymap', {
40
+ ToggleBold: {
41
+ shortcuts: ['Mod-b'],
42
+ command: (ctx) => {
43
+ const commands = ctx.get(commandsCtx)
44
+ return () => commands.call(toggleStrongCommand.key)
45
+ },
46
+ },
42
47
  })
@@ -1,43 +1,49 @@
1
1
  /* Copyright 2021, Milkdown by Mirone. */
2
- import { createCmd, createCmdKey } from '@milkdown/core'
2
+ import { commandsCtx } from '@milkdown/core'
3
3
  import { wrapIn } from '@milkdown/prose/commands'
4
4
  import { wrappingInputRule } from '@milkdown/prose/inputrules'
5
- import { createNode, createShortcut } from '@milkdown/utils'
5
+ import type { $NodeSchema } from '@milkdown/utils'
6
+ import { $command, $inputRule, $nodeAttr, $nodeSchema, $useKeymap } from '@milkdown/utils'
6
7
 
7
- import { SupportedKeys } from '../supported-keys'
8
+ /// HTML attributes for blockquote node.
9
+ export const blockquoteAttr = $nodeAttr('blockquote')
8
10
 
9
- type Keys = SupportedKeys['Blockquote']
11
+ /// Schema for blockquote node.
12
+ export const blockquoteSchema: $NodeSchema<'blockquote'> = $nodeSchema('blockquote', ctx => ({
13
+ content: 'block+',
14
+ group: 'block',
15
+ defining: true,
16
+ parseDOM: [{ tag: 'blockquote' }],
17
+ toDOM: node => ['blockquote', ctx.get(blockquoteAttr.key)(node), 0],
18
+ parseMarkdown: {
19
+ match: ({ type }) => type === 'blockquote',
20
+ runner: (state, node, type) => {
21
+ state.openNode(type).next(node.children).closeNode()
22
+ },
23
+ },
24
+ toMarkdown: {
25
+ match: node => node.type.name === 'blockquote',
26
+ runner: (state, node) => {
27
+ state.openNode('blockquote').next(node.content).closeNode()
28
+ },
29
+ },
30
+ }))
10
31
 
11
- const id = 'blockquote'
32
+ /// This input rule will convert a line that starts with `> ` into a blockquote.
33
+ /// You can type `> ` at the start of a line to create a blockquote.
34
+ export const wrapInBlockquoteInputRule = $inputRule(() => wrappingInputRule(/^\s*>\s$/, blockquoteSchema.type()))
12
35
 
13
- export const WrapInBlockquote = createCmdKey('WrapInBlockquote')
36
+ /// This command will wrap the current selection in a blockquote.
37
+ export const wrapInBlockquoteCommand = $command('WrapInBlockquote', () => () => wrapIn(blockquoteSchema.type()))
14
38
 
15
- export const blockquote = createNode<Keys>((utils) => {
16
- return {
17
- id,
18
- schema: () => ({
19
- content: 'block+',
20
- group: 'block',
21
- defining: true,
22
- parseDOM: [{ tag: 'blockquote' }],
23
- toDOM: node => ['blockquote', { class: utils.getClassName(node.attrs, id) }, 0],
24
- parseMarkdown: {
25
- match: ({ type }) => type === id,
26
- runner: (state, node, type) => {
27
- state.openNode(type).next(node.children).closeNode()
28
- },
29
- },
30
- toMarkdown: {
31
- match: node => node.type.name === id,
32
- runner: (state, node) => {
33
- state.openNode('blockquote').next(node.content).closeNode()
34
- },
35
- },
36
- }),
37
- inputRules: nodeType => [wrappingInputRule(/^\s*>\s$/, nodeType)],
38
- commands: nodeType => [createCmd(WrapInBlockquote, () => wrapIn(nodeType))],
39
- shortcuts: {
40
- [SupportedKeys.Blockquote]: createShortcut(WrapInBlockquote, 'Mod-Shift-b'),
39
+ /// Keymap for blockquote.
40
+ /// - `Mod-Shift-b`: Wrap selection in blockquote.
41
+ export const blockquoteKeymap = $useKeymap('blockquoteKeymap', {
42
+ WrapInBlockquote: {
43
+ shortcuts: 'Mod-Shift-b',
44
+ command: (ctx) => {
45
+ const commands = ctx.get(commandsCtx)
46
+ return () => commands.call(wrapInBlockquoteCommand.key)
41
47
  },
42
- }
48
+ },
43
49
  })
@@ -1,72 +1,79 @@
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
4
  import { wrapIn } from '@milkdown/prose/commands'
5
5
  import { wrappingInputRule } from '@milkdown/prose/inputrules'
6
- import { createNode, createShortcut } from '@milkdown/utils'
6
+ import { $command, $inputRule, $nodeAttr, $nodeSchema, $useKeymap } from '@milkdown/utils'
7
7
 
8
- import { SupportedKeys } from '../supported-keys'
8
+ /// HTML attributes for bullet list node.
9
+ export const bulletListAttr = $nodeAttr('bulletList')
9
10
 
10
- type Keys = SupportedKeys['BulletList']
11
-
12
- export const WrapInBulletList = createCmdKey('WrapInBulletList')
13
-
14
- export const bulletList = createNode<Keys>((utils) => {
15
- const id = 'bullet_list'
11
+ /// Schema for bullet list node.
12
+ export const bulletListSchema = $nodeSchema('bullet_list', (ctx) => {
16
13
  return {
17
- id,
18
- schema: () => ({
19
- content: 'listItem+',
20
- group: 'block',
21
- attrs: {
22
- spread: {
23
- default: false,
24
- },
14
+ content: 'listItem+',
15
+ group: 'block',
16
+ attrs: {
17
+ spread: {
18
+ default: false,
25
19
  },
26
- parseDOM: [
27
- {
28
- tag: 'ul',
29
- getAttrs: (dom) => {
30
- if (!(dom instanceof HTMLElement))
31
- throw expectDomTypeError(dom)
20
+ },
21
+ parseDOM: [
22
+ {
23
+ tag: 'ul',
24
+ getAttrs: (dom) => {
25
+ if (!(dom instanceof HTMLElement))
26
+ throw expectDomTypeError(dom)
32
27
 
33
- return {
34
- spread: dom.dataset.spread,
35
- }
36
- },
28
+ return {
29
+ spread: dom.dataset.spread,
30
+ }
37
31
  },
38
- ],
39
- toDOM: (node) => {
40
- return [
41
- 'ul',
42
- {
43
- 'data-spread': node.attrs.spread,
44
- 'class': utils.getClassName(node.attrs, 'bullet-list'),
45
- },
46
- 0,
47
- ]
48
32
  },
49
- parseMarkdown: {
50
- match: ({ type, ordered }) => type === 'list' && !ordered,
51
- runner: (state, node, type) => {
52
- const spread = node.spread != null ? `${node.spread}` : 'false'
53
- state.openNode(type, { spread }).next(node.children).closeNode()
33
+ ],
34
+ toDOM: (node) => {
35
+ return [
36
+ 'ul',
37
+ {
38
+ ...ctx.get(bulletListAttr.key)(node),
39
+ 'data-spread': node.attrs.spread,
54
40
  },
41
+ 0,
42
+ ]
43
+ },
44
+ parseMarkdown: {
45
+ match: ({ type, ordered }) => type === 'list' && !ordered,
46
+ runner: (state, node, type) => {
47
+ const spread = node.spread != null ? `${node.spread}` : 'false'
48
+ state.openNode(type, { spread }).next(node.children).closeNode()
55
49
  },
56
- toMarkdown: {
57
- match: node => node.type.name === id,
58
- runner: (state, node) => {
59
- state
60
- .openNode('list', undefined, { ordered: false, spread: node.attrs.spread === 'true' })
61
- .next(node.content)
62
- .closeNode()
63
- },
50
+ },
51
+ toMarkdown: {
52
+ match: node => node.type.name === 'bullet_list',
53
+ runner: (state, node) => {
54
+ state
55
+ .openNode('list', undefined, { ordered: false, spread: node.attrs.spread === 'true' })
56
+ .next(node.content)
57
+ .closeNode()
64
58
  },
65
- }),
66
- inputRules: nodeType => [wrappingInputRule(/^\s*([-+*])\s$/, nodeType)],
67
- commands: nodeType => [createCmd(WrapInBulletList, () => wrapIn(nodeType))],
68
- shortcuts: {
69
- [SupportedKeys.BulletList]: createShortcut(WrapInBulletList, 'Mod-Alt-8'),
70
59
  },
71
60
  }
72
61
  })
62
+
63
+ /// Input rule for wrapping a block in bullet list node.
64
+ export const wrapInBulletListInputRule = $inputRule(() => wrappingInputRule(/^\s*([-+*])\s$/, bulletListSchema.type()))
65
+
66
+ /// Command for creating bullet list node.
67
+ export const wrapInBulletListCommand = $command('WrapInBulletList', () => () => wrapIn(bulletListSchema.type()))
68
+
69
+ /// Keymap for bullet list node.
70
+ /// - `Mod-Alt-8`: Wrap a block in bullet list.
71
+ export const bulletListKeymap = $useKeymap('bulletListKeymap', {
72
+ WrapInBulletList: {
73
+ shortcuts: 'Mod-Alt-8',
74
+ command: (ctx) => {
75
+ const commands = ctx.get(commandsCtx)
76
+ return () => commands.call(wrapInBulletListCommand.key)
77
+ },
78
+ },
79
+ })
@@ -0,0 +1,103 @@
1
+ /* Copyright 2021, Milkdown by Mirone. */
2
+ import { commandsCtx } from '@milkdown/core'
3
+ import { expectDomTypeError } from '@milkdown/exception'
4
+ import { setBlockType } from '@milkdown/prose/commands'
5
+ import { textblockTypeInputRule } from '@milkdown/prose/inputrules'
6
+ import { $command, $inputRule, $nodeAttr, $nodeSchema, $useKeymap } from '@milkdown/utils'
7
+
8
+ /// HTML attributes for code block node.
9
+ export const codeBlockAttr = $nodeAttr('codeBlock', () => ({
10
+ pre: {},
11
+ code: {},
12
+ }))
13
+
14
+ /// Schema for code block node.
15
+ export const codeBlockSchema = $nodeSchema('code_block', (ctx) => {
16
+ return {
17
+ content: 'text*',
18
+ group: 'block',
19
+ marks: '',
20
+ defining: true,
21
+ code: true,
22
+ attrs: {
23
+ language: {
24
+ default: '',
25
+ },
26
+ },
27
+ parseDOM: [
28
+ {
29
+ tag: 'pre',
30
+ preserveWhitespace: 'full',
31
+ getAttrs: (dom) => {
32
+ if (!(dom instanceof HTMLElement))
33
+ throw expectDomTypeError(dom)
34
+
35
+ return { language: dom.dataset.language }
36
+ },
37
+ },
38
+ ],
39
+ toDOM: (node) => {
40
+ const attr = ctx.get(codeBlockAttr.key)(node)
41
+ return [
42
+ 'pre',
43
+ {
44
+ ...attr.pre,
45
+ 'data-language': node.attrs.language,
46
+ },
47
+ ['code', attr.code, 0],
48
+ ]
49
+ },
50
+ parseMarkdown: {
51
+ match: ({ type }) => type === 'code',
52
+ runner: (state, node, type) => {
53
+ const language = node.lang as string
54
+ const value = node.value as string
55
+ state.openNode(type, { language })
56
+ if (value)
57
+ state.addText(value)
58
+
59
+ state.closeNode()
60
+ },
61
+ },
62
+ toMarkdown: {
63
+ match: node => node.type.name === 'code_block',
64
+ runner: (state, node) => {
65
+ state.addNode('code', undefined, node.content.firstChild?.text || '', {
66
+ lang: node.attrs.language,
67
+ })
68
+ },
69
+ },
70
+ }
71
+ })
72
+
73
+ /// A input rule for creating code block.
74
+ /// For example, ` ```javascript ` will create a code block with language javascript.
75
+ export const createCodeBlockInputRule = $inputRule(() => textblockTypeInputRule(/^```(?<language>[a-z]*)?[\s\n]$/, codeBlockSchema.type(), match => ({
76
+ language: match.groups?.language ?? '',
77
+ })))
78
+
79
+ /// A command for creating code block.
80
+ /// You can pass the language of the code block as the parameter.
81
+ export const createCodeBlockCommand = $command('CreateCodeBlock', () => (language = '') => setBlockType(codeBlockSchema.type(), { language }))
82
+
83
+ /// A command for updating the code block language of the target position.
84
+ export const updateCodeBlockLanguageCommand = $command('UpdateCodeBlockLanguage', () => ({ pos, language }: { pos: number; language: string } = { pos: -1, language: '' }) => (state, dispatch) => {
85
+ if (pos >= 0) {
86
+ dispatch?.(state.tr.setNodeAttribute(pos, 'language', language))
87
+ return true
88
+ }
89
+
90
+ return false
91
+ })
92
+
93
+ /// Keymap for code block.
94
+ /// - `Mod-Alt-c`: Create a code block.
95
+ export const codeBlockKeymap = $useKeymap('codeBlockKeymap', {
96
+ CreateCodeBlock: {
97
+ shortcuts: 'Mod-Alt-c',
98
+ command: (ctx) => {
99
+ const commands = ctx.get(commandsCtx)
100
+ return () => commands.call(createCodeBlockCommand.key)
101
+ },
102
+ },
103
+ })
package/src/node/doc.ts CHANGED
@@ -1,24 +1,20 @@
1
1
  /* Copyright 2021, Milkdown by Mirone. */
2
- import { createNode } from '@milkdown/utils'
2
+ import { $node } from '@milkdown/utils'
3
3
 
4
- export const doc = createNode(() => {
5
- return {
6
- id: 'doc',
7
- schema: () => ({
8
- content: 'block+',
9
- parseMarkdown: {
10
- match: ({ type }) => type === 'root',
11
- runner: (state, node, type) => {
12
- state.injectRoot(node, type)
13
- },
14
- },
15
- toMarkdown: {
16
- match: node => node.type.name === 'doc',
17
- runner: (state, node) => {
18
- state.openNode('root')
19
- state.next(node.content)
20
- },
21
- },
22
- }),
23
- }
24
- })
4
+ /// The top-level document node.
5
+ export const docSchema = $node('doc', () => ({
6
+ content: 'block+',
7
+ parseMarkdown: {
8
+ match: ({ type }) => type === 'root',
9
+ runner: (state, node, type) => {
10
+ state.injectRoot(node, type)
11
+ },
12
+ },
13
+ toMarkdown: {
14
+ match: node => node.type.name === 'doc',
15
+ runner: (state, node) => {
16
+ state.openNode('root')
17
+ state.next(node.content)
18
+ },
19
+ },
20
+ }))
@@ -1,125 +1,76 @@
1
1
  /* Copyright 2021, Milkdown by Mirone. */
2
- import { createCmd, createCmdKey } from '@milkdown/core'
3
- import { Plugin, PluginKey, Selection } from '@milkdown/prose/state'
4
- import { AddMarkStep, ReplaceStep } from '@milkdown/prose/transform'
5
- import { createNode, createShortcut } from '@milkdown/utils'
2
+ import { commandsCtx } from '@milkdown/core'
3
+ import { Selection } from '@milkdown/prose/state'
4
+ import { $command, $nodeAttr, $nodeSchema, $useKeymap } from '@milkdown/utils'
6
5
 
7
- import { SupportedKeys } from '../supported-keys'
8
-
9
- type Keys = SupportedKeys['HardBreak']
10
-
11
- export const InsertHardbreak = createCmdKey('InsertHardbreak')
12
-
13
- export const HardbreakFilterPluginKey = new PluginKey('MILKDOWN_HARDBREAK_FILTER')
14
-
15
- export const hardbreak = createNode<
16
- Keys,
17
- {
18
- notIn: string[]
19
- }
20
- >((utils, options) => {
21
- const notIn = options?.notIn ?? ['table', 'fence']
6
+ /// HTML attributes for the hardbreak node.
7
+ ///
8
+ /// Default value:
9
+ /// - `data-is-inline` - Whether the hardbreak is inline.
10
+ export const hardbreakAttr = $nodeAttr('hardbreak', (node) => {
22
11
  return {
23
- id: 'hardbreak',
24
- schema: () => ({
25
- inline: true,
26
- group: 'inline',
27
- selectable: false,
28
- parseDOM: [{ tag: 'br' }],
29
- toDOM: node => ['br', { class: utils.getClassName(node.attrs, 'hardbreak') }],
30
- parseMarkdown: {
31
- match: ({ type }) => type === 'break',
32
- runner: (state, _, type) => {
33
- state.addNode(type)
34
- },
35
- },
36
- toMarkdown: {
37
- match: node => node.type.name === 'hardbreak',
38
- runner: (state) => {
39
- state.addNode('break')
40
- },
41
- },
42
- }),
43
- commands: type => [
44
- createCmd(InsertHardbreak, () => (state, dispatch) => {
45
- const { selection, tr } = state
46
- if (selection.empty) {
47
- // Transform two successive hardbreak into a new line
48
- const node = selection.$from.node()
49
- if (node.childCount > 0 && node.lastChild?.type.name === 'hardbreak') {
50
- dispatch?.(
51
- tr
52
- .replaceRangeWith(selection.to - 1, selection.to, state.schema.node('paragraph'))
53
- .setSelection(Selection.near(tr.doc.resolve(selection.to)))
54
- .scrollIntoView(),
55
- )
56
- return true
57
- }
58
- }
59
- dispatch?.(tr.setMeta('hardbreak', true).replaceSelectionWith(type.create()).scrollIntoView())
60
- return true
61
- }),
62
- ],
63
- shortcuts: {
64
- [SupportedKeys.HardBreak]: createShortcut(InsertHardbreak, 'Shift-Enter'),
65
- },
66
- prosePlugins: type => [
67
- new Plugin({
68
- key: HardbreakFilterPluginKey,
69
- filterTransaction: (tr, state) => {
70
- const isInsertHr = tr.getMeta('hardbreak')
71
- const [step] = tr.steps
72
- if (isInsertHr && step) {
73
- const { from } = step as unknown as { from: number }
74
- const $from = state.doc.resolve(from)
75
- let curDepth = $from.depth
76
- let canApply = true
77
- while (curDepth > 0) {
78
- if (notIn.includes($from.node(curDepth).type.name))
79
- canApply = false
80
-
81
- curDepth--
82
- }
83
- return canApply
84
- }
85
- return true
86
- },
87
- }),
88
- new Plugin({
89
- key: new PluginKey('MILKDOWN_HARDBREAK_MARKS'),
90
- appendTransaction: (trs, _oldState, newState) => {
91
- if (!trs.length)
92
- return
93
- const [tr] = trs
94
- if (!tr)
95
- return
96
-
97
- const [step] = tr.steps
98
-
99
- const isInsertHr = tr.getMeta('hardbreak')
100
- if (isInsertHr) {
101
- if (!(step instanceof ReplaceStep))
102
- return
103
-
104
- const { from } = step as unknown as { from: number }
105
- return newState.tr.setNodeMarkup(from, type, undefined, [])
106
- }
12
+ 'data-is-inline': node.attrs.isInline,
13
+ }
14
+ })
107
15
 
108
- const isAddMarkStep = step instanceof AddMarkStep
109
- if (isAddMarkStep) {
110
- let _tr = newState.tr
111
- const { from, to } = step as unknown as { from: number; to: number }
112
- newState.doc.nodesBetween(from, to, (node, pos) => {
113
- if (node.type === type)
114
- _tr = _tr.setNodeMarkup(pos, type, undefined, [])
115
- })
16
+ /// Hardbreak node schema.
17
+ export const hardbreakSchema = $nodeSchema('hardbreak', ctx => ({
18
+ inline: true,
19
+ group: 'inline',
20
+ attrs: {
21
+ isInline: {
22
+ default: false,
23
+ },
24
+ },
25
+ selectable: false,
26
+ parseDOM: [{ tag: 'br' }],
27
+ toDOM: node => ['br', ctx.get(hardbreakAttr.key)(node)],
28
+ parseMarkdown: {
29
+ match: ({ type }) => type === 'break',
30
+ runner: (state, node, type) => {
31
+ state.addNode(type, { isInline: Boolean(node.data?.isInline) })
32
+ },
33
+ },
34
+ toMarkdown: {
35
+ match: node => node.type.name === 'hardbreak',
36
+ runner: (state, node) => {
37
+ if (node.attrs.isInline)
38
+ state.addNode('text', undefined, '\n')
116
39
 
117
- return _tr
118
- }
40
+ else
41
+ state.addNode('break')
42
+ },
43
+ },
44
+ }))
119
45
 
120
- return undefined
121
- },
122
- }),
123
- ],
46
+ /// Command to insert a hardbreak.
47
+ export const insertHardbreakCommand = $command('InsertHardbreak', () => () => (state, dispatch) => {
48
+ const { selection, tr } = state
49
+ if (selection.empty) {
50
+ // Transform two successive hardbreak into a new line
51
+ const node = selection.$from.node()
52
+ if (node.childCount > 0 && node.lastChild?.type.name === 'hardbreak') {
53
+ dispatch?.(
54
+ tr
55
+ .replaceRangeWith(selection.to - 1, selection.to, state.schema.node('paragraph'))
56
+ .setSelection(Selection.near(tr.doc.resolve(selection.to)))
57
+ .scrollIntoView(),
58
+ )
59
+ return true
60
+ }
124
61
  }
62
+ dispatch?.(tr.setMeta('hardbreak', true).replaceSelectionWith(hardbreakSchema.type().create()).scrollIntoView())
63
+ return true
64
+ })
65
+
66
+ /// Keymap for the hardbreak node.
67
+ /// - `Shift-Enter` - Insert a hardbreak.
68
+ export const hardbreakKeymap = $useKeymap('hardbreakKeymap', {
69
+ InsertHardbreak: {
70
+ shortcuts: 'Shift-Enter',
71
+ command: (ctx) => {
72
+ const commands = ctx.get(commandsCtx)
73
+ return () => commands.call(insertHardbreakCommand.key)
74
+ },
75
+ },
125
76
  })