@nerd-bible/wordgard 0.3.5 → 0.5.2-beta

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/schema.js CHANGED
@@ -1290,7 +1290,7 @@ function computeLinkTooltip(state) {
1290
1290
  if (!state.selection.isCursor)
1291
1291
  return null;
1292
1292
  let { head } = state.sel, before = head.nodeBefore, link = before && Link.isInSet(before.marks);
1293
- if (!link)
1293
+ if (!link || head.matchingParent(plot => state.isAtom(plot.type)))
1294
1294
  return null;
1295
1295
  let start = head.pos - before.length, end = head.pos, siblings = head.parent.node.content;
1296
1296
  for (let index = head.index - 1; index > 0 && link.isInSet(siblings[index - 1].marks);)
package/dist/state.d.ts CHANGED
@@ -136,6 +136,10 @@ declare abstract class GardSelection {
136
136
  */
137
137
  static cursor(pos: number, side?: -1 | 1, goalColumn?: number): GardSelection.Text;
138
138
  /**
139
+ Find a normal cursor near the given position.
140
+ */
141
+ static near(cx: GardSelection.Context, pos: number, side?: -1 | 1, goalColumn?: number): GardSelection.Text;
142
+ /**
139
143
  Create a text selection.
140
144
  */
141
145
  static range(anchor: number, head?: number, headSide?: -1 | 1, goalColumn?: number): GardSelection.Text;
@@ -147,9 +151,7 @@ declare abstract class GardSelection {
147
151
  Find the next normal cursor position after or before this selection's
148
152
  head. Normal cursor positions are:
149
153
 
150
- - Any inline position, except one directly inside of an inline
151
- plot that doesn't have {@link Plot.Spec.cursorInsideBounds
152
- `cursorInsideBounds`} set.
154
+ - Any inline position.
153
155
 
154
156
  - Positions between two cursor barriers, if not already an
155
157
  inline position. Cursor barriers are the sides of the
@@ -161,18 +163,10 @@ declare abstract class GardSelection {
161
163
  */
162
164
  nextNormalCursor(cx: GardSelection.Context, forward?: boolean): GardSelection.Text | null;
163
165
  /**
164
- Get a normal cursor at the start or end of this selection.
165
- */
166
- normalCursorAtBound(cx: GardSelection.Context, forward?: boolean): GardSelection.Text | null;
167
- /**
168
166
  Move across one word starting from this selection's head.
169
167
  */
170
168
  skipWord(cx: GardSelection.Context, forward?: boolean): GardSelection.Text | null;
171
169
  /**
172
- Find a normal selection near the given position.
173
- */
174
- static near(cx: GardSelection.Context, pos: number, bias?: -1 | 1): GardSelection.Text;
175
- /**
176
170
  Find a normal selection at the start of the document or the
177
171
  given textblock.
178
172
  */
package/dist/state.js CHANGED
@@ -384,19 +384,11 @@ class TextblockMap {
384
384
  sectionPos = pos + ch.length;
385
385
  }
386
386
  }
387
- else if (ch.type.spec.cursorInsideBounds) {
387
+ else {
388
388
  text += " ";
389
389
  scan(ch, pos + 1);
390
390
  text += " ";
391
391
  }
392
- else {
393
- flush(pos);
394
- sections.push((1 << 2) | 3);
395
- scan(ch, sectionPos = pos + 1);
396
- flush(pos + ch.length - 1);
397
- sections.push((1 << 2) | 2);
398
- sectionPos = pos + ch.length;
399
- }
400
392
  pos += ch.length;
401
393
  }
402
394
  };
@@ -590,6 +582,10 @@ class GardSelection {
590
582
  static cursor(pos, side, goalColumn) {
591
583
  return GardSelection.Text.createInner(pos, pos, side, goalColumn);
592
584
  }
585
+ static near(cx, pos, side = 1, goalColumn) {
586
+ let norm = findNormalAt(cx, pos, side);
587
+ return GardSelection.cursor(norm.pos, norm.side, goalColumn);
588
+ }
593
589
  static range(anchor, head, headSide, goalColumn) {
594
590
  return GardSelection.Text.createInner(anchor, head ?? anchor, headSide, goalColumn);
595
591
  }
@@ -597,23 +593,13 @@ class GardSelection {
597
593
  return GardSelection.Node.create(pos, node, goalColumn);
598
594
  }
599
595
  nextNormalCursor(cx, forward = true) {
600
- let found = scanNormalFrom(cx, this.head, this.headSide, forward, true);
601
- return found && GardSelection.cursor(found.pos, found.side);
602
- }
603
- normalCursorAtBound(cx, forward = true) {
604
- let found = scanNormalFrom(cx, forward ? this.to : this.from, forward ? -1 : 1, forward, false);
596
+ let found = scanNormalFrom(cx, this.head, this.headSide, forward);
605
597
  return found && GardSelection.cursor(found.pos, found.side);
606
598
  }
607
599
  skipWord(cx, forward = true) {
608
600
  let found = skipWord(cx, this.head, this.headSide, forward);
609
601
  return found && GardSelection.cursor(found.pos, found.side);
610
602
  }
611
- static near(cx, pos, bias = 1) {
612
- let norm = scanNormalFrom(cx, pos, bias, bias > 0, false) ??
613
- scanNormalFrom(cx, pos, -bias, bias < 0, false) ??
614
- { pos: pos, side: -1 };
615
- return GardSelection.cursor(norm.pos, norm.side);
616
- }
617
603
  static atStart(cx, block) {
618
604
  return cursorAtStart(cx, block);
619
605
  }
@@ -621,7 +607,7 @@ class GardSelection {
621
607
  let found = block
622
608
  ? TextblockMap.get(cx, block.start, block.node).visualSide(false)
623
609
  : cx.doc.inlineContent ? TextblockMap.get(cx, 0, cx.doc).visualSide(false)
624
- : scanNormalFrom(cx, cx.doc.length, -1, false, false) ?? { pos: cx.doc.length, side: -1 };
610
+ : findNormalAt(cx, cx.doc.length, -1);
625
611
  return GardSelection.cursor(found.pos, found.side);
626
612
  }
627
613
  }
@@ -760,22 +746,20 @@ function cursorAtStart(cx, block) {
760
746
  let found = block
761
747
  ? TextblockMap.get(cx, block.start, block.node).visualSide(true)
762
748
  : cx.doc.inlineContent ? TextblockMap.get(cx, 0, cx.doc).visualSide(true)
763
- : scanNormalFrom(cx, 0, 1, true, false) ?? { pos: 0, side: 1 };
749
+ : findNormalAt(cx, 0, 1);
764
750
  return GardSelection.cursor(found.pos, found.side);
765
751
  }
766
752
  function isBarrier(cx, node) {
767
753
  if (node.isLeaf)
768
- return node.type.isBlock;
754
+ return node.isBlock;
769
755
  let override = node.type.spec.cursorBarrier;
770
756
  if (override != null)
771
757
  return override;
772
- return node.type.isolating || node.type.preserveWhitespace || node.type.isBlock && cx.config.isAtom(node.type);
758
+ return node.isBlock && (node.type.isolating || node.type.preserveWhitespace || cx.config.isAtom(node.type));
773
759
  }
774
- function scanNormalFrom(cx, from, side, forward, mustMove) {
760
+ function scanNormalFrom(cx, from, side, forward) {
775
761
  let pos = cx.doc.resolve(from), pastBarrier = false;
776
762
  if (pos.parent.node.inlineContent) {
777
- if (!mustMove)
778
- return { pos: pos.pos, side };
779
763
  let block = pos.textblockParent;
780
764
  let map = TextblockMap.get(cx, block.start, block.node);
781
765
  let next = cx.config.visualCursorMotion ? map.moveVisually(pos.pos, side, forward) : map.moveLogically(pos.pos, forward);
@@ -813,7 +797,7 @@ function scanNormalFrom(cx, from, side, forward, mustMove) {
813
797
  }
814
798
  if (index == (forward ? node.content.length : 0)) {
815
799
  let barrier = !next || isBarrier(cx, node);
816
- if ((bottom != from || !mustMove) && pastBarrier && barrier)
800
+ if ((bottom != from) && pastBarrier && barrier)
817
801
  return { pos: bottom, side: forward ? -1 : 1 };
818
802
  if (!next)
819
803
  return null;
@@ -827,7 +811,7 @@ function scanNormalFrom(cx, from, side, forward, mustMove) {
827
811
  else {
828
812
  let nextNode = node.content[index - (forward ? 0 : 1)];
829
813
  let barrier = isBarrier(cx, nextNode);
830
- if (pastBarrier && (bottom != from || !mustMove) && barrier)
814
+ if (pastBarrier && (bottom != from) && barrier)
831
815
  return { pos: bottom, side: forward ? -1 : 1 };
832
816
  if (nextNode.isLeaf || cx.config.isAtom(nextNode.type)) {
833
817
  index += step;
@@ -847,12 +831,50 @@ function scanNormalFrom(cx, from, side, forward, mustMove) {
847
831
  }
848
832
  }
849
833
  }
834
+ function findNormalAt(cx, pos, bias) {
835
+ let res = cx.doc.resolve(pos), lowest = pos;
836
+ if (res.inText) {
837
+ let text = res.parent.node.content[res.index].tag.param;
838
+ let off = bias > 0 ? findClusterBreak(text, res.inText - 1) : findClusterBreak(text, res.inText + 1, false);
839
+ pos += off - res.inText;
840
+ if (off > 0 && off < text.length)
841
+ return { pos, side: bias };
842
+ res = Pos.create(res.parent, pos, res.index + (off ? 1 : 0), 0);
843
+ }
844
+ for (let pass = 0; pass < 2; pass++) {
845
+ let dir = !pass ? bias : -bias, { parent, index } = res, curPos = pos;
846
+ for (;;) {
847
+ if (parent.node.inlineContent)
848
+ return { pos: curPos, side: bias };
849
+ if (index == (dir > 0 ? parent.node.content.length : 0)) {
850
+ if (isBarrier(cx, parent.node) || !parent.parent)
851
+ break;
852
+ lowest = curPos = curPos + dir;
853
+ index = parent.index + (dir > 0 ? 1 : 0);
854
+ parent = parent.parent;
855
+ }
856
+ else {
857
+ let next = parent.node.content[index + (dir > 0 ? 0 : -1)];
858
+ if (next.isLeaf || isBarrier(cx, next))
859
+ break;
860
+ if (!parent.node.inlineContent && next.inlineContent && cx.config.visualCursorMotion) {
861
+ let startPos = curPos - (dir > 0 ? 0 : next.length) + 1;
862
+ return TextblockMap.get(cx, startPos, next).visualSide(dir > 0);
863
+ }
864
+ parent = Pos.Plot.create(parent, next, curPos, index);
865
+ index = dir > 0 ? 0 : next.content.length;
866
+ curPos += dir;
867
+ }
868
+ }
869
+ }
870
+ return { pos: lowest, side: bias };
871
+ }
850
872
  function skipWord(cx, start, side, forward) {
851
873
  let last = null;
852
874
  for (let pos = start, visually = cx.config.visualCursorMotion;;) {
853
875
  let block = cx.doc.resolve(pos).textblockParent;
854
876
  if (!block) {
855
- let next = scanNormalFrom(cx, pos, side, forward, true);
877
+ let next = scanNormalFrom(cx, pos, side, forward);
856
878
  if (!next)
857
879
  return last;
858
880
  ({ pos, side } = next);
package/dist/table.js CHANGED
@@ -205,10 +205,11 @@ function computeMap(table) {
205
205
  }
206
206
  pos++;
207
207
  }
208
- for (let row = 0, i = width; row < height; row++, i += width) {
208
+ for (let row = 0, i = 0; row < height; row++) {
209
209
  let missing = 0;
210
- while (missing < width && map[i - missing - 1] == 0)
211
- missing++;
210
+ for (let col = 0; col < width; col++)
211
+ if (map[i++] == 0)
212
+ missing++;
212
213
  if (missing)
213
214
  (problems || (problems = [])).push({ type: "missing", row, n: missing });
214
215
  }
package/dist/types.d.ts CHANGED
@@ -1,5 +1,10 @@
1
1
  import { Mark, Plot, Leaf } from 'wordgard/doc';
2
2
 
3
+ /**
4
+ A hard line break. Renders as `<br>` and has the {@link
5
+ Node.Role.LineBreak | `LineBreak`} role.
6
+ */
7
+ declare const LineBreak: Leaf<null>;
3
8
  /**
4
9
  A paragraph. Part of the {@link Node.Group.Content | `Content`}
5
10
  group, allowing inline content, rendered as `<p>`.
@@ -58,11 +63,6 @@ A horizontal separator. Part of the {@link Node.Group.Content |
58
63
  */
59
64
  declare const HorizontalRule: Leaf<null>;
60
65
  /**
61
- A hard line break. Renders as `<br>` and has the {@link
62
- Node.Role.LineBreak | `LineBreak`} role.
63
- */
64
- declare const LineBreak: Leaf<null>;
65
- /**
66
66
  Table cell plot. Allows inline content, and is in the {@link
67
67
  Node.Group.TableCell | `TableCell`} group. Rendered as `<td>`
68
68
  */
package/dist/types.js CHANGED
@@ -1,6 +1,12 @@
1
- import { Node, Plot, Elt, ValidationError, Mark, Leaf, parse } from 'wordgard/doc';
1
+ import { Node, Leaf, Plot, Elt, ValidationError, Mark, parse } from 'wordgard/doc';
2
2
 
3
3
  const G = /*@__PURE__*/(() => Node.Group)();
4
+ const LineBreak = /*@__PURE__*/(() => Leaf.define("LineBreak", {
5
+ inline: true,
6
+ role: Node.Role.LineBreak,
7
+ toText: () => "\n",
8
+ shape: { element: "br" }
9
+ }))();
4
10
  const Paragraph = /*@__PURE__*/(() => Plot.define("Paragraph", {
5
11
  inlineContent: true,
6
12
  group: G.Content,
@@ -27,7 +33,7 @@ const Heading = /*@__PURE__*/(() => Plot.Type.define("Heading", {
27
33
  ]
28
34
  }))();
29
35
  const CodeBlock = /*@__PURE__*/(() => Plot.define("CodeBlock", {
30
- inlineContent: true,
36
+ inlineContent: [Leaf.Text, LineBreak],
31
37
  group: G.Content,
32
38
  role: Node.Role.Code,
33
39
  shape: { element: "pre" },
@@ -81,12 +87,6 @@ const HorizontalRule = /*@__PURE__*/(() => Leaf.define("HorizontalRule", {
81
87
  toText: () => "---",
82
88
  selectable: true
83
89
  }))();
84
- const LineBreak = /*@__PURE__*/(() => Leaf.define("LineBreak", {
85
- inline: true,
86
- role: Node.Role.LineBreak,
87
- toText: () => "\n",
88
- shape: { element: "br" }
89
- }))();
90
90
  const Cell = /*@__PURE__*/(() => Plot.define("Cell", {
91
91
  inlineContent: true,
92
92
  group: G.TableCell,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nerd-bible/wordgard",
3
- "version": "0.3.5",
3
+ "version": "0.5.2-beta",
4
4
  "description": "Semantic rich text editor system",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",