@milkdown/preset-gfm 7.22.0 → 7.22.2

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 (36) hide show
  1. package/lib/__test__/inline-br-containers.spec.d.ts +2 -0
  2. package/lib/__test__/inline-br-containers.spec.d.ts.map +1 -0
  3. package/lib/__test__/inline-code-input-rule.spec.d.ts +2 -0
  4. package/lib/__test__/inline-code-input-rule.spec.d.ts.map +1 -0
  5. package/lib/__test__/task-list-spread-roundtrip.spec.d.ts +1 -1
  6. package/lib/__test__/task-list-spread-roundtrip.spec.d.ts.map +1 -1
  7. package/lib/__test__/test-utils.d.ts +7 -0
  8. package/lib/__test__/test-utils.d.ts.map +1 -0
  9. package/lib/index.js +14 -2
  10. package/lib/index.js.map +1 -1
  11. package/lib/node/footnote/definition.d.ts.map +1 -1
  12. package/lib/node/footnote/reference.d.ts.map +1 -1
  13. package/lib/node/table/input.d.ts.map +1 -1
  14. package/lib/node/table/schema.d.ts.map +1 -1
  15. package/lib/node/task-list-item.d.ts.map +1 -1
  16. package/lib/plugin/auto-insert-span-plugin.d.ts.map +1 -1
  17. package/lib/plugin/column-resizing-plugin.d.ts.map +1 -1
  18. package/lib/plugin/remark-gfm-plugin.d.ts.map +1 -1
  19. package/lib/plugin/table-editing-plugin.d.ts.map +1 -1
  20. package/lib/tsconfig.tsbuildinfo +1 -1
  21. package/package.json +9 -9
  22. package/src/__test__/inline-br-containers.spec.ts +106 -0
  23. package/src/__test__/inline-code-input-rule.spec.ts +69 -0
  24. package/src/__test__/table-header-row.spec.ts +1 -2
  25. package/src/__test__/task-list-spread-roundtrip.spec.ts +9 -32
  26. package/src/__test__/test-utils.ts +63 -0
  27. package/src/node/footnote/definition.ts +2 -1
  28. package/src/node/footnote/reference.ts +2 -1
  29. package/src/node/table/input.ts +9 -8
  30. package/src/node/table/schema.ts +35 -8
  31. package/src/node/task-list-item.ts +4 -3
  32. package/src/plugin/auto-insert-span-plugin.ts +3 -2
  33. package/src/plugin/column-resizing-plugin.ts +2 -1
  34. package/src/plugin/keep-table-align-plugin.ts +1 -1
  35. package/src/plugin/remark-gfm-plugin.ts +2 -1
  36. package/src/plugin/table-editing-plugin.ts +2 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@milkdown/preset-gfm",
3
- "version": "7.22.0",
3
+ "version": "7.22.2",
4
4
  "keywords": [
5
5
  "gfm",
6
6
  "markdown",
@@ -27,15 +27,15 @@
27
27
  }
28
28
  },
29
29
  "dependencies": {
30
+ "@milkdown/core": "7.22.2",
31
+ "@milkdown/ctx": "7.22.2",
32
+ "@milkdown/exception": "7.22.2",
33
+ "@milkdown/preset-commonmark": "7.22.2",
34
+ "@milkdown/prose": "7.22.2",
35
+ "@milkdown/transformer": "7.22.2",
36
+ "@milkdown/utils": "7.22.2",
30
37
  "prosemirror-safari-ime-span": "^1.0.1",
31
- "remark-gfm": "^4.0.1",
32
- "@milkdown/core": "7.22.0",
33
- "@milkdown/ctx": "7.22.0",
34
- "@milkdown/exception": "7.22.0",
35
- "@milkdown/prose": "7.22.0",
36
- "@milkdown/transformer": "7.22.0",
37
- "@milkdown/utils": "7.22.0",
38
- "@milkdown/preset-commonmark": "7.22.0"
38
+ "remark-gfm": "^4.0.1"
39
39
  },
40
40
  "scripts": {
41
41
  "build": "vite build"
@@ -0,0 +1,106 @@
1
+ import { editorViewCtx } from '@milkdown/core'
2
+ import { getMarkdown } from '@milkdown/utils'
3
+ import { describe, expect, it } from 'vitest'
4
+
5
+ import { countBrAtomsIn, roundTrip, withEditor } from './test-utils'
6
+
7
+ describe('inline br in gfm containers', () => {
8
+ it('does not drop a footnote whose definition has a block <br>', async () => {
9
+ const input = '[^note]: foo\n\n <br />\n\n bar\n\n'
10
+ const output = await roundTrip(input)
11
+ expect(output).toBe('[^note]: foo\n\n <br />\n\n bar\n')
12
+ })
13
+
14
+ it('keeps a referenced footnote whose definition has a block <br>', async () => {
15
+ const input = 'See [^note].\n\n[^note]: foo\n\n <br />\n\n bar\n\n'
16
+ const output = await roundTrip(input)
17
+ expect(output).toBe(
18
+ 'See [^note].\n\n[^note]: foo\n\n <br />\n\n bar\n'
19
+ )
20
+ })
21
+
22
+ it('keeps an inline <br> inside a footnote definition', async () => {
23
+ const output = await roundTrip('[^note]: foo<br>bar\n')
24
+ expect(output).toBe('[^note]: foo<br>bar\n')
25
+ })
26
+
27
+ // A lone <br> in a table cell is byte-identical to the placeholder the
28
+ // old serializer emitted for every empty cell, so it folds into an
29
+ // empty cell; the serializer no longer emits placeholders inside cells.
30
+ it('folds a lone table-cell <br> into an empty cell', async () => {
31
+ const input = '| <br> | c |\n| --- | --- |\n| x | y |\n'
32
+ expect(await countBrAtomsIn(input)).toBe(0)
33
+ const output = await roundTrip(input)
34
+ expect(output).toBe('| | c |\n| - | - |\n| x | y |\n')
35
+ })
36
+
37
+ it('loads a legacy empty-cell placeholder as an empty cell', async () => {
38
+ const input = '| <br /> | c |\n| --- | --- |\n| x | y |\n'
39
+ expect(await countBrAtomsIn(input)).toBe(0)
40
+ const output = await roundTrip(input)
41
+ expect(output).toBe('| | c |\n| - | - |\n| x | y |\n')
42
+ })
43
+
44
+ it('round-trips an empty table cell without a placeholder', async () => {
45
+ const input = '| | c |\n| --- | --- |\n| x | y |\n'
46
+ const output = await roundTrip(input)
47
+ expect(output).toBe('| | c |\n| - | - |\n| x | y |\n')
48
+ expect(output).not.toContain('<br')
49
+ })
50
+
51
+ it('keeps consecutive <br>s inside a table cell as atoms', async () => {
52
+ const input = '| <br><br> | c |\n| --- | --- |\n| x | y |\n'
53
+ expect(await countBrAtomsIn(input)).toBe(2)
54
+ const output = await roundTrip(input)
55
+ expect(output).toBe(
56
+ '| <br><br> | c |\n| -------- | - |\n| x | y |\n'
57
+ )
58
+ })
59
+
60
+ it('keeps sibling text and an inline <br> inside a table cell', async () => {
61
+ const input = '| a<br>b | c |\n| --- | --- |\n| x | y |\n'
62
+ expect(await countBrAtomsIn(input)).toBe(1)
63
+ const output = await roundTrip(input)
64
+ expect(output).toBe('| a<br>b | c |\n| ------ | - |\n| x | y |\n')
65
+ })
66
+
67
+ // An HTML paste can put a trailing hardbreak in a cell. The
68
+ // serializer drops it, the same as the paragraph serializer does.
69
+ // Otherwise it renders as a trailing space that the next parse trims,
70
+ // and two consecutive saves diverge.
71
+ it('drops a trailing hardbreak in a cell so saves stay stable', async () => {
72
+ const output = await withEditor(
73
+ '| a | c |\n| --- | --- |\n| x | y |\n',
74
+ (editor) =>
75
+ editor.action((ctx) => {
76
+ const view = ctx.get(editorViewCtx)
77
+ const { state } = view
78
+ const hardbreak = state.schema.nodes.hardbreak
79
+ if (!hardbreak) throw new Error('hardbreak type missing')
80
+ let pos = -1
81
+ state.doc.descendants((node, nodePos) => {
82
+ if (
83
+ pos === -1 &&
84
+ node.type.name === 'paragraph' &&
85
+ node.textContent === 'a'
86
+ )
87
+ pos = nodePos + node.nodeSize - 1
88
+ return pos === -1
89
+ })
90
+ view.dispatch(state.tr.insert(pos, hardbreak.create()))
91
+ return getMarkdown()(ctx)
92
+ })
93
+ )
94
+ expect(output).toBe('| a | c |\n| - | - |\n| x | y |\n')
95
+ })
96
+
97
+ it('keeps a lone <br> inside strikethrough', async () => {
98
+ const output = await roundTrip('~~<br>~~\n')
99
+ expect(output).toBe('~~<br>~~\n')
100
+ })
101
+
102
+ it('keeps an inline <br> inside a task list item', async () => {
103
+ const output = await roundTrip('- [ ] foo<br>bar\n')
104
+ expect(output).toBe('* [ ] foo<br>bar\n')
105
+ })
106
+ })
@@ -0,0 +1,69 @@
1
+ import '@testing-library/jest-dom/vitest'
2
+ import { Editor, editorViewCtx } from '@milkdown/core'
3
+ import { commonmark } from '@milkdown/preset-commonmark'
4
+ import { TextSelection } from '@milkdown/prose/state'
5
+ import { getMarkdown } from '@milkdown/utils'
6
+ import userEvent from '@testing-library/user-event'
7
+ import { describe, expect, it } from 'vitest'
8
+
9
+ import { gfm } from '..'
10
+
11
+ // The strikethrough input rule goes through the same `markRule` helper as the
12
+ // CommonMark marks, so it follows the same inline code boundary policy.
13
+
14
+ async function createEditor() {
15
+ const editor = Editor.make()
16
+ editor.use(commonmark)
17
+ editor.use(gfm)
18
+ await editor.create()
19
+ return editor
20
+ }
21
+
22
+ // Moving the caret drops the stored marks, so the input rule can no longer rely
23
+ // on them to tell whether the next character lands inside an inline code span.
24
+ function moveCaret(editor: Editor, pos?: number) {
25
+ const view = editor.ctx.get(editorViewCtx)
26
+ const { state } = view
27
+ view.dispatch(
28
+ state.tr.setSelection(
29
+ TextSelection.create(state.doc, pos ?? state.selection.from)
30
+ )
31
+ )
32
+ }
33
+
34
+ describe('strikethrough input rule around inline code', () => {
35
+ it('keeps delimiters typed inside an existing inline code literal', async () => {
36
+ const user = userEvent.setup()
37
+ const editor = await createEditor()
38
+ const view = editor.ctx.get(editorViewCtx)
39
+
40
+ await user.type(view.dom, '`ab`')
41
+ // put the caret between `a` and `b`, inside the code span
42
+ view.focus()
43
+ moveCaret(editor, 2)
44
+ await user.keyboard('~~x~~')
45
+
46
+ expect(editor.action(getMarkdown())).toBe('`a~~x~~b`\n')
47
+ })
48
+
49
+ it('still creates a strikethrough around inline code', async () => {
50
+ const user = userEvent.setup()
51
+ const editor = await createEditor()
52
+
53
+ await user.type(editor.ctx.get(editorViewCtx).dom, '~~`code`~~')
54
+
55
+ expect(editor.action(getMarkdown())).toBe('~~`code`~~\n')
56
+ })
57
+
58
+ it('still creates a strikethrough around inline code when the caret moved', async () => {
59
+ const user = userEvent.setup()
60
+ const editor = await createEditor()
61
+ const view = editor.ctx.get(editorViewCtx)
62
+
63
+ await user.type(view.dom, '~~`code`')
64
+ moveCaret(editor)
65
+ await user.type(view.dom, '~~')
66
+
67
+ expect(editor.action(getMarkdown())).toBe('~~`code`~~\n')
68
+ })
69
+ })
@@ -30,7 +30,7 @@ it('should not crash when serializing a table with empty header row', async () =
30
30
  const schema = editor.ctx.get(schemaCtx)
31
31
  const serializer = editor.ctx.get(serializerCtx)
32
32
 
33
- // Create a table with an empty header row (content.size === 0)
33
+ // An empty header row has a content size of 0.
34
34
  const tableHeaderRow = schema.nodes.table_header_row!.create()
35
35
  const tableRow = schema.nodes.table_row!.create(null, [
36
36
  schema.nodes.table_cell!.create(
@@ -41,7 +41,6 @@ it('should not crash when serializing a table with empty header row', async () =
41
41
  const table = schema.nodes.table!.create(null, [tableHeaderRow, tableRow])
42
42
  const doc = schema.topNodeType.createAndFill(null, [table])!
43
43
 
44
- // This should not throw
45
44
  expect(() => serializer(doc)).not.toThrow()
46
45
  })
47
46
 
@@ -1,31 +1,7 @@
1
- import '@testing-library/jest-dom/vitest'
2
- import {
3
- defaultValueCtx,
4
- Editor,
5
- editorViewCtx,
6
- schemaCtx,
7
- } from '@milkdown/core'
8
- import { commonmark } from '@milkdown/preset-commonmark'
9
- import { getMarkdown } from '@milkdown/utils'
1
+ import { editorViewCtx, schemaCtx } from '@milkdown/core'
10
2
  import { describe, expect, it } from 'vitest'
11
3
 
12
- import { gfm } from '..'
13
-
14
- async function createEditor(defaultValue: string) {
15
- const editor = Editor.make()
16
- editor.config((ctx) => {
17
- ctx.set(defaultValueCtx, defaultValue)
18
- })
19
- editor.use(commonmark)
20
- editor.use(gfm)
21
- await editor.create()
22
- return editor
23
- }
24
-
25
- async function roundTrip(markdown: string) {
26
- const editor = await createEditor(markdown)
27
- return editor.action(getMarkdown())
28
- }
4
+ import { roundTrip, withEditor } from './test-utils'
29
5
 
30
6
  // https://github.com/Milkdown/milkdown/issues/2419
31
7
  // Tight task lists must round-trip as tight, and the checkbox syntax
@@ -59,12 +35,13 @@ describe('task list spread round-trip (#2419)', () => {
59
35
  // does not throw on documents containing task lists.
60
36
  cases.forEach((markdown) => {
61
37
  it(`should round-trip through nodeFromJSON for ${JSON.stringify(markdown)}`, async () => {
62
- const editor = await createEditor(markdown)
63
- const doc = editor.ctx.get(editorViewCtx).state.doc
64
- const schema = editor.ctx.get(schemaCtx)
65
- const json = doc.toJSON()
66
- expect(() => schema.nodeFromJSON(json)).not.toThrow()
67
- expect(schema.nodeFromJSON(json).eq(doc)).toBe(true)
38
+ await withEditor(markdown, (editor) => {
39
+ const doc = editor.ctx.get(editorViewCtx).state.doc
40
+ const schema = editor.ctx.get(schemaCtx)
41
+ const json = doc.toJSON()
42
+ expect(() => schema.nodeFromJSON(json)).not.toThrow()
43
+ expect(schema.nodeFromJSON(json).eq(doc)).toBe(true)
44
+ })
68
45
  })
69
46
  })
70
47
  })
@@ -0,0 +1,63 @@
1
+ import { defaultValueCtx, Editor, editorViewCtx } from '@milkdown/core'
2
+ import { commonmark } from '@milkdown/preset-commonmark'
3
+ import { getMarkdown } from '@milkdown/utils'
4
+
5
+ import { gfm } from '..'
6
+
7
+ type EditorPlugins = Parameters<Editor['use']>[0]
8
+
9
+ /// Run `fn` against a fresh editor loaded with `defaultValue` and destroy
10
+ /// the editor afterwards. Uses the commonmark and gfm presets unless
11
+ /// `plugins` are given, in which case exactly those are used.
12
+ export async function withEditor<T>(
13
+ defaultValue: string,
14
+ fn: (editor: Editor) => T | Promise<T>,
15
+ ...plugins: EditorPlugins[]
16
+ ): Promise<T> {
17
+ const editor = Editor.make()
18
+ editor.config((ctx) => {
19
+ ctx.set(defaultValueCtx, defaultValue)
20
+ })
21
+ for (const plugin of plugins.length ? plugins : [commonmark, gfm])
22
+ editor.use(plugin)
23
+ // Outside the try: destroy() never settles on a half-created editor, so
24
+ // a creation failure must propagate directly instead of timing out.
25
+ await editor.create()
26
+ try {
27
+ return await fn(editor)
28
+ } finally {
29
+ await editor.destroy().catch(() => {})
30
+ }
31
+ }
32
+
33
+ export function roundTrip(markdown: string, ...plugins: EditorPlugins[]) {
34
+ return withEditor(
35
+ markdown,
36
+ (editor) => editor.action(getMarkdown()),
37
+ ...plugins
38
+ )
39
+ }
40
+
41
+ // Keep in sync with `isBrHtmlValue` in
42
+ // preset-commonmark/src/__internal__/empty-line-br.ts (deliberately not
43
+ // part of the public API).
44
+ const BR_VALUE_PATTERN = /^<br\s*\/?\s*>$/i
45
+
46
+ /// Load `markdown` and count the html atoms holding a `<br>` in the
47
+ /// resulting document.
48
+ export function countBrAtomsIn(markdown: string) {
49
+ return withEditor(markdown, (editor) =>
50
+ editor.action((ctx) => {
51
+ const doc = ctx.get(editorViewCtx).state.doc
52
+ let count = 0
53
+ doc.descendants((node) => {
54
+ if (
55
+ node.type.name === 'html' &&
56
+ BR_VALUE_PATTERN.test(String(node.attrs.value).trim())
57
+ )
58
+ count += 1
59
+ })
60
+ return count
61
+ })
62
+ )
63
+ }
@@ -38,7 +38,8 @@ export const footnoteDefinitionSchema = $nodeSchema(
38
38
  return [
39
39
  'dl',
40
40
  {
41
- // TODO: add a prosemirror plugin to sync label on change
41
+ // TODO: add a prosemirror plugin that syncs the label on a
42
+ // change.
42
43
  'data-label': label,
43
44
  'data-type': id,
44
45
  },
@@ -35,7 +35,8 @@ export const footnoteReferenceSchema = $nodeSchema(
35
35
  return [
36
36
  'sup',
37
37
  {
38
- // TODO: add a prosemirror plugin to sync label on change
38
+ // TODO: add a prosemirror plugin that syncs the label on a
39
+ // change.
39
40
  'data-label': label,
40
41
  'data-type': id,
41
42
  },
@@ -59,10 +59,10 @@ withMeta(insertTableInputRule, {
59
59
  group: 'Table',
60
60
  })
61
61
 
62
- /// A paste rule for fixing tables without header cells.
63
- /// This is a workaround for some editors (e.g. Google Docs) which allow creating tables without header cells,
64
- /// which is not supported by Markdown schema.
65
- /// This paste rule will promote the first data row to header, or add empty header cells as a fallback.
62
+ /// A paste rule that fixes a table without header cells. An editor such
63
+ /// as Google Docs creates a table without header cells, which the
64
+ /// Markdown schema does not support. This rule promotes the first data
65
+ /// row to a header row, or adds empty header cells as a fallback.
66
66
  export const tablePasteRule = $pasteRule((ctx) => ({
67
67
  run: (slice, _view, isPlainText) => {
68
68
  if (isPlainText) {
@@ -124,9 +124,9 @@ export const tablePasteRule = $pasteRule((ctx) => ({
124
124
  return newTable
125
125
  }
126
126
 
127
- // Wrap consecutive orphaned table_row nodes (at the top level of a fragment)
128
- // into a proper table. This happens when ProseMirror's parseSlice breaks
129
- // a table apart (e.g. when pasting multiple tables from Google Docs).
127
+ // Wrap the consecutive orphaned table_row nodes at the top level of
128
+ // a fragment into a table. `parseSlice` breaks a table apart this
129
+ // way, for example on a paste of several tables from Google Docs.
130
130
  function wrapOrphanedRows(fragment: FragmentType): FragmentType {
131
131
  const rowType = tableRowSchema.type(ctx)
132
132
  const nodes: ProsemirrorNode[] = []
@@ -136,7 +136,8 @@ export const tablePasteRule = $pasteRule((ctx) => ({
136
136
  function flushPendingRows() {
137
137
  if (pendingRows.length === 0) return
138
138
 
139
- // Create an empty table_header_row, then fixTable will promote the first data row
139
+ // An empty table_header_row lets `fixTable` promote the first
140
+ // data row.
140
141
  const emptyHeaderRow = tableHeaderRowSchema.type(ctx).createAndFill()!
141
142
  const table = tableSchema
142
143
  .type(ctx)
@@ -1,11 +1,36 @@
1
- import type { NodeType } from '@milkdown/prose/model'
2
- import type { MarkdownNode } from '@milkdown/transformer'
1
+ import type { Node, NodeType } from '@milkdown/prose/model'
2
+ import type { MarkdownNode, SerializerState } from '@milkdown/transformer'
3
3
 
4
4
  import { tableNodes } from '@milkdown/prose/tables'
5
5
  import { $nodeSchema } from '@milkdown/utils'
6
6
 
7
7
  import { withMeta } from '../../__internal__'
8
8
 
9
+ /// A cell holds exactly one paragraph. See `cellContent` below. An mdast
10
+ /// tableCell holds phrasing content directly. Serializing the inline
11
+ /// content of the paragraph keeps the paragraph serializer and its
12
+ /// empty-line placeholder out of a table cell. The parse runners mirror
13
+ /// this and wrap the flat cell content in a paragraph.
14
+ ///
15
+ /// Like `serializeText` in the paragraph runner, a trailing hardbreak is
16
+ /// dropped: mdast renders it as a trailing space inside a cell, which
17
+ /// the next parse trims, so keeping it makes consecutive saves diverge.
18
+ /// Cells that are not a single paragraph (schema-invalid but loadable
19
+ /// from JSON documents) are serialized as-is instead of losing children.
20
+ function serializeCellContent(state: SerializerState, node: Node) {
21
+ const paragraph = node.content.firstChild
22
+ if (node.childCount !== 1 || paragraph?.type.name !== 'paragraph') {
23
+ state.next(node.content)
24
+ return
25
+ }
26
+ const last = paragraph.lastChild
27
+ const content =
28
+ last?.type.name === 'hardbreak'
29
+ ? paragraph.content.cut(0, paragraph.content.size - last.nodeSize)
30
+ : paragraph.content
31
+ state.next(content)
32
+ }
33
+
9
34
  const originalSchema = tableNodes({
10
35
  tableGroup: 'block',
11
36
  cellContent: 'paragraph',
@@ -104,8 +129,8 @@ export const tableHeaderRowSchema = $nodeSchema('table_header_row', () => ({
104
129
  toMarkdown: {
105
130
  match: (node) => node.type.name === 'table_header_row',
106
131
  runner: (state, node) => {
107
- // if the row is empty, we don't need to create a table row
108
- // prevent remark from crashing
132
+ // An empty row needs no table row, and skipping it keeps remark
133
+ // from crashing.
109
134
  if (node.content.size === 0) {
110
135
  return
111
136
  }
@@ -147,8 +172,8 @@ export const tableRowSchema = $nodeSchema('table_row', () => ({
147
172
  toMarkdown: {
148
173
  match: (node) => node.type.name === 'table_row',
149
174
  runner: (state, node) => {
150
- // if the row is empty, we don't need to create a table row
151
- // prevent remark from crashing
175
+ // An empty row needs no table row, and skipping it keeps remark
176
+ // from crashing.
152
177
  if (node.content.size === 0) {
153
178
  return
154
179
  }
@@ -188,7 +213,9 @@ export const tableCellSchema = $nodeSchema('table_cell', () => ({
188
213
  toMarkdown: {
189
214
  match: (node) => node.type.name === 'table_cell',
190
215
  runner: (state, node) => {
191
- state.openNode('tableCell').next(node.content).closeNode()
216
+ state.openNode('tableCell')
217
+ serializeCellContent(state, node)
218
+ state.closeNode()
192
219
  },
193
220
  },
194
221
  }))
@@ -222,7 +249,7 @@ export const tableHeaderSchema = $nodeSchema('table_header', () => ({
222
249
  match: (node) => node.type.name === 'table_header',
223
250
  runner: (state, node) => {
224
251
  state.openNode('tableCell')
225
- state.next(node.content)
252
+ serializeCellContent(state, node)
226
253
  state.closeNode()
227
254
  },
228
255
  },
@@ -5,7 +5,8 @@ import { $inputRule } from '@milkdown/utils'
5
5
 
6
6
  import { withMeta } from '../__internal__'
7
7
 
8
- /// This schema extends the [list item](/preset-commonmark#list-item) schema and add task list support for it.
8
+ /// This schema extends the [list item](/preset-commonmark#list-item)
9
+ /// schema and adds task list support to it.
9
10
  export const extendListItemSchemaForTask = listItemSchema.extendSchema(
10
11
  (prev) => {
11
12
  return (ctx) => {
@@ -109,8 +110,8 @@ withMeta(extendListItemSchemaForTask.ctx, {
109
110
  group: 'ListItem',
110
111
  })
111
112
 
112
- /// Input rule for wrapping a block in task list node.
113
- /// Users can type `[ ] ` or `[x] ` to wrap the block in task list node with checked status.
113
+ /// An input rule that wraps a block in a task list node. Type `[ ] ` or
114
+ /// `[x] ` to wrap the block and set its checked status.
114
115
  export const wrapInTaskListInputRule = $inputRule(() => {
115
116
  return new InputRule(
116
117
  /^\[(?<checked>\s|x)\]\s$/,
@@ -3,8 +3,9 @@ import { imeSpan } from 'prosemirror-safari-ime-span'
3
3
 
4
4
  import { withMeta } from '../__internal__'
5
5
 
6
- /// This plugin is used to fix the bug of IME composing in table in Safari browser.
7
- /// original discussion in https://discuss.prosemirror.net/t/ime-composing-problems-on-td-or-th-element-in-safari-browser/4501
6
+ /// This plugin fixes an IME composing bug in a table in the Safari browser. See
7
+ /// the
8
+ /// [original discussion](https://discuss.prosemirror.net/t/ime-composing-problems-on-td-or-th-element-in-safari-browser/4501).
8
9
  export const autoInsertSpanPlugin = $prose(() => imeSpan)
9
10
 
10
11
  withMeta(autoInsertSpanPlugin, {
@@ -3,7 +3,8 @@ import { $prose } from '@milkdown/utils'
3
3
 
4
4
  import { withMeta } from '../__internal__'
5
5
 
6
- /// This plugin is wrapping the `columnResizing` plugin from [prosemirror-tables](https://github.com/ProseMirror/prosemirror-tables).
6
+ /// This plugin wraps the `columnResizing` plugin from
7
+ /// [prosemirror-tables](https://github.com/ProseMirror/prosemirror-tables).
7
8
  export const columnResizingPlugin = $prose(() => columnResizing({}))
8
9
 
9
10
  withMeta(columnResizingPlugin, {
@@ -47,7 +47,7 @@ export const keepTableAlignPlugin = $prose(() => {
47
47
  const tableRow = $pos.node($pos.depth)
48
48
  const table = $pos.node($pos.depth - 1)
49
49
  const tableHeaderRow = table.firstChild
50
- // TODO: maybe consider add a header row
50
+ // TODO: add a header row when the table has none.
51
51
  if (!tableHeaderRow) return
52
52
 
53
53
  const index = getChildIndex(node, tableRow)
@@ -6,7 +6,8 @@ import remarkGFM from 'remark-gfm'
6
6
 
7
7
  import { withMeta } from '../__internal__'
8
8
 
9
- /// This plugin is wrapping the [remark-gfm](https://github.com/remarkjs/remark-gfm).
9
+ /// This plugin wraps
10
+ /// [remark-gfm](https://github.com/remarkjs/remark-gfm).
10
11
  export const remarkGFMPlugin: $Remark<'remarkGFM', Options | null | undefined> =
11
12
  $remark('remarkGFM', () => remarkGFM)
12
13
 
@@ -3,7 +3,8 @@ import { $prose } from '@milkdown/utils'
3
3
 
4
4
  import { withMeta } from '../__internal__'
5
5
 
6
- /// This plugin is wrapping the `tableEditing` plugin from [prosemirror-tables](https://github.com/ProseMirror/prosemirror-tables).
6
+ /// This plugin wraps the `tableEditing` plugin from
7
+ /// [prosemirror-tables](https://github.com/ProseMirror/prosemirror-tables).
7
8
  export const tableEditingPlugin = $prose(() =>
8
9
  tableEditing({ allowTableNodeSelection: true })
9
10
  )