@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/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 { ChangeSet, Plot, Slice } from 'wordgard/doc';
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, context: readonly Plot.Tag[], drop?: number): false | Transaction.Spec;
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
- constructor(start, data) {
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, context) {
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: context });
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, context) {
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, context);
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, context, drop) {
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, context);
996
+ let cells = pastedCells(schema, slice);
969
997
  if (!cells) {
970
- let single = fitSlice(schema, cellTag(schema), slice, context);
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, context)))
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, context) => {
988
- let tr = handleTablePaste(wg.state, slice, context);
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, context) => {
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, context, pos);
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.5.3-beta7",
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",