@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
@@ -1,322 +0,0 @@
1
- /* Copyright 2021, Milkdown by Mirone. */
2
-
3
- import type { Node, NodeType, Schema } from '@milkdown/prose/model'
4
- import { Fragment, Slice } from '@milkdown/prose/model'
5
- import type { EditorState, Transaction } from '@milkdown/prose/state'
6
- import { Transform } from '@milkdown/prose/transform'
7
-
8
- import { CellSelection } from './cell-selection'
9
- import { tableNodeTypes } from './schema'
10
- import type { Rect } from './table-map'
11
- import { TableMap } from './table-map'
12
- import { removeColSpan, setAttr } from './util'
13
-
14
- // Utilities to help with copying and pasting table cells
15
-
16
- // : (Slice) → ?{width: number, height: number, rows: [Fragment]}
17
- // Get a rectangular area of cells from a slice, or null if the outer
18
- // nodes of the slice aren't table cells or rows.
19
- export function pastedCells(slice: Slice) {
20
- if (!slice.size)
21
- return null
22
- let { content, openStart, openEnd } = slice
23
- while (
24
- content.childCount == 1
25
- && ((openStart > 0 && openEnd > 0) || (content.firstChild as Node).type.spec.tableRole == 'table')
26
- ) {
27
- openStart--
28
- openEnd--
29
- content = (content.firstChild as Node).content
30
- }
31
- const first = content.firstChild as Node
32
- const role = first.type.spec.tableRole
33
- const schema = first.type.schema
34
- const rows = []
35
- if (role == 'row') {
36
- for (let i = 0; i < content.childCount; i++) {
37
- let cells = content.child(i).content
38
- const left = i ? 0 : Math.max(0, openStart - 1)
39
- const right = i < content.childCount - 1 ? 0 : Math.max(0, openEnd - 1)
40
- if (left || right)
41
- cells = fitSlice(tableNodeTypes(schema).row, new Slice(cells, left, right)).content
42
- rows.push(cells)
43
- }
44
- }
45
- else if (role == 'cell' || role == 'header_cell') {
46
- rows.push(
47
- openStart || openEnd
48
- ? fitSlice(tableNodeTypes(schema).row, new Slice(content, openStart, openEnd)).content
49
- : content,
50
- )
51
- }
52
- else {
53
- return null
54
- }
55
- return ensureRectangular(schema, rows)
56
- }
57
-
58
- // : (Schema, [Fragment]) → {width: number, height: number, rows: [Fragment]}
59
- // Compute the width and height of a set of cells, and make sure each
60
- // row has the same number of cells.
61
- export interface R { width: number; height: number; rows: Fragment[] }
62
- function ensureRectangular(schema: Schema, rows: Fragment[]): R {
63
- const widths: number[] = []
64
- for (let i = 0; i < rows.length; i++) {
65
- const row = rows[i] as Fragment
66
- for (let j = row.childCount - 1; j >= 0; j--) {
67
- const { rowspan, colspan } = row.child(j).attrs
68
- for (let r = i; r < i + rowspan; r++) widths[r] = (widths[r] || 0) + colspan
69
- }
70
- }
71
- let width = 0
72
- for (let r = 0; r < widths.length; r++) width = Math.max(width, widths[r] as number)
73
- for (let r = 0; r < widths.length; r++) {
74
- if (r >= rows.length)
75
- rows.push(Fragment.empty)
76
- if ((widths[r] as number) < width) {
77
- const empty = tableNodeTypes(schema).cell.createAndFill()
78
- const cells = []
79
- for (let i = widths[r] as number; i < width; i++) cells.push(empty)
80
- rows[r] = (rows[r] as Fragment).append(Fragment.from(cells))
81
- }
82
- }
83
- return { height: rows.length, width, rows }
84
- }
85
-
86
- export function fitSlice(nodeType: NodeType, slice: Slice) {
87
- const node = nodeType.createAndFill() as Node
88
- const tr = new Transform(node).replace(0, node.content.size, slice)
89
- return tr.doc
90
- }
91
-
92
- // Clip or extend (repeat) the given set of cells to cover the given
93
- // width and height. Will clip rowspan/colspan cells at the edges when
94
- // they stick out.
95
- export function clipCells({ width, height, rows }: R, newWidth: number, newHeight: number): R {
96
- if (width != newWidth) {
97
- const added: number[] = []
98
- const newRows: Fragment[] = []
99
- for (let row = 0; row < rows.length; row++) {
100
- const frag = rows[row] as Fragment
101
- const cells = []
102
- for (let col = added[row] || 0, i = 0; col < newWidth; i++) {
103
- let cell = frag.child(i % frag.childCount)
104
- if (col + cell.attrs.colspan > newWidth) {
105
- cell = cell.type.create(
106
- removeColSpan(cell.attrs, cell.attrs.colspan, col + cell.attrs.colspan - newWidth),
107
- cell.content,
108
- )
109
- }
110
- cells.push(cell)
111
- col += cell.attrs.colspan
112
- for (let j = 1; j < cell.attrs.rowspan; j++)
113
- added[row + j] = (added[row + j] || 0) + cell.attrs.colspan
114
- }
115
- newRows.push(Fragment.from(cells))
116
- }
117
- rows = newRows
118
- width = newWidth
119
- }
120
-
121
- if (height != newHeight) {
122
- const newRows = []
123
- for (let row = 0, i = 0; row < newHeight; row++, i++) {
124
- const cells = []
125
- const source = rows[i % height] as Fragment
126
- for (let j = 0; j < source.childCount; j++) {
127
- let cell = source.child(j)
128
- if (row + cell.attrs.rowspan > newHeight) {
129
- cell = cell.type.create(
130
- setAttr(cell.attrs, 'rowspan', Math.max(1, newHeight - cell.attrs.rowspan)),
131
- cell.content,
132
- )
133
- }
134
- cells.push(cell)
135
- }
136
- newRows.push(Fragment.from(cells))
137
- }
138
- rows = newRows
139
- height = newHeight
140
- }
141
-
142
- return { width, height, rows }
143
- }
144
-
145
- // Make sure a table has at least the given width and height. Return
146
- // true if something was changed.
147
- function growTable(
148
- tr: Transaction,
149
- map: TableMap,
150
- table: Node,
151
- start: number,
152
- width: number,
153
- height: number,
154
- mapFrom: number,
155
- ) {
156
- const schema = tr.doc.type.schema
157
- const types = tableNodeTypes(schema)
158
- let empty, emptyHead
159
- if (width > map.width) {
160
- for (let row = 0, rowEnd = 0; row < map.height; row++) {
161
- const rowNode = table.child(row)
162
- rowEnd += rowNode.nodeSize
163
- const cells = []
164
- let add
165
- if (rowNode.lastChild == null || rowNode.lastChild.type == types.cell)
166
- add = empty || (empty = types.cell.createAndFill())
167
- else add = emptyHead || (emptyHead = types.header_cell.createAndFill())
168
- for (let i = map.width; i < width; i++) cells.push(add)
169
- tr.insert(tr.mapping.slice(mapFrom).map(rowEnd - 1 + start), cells)
170
- }
171
- }
172
- if (height > map.height) {
173
- const cells = []
174
- for (let i = 0, start = (map.height - 1) * map.width; i < Math.max(map.width, width); i++) {
175
- const header
176
- = i >= map.width ? false : (table.nodeAt(map.map[start + i] as number) as Node).type == types.header_cell
177
- cells.push(
178
- header
179
- ? emptyHead || (emptyHead = types.header_cell.createAndFill())
180
- : empty || (empty = types.cell.createAndFill()),
181
- )
182
- }
183
-
184
- const emptyRow = types.row.create(null, Fragment.from(cells))
185
- const rows = []
186
- for (let i = map.height; i < height; i++) rows.push(emptyRow)
187
- tr.insert(tr.mapping.slice(mapFrom).map(start + table.nodeSize - 2), rows)
188
- }
189
- return !!(empty || emptyHead)
190
- }
191
-
192
- // Make sure the given line (left, top) to (right, top) doesn't cross
193
- // any rowspan cells by splitting cells that cross it. Return true if
194
- // something changed.
195
- function isolateHorizontal(
196
- tr: Transaction,
197
- map: TableMap,
198
- table: Node,
199
- start: number,
200
- left: number,
201
- right: number,
202
- top: number,
203
- mapFrom: number,
204
- ) {
205
- if (top == 0 || top == map.height)
206
- return false
207
- let found = false
208
- for (let col = left; col < right; col++) {
209
- const index = top * map.width + col
210
- const pos = map.map[index] as number
211
- if (map.map[index - map.width] == pos) {
212
- found = true
213
- const cell = table.nodeAt(pos) as Node
214
- const { top: cellTop, left: cellLeft } = map.findCell(pos)
215
- tr.setNodeMarkup(
216
- tr.mapping.slice(mapFrom).map(pos + start),
217
- null,
218
- setAttr(cell.attrs, 'rowspan', top - cellTop),
219
- )
220
- tr.insert(
221
- tr.mapping.slice(mapFrom).map(map.positionAt(top, cellLeft, table)),
222
- cell.type.createAndFill(setAttr(cell.attrs, 'rowspan', cellTop + cell.attrs.rowspan - top)) as Node,
223
- )
224
- col += cell.attrs.colspan - 1
225
- }
226
- }
227
- return found
228
- }
229
-
230
- // Make sure the given line (left, top) to (left, bottom) doesn't
231
- // cross any colspan cells by splitting cells that cross it. Return
232
- // true if something changed.
233
- function isolateVertical(
234
- tr: Transaction,
235
- map: TableMap,
236
- table: Node,
237
- start: number,
238
- top: number,
239
- bottom: number,
240
- left: number,
241
- mapFrom: number,
242
- ) {
243
- if (left == 0 || left == map.width)
244
- return false
245
- let found = false
246
- for (let row = top; row < bottom; row++) {
247
- const index = row * map.width + left
248
- const pos = map.map[index] as number
249
- if (map.map[index - 1] == pos) {
250
- found = true
251
- const cell = table.nodeAt(pos) as Node
252
- const cellLeft = map.colCount(pos)
253
- const updatePos = tr.mapping.slice(mapFrom).map(pos + start)
254
- tr.setNodeMarkup(
255
- updatePos,
256
- null,
257
- removeColSpan(cell.attrs, left - cellLeft, cell.attrs.colspan - (left - cellLeft)),
258
- )
259
- tr.insert(
260
- updatePos + cell.nodeSize,
261
- cell.type.createAndFill(removeColSpan(cell.attrs, 0, left - cellLeft)) as Node,
262
- )
263
- row += cell.attrs.rowspan - 1
264
- }
265
- }
266
- return found
267
- }
268
-
269
- // Insert the given set of cells (as returned by `pastedCells`) into a
270
- // table, at the position pointed at by rect.
271
- export function insertCells(
272
- state: EditorState,
273
- dispatch: (tr: Transaction) => void,
274
- tableStart: number,
275
- rect: Rect,
276
- cells: R,
277
- ) {
278
- let table = (tableStart ? state.doc.nodeAt(tableStart - 1) : state.doc) as Node
279
- let map = TableMap.get(table)
280
- const { top, left } = rect
281
- const right = left + cells.width
282
- const bottom = top + cells.height
283
- const tr = state.tr
284
- let mapFrom = 0
285
- function recomp() {
286
- table = (tableStart ? tr.doc.nodeAt(tableStart - 1) : tr.doc) as Node
287
- map = TableMap.get(table)
288
- mapFrom = tr.mapping.maps.length
289
- }
290
- // Prepare the table to be large enough and not have any cells
291
- // crossing the boundaries of the rectangle that we want to
292
- // insert into. If anything about it changes, recompute the table
293
- // map so that subsequent operations can see the current shape.
294
- if (growTable(tr, map, table, tableStart, right, bottom, mapFrom))
295
- recomp()
296
- if (isolateHorizontal(tr, map, table, tableStart, left, right, top, mapFrom))
297
- recomp()
298
- if (isolateHorizontal(tr, map, table, tableStart, left, right, bottom, mapFrom))
299
- recomp()
300
- if (isolateVertical(tr, map, table, tableStart, top, bottom, left, mapFrom))
301
- recomp()
302
- if (isolateVertical(tr, map, table, tableStart, top, bottom, right, mapFrom))
303
- recomp()
304
-
305
- for (let row = top; row < bottom; row++) {
306
- const from = map.positionAt(row, left, table)
307
- const to = map.positionAt(row, right, table)
308
- tr.replace(
309
- tr.mapping.slice(mapFrom).map(from + tableStart),
310
- tr.mapping.slice(mapFrom).map(to + tableStart),
311
- new Slice(cells.rows[row - top] as Fragment, 0, 0),
312
- )
313
- }
314
- recomp()
315
- tr.setSelection(
316
- new CellSelection(
317
- tr.doc.resolve(tableStart + map.positionAt(top, left, table)),
318
- tr.doc.resolve(tableStart + map.positionAt(bottom - 1, right - 1, table)),
319
- ),
320
- )
321
- dispatch(tr)
322
- }
@@ -1,132 +0,0 @@
1
- /* Copyright 2021, Milkdown by Mirone. */
2
-
3
- import type { Node } from '@milkdown/prose/model'
4
- import type { EditorState, Transaction } from '@milkdown/prose/state'
5
- import { PluginKey } from '@milkdown/prose/state'
6
-
7
- import { tableNodeTypes } from './schema'
8
- import type { Problem } from './table-map'
9
- import { TableMap } from './table-map'
10
- import { removeColSpan, setAttr } from './util'
11
-
12
- export const fixTablesKey = new PluginKey('fix-tables')
13
-
14
- // Helper for iterating through the nodes in a document that changed
15
- // compared to the given previous document. Useful for avoiding
16
- // duplicate work on each transaction.
17
- function changedDescendants(old: Node, cur: Node, offset: number, f: (node: Node, pos: number) => void | boolean) {
18
- const oldSize = old.childCount
19
- const curSize = cur.childCount
20
- // eslint-disable-next-line no-restricted-syntax, no-labels
21
- outer: for (let i = 0, j = 0; i < curSize; i++) {
22
- const child = cur.child(i)
23
- for (let scan = j, e = Math.min(oldSize, i + 3); scan < e; scan++) {
24
- if (old.child(scan) == child) {
25
- j = scan + 1
26
- offset += child.nodeSize
27
- // eslint-disable-next-line no-labels
28
- continue outer
29
- }
30
- }
31
- f(child, offset)
32
- if (j < oldSize && old.child(j).sameMarkup(child))
33
- changedDescendants(old.child(j), child, offset + 1, f)
34
- else child.nodesBetween(0, child.content.size, f, offset + 1)
35
- offset += child.nodeSize
36
- }
37
- }
38
-
39
- // :: (EditorState, ?EditorState) → ?Transaction
40
- // Inspect all tables in the given state's document and return a
41
- // transaction that fixes them, if necessary. If `oldState` was
42
- // provided, that is assumed to hold a previous, known-good state,
43
- // which will be used to avoid re-scanning unchanged parts of the
44
- // document.
45
- export function fixTables(state: EditorState, oldState: EditorState) {
46
- let tr: undefined | Transaction
47
- const check = (node: Node, pos: number) => {
48
- if (node.type.spec.tableRole == 'table')
49
- tr = fixTable(state, node, pos, tr)
50
- }
51
- if (!oldState)
52
- state.doc.descendants(check)
53
- else if (oldState.doc != state.doc)
54
- changedDescendants(oldState.doc, state.doc, 0, check)
55
- return tr
56
- }
57
-
58
- // : (EditorState, Node, number, ?Transaction) → ?Transaction
59
- // Fix the given table, if necessary. Will append to the transaction
60
- // it was given, if non-null, or create a new one if necessary.
61
- export function fixTable(state: EditorState, table: Node, tablePos: number, tr?: Transaction) {
62
- const map = TableMap.get(table)
63
- if (!map.problems)
64
- return tr
65
- if (!tr)
66
- tr = state.tr
67
-
68
- // Track which rows we must add cells to, so that we can adjust that
69
- // when fixing collisions.
70
- const mustAdd = []
71
- for (let i = 0; i < map.height; i++) mustAdd.push(0)
72
- for (let i = 0; i < map.problems.length; i++) {
73
- const prob = map.problems[i] as Problem
74
- if (prob.type == 'collision') {
75
- const cell = table.nodeAt(prob.pos) as Node
76
- for (let j = 0; j < cell.attrs.rowspan; j++) mustAdd[prob.row + j] += prob.n
77
- tr.setNodeMarkup(
78
- tr.mapping.map(tablePos + 1 + prob.pos),
79
- null,
80
- removeColSpan(cell.attrs, cell.attrs.colspan - prob.n, prob.n),
81
- )
82
- }
83
- else if (prob.type == 'missing') {
84
- mustAdd[prob.row] += prob.n
85
- }
86
- else if (prob.type == 'overlong_rowspan') {
87
- const cell = table.nodeAt(prob.pos) as Node
88
- tr.setNodeMarkup(
89
- tr.mapping.map(tablePos + 1 + prob.pos),
90
- null,
91
- setAttr(cell.attrs, 'rowspan', cell.attrs.rowspan - prob.n),
92
- )
93
- }
94
- else if (prob.type == 'colwidth mismatch') {
95
- const cell = table.nodeAt(prob.pos) as Node
96
- tr.setNodeMarkup(
97
- tr.mapping.map(tablePos + 1 + prob.pos),
98
- null,
99
- setAttr(cell.attrs, 'colwidth', prob.colwidth),
100
- )
101
- }
102
- }
103
- let first, last
104
- for (let i = 0; i < mustAdd.length; i++) {
105
- if (mustAdd[i]) {
106
- if (first == null)
107
- first = i
108
- last = i
109
- }
110
- }
111
- // Add the necessary cells, using a heuristic for whether to add the
112
- // cells at the start or end of the rows (if it looks like a 'bite'
113
- // was taken out of the table, add cells at the start of the row
114
- // after the bite. Otherwise add them at the end).
115
- for (let i = 0, pos = tablePos + 1; i < map.height; i++) {
116
- const row = table.child(i)
117
- const end = pos + row.nodeSize
118
- const add = mustAdd[i] as number
119
- if (add > 0) {
120
- let tableNodeType = 'cell'
121
- if (row.firstChild)
122
- tableNodeType = row.firstChild.type.spec.tableRole
123
-
124
- const nodes = []
125
- for (let j = 0; j < add; j++) nodes.push(tableNodeTypes(state.schema)[tableNodeType].createAndFill())
126
- const side = (i == 0 || first == i - 1) && last == i ? pos + 1 : end - 1
127
- tr.insert(tr.mapping.map(side), nodes)
128
- }
129
- pos = end
130
- }
131
- return tr.setMeta(fixTablesKey, { fixTables: true })
132
- }
@@ -1,4 +0,0 @@
1
- /* Copyright 2021, Milkdown by Mirone. */
2
- export * from './cell-selection'
3
- export * from './commands'
4
- export * from './util'
@@ -1,120 +0,0 @@
1
- /* Copyright 2021, Milkdown by Mirone. */
2
- import type { Attrs, Node, NodeSpec, Schema } from '@milkdown/prose/model'
3
-
4
- import type { TableNodesOptions } from './types'
5
-
6
- function getCellAttrs(dom: HTMLElement, extraAttrs: Attrs) {
7
- const widthAttr = dom.getAttribute('data-colwidth')
8
- const widths = widthAttr && /^\d+(,\d+)*$/.test(widthAttr) ? widthAttr.split(',').map(s => Number(s)) : null
9
- const colspan = Number(dom.getAttribute('colspan') || 1)
10
- const result = {
11
- colspan,
12
- rowspan: Number(dom.getAttribute('rowspan') || 1),
13
- colwidth: widths && widths.length == colspan ? widths : null,
14
- }
15
- for (const prop in extraAttrs) {
16
- const getter = extraAttrs[prop].getFromDOM
17
- const value = getter && getter(dom)
18
- if (value != null)
19
- result[prop as keyof typeof result] = value
20
- }
21
- return result
22
- }
23
-
24
- function setCellAttrs(node: Node, extraAttrs: Attrs) {
25
- const attrs: Record<string, unknown> = {}
26
- if (node.attrs.colspan != 1)
27
- attrs.colspan = node.attrs.colspan
28
- if (node.attrs.rowspan != 1)
29
- attrs.rowspan = node.attrs.rowspan
30
- if (node.attrs.colwidth)
31
- attrs['data-colwidth'] = node.attrs.colwidth.join(',')
32
- for (const prop in extraAttrs) {
33
- const setter = extraAttrs[prop].setDOMAttr
34
- if (setter)
35
- setter(node.attrs[prop], attrs)
36
- }
37
- return attrs
38
- }
39
-
40
- function tableNodesSpecCreator(options: TableNodesOptions) {
41
- const extraAttrs: Attrs = options.cellAttributes || {}
42
- const cellAttrs: Record<string, unknown> = {
43
- colspan: { default: 1 },
44
- rowspan: { default: 1 },
45
- colwidth: { default: null },
46
- }
47
- for (const prop in extraAttrs) cellAttrs[prop] = { default: extraAttrs[prop].default }
48
- const finalAttrs = cellAttrs as Attrs
49
-
50
- const schema: Record<'table' | 'table_row' | 'table_cell' | 'table_header', NodeSpec> = {
51
- table: {
52
- content: 'table_row+',
53
- tableRole: 'table',
54
- isolating: true,
55
- group: options.tableGroup,
56
- parseDOM: [{ tag: 'table' }],
57
- toDOM() {
58
- return ['table', ['tbody', 0]]
59
- },
60
- },
61
- table_row: {
62
- content: '(table_cell | table_header)*',
63
- tableRole: 'row',
64
- parseDOM: [{ tag: 'tr' }],
65
- toDOM() {
66
- return ['tr', 0]
67
- },
68
- },
69
- table_cell: {
70
- content: options.cellContent,
71
- attrs: finalAttrs,
72
- tableRole: 'cell',
73
- isolating: true,
74
- parseDOM: [{ tag: 'td', getAttrs: dom => getCellAttrs(dom as HTMLElement, extraAttrs) }],
75
- toDOM(node) {
76
- return ['td', setCellAttrs(node, extraAttrs), 0]
77
- },
78
- },
79
- table_header: {
80
- content: options.cellContent,
81
- attrs: finalAttrs,
82
- tableRole: 'header_cell',
83
- isolating: true,
84
- parseDOM: [{ tag: 'th', getAttrs: dom => getCellAttrs(dom as HTMLElement, extraAttrs) }],
85
- toDOM(node) {
86
- return ['th', setCellAttrs(node, extraAttrs), 0]
87
- },
88
- },
89
- }
90
-
91
- return schema
92
- }
93
-
94
- export function tableNodeTypes(schema: Schema) {
95
- let result = schema.cached.tableNodeTypes
96
- if (!result) {
97
- result = schema.cached.tableNodeTypes = {}
98
- for (const name in schema.nodes) {
99
- const type = schema.nodes[name]
100
- const role = type?.spec.tableRole
101
- if (role)
102
- result[role] = type
103
- }
104
- }
105
- return result
106
- }
107
-
108
- export const schema = tableNodesSpecCreator({
109
- tableGroup: 'block',
110
- cellContent: 'paragraph',
111
- cellAttributes: {
112
- alignment: {
113
- default: 'left',
114
- getFromDOM: dom => (dom as HTMLElement).style.textAlign || 'left',
115
- setDOMAttr: (value, attrs) => {
116
- attrs.style = `text-align: ${value || 'left'}`
117
- },
118
- },
119
- },
120
- })