@milkdown/preset-gfm 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 (156) hide show
  1. package/lib/composed/commands.d.ts +8 -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 -34
  14. package/lib/index.d.ts.map +1 -1
  15. package/lib/index.es.js +634 -2328
  16. package/lib/index.es.js.map +1 -1
  17. package/lib/mark/index.d.ts +2 -0
  18. package/lib/mark/index.d.ts.map +1 -0
  19. package/lib/mark/strike-through.d.ts +5 -0
  20. package/lib/mark/strike-through.d.ts.map +1 -0
  21. package/lib/node/footnote/definition.d.ts +2 -0
  22. package/lib/node/footnote/definition.d.ts.map +1 -0
  23. package/lib/{footnote → node/footnote}/index.d.ts +0 -0
  24. package/lib/node/footnote/index.d.ts.map +1 -0
  25. package/lib/node/footnote/reference.d.ts +2 -0
  26. package/lib/node/footnote/reference.d.ts.map +1 -0
  27. package/lib/node/index.d.ts +4 -0
  28. package/lib/node/index.d.ts.map +1 -0
  29. package/lib/node/table/index.d.ts +32 -0
  30. package/lib/node/table/index.d.ts.map +1 -0
  31. package/lib/node/table/utils.d.ts +26 -0
  32. package/lib/node/table/utils.d.ts.map +1 -0
  33. package/lib/node/task-list-item.d.ts +2 -0
  34. package/lib/node/task-list-item.d.ts.map +1 -0
  35. package/lib/plugin/auto-insert-zero-space-plugin.d.ts +2 -0
  36. package/lib/plugin/auto-insert-zero-space-plugin.d.ts.map +1 -0
  37. package/lib/plugin/column-resizing-plugin.d.ts +2 -0
  38. package/lib/plugin/column-resizing-plugin.d.ts.map +1 -0
  39. package/lib/plugin/index.d.ts +5 -0
  40. package/lib/plugin/index.d.ts.map +1 -0
  41. package/lib/plugin/remark-gfm-plugin.d.ts +2 -0
  42. package/lib/plugin/remark-gfm-plugin.d.ts.map +1 -0
  43. package/lib/plugin/table-editing-plugin.d.ts +2 -0
  44. package/lib/plugin/table-editing-plugin.d.ts.map +1 -0
  45. package/package.json +13 -10
  46. package/src/composed/commands.ts +24 -0
  47. package/src/composed/index.ts +6 -0
  48. package/src/composed/inputrules.ts +8 -0
  49. package/src/composed/keymap.ts +10 -0
  50. package/src/composed/plugins.ts +11 -0
  51. package/src/composed/schema.ts +20 -0
  52. package/src/index.ts +6 -89
  53. package/src/mark/index.ts +2 -0
  54. package/src/mark/strike-through.ts +46 -0
  55. package/src/node/footnote/definition.ts +70 -0
  56. package/src/{footnote → node/footnote}/index.ts +0 -0
  57. package/src/node/footnote/reference.ts +60 -0
  58. package/src/node/index.ts +4 -0
  59. package/src/node/table/index.ts +318 -0
  60. package/src/node/table/utils.ts +509 -0
  61. package/src/node/task-list-item.ts +88 -0
  62. package/src/{table/plugin/auto-insert-zero-space.ts → plugin/auto-insert-zero-space-plugin.ts} +14 -15
  63. package/src/plugin/column-resizing-plugin.ts +6 -0
  64. package/src/plugin/index.ts +5 -0
  65. package/src/plugin/remark-gfm-plugin.ts +6 -0
  66. package/src/plugin/table-editing-plugin.ts +6 -0
  67. package/lib/footnote/definition.d.ts +0 -3
  68. package/lib/footnote/definition.d.ts.map +0 -1
  69. package/lib/footnote/index.d.ts.map +0 -1
  70. package/lib/footnote/reference.d.ts +0 -3
  71. package/lib/footnote/reference.d.ts.map +0 -1
  72. package/lib/footnote/utils.d.ts +0 -3
  73. package/lib/footnote/utils.d.ts.map +0 -1
  74. package/lib/strike-through.d.ts +0 -3
  75. package/lib/strike-through.d.ts.map +0 -1
  76. package/lib/supported-keys.d.ts +0 -28
  77. package/lib/supported-keys.d.ts.map +0 -1
  78. package/lib/table/command.d.ts +0 -4
  79. package/lib/table/command.d.ts.map +0 -1
  80. package/lib/table/index.d.ts +0 -10
  81. package/lib/table/index.d.ts.map +0 -1
  82. package/lib/table/nodes/index.d.ts +0 -12
  83. package/lib/table/nodes/index.d.ts.map +0 -1
  84. package/lib/table/operator-plugin/actions.d.ts +0 -20
  85. package/lib/table/operator-plugin/actions.d.ts.map +0 -1
  86. package/lib/table/operator-plugin/calc-pos.d.ts +0 -3
  87. package/lib/table/operator-plugin/calc-pos.d.ts.map +0 -1
  88. package/lib/table/operator-plugin/constant.d.ts +0 -6
  89. package/lib/table/operator-plugin/constant.d.ts.map +0 -1
  90. package/lib/table/operator-plugin/helper.d.ts +0 -7
  91. package/lib/table/operator-plugin/helper.d.ts.map +0 -1
  92. package/lib/table/operator-plugin/index.d.ts +0 -6
  93. package/lib/table/operator-plugin/index.d.ts.map +0 -1
  94. package/lib/table/operator-plugin/style.d.ts +0 -3
  95. package/lib/table/operator-plugin/style.d.ts.map +0 -1
  96. package/lib/table/operator-plugin/widget.d.ts +0 -8
  97. package/lib/table/operator-plugin/widget.d.ts.map +0 -1
  98. package/lib/table/plugin/auto-insert-zero-space.d.ts +0 -3
  99. package/lib/table/plugin/auto-insert-zero-space.d.ts.map +0 -1
  100. package/lib/table/plugin/cell-selection.d.ts +0 -40
  101. package/lib/table/plugin/cell-selection.d.ts.map +0 -1
  102. package/lib/table/plugin/column-resizing.d.ts +0 -18
  103. package/lib/table/plugin/column-resizing.d.ts.map +0 -1
  104. package/lib/table/plugin/commands.d.ts +0 -30
  105. package/lib/table/plugin/commands.d.ts.map +0 -1
  106. package/lib/table/plugin/copy-paste.d.ts +0 -14
  107. package/lib/table/plugin/copy-paste.d.ts.map +0 -1
  108. package/lib/table/plugin/fix-tables.d.ts +0 -7
  109. package/lib/table/plugin/fix-tables.d.ts.map +0 -1
  110. package/lib/table/plugin/index.d.ts +0 -4
  111. package/lib/table/plugin/index.d.ts.map +0 -1
  112. package/lib/table/plugin/schema.d.ts +0 -4
  113. package/lib/table/plugin/schema.d.ts.map +0 -1
  114. package/lib/table/plugin/table-editing.d.ts +0 -9
  115. package/lib/table/plugin/table-editing.d.ts.map +0 -1
  116. package/lib/table/plugin/table-map.d.ts +0 -44
  117. package/lib/table/plugin/table-map.d.ts.map +0 -1
  118. package/lib/table/plugin/table-view.d.ts +0 -15
  119. package/lib/table/plugin/table-view.d.ts.map +0 -1
  120. package/lib/table/plugin/types.d.ts +0 -15
  121. package/lib/table/plugin/types.d.ts.map +0 -1
  122. package/lib/table/plugin/util.d.ts +0 -16
  123. package/lib/table/plugin/util.d.ts.map +0 -1
  124. package/lib/table/utils.d.ts +0 -21
  125. package/lib/table/utils.d.ts.map +0 -1
  126. package/lib/task-list-item.d.ts +0 -9
  127. package/lib/task-list-item.d.ts.map +0 -1
  128. package/src/footnote/definition.ts +0 -187
  129. package/src/footnote/reference.ts +0 -178
  130. package/src/footnote/utils.ts +0 -4
  131. package/src/strike-through.ts +0 -43
  132. package/src/supported-keys.ts +0 -13
  133. package/src/table/command.ts +0 -20
  134. package/src/table/index.ts +0 -13
  135. package/src/table/nodes/index.ts +0 -189
  136. package/src/table/operator-plugin/actions.ts +0 -116
  137. package/src/table/operator-plugin/calc-pos.ts +0 -36
  138. package/src/table/operator-plugin/constant.ts +0 -7
  139. package/src/table/operator-plugin/helper.ts +0 -39
  140. package/src/table/operator-plugin/index.ts +0 -110
  141. package/src/table/operator-plugin/style.ts +0 -123
  142. package/src/table/operator-plugin/widget.ts +0 -57
  143. package/src/table/plugin/cell-selection.ts +0 -381
  144. package/src/table/plugin/column-resizing.ts +0 -288
  145. package/src/table/plugin/commands.ts +0 -594
  146. package/src/table/plugin/copy-paste.ts +0 -322
  147. package/src/table/plugin/fix-tables.ts +0 -132
  148. package/src/table/plugin/index.ts +0 -4
  149. package/src/table/plugin/schema.ts +0 -120
  150. package/src/table/plugin/table-editing.ts +0 -369
  151. package/src/table/plugin/table-map.ts +0 -345
  152. package/src/table/plugin/table-view.ts +0 -80
  153. package/src/table/plugin/types.ts +0 -16
  154. package/src/table/plugin/util.ts +0 -119
  155. package/src/table/utils.ts +0 -165
  156. package/src/task-list-item.ts +0 -159
@@ -0,0 +1,509 @@
1
+ /* Copyright 2021, Milkdown by Mirone. */
2
+
3
+ import type { ContentNodeWithPos } from '@milkdown/prose'
4
+ import { cloneTr, findParentNode } from '@milkdown/prose'
5
+ import type { Node } from '@milkdown/prose/model'
6
+ import type { Selection, Transaction } from '@milkdown/prose/state'
7
+ import type { TableRect } from '@milkdown/prose/tables'
8
+ import { CellSelection, TableMap } from '@milkdown/prose/tables'
9
+
10
+ import { tableCellSchema, tableHeaderSchema, tableRowSchema, tableSchema } from '.'
11
+
12
+ /// @internal
13
+ export interface CellPos {
14
+ pos: number
15
+ start: number
16
+ node: Node
17
+ }
18
+
19
+ /// @internal
20
+ export const createTable = (rowsCount = 3, colsCount = 3): Node => {
21
+ const cells = Array(colsCount)
22
+ .fill(0)
23
+ .map(() => tableCellSchema.type().createAndFill()!)
24
+
25
+ const headerCells = Array(colsCount)
26
+ .fill(0)
27
+ .map(() => tableHeaderSchema.type().createAndFill()!)
28
+
29
+ const rows = Array(rowsCount)
30
+ .fill(0)
31
+ .map((_, i) => tableRowSchema.type().create(null, i === 0 ? headerCells : cells))
32
+
33
+ return tableSchema.type().create(null, rows)
34
+ }
35
+
36
+ /// Find the table node with position information for current selection.
37
+ export const findTable = (selection: Selection) =>
38
+ findParentNode(node => node.type.spec.tableRole === 'table')(selection)
39
+
40
+ /// Get cells in a column of a table.
41
+ export const getCellsInCol = (columnIndex: number, selection: Selection): CellPos[] | undefined => {
42
+ const table = findTable(selection)
43
+ if (!table)
44
+ return undefined
45
+ const map = TableMap.get(table.node)
46
+ if (columnIndex < 0 || columnIndex >= map.width)
47
+ return undefined
48
+
49
+ return map
50
+ .cellsInRect({ left: columnIndex, right: columnIndex + 1, top: 0, bottom: map.height })
51
+ .map((pos) => {
52
+ const node = table.node.nodeAt(pos)
53
+ if (!node)
54
+ return undefined
55
+ const start = pos + table.start
56
+ return {
57
+ pos: start,
58
+ start: start + 1,
59
+ node,
60
+ }
61
+ })
62
+ .filter((x): x is CellPos => x != null)
63
+ }
64
+
65
+ /// Get cells in a row of a table.
66
+ export const getCellsInRow = (rowIndex: number, selection: Selection): CellPos[] | undefined => {
67
+ const table = findTable(selection)
68
+ if (!table)
69
+ return undefined
70
+ const map = TableMap.get(table.node)
71
+ if (rowIndex < 0 || rowIndex >= map.height)
72
+ return undefined
73
+
74
+ return map
75
+ .cellsInRect({ left: 0, right: map.width, top: rowIndex, bottom: rowIndex + 1 })
76
+ .map((pos) => {
77
+ const node = table.node.nodeAt(pos)
78
+ if (!node)
79
+ return undefined
80
+ const start = pos + table.start
81
+ return {
82
+ pos: start,
83
+ start: start + 1,
84
+ node,
85
+ }
86
+ })
87
+ .filter((x): x is CellPos => x != null)
88
+ }
89
+
90
+ /// Get all cells in a table.
91
+ export const getAllCellsInTable = (selection: Selection) => {
92
+ const table = findTable(selection)
93
+ if (!table)
94
+ return
95
+
96
+ const map = TableMap.get(table.node)
97
+ const cells = map.cellsInRect({
98
+ left: 0,
99
+ right: map.width,
100
+ top: 0,
101
+ bottom: map.height,
102
+ })
103
+ return cells.map((nodePos) => {
104
+ const node = table.node.nodeAt(nodePos)
105
+ const pos = nodePos + table.start
106
+ return { pos, start: pos + 1, node }
107
+ })
108
+ }
109
+
110
+ /// Select a possible table in current selection.
111
+ export const selectTable = (tr: Transaction) => {
112
+ const cells = getAllCellsInTable(tr.selection)
113
+ if (cells && cells[0]) {
114
+ const $firstCell = tr.doc.resolve(cells[0].pos)
115
+ const last = cells[cells.length - 1]
116
+ if (last) {
117
+ const $lastCell = tr.doc.resolve(last.pos)
118
+ return cloneTr(tr.setSelection(new CellSelection($lastCell, $firstCell)))
119
+ }
120
+ }
121
+ return tr
122
+ }
123
+
124
+ /// @internal
125
+ export function addRowWithAlignment(tr: Transaction, { map, tableStart, table }: TableRect, row: number) {
126
+ const rowPos = Array(row)
127
+ .fill(0)
128
+ .reduce((acc, _, i) => {
129
+ return acc + table.child(i).nodeSize
130
+ }, tableStart)
131
+
132
+ const cells = Array(map.width)
133
+ .fill(0)
134
+ .map((_, col) => {
135
+ const headerCol = table.nodeAt(map.map[col] as number)
136
+ return tableCellSchema.type().createAndFill({ alignment: headerCol?.attrs.alignment }) as Node
137
+ })
138
+
139
+ tr.insert(rowPos, tableRowSchema.type().create(null, cells))
140
+ return tr
141
+ }
142
+
143
+ /// @internal
144
+ export const selectLine = (type: 'row' | 'col') => (index: number) => (tr: Transaction) => {
145
+ const table = findTable(tr.selection)
146
+ const isRowSelection = type === 'row'
147
+ if (table) {
148
+ const map = TableMap.get(table.node)
149
+
150
+ // Check if the index is valid
151
+ if (index >= 0 && index < (isRowSelection ? map.height : map.width)) {
152
+ const lastCell = map.positionAt(
153
+ isRowSelection ? index : map.height - 1,
154
+ isRowSelection ? map.width - 1 : index,
155
+ table.node,
156
+ )
157
+ const $lastCell = tr.doc.resolve(table.start + lastCell)
158
+
159
+ const createCellSelection = isRowSelection ? CellSelection.rowSelection : CellSelection.colSelection
160
+
161
+ const firstCell = map.positionAt(isRowSelection ? index : 0, isRowSelection ? 0 : index, table.node)
162
+ const $firstCell = tr.doc.resolve(table.start + firstCell)
163
+ return cloneTr(tr.setSelection(createCellSelection($lastCell, $firstCell) as unknown as Selection))
164
+ }
165
+ }
166
+ return tr
167
+ }
168
+
169
+ /// If the selection is in a table,
170
+ /// select the {index} row.
171
+ export const selectRow = selectLine('row')
172
+
173
+ /// If the selection is in a table,
174
+ /// select the {index} column.
175
+ export const selectCol = selectLine('col')
176
+
177
+ const transpose = <T>(array: T[][]) => {
178
+ return array[0]!.map((_, i) => {
179
+ return array.map(column => column[i])
180
+ }) as T[][]
181
+ }
182
+
183
+ const convertArrayOfRowsToTableNode = (tableNode: Node, arrayOfNodes: (Node | null)[][]) => {
184
+ const rowsPM = []
185
+ const map = TableMap.get(tableNode)
186
+ for (let rowIndex = 0; rowIndex < map.height; rowIndex++) {
187
+ const row = tableNode.child(rowIndex)
188
+ const rowCells = []
189
+
190
+ for (let colIndex = 0; colIndex < map.width; colIndex++) {
191
+ if (!arrayOfNodes[rowIndex]![colIndex])
192
+ continue
193
+
194
+ const cellPos = map.map[rowIndex * map.width + colIndex]!
195
+
196
+ const cell = arrayOfNodes[rowIndex]![colIndex]!
197
+ const oldCell = tableNode.nodeAt(cellPos)!
198
+ const newCell = oldCell.type.createChecked(
199
+ Object.assign({}, cell.attrs),
200
+ cell.content,
201
+ cell.marks,
202
+ )
203
+ rowCells.push(newCell)
204
+ }
205
+
206
+ rowsPM.push(row.type.createChecked(row.attrs, rowCells, row.marks))
207
+ }
208
+
209
+ const newTable = tableNode.type.createChecked(
210
+ tableNode.attrs,
211
+ rowsPM,
212
+ tableNode.marks,
213
+ )
214
+
215
+ return newTable
216
+ }
217
+
218
+ const convertTableNodeToArrayOfRows = (tableNode: Node) => {
219
+ const map = TableMap.get(tableNode)
220
+ const rows: (Node | null)[][] = []
221
+ for (let rowIndex = 0; rowIndex < map.height; rowIndex++) {
222
+ const rowCells: (Node | null)[] = []
223
+ const seen: Record<number, boolean> = {}
224
+
225
+ for (let colIndex = 0; colIndex < map.width; colIndex++) {
226
+ const cellPos = map.map[rowIndex * map.width + colIndex]!
227
+ const cell = tableNode.nodeAt(cellPos)
228
+ const rect = map.findCell(cellPos)
229
+ if (seen[cellPos] || rect.top !== rowIndex) {
230
+ rowCells.push(null)
231
+ continue
232
+ }
233
+ seen[cellPos] = true
234
+
235
+ rowCells.push(cell)
236
+ }
237
+
238
+ rows.push(rowCells)
239
+ }
240
+
241
+ return rows
242
+ }
243
+
244
+ const moveRowInArrayOfRows = (
245
+ rows: (Node | null)[][],
246
+ indexesOrigin: number[],
247
+ indexesTarget: number[],
248
+ directionOverride: -1 | 1 | 0,
249
+ ) => {
250
+ const direction = indexesOrigin[0]! > indexesTarget[0]! ? -1 : 1
251
+
252
+ const rowsExtracted = rows.splice(indexesOrigin[0]!, indexesOrigin.length)
253
+ const positionOffset = rowsExtracted.length % 2 === 0 ? 1 : 0
254
+ let target: number
255
+
256
+ if (directionOverride === -1 && direction === 1) {
257
+ target = indexesTarget[0]! - 1
258
+ }
259
+ else if (directionOverride === 1 && direction === -1) {
260
+ target = indexesTarget[indexesTarget.length - 1]! - positionOffset + 1
261
+ }
262
+ else {
263
+ target
264
+ = direction === -1
265
+ ? indexesTarget[0]!
266
+ : indexesTarget[indexesTarget.length - 1]! - positionOffset
267
+ }
268
+
269
+ rows.splice(target, 0, ...rowsExtracted)
270
+ return rows
271
+ }
272
+
273
+ const moveTableColumn = (
274
+ table: ContentNodeWithPos,
275
+ indexesOrigin: number[],
276
+ indexesTarget: number[],
277
+ direction: -1 | 1 | 0,
278
+ ) => {
279
+ let rows = transpose(convertTableNodeToArrayOfRows(table.node))
280
+
281
+ rows = moveRowInArrayOfRows(rows, indexesOrigin, indexesTarget, direction)
282
+ rows = transpose(rows)
283
+
284
+ return convertArrayOfRowsToTableNode(table.node, rows)
285
+ }
286
+
287
+ const moveTableRow = (
288
+ table: ContentNodeWithPos,
289
+ indexesOrigin: number[],
290
+ indexesTarget: number[],
291
+ direction: -1 | 1 | 0,
292
+ ) => {
293
+ let rows = convertTableNodeToArrayOfRows(table.node)
294
+
295
+ rows = moveRowInArrayOfRows(rows, indexesOrigin, indexesTarget, direction)
296
+
297
+ return convertArrayOfRowsToTableNode(table.node, rows)
298
+ }
299
+
300
+ const getSelectionRangeInColumn = (columnIndex: number, tr: Transaction) => {
301
+ let startIndex = columnIndex
302
+ let endIndex = columnIndex
303
+
304
+ // looking for selection start column (startIndex)
305
+ for (let i = columnIndex; i >= 0; i--) {
306
+ const cells = getCellsInCol(i, tr.selection)
307
+ if (cells) {
308
+ cells.forEach((cell) => {
309
+ const maybeEndIndex = cell.node.attrs.colspan + i - 1
310
+ if (maybeEndIndex >= startIndex)
311
+ startIndex = i
312
+
313
+ if (maybeEndIndex > endIndex)
314
+ endIndex = maybeEndIndex
315
+ })
316
+ }
317
+ }
318
+ // looking for selection end column (endIndex)
319
+ for (let i = columnIndex; i <= endIndex; i++) {
320
+ const cells = getCellsInCol(i, tr.selection)
321
+ if (cells) {
322
+ cells.forEach((cell) => {
323
+ const maybeEndIndex = cell.node.attrs.colspan + i - 1
324
+ if (cell.node.attrs.colspan > 1 && maybeEndIndex > endIndex)
325
+ endIndex = maybeEndIndex
326
+ })
327
+ }
328
+ }
329
+
330
+ // filter out columns without cells (where all rows have colspan > 1 in the same column)
331
+ const indexes = []
332
+ for (let i = startIndex; i <= endIndex; i++) {
333
+ const maybeCells = getCellsInCol(i, tr.selection)
334
+ if (maybeCells && maybeCells.length)
335
+ indexes.push(i)
336
+ }
337
+ startIndex = indexes[0]!
338
+ endIndex = indexes[indexes.length - 1]!
339
+
340
+ const firstSelectedColumnCells = getCellsInCol(startIndex, tr.selection)!
341
+ const firstRowCells = getCellsInRow(0, tr.selection)!
342
+ const $anchor = tr.doc.resolve(
343
+ firstSelectedColumnCells[firstSelectedColumnCells.length - 1]!.pos,
344
+ )
345
+
346
+ let headCell: CellPos | undefined
347
+ for (let i = endIndex; i >= startIndex; i--) {
348
+ const columnCells = getCellsInCol(i, tr.selection)
349
+ if (columnCells && columnCells.length) {
350
+ for (let j = firstRowCells.length - 1; j >= 0; j--) {
351
+ if (firstRowCells[j]!.pos === columnCells[0]!.pos) {
352
+ headCell = columnCells[0]
353
+ break
354
+ }
355
+ }
356
+ if (headCell)
357
+ break
358
+ }
359
+ }
360
+
361
+ const $head = tr.doc.resolve(headCell!.pos)
362
+ return { $anchor, $head, indexes }
363
+ }
364
+
365
+ const getSelectionRangeInRow = (rowIndex: number, tr: Transaction) => {
366
+ let startIndex = rowIndex
367
+ let endIndex = rowIndex
368
+ // looking for selection start row (startIndex)
369
+ for (let i = rowIndex; i >= 0; i--) {
370
+ const cells = getCellsInRow(i, tr.selection)
371
+ cells!.forEach((cell) => {
372
+ const maybeEndIndex = cell.node.attrs.rowspan + i - 1
373
+ if (maybeEndIndex >= startIndex)
374
+ startIndex = i
375
+
376
+ if (maybeEndIndex > endIndex)
377
+ endIndex = maybeEndIndex
378
+ })
379
+ }
380
+ // looking for selection end row (endIndex)
381
+ for (let i = rowIndex; i <= endIndex; i++) {
382
+ const cells = getCellsInRow(i, tr.selection)
383
+ cells!.forEach((cell) => {
384
+ const maybeEndIndex = cell.node.attrs.rowspan + i - 1
385
+ if (cell.node.attrs.rowspan > 1 && maybeEndIndex > endIndex)
386
+ endIndex = maybeEndIndex
387
+ })
388
+ }
389
+
390
+ // filter out rows without cells (where all columns have rowspan > 1 in the same row)
391
+ const indexes = []
392
+ for (let i = startIndex; i <= endIndex; i++) {
393
+ const maybeCells = getCellsInRow(i, tr.selection)
394
+ if (maybeCells && maybeCells.length)
395
+ indexes.push(i)
396
+ }
397
+ startIndex = indexes[0]!
398
+ endIndex = indexes[indexes.length - 1]!
399
+
400
+ const firstSelectedRowCells = getCellsInRow(startIndex, tr.selection)!
401
+ const firstColumnCells = getCellsInCol(0, tr.selection)!
402
+ const $anchor = tr.doc.resolve(firstSelectedRowCells[firstSelectedRowCells.length - 1]!.pos)
403
+
404
+ let headCell: CellPos | undefined
405
+ for (let i = endIndex; i >= startIndex; i--) {
406
+ const rowCells = getCellsInRow(i, tr.selection)
407
+ if (rowCells && rowCells.length) {
408
+ for (let j = firstColumnCells.length - 1; j >= 0; j--) {
409
+ if (firstColumnCells[j]!.pos === rowCells[0]!.pos) {
410
+ headCell = rowCells[0]!
411
+ break
412
+ }
413
+ }
414
+ if (headCell)
415
+ break
416
+ }
417
+ }
418
+
419
+ const $head = tr.doc.resolve(headCell!.pos)
420
+ return { $anchor, $head, indexes }
421
+ }
422
+
423
+ /// If the selection is in a table,
424
+ /// Move the columns at `origin` to `target` in current table.
425
+ /// The `select` is true by default, which means the selection will be set to the moved column.
426
+ export function moveCol(tr: Transaction, origin: number, target: number, select = true) {
427
+ const table = findTable(tr.selection)
428
+ if (!table)
429
+ return tr
430
+
431
+ const { indexes: indexesOriginColumn } = getSelectionRangeInColumn(origin, tr)
432
+ const { indexes: indexesTargetColumn } = getSelectionRangeInColumn(target, tr)
433
+
434
+ if (indexesOriginColumn.includes(target))
435
+ return tr
436
+
437
+ const newTable = moveTableColumn(
438
+ table,
439
+ indexesOriginColumn,
440
+ indexesTargetColumn,
441
+ 0,
442
+ )
443
+
444
+ const _tr = cloneTr(tr).replaceWith(
445
+ table.pos,
446
+ table.pos + table.node.nodeSize,
447
+ newTable,
448
+ )
449
+
450
+ if (!select)
451
+ return _tr
452
+
453
+ const map = TableMap.get(newTable)
454
+ const start = table.start
455
+ const index = target
456
+ const lastCell = map.positionAt(map.height - 1, index, newTable)
457
+ const $lastCell = _tr.doc.resolve(start + lastCell)
458
+
459
+ const createCellSelection = CellSelection.colSelection
460
+
461
+ const firstCell = map.positionAt(0, index, newTable)
462
+ const $firstCell = _tr.doc.resolve(start + firstCell)
463
+
464
+ return _tr.setSelection(createCellSelection($lastCell, $firstCell))
465
+ }
466
+
467
+ /// If the selection is in a table,
468
+ /// Move the rows at `origin` and `target` in current table.
469
+ /// The `select` is true by default, which means the selection will be set to the moved row.
470
+ export function moveRow(tr: Transaction, origin: number, target: number, select = true) {
471
+ const table = findTable(tr.selection)
472
+ if (!table)
473
+ return tr
474
+
475
+ const { indexes: indexesOriginRow } = getSelectionRangeInRow(origin, tr)
476
+ const { indexes: indexesTargetRow } = getSelectionRangeInRow(target, tr)
477
+
478
+ if (indexesOriginRow.includes(target))
479
+ return tr
480
+
481
+ const newTable = moveTableRow(
482
+ table,
483
+ indexesOriginRow,
484
+ indexesTargetRow,
485
+ 0,
486
+ )
487
+
488
+ const _tr = cloneTr(tr).replaceWith(
489
+ table.pos,
490
+ table.pos + table.node.nodeSize,
491
+ newTable,
492
+ )
493
+
494
+ if (!select)
495
+ return _tr
496
+
497
+ const map = TableMap.get(newTable)
498
+ const start = table.start
499
+ const index = target
500
+ const lastCell = map.positionAt(index, map.width - 1, newTable)
501
+ const $lastCell = _tr.doc.resolve(start + lastCell)
502
+
503
+ const createCellSelection = CellSelection.rowSelection
504
+
505
+ const firstCell = map.positionAt(index, 0, newTable)
506
+ const $firstCell = _tr.doc.resolve(start + firstCell)
507
+
508
+ return _tr.setSelection(createCellSelection($lastCell, $firstCell))
509
+ }
@@ -0,0 +1,88 @@
1
+ /* Copyright 2021, Milkdown by Mirone. */
2
+ import { expectDomTypeError } from '@milkdown/exception'
3
+ import { listItemSchema } from '@milkdown/preset-commonmark'
4
+
5
+ /// This schema extends the [list item](/preset-commonmark#list-item) schema and add task list support for it.
6
+ export const extendListItemSchemaForTask = listItemSchema.extendSchema((prev) => {
7
+ return (ctx) => {
8
+ const baseSchema = prev(ctx)
9
+ return {
10
+ ...baseSchema,
11
+ attrs: {
12
+ ...baseSchema.attrs,
13
+ checked: {
14
+ default: null,
15
+ },
16
+ },
17
+ parseDOM: [
18
+ {
19
+ tag: 'li[data-item-type="task"]',
20
+ getAttrs: (dom) => {
21
+ if (!(dom instanceof HTMLElement))
22
+ throw expectDomTypeError(dom)
23
+
24
+ return {
25
+ label: dom.dataset.label,
26
+ listType: dom.dataset['list-type'],
27
+ spread: dom.dataset.spread,
28
+ checked: dom.dataset.checked ? dom.dataset.checked === 'true' : null,
29
+ }
30
+ },
31
+ },
32
+ ...baseSchema?.parseDOM || [],
33
+ ],
34
+ toDOM: (node) => {
35
+ if (baseSchema.toDOM && node.attrs.checked == null)
36
+ return baseSchema.toDOM(node)
37
+
38
+ return [
39
+ 'li',
40
+ {
41
+ 'data-item-type': 'task',
42
+ 'data-label': node.attrs.label,
43
+ 'data-list-type': node.attrs.listType,
44
+ 'data-spread': node.attrs.spread,
45
+ 'data-checked': node.attrs.checked,
46
+ },
47
+ 0,
48
+ ]
49
+ },
50
+ parseMarkdown: {
51
+ match: ({ type }) => type === 'listItem',
52
+ runner: (state, node, type) => {
53
+ if (node.checked == null) {
54
+ baseSchema.parseMarkdown.runner(state, node, type)
55
+ return
56
+ }
57
+
58
+ const label = node.label != null ? `${node.label}.` : '•'
59
+ const checked = node.checked != null ? Boolean(node.checked) : null
60
+ const listType = node.label != null ? 'ordered' : 'bullet'
61
+ const spread = node.spread != null ? `${node.spread}` : 'true'
62
+
63
+ state.openNode(type, { label, listType, spread, checked })
64
+ state.next(node.children)
65
+ state.closeNode()
66
+ },
67
+ },
68
+ toMarkdown: {
69
+ match: node => node.type.name === 'list_item',
70
+ runner: (state, node) => {
71
+ if (node.attrs.checked == null) {
72
+ baseSchema.toMarkdown.runner(state, node)
73
+ return
74
+ }
75
+
76
+ const label = node.attrs.label
77
+ const listType = node.attrs.listType
78
+ const spread = node.attrs.spread === 'true'
79
+ const checked = node.attrs.checked
80
+
81
+ state.openNode('listItem', undefined, { label, listType, spread, checked })
82
+ state.next(node.content)
83
+ state.closeNode()
84
+ },
85
+ },
86
+ }
87
+ }
88
+ })
@@ -1,21 +1,20 @@
1
1
  /* Copyright 2021, Milkdown by Mirone. */
2
2
  import { browser } from '@milkdown/prose'
3
3
  import type { Node } from '@milkdown/prose/model'
4
+ import { isInTable } from '@milkdown/prose/tables'
4
5
  import { Plugin, PluginKey } from '@milkdown/prose/state'
6
+ import { paragraphSchema } from '@milkdown/preset-commonmark'
7
+ import { $prose } from '@milkdown/utils'
5
8
 
6
- import { isInTable } from './util'
9
+ /// This plugin is used to fix the bug of IME composing in table in Safari browser.
10
+ /// original discussion in https://discuss.prosemirror.net/t/ime-composing-problems-on-td-or-th-element-in-safari-browser/4501
11
+ export const autoInsertZeroSpaceInTablePlugin = $prose(() => {
12
+ const pluginKey = new PluginKey('MILKDOWN_AUTO_INSERT_ZERO_SPACE')
7
13
 
8
- const isEmptyParagraph = (node: Node) => {
9
- return node.type.name === 'paragraph' && node.nodeSize === 2
10
- }
14
+ const isParagraph = (node: Node) => node.type === paragraphSchema.type()
11
15
 
12
- const isParagraph = (node: Node) => {
13
- return node.type.name === 'paragraph'
14
- }
16
+ const isEmptyParagraph = (node: Node) => isParagraph(node) && node.nodeSize === 2
15
17
 
16
- const pluginKey = new PluginKey('plugin_autoInsertZeroSpace')
17
-
18
- export const autoInsertZeroSpace = () => {
19
18
  return new Plugin({
20
19
  key: pluginKey,
21
20
  props: {
@@ -36,10 +35,10 @@ export const autoInsertZeroSpace = () => {
36
35
 
37
36
  if (
38
37
  browser.safari
39
- && isInTable(state)
40
- && selection.empty
41
- && isParagraph($from.parent)
42
- && $from.parent.textContent.startsWith('\u2060')
38
+ && isInTable(state)
39
+ && selection.empty
40
+ && isParagraph($from.parent)
41
+ && $from.parent.textContent.startsWith('\u2060')
43
42
  )
44
43
  dispatch(tr.delete($from.start(), $from.start() + 1))
45
44
 
@@ -48,4 +47,4 @@ export const autoInsertZeroSpace = () => {
48
47
  },
49
48
  },
50
49
  })
51
- }
50
+ })
@@ -0,0 +1,6 @@
1
+ /* Copyright 2021, Milkdown by Mirone. */
2
+ import { columnResizing } from '@milkdown/prose/tables'
3
+ import { $prose } from '@milkdown/utils'
4
+
5
+ /// This plugin is wrapping the `columnResizing` plugin from [prosemirror-tables](https://github.com/ProseMirror/prosemirror-tables).
6
+ export const columnResizingPlugin = $prose(() => columnResizing({}))
@@ -0,0 +1,5 @@
1
+ /* Copyright 2021, Milkdown by Mirone. */
2
+ export * from './auto-insert-zero-space-plugin'
3
+ export * from './column-resizing-plugin'
4
+ export * from './table-editing-plugin'
5
+ export * from './remark-gfm-plugin'
@@ -0,0 +1,6 @@
1
+ /* Copyright 2021, Milkdown by Mirone. */
2
+ import { $remark } from '@milkdown/utils'
3
+ import remarkGFM from 'remark-gfm'
4
+
5
+ /// This plugin is wrapping the [remark-gfm](https://github.com/remarkjs/remark-gfm).
6
+ export const remarkGFMPlugin = $remark(() => remarkGFM)
@@ -0,0 +1,6 @@
1
+ /* Copyright 2021, Milkdown by Mirone. */
2
+ import { tableEditing } from '@milkdown/prose/tables'
3
+ import { $prose } from '@milkdown/utils'
4
+
5
+ /// This plugin is wrapping the `tableEditing` plugin from [prosemirror-tables](https://github.com/ProseMirror/prosemirror-tables).
6
+ export const tableEditingPlugin = $prose(() => tableEditing())
@@ -1,3 +0,0 @@
1
- export declare const ModifyFootnoteDef: import("@milkdown/core").CmdKey<string>;
2
- export declare const footnoteDefinition: import("@milkdown/utils").NodeCreator<string, {}>;
3
- //# sourceMappingURL=definition.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/footnote/definition.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,iBAAiB,yCAA4C,CAAA;AAE1E,eAAO,MAAM,kBAAkB,mDA0K7B,CAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/footnote/index.ts"],"names":[],"mappings":"AACA,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA"}
@@ -1,3 +0,0 @@
1
- export declare const ModifyFootnoteRef: import("@milkdown/core").CmdKey<string>;
2
- export declare const footnoteReference: import("@milkdown/utils").NodeCreator<string, {}>;
3
- //# sourceMappingURL=reference.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"reference.d.ts","sourceRoot":"","sources":["../../src/footnote/reference.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,iBAAiB,yCAA4C,CAAA;AAG1E,eAAO,MAAM,iBAAiB,mDAiK5B,CAAA"}