@milkdown/preset-gfm 6.5.3 → 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 +18 -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,381 +0,0 @@
1
- /* Copyright 2021, Milkdown by Mirone. */
2
-
3
- import type { Node, ResolvedPos } from '@milkdown/prose/model'
4
- import { Fragment, Slice } from '@milkdown/prose/model'
5
- import type {
6
- EditorState,
7
- Transaction,
8
- } from '@milkdown/prose/state'
9
- import {
10
- NodeSelection,
11
- Selection,
12
- SelectionRange,
13
- TextSelection,
14
- } from '@milkdown/prose/state'
15
- import type { Mappable } from '@milkdown/prose/transform'
16
- import { Decoration, DecorationSet } from '@milkdown/prose/view'
17
-
18
- import { TableMap } from './table-map'
19
- import { inSameTable, pointsAtCell, removeColSpan, setAttr } from './util'
20
-
21
- // ::- A [`Selection`](http://prosemirror.net/docs/ref/#state.Selection)
22
- // subclass that represents a cell selection spanning part of a table.
23
- // With the plugin enabled, these will be created when the user
24
- // selects across cells, and will be drawn by giving selected cells a
25
- // `selectedCell` CSS class.
26
- export class CellSelection extends Selection {
27
- // :: (ResolvedPos, ?ResolvedPos)
28
- // A table selection is identified by its anchor and head cells. The
29
- // positions given to this constructor should point _before_ two
30
- // cells in the same table. They may be the same, to select a single
31
- // cell.
32
- constructor(public $anchorCell: ResolvedPos, public $headCell = $anchorCell) {
33
- const table = $anchorCell.node(-1)
34
- const map = TableMap.get(table)
35
- const start = $anchorCell.start(-1)
36
- const rect = map.rectBetween($anchorCell.pos - start, $headCell.pos - start)
37
- const doc = $anchorCell.node(0)
38
- const cells = map.cellsInRect(rect).filter(p => p != $headCell.pos - start)
39
- // Make the head cell the first range, so that it counts as the
40
- // primary part of the selection
41
- cells.unshift($headCell.pos - start)
42
- const ranges = cells.map((pos) => {
43
- const cell = table.nodeAt(pos) as Node
44
- const from = pos + start + 1
45
-
46
- return new (SelectionRange as any)(doc.resolve(from), doc.resolve(from + cell.content.size))
47
- })
48
- super(ranges[0].$from, ranges[0].$to, ranges)
49
- // :: ResolvedPos
50
- // A resolved position pointing _in front of_ the anchor cell (the one
51
- // that doesn't move when extending the selection).
52
- this.$anchorCell = $anchorCell
53
- // :: ResolvedPos
54
- // A resolved position pointing in front of the head cell (the one
55
- // moves when extending the selection).
56
- this.$headCell = $headCell
57
- }
58
-
59
- map(doc: Node, mapping: Mappable): Selection {
60
- const $anchorCell = doc.resolve(mapping.map(this.$anchorCell.pos))
61
- const $headCell = doc.resolve(mapping.map(this.$headCell.pos))
62
- if (pointsAtCell($anchorCell) && pointsAtCell($headCell) && inSameTable($anchorCell, $headCell)) {
63
- const tableChanged = this.$anchorCell.node(-1) != $anchorCell.node(-1)
64
- if (tableChanged && this.isRowSelection())
65
- return CellSelection.rowSelection($anchorCell, $headCell)
66
- else if (tableChanged && this.isColSelection())
67
- return CellSelection.colSelection($anchorCell, $headCell)
68
- else return new CellSelection($anchorCell, $headCell)
69
- }
70
- return TextSelection.between($anchorCell, $headCell)
71
- }
72
-
73
- // :: () → Slice
74
- // Returns a rectangular slice of table rows containing the selected
75
- // cells.
76
- override content(): Slice {
77
- const table = this.$anchorCell.node(-1)
78
- const map = TableMap.get(table)
79
- const start = this.$anchorCell.start(-1)
80
- const rect = map.rectBetween(this.$anchorCell.pos - start, this.$headCell.pos - start)
81
- const seen: Record<number, boolean> = {}
82
- const rows = []
83
- for (let row = rect.top; row < rect.bottom; row++) {
84
- const rowContent = []
85
- for (let index = row * map.width + rect.left, col = rect.left; col < rect.right; col++, index++) {
86
- const pos = map.map[index] as number
87
- if (!seen[pos]) {
88
- seen[pos] = true
89
- const cellRect = map.findCell(pos)
90
- let cell = table.nodeAt(pos) as Node
91
- const extraLeft = rect.left - cellRect.left
92
- const extraRight = cellRect.right - rect.right
93
- if (extraLeft > 0 || extraRight > 0) {
94
- let attrs = cell.attrs
95
- if (extraLeft > 0)
96
- attrs = removeColSpan(attrs, 0, extraLeft)
97
- if (extraRight > 0)
98
- attrs = removeColSpan(attrs, attrs.colspan - extraRight, extraRight)
99
- if (cellRect.left < rect.left)
100
- cell = cell.type.createAndFill(attrs) as Node
101
- else cell = cell.type.create(attrs, cell.content)
102
- }
103
- if (cellRect.top < rect.top || cellRect.bottom > rect.bottom) {
104
- const attrs = setAttr(
105
- cell.attrs,
106
- 'rowspan',
107
- Math.min(cellRect.bottom, rect.bottom) - Math.max(cellRect.top, rect.top),
108
- )
109
- if (cellRect.top < rect.top)
110
- cell = cell.type.createAndFill(attrs) as Node
111
- else cell = cell.type.create(attrs, cell.content)
112
- }
113
- rowContent.push(cell)
114
- }
115
- }
116
- rows.push(table.child(row).copy(Fragment.from(rowContent)))
117
- }
118
-
119
- const fragment = this.isColSelection() && this.isRowSelection() ? table : rows
120
- return new Slice(Fragment.from(fragment), 1, 1)
121
- }
122
-
123
- override replace(tr: Transaction, content = Slice.empty) {
124
- const mapFrom = tr.steps.length
125
- const ranges = this.ranges
126
- for (let i = 0; i < ranges.length; i++) {
127
- const { $from, $to } = ranges[i] as SelectionRange
128
- const mapping = tr.mapping.slice(mapFrom)
129
- tr.replace(mapping.map($from.pos), mapping.map($to.pos), i ? Slice.empty : content)
130
- }
131
- const sel = Selection.findFrom(tr.doc.resolve(tr.mapping.slice(mapFrom).map(this.to)), -1)
132
- if (sel)
133
- tr.setSelection(sel)
134
- }
135
-
136
- override replaceWith(tr: Transaction, node: Node) {
137
- this.replace(tr, new Slice(Fragment.from(node), 0, 0))
138
- }
139
-
140
- forEachCell(f: (node: Node, index: number) => void) {
141
- const table = this.$anchorCell.node(-1)
142
- const map = TableMap.get(table)
143
- const start = this.$anchorCell.start(-1)
144
- const cells = map.cellsInRect(map.rectBetween(this.$anchorCell.pos - start, this.$headCell.pos - start))
145
- for (let i = 0; i < cells.length; i++)
146
- f(table.nodeAt(cells[i] as number) as Node, start + (cells[i] as number))
147
- }
148
-
149
- // :: () → bool
150
- // True if this selection goes all the way from the top to the
151
- // bottom of the table.
152
- isColSelection() {
153
- const anchorTop = this.$anchorCell.index(-1)
154
- const headTop = this.$headCell.index(-1)
155
- if (Math.min(anchorTop, headTop) > 0)
156
- return false
157
- const anchorBot = anchorTop + (this.$anchorCell.nodeAfter as Node).attrs.rowspan
158
- const headBot = headTop + (this.$headCell.nodeAfter as Node).attrs.rowspan
159
- return Math.max(anchorBot, headBot) == this.$headCell.node(-1).childCount
160
- }
161
-
162
- // :: (ResolvedPos, ?ResolvedPos) → CellSelection
163
- // Returns the smallest column selection that covers the given anchor
164
- // and head cell.
165
- static colSelection($anchorCell: ResolvedPos, $headCell = $anchorCell) {
166
- const map = TableMap.get($anchorCell.node(-1))
167
- const start = $anchorCell.start(-1)
168
- const anchorRect = map.findCell($anchorCell.pos - start)
169
- const headRect = map.findCell($headCell.pos - start)
170
- const doc = $anchorCell.node(0)
171
- if (anchorRect.top <= headRect.top) {
172
- if (anchorRect.top > 0) {
173
- const left = map.map[anchorRect.left] as number
174
- $anchorCell = doc.resolve(start + left)
175
- }
176
- if (headRect.bottom < map.height) {
177
- const pos = map.map[map.width * (map.height - 1) + headRect.right - 1] as number
178
- $headCell = doc.resolve(start + pos)
179
- }
180
- }
181
- else {
182
- if (headRect.top > 0) {
183
- const left = map.map[anchorRect.left] as number
184
- $headCell = doc.resolve(start + left)
185
- }
186
- if (anchorRect.bottom < map.height) {
187
- const pos = map.map[map.width * (map.height - 1) + anchorRect.right - 1] as number
188
- $anchorCell = doc.resolve(start + pos)
189
- }
190
- }
191
- return new CellSelection($anchorCell, $headCell)
192
- }
193
-
194
- // :: () → bool
195
- // True if this selection goes all the way from the left to the
196
- // right of the table.
197
- isRowSelection() {
198
- const map = TableMap.get(this.$anchorCell.node(-1))
199
- const start = this.$anchorCell.start(-1)
200
- const anchorLeft = map.colCount(this.$anchorCell.pos - start)
201
- const headLeft = map.colCount(this.$headCell.pos - start)
202
- if (Math.min(anchorLeft, headLeft) > 0)
203
- return false
204
- const anchorRight = anchorLeft + (this.$anchorCell.nodeAfter as Node).attrs.colspan
205
- const headRight = headLeft + (this.$headCell.nodeAfter as Node).attrs.colspan
206
- return Math.max(anchorRight, headRight) == map.width
207
- }
208
-
209
- eq(other: Selection): boolean {
210
- return (
211
- other instanceof CellSelection
212
- && other.$anchorCell.pos == this.$anchorCell.pos
213
- && other.$headCell.pos == this.$headCell.pos
214
- )
215
- }
216
-
217
- // :: (ResolvedPos, ?ResolvedPos) → CellSelection
218
- // Returns the smallest row selection that covers the given anchor
219
- // and head cell.
220
- static rowSelection($anchorCell: ResolvedPos, $headCell = $anchorCell) {
221
- const map = TableMap.get($anchorCell.node(-1))
222
- const start = $anchorCell.start(-1)
223
- const anchorRect = map.findCell($anchorCell.pos - start)
224
- const headRect = map.findCell($headCell.pos - start)
225
- const doc = $anchorCell.node(0)
226
- if (anchorRect.left <= headRect.left) {
227
- if (anchorRect.left > 0) {
228
- const pos = map.map[anchorRect.top * map.width] as number
229
- $anchorCell = doc.resolve(start + pos)
230
- }
231
- if (headRect.right < map.width) {
232
- const pos = map.map[map.width * (headRect.top + 1) - 1] as number
233
- $headCell = doc.resolve(start + pos)
234
- }
235
- }
236
- else {
237
- if (headRect.left > 0) {
238
- const pos = map.map[headRect.top * map.width] as number
239
- $headCell = doc.resolve(start + pos)
240
- }
241
- if (anchorRect.right < map.width) {
242
- const pos = map.map[map.width * (anchorRect.top + 1) - 1] as number
243
-
244
- $anchorCell = doc.resolve(start + pos)
245
- }
246
- }
247
- return new CellSelection($anchorCell, $headCell)
248
- }
249
-
250
- toJSON() {
251
- return {
252
- type: 'cell',
253
- anchor: this.$anchorCell.pos,
254
- head: this.$headCell.pos,
255
- }
256
- }
257
-
258
- static override fromJSON(doc: Node, json: any) {
259
- return new CellSelection(doc.resolve(json.anchor), doc.resolve(json.head))
260
- }
261
-
262
- // :: (Node, number, ?number) → CellSelection
263
- static create(doc: Node, anchorCell: number, headCell = anchorCell) {
264
- return new CellSelection(doc.resolve(anchorCell), doc.resolve(headCell))
265
- }
266
-
267
- override getBookmark() {
268
- return new CellBookmark(this.$anchorCell.pos, this.$headCell.pos)
269
- }
270
- }
271
-
272
- CellSelection.prototype.visible = false
273
-
274
- Selection.jsonID('cell', CellSelection)
275
-
276
- class CellBookmark {
277
- constructor(public anchor: number, public head: number) {
278
- this.anchor = anchor
279
- this.head = head
280
- }
281
-
282
- map(mapping: Mappable) {
283
- return new CellBookmark(mapping.map(this.anchor), mapping.map(this.head))
284
- }
285
-
286
- resolve(doc: Node): Selection {
287
- const $anchorCell = doc.resolve(this.anchor)
288
- const $headCell = doc.resolve(this.head)
289
- if (
290
- $anchorCell.parent.type.spec.tableRole == 'row'
291
- && $headCell.parent.type.spec.tableRole == 'row'
292
- && $anchorCell.index() < $anchorCell.parent.childCount
293
- && $headCell.index() < $headCell.parent.childCount
294
- && inSameTable($anchorCell, $headCell)
295
- )
296
- return new CellSelection($anchorCell, $headCell)
297
- else return Selection.near($headCell, 1)
298
- }
299
- }
300
-
301
- export function drawCellSelection(state: EditorState) {
302
- if (!(state.selection instanceof CellSelection))
303
- return null
304
- const cells: Decoration[] = []
305
- state.selection.forEachCell((node, pos) => {
306
- cells.push(Decoration.node(pos, pos + node.nodeSize, { class: 'selectedCell' }))
307
- })
308
- return DecorationSet.create(state.doc, cells)
309
- }
310
-
311
- function isCellBoundarySelection({ $from, $to }: Selection) {
312
- if ($from.pos == $to.pos || $from.pos < $from.pos - 6)
313
- return false // Cheap elimination
314
- let afterFrom = $from.pos
315
- let beforeTo = $to.pos
316
- let depth = $from.depth
317
- for (; depth >= 0; depth--, afterFrom++) {
318
- if ($from.after(depth + 1) < $from.end(depth))
319
- break
320
- }
321
- for (let d = $to.depth; d >= 0; d--, beforeTo--) {
322
- if ($to.before(d + 1) > $to.start(d))
323
- break
324
- }
325
- return afterFrom == beforeTo && /row|table/.test($from.node(depth).type.spec.tableRole)
326
- }
327
-
328
- function isTextSelectionAcrossCells({ $from, $to }: Selection) {
329
- let fromCellBoundaryNode
330
- let toCellBoundaryNode
331
-
332
- for (let i = $from.depth; i > 0; i--) {
333
- const node = $from.node(i)
334
- if (node.type.spec.tableRole === 'cell' || node.type.spec.tableRole === 'header_cell') {
335
- fromCellBoundaryNode = node
336
- break
337
- }
338
- }
339
-
340
- for (let i = $to.depth; i > 0; i--) {
341
- const node = $to.node(i)
342
- if (node.type.spec.tableRole === 'cell' || node.type.spec.tableRole === 'header_cell') {
343
- toCellBoundaryNode = node
344
- break
345
- }
346
- }
347
-
348
- return fromCellBoundaryNode !== toCellBoundaryNode && $to.parentOffset === 0
349
- }
350
-
351
- export function normalizeSelection(state: EditorState, tr: Transaction | undefined, allowTableNodeSelection: boolean) {
352
- const sel = (tr || state).selection
353
- const doc = (tr || state).doc
354
- let normalize, role
355
- // eslint-disable-next-line no-cond-assign
356
- if (sel instanceof NodeSelection && (role = sel.node.type.spec.tableRole)) {
357
- if (role == 'cell' || role == 'header_cell') {
358
- normalize = CellSelection.create(doc, sel.from)
359
- }
360
- else if (role == 'row') {
361
- const $cell = doc.resolve(sel.from + 1)
362
- normalize = CellSelection.rowSelection($cell, $cell)
363
- }
364
- else if (!allowTableNodeSelection) {
365
- const map = TableMap.get(sel.node)
366
- const start = sel.from + 1
367
- const pos = map.map[map.width * map.height - 1] as number
368
- const lastCell = start + pos
369
- normalize = CellSelection.create(doc, start + 1, lastCell)
370
- }
371
- }
372
- else if (sel instanceof TextSelection && isCellBoundarySelection(sel)) {
373
- normalize = TextSelection.create(doc, sel.from)
374
- }
375
- else if (sel instanceof TextSelection && isTextSelectionAcrossCells(sel)) {
376
- normalize = TextSelection.create(doc, sel.$from.start(), sel.$from.end())
377
- }
378
- if (normalize)
379
- (tr || (tr = state.tr)).setSelection(normalize)
380
- return tr
381
- }
@@ -1,288 +0,0 @@
1
- /* Copyright 2021, Milkdown by Mirone. */
2
- import type { Attrs, Node } from '@milkdown/prose/model'
3
- import type { EditorState, Transaction } from '@milkdown/prose/state'
4
- import { Plugin, PluginKey } from '@milkdown/prose/state'
5
- import type { EditorView } from '@milkdown/prose/view'
6
- import { Decoration, DecorationSet } from '@milkdown/prose/view'
7
-
8
- import { tableNodeTypes } from './schema'
9
- import { TableMap } from './table-map'
10
- import { TableView, updateColumns } from './table-view'
11
- import { cellAround, pointsAtCell, setAttr } from './util'
12
-
13
- export const key = new PluginKey('tableColumnResizing')
14
-
15
- export function columnResizing({
16
- handleWidth = 5,
17
- cellMinWidth = 25,
18
- View = TableView,
19
- lastColumnResizable = true,
20
- } = {}) {
21
- const plugin = new Plugin({
22
- key,
23
- state: {
24
- init(this: Plugin, _, state) {
25
- this.spec.props!.nodeViews![tableNodeTypes(state.schema).table.name] = node =>
26
- new View(node, cellMinWidth)
27
- return new ResizeState(-1, false)
28
- },
29
- apply(tr, prev) {
30
- return prev.apply(tr)
31
- },
32
- },
33
- props: {
34
- attributes(state) {
35
- const pluginState = key.getState(state)
36
- return pluginState.activeHandle > -1 ? { class: 'resize-cursor' } : (undefined as unknown as Attrs)
37
- },
38
-
39
- handleDOMEvents: {
40
- mousemove(view, event) {
41
- if (!view.editable)
42
- return
43
- handleMouseMove(view, event as MouseEvent, handleWidth, lastColumnResizable)
44
- },
45
- mouseleave(view) {
46
- if (!view.editable)
47
- return
48
- handleMouseLeave(view)
49
- },
50
- mousedown(view, event) {
51
- if (!view.editable)
52
- return
53
- handleMouseDown(view, event as MouseEvent, cellMinWidth)
54
- },
55
- },
56
-
57
- decorations(state) {
58
- const pluginState = key.getState(state)
59
- if (pluginState.activeHandle > -1)
60
- return handleDecorations(state, pluginState.activeHandle)
61
-
62
- return null
63
- },
64
-
65
- nodeViews: {},
66
- },
67
- })
68
- return plugin
69
- }
70
-
71
- class ResizeState {
72
- constructor(public activeHandle: number, public dragging: null | boolean) {
73
- this.activeHandle = activeHandle
74
- this.dragging = dragging
75
- }
76
-
77
- apply(this: ResizeState, tr: Transaction) {
78
- // eslint-disable-next-line @typescript-eslint/no-this-alias
79
- let state = this
80
- const action = tr.getMeta(key)
81
- if (action && action.setHandle != null)
82
- return new ResizeState(action.setHandle, null)
83
- if (action && action.setDragging !== undefined)
84
- return new ResizeState(state.activeHandle, action.setDragging)
85
- if (state.activeHandle > -1 && tr.docChanged) {
86
- let handle = tr.mapping.map(state.activeHandle, -1)
87
- if (!pointsAtCell(tr.doc.resolve(handle)))
88
- handle = 0
89
- state = new ResizeState(handle, state.dragging)
90
- }
91
- return state
92
- }
93
- }
94
-
95
- function handleMouseMove(view: EditorView, event: MouseEvent, handleWidth: number, lastColumnResizable: boolean) {
96
- const pluginState = key.getState(view.state)
97
-
98
- if (!pluginState.dragging) {
99
- const target = domCellAround(event.target as Element)
100
- let cell = -1
101
- if (target) {
102
- const { left, right } = target.getBoundingClientRect()
103
- if (
104
- right - event.clientX <= handleWidth
105
- // hover on the right border of the cell, the `target` is the next cell
106
- || event.clientX === Math.floor(left)
107
- )
108
- cell = edgeCell(view, event, 'right')
109
- else if (event.clientX - left <= handleWidth)
110
- cell = edgeCell(view, event, 'left')
111
- }
112
-
113
- if (cell != pluginState.activeHandle) {
114
- if (!lastColumnResizable && cell !== -1) {
115
- const $cell = view.state.doc.resolve(cell)
116
- const table = $cell.node(-1)
117
- const map = TableMap.get(table)
118
- const start = $cell.start(-1)
119
-
120
- const col = map.colCount($cell.pos - start) + $cell.nodeAfter!.attrs.colspan - 1
121
-
122
- if (col == map.width - 1)
123
- return
124
- }
125
-
126
- updateHandle(view, cell)
127
- }
128
- }
129
- }
130
-
131
- function handleMouseLeave(view: EditorView) {
132
- const pluginState = key.getState(view.state)
133
- if (pluginState.activeHandle > -1 && !pluginState.dragging)
134
- updateHandle(view, -1)
135
- }
136
-
137
- function handleMouseDown(view: EditorView, event: MouseEvent, cellMinWidth: number) {
138
- const pluginState = key.getState(view.state)
139
- if (pluginState.activeHandle == -1 || pluginState.dragging)
140
- return false
141
-
142
- const cell = view.state.doc.nodeAt(pluginState.activeHandle) as Node
143
- const width = currentColWidth(view, pluginState.activeHandle, cell.attrs)
144
- view.dispatch(
145
- view.state.tr.setMeta(key, {
146
- setDragging: { startX: event.clientX, startWidth: width },
147
- }),
148
- )
149
-
150
- function finish(event: MouseEvent) {
151
- window.removeEventListener('mouseup', finish)
152
- window.removeEventListener('mousemove', move)
153
- const pluginState = key.getState(view.state)
154
- if (pluginState.dragging) {
155
- updateColumnWidth(view, pluginState.activeHandle, draggedWidth(pluginState.dragging, event, cellMinWidth))
156
- view.dispatch(view.state.tr.setMeta(key, { setDragging: null }))
157
- }
158
- }
159
- function move(event: MouseEvent) {
160
- if (!event.which)
161
- return finish(event)
162
- const pluginState = key.getState(view.state)
163
- const dragged = draggedWidth(pluginState.dragging, event, cellMinWidth)
164
- displayColumnWidth(view, pluginState.activeHandle, dragged, cellMinWidth)
165
- }
166
-
167
- window.addEventListener('mouseup', finish)
168
- window.addEventListener('mousemove', move)
169
- event.preventDefault()
170
- return true
171
- }
172
-
173
- function currentColWidth(view: EditorView, cellPos: number, { colspan, colwidth }: Attrs) {
174
- const width = colwidth && colwidth[colwidth.length - 1]
175
- if (width)
176
- return width
177
- const dom = view.domAtPos(cellPos)
178
- const node = dom.node.childNodes[dom.offset] as HTMLElement
179
- let domWidth = node.offsetWidth
180
- let parts = colspan
181
- if (colwidth) {
182
- for (let i = 0; i < colspan; i++) {
183
- if (colwidth[i]) {
184
- domWidth -= colwidth[i]
185
- parts--
186
- }
187
- }
188
- }
189
- return domWidth / parts
190
- }
191
-
192
- function domCellAround(target: Element | null) {
193
- while (target && target.nodeName != 'TD' && target.nodeName != 'TH')
194
- target = target.classList.contains('ProseMirror') ? null : (target.parentNode as Element)
195
- return target
196
- }
197
-
198
- function edgeCell(view: EditorView, event: MouseEvent, side: 'left' | 'right') {
199
- const found = view.posAtCoords({ left: event.clientX, top: event.clientY })
200
- if (!found)
201
- return -1
202
- const { pos } = found
203
- const $cell = cellAround(view.state.doc.resolve(pos))
204
- if (!$cell)
205
- return -1
206
- if (side == 'right')
207
- return $cell.pos
208
- const map = TableMap.get($cell.node(-1))
209
- const start = $cell.start(-1)
210
- const index = map.map.indexOf($cell.pos - start)
211
- return index % map.width == 0 ? -1 : start + (map.map[index - 1] as number)
212
- }
213
-
214
- function draggedWidth(dragging: { startX: number; startWidth: number }, event: MouseEvent, cellMinWidth: number) {
215
- const offset = event.clientX - dragging.startX
216
- return Math.max(cellMinWidth, dragging.startWidth + offset)
217
- }
218
-
219
- function updateHandle(view: EditorView, value: number) {
220
- view.dispatch(view.state.tr.setMeta(key, { setHandle: value }))
221
- }
222
-
223
- function updateColumnWidth(view: EditorView, cell: number, width: number) {
224
- const $cell = view.state.doc.resolve(cell)
225
- const table = $cell.node(-1)
226
- const map = TableMap.get(table)
227
- const start = $cell.start(-1)
228
- const col = map.colCount($cell.pos - start) + ($cell.nodeAfter as Node).attrs.colspan - 1
229
- const tr = view.state.tr
230
- for (let row = 0; row < map.height; row++) {
231
- const mapIndex = row * map.width + col
232
- // Rowspanning cell that has already been handled
233
- if (row && map.map[mapIndex] == map.map[mapIndex - map.width])
234
- continue
235
- const pos = map.map[mapIndex] as number
236
- const { attrs } = table.nodeAt(pos) as Node
237
- const index = attrs.colspan == 1 ? 0 : col - map.colCount(pos)
238
- if (attrs.colwidth && attrs.colwidth[index] == width)
239
- continue
240
- const colwidth = attrs.colwidth ? attrs.colwidth.slice() : zeroes(attrs.colspan)
241
- colwidth[index] = width
242
- tr.setNodeMarkup(start + pos, null, setAttr(attrs, 'colwidth', colwidth))
243
- }
244
- if (tr.docChanged)
245
- view.dispatch(tr)
246
- }
247
-
248
- function displayColumnWidth(view: EditorView, cell: number, width: number, cellMinWidth: number) {
249
- const $cell = view.state.doc.resolve(cell)
250
- const table = $cell.node(-1)
251
- const start = $cell.start(-1)
252
- const col = TableMap.get(table).colCount($cell.pos - start) + ($cell.nodeAfter as Node).attrs.colspan - 1
253
- let dom = view.domAtPos($cell.start(-1)).node as HTMLElement
254
- while (dom.nodeName != 'TABLE') dom = dom.parentNode as HTMLElement
255
- updateColumns(table, dom.firstChild as HTMLTableColElement, dom as HTMLTableElement, cellMinWidth, col, width)
256
- }
257
-
258
- function zeroes(n: number) {
259
- const result = []
260
- for (let i = 0; i < n; i++) result.push(0)
261
- return result
262
- }
263
-
264
- function handleDecorations(state: EditorState, cell: number) {
265
- const decorations = []
266
- const $cell = state.doc.resolve(cell)
267
- const table = $cell.node(-1)
268
- const map = TableMap.get(table)
269
- const start = $cell.start(-1)
270
- const col = map.colCount($cell.pos - start) + ($cell.nodeAfter as Node).attrs.colspan
271
- for (let row = 0; row < map.height; row++) {
272
- const index = col + row * map.width - 1
273
- // For positions that are have either a different cell or the end
274
- // of the table to their right, and either the top of the table or
275
- // a different cell above them, add a decoration
276
- if (
277
- (col == map.width || map.map[index] != map.map[index + 1])
278
- && (row == 0 || map.map[index - 1] != map.map[index - 1 - map.width])
279
- ) {
280
- const cellPos = map.map[index] as number
281
- const pos = start + cellPos + (table.nodeAt(cellPos) as Node).nodeSize - 1
282
- const dom = document.createElement('div')
283
- dom.className = 'column-resize-handle'
284
- decorations.push(Decoration.widget(pos, dom))
285
- }
286
- }
287
- return DecorationSet.create(state.doc, decorations)
288
- }