@nerd-bible/wordgard 0.5.2-beta2 → 0.5.2-beta4

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/command.d.ts CHANGED
@@ -539,6 +539,24 @@ points.
539
539
  */
540
540
  declare const deleteToLineEnd: Command<"forward" | "backward">;
541
541
  /**
542
+ Command similar to forward `deleteToLineEnd` for macOS's Ctrl-k
543
+ binding. If there's no content left on the line, this will delete
544
+ the node (generally a line break) after the cursor of, if at end
545
+ of textblock, join it to the next textblock.
546
+
547
+ Content deleted by this command is added to a ‘kill buffer’, and
548
+ can be reinserted with {@link yankKilled}. Multiple kill actions
549
+ in sequence will accumulate the deleted content in the buffer.
550
+ Doing anything else and then running this command again will reset
551
+ the buffer to hold only the newly killed content.
552
+ */
553
+ declare const killToLineEnd: Command;
554
+ /**
555
+ Insert the content killed by the most recent {@link killToLineEnd}
556
+ command (or sequence thereof) at the cursor position.
557
+ */
558
+ declare const yankKilled: Command;
559
+ /**
542
560
  Delete the selection, or if that is empty, the line around the
543
561
  cursor.
544
562
  */
@@ -805,4 +823,4 @@ updated to perform those joins.
805
823
  */
806
824
  declare function autoJoinBlocks(state: GardState, tr: Transaction.Spec): Transaction.Spec;
807
825
 
808
- 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, 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 };
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 };
package/dist/command.js CHANGED
@@ -676,7 +676,7 @@ function joinBlocks(before, after) {
676
676
  if (atEnd)
677
677
  end++;
678
678
  else
679
- tokensAfter.push(level.parent.node.tag);
679
+ tokensAfter.unshift(level.parent.node.tag);
680
680
  }
681
681
  }
682
682
  if (tokensAfter.length || end > posAfter)
@@ -807,7 +807,7 @@ const deleteToLineEnd = (wg, dir) => {
807
807
  return false;
808
808
  let tr = deleteSelection(wg.state), { selection } = wg.state;
809
809
  if (tr)
810
- return (wg.dispatch(tr), true);
810
+ return tr;
811
811
  if (!(selection instanceof GardSelection.Text))
812
812
  return false;
813
813
  let end = wg.moveToLineBoundary(selection, dir == "forward");
@@ -819,12 +819,76 @@ const deleteToLineEnd = (wg, dir) => {
819
819
  userEvent: "delete." + dir
820
820
  };
821
821
  };
822
+ const addToKillBuffer = /*@__PURE__*/Transaction.Effect.define();
823
+ const killBuffer = /*@__PURE__*/GardState.Field.define({
824
+ create() { return { content: [], active: false }; },
825
+ update(value, tr) {
826
+ let add = tr.effects.find(e => e.is(addToKillBuffer));
827
+ if (add)
828
+ return { content: value.active ? value.content.concat(add.value) : add.value, active: true };
829
+ return !value.active || tr.annotation(Transaction.remote) || !(tr.docChanged || tr.selection)
830
+ ? value : { content: value.content, active: false };
831
+ }
832
+ });
833
+ function killText(state, from, to) {
834
+ let add = addToKillBuffer.of(state.doc.slice(from, to).content);
835
+ return state.field(killBuffer, false) ? [add] : [GardState.appendConfig.of(killBuffer), add];
836
+ }
837
+ const killToLineEnd = wg => {
838
+ let { state } = wg, { selection } = state;
839
+ if (state.readOnly || !(selection instanceof GardSelection.Text))
840
+ return false;
841
+ let end = wg.moveToLineBoundary(selection, true);
842
+ if (!end)
843
+ return false;
844
+ if (end.head > selection.head)
845
+ return {
846
+ changes: { correct: { from: selection.head, to: end.head } },
847
+ scrollIntoView: true,
848
+ effects: killText(state, selection.head, end.head),
849
+ userEvent: "delete.forward"
850
+ };
851
+ let join = joinForward(state);
852
+ if (join) {
853
+ let joinEnd;
854
+ state.doc.iterate(state.sel.head.textblockParent.after, state.doc.length, (node, pos) => {
855
+ if (joinEnd != null)
856
+ return false;
857
+ if (node.isPlot && node.isTextblock)
858
+ joinEnd = pos + 1;
859
+ });
860
+ return Transaction.merge(state, join, {
861
+ effects: joinEnd == null ? undefined : killText(state, selection.head, joinEnd)
862
+ });
863
+ }
864
+ let next = state.sel.head.nodeAfter;
865
+ if (next)
866
+ return {
867
+ changes: { correct: { from: selection.head, to: selection.head + next.length } },
868
+ scrollIntoView: true,
869
+ effects: killText(state, selection.head, selection.head + next.length),
870
+ userEvent: "delete.forward"
871
+ };
872
+ return false;
873
+ };
874
+ const yankKilled = wg => {
875
+ let { state } = wg, buffer = wg.state.field(killBuffer, false);
876
+ if (!buffer || !buffer.content.length || !(state.selection instanceof GardSelection.Text))
877
+ return false;
878
+ let { selection } = state;
879
+ return {
880
+ changes: { correct: { from: selection.from, to: selection.to, insert: buffer.content } },
881
+ scrollIntoView: true,
882
+ selection: (cx, changes) => GardSelection.near(cx, changes.mapPos(selection.from, 1)),
883
+ userEvent: "input.yank"
884
+ };
885
+ };
822
886
  const deleteLine = wg => {
823
887
  if (wg.state.readOnly)
824
888
  return false;
825
889
  let tr = deleteSelection(wg.state), { selection } = wg.state;
826
890
  if (tr)
827
- return (wg.dispatch(tr), true);
891
+ return tr;
828
892
  if (!(selection instanceof GardSelection.Text))
829
893
  return false;
830
894
  let start = wg.moveToLineBoundary(selection, false), end = wg.moveToLineBoundary(selection, true);
@@ -1476,4 +1540,4 @@ const Menu = /*@__PURE__*/(function (Menu) {
1476
1540
  Menu.resolve = resolve;
1477
1541
  ;return Menu})({});
1478
1542
 
1479
- 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, 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 };
1543
+ 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 };
package/dist/editor.d.ts CHANGED
@@ -524,10 +524,11 @@ declare abstract class Tile {
524
524
  ignoreEvent(event: Event): boolean;
525
525
  get ignoreMutations(): boolean;
526
526
  toString(): string;
527
- sync(): void;
527
+ abstract sync(): void;
528
528
  connect(): void;
529
529
  disconnect(reused?: Map<Tile, Reused>): void;
530
530
  nearestNode(): Tile;
531
+ markDirty(): void;
531
532
  posAtCoords(state: GardState, x: number, y: number): CoordPos;
532
533
  abstract posAtCoordsInner(start: number, state: GardState, x: number, y: number, textblock: TextblockMap | null, orientation: Orientation): CoordPos;
533
534
  static get(node: DOMNode): Tile | undefined;
@@ -1421,11 +1422,12 @@ declare namespace KeyBinding {
1421
1422
  - `Ctrl-e` to {@link command.moveToTextblockSide} (`{dir: "forward"}`)
1422
1423
  - `Ctrl-d` to {@link command.deleteUnit} (`"forward"`)
1423
1424
  - `Ctrl-h` to {@link command.deleteUnit} (`"backward"`)
1424
- - `Ctrl-k` to {@link command.deleteToLineEnd} (`"forward"`)
1425
+ - `Ctrl-k` to {@link command.killToLineEnd}
1425
1426
  - `Ctrl-Alt-h` to {@link command.deleteWord} (`"backward"`)
1426
1427
  - `Ctrl-o` to {@link command.insertLineBreak}
1427
1428
  - `Ctrl-t` to {@link command.transposeChars}
1428
1429
  - `Ctrl-v` to {@link command.moveByPage} (`{dir: "down"}`)
1430
+ - `Ctrl-y` to {@link command.yankKilled}
1429
1431
  */
1430
1432
  const defaultKeymap: readonly KeyBinding[];
1431
1433
  }
package/dist/editor.js CHANGED
@@ -2,7 +2,7 @@ import { GardState, GardSelection, TextblockMap, BidiSpan, Transaction } from 'w
2
2
  import { Attributes, Elt, Node, Leaf, parse, Slice, Plot, serialize, Pos, ChangeSet, ValidationError, Mark } from 'wordgard/doc';
3
3
  import { StyleModule } from 'style-mod';
4
4
  import { findClusterBreak } from '@marijn/find-cluster-break';
5
- import { enter, insertLineBreak, selectAll, undo, redo, transposeChars, Command, deleteUnit, deleteWord, deleteToLineEnd, moveByUnit, moveByLine, moveByWord, moveToLineSide, moveToDocSide, moveByPage, moveToTextblockSide, setAlignment, toggleUnderline, toggleEmphasis, toggleStrong, deleteLine, insertText, setDirection, deleteSelection, Menu, findWrappable, wrapBlockRange, autoJoinBlocks } from 'wordgard/command';
5
+ import { enter, insertLineBreak, selectAll, undo, redo, killToLineEnd, yankKilled, transposeChars, Command, deleteUnit, deleteWord, deleteToLineEnd, moveByUnit, moveByLine, moveByWord, moveToLineSide, moveToDocSide, moveByPage, moveToTextblockSide, setAlignment, toggleUnderline, toggleEmphasis, toggleStrong, deleteLine, insertText, setDirection, deleteSelection, Menu, findWrappable, wrapBlockRange, autoJoinBlocks } from 'wordgard/command';
6
6
  import { PhraseSet, phrases } from 'wordgard/phrases';
7
7
  import { history } from 'wordgard/history';
8
8
 
@@ -218,10 +218,10 @@ class Widget {
218
218
  of(value) { return Widget.new(this, value); }
219
219
  }
220
220
  Widget.Type = Type;
221
- Widget.Text = Widget.define({
221
+ Widget.text = Widget.define({
222
222
  render: s => document.createTextNode(s)
223
223
  });
224
- Widget.EditableText = Widget.define({
224
+ Widget.editableText = Widget.define({
225
225
  render: s => document.createTextNode(s)
226
226
  });
227
227
  Widget.img = Widget.create({
@@ -394,7 +394,7 @@ function applyDeco(shape, deco, tag) {
394
394
  return shape;
395
395
  }
396
396
  const baseTagShape = /*@__PURE__*/memo((tag) => {
397
- return addMarkAttributes(tag.is(Leaf.Text) ? Widget.EditableText.of(tag.param)
397
+ return addMarkAttributes(tag.is(Leaf.Text) ? Widget.editableText.of(tag.param)
398
398
  : tag.type.shape.create(tag.param), tag);
399
399
  });
400
400
  function renderMarks(marks, around) {
@@ -1801,7 +1801,6 @@ class Tile {
1801
1801
  ignoreEvent(event) { return false; }
1802
1802
  get ignoreMutations() { return false; }
1803
1803
  toString() { return this.dom.nodeName + (this.children.length ? `(${this.children})` : ""); }
1804
- sync() { }
1805
1804
  connect() {
1806
1805
  for (let ch of this.children)
1807
1806
  ch.connect();
@@ -1817,12 +1816,25 @@ class Tile {
1817
1816
  tile = tile.parent;
1818
1817
  return tile;
1819
1818
  }
1819
+ markDirty() {
1820
+ if (!(this.flags & 8192)) {
1821
+ this.flags |= 8192;
1822
+ this.parent?.markDirty();
1823
+ }
1824
+ }
1820
1825
  posAtCoords(state, x, y) {
1821
1826
  let nodeTile = this.nearestNode();
1822
1827
  return nodeTile.posAtCoordsInner(nodeTile.posAtStart, state, x, y, null, 1);
1823
1828
  }
1824
1829
  static get(node) { return node.wgTile; }
1825
1830
  }
1831
+ function checkSync(tile) {
1832
+ if ((tile.flags & 256) && !(tile.flags & 8192))
1833
+ return false;
1834
+ tile.flags |= 256;
1835
+ tile.flags &= -8193;
1836
+ return true;
1837
+ }
1826
1838
  class CompositeTile extends Tile {
1827
1839
  children = [];
1828
1840
  addChild(child) {
@@ -1840,9 +1852,8 @@ class CompositeTile extends Tile {
1840
1852
  child.parent = this;
1841
1853
  }
1842
1854
  sync() {
1843
- if (this.flags & 256)
1855
+ if (!checkSync(this))
1844
1856
  return;
1845
- this.flags |= 256;
1846
1857
  let len = this.boundary * 2;
1847
1858
  for (let ch of this.children) {
1848
1859
  ch.sync();
@@ -2270,6 +2281,15 @@ class EltTile extends CompositeTile {
2270
2281
  return new EltTile(elt, node, flags, length, dom || elt.outerDOM());
2271
2282
  }
2272
2283
  }
2284
+ function setUneditable(dom) {
2285
+ if (dom.nodeType != 1) {
2286
+ let span = document.createElement("span");
2287
+ span.appendChild(dom);
2288
+ dom = span;
2289
+ }
2290
+ if (dom.contentEditable == "inherit" && !/^(br|hr|img|input|wbr)$/i.test(dom.nodeName))
2291
+ dom.contentEditable = "false";
2292
+ }
2273
2293
  class WidgetTile extends Tile {
2274
2294
  widget;
2275
2295
  _node;
@@ -2278,14 +2298,14 @@ class WidgetTile extends Tile {
2278
2298
  this.widget = widget;
2279
2299
  this._node = _node;
2280
2300
  this.length = length;
2281
- if (dom.nodeType == 1 && !widget.type.editable && dom.contentEditable == "inherit")
2282
- dom.contentEditable = "false";
2283
2301
  }
2284
2302
  get isNodeOuter() { return !!this._node; }
2285
2303
  get isAtom() { return true; }
2286
2304
  get node() { return this._node; }
2287
2305
  get children() { return noChildren; }
2288
2306
  ignoreEvent(event) { return !this.widget.type.propagateEvent(event); }
2307
+ get ignoreMutations() { return !this.widget.type.editable; }
2308
+ sync() { checkSync(this); }
2289
2309
  connect() {
2290
2310
  this.widget.type.connect?.(this.widget.value, this.dom);
2291
2311
  }
@@ -2294,7 +2314,7 @@ class WidgetTile extends Tile {
2294
2314
  this.widget.type.disconnect?.(this.widget.value, this.dom);
2295
2315
  }
2296
2316
  toString() {
2297
- return this.widget.type == Widget.EditableText || this.widget.type == Widget.Text
2317
+ return this.widget.type == Widget.editableText || this.widget.type == Widget.text
2298
2318
  ? JSON.stringify(this.widget.value) : super.toString();
2299
2319
  }
2300
2320
  posAtCoordsInner(start, state, x, y, textblock, orientation) {
@@ -2319,9 +2339,8 @@ class TextTile extends Tile {
2319
2339
  get isNodeOuter() { return true; }
2320
2340
  get isAtom() { return true; }
2321
2341
  sync() {
2322
- if (this.flags & 256)
2342
+ if (!checkSync(this))
2323
2343
  return;
2324
- this.flags |= 256;
2325
2344
  if (this.dom.nodeValue != this.text)
2326
2345
  this.dom.nodeValue = this.text;
2327
2346
  }
@@ -2754,7 +2773,10 @@ class ContentUpdate {
2754
2773
  : endOld && this.posB == end ? endOld.matchingWidget(widget, sideFlag, this.reused)
2755
2774
  : null;
2756
2775
  if (!tile) {
2757
- tile = new WidgetTile(widget, null, 16 | sideFlag, widget.render(this.wg));
2776
+ let dom = widget.render(this.wg);
2777
+ if (!widget.type.editable)
2778
+ setUneditable(dom);
2779
+ tile = new WidgetTile(widget, null, 16 | sideFlag, dom);
2758
2780
  if (widget.type.connect)
2759
2781
  this.toConnect.push(tile);
2760
2782
  }
@@ -2789,11 +2811,13 @@ class ContentUpdate {
2789
2811
  }
2790
2812
  return null;
2791
2813
  }
2792
- buildNodeShape(node, shape, reuse, afterContent = 0) {
2814
+ buildNodeShape(node, shape, reuse, inEditable = true, afterContent = 0) {
2793
2815
  if (shape instanceof Elt) {
2794
- if (node && !shape.hasContent && Attributes.get(shape.attrs, "contenteditable") == null &&
2795
- !/^(br|hr|img|input|wbr)$/i.test(shape.tagName))
2796
- shape = Elt.create(shape.tagName, Attributes.merge(shape.attrs, ["contenteditable", "false"]), shape.children);
2816
+ if (inEditable && !shape.hasContent) {
2817
+ if (Attributes.get(shape.attrs, "contenteditable") == null && !/^(br|hr|img|input|wbr)$/i.test(shape.tagName))
2818
+ shape = Elt.create(shape.tagName, Attributes.merge(shape.attrs, ["contenteditable", "false"]), shape.children);
2819
+ inEditable = false;
2820
+ }
2797
2821
  let reusable, dom, strict = true;
2798
2822
  if (reusable = this.findReusableTile(shape, reuse, strict) || this.findReusableTile(shape, reuse, strict = false)) {
2799
2823
  this.reused.set(reusable, 2);
@@ -2813,7 +2837,7 @@ class ContentUpdate {
2813
2837
  tile.flags |= 2;
2814
2838
  }
2815
2839
  else {
2816
- tile.addChild(this.buildNodeShape(null, typeof ch == "string" ? Widget.Text.of(ch) : ch, reusable ? reusable.children : reuse, afterContentInner));
2840
+ tile.addChild(this.buildNodeShape(null, typeof ch == "string" ? Widget.text.of(ch) : ch, reusable ? reusable.children : reuse, inEditable, afterContentInner));
2817
2841
  }
2818
2842
  }
2819
2843
  return tile;
@@ -2824,8 +2848,13 @@ class ContentUpdate {
2824
2848
  this.reused.set(reusable, 2);
2825
2849
  dom = reusable.dom;
2826
2850
  }
2851
+ else {
2852
+ dom = shape.render(this.wg);
2853
+ }
2854
+ if (inEditable && !shape.type.editable)
2855
+ setUneditable(dom);
2827
2856
  let flags = (node ? 512 : 16 | 1) | afterContent;
2828
- let tile = new WidgetTile(shape, node, flags, dom || shape.render(this.wg), node ? node.length : 0);
2857
+ let tile = new WidgetTile(shape, node, flags, dom, node ? node.length : 0);
2829
2858
  if (shape.type.connect)
2830
2859
  this.toConnect.push(tile);
2831
2860
  return tile;
@@ -3783,7 +3812,7 @@ class DOMObserver {
3783
3812
  let tile = this.wg.docTile.nearest(record.target);
3784
3813
  if (!tile || tile.ignoreMutations)
3785
3814
  return null;
3786
- tile.flags |= 8192;
3815
+ tile.markDirty();
3787
3816
  if (record.type == "attributes" || record.type == "characterData") {
3788
3817
  if (tile == this.wg.docTile) {
3789
3818
  return null;
@@ -3917,7 +3946,8 @@ class KeyBinding {
3917
3946
  shift: Command.bind(moveToTextblockSide, { dir: "forward", extend: true }) },
3918
3947
  { mac: "Ctrl-d", run: Command.bind(deleteUnit, "forward") },
3919
3948
  { mac: "Ctrl-h", run: Command.bind(deleteUnit, "backward") },
3920
- { mac: "Ctrl-k", run: Command.bind(deleteToLineEnd, "forward") },
3949
+ { mac: "Ctrl-k", run: killToLineEnd },
3950
+ { mac: "Ctrl-y", run: yankKilled },
3921
3951
  { mac: "Ctrl-Alt-h", run: Command.bind(deleteWord, "backward") },
3922
3952
  { mac: "Ctrl-o", run: insertLineBreak },
3923
3953
  { mac: "Ctrl-t", run: transposeChars },
@@ -4620,9 +4650,9 @@ function compositionUpdate(wg, event) {
4620
4650
  if (!event.data) {
4621
4651
  let sel = wg.state.selection, rSel = wg.state.sel;
4622
4652
  if (sel.empty && (sel instanceof GardSelection.Text && sel.marks || !rSel.head.inText && rSel.head.index) &&
4623
- !eqArray(rSel.head.nodeBefore?.tag.marks, rSel.activeMarks))
4624
- wrap = rSel.activeMarks;
4625
- else if (sel.empty && inlineBoundNear(wg.state.sel.head))
4653
+ !eqArray(rSel.head.nodeBefore?.tag.marks, rSel.activeMarks) ||
4654
+ sel.empty && inlineBoundNear(wg.state.sel.head) ||
4655
+ !inEditableDOM(wg, wg.observer.selectionRange.focusNode))
4626
4656
  wrap = rSel.activeMarks;
4627
4657
  }
4628
4658
  if (wrap)
@@ -4642,6 +4672,12 @@ function inlineBoundNear(pos) {
4642
4672
  return (index ? parent.node.content[index - 1].isPlot : parent.node.isInline) ||
4643
4673
  (index < parent.node.content.length ? parent.node.content[index].isPlot : parent.node.isInline);
4644
4674
  }
4675
+ function inEditableDOM(wg, node) {
4676
+ if (!node)
4677
+ return false;
4678
+ let tile = wg.docTile.nearest(node);
4679
+ return tile ? !(tile.isPoint || tile instanceof WidgetTile) : false;
4680
+ }
4645
4681
  function isDeletionInputEvent(type) { return /^delete(Content|Word)/.test(type); }
4646
4682
  const inputTypeCommands = /*@__PURE__*/(() => ({
4647
4683
  historyUndo: undo,
@@ -4781,16 +4817,17 @@ const baseHandlers = {
4781
4817
  data: event.data,
4782
4818
  domRange: null,
4783
4819
  };
4784
- let ranges = event.getTargetRanges();
4820
+ let ranges = event.getTargetRanges(), editable = true;
4785
4821
  if (ranges.length) {
4786
- let r = ranges[0];
4787
- data.domRange = { from: wg.inputState.getDOMPos(r.startContainer, r.startOffset),
4788
- to: wg.inputState.getDOMPos(r.endContainer, r.endOffset) };
4822
+ let r = ranges[0], empty = r.collapsed;
4823
+ let from = wg.inputState.getDOMPos(r.startContainer, r.startOffset);
4824
+ data.domRange = { from, to: empty ? from : wg.inputState.getDOMPos(r.endContainer, r.endOffset) };
4825
+ editable = inEditableDOM(wg, r.startContainer) && (empty || inEditableDOM(wg, r.endContainer));
4789
4826
  }
4790
4827
  wg.inputState.beforeInput(event, wg.inputState.pendingInputEvent = data);
4791
4828
  wg.scheduleFlush();
4792
4829
  let allow = type == "insertCompositionText" ||
4793
- (type == "insertText" || isDeletionInputEvent(type) &&
4830
+ editable && (type == "insertText" || isDeletionInputEvent(type) &&
4794
4831
  data.domRange && inlineContext(wg.inputState.domDoc, data.domRange));
4795
4832
  return !allow;
4796
4833
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nerd-bible/wordgard",
3
- "version": "0.5.2-beta2",
3
+ "version": "0.5.2-beta4",
4
4
  "description": "Semantic rich text editor system",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -36,7 +36,7 @@
36
36
  "style-mod": "^4.1.3"
37
37
  },
38
38
  "devDependencies": {
39
- "@nerd-bible/config": "^0.2.2",
39
+ "@nerd-bible/config": "^0.2.4",
40
40
  "@swc/wasm-typescript": "^1.15.3",
41
41
  "@types/mocha": "^10.0.10",
42
42
  "@types/node": "^24.10.2",