@milkdown/preset-gfm 7.4.0 → 7.5.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.
- package/lib/composed/commands.d.ts +5 -1
- package/lib/composed/commands.d.ts.map +1 -1
- package/lib/composed/schema.d.ts.map +1 -1
- package/lib/index.es.js +544 -481
- package/lib/index.es.js.map +1 -1
- package/lib/node/table/command.d.ts +33 -0
- package/lib/node/table/command.d.ts.map +1 -0
- package/lib/node/table/index.d.ts +3 -30
- package/lib/node/table/index.d.ts.map +1 -1
- package/lib/node/table/input.d.ts +3 -0
- package/lib/node/table/input.d.ts.map +1 -0
- package/lib/node/table/schema.d.ts +6 -0
- package/lib/node/table/schema.d.ts.map +1 -0
- package/lib/node/table/utils.d.ts +21 -7
- package/lib/node/table/utils.d.ts.map +1 -1
- package/lib/plugin/auto-insert-span-plugin.d.ts +2 -0
- package/lib/plugin/auto-insert-span-plugin.d.ts.map +1 -0
- package/lib/plugin/index.d.ts +2 -1
- package/lib/plugin/index.d.ts.map +1 -1
- package/lib/plugin/keep-table-align-plugin.d.ts +2 -0
- package/lib/plugin/keep-table-align-plugin.d.ts.map +1 -0
- package/lib/plugin/table-editing-plugin.d.ts.map +1 -1
- package/package.json +12 -17
- package/src/composed/commands.ts +2 -2
- package/src/composed/plugins.ts +4 -4
- package/src/composed/schema.ts +11 -1
- package/src/index.ts +1 -1
- package/src/node/table/command.ts +228 -0
- package/src/node/table/index.ts +3 -450
- package/src/node/table/input.ts +73 -0
- package/src/node/table/schema.ts +216 -0
- package/src/node/table/utils.ts +49 -18
- package/src/plugin/auto-insert-span-plugin.ts +12 -0
- package/src/plugin/index.ts +2 -1
- package/src/plugin/keep-table-align-plugin.ts +60 -0
- package/src/plugin/table-editing-plugin.ts +1 -1
- package/lib/plugin/auto-insert-zero-space-plugin.d.ts +0 -2
- package/lib/plugin/auto-insert-zero-space-plugin.d.ts.map +0 -1
- package/src/plugin/auto-insert-zero-space-plugin.ts +0 -55
package/src/node/table/index.ts
CHANGED
|
@@ -1,451 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { paragraphSchema } from '@milkdown/preset-commonmark'
|
|
4
|
-
import { InputRule } from '@milkdown/prose/inputrules'
|
|
5
|
-
import type { NodeType } from '@milkdown/prose/model'
|
|
6
|
-
import { Selection, TextSelection } from '@milkdown/prose/state'
|
|
7
|
-
import { CellSelection, addColumnAfter, addColumnBefore, deleteColumn, deleteRow, deleteTable, goToNextCell, isInTable, selectedRect, setCellAttr, tableNodes } from '@milkdown/prose/tables'
|
|
8
|
-
import { $command, $inputRule, $nodeSchema, $useKeymap } from '@milkdown/utils'
|
|
9
|
-
import { withMeta } from '../../__internal__'
|
|
10
|
-
import { addRowWithAlignment, createTable, moveCol, moveRow, selectCol, selectRow, selectTable } from './utils'
|
|
11
|
-
|
|
12
|
-
const originalSchema = tableNodes({
|
|
13
|
-
tableGroup: 'block',
|
|
14
|
-
cellContent: 'paragraph',
|
|
15
|
-
cellAttributes: {
|
|
16
|
-
alignment: {
|
|
17
|
-
default: 'left',
|
|
18
|
-
getFromDOM: dom => (dom).style.textAlign || 'left',
|
|
19
|
-
setDOMAttr: (value, attrs) => {
|
|
20
|
-
attrs.style = `text-align: ${value || 'left'}`
|
|
21
|
-
},
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
/// Schema for table node.
|
|
27
|
-
export const tableSchema = $nodeSchema('table', () => ({
|
|
28
|
-
...originalSchema.table,
|
|
29
|
-
parseMarkdown: {
|
|
30
|
-
match: node => node.type === 'table',
|
|
31
|
-
runner: (state, node, type) => {
|
|
32
|
-
const align = node.align as (string | null)[]
|
|
33
|
-
const children = (node.children as MarkdownNode[]).map((x, i) => ({
|
|
34
|
-
...x,
|
|
35
|
-
align,
|
|
36
|
-
isHeader: i === 0,
|
|
37
|
-
}))
|
|
38
|
-
state.openNode(type)
|
|
39
|
-
state.next(children)
|
|
40
|
-
state.closeNode()
|
|
41
|
-
},
|
|
42
|
-
},
|
|
43
|
-
toMarkdown: {
|
|
44
|
-
match: node => node.type.name === 'table',
|
|
45
|
-
runner: (state, node) => {
|
|
46
|
-
const firstLine = node.content.firstChild?.content
|
|
47
|
-
if (!firstLine)
|
|
48
|
-
return
|
|
49
|
-
|
|
50
|
-
const align: (string | null)[] = []
|
|
51
|
-
firstLine.forEach((cell) => {
|
|
52
|
-
align.push(cell.attrs.alignment)
|
|
53
|
-
})
|
|
54
|
-
state.openNode('table', undefined, { align })
|
|
55
|
-
state.next(node.content)
|
|
56
|
-
state.closeNode()
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
}))
|
|
60
|
-
|
|
61
|
-
withMeta(tableSchema.node, {
|
|
62
|
-
displayName: 'NodeSchema<table>',
|
|
63
|
-
group: 'Table',
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
withMeta(tableSchema.ctx, {
|
|
67
|
-
displayName: 'NodeSchemaCtx<table>',
|
|
68
|
-
group: 'Table',
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
/// Schema for table row node.
|
|
72
|
-
export const tableRowSchema = $nodeSchema('table_row', () => ({
|
|
73
|
-
...originalSchema.table_row,
|
|
74
|
-
parseMarkdown: {
|
|
75
|
-
match: node => node.type === 'tableRow',
|
|
76
|
-
runner: (state, node, type) => {
|
|
77
|
-
const align = node.align as (string | null)[]
|
|
78
|
-
const children = (node.children as MarkdownNode[]).map((x, i) => ({
|
|
79
|
-
...x,
|
|
80
|
-
align: align[i],
|
|
81
|
-
isHeader: node.isHeader,
|
|
82
|
-
}))
|
|
83
|
-
state.openNode(type)
|
|
84
|
-
state.next(children)
|
|
85
|
-
state.closeNode()
|
|
86
|
-
},
|
|
87
|
-
},
|
|
88
|
-
toMarkdown: {
|
|
89
|
-
match: node => node.type.name === 'table_row',
|
|
90
|
-
runner: (state, node) => {
|
|
91
|
-
state.openNode('tableRow')
|
|
92
|
-
state.next(node.content)
|
|
93
|
-
state.closeNode()
|
|
94
|
-
},
|
|
95
|
-
},
|
|
96
|
-
}))
|
|
97
|
-
|
|
98
|
-
withMeta(tableRowSchema.node, {
|
|
99
|
-
displayName: 'NodeSchema<tableRow>',
|
|
100
|
-
group: 'Table',
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
withMeta(tableRowSchema.ctx, {
|
|
104
|
-
displayName: 'NodeSchemaCtx<tableRow>',
|
|
105
|
-
group: 'Table',
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
/// Schema for table cell node.
|
|
109
|
-
export const tableCellSchema = $nodeSchema('table_cell', () => ({
|
|
110
|
-
...originalSchema.table_cell,
|
|
111
|
-
parseMarkdown: {
|
|
112
|
-
match: node => node.type === 'tableCell' && !node.isHeader,
|
|
113
|
-
runner: (state, node, type) => {
|
|
114
|
-
const align = node.align as string
|
|
115
|
-
state
|
|
116
|
-
.openNode(type, { alignment: align })
|
|
117
|
-
.openNode(state.schema.nodes.paragraph as NodeType)
|
|
118
|
-
.next(node.children)
|
|
119
|
-
.closeNode()
|
|
120
|
-
.closeNode()
|
|
121
|
-
},
|
|
122
|
-
},
|
|
123
|
-
toMarkdown: {
|
|
124
|
-
match: node => node.type.name === 'table_cell',
|
|
125
|
-
runner: (state, node) => {
|
|
126
|
-
state.openNode('tableCell').next(node.content).closeNode()
|
|
127
|
-
},
|
|
128
|
-
},
|
|
129
|
-
}))
|
|
130
|
-
|
|
131
|
-
withMeta(tableCellSchema.node, {
|
|
132
|
-
displayName: 'NodeSchema<tableCell>',
|
|
133
|
-
group: 'Table',
|
|
134
|
-
})
|
|
135
|
-
|
|
136
|
-
withMeta(tableCellSchema.ctx, {
|
|
137
|
-
displayName: 'NodeSchemaCtx<tableCell>',
|
|
138
|
-
group: 'Table',
|
|
139
|
-
})
|
|
140
|
-
|
|
141
|
-
/// Schema for table header node.
|
|
142
|
-
export const tableHeaderSchema = $nodeSchema('table_header', () => ({
|
|
143
|
-
...originalSchema.table_header,
|
|
144
|
-
parseMarkdown: {
|
|
145
|
-
match: node => node.type === 'tableCell' && !!node.isHeader,
|
|
146
|
-
runner: (state, node, type) => {
|
|
147
|
-
const align = node.align as string
|
|
148
|
-
state.openNode(type, { alignment: align })
|
|
149
|
-
state.openNode(state.schema.nodes.paragraph as NodeType)
|
|
150
|
-
state.next(node.children)
|
|
151
|
-
state.closeNode()
|
|
152
|
-
state.closeNode()
|
|
153
|
-
},
|
|
154
|
-
},
|
|
155
|
-
toMarkdown: {
|
|
156
|
-
match: node => node.type.name === 'table_header',
|
|
157
|
-
runner: (state, node) => {
|
|
158
|
-
state.openNode('tableCell')
|
|
159
|
-
state.next(node.content)
|
|
160
|
-
state.closeNode()
|
|
161
|
-
},
|
|
162
|
-
},
|
|
163
|
-
}))
|
|
164
|
-
|
|
165
|
-
withMeta(tableHeaderSchema.node, {
|
|
166
|
-
displayName: 'NodeSchema<tableHeader>',
|
|
167
|
-
group: 'Table',
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
withMeta(tableHeaderSchema.ctx, {
|
|
171
|
-
displayName: 'NodeSchemaCtx<tableHeader>',
|
|
172
|
-
group: 'Table',
|
|
173
|
-
})
|
|
174
|
-
|
|
175
|
-
/// A input rule for creating table.
|
|
176
|
-
/// For example, `|2x2|` will create a 2x2 table.
|
|
177
|
-
export const insertTableInputRule = $inputRule(ctx => new InputRule(
|
|
178
|
-
/^\|(?<col>\d+)[xX](?<row>\d+)\|\s$/,
|
|
179
|
-
(state, match, start, end) => {
|
|
180
|
-
const $start = state.doc.resolve(start)
|
|
181
|
-
if (!$start.node(-1).canReplaceWith($start.index(-1), $start.indexAfter(-1), tableSchema.type(ctx)))
|
|
182
|
-
return null
|
|
183
|
-
|
|
184
|
-
const tableNode = createTable(
|
|
185
|
-
ctx,
|
|
186
|
-
Number(match.groups?.row),
|
|
187
|
-
Number(match.groups?.col),
|
|
188
|
-
)
|
|
189
|
-
const tr = state.tr.replaceRangeWith(start, end, tableNode)
|
|
190
|
-
return tr.setSelection(TextSelection.create(tr.doc, start + 3)).scrollIntoView()
|
|
191
|
-
},
|
|
192
|
-
))
|
|
193
|
-
|
|
194
|
-
withMeta(insertTableInputRule, {
|
|
195
|
-
displayName: 'InputRule<insertTableInputRule>',
|
|
196
|
-
group: 'Table',
|
|
197
|
-
})
|
|
198
|
-
|
|
199
|
-
/// A command for moving cursor to previous cell.
|
|
200
|
-
export const goToPrevTableCellCommand = $command('GoToPrevTableCell', () => () => goToNextCell(-1))
|
|
201
|
-
|
|
202
|
-
withMeta(goToPrevTableCellCommand, {
|
|
203
|
-
displayName: 'Command<goToPrevTableCellCommand>',
|
|
204
|
-
group: 'Table',
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
/// A command for moving cursor to next cell.
|
|
208
|
-
export const goToNextTableCellCommand = $command('GoToNextTableCell', () => () => goToNextCell(1))
|
|
209
|
-
|
|
210
|
-
withMeta(goToNextTableCellCommand, {
|
|
211
|
-
displayName: 'Command<goToNextTableCellCommand>',
|
|
212
|
-
group: 'Table',
|
|
213
|
-
})
|
|
214
|
-
|
|
215
|
-
/// A command for splitting current table into two tables.
|
|
216
|
-
/// If the selection is at the end of the table,
|
|
217
|
-
/// it will just quit the table and insert a new paragraph node.
|
|
218
|
-
export const breakTableCommand = $command('BreakTable', ctx => () => (state, dispatch) => {
|
|
219
|
-
if (!isInTable(state))
|
|
220
|
-
return false
|
|
221
|
-
|
|
222
|
-
const { $head } = state.selection
|
|
223
|
-
const pos = $head.after()
|
|
224
|
-
const tr = state.tr
|
|
225
|
-
.replaceWith(pos, pos, paragraphSchema.type(ctx).createAndFill()!)
|
|
226
|
-
|
|
227
|
-
tr.setSelection(Selection.near(tr.doc.resolve(pos), 1)).scrollIntoView()
|
|
228
|
-
dispatch?.(tr)
|
|
229
|
-
return true
|
|
230
|
-
})
|
|
231
|
-
|
|
232
|
-
withMeta(breakTableCommand, {
|
|
233
|
-
displayName: 'Command<breakTableCommand>',
|
|
234
|
-
group: 'Table',
|
|
235
|
-
})
|
|
236
|
-
|
|
237
|
-
/// A command for inserting a table.
|
|
238
|
-
/// You can specify the number of rows and columns.
|
|
239
|
-
/// By default, it will insert a 3x3 table.
|
|
240
|
-
export const insertTableCommand = $command('InsertTable', ctx => ({ row, col }: { row?: number, col?: number } = {}) => (state, dispatch) => {
|
|
241
|
-
const { selection, tr } = state
|
|
242
|
-
const { from } = selection
|
|
243
|
-
const table = createTable(ctx, row, col)
|
|
244
|
-
const _tr = tr.replaceSelectionWith(table)
|
|
245
|
-
const sel = Selection.findFrom(_tr.doc.resolve(from), 1, true)
|
|
246
|
-
if (sel)
|
|
247
|
-
_tr.setSelection(sel)
|
|
248
|
-
|
|
249
|
-
dispatch?.(_tr)
|
|
250
|
-
|
|
251
|
-
return true
|
|
252
|
-
})
|
|
253
|
-
|
|
254
|
-
withMeta(insertTableCommand, {
|
|
255
|
-
displayName: 'Command<insertTableCommand>',
|
|
256
|
-
group: 'Table',
|
|
257
|
-
})
|
|
258
|
-
|
|
259
|
-
/// A command for moving a row in a table.
|
|
260
|
-
/// You should specify the `from` and `to` index.
|
|
261
|
-
export const moveRowCommand = $command('MoveRow', () => ({ from, to }: { from?: number, to?: number } = {}) => (state, dispatch) => {
|
|
262
|
-
const { tr } = state
|
|
263
|
-
const result = dispatch?.(moveRow(tr, from ?? 0, to ?? 0, true))
|
|
264
|
-
|
|
265
|
-
return Boolean(result)
|
|
266
|
-
})
|
|
267
|
-
|
|
268
|
-
withMeta(moveRowCommand, {
|
|
269
|
-
displayName: 'Command<moveRowCommand>',
|
|
270
|
-
group: 'Table',
|
|
271
|
-
})
|
|
272
|
-
|
|
273
|
-
/// A command for moving a column in a table.
|
|
274
|
-
/// You should specify the `from` and `to` index.
|
|
275
|
-
export const moveColCommand = $command('MoveCol', () => ({ from, to }: { from?: number, to?: number } = {}) => (state, dispatch) => {
|
|
276
|
-
const { tr } = state
|
|
277
|
-
const result = dispatch?.(moveCol(tr, from ?? 0, to ?? 0, true))
|
|
278
|
-
|
|
279
|
-
return Boolean(result)
|
|
280
|
-
})
|
|
281
|
-
|
|
282
|
-
withMeta(moveColCommand, {
|
|
283
|
-
displayName: 'Command<moveColCommand>',
|
|
284
|
-
group: 'Table',
|
|
285
|
-
})
|
|
286
|
-
|
|
287
|
-
/// A command for selecting a row.
|
|
288
|
-
export const selectRowCommand = $command<number, 'SelectRow'>('SelectRow', () => (index = 0) => (state, dispatch) => {
|
|
289
|
-
const { tr } = state
|
|
290
|
-
const result = dispatch?.(selectRow(index)(tr))
|
|
291
|
-
|
|
292
|
-
return Boolean(result)
|
|
293
|
-
})
|
|
294
|
-
|
|
295
|
-
withMeta(selectRowCommand, {
|
|
296
|
-
displayName: 'Command<selectRowCommand>',
|
|
297
|
-
group: 'Table',
|
|
298
|
-
})
|
|
299
|
-
|
|
300
|
-
/// A command for selecting a column.
|
|
301
|
-
export const selectColCommand = $command<number, 'SelectCol'>('SelectCol', () => (index = 0) => (state, dispatch) => {
|
|
302
|
-
const { tr } = state
|
|
303
|
-
const result = dispatch?.(selectCol(index)(tr))
|
|
304
|
-
|
|
305
|
-
return Boolean(result)
|
|
306
|
-
})
|
|
307
|
-
|
|
308
|
-
withMeta(selectColCommand, {
|
|
309
|
-
displayName: 'Command<selectColCommand>',
|
|
310
|
-
group: 'Table',
|
|
311
|
-
})
|
|
312
|
-
|
|
313
|
-
/// A command for selecting a table.
|
|
314
|
-
export const selectTableCommand = $command('SelectTable', () => () => (state, dispatch) => {
|
|
315
|
-
const { tr } = state
|
|
316
|
-
const result = dispatch?.(selectTable(tr))
|
|
317
|
-
|
|
318
|
-
return Boolean(result)
|
|
319
|
-
})
|
|
320
|
-
|
|
321
|
-
withMeta(selectTableCommand, {
|
|
322
|
-
displayName: 'Command<selectTableCommand>',
|
|
323
|
-
group: 'Table',
|
|
324
|
-
})
|
|
325
|
-
|
|
326
|
-
/// A command for deleting selected cells.
|
|
327
|
-
/// If the selection is a row or column, the row or column will be deleted.
|
|
328
|
-
/// If all cells are selected, the table will be deleted.
|
|
329
|
-
export const deleteSelectedCellsCommand = $command('DeleteSelectedCells', () => () => (state, dispatch) => {
|
|
330
|
-
const { selection } = state
|
|
331
|
-
if (!(selection instanceof CellSelection))
|
|
332
|
-
return false
|
|
333
|
-
|
|
334
|
-
const isRow = selection.isRowSelection()
|
|
335
|
-
const isCol = selection.isColSelection()
|
|
336
|
-
|
|
337
|
-
if (isRow && isCol)
|
|
338
|
-
return deleteTable(state, dispatch)
|
|
339
|
-
|
|
340
|
-
if (isCol)
|
|
341
|
-
return deleteColumn(state, dispatch)
|
|
342
|
-
|
|
343
|
-
else
|
|
344
|
-
return deleteRow(state, dispatch)
|
|
345
|
-
})
|
|
346
|
-
|
|
347
|
-
withMeta(deleteSelectedCellsCommand, {
|
|
348
|
-
displayName: 'Command<deleteSelectedCellsCommand>',
|
|
349
|
-
group: 'Table',
|
|
350
|
-
})
|
|
351
|
-
|
|
352
|
-
/// A command for adding a column before the current column.
|
|
353
|
-
export const addColBeforeCommand = $command('AddColBefore', () => () => addColumnBefore)
|
|
354
|
-
|
|
355
|
-
withMeta(addColBeforeCommand, {
|
|
356
|
-
displayName: 'Command<addColBeforeCommand>',
|
|
357
|
-
group: 'Table',
|
|
358
|
-
})
|
|
359
|
-
|
|
360
|
-
/// A command for adding a column after the current column.
|
|
361
|
-
export const addColAfterCommand = $command('AddColAfter', () => () => addColumnAfter)
|
|
362
|
-
|
|
363
|
-
withMeta(addColAfterCommand, {
|
|
364
|
-
displayName: 'Command<addColAfterCommand>',
|
|
365
|
-
group: 'Table',
|
|
366
|
-
})
|
|
367
|
-
|
|
368
|
-
/// A command for adding a row before the current row.
|
|
369
|
-
export const addRowBeforeCommand = $command('AddRowBefore', ctx => () => (state, dispatch) => {
|
|
370
|
-
if (!isInTable(state))
|
|
371
|
-
return false
|
|
372
|
-
if (dispatch) {
|
|
373
|
-
const rect = selectedRect(state)
|
|
374
|
-
dispatch(addRowWithAlignment(ctx, state.tr, rect, rect.top))
|
|
375
|
-
}
|
|
376
|
-
return true
|
|
377
|
-
})
|
|
378
|
-
|
|
379
|
-
withMeta(addRowBeforeCommand, {
|
|
380
|
-
displayName: 'Command<addRowBeforeCommand>',
|
|
381
|
-
group: 'Table',
|
|
382
|
-
})
|
|
383
|
-
|
|
384
|
-
/// A command for adding a row after the current row.
|
|
385
|
-
export const addRowAfterCommand = $command('AddRowAfter', ctx => () => (state, dispatch) => {
|
|
386
|
-
if (!isInTable(state))
|
|
387
|
-
return false
|
|
388
|
-
if (dispatch) {
|
|
389
|
-
const rect = selectedRect(state)
|
|
390
|
-
dispatch(addRowWithAlignment(ctx, state.tr, rect, rect.bottom))
|
|
391
|
-
}
|
|
392
|
-
return true
|
|
393
|
-
})
|
|
394
|
-
|
|
395
|
-
withMeta(addRowAfterCommand, {
|
|
396
|
-
displayName: 'Command<addRowAfterCommand>',
|
|
397
|
-
group: 'Table',
|
|
398
|
-
})
|
|
399
|
-
|
|
400
|
-
/// A command for setting alignment property for selected cells.
|
|
401
|
-
/// You can specify the alignment as `left`, `center`, or `right`.
|
|
402
|
-
/// It's `left` by default.
|
|
403
|
-
export const setAlignCommand = $command<'left' | 'center' | 'right', 'SetAlign'>('SetAlign', () => (alignment = 'left') => setCellAttr('alignment', alignment))
|
|
404
|
-
|
|
405
|
-
withMeta(setAlignCommand, {
|
|
406
|
-
displayName: 'Command<setAlignCommand>',
|
|
407
|
-
group: 'Table',
|
|
408
|
-
})
|
|
409
|
-
|
|
410
|
-
/// Keymap for table commands.
|
|
411
|
-
/// - `<Mod-]>`/`<Tab>`: Move to the next cell.
|
|
412
|
-
/// - `<Mod-[>`/`<Shift-Tab>`: Move to the previous cell.
|
|
413
|
-
/// - `<Mod-Enter>`: Exit the table, and break it if possible.
|
|
414
|
-
export const tableKeymap = $useKeymap('tableKeymap', {
|
|
415
|
-
NextCell: {
|
|
416
|
-
shortcuts: ['Mod-]', 'Tab'],
|
|
417
|
-
command: (ctx) => {
|
|
418
|
-
const commands = ctx.get(commandsCtx)
|
|
419
|
-
|
|
420
|
-
return () => commands.call(goToNextTableCellCommand.key)
|
|
421
|
-
},
|
|
422
|
-
},
|
|
423
|
-
PrevCell: {
|
|
424
|
-
shortcuts: ['Mod-[', 'Shift-Tab'],
|
|
425
|
-
command: (ctx) => {
|
|
426
|
-
const commands = ctx.get(commandsCtx)
|
|
427
|
-
|
|
428
|
-
return () => commands.call(goToPrevTableCellCommand.key)
|
|
429
|
-
},
|
|
430
|
-
},
|
|
431
|
-
ExitTable: {
|
|
432
|
-
shortcuts: ['Mod-Enter'],
|
|
433
|
-
command: (ctx) => {
|
|
434
|
-
const commands = ctx.get(commandsCtx)
|
|
435
|
-
|
|
436
|
-
return () => commands.call(breakTableCommand.key)
|
|
437
|
-
},
|
|
438
|
-
},
|
|
439
|
-
})
|
|
440
|
-
|
|
441
|
-
withMeta(tableKeymap.ctx, {
|
|
442
|
-
displayName: 'KeymapCtx<table>',
|
|
443
|
-
group: 'Table',
|
|
444
|
-
})
|
|
445
|
-
|
|
446
|
-
withMeta(tableKeymap.shortcuts, {
|
|
447
|
-
displayName: 'Keymap<table>',
|
|
448
|
-
group: 'Table',
|
|
449
|
-
})
|
|
450
|
-
|
|
1
|
+
export * from './schema'
|
|
2
|
+
export * from './command'
|
|
451
3
|
export * from './utils'
|
|
4
|
+
export * from './input'
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { commandsCtx } from '@milkdown/core'
|
|
2
|
+
import { InputRule } from '@milkdown/prose/inputrules'
|
|
3
|
+
import { TextSelection } from '@milkdown/prose/state'
|
|
4
|
+
import { $inputRule, $useKeymap } from '@milkdown/utils'
|
|
5
|
+
import { withMeta } from '../../__internal__'
|
|
6
|
+
import { createTable } from './utils'
|
|
7
|
+
import { tableSchema } from './schema'
|
|
8
|
+
import { exitTable, goToNextTableCellCommand, goToPrevTableCellCommand } from './command'
|
|
9
|
+
|
|
10
|
+
/// A input rule for creating table.
|
|
11
|
+
/// For example, `|2x2|` will create a 2x2 table.
|
|
12
|
+
export const insertTableInputRule = $inputRule(ctx => new InputRule(
|
|
13
|
+
/^\|(?<col>\d+)[xX](?<row>\d+)\|\s$/,
|
|
14
|
+
(state, match, start, end) => {
|
|
15
|
+
const $start = state.doc.resolve(start)
|
|
16
|
+
if (!$start.node(-1).canReplaceWith($start.index(-1), $start.indexAfter(-1), tableSchema.type(ctx)))
|
|
17
|
+
return null
|
|
18
|
+
|
|
19
|
+
const tableNode = createTable(
|
|
20
|
+
ctx,
|
|
21
|
+
Number(match.groups?.row),
|
|
22
|
+
Number(match.groups?.col),
|
|
23
|
+
)
|
|
24
|
+
const tr = state.tr.replaceRangeWith(start, end, tableNode)
|
|
25
|
+
return tr.setSelection(TextSelection.create(tr.doc, start + 3)).scrollIntoView()
|
|
26
|
+
},
|
|
27
|
+
))
|
|
28
|
+
|
|
29
|
+
withMeta(insertTableInputRule, {
|
|
30
|
+
displayName: 'InputRule<insertTableInputRule>',
|
|
31
|
+
group: 'Table',
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
/// Keymap for table commands.
|
|
35
|
+
/// - `<Mod-]>`/`<Tab>`: Move to the next cell.
|
|
36
|
+
/// - `<Mod-[>`/`<Shift-Tab>`: Move to the previous cell.
|
|
37
|
+
/// - `<Mod-Enter>`: Exit the table, and break it if possible.
|
|
38
|
+
export const tableKeymap = $useKeymap('tableKeymap', {
|
|
39
|
+
NextCell: {
|
|
40
|
+
shortcuts: ['Mod-]', 'Tab'],
|
|
41
|
+
command: (ctx) => {
|
|
42
|
+
const commands = ctx.get(commandsCtx)
|
|
43
|
+
|
|
44
|
+
return () => commands.call(goToNextTableCellCommand.key)
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
PrevCell: {
|
|
48
|
+
shortcuts: ['Mod-[', 'Shift-Tab'],
|
|
49
|
+
command: (ctx) => {
|
|
50
|
+
const commands = ctx.get(commandsCtx)
|
|
51
|
+
|
|
52
|
+
return () => commands.call(goToPrevTableCellCommand.key)
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
ExitTable: {
|
|
56
|
+
shortcuts: ['Mod-Enter'],
|
|
57
|
+
command: (ctx) => {
|
|
58
|
+
const commands = ctx.get(commandsCtx)
|
|
59
|
+
|
|
60
|
+
return () => commands.call(exitTable.key)
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
withMeta(tableKeymap.ctx, {
|
|
66
|
+
displayName: 'KeymapCtx<table>',
|
|
67
|
+
group: 'Table',
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
withMeta(tableKeymap.shortcuts, {
|
|
71
|
+
displayName: 'Keymap<table>',
|
|
72
|
+
group: 'Table',
|
|
73
|
+
})
|