@nerd-bible/wordgard 0.5.3-beta7 → 0.6.2-beta10
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/dist/collab.js +3 -0
- package/dist/command.d.ts +15 -7
- package/dist/command.js +38 -18
- package/dist/doc.d.ts +58 -50
- package/dist/doc.js +224 -169
- package/dist/editor.d.ts +212 -111
- package/dist/editor.js +2263 -1767
- package/dist/highlight-code.d.ts +249 -0
- package/dist/highlight-code.js +264 -0
- package/dist/history.js +7 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/phrases.d.ts +3 -2
- package/dist/phrases.js +21 -1
- package/dist/schema.d.ts +37 -1
- package/dist/schema.js +164 -134
- package/dist/set.d.ts +3 -2
- package/dist/set.js +19 -13
- package/dist/state.d.ts +120 -29
- package/dist/state.js +224 -136
- package/dist/table.d.ts +114 -3
- package/dist/table.js +64 -36
- package/package.json +3 -2
package/dist/table.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as wordgard_state from 'wordgard/state';
|
|
2
2
|
import { GardState, GardSelection, Transaction } from 'wordgard/state';
|
|
3
3
|
import { Menu, Command } from 'wordgard/command';
|
|
4
|
-
import {
|
|
4
|
+
import { Plot, Slice, ChangeSet } from 'wordgard/doc';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
Enable table support with the given configuration. The returned
|
|
@@ -144,6 +144,7 @@ declare class CellSelection extends GardSelection {
|
|
|
144
144
|
readonly head: number;
|
|
145
145
|
readonly headSide: -1;
|
|
146
146
|
};
|
|
147
|
+
toSlice(doc: Plot.Doc): Slice;
|
|
147
148
|
eq(other: GardSelection): boolean;
|
|
148
149
|
map(changes: ChangeSet, cx: GardSelection.Context, assoc?: -1 | 1): GardSelection.Text | CellSelection;
|
|
149
150
|
/**
|
|
@@ -174,6 +175,116 @@ declare class CellSelection extends GardSelection {
|
|
|
174
175
|
static extension: GardState.Extension;
|
|
175
176
|
}
|
|
176
177
|
|
|
178
|
+
/**
|
|
179
|
+
A table map describes the structore of a given table.
|
|
180
|
+
*/
|
|
181
|
+
declare class TableMap {
|
|
182
|
+
/**
|
|
183
|
+
The start position of the table's content.
|
|
184
|
+
*/
|
|
185
|
+
readonly start: number;
|
|
186
|
+
/**
|
|
187
|
+
Get a table map for the given table node. Will reuse known
|
|
188
|
+
structure of unchanged tables across document changes.
|
|
189
|
+
*/
|
|
190
|
+
static get(table: Plot, start: number): TableMap;
|
|
191
|
+
private constructor();
|
|
192
|
+
/**
|
|
193
|
+
The number of columns in this table.
|
|
194
|
+
*/
|
|
195
|
+
get width(): number;
|
|
196
|
+
/**
|
|
197
|
+
The number of rows in the table.
|
|
198
|
+
*/
|
|
199
|
+
get height(): number;
|
|
200
|
+
/**
|
|
201
|
+
The table plot.
|
|
202
|
+
*/
|
|
203
|
+
get table(): Plot;
|
|
204
|
+
/**
|
|
205
|
+
The document position before the table.
|
|
206
|
+
*/
|
|
207
|
+
get tablePos(): number;
|
|
208
|
+
/**
|
|
209
|
+
Find the dimensions of the cell at the given position.
|
|
210
|
+
*/
|
|
211
|
+
cellRect(pos: number): TableMap.Rect;
|
|
212
|
+
/**
|
|
213
|
+
Find the end position of the given cell.
|
|
214
|
+
*/
|
|
215
|
+
cellEnd(pos: number): number;
|
|
216
|
+
/**
|
|
217
|
+
Get the rectangle spanning the two given cells.
|
|
218
|
+
*/
|
|
219
|
+
rectBetween(a: number, b: number): TableMap.Rect;
|
|
220
|
+
/**
|
|
221
|
+
Return the position of all cells that have their top start
|
|
222
|
+
corner in the given rectangle.
|
|
223
|
+
*/
|
|
224
|
+
cellsInRect(rect: TableMap.Rect): number[];
|
|
225
|
+
/**
|
|
226
|
+
Return the position of the cell that occupies the position at the
|
|
227
|
+
given row and column (which must be in bounds for the table).
|
|
228
|
+
*/
|
|
229
|
+
cellAt(col: number, row: number): number | null;
|
|
230
|
+
/**
|
|
231
|
+
Get the position at the start of the given row (which may be
|
|
232
|
+
`width` to query the position after the last row).
|
|
233
|
+
*/
|
|
234
|
+
rowPos(row: number): number;
|
|
235
|
+
/**
|
|
236
|
+
Get the position where a cell would have to be inserted to
|
|
237
|
+
appear at the given column and row.
|
|
238
|
+
*/
|
|
239
|
+
cellInsertionPos(col: number, row: number): number;
|
|
240
|
+
/**
|
|
241
|
+
Get the node for the cell at the given position.
|
|
242
|
+
*/
|
|
243
|
+
getCell(pos: number): Plot;
|
|
244
|
+
}
|
|
245
|
+
declare namespace TableMap {
|
|
246
|
+
/**
|
|
247
|
+
Data type used for a rectangular area in a table.
|
|
248
|
+
*/
|
|
249
|
+
class Rect {
|
|
250
|
+
/**
|
|
251
|
+
Starting column of the rectangle.
|
|
252
|
+
*/
|
|
253
|
+
readonly startCol: number;
|
|
254
|
+
/**
|
|
255
|
+
Starting row.
|
|
256
|
+
*/
|
|
257
|
+
readonly startRow: number;
|
|
258
|
+
/**
|
|
259
|
+
The end column. Non-inclusive. Always higher than
|
|
260
|
+
`startCol`.
|
|
261
|
+
*/
|
|
262
|
+
readonly endCol: number;
|
|
263
|
+
/**
|
|
264
|
+
The end row. Non-inclusive. Always higher than `startRow`.
|
|
265
|
+
*/
|
|
266
|
+
readonly endRow: number;
|
|
267
|
+
constructor(
|
|
268
|
+
/**
|
|
269
|
+
Starting column of the rectangle.
|
|
270
|
+
*/
|
|
271
|
+
startCol: number,
|
|
272
|
+
/**
|
|
273
|
+
Starting row.
|
|
274
|
+
*/
|
|
275
|
+
startRow: number,
|
|
276
|
+
/**
|
|
277
|
+
The end column. Non-inclusive. Always higher than
|
|
278
|
+
`startCol`.
|
|
279
|
+
*/
|
|
280
|
+
endCol: number,
|
|
281
|
+
/**
|
|
282
|
+
The end row. Non-inclusive. Always higher than `startRow`.
|
|
283
|
+
*/
|
|
284
|
+
endRow: number);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
177
288
|
declare const toggleHeaderCell: Command.Pure;
|
|
178
289
|
/**
|
|
179
290
|
Add a column at the given side of the selection. The selection may
|
|
@@ -210,6 +321,6 @@ declare const splitCell: Command.Pure;
|
|
|
210
321
|
/**
|
|
211
322
|
@hidden exported for testing
|
|
212
323
|
*/
|
|
213
|
-
declare function handleTablePaste(state: GardState, slice: Slice,
|
|
324
|
+
declare function handleTablePaste(state: GardState, slice: Slice, drop?: number): false | Transaction.Spec;
|
|
214
325
|
|
|
215
|
-
export { CellSelection, addColumn, addRow, deleteColumn, deleteRow, handleTablePaste, mergeCells, splitCell, tableMenu, tables, toggleHeaderCell };
|
|
326
|
+
export { CellSelection, TableMap, addColumn, addRow, deleteColumn, deleteRow, handleTablePaste, mergeCells, splitCell, tableMenu, tables, toggleHeaderCell };
|
package/dist/table.js
CHANGED
|
@@ -1,22 +1,10 @@
|
|
|
1
1
|
import { Decoration, Wordgard } from 'wordgard/editor';
|
|
2
2
|
import { GardState, Transaction, GardSelection, Correction } from 'wordgard/state';
|
|
3
3
|
import { Table, ColSpan, RowSpan, TableRow, Cell, BlockCell, HeaderCell, BlockHeaderCell } from 'wordgard/types';
|
|
4
|
-
import { Node, ValidationError, Token, ChangeSet } from 'wordgard/doc';
|
|
4
|
+
import { Node, Slice, ValidationError, Token, ChangeSet } from 'wordgard/doc';
|
|
5
5
|
import { Command, moveByUnit, moveByWord, moveByLine, moveToLineSide, Menu } from 'wordgard/command';
|
|
6
6
|
import { tablePhrases } from 'wordgard/phrases';
|
|
7
7
|
|
|
8
|
-
class Rect {
|
|
9
|
-
startCol;
|
|
10
|
-
startRow;
|
|
11
|
-
endCol;
|
|
12
|
-
endRow;
|
|
13
|
-
constructor(startCol, startRow, endCol, endRow) {
|
|
14
|
-
this.startCol = startCol;
|
|
15
|
-
this.startRow = startRow;
|
|
16
|
-
this.endCol = endCol;
|
|
17
|
-
this.endRow = endRow;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
8
|
class MapData {
|
|
21
9
|
table;
|
|
22
10
|
width;
|
|
@@ -37,7 +25,15 @@ let cache = /*@__PURE__*/(() => new WeakMap())();
|
|
|
37
25
|
class TableMap {
|
|
38
26
|
start;
|
|
39
27
|
data;
|
|
40
|
-
|
|
28
|
+
static get(table, start) {
|
|
29
|
+
let data = cache.get(table);
|
|
30
|
+
if (!data)
|
|
31
|
+
cache.set(table, data = computeMap(table));
|
|
32
|
+
return new TableMap(start, data);
|
|
33
|
+
}
|
|
34
|
+
constructor(
|
|
35
|
+
start,
|
|
36
|
+
data) {
|
|
41
37
|
this.start = start;
|
|
42
38
|
this.data = data;
|
|
43
39
|
}
|
|
@@ -55,7 +51,7 @@ class TableMap {
|
|
|
55
51
|
endCol++;
|
|
56
52
|
for (let j = 1; endRow < height && map[i + (width * j)] == localPos; j++)
|
|
57
53
|
endRow++;
|
|
58
|
-
return new Rect(startCol, startRow, endCol, endRow);
|
|
54
|
+
return new TableMap.Rect(startCol, startRow, endCol, endRow);
|
|
59
55
|
}
|
|
60
56
|
throw new RangeError(`No cell with offset ${pos} found`);
|
|
61
57
|
}
|
|
@@ -87,7 +83,7 @@ class TableMap {
|
|
|
87
83
|
rectBetween(a, b) {
|
|
88
84
|
let { startCol: startColA, endCol: endColA, startRow: startRowA, endRow: endRowA } = this.cellRect(a);
|
|
89
85
|
let { startCol: startColB, endCol: endColB, startRow: startRowB, endRow: endRowB } = this.cellRect(b);
|
|
90
|
-
return new Rect(Math.min(startColA, startColB), Math.min(startRowA, startRowB), Math.max(endColA, endColB), Math.max(endRowA, endRowB));
|
|
86
|
+
return new TableMap.Rect(Math.min(startColA, startColB), Math.min(startRowA, startRowB), Math.max(endColA, endColB), Math.max(endRowA, endRowB));
|
|
91
87
|
}
|
|
92
88
|
cellsInRect(rect) {
|
|
93
89
|
let result = [], { map, width } = this.data;
|
|
@@ -148,13 +144,26 @@ class TableMap {
|
|
|
148
144
|
}
|
|
149
145
|
return false;
|
|
150
146
|
}
|
|
151
|
-
static get(table, start) {
|
|
152
|
-
let data = cache.get(table);
|
|
153
|
-
if (!data)
|
|
154
|
-
cache.set(table, data = computeMap(table));
|
|
155
|
-
return new TableMap(start, data);
|
|
156
|
-
}
|
|
157
147
|
}
|
|
148
|
+
;TableMap = /*@__PURE__*/(function (TableMap) {
|
|
149
|
+
class Rect {
|
|
150
|
+
startCol;
|
|
151
|
+
startRow;
|
|
152
|
+
endCol;
|
|
153
|
+
endRow;
|
|
154
|
+
constructor(
|
|
155
|
+
startCol,
|
|
156
|
+
startRow,
|
|
157
|
+
endCol,
|
|
158
|
+
endRow) {
|
|
159
|
+
this.startCol = startCol;
|
|
160
|
+
this.startRow = startRow;
|
|
161
|
+
this.endCol = endCol;
|
|
162
|
+
this.endRow = endRow;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
TableMap.Rect = Rect;
|
|
166
|
+
;return TableMap})(TableMap);
|
|
158
167
|
function sameCell(a, b) {
|
|
159
168
|
return a != 0 && a == b;
|
|
160
169
|
}
|
|
@@ -227,6 +236,7 @@ function growMap(map, width, height, count) {
|
|
|
227
236
|
}
|
|
228
237
|
|
|
229
238
|
const cellSelectionDeco = /*@__PURE__*/GardState.Field.define({
|
|
239
|
+
name: "cellSelectionDeco",
|
|
230
240
|
create: getCellDeco,
|
|
231
241
|
update: (deco, tr) => {
|
|
232
242
|
return tr.docChanged || tr.selection ? getCellDeco(tr.state) : deco;
|
|
@@ -330,6 +340,24 @@ class CellSelection extends GardSelection {
|
|
|
330
340
|
let { from, to } = this.replacementRange;
|
|
331
341
|
return { anchor: from, anchorSide: 1, head: to, headSide: -1 };
|
|
332
342
|
}
|
|
343
|
+
toSlice(doc) {
|
|
344
|
+
let base = doc.resolve(this.anchorCell), table = base.parent.parent;
|
|
345
|
+
let map = TableMap.get(table.node, table.start);
|
|
346
|
+
let rect = map.rectBetween(this.anchorCell, this.headCell);
|
|
347
|
+
let rows = [], added = new Set();
|
|
348
|
+
for (let row = rect.startRow; row < rect.endRow; row++) {
|
|
349
|
+
let rowContent = [];
|
|
350
|
+
for (let col = rect.startCol; col < rect.endCol; col++) {
|
|
351
|
+
let cell = map.cellAt(col, row);
|
|
352
|
+
if (added.has(cell))
|
|
353
|
+
continue;
|
|
354
|
+
added.add(cell);
|
|
355
|
+
rowContent.push(map.getCell(cell));
|
|
356
|
+
}
|
|
357
|
+
rows.push(table.node.content[row].tag.create(rowContent));
|
|
358
|
+
}
|
|
359
|
+
return Slice.of(rows, [table.node.tag]);
|
|
360
|
+
}
|
|
333
361
|
eq(other) {
|
|
334
362
|
return other instanceof CellSelection && other.anchor == this.anchor && other.head == this.head;
|
|
335
363
|
}
|
|
@@ -768,7 +796,7 @@ const splitCell = ({ state }) => {
|
|
|
768
796
|
};
|
|
769
797
|
};
|
|
770
798
|
|
|
771
|
-
function fitSlice(schema, parent, slice
|
|
799
|
+
function fitSlice(schema, parent, slice) {
|
|
772
800
|
let wrap = schema.findWrapping(schema.docTag.type, parent.type);
|
|
773
801
|
if (!wrap)
|
|
774
802
|
return null;
|
|
@@ -776,7 +804,7 @@ function fitSlice(schema, parent, slice, context) {
|
|
|
776
804
|
for (let i = wrap.length - 1; i >= 0; i--)
|
|
777
805
|
content = [wrap[i].create(content)];
|
|
778
806
|
let doc = schema.doc(content);
|
|
779
|
-
let changes = ChangeSet.create(doc, { from: wrap.length + 1, to: doc.length - wrap.length - 1, insert: slice, fit:
|
|
807
|
+
let changes = ChangeSet.create(doc, { from: wrap.length + 1, to: doc.length - wrap.length - 1, insert: slice, fit: true });
|
|
780
808
|
doc = changes.apply(doc);
|
|
781
809
|
let node = doc.length > wrap.length && doc.plotAt(wrap.length);
|
|
782
810
|
return node && node.type == parent.type ? node : null;
|
|
@@ -784,15 +812,15 @@ function fitSlice(schema, parent, slice, context) {
|
|
|
784
812
|
function isTableContent(schema, type) {
|
|
785
813
|
return type == TableRow.type || schema.matchNode(type, Node.Group.TableCell);
|
|
786
814
|
}
|
|
787
|
-
function pastedCells(schema, slice
|
|
815
|
+
function pastedCells(schema, slice) {
|
|
788
816
|
let table = null, tok;
|
|
789
817
|
if (slice.content.length == 1 && (tok = slice.content[0]).tokenType == Token.Type.Node &&
|
|
790
818
|
tok.type == Table.type) {
|
|
791
819
|
table = tok;
|
|
792
820
|
}
|
|
793
|
-
else if (context.some(tag => isTableContent(schema, tag.type)) ||
|
|
821
|
+
else if (slice.context.some(tag => isTableContent(schema, tag.type)) ||
|
|
794
822
|
slice.content.some(tok => tok.tokenType != Token.Type.Close && isTableContent(schema, tok.type))) {
|
|
795
|
-
table = fitSlice(schema, Table, slice
|
|
823
|
+
table = fitSlice(schema, Table, slice);
|
|
796
824
|
}
|
|
797
825
|
return table && ensureRectangular(schema, table.content.map(row => row.content));
|
|
798
826
|
}
|
|
@@ -960,14 +988,14 @@ function insertCells(state, map, startCol, startRow, cells, event) {
|
|
|
960
988
|
userEvent: `${event}.paste`
|
|
961
989
|
};
|
|
962
990
|
}
|
|
963
|
-
function handleTablePaste(state, slice,
|
|
991
|
+
function handleTablePaste(state, slice, drop) {
|
|
964
992
|
if (state.readOnly)
|
|
965
993
|
return false;
|
|
966
994
|
let { schema } = state.doc;
|
|
967
995
|
if (drop == null && state.selection instanceof CellSelection) {
|
|
968
|
-
let cells = pastedCells(schema, slice
|
|
996
|
+
let cells = pastedCells(schema, slice);
|
|
969
997
|
if (!cells) {
|
|
970
|
-
let single = fitSlice(schema, cellTag(schema), slice
|
|
998
|
+
let single = fitSlice(schema, cellTag(schema), slice);
|
|
971
999
|
if (!single)
|
|
972
1000
|
return false;
|
|
973
1001
|
cells = { width: 1, height: 1, rows: [[single]] };
|
|
@@ -978,20 +1006,20 @@ function handleTablePaste(state, slice, context, drop) {
|
|
|
978
1006
|
}
|
|
979
1007
|
else {
|
|
980
1008
|
let cx = tableContext(state, drop), cells;
|
|
981
|
-
if (!cx || !(cells = pastedCells(schema, slice
|
|
1009
|
+
if (!cx || !(cells = pastedCells(schema, slice)))
|
|
982
1010
|
return false;
|
|
983
1011
|
let rect = cx.map.cellRect(cx.cells[0]);
|
|
984
1012
|
return insertCells(state, cx.map, rect.startCol, rect.startRow, cells, drop == null ? "drop" : "paste");
|
|
985
1013
|
}
|
|
986
1014
|
}
|
|
987
|
-
const tablePasteHandler = /*@__PURE__*/Wordgard.pasteHandler.of((wg, _event, slice
|
|
988
|
-
let tr = handleTablePaste(wg.state, slice
|
|
1015
|
+
const tablePasteHandler = /*@__PURE__*/Wordgard.pasteHandler.of((wg, _event, slice) => {
|
|
1016
|
+
let tr = handleTablePaste(wg.state, slice);
|
|
989
1017
|
return tr && (wg.dispatch(tr), true);
|
|
990
1018
|
});
|
|
991
|
-
const tableDropHandler = /*@__PURE__*/Wordgard.dropHandler.of((wg, _event, pos, move, slice
|
|
1019
|
+
const tableDropHandler = /*@__PURE__*/Wordgard.dropHandler.of((wg, _event, pos, move, slice) => {
|
|
992
1020
|
if (wg.state.readOnly)
|
|
993
1021
|
return false;
|
|
994
|
-
let tr = handleTablePaste(wg.state, slice,
|
|
1022
|
+
let tr = handleTablePaste(wg.state, slice, pos);
|
|
995
1023
|
if (!tr)
|
|
996
1024
|
return false;
|
|
997
1025
|
if (move) {
|
|
@@ -1300,4 +1328,4 @@ function tables(config = {}) {
|
|
|
1300
1328
|
tables.dropHandler = tableDropHandler;
|
|
1301
1329
|
;return tables})(tables);
|
|
1302
1330
|
|
|
1303
|
-
export { CellSelection, addColumn, addRow, deleteColumn, deleteRow, handleTablePaste, mergeCells, splitCell, tableMenu, tables, toggleHeaderCell };
|
|
1331
|
+
export { CellSelection, TableMap, addColumn, addRow, deleteColumn, deleteRow, handleTablePaste, mergeCells, splitCell, tableMenu, tables, toggleHeaderCell };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nerd-bible/wordgard",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.2-beta10",
|
|
4
4
|
"description": "Semantic rich text editor system",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -22,12 +22,13 @@
|
|
|
22
22
|
"author": "Marijn Haverbeke <marijn@haverbeke.berlin>",
|
|
23
23
|
"license": "MIT",
|
|
24
24
|
"dependencies": {
|
|
25
|
+
"@codemirror/legacy-modes": "^6.5.5",
|
|
26
|
+
"@codemirror/streamparser": "^6.0.0",
|
|
25
27
|
"@marijn/find-cluster-break": "^1.0.2",
|
|
26
28
|
"crelt": "^1.0.6",
|
|
27
29
|
"style-mod": "^4.1.3"
|
|
28
30
|
},
|
|
29
31
|
"devDependencies": {
|
|
30
|
-
"@nerd-bible/config": "^0.2.5",
|
|
31
32
|
"@swc/wasm-typescript": "^1.15.3",
|
|
32
33
|
"@types/mocha": "^10.0.10",
|
|
33
34
|
"@types/node": "^24.10.2",
|