@milkdown/preset-gfm 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 (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 +633 -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 +4 -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 +27 -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 +23 -0
  47. package/src/composed/index.ts +6 -0
  48. package/src/composed/inputrules.ts +7 -0
  49. package/src/composed/keymap.ts +9 -0
  50. package/src/composed/plugins.ts +10 -0
  51. package/src/composed/schema.ts +18 -0
  52. package/src/index.ts +5 -89
  53. package/src/mark/index.ts +2 -0
  54. package/src/mark/strike-through.ts +39 -0
  55. package/src/node/footnote/definition.ts +68 -0
  56. package/src/{footnote → node/footnote}/index.ts +0 -0
  57. package/src/node/footnote/reference.ts +58 -0
  58. package/src/node/index.ts +4 -0
  59. package/src/node/table/index.ts +283 -0
  60. package/src/node/table/utils.ts +489 -0
  61. package/src/node/task-list-item.ts +87 -0
  62. package/src/{table/plugin/auto-insert-zero-space.ts → plugin/auto-insert-zero-space-plugin.ts} +13 -15
  63. package/src/plugin/column-resizing-plugin.ts +4 -0
  64. package/src/plugin/index.ts +5 -0
  65. package/src/plugin/remark-gfm-plugin.ts +5 -0
  66. package/src/plugin/table-editing-plugin.ts +4 -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
@@ -1,594 +0,0 @@
1
- /* Copyright 2021, Milkdown by Mirone. */
2
-
3
- import type { Node, NodeSpec, NodeType, ResolvedPos } from '@milkdown/prose/model'
4
- import { Fragment } from '@milkdown/prose/model'
5
- import type { Command, EditorState, Transaction } from '@milkdown/prose/state'
6
- import { TextSelection } from '@milkdown/prose/state'
7
-
8
- import { CellSelection } from './cell-selection'
9
- import { tableNodeTypes } from './schema'
10
- import { Rect, TableMap } from './table-map'
11
- import {
12
- addColSpan,
13
- cellAround,
14
- cellWrapping,
15
- columnIsHeader,
16
- isInTable,
17
- moveCellForward,
18
- removeColSpan,
19
- selectionCell,
20
- setAttr,
21
- } from './util'
22
-
23
- // Helper to get the selected rectangle in a table, if any. Adds table
24
- // map, table node, and table start offset to the object for
25
- // convenience.
26
- export function selectedRect(state: EditorState): Required<Rect> {
27
- const sel = state.selection
28
- const $pos = selectionCell(state) as ResolvedPos
29
- const table = $pos.node(-1)
30
- const tableStart = $pos.start(-1)
31
- const map = TableMap.get(table)
32
- let rect
33
- if (sel instanceof CellSelection)
34
- rect = map.rectBetween(sel.$anchorCell.pos - tableStart, sel.$headCell.pos - tableStart)
35
- else rect = map.findCell($pos.pos - tableStart)
36
- rect.tableStart = tableStart
37
- rect.map = map
38
- rect.table = table
39
- return rect as Required<Rect>
40
- }
41
-
42
- // Add a column at the given position in a table.
43
- export function addColumn(tr: Transaction, { map, tableStart, table }: Rect, col: number) {
44
- map = map as TableMap
45
- table = table as Node
46
- tableStart = tableStart as number
47
- let refColumn: number | null = col > 0 ? -1 : 0
48
- if (columnIsHeader(map, table, col + refColumn))
49
- refColumn = col == 0 || col == map.width ? null : 0
50
-
51
- for (let row = 0; row < map.height; row++) {
52
- const index = row * map.width + col
53
- // If this position falls inside a col-spanning cell
54
- if (col > 0 && col < map.width && map.map[index - 1] == map.map[index]) {
55
- const pos = map.map[index] as number
56
- const cell = table.nodeAt(pos) as Node
57
- tr.setNodeMarkup(tr.mapping.map(tableStart + pos), null, addColSpan(cell.attrs, col - map.colCount(pos)))
58
- // Skip ahead if rowspan > 1
59
- row += cell.attrs.rowspan - 1
60
- }
61
- else {
62
- const offset = map.map[index + (refColumn as number)] as number
63
- const type
64
- = refColumn == null ? tableNodeTypes(table.type.schema).cell : (table.nodeAt(offset) as Node).type
65
- const pos = map.positionAt(row, col, table)
66
- tr.insert(tr.mapping.map(tableStart + pos), type.createAndFill())
67
- }
68
- }
69
- return tr
70
- }
71
-
72
- // :: (EditorState, dispatch: ?(tr: Transaction)) → bool
73
- // Command to add a column before the column with the selection.
74
- export const addColumnBefore: Command = (state, dispatch) => {
75
- if (!isInTable(state))
76
- return false
77
- if (dispatch) {
78
- const rect = selectedRect(state)
79
- dispatch(addColumn(state.tr, rect, rect.left))
80
- }
81
- return true
82
- }
83
-
84
- // :: (EditorState, dispatch: ?(tr: Transaction)) → bool
85
- // Command to add a column after the column with the selection.
86
- export const addColumnAfter: Command = (state, dispatch) => {
87
- if (!isInTable(state))
88
- return false
89
- if (dispatch) {
90
- const rect = selectedRect(state)
91
- dispatch(addColumn(state.tr, rect, rect.right))
92
- }
93
- return true
94
- }
95
-
96
- export function removeColumn(tr: Transaction, { map, table, tableStart }: Rect, col: number) {
97
- map = map as TableMap
98
- table = table as Node
99
- tableStart = tableStart as number
100
- const mapStart = tr.mapping.maps.length
101
- for (let row = 0; row < map.height;) {
102
- const index = row * map.width + col
103
- const pos = map.map[index] as number
104
- const cell = table.nodeAt(pos) as Node
105
- // If this is part of a col-spanning cell
106
- if ((col > 0 && map.map[index - 1] == pos) || (col < map.width - 1 && map.map[index + 1] == pos)) {
107
- tr.setNodeMarkup(
108
- tr.mapping.slice(mapStart).map(tableStart + pos),
109
- null,
110
- removeColSpan(cell.attrs, col - map.colCount(pos)),
111
- )
112
- }
113
- else {
114
- const start = tr.mapping.slice(mapStart).map(tableStart + pos)
115
- tr.delete(start, start + cell.nodeSize)
116
- }
117
- row += cell.attrs.rowspan
118
- }
119
- }
120
-
121
- // :: (EditorState, dispatch: ?(tr: Transaction)) → bool
122
- // Command function that removes the selected columns from a table.
123
- export const deleteColumn: Command = (state, dispatch) => {
124
- if (!isInTable(state))
125
- return false
126
- if (dispatch) {
127
- const rect = selectedRect(state) as Required<Rect>
128
- const tr = state.tr
129
- if (rect.left == 0 && rect.right == rect.map.width)
130
- return false
131
- for (let i = rect.right - 1; ; i--) {
132
- removeColumn(tr, rect, i)
133
- if (i == rect.left)
134
- break
135
- rect.table = (rect.tableStart ? tr.doc.nodeAt(rect.tableStart - 1) : tr.doc) as Node
136
- rect.map = TableMap.get(rect.table)
137
- }
138
- dispatch(tr)
139
- }
140
- return true
141
- }
142
-
143
- export function rowIsHeader(map: TableMap, table: Node, row: number) {
144
- const headerCell = tableNodeTypes(table.type.schema).header_cell
145
- for (let col = 0; col < map.width; col++) {
146
- const offset = map.map[col + row * map.width] as number
147
- if ((table.nodeAt(offset) as Node).type != headerCell)
148
- return false
149
- }
150
- return true
151
- }
152
-
153
- export function addRow(tr: Transaction, { map, tableStart, table }: Rect, row: number) {
154
- map = map as TableMap
155
- table = table as Node
156
- tableStart = tableStart as number
157
- let rowPos = tableStart
158
- for (let i = 0; i < row; i++) rowPos += table.child(i).nodeSize
159
- const cells = []
160
- let refRow: number | null = row > 0 ? -1 : 0
161
- if (rowIsHeader(map, table, row + refRow))
162
- refRow = row == 0 || row == map.height ? null : 0
163
- for (let col = 0, index = map.width * row; col < map.width; col++, index++) {
164
- // Covered by a rowspan cell
165
- if (row > 0 && row < map.height && map.map[index] == map.map[index - map.width]) {
166
- const pos = map.map[index] as number
167
- const attrs = (table.nodeAt(pos) as Node).attrs
168
- tr.setNodeMarkup(tableStart + pos, null, setAttr(attrs, 'rowspan', attrs.rowspan + 1))
169
- col += attrs.colspan - 1
170
- }
171
- else {
172
- const type
173
- = refRow == null
174
- ? tableNodeTypes(table.type.schema).cell
175
- : (table.nodeAt(map.map[index + refRow * map.width] as number) as Node).type
176
- cells.push(type.createAndFill())
177
- }
178
- }
179
- tr.insert(rowPos, tableNodeTypes(table.type.schema).row.create(null, cells))
180
- return tr
181
- }
182
-
183
- // :: (EditorState, dispatch: ?(tr: Transaction)) → bool
184
- // Add a table row before the selection.
185
- export function addRowBefore(state: EditorState, dispatch?: (tr: Transaction) => boolean) {
186
- if (!isInTable(state))
187
- return false
188
- if (dispatch) {
189
- const rect = selectedRect(state)
190
- dispatch(addRow(state.tr, rect, rect.top))
191
- }
192
- return true
193
- }
194
-
195
- // :: (EditorState, dispatch: ?(tr: Transaction)) → bool
196
- // Add a table row after the selection.
197
- export function addRowAfter(state: EditorState, dispatch?: (tr: Transaction) => boolean) {
198
- if (!isInTable(state))
199
- return false
200
- if (dispatch) {
201
- const rect = selectedRect(state)
202
- dispatch(addRow(state.tr, rect, rect.bottom))
203
- }
204
- return true
205
- }
206
-
207
- export function removeRow(tr: Transaction, { map, tableStart, table }: Rect, row: number) {
208
- map = map as TableMap
209
- table = table as Node
210
- tableStart = tableStart as number
211
- let rowPos = 0
212
- for (let i = 0; i < row; i++) rowPos += table.child(i).nodeSize
213
- const nextRow = rowPos + table.child(row).nodeSize
214
-
215
- const mapFrom = tr.mapping.maps.length
216
- tr.delete(rowPos + tableStart, nextRow + tableStart)
217
-
218
- for (let col = 0, index = row * map.width; col < map.width; col++, index++) {
219
- const pos = map.map[index] as number
220
- if (row > 0 && pos == map.map[index - map.width]) {
221
- // If this cell starts in the row above, simply reduce its rowspan
222
- const attrs = (table.nodeAt(pos) as Node).attrs
223
- tr.setNodeMarkup(
224
- tr.mapping.slice(mapFrom).map(pos + tableStart),
225
- null,
226
- setAttr(attrs, 'rowspan', attrs.rowspan - 1),
227
- )
228
- col += attrs.colspan - 1
229
- }
230
- else if (row < map.width && pos == map.map[index + map.width]) {
231
- // Else, if it continues in the row below, it has to be moved down
232
- const cell = table.nodeAt(pos) as Node
233
- const copy = cell.type.create(setAttr(cell.attrs, 'rowspan', cell.attrs.rowspan - 1), cell.content)
234
- const newPos = map.positionAt(row + 1, col, table)
235
- tr.insert(tr.mapping.slice(mapFrom).map(tableStart + newPos), copy)
236
- col += cell.attrs.colspan - 1
237
- }
238
- }
239
- }
240
-
241
- // :: (EditorState, dispatch: ?(tr: Transaction)) → bool
242
- // Remove the selected rows from a table.
243
- export const deleteRow: Command = (state, dispatch) => {
244
- if (!isInTable(state))
245
- return false
246
- if (dispatch) {
247
- const rect = selectedRect(state) as Required<Rect>
248
- const tr = state.tr
249
- if (rect.top == 0 && rect.bottom == rect.map.height)
250
- return false
251
- for (let i = rect.bottom - 1; ; i--) {
252
- removeRow(tr, rect, i)
253
- if (i == rect.top)
254
- break
255
- rect.table = rect.tableStart ? (tr.doc.nodeAt(rect.tableStart - 1) as Node) : tr.doc
256
- rect.map = TableMap.get(rect.table)
257
- }
258
- dispatch(tr)
259
- }
260
- return true
261
- }
262
-
263
- function isEmpty(cell: Node) {
264
- const c = cell.content
265
- return c.childCount == 1 && (c.firstChild as Node).isTextblock && (c.firstChild as Node).childCount == 0
266
- }
267
-
268
- function cellsOverlapRectangle({ width, height, map }: TableMap, rect: Rect) {
269
- let indexTop = rect.top * width + rect.left
270
- let indexLeft = indexTop
271
- let indexBottom = (rect.bottom - 1) * width + rect.left
272
- let indexRight = indexTop + (rect.right - rect.left - 1)
273
- for (let i = rect.top; i < rect.bottom; i++) {
274
- if (
275
- (rect.left > 0 && map[indexLeft] == map[indexLeft - 1])
276
- || (rect.right < width && map[indexRight] == map[indexRight + 1])
277
- )
278
- return true
279
- indexLeft += width
280
- indexRight += width
281
- }
282
- for (let i = rect.left; i < rect.right; i++) {
283
- if (
284
- (rect.top > 0 && map[indexTop] == map[indexTop - width])
285
- || (rect.bottom < height && map[indexBottom] == map[indexBottom + width])
286
- )
287
- return true
288
- indexTop++
289
- indexBottom++
290
- }
291
- return false
292
- }
293
-
294
- // :: (EditorState, dispatch: ?(tr: Transaction)) → bool
295
- // Merge the selected cells into a single cell. Only available when
296
- // the selected cells' outline forms a rectangle.
297
- export function mergeCells(state: EditorState, dispatch?: (tr: Transaction) => boolean) {
298
- const sel = state.selection
299
- if (!(sel instanceof CellSelection) || sel.$anchorCell.pos == sel.$headCell.pos)
300
- return false
301
- const rect = selectedRect(state) as Required<Rect>
302
- const { map } = rect
303
- if (cellsOverlapRectangle(map as TableMap, rect))
304
- return false
305
- if (dispatch) {
306
- const tr = state.tr
307
- const seen: Record<number, boolean> = {}
308
- let content = Fragment.empty
309
- let mergedPos
310
- let mergedCell
311
- for (let row = rect.top; row < rect.bottom; row++) {
312
- for (let col = rect.left; col < rect.right; col++) {
313
- const cellPos = map.map[row * map.width + col] as number
314
- const cell = rect.table.nodeAt(cellPos) as Node
315
- if (seen[cellPos])
316
- continue
317
- seen[cellPos] = true
318
- if (mergedPos == null) {
319
- mergedPos = cellPos
320
- mergedCell = cell
321
- }
322
- else {
323
- if (!isEmpty(cell))
324
- content = content.append(cell.content)
325
- const mapped = tr.mapping.map(cellPos + rect.tableStart)
326
- tr.delete(mapped, mapped + cell.nodeSize)
327
- }
328
- }
329
- }
330
- mergedCell = mergedCell as Node
331
- mergedPos = mergedPos as number
332
- tr.setNodeMarkup(
333
- mergedPos + rect.tableStart,
334
- null,
335
- setAttr(
336
- addColSpan(
337
- mergedCell.attrs,
338
- mergedCell.attrs.colspan,
339
- rect.right - rect.left - mergedCell.attrs.colspan,
340
- ),
341
- 'rowspan',
342
- rect.bottom - rect.top,
343
- ),
344
- )
345
- if (content.size) {
346
- const end = mergedPos + 1 + mergedCell.content.size
347
- const start = isEmpty(mergedCell) ? mergedPos + 1 : end
348
- tr.replaceWith(start + rect.tableStart, end + rect.tableStart, content)
349
- }
350
- tr.setSelection(new CellSelection(tr.doc.resolve(mergedPos + rect.tableStart)))
351
- dispatch(tr)
352
- }
353
- return true
354
- }
355
- // :: (EditorState, dispatch: ?(tr: Transaction)) → bool
356
- // Split a selected cell, whose rowpan or colspan is greater than one,
357
- // into smaller cells. Use the first cell type for the new cells.
358
- export function splitCell(state: EditorState, dispatch?: (tr: Transaction) => boolean) {
359
- const nodeTypes = tableNodeTypes(state.schema)
360
- return splitCellWithType(({ node }) => {
361
- return nodeTypes[node.type.spec.tableRole]
362
- })(state, dispatch)
363
- }
364
-
365
- // :: (getCellType: ({ row: number, col: number, node: Node}) → NodeType) → (EditorState, dispatch: ?(tr: Transaction)) → bool
366
- // Split a selected cell, whose rowpan or colspan is greater than one,
367
- // into smaller cells with the cell type (th, td) returned by getType function.
368
- export function splitCellWithType(getCellType: (pos: { row: number; col: number; node: Node }) => NodeType) {
369
- return (state: EditorState, dispatch?: (tr: Transaction) => boolean) => {
370
- const sel = state.selection
371
- let cellNode, cellPos
372
- if (!(sel instanceof CellSelection)) {
373
- cellNode = cellWrapping(sel.$from)
374
- if (!cellNode)
375
- return false
376
- cellPos = (cellAround(sel.$from) as ResolvedPos).pos
377
- }
378
- else {
379
- if (sel.$anchorCell.pos != sel.$headCell.pos)
380
- return false
381
- cellNode = sel.$anchorCell.nodeAfter as Node
382
- cellPos = sel.$anchorCell.pos
383
- }
384
- if (cellNode.attrs.colspan == 1 && cellNode.attrs.rowspan == 1)
385
- return false
386
-
387
- if (dispatch) {
388
- let baseAttrs = cellNode.attrs
389
- const attrs = []
390
- const colwidth = baseAttrs.colwidth
391
- if (baseAttrs.rowspan > 1)
392
- baseAttrs = setAttr(baseAttrs, 'rowspan', 1)
393
- if (baseAttrs.colspan > 1)
394
- baseAttrs = setAttr(baseAttrs, 'colspan', 1)
395
- const rect = selectedRect(state) as Required<Rect>
396
- const tr = state.tr
397
- for (let i = 0; i < rect.right - rect.left; i++) {
398
- attrs.push(
399
- colwidth
400
- ? setAttr(baseAttrs, 'colwidth', colwidth && colwidth[i] ? [colwidth[i]] : null)
401
- : baseAttrs,
402
- )
403
- }
404
- let lastCell
405
- for (let row = rect.top; row < rect.bottom; row++) {
406
- let pos = rect.map.positionAt(row, rect.left, rect.table)
407
- if (row == rect.top)
408
- pos += cellNode.nodeSize
409
- for (let col = rect.left, i = 0; col < rect.right; col++, i++) {
410
- if (col == rect.left && row == rect.top)
411
- continue
412
- tr.insert(
413
- (lastCell = tr.mapping.map(pos + rect.tableStart, 1)),
414
- getCellType({ node: cellNode, row, col }).createAndFill(attrs[i]) as Node,
415
- )
416
- }
417
- }
418
- tr.setNodeMarkup(cellPos, getCellType({ node: cellNode, row: rect.top, col: rect.left }), attrs[0])
419
- if (sel instanceof CellSelection) {
420
- let pos: ResolvedPos | undefined
421
- if (lastCell)
422
- pos = tr.doc.resolve(lastCell)
423
-
424
- tr.setSelection(new CellSelection(tr.doc.resolve(sel.$anchorCell.pos), pos))
425
- }
426
- dispatch(tr)
427
- }
428
- return true
429
- }
430
- }
431
-
432
- // :: (string, any) → (EditorState, dispatch: ?(tr: Transaction)) → bool
433
- // Returns a command that sets the given attribute to the given value,
434
- // and is only available when the currently selected cell doesn't
435
- // already have that attribute set to that value.
436
- export function setCellAttr<T>(name: string, value: T): Command {
437
- return (state, dispatch) => {
438
- if (!isInTable(state))
439
- return false
440
- const $cell = selectionCell(state) as ResolvedPos
441
- if (($cell.nodeAfter as Node).attrs[name] === value)
442
- return false
443
- if (dispatch) {
444
- const tr = state.tr
445
- if (state.selection instanceof CellSelection) {
446
- state.selection.forEachCell((node, pos) => {
447
- if (node.attrs[name] !== value)
448
- tr.setNodeMarkup(pos, null, setAttr(node.attrs, name, value))
449
- })
450
- }
451
- else { tr.setNodeMarkup($cell.pos, null, setAttr(($cell.nodeAfter as Node).attrs, name, value)) }
452
- dispatch(tr)
453
- }
454
- return true
455
- }
456
- }
457
-
458
- function isHeaderEnabledByType(type: string, rect: Required<Rect>, types: Record<string, NodeSpec>) {
459
- // Get cell positions for first row or first column
460
- const cellPositions = rect.map.cellsInRect({
461
- left: 0,
462
- top: 0,
463
- right: type == 'row' ? rect.map.width : 1,
464
- bottom: type == 'column' ? rect.map.height : 1,
465
- })
466
-
467
- for (let i = 0; i < cellPositions.length; i++) {
468
- const cell = rect.table.nodeAt(cellPositions[i] as number)
469
- if (cell && cell.type !== types.header_cell)
470
- return false
471
- }
472
-
473
- return true
474
- }
475
-
476
- // Toggles between row/column header and normal cells (Only applies to first row/column).
477
- // For deprecated behavior pass `useDeprecatedLogic` in options with true.
478
- export function toggleHeader(type: string) {
479
- return function (state: EditorState, dispatch?: (tr: Transaction) => boolean) {
480
- if (!isInTable(state))
481
- return false
482
- if (dispatch) {
483
- const types = tableNodeTypes(state.schema)
484
- const rect = selectedRect(state)
485
- const tr = state.tr
486
-
487
- const isHeaderRowEnabled = isHeaderEnabledByType('row', rect, types)
488
- const isHeaderColumnEnabled = isHeaderEnabledByType('column', rect, types)
489
-
490
- const isHeaderEnabled
491
- = type === 'column' ? isHeaderRowEnabled : type === 'row' ? isHeaderColumnEnabled : false
492
-
493
- const selectionStartsAt = isHeaderEnabled ? 1 : 0
494
-
495
- const cellsRect
496
- = type == 'column'
497
- ? new Rect(0, selectionStartsAt, 1, rect.map.height)
498
- : type == 'row'
499
- ? new Rect(selectionStartsAt, 0, rect.map.width, 1)
500
- : rect
501
-
502
- const newType
503
- = type == 'column'
504
- ? isHeaderColumnEnabled
505
- ? types.cell
506
- : types.header_cell
507
- : type == 'row'
508
- ? isHeaderRowEnabled
509
- ? types.cell
510
- : types.header_cell
511
- : types.cell
512
-
513
- rect.map.cellsInRect(cellsRect).forEach((relativeCellPos) => {
514
- const cellPos = relativeCellPos + rect.tableStart
515
- const cell = tr.doc.nodeAt(cellPos)
516
-
517
- if (cell)
518
- tr.setNodeMarkup(cellPos, newType, cell.attrs)
519
- })
520
-
521
- dispatch(tr)
522
- }
523
- return true
524
- }
525
- }
526
-
527
- // :: (EditorState, dispatch: ?(tr: Transaction)) → bool
528
- // Toggles whether the selected row contains header cells.
529
- export const toggleHeaderRow = toggleHeader('row')
530
-
531
- // :: (EditorState, dispatch: ?(tr: Transaction)) → bool
532
- // Toggles whether the selected column contains header cells.
533
- export const toggleHeaderColumn = toggleHeader('column')
534
-
535
- // :: (EditorState, dispatch: ?(tr: Transaction)) → bool
536
- // Toggles whether the selected cells are header cells.
537
- export const toggleHeaderCell = toggleHeader('cell')
538
-
539
- function findNextCell($cell: ResolvedPos, dir: number) {
540
- if (dir < 0) {
541
- const before = $cell.nodeBefore
542
- if (before)
543
- return $cell.pos - before.nodeSize
544
- for (let row = $cell.index(-1) - 1, rowEnd = $cell.before(); row >= 0; row--) {
545
- const rowNode = $cell.node(-1).child(row)
546
- if (rowNode.childCount)
547
- return rowEnd - 1 - (rowNode.lastChild as Node).nodeSize
548
- rowEnd -= rowNode.nodeSize
549
- }
550
- }
551
- else {
552
- if ($cell.index() < $cell.parent.childCount - 1)
553
- return $cell.pos + ($cell.nodeAfter as Node).nodeSize
554
- const table = $cell.node(-1)
555
- for (let row = $cell.indexAfter(-1), rowStart = $cell.after(); row < table.childCount; row++) {
556
- const rowNode = table.child(row)
557
- if (rowNode.childCount)
558
- return rowStart + 1
559
- rowStart += rowNode.nodeSize
560
- }
561
- }
562
- return undefined
563
- }
564
-
565
- // Returns a command for selecting the next (direction=1) or previous
566
- // (direction=-1) cell in a table.
567
- export function goToNextCell(direction: number): Command {
568
- return (state, dispatch) => {
569
- if (!isInTable(state))
570
- return false
571
- const cell = findNextCell(selectionCell(state) as ResolvedPos, direction)
572
- if (cell == null)
573
- return false
574
- if (dispatch) {
575
- const $cell = state.doc.resolve(cell)
576
- dispatch(state.tr.setSelection(TextSelection.between($cell, moveCellForward($cell))).scrollIntoView())
577
- }
578
- return true
579
- }
580
- }
581
-
582
- // Deletes the table around the selection, if any.
583
- export const deleteTable: Command = (state, dispatch) => {
584
- const $pos = state.selection.$anchor
585
- for (let d = $pos.depth; d > 0; d--) {
586
- const node = $pos.node(d)
587
- if (node.type.spec.tableRole == 'table') {
588
- if (dispatch)
589
- dispatch(state.tr.delete($pos.before(d), $pos.after(d)).scrollIntoView())
590
- return true
591
- }
592
- }
593
- return false
594
- }