@nerd-bible/wordgard 0.6.2-beta1 → 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 +27 -8
- package/dist/doc.d.ts +13 -2
- package/dist/doc.js +93 -41
- package/dist/editor.d.ts +25 -10
- package/dist/editor.js +349 -205
- package/dist/history.js +7 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/phrases.js +1 -0
- package/dist/schema.js +11 -8
- package/dist/set.d.ts +3 -2
- package/dist/set.js +16 -11
- package/dist/state.d.ts +52 -7
- package/dist/state.js +92 -34
- package/dist/table.d.ts +111 -1
- package/dist/table.js +32 -22
- package/package.json +1 -1
package/dist/collab.js
CHANGED
|
@@ -37,6 +37,7 @@ class CollabState {
|
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
const collabConfig = /*@__PURE__*/GardState.Facet.define({
|
|
40
|
+
name: "collabConfig",
|
|
40
41
|
combine(configs) {
|
|
41
42
|
let combined = GardState.Facet.combineConfig(configs, {
|
|
42
43
|
startVersion: 0,
|
|
@@ -52,12 +53,14 @@ const collabConfig = /*@__PURE__*/GardState.Facet.define({
|
|
|
52
53
|
}
|
|
53
54
|
});
|
|
54
55
|
const collabReceive = /*@__PURE__*/Transaction.Effect.define({
|
|
56
|
+
name: "collabReceive",
|
|
55
57
|
map(state, changes) {
|
|
56
58
|
return changes.empty ? state
|
|
57
59
|
: new CollabState(state.version, state.syncedDoc, state.nextUpdate, addUpdate(state.openUpdate, changes));
|
|
58
60
|
}
|
|
59
61
|
});
|
|
60
62
|
const collabField = /*@__PURE__*/GardState.Field.define({
|
|
63
|
+
name: "collab",
|
|
61
64
|
create(state) {
|
|
62
65
|
return new CollabState(state.facet(collabConfig).startVersion, state.doc, null, null);
|
|
63
66
|
},
|
package/dist/command.d.ts
CHANGED
|
@@ -518,10 +518,10 @@ declare const enter: Command.Pure;
|
|
|
518
518
|
/**
|
|
519
519
|
Delete the selection, or the unit after or before the selection.
|
|
520
520
|
If that unit is the start or end of a textblock, this will try to
|
|
521
|
-
join that textblock to the next one. Otherwise, if
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
521
|
+
join that textblock to the next one. Otherwise, if the cursor is
|
|
522
|
+
in an empty textblock, this will delete the textblock. Finally, if
|
|
523
|
+
there is a character or leaf node in the given direction, that is
|
|
524
|
+
deleted.
|
|
525
525
|
|
|
526
526
|
When deleting backward at the start of a list item that has a
|
|
527
527
|
sibling before it, this command will try to join those list items.
|
|
@@ -709,9 +709,17 @@ declare const redo: Command;
|
|
|
709
709
|
|
|
710
710
|
/**
|
|
711
711
|
If the cursor is in an empty textblock that can be lifted out of a
|
|
712
|
-
parent, return a transaction that does this.
|
|
712
|
+
parent, return a transaction that does this. Unless
|
|
713
|
+
`splitListItem` is set to false, if the block is part of a
|
|
714
|
+
continued list item, this function will split the item above the
|
|
715
|
+
block before it lifts it.
|
|
713
716
|
*/
|
|
714
|
-
declare function liftEmptyBlock(state: GardState): Transaction.Spec | false;
|
|
717
|
+
declare function liftEmptyBlock(state: GardState, splitListItem?: boolean): Transaction.Spec | false;
|
|
718
|
+
/**
|
|
719
|
+
Lift the textblock that the cursor is at the start of out of its
|
|
720
|
+
innermost parent, if possible.
|
|
721
|
+
*/
|
|
722
|
+
declare function liftTextblock(state: GardState): Transaction.Spec | false;
|
|
715
723
|
/**
|
|
716
724
|
If the selection is in a {@link Plot.Spec.preserveWhitespace
|
|
717
725
|
`preserveWhitespace`} textblock, replace the selected content with
|
|
@@ -823,4 +831,4 @@ updated to perform those joins.
|
|
|
823
831
|
*/
|
|
824
832
|
declare function autoJoinBlocks(state: GardState, tr: Transaction.Spec): Transaction.Spec;
|
|
825
833
|
|
|
826
|
-
export { Command, Menu, autoJoinBlocks, canAddMarkInRange, clearNonFitting, deleteBackward, deleteEmptyPlot, deleteForward, deleteLine, deleteSelection, deleteToLineEnd, deleteUnit, deleteWord, doUnwrapBlock, enter, enterInCode, findUnwrappable, findWrappable, insertLineBreak, insertText, joinBackward, joinBlocks, joinForward, joinListItems, killToLineEnd, liftEmptyBlock, listIsActive, moveByLine, moveByPage, moveByUnit, moveByWord, moveToDocSide, moveToLineSide, moveToTextblockSide, redo, selectAll, selectedTextblocks, setAlignment, setDirection, setTextblockType, splitTextblock, toggleBlock, toggleEmphasis, toggleList, toggleMark, toggleStrong, toggleUnderline, transposeChars, undo, unwrapBlock, wrapBlock, wrapBlockRange, yankKilled };
|
|
834
|
+
export { Command, Menu, autoJoinBlocks, canAddMarkInRange, clearNonFitting, deleteBackward, deleteEmptyPlot, deleteForward, deleteLine, deleteSelection, deleteToLineEnd, deleteUnit, deleteWord, doUnwrapBlock, enter, enterInCode, findUnwrappable, findWrappable, insertLineBreak, insertText, joinBackward, joinBlocks, joinForward, joinListItems, killToLineEnd, liftEmptyBlock, liftTextblock, listIsActive, moveByLine, moveByPage, moveByUnit, moveByWord, moveToDocSide, moveToLineSide, moveToTextblockSide, redo, selectAll, selectedTextblocks, setAlignment, setDirection, setTextblockType, splitTextblock, toggleBlock, toggleEmphasis, toggleList, toggleMark, toggleStrong, toggleUnderline, transposeChars, undo, unwrapBlock, wrapBlock, wrapBlockRange, yankKilled };
|
package/dist/command.js
CHANGED
|
@@ -5,6 +5,7 @@ import { findClusterBreak } from '@marijn/find-cluster-break';
|
|
|
5
5
|
import { Alignment, Direction, Emphasis, Strong, Underline } from 'wordgard/types';
|
|
6
6
|
|
|
7
7
|
const commandHandler = /*@__PURE__*/GardState.Facet.define({
|
|
8
|
+
name: "commandHandler",
|
|
8
9
|
combine(handlers) {
|
|
9
10
|
let map = new Map();
|
|
10
11
|
for (let [cmd, handler] of handlers) {
|
|
@@ -45,12 +46,27 @@ const Command = /*@__PURE__*/(function (Command) {
|
|
|
45
46
|
Command.dispatch = dispatch;
|
|
46
47
|
;return Command})({});
|
|
47
48
|
|
|
48
|
-
function liftEmptyBlock(state) {
|
|
49
|
+
function liftEmptyBlock(state, splitListItem = true) {
|
|
49
50
|
if (!state.selection.isCursor)
|
|
50
51
|
return false;
|
|
51
52
|
let sel = state.sel, block = sel.head.textblockParent;
|
|
52
53
|
if (!block || !sel.head.isAtStart(block) || !sel.head.isAtEnd(block))
|
|
53
54
|
return false;
|
|
55
|
+
if (splitListItem && block.parent?.parent && block.index && block.parent.parent.node.type.hasRole(Node.Role.List))
|
|
56
|
+
return {
|
|
57
|
+
changes: { from: block.before, insert: [Plot.End, block.parent.node.tag] },
|
|
58
|
+
scrollIntoView: true,
|
|
59
|
+
userEvent: "split.list"
|
|
60
|
+
};
|
|
61
|
+
return liftBlock(state, block);
|
|
62
|
+
}
|
|
63
|
+
function liftTextblock(state) {
|
|
64
|
+
if (!state.selection.isCursor)
|
|
65
|
+
return false;
|
|
66
|
+
let { head } = state.sel, block = head.textblockParent;
|
|
67
|
+
return !block || !head.isAtStart(block) ? false : liftBlock(state, block);
|
|
68
|
+
}
|
|
69
|
+
function liftBlock(state, block) {
|
|
54
70
|
let start = block.before, end = block.after, before = [], after = [];
|
|
55
71
|
for (let level = block.parent, index = block.index, atStart = true, atEnd = true, first = true; level; first = false, index = level.index, level = level.parent) {
|
|
56
72
|
if (!first && state.schema.canContain(level.node.type, block.node.type))
|
|
@@ -60,7 +76,7 @@ function liftEmptyBlock(state) {
|
|
|
60
76
|
{ from: block.after, to: end, insert: after }
|
|
61
77
|
],
|
|
62
78
|
scrollIntoView: true,
|
|
63
|
-
userEvent: "unwrap
|
|
79
|
+
userEvent: "unwrap"
|
|
64
80
|
};
|
|
65
81
|
if (level.node.isInline || level.node.type.isolating)
|
|
66
82
|
break;
|
|
@@ -740,7 +756,7 @@ const insertText = ({ state }, { from, to, insert, userEvent }) => {
|
|
|
740
756
|
let marks = (from == selection.from && to == selection.to && state.sel.activeMarks) ||
|
|
741
757
|
state.doc.resolve(from).marks(state.doc.resolve(to));
|
|
742
758
|
return {
|
|
743
|
-
changes: { from, to, insert: [Leaf.
|
|
759
|
+
changes: { from, to, insert: insert ? [Leaf.text(insert, marks)] : undefined, fit: true },
|
|
744
760
|
scrollIntoView: true,
|
|
745
761
|
selection: (cx, changes) => GardSelection.near(cx, changes.mapPos(to, 1), -1),
|
|
746
762
|
userEvent
|
|
@@ -792,8 +808,8 @@ const deleteUnit = ({ state }, dir) => {
|
|
|
792
808
|
if (state.readOnly)
|
|
793
809
|
return false;
|
|
794
810
|
return deleteSelection(state) || (dir == "forward"
|
|
795
|
-
? joinForward(state) ||
|
|
796
|
-
: joinListItems(state) ||
|
|
811
|
+
? joinForward(state) || deleteEmptyPlot(state, 1) || deleteForward(state)
|
|
812
|
+
: joinListItems(state) || liftTextblock(state) || joinBackward(state) || deleteEmptyPlot(state, -1) || deleteBackward(state));
|
|
797
813
|
};
|
|
798
814
|
const deleteWord = ({ state }, dir) => {
|
|
799
815
|
if (state.readOnly)
|
|
@@ -819,8 +835,9 @@ const deleteToLineEnd = (wg, dir) => {
|
|
|
819
835
|
userEvent: "delete." + dir
|
|
820
836
|
};
|
|
821
837
|
};
|
|
822
|
-
const addToKillBuffer = /*@__PURE__*/Transaction.Effect.define();
|
|
838
|
+
const addToKillBuffer = /*@__PURE__*/Transaction.Effect.define({ name: "addToKillBuffer" });
|
|
823
839
|
const killBuffer = /*@__PURE__*/GardState.Field.define({
|
|
840
|
+
name: "killBuffer",
|
|
824
841
|
create() { return { content: [], active: false }; },
|
|
825
842
|
update(value, tr) {
|
|
826
843
|
let add = tr.effects.find(e => e.is(addToKillBuffer));
|
|
@@ -1303,9 +1320,10 @@ const Menu = /*@__PURE__*/(function (Menu) {
|
|
|
1303
1320
|
let src = Menu.Item.source.of(this);
|
|
1304
1321
|
this.extension = this.parent ? [src, this.parent] : src;
|
|
1305
1322
|
}
|
|
1323
|
+
toString() { return "Menu.Item"; }
|
|
1306
1324
|
}
|
|
1307
1325
|
Item.Base = Base;
|
|
1308
|
-
Item.source = GardState.Facet.define();
|
|
1326
|
+
Item.source = GardState.Facet.define({ name: "menuItem" });
|
|
1309
1327
|
})(Item = Menu.Item || (Menu.Item = {}));
|
|
1310
1328
|
class Button extends Item.Base {
|
|
1311
1329
|
spec;
|
|
@@ -1380,6 +1398,7 @@ const Menu = /*@__PURE__*/(function (Menu) {
|
|
|
1380
1398
|
template(...content) {
|
|
1381
1399
|
return Template.new(this, content.length ? content : ["..."]);
|
|
1382
1400
|
}
|
|
1401
|
+
toString() { return "Menu.Group"; }
|
|
1383
1402
|
}
|
|
1384
1403
|
Menu.Group = Group;
|
|
1385
1404
|
(function (Group) {
|
|
@@ -1541,4 +1560,4 @@ const Menu = /*@__PURE__*/(function (Menu) {
|
|
|
1541
1560
|
Menu.resolve = resolve;
|
|
1542
1561
|
;return Menu})({});
|
|
1543
1562
|
|
|
1544
|
-
export { Command, Menu, autoJoinBlocks, canAddMarkInRange, clearNonFitting, deleteBackward, deleteEmptyPlot, deleteForward, deleteLine, deleteSelection, deleteToLineEnd, deleteUnit, deleteWord, doUnwrapBlock, enter, enterInCode, findUnwrappable, findWrappable, insertLineBreak, insertText, joinBackward, joinBlocks, joinForward, joinListItems, killToLineEnd, liftEmptyBlock, listIsActive, moveByLine, moveByPage, moveByUnit, moveByWord, moveToDocSide, moveToLineSide, moveToTextblockSide, redo, selectAll, selectedTextblocks, setAlignment, setDirection, setTextblockType, splitTextblock, toggleBlock, toggleEmphasis, toggleList, toggleMark, toggleStrong, toggleUnderline, transposeChars, undo, unwrapBlock, wrapBlock, wrapBlockRange, yankKilled };
|
|
1563
|
+
export { Command, Menu, autoJoinBlocks, canAddMarkInRange, clearNonFitting, deleteBackward, deleteEmptyPlot, deleteForward, deleteLine, deleteSelection, deleteToLineEnd, deleteUnit, deleteWord, doUnwrapBlock, enter, enterInCode, findUnwrappable, findWrappable, insertLineBreak, insertText, joinBackward, joinBlocks, joinForward, joinListItems, killToLineEnd, liftEmptyBlock, liftTextblock, listIsActive, moveByLine, moveByPage, moveByUnit, moveByWord, moveToDocSide, moveToLineSide, moveToTextblockSide, redo, selectAll, selectedTextblocks, setAlignment, setDirection, setTextblockType, splitTextblock, toggleBlock, toggleEmphasis, toggleList, toggleMark, toggleStrong, toggleUnderline, transposeChars, undo, unwrapBlock, wrapBlock, wrapBlockRange, yankKilled };
|
package/dist/doc.d.ts
CHANGED
|
@@ -1310,12 +1310,19 @@ declare namespace Node {
|
|
|
1310
1310
|
implies membership of its parent groups.
|
|
1311
1311
|
*/
|
|
1312
1312
|
readonly parent: Group | undefined;
|
|
1313
|
+
/**
|
|
1314
|
+
This group's debug name.
|
|
1315
|
+
*/
|
|
1316
|
+
readonly name: string | null;
|
|
1313
1317
|
private tag;
|
|
1314
1318
|
private constructor();
|
|
1315
1319
|
/**
|
|
1316
1320
|
Define a custom node group.
|
|
1317
1321
|
*/
|
|
1318
|
-
static define(
|
|
1322
|
+
static define(spec?: {
|
|
1323
|
+
parent?: Group;
|
|
1324
|
+
name?: string;
|
|
1325
|
+
}): Group;
|
|
1319
1326
|
/**
|
|
1320
1327
|
A group that contains every node type.
|
|
1321
1328
|
*/
|
|
@@ -1374,11 +1381,15 @@ declare namespace Node {
|
|
|
1374
1381
|
whether a given node has the role attached.
|
|
1375
1382
|
*/
|
|
1376
1383
|
class Role {
|
|
1384
|
+
/**
|
|
1385
|
+
This role's name.
|
|
1386
|
+
*/
|
|
1387
|
+
readonly name: string | null;
|
|
1377
1388
|
private constructor();
|
|
1378
1389
|
/**
|
|
1379
1390
|
Define a new role.
|
|
1380
1391
|
*/
|
|
1381
|
-
static define(): Role;
|
|
1392
|
+
static define(name?: string): Role;
|
|
1382
1393
|
/**
|
|
1383
1394
|
This role indicates that a plot contains code, and makes some
|
|
1384
1395
|
commands behave differently inside such a plot.
|
package/dist/doc.js
CHANGED
|
@@ -412,7 +412,7 @@ const Attributes = /*@__PURE__*/(function (Attributes) {
|
|
|
412
412
|
score--;
|
|
413
413
|
iA += 2;
|
|
414
414
|
}
|
|
415
|
-
else if (iB < b.length
|
|
415
|
+
else if (iB < b.length) {
|
|
416
416
|
score--;
|
|
417
417
|
iB += 2;
|
|
418
418
|
}
|
|
@@ -867,8 +867,8 @@ class Pos {
|
|
|
867
867
|
let d = this.depth;
|
|
868
868
|
if (depth > d)
|
|
869
869
|
throw new RangeError("Asking for parent deeper than position depth");
|
|
870
|
-
for (let
|
|
871
|
-
if (d == depth)
|
|
870
|
+
for (let p = this.parent;; p = p.parent)
|
|
871
|
+
if (d-- == depth)
|
|
872
872
|
return p;
|
|
873
873
|
}
|
|
874
874
|
isAtStart(parent) {
|
|
@@ -1093,6 +1093,7 @@ class BaseType {
|
|
|
1093
1093
|
get isBlock() { return (this.flags & 1) == 0; }
|
|
1094
1094
|
get isAtom() { return (this.flags & 4) > 0; }
|
|
1095
1095
|
get isSelectable() { return (this.flags & 32) > 0; }
|
|
1096
|
+
toString() { return this.name; }
|
|
1096
1097
|
}
|
|
1097
1098
|
class BaseTag {
|
|
1098
1099
|
param;
|
|
@@ -1131,29 +1132,48 @@ const Node = /*@__PURE__*/(function (Node) {
|
|
|
1131
1132
|
})(Node.Type || (Node.Type = {}));
|
|
1132
1133
|
class Group {
|
|
1133
1134
|
parent;
|
|
1135
|
+
name;
|
|
1134
1136
|
constructor(
|
|
1135
|
-
parent
|
|
1137
|
+
parent,
|
|
1138
|
+
name) {
|
|
1136
1139
|
this.parent = parent;
|
|
1140
|
+
this.name = name;
|
|
1137
1141
|
}
|
|
1138
|
-
static define(
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
static
|
|
1142
|
-
static
|
|
1143
|
-
static
|
|
1144
|
-
static
|
|
1145
|
-
static
|
|
1146
|
-
static
|
|
1147
|
-
static
|
|
1142
|
+
static define(spec = {}) {
|
|
1143
|
+
return new Group(spec.parent, spec.name || null);
|
|
1144
|
+
}
|
|
1145
|
+
static All = Group.define({ name: "All" });
|
|
1146
|
+
static Inline = Group.define({ name: "Inline" });
|
|
1147
|
+
static Block = Group.define({ name: "Block" });
|
|
1148
|
+
static Leaf = Group.define({ name: "Leaf" });
|
|
1149
|
+
static Plot = Group.define({ name: "Plot" });
|
|
1150
|
+
static Textblock = Group.define({ name: "Textblock" });
|
|
1151
|
+
static Content = Group.define({ name: "Content" });
|
|
1152
|
+
static TableCell = Group.define({ name: "TableCell" });
|
|
1153
|
+
static ListItem = Group.define({ name: "ListItem" });
|
|
1148
1154
|
static builtin = [Group.All, Group.Inline, Group.Block, Group.Leaf, Group.Plot, Group.Textblock];
|
|
1155
|
+
toString() { return "Node.Group" + (this.name ? ":" + this.name : ""); }
|
|
1149
1156
|
}
|
|
1150
1157
|
Node.Group = Group;
|
|
1158
|
+
function queryToString(q) {
|
|
1159
|
+
if ("and" in q)
|
|
1160
|
+
return `and(${q.and.map(queryToString)})`;
|
|
1161
|
+
if (Array.isArray(q))
|
|
1162
|
+
return `or(q.map(queryToString))`;
|
|
1163
|
+
return String(q);
|
|
1164
|
+
}
|
|
1165
|
+
Node.queryToString = queryToString;
|
|
1151
1166
|
class Role {
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1167
|
+
name;
|
|
1168
|
+
constructor(
|
|
1169
|
+
name) {
|
|
1170
|
+
this.name = name;
|
|
1171
|
+
}
|
|
1172
|
+
static define(name) { return new Role(name || null); }
|
|
1173
|
+
static Code = Role.define("Code");
|
|
1174
|
+
static List = Role.define("List");
|
|
1175
|
+
static LineBreak = Role.define("LineBreak");
|
|
1176
|
+
toString() { return "Node.Role" + (this.name ? ":" + this.name : ""); }
|
|
1157
1177
|
}
|
|
1158
1178
|
Node.Role = Role;
|
|
1159
1179
|
;return Node})({});
|
|
@@ -1207,6 +1227,8 @@ class Leaf extends BaseTag {
|
|
|
1207
1227
|
return Leaf.Text.of(this.param.slice(Math.max(from, 0), Math.max(0, to)), this.marks);
|
|
1208
1228
|
}
|
|
1209
1229
|
static text(text, marks = Mark.none) {
|
|
1230
|
+
if (!text)
|
|
1231
|
+
throw new Error("Cannot create empty text nodes");
|
|
1210
1232
|
return Leaf.Text.of(text, marks);
|
|
1211
1233
|
}
|
|
1212
1234
|
toString() {
|
|
@@ -1390,6 +1412,8 @@ class Plot {
|
|
|
1390
1412
|
constructor(type, param, marks) {
|
|
1391
1413
|
super(param, marks);
|
|
1392
1414
|
this.type = type;
|
|
1415
|
+
if (this.type.isDoc && marks.length)
|
|
1416
|
+
throw new Error("Document nodes cannot have marks");
|
|
1393
1417
|
}
|
|
1394
1418
|
static new(type, param, marks) {
|
|
1395
1419
|
return new Tag(type, param, marks);
|
|
@@ -1995,11 +2019,9 @@ class Builder {
|
|
|
1995
2019
|
return this.schema.doc(this.stack.children);
|
|
1996
2020
|
}
|
|
1997
2021
|
}
|
|
1998
|
-
function isAdd(m) { return !!m.add; }
|
|
1999
|
-
function isRemove(m) { return !!m.remove; }
|
|
2000
2022
|
function applyModifications(modifications, marks, type) {
|
|
2001
2023
|
for (const m of modifications) {
|
|
2002
|
-
if (
|
|
2024
|
+
if ("add" in m) {
|
|
2003
2025
|
marks = m.add.addToSet(marks);
|
|
2004
2026
|
}
|
|
2005
2027
|
else {
|
|
@@ -2009,7 +2031,7 @@ function applyModifications(modifications, marks, type) {
|
|
|
2009
2031
|
return marks;
|
|
2010
2032
|
}
|
|
2011
2033
|
function modificationToJSON(m) {
|
|
2012
|
-
return
|
|
2034
|
+
return "add" in m ? { add: m.add.name, value: m.add.value } : { remove: m.remove.name, value: m.remove.value };
|
|
2013
2035
|
}
|
|
2014
2036
|
function modificationFromJSON(schema, json) {
|
|
2015
2037
|
let { add, remove } = json;
|
|
@@ -2034,7 +2056,7 @@ function compareModifications(a, b) {
|
|
|
2034
2056
|
return true;
|
|
2035
2057
|
}
|
|
2036
2058
|
function compareModification(a, b) {
|
|
2037
|
-
return
|
|
2059
|
+
return "add" in a ? "add" in b && a.add.eq(b.add) : "remove" in b && a.remove.eq(b.remove);
|
|
2038
2060
|
}
|
|
2039
2061
|
function isNatNum(value) {
|
|
2040
2062
|
return typeof value == "number" && Math.floor(value) == value && value >= 0;
|
|
@@ -2371,7 +2393,7 @@ class ChangeSet {
|
|
|
2371
2393
|
}
|
|
2372
2394
|
else if (data) {
|
|
2373
2395
|
text += `[${data.map(mod => {
|
|
2374
|
-
return `${
|
|
2396
|
+
return `${"add" in mod ? "+" + mod.add : "-" + mod.remove}`;
|
|
2375
2397
|
})}]`;
|
|
2376
2398
|
}
|
|
2377
2399
|
if (text)
|
|
@@ -2397,6 +2419,36 @@ class ChangeSetBuilder {
|
|
|
2397
2419
|
sections = [];
|
|
2398
2420
|
data = [];
|
|
2399
2421
|
pos = 0;
|
|
2422
|
+
addSection(from, to, ins, value) {
|
|
2423
|
+
if (from >= this.pos) {
|
|
2424
|
+
addSection(this.sections, this.data, from - this.pos, -1, null);
|
|
2425
|
+
addSection(this.sections, this.data, to - from, ins, value);
|
|
2426
|
+
this.pos = to;
|
|
2427
|
+
return true;
|
|
2428
|
+
}
|
|
2429
|
+
if (this.sections.length && this.sections[0] > to && this.sections[1] == -1) {
|
|
2430
|
+
this.spliceSection(0, from, to, ins, value);
|
|
2431
|
+
return true;
|
|
2432
|
+
}
|
|
2433
|
+
for (let pos = this.pos, i = this.sections.length; i > 2 && pos > to;) {
|
|
2434
|
+
let nextIns = this.sections[--i], nextLen = this.sections[--i];
|
|
2435
|
+
let start = pos - nextLen;
|
|
2436
|
+
if (nextIns == -1 && start < from) {
|
|
2437
|
+
this.spliceSection(i, from - start, to - start, ins, value);
|
|
2438
|
+
return true;
|
|
2439
|
+
}
|
|
2440
|
+
pos = start;
|
|
2441
|
+
}
|
|
2442
|
+
return false;
|
|
2443
|
+
}
|
|
2444
|
+
spliceSection(i, from, to, ins, value) {
|
|
2445
|
+
let sections = [], data = [];
|
|
2446
|
+
addSection(sections, data, from, -1, null);
|
|
2447
|
+
addSection(sections, data, to - from, ins, value);
|
|
2448
|
+
addSection(sections, data, this.sections[i] - to, -1, null);
|
|
2449
|
+
this.sections.splice(i, 2, ...sections);
|
|
2450
|
+
this.data.splice(i >> 1, 1, ...data);
|
|
2451
|
+
}
|
|
2400
2452
|
}
|
|
2401
2453
|
function sliceLen(tokens) {
|
|
2402
2454
|
return tokens.reduce((l, e) => l + (e.tokenType == Token.Type.Node ? e.length : 1), 0);
|
|
@@ -2417,14 +2469,11 @@ function createChangeSet(doc, spec, mayCorrect = true) {
|
|
|
2417
2469
|
accum = accum ? accum.compose(transform(set, accum, doc, false, false).set) : set;
|
|
2418
2470
|
};
|
|
2419
2471
|
let section = (from, to, ins, value) => {
|
|
2420
|
-
if (!cur
|
|
2472
|
+
if (!cur?.addSection(from, to, ins, value)) {
|
|
2421
2473
|
flush();
|
|
2422
2474
|
cur = new ChangeSetBuilder(doc.length);
|
|
2475
|
+
cur.addSection(from, to, ins, value);
|
|
2423
2476
|
}
|
|
2424
|
-
if (from > cur.pos)
|
|
2425
|
-
addSection(cur.sections, cur.data, from - cur.pos, -1, null);
|
|
2426
|
-
addSection(cur.sections, cur.data, to - from, ins, value);
|
|
2427
|
-
cur.pos = to;
|
|
2428
2477
|
};
|
|
2429
2478
|
let build = (spec) => {
|
|
2430
2479
|
if (Array.isArray(spec)) {
|
|
@@ -2474,17 +2523,20 @@ function createChangeSet(doc, spec, mayCorrect = true) {
|
|
|
2474
2523
|
if (remove) {
|
|
2475
2524
|
let mods = [{ remove }];
|
|
2476
2525
|
markableSections(doc, from, to, remove.type.spanning, (node, from, to) => {
|
|
2477
|
-
const has = remove.isInSet(node.tag.marks);
|
|
2478
|
-
if (!has || !doc.schema.markAllowed(remove.type, node.type))
|
|
2479
|
-
return false;
|
|
2480
|
-
let modsHere = mods;
|
|
2481
2526
|
if (remove.type.set) {
|
|
2482
|
-
let
|
|
2527
|
+
let has = remove.type.isInSet(node.tag.marks);
|
|
2528
|
+
if (!has)
|
|
2529
|
+
return false;
|
|
2530
|
+
let left = remove.value.filter(a => has.value.some(b => remove.type.set(a, b) == 0));
|
|
2483
2531
|
if (!left.length)
|
|
2484
2532
|
return false;
|
|
2485
|
-
|
|
2533
|
+
section(from, to, -2, left.length == remove.value.length ? mods : [{ remove: remove.type.of(left) }]);
|
|
2534
|
+
}
|
|
2535
|
+
else {
|
|
2536
|
+
if (!remove.isInSet(node.tag.marks))
|
|
2537
|
+
return false;
|
|
2538
|
+
section(from, to, -2, mods);
|
|
2486
2539
|
}
|
|
2487
|
-
section(from, to, -2, modsHere);
|
|
2488
2540
|
return true;
|
|
2489
2541
|
});
|
|
2490
2542
|
}
|
|
@@ -2631,16 +2683,16 @@ function filterMods(mods, against) {
|
|
|
2631
2683
|
return mods.filter(m => !against.some(a => modCancels(a, m)));
|
|
2632
2684
|
}
|
|
2633
2685
|
function modCancels(mod, other) {
|
|
2634
|
-
if (
|
|
2635
|
-
return
|
|
2686
|
+
if ("add" in other) {
|
|
2687
|
+
return "add" in mod ? mod.add.type == other.add.type && !mod.add.type.set : mod.remove.eq(other.add);
|
|
2636
2688
|
}
|
|
2637
2689
|
else {
|
|
2638
|
-
return
|
|
2690
|
+
return "add" in mod && mod.add.eq(other.remove);
|
|
2639
2691
|
}
|
|
2640
2692
|
}
|
|
2641
2693
|
function invertMods(mods, target) {
|
|
2642
2694
|
return mods.map(mod => {
|
|
2643
|
-
if (
|
|
2695
|
+
if ("remove" in mod)
|
|
2644
2696
|
return { add: mod.remove };
|
|
2645
2697
|
if (!mod.add.type.set) {
|
|
2646
2698
|
let existed = mod.add.type.isInSet(target.marks);
|
package/dist/editor.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { PointSet, Set, RangeSet } from 'wordgard/set';
|
|
|
8
8
|
|
|
9
9
|
type MakeSelectionStyle = (wg: Wordgard, event: MouseEvent) => Wordgard.MouseSelectionStyle | null;
|
|
10
10
|
|
|
11
|
+
import Mark_ = Mark;
|
|
11
12
|
/**
|
|
12
13
|
A widget describes a piece of DOM content that can be used to
|
|
13
14
|
render a node, a part of a node, or an extra element added via a
|
|
@@ -193,8 +194,8 @@ declare namespace Decoration {
|
|
|
193
194
|
/**
|
|
194
195
|
Override the shape used for a given mark inside the editor.
|
|
195
196
|
*/
|
|
196
|
-
function shape<V>(type:
|
|
197
|
-
function shape(mark:
|
|
197
|
+
function shape<V>(type: Mark_.Type<V>, shape: Shape.Element<V> | Shape.Attribute<V> | Shape.Attributes<V>): GardState.Extension;
|
|
198
|
+
function shape(mark: Mark_<null>, shape: Shape.Element<null> | Shape.Attribute<null> | Shape.Attributes<null>): GardState.Extension;
|
|
198
199
|
}
|
|
199
200
|
/**
|
|
200
201
|
A point decoration is a decoration that targets a given position
|
|
@@ -375,10 +376,11 @@ declare const enum TileFlag {
|
|
|
375
376
|
Composition = 128,
|
|
376
377
|
Synced = 256,// Node has been synced. DOM content matches child list / text content, child array becomes read-only
|
|
377
378
|
Atom = 512,// Composite tile whose length isn't determined by child length
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
379
|
+
Uneditable = 1024,// Tile's DOM is uneditable
|
|
380
|
+
HasContent = 2048,// EltTile whose elt has a content hole
|
|
381
|
+
AfterContent = 4096,// Tiles that sit after their parent's content position
|
|
382
|
+
ContentNotLast = 8192,// EltTile that has children with AfterContent flag
|
|
383
|
+
Dirty = 16384
|
|
382
384
|
}
|
|
383
385
|
declare const enum Orientation {
|
|
384
386
|
Row = 0,
|
|
@@ -420,14 +422,15 @@ declare abstract class Tile {
|
|
|
420
422
|
get boundary(): 0 | 1;
|
|
421
423
|
get firstChild(): Tile | null;
|
|
422
424
|
get lastChild(): Tile | null;
|
|
423
|
-
get nodeParent(): Tile;
|
|
424
425
|
ignoreEvent(event: Event): boolean;
|
|
425
426
|
get ignoreMutations(): boolean;
|
|
426
427
|
toString(): string;
|
|
427
428
|
abstract sync(): void;
|
|
428
429
|
connect(): void;
|
|
429
430
|
disconnect(reused?: Map<Tile, Reused>): void;
|
|
430
|
-
nearestNode(): Tile
|
|
431
|
+
nearestNode(): Tile & {
|
|
432
|
+
tag: Node$1.Tag;
|
|
433
|
+
};
|
|
431
434
|
markDirty(): void;
|
|
432
435
|
posAtCoords(state: GardState, x: number, y: number): CoordPos;
|
|
433
436
|
abstract posAtCoordsInner(start: number, state: GardState, x: number, y: number, textblock: TextblockMap | null, orientation: Orientation): CoordPos;
|
|
@@ -437,6 +440,7 @@ declare class CompositeTile extends Tile {
|
|
|
437
440
|
children: Tile[];
|
|
438
441
|
dom: Element;
|
|
439
442
|
addChild(child: Tile): void;
|
|
443
|
+
putChild(child: Tile, index: number): void;
|
|
440
444
|
sync(): void;
|
|
441
445
|
syncChildren(): void;
|
|
442
446
|
posAtCoordsInner(start: number, state: GardState, x: number, y: number, textblock: TextblockMap | null, orientation: Orientation): CoordPos;
|
|
@@ -727,7 +731,13 @@ declare class Wordgard {
|
|
|
727
731
|
Facet that allows you to register handlers to override paste
|
|
728
732
|
behavior.
|
|
729
733
|
*/
|
|
730
|
-
static pasteHandler: GardState.Facet<(wg: Wordgard, event: InputEvent, slice: wordgard_doc.Slice) => boolean, readonly ((wg: Wordgard, event: InputEvent, slice: wordgard_doc.Slice) => boolean)[]>;
|
|
734
|
+
static pasteHandler: GardState.Facet<(wg: Wordgard, event: InputEvent | null, slice: wordgard_doc.Slice, html: string, text: string) => boolean, readonly ((wg: Wordgard, event: InputEvent | null, slice: wordgard_doc.Slice, html: string, text: string) => boolean)[]>;
|
|
735
|
+
/**
|
|
736
|
+
Perform a paste with the given content. This will run {@link
|
|
737
|
+
Wordgard.pasteHandler paste handlers} and, if none handles the
|
|
738
|
+
paste, fall back to the default handling.
|
|
739
|
+
*/
|
|
740
|
+
paste(html: string, text?: string): void;
|
|
731
741
|
/**
|
|
732
742
|
Facet for custom drop handlers. When the drop is done inside the
|
|
733
743
|
editor and should move an existing range, the `move` parameter
|
|
@@ -853,7 +863,7 @@ declare class Wordgard {
|
|
|
853
863
|
the editor's {@link Wordgard.dom wrapper element} (to which the
|
|
854
864
|
scope class will be added) need to be explicitly differentiated
|
|
855
865
|
by adding an `&` to the selector for that element—for example
|
|
856
|
-
|
|
866
|
+
`&.wg-focused`.
|
|
857
867
|
*/
|
|
858
868
|
static theme(spec: Record<string, StyleSpec>): GardState.Extension;
|
|
859
869
|
/**
|
|
@@ -922,6 +932,11 @@ declare class Wordgard {
|
|
|
922
932
|
part of the editor (for example a gutter).
|
|
923
933
|
*/
|
|
924
934
|
static coveredMargins: GardState.Facet<(wg: Wordgard) => Partial<DOMRect> | null, readonly ((wg: Wordgard) => Partial<DOMRect> | null)[]>;
|
|
935
|
+
/**
|
|
936
|
+
Given a DOM element that may be a Wordgard editor, retrieve its
|
|
937
|
+
editor instance.
|
|
938
|
+
*/
|
|
939
|
+
static findFromDOM(elt: Element): Wordgard | null;
|
|
925
940
|
}
|
|
926
941
|
declare namespace Wordgard {
|
|
927
942
|
/**
|