@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
@@ -0,0 +1,19 @@
1
+ /* Copyright 2021, Milkdown by Mirone. */
2
+ import type { MilkdownPlugin } from '@milkdown/ctx'
3
+ import { emphasisKeymap, inlineCodeKeymap, strongKeymap } from '../mark'
4
+ import { blockquoteKeymap, bulletListKeymap, codeBlockKeymap, hardbreakKeymap, headingKeymap, listItemKeymap, orderedListKeymap, paragraphKeymap } from '../node'
5
+
6
+ export const keymap: MilkdownPlugin[] = [
7
+ blockquoteKeymap,
8
+ codeBlockKeymap,
9
+ hardbreakKeymap,
10
+ headingKeymap,
11
+ listItemKeymap,
12
+ orderedListKeymap,
13
+ bulletListKeymap,
14
+ paragraphKeymap,
15
+
16
+ emphasisKeymap,
17
+ inlineCodeKeymap,
18
+ strongKeymap,
19
+ ].flat()
@@ -0,0 +1,21 @@
1
+ /* Copyright 2021, Milkdown by Mirone. */
2
+
3
+ import { hardbreakClearMarkPlugin, hardbreakFilterNodes, hardbreakFilterPlugin, inlineNodesCursorPlugin, inlineSyncConfig, inlineSyncPlugin, remarkAddOrderInListPlugin, remarkInlineLinkPlugin, remarkLineBreak, syncHeadingIdPlugin, syncListOrderPlugin } from '../plugin'
4
+
5
+ export const plugins = [
6
+ inlineSyncConfig,
7
+ inlineSyncPlugin,
8
+
9
+ hardbreakClearMarkPlugin,
10
+ hardbreakFilterNodes,
11
+ hardbreakFilterPlugin,
12
+
13
+ inlineNodesCursorPlugin,
14
+
15
+ remarkAddOrderInListPlugin,
16
+ remarkInlineLinkPlugin,
17
+ remarkLineBreak,
18
+
19
+ syncHeadingIdPlugin,
20
+ syncListOrderPlugin,
21
+ ]
@@ -0,0 +1,54 @@
1
+ /* Copyright 2021, Milkdown by Mirone. */
2
+
3
+ import type { MilkdownPlugin } from '@milkdown/ctx'
4
+ import { emphasisAttr, emphasisSchema, inlineCodeAttr, inlineCodeSchema, linkAttr, linkSchema, strongAttr, strongSchema } from '../mark'
5
+ import { blockquoteAttr, blockquoteSchema, bulletListAttr, bulletListSchema, codeBlockAttr, codeBlockSchema, docSchema, hardbreakAttr, hardbreakSchema, headingAttr, headingIdGenerator, headingSchema, hrAttr, hrSchema, imageAttr, imageSchema, listItemAttr, listItemSchema, orderedListAttr, orderedListSchema, paragraphAttr, paragraphSchema, textSchema } from '../node'
6
+
7
+ export const schema: MilkdownPlugin[] = [
8
+ docSchema,
9
+
10
+ paragraphAttr,
11
+ paragraphSchema,
12
+
13
+ headingIdGenerator,
14
+ headingAttr,
15
+ headingSchema,
16
+
17
+ hardbreakAttr,
18
+ hardbreakSchema,
19
+
20
+ blockquoteAttr,
21
+ blockquoteSchema,
22
+
23
+ codeBlockAttr,
24
+ codeBlockSchema,
25
+
26
+ hrAttr,
27
+ hrSchema,
28
+
29
+ imageAttr,
30
+ imageSchema,
31
+
32
+ bulletListAttr,
33
+ bulletListSchema,
34
+
35
+ orderedListAttr,
36
+ orderedListSchema,
37
+
38
+ listItemAttr,
39
+ listItemSchema,
40
+
41
+ emphasisAttr,
42
+ emphasisSchema,
43
+
44
+ strongAttr,
45
+ strongSchema,
46
+
47
+ inlineCodeAttr,
48
+ inlineCodeSchema,
49
+
50
+ linkAttr,
51
+ linkSchema,
52
+
53
+ textSchema,
54
+ ].flat()
package/src/index.ts CHANGED
@@ -1,57 +1,10 @@
1
1
  /* Copyright 2021, Milkdown by Mirone. */
2
- import { AtomList } from '@milkdown/utils'
3
2
 
4
- import { ModifyLink, ToggleBold, ToggleInlineCode, ToggleItalic, ToggleLink, marks } from './mark'
5
- import {
6
- InsertHardbreak,
7
- InsertHr,
8
- InsertImage,
9
- LiftListItem,
10
- ModifyImage,
11
- SinkListItem,
12
- SplitListItem,
13
- TurnIntoCodeFence,
14
- TurnIntoHeading,
15
- TurnIntoText,
16
- WrapInBlockquote,
17
- WrapInBulletList,
18
- WrapInOrderedList,
19
- nodes,
20
- } from './node'
21
- import { commonmarkPlugins } from './plugin'
3
+ import { commands, inputrules, keymap, plugins, schema } from './composed'
22
4
 
23
- export * from './mark'
24
5
  export * from './node'
25
- export { inlineSyncConfigCtx } from './plugin'
26
- export * from './supported-keys'
27
-
28
- export const commonmarkNodes = AtomList.create([...nodes, ...marks])
29
- export { commonmarkPlugins }
30
- export const commonmark = AtomList.create([...commonmarkPlugins, ...commonmarkNodes])
31
-
32
- export const commands = {
33
- ToggleInlineCode,
34
- ToggleItalic,
35
- ToggleLink,
36
- ToggleBold,
37
-
38
- ModifyLink,
39
- ModifyImage,
40
-
41
- WrapInBlockquote,
42
- WrapInBulletList,
43
- WrapInOrderedList,
44
-
45
- TurnIntoCodeFence,
46
- TurnIntoHeading,
47
- TurnIntoText,
48
-
49
- InsertHardbreak,
50
- InsertHr,
51
- InsertImage,
6
+ export * from './mark'
7
+ export * from './plugin'
8
+ export * from './composed'
52
9
 
53
- SplitListItem,
54
- SinkListItem,
55
- LiftListItem,
56
- } as const
57
- export type Commands = typeof commands
10
+ export const commonmark = [schema, inputrules, commands, keymap, plugins].flat()
@@ -0,0 +1,42 @@
1
+ /* Copyright 2021, Milkdown by Mirone. */
2
+ import { commandsCtx } from '@milkdown/core'
3
+ import { toggleMark } from '@milkdown/prose/commands'
4
+ import { $command, $markAttr, $markSchema, $useKeymap } from '@milkdown/utils'
5
+
6
+ export const emphasisAttr = $markAttr('emphasis')
7
+
8
+ export const emphasisSchema = $markSchema('emphasis', ctx => ({
9
+ inclusive: false,
10
+ parseDOM: [
11
+ { tag: 'i' },
12
+ { tag: 'em' },
13
+ { style: 'font-style', getAttrs: value => (value === 'italic') as false },
14
+ ],
15
+ toDOM: mark => ['em', ctx.get(emphasisAttr.key)(mark)],
16
+ parseMarkdown: {
17
+ match: node => node.type === 'emphasis',
18
+ runner: (state, node, markType) => {
19
+ state.openMark(markType)
20
+ state.next(node.children)
21
+ state.closeMark(markType)
22
+ },
23
+ },
24
+ toMarkdown: {
25
+ match: mark => mark.type.name === 'emphasis',
26
+ runner: (state, mark) => {
27
+ state.withMark(mark, 'emphasis')
28
+ },
29
+ },
30
+ }))
31
+
32
+ export const toggleEmphasisCommand = $command('ToggleEmphasis', () => () => toggleMark(emphasisSchema.type()))
33
+
34
+ export const emphasisKeymap = $useKeymap('emphasisKeymap', {
35
+ ToggleEmphasis: {
36
+ shortcuts: 'Mod-i',
37
+ command: (ctx) => {
38
+ const commands = ctx.get(commandsCtx)
39
+ return () => commands.call(toggleEmphasisCommand.key)
40
+ },
41
+ },
42
+ })
package/src/mark/index.ts CHANGED
@@ -1,12 +1,5 @@
1
1
  /* Copyright 2021, Milkdown by Mirone. */
2
- import { codeInline } from './code-inline'
3
- import { em } from './em'
4
- import { link } from './link'
5
- import { strong } from './strong'
6
-
7
- export const marks = [codeInline(), em(), strong(), link()]
8
-
9
- export * from './code-inline'
10
- export * from './em'
11
- export * from './link'
2
+ export * from './emphasis'
12
3
  export * from './strong'
4
+ export * from './inline-code'
5
+ export * from './link'
@@ -0,0 +1,64 @@
1
+ /* Copyright 2021, Milkdown by Mirone. */
2
+ import { commandsCtx } from '@milkdown/core'
3
+ import type { MarkType } from '@milkdown/prose/model'
4
+ import { $command, $markAttr, $markSchema, $useKeymap } from '@milkdown/utils'
5
+
6
+ export const inlineCodeAttr = $markAttr('inlineCode')
7
+ export const inlineCodeSchema = $markSchema('inlineCode', ctx => ({
8
+ priority: 100,
9
+ code: true,
10
+ inclusive: false,
11
+ parseDOM: [{ tag: 'code' }],
12
+ toDOM: mark => ['code', ctx.get(inlineCodeAttr.key)(mark)],
13
+ parseMarkdown: {
14
+ match: node => node.type === 'inlineCode',
15
+ runner: (state, node, markType) => {
16
+ state.openMark(markType)
17
+ state.addText(node.value as string)
18
+ state.closeMark(markType)
19
+ },
20
+ },
21
+ toMarkdown: {
22
+ match: mark => mark.type.name === 'inlineCode',
23
+ runner: (state, mark, node) => {
24
+ state.withMark(mark, 'inlineCode', node.text || '')
25
+ },
26
+ },
27
+ }))
28
+
29
+ export const toggleInlineCodeCommand = $command('ToggleInlineCode', () => () => (state, dispatch) => {
30
+ const { selection, tr } = state
31
+ if (selection.empty)
32
+ return false
33
+ const { from, to } = selection
34
+
35
+ const has = state.doc.rangeHasMark(from, to, inlineCodeSchema.type())
36
+ // remove exists inlineCode mark if have
37
+ if (has) {
38
+ dispatch?.(tr.removeMark(from, to, inlineCodeSchema.type()))
39
+ return true
40
+ }
41
+
42
+ const restMarksName = Object.keys(state.schema.marks).filter(x => x !== inlineCodeSchema.type.name)
43
+
44
+ // remove other marks
45
+ restMarksName
46
+ .map(name => state.schema.marks[name] as MarkType)
47
+ .forEach((t) => {
48
+ tr.removeMark(from, to, t)
49
+ })
50
+
51
+ // add inlineCode mark
52
+ dispatch?.(tr.addMark(from, to, inlineCodeSchema.type().create()))
53
+ return true
54
+ })
55
+
56
+ export const inlineCodeKeymap = $useKeymap('inlineCodeKeymap', {
57
+ ToggleInlineCode: {
58
+ shortcuts: 'Mod-e',
59
+ command: (ctx) => {
60
+ const commands = ctx.get(commandsCtx)
61
+ return () => commands.call(toggleInlineCodeCommand.key)
62
+ },
63
+ },
64
+ })
package/src/mark/link.ts CHANGED
@@ -1,253 +1,93 @@
1
1
  /* Copyright 2021, Milkdown by Mirone. */
2
- import type { ThemeInputChipType } from '@milkdown/core'
3
- import { commandsCtx, createCmd, createCmdKey } from '@milkdown/core'
4
- import { expectDomTypeError, missingRootElement } from '@milkdown/exception'
5
- import { calculateTextPosition } from '@milkdown/prose'
2
+ import { expectDomTypeError } from '@milkdown/exception'
6
3
  import { toggleMark } from '@milkdown/prose/commands'
7
4
  import type { Node as ProseNode } from '@milkdown/prose/model'
8
- import { NodeSelection, Plugin, PluginKey, TextSelection } from '@milkdown/prose/state'
9
- import type { EditorView } from '@milkdown/prose/view'
10
- import { createMark } from '@milkdown/utils'
11
-
12
- const key = new PluginKey('MILKDOWN_LINK_INPUT')
13
-
14
- export const ToggleLink = createCmdKey<string>('ToggleLink')
15
- export const ModifyLink = createCmdKey<string>('ModifyLink')
16
- const id = 'link'
17
- export interface LinkOptions {
18
- input: {
19
- placeholder?: string
20
- buttonText?: string
21
- displayWhenSelected?: boolean
22
- }
23
- }
24
- export const link = createMark<string, LinkOptions>((utils, options) => {
25
- return {
26
- id,
27
- schema: () => ({
28
- attrs: {
29
- href: {},
30
- title: { default: null },
31
- },
32
- parseDOM: [
33
- {
34
- tag: 'a[href]',
35
- getAttrs: (dom) => {
36
- if (!(dom instanceof HTMLElement))
37
- throw expectDomTypeError(dom)
38
-
39
- return { href: dom.getAttribute('href'), title: dom.getAttribute('title') }
40
- },
41
- },
42
- ],
43
- toDOM: mark => ['a', { ...mark.attrs, class: utils.getClassName(mark.attrs, id) }],
44
- parseMarkdown: {
45
- match: node => node.type === 'link',
46
- runner: (state, node, markType) => {
47
- const url = node.url as string
48
- const title = node.title as string
49
- state.openMark(markType, { href: url, title })
50
- state.next(node.children)
51
- state.closeMark(markType)
52
- },
53
- },
54
- toMarkdown: {
55
- match: mark => mark.type.name === id,
56
- runner: (state, mark) => {
57
- state.withMark(mark, 'link', undefined, {
58
- title: mark.attrs.title,
59
- url: mark.attrs.href,
60
- })
61
- },
5
+ import { TextSelection } from '@milkdown/prose/state'
6
+ import { $command, $markAttr, $markSchema } from '@milkdown/utils'
7
+
8
+ export const linkAttr = $markAttr('link')
9
+ export const linkSchema = $markSchema('link', ctx => ({
10
+ attrs: {
11
+ href: {},
12
+ title: { default: null },
13
+ },
14
+ parseDOM: [
15
+ {
16
+ tag: 'a[href]',
17
+ getAttrs: (dom) => {
18
+ if (!(dom instanceof HTMLElement))
19
+ throw expectDomTypeError(dom)
20
+
21
+ return { href: dom.getAttribute('href'), title: dom.getAttribute('title') }
62
22
  },
63
- }),
64
- commands: markType => [
65
- createCmd(ToggleLink, (href = '') => toggleMark(markType, { href })),
66
- createCmd(ModifyLink, (href = '') => (state, dispatch) => {
67
- if (!dispatch)
68
- return false
69
-
70
- const { marks } = state.schema
71
-
72
- let node: ProseNode | undefined
73
- let pos = -1
74
- const { selection } = state
75
- const { from, to } = selection
76
- state.doc.nodesBetween(from, from === to ? to + 1 : to, (n, p) => {
77
- if (marks.link?.isInSet(n.marks)) {
78
- node = n
79
- pos = p
80
- return false
81
- }
82
-
83
- return undefined
84
- })
85
- if (!node)
86
- return false
87
-
88
- const mark = node.marks.find(({ type }) => type === markType)
89
- if (!mark)
90
- return false
91
-
92
- const start = pos
93
- const end = pos + node.nodeSize
94
- const { tr } = state
95
- const linkMark = marks.link?.create({ ...mark.attrs, href })
96
- if (!linkMark)
97
- return false
98
- dispatch(
99
- tr
100
- .removeMark(start, end, mark)
101
- .addMark(start, end, linkMark)
102
- .setSelection(new TextSelection(tr.selection.$anchor))
103
- .scrollIntoView(),
104
- )
105
-
106
- return true
107
- }),
108
- ],
109
- prosePlugins: (type, ctx) => {
110
- let renderOnTop = false
111
- return [
112
- new Plugin({
113
- key,
114
- view: (editorView) => {
115
- const inputChipRenderer = utils.themeManager.get<ThemeInputChipType>('input-chip', {
116
- placeholder: options?.input?.placeholder ?? 'Input Web Link',
117
- buttonText: options?.input?.buttonText,
118
- onUpdate: (value) => {
119
- ctx.get(commandsCtx).call(ModifyLink, value)
120
- },
121
- calculatePosition: (view, input) => {
122
- calculateTextPosition(view, input, (start, end, target, parent) => {
123
- const $editor = view.dom.parentElement
124
- if (!$editor)
125
- throw missingRootElement()
126
-
127
- const selectionWidth = end.left - start.left
128
- let left = start.left - parent.left - (target.width - selectionWidth) / 2
129
- let top = start.bottom - parent.top + 14 + $editor.scrollTop
130
-
131
- if (renderOnTop)
132
- top = start.top - parent.top - target.height - 14 + $editor.scrollTop
133
-
134
- if (left < 0)
135
- left = 0
136
-
137
- const maxLeft = $editor.clientWidth - (target.width + 4)
138
- if (left > maxLeft)
139
- left = maxLeft
140
-
141
- return [top, left]
142
- })
143
- },
144
- })
145
- if (!inputChipRenderer)
146
- return {}
147
- const shouldDisplay = (view: EditorView) => {
148
- const { selection, doc } = view.state
149
- const { from, to } = selection
150
-
151
- if (!view.hasFocus())
152
- return false
153
-
154
- if (
155
- selection instanceof TextSelection
156
- && to < doc.content.size
157
- && from < doc.content.size
158
- && doc.rangeHasMark(from, from === to ? to + 1 : to, type)
159
- ) {
160
- let shouldDisplay = selection.empty
161
- if (options?.input?.displayWhenSelected && !shouldDisplay) {
162
- doc.nodesBetween(from, from === to ? to + 1 : to, (node, pos) => {
163
- if (
164
- node.marks.some(
165
- mark =>
166
- mark.type === type && from >= pos && to <= pos + node.nodeSize,
167
- )
168
- ) {
169
- shouldDisplay = true
170
- return false
171
- }
172
-
173
- return undefined
174
- })
175
- }
176
- if (shouldDisplay) {
177
- renderOnTop = false
178
- return true
179
- }
180
- }
181
-
182
- if (selection instanceof NodeSelection) {
183
- const { node } = selection
184
- if (
185
- node.type.name === 'image'
186
- && node.marks.findIndex(mark => mark.type.name === id) > -1
187
- ) {
188
- renderOnTop = true
189
- return true
190
- }
191
- }
192
-
193
- return false
194
- }
195
- const getCurrentLink = (view: EditorView) => {
196
- const { selection } = view.state
197
- let node: ProseNode | undefined
198
- const { from, to } = selection
199
- view.state.doc.nodesBetween(from, from === to ? to + 1 : to, (n) => {
200
- if (type.isInSet(n.marks)) {
201
- node = n
202
- return false
203
- }
204
-
205
- return undefined
206
- })
207
- if (!node)
208
- return
209
-
210
- const mark = node.marks.find(m => m.type === type)
211
- if (!mark)
212
- return
213
-
214
- const value = mark.attrs.href
215
- return value
216
- }
217
- const renderByView = (view: EditorView) => {
218
- if (!view.editable)
219
- return
220
-
221
- const display = shouldDisplay(view)
222
- if (display) {
223
- inputChipRenderer.show(view)
224
- inputChipRenderer.update(getCurrentLink(view))
225
- }
226
- else {
227
- inputChipRenderer.hide()
228
- }
229
- }
230
- inputChipRenderer.init(editorView)
231
- renderByView(editorView)
232
-
233
- return {
234
- update: (view, prevState) => {
235
- const isEqualSelection
236
- = prevState?.doc.eq(view.state.doc) && prevState.selection.eq(view.state.selection)
237
- if (isEqualSelection)
238
- return
239
-
240
- requestAnimationFrame(() => {
241
- renderByView(view)
242
- })
243
- },
244
- destroy: () => {
245
- inputChipRenderer.destroy()
246
- },
247
- }
248
- },
249
- }),
250
- ]
251
23
  },
252
- }
24
+ ],
25
+ toDOM: mark => ['a', { ...ctx.get(linkAttr.key)(mark), ...mark.attrs }],
26
+ parseMarkdown: {
27
+ match: node => node.type === 'link',
28
+ runner: (state, node, markType) => {
29
+ const url = node.url as string
30
+ const title = node.title as string
31
+ state.openMark(markType, { href: url, title })
32
+ state.next(node.children)
33
+ state.closeMark(markType)
34
+ },
35
+ },
36
+ toMarkdown: {
37
+ match: mark => mark.type.name === 'link',
38
+ runner: (state, mark) => {
39
+ state.withMark(mark, 'link', undefined, {
40
+ title: mark.attrs.title,
41
+ url: mark.attrs.href,
42
+ })
43
+ },
44
+ },
45
+ }))
46
+
47
+ export type UpdateLinkCommandPayload = {
48
+ href?: string
49
+ title?: string
50
+ }
51
+ export const toggleLinkCommand = $command('ToggleLink', () => (payload: UpdateLinkCommandPayload = {}) => toggleMark(linkSchema.type(), payload))
52
+ export const updateLinkCommand = $command('UpdateLink', () => (payload: UpdateLinkCommandPayload = {}) => (state, dispatch) => {
53
+ if (!dispatch)
54
+ return false
55
+
56
+ let node: ProseNode | undefined
57
+ let pos = -1
58
+ const { selection } = state
59
+ const { from, to } = selection
60
+ state.doc.nodesBetween(from, from === to ? to + 1 : to, (n, p) => {
61
+ if (linkSchema.type().isInSet(n.marks)) {
62
+ node = n
63
+ pos = p
64
+ return false
65
+ }
66
+
67
+ return undefined
68
+ })
69
+
70
+ if (!node)
71
+ return false
72
+
73
+ const mark = node.marks.find(({ type }) => type === linkSchema.type())
74
+ if (!mark)
75
+ return false
76
+
77
+ const start = pos
78
+ const end = pos + node.nodeSize
79
+ const { tr } = state
80
+ const linkMark = linkSchema.type().create({ ...mark.attrs, ...payload })
81
+ if (!linkMark)
82
+ return false
83
+
84
+ dispatch(
85
+ tr
86
+ .removeMark(start, end, mark)
87
+ .addMark(start, end, linkMark)
88
+ .setSelection(new TextSelection(tr.selection.$anchor))
89
+ .scrollIntoView(),
90
+ )
91
+
92
+ return true
253
93
  })