smeditor 0.2.1 → 0.2.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 84ee0bbaa2884f82336e20cf7962934d728d539ab71a68c87c865c09122d1100
4
- data.tar.gz: 80da9de751d692cb0398e80f9b3017324fbf848873dc6a2e73dfa3c85fe9c8fb
3
+ metadata.gz: deea7d855b9ea5c7d61a51d82adeb656e3583db0dc9ed8d677345fe2d1bac550
4
+ data.tar.gz: 99a68a8823548919c2acb1aaea114822b677e33d464cd37a66f42fe4cc802e73
5
5
  SHA512:
6
- metadata.gz: 1a905c9df109f03de095aab6652d2eeedd1d42acffeb505a020872c6ffaf5ad88b4ea3cb7cdf5a518b449528b009c6eb53735ef3d61aa50ad6cc554f19114aeb
7
- data.tar.gz: eb385c65cbae2a229035f98a66950f160d7d301c475cf9976429eebda3e1cc32faf3acfe3206c3478689f9567d33d78a02554dae6d3fe58f01bd3b7a21dadd9c
6
+ metadata.gz: 6cf34629807ab5b326dff8ddaa85e80bc2f4b5c7de86a233e4d2a9c1196a3151df18af818f658f6826e0f21c7d90317c8f190df1697f5ecc8501c4f24511c9b7
7
+ data.tar.gz: 3f72f9d9fc819294563dd2519eb07e84dd159432fd2bc8ad6111b0ed125c46790163ef7caae49ae1b76ea7ced5406baf65b1dc9a2350e6115edc15b34c3d57bc
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog — smeditor
2
2
 
3
+ ## 0.2.2 — 2026-09-09
4
+
5
+ - Fixed caret jumps and reordered typing inside the Rails Shadow DOM editor. The core now resolves the live DOM Selection from the editor's own root instead of always using `document.getSelection()`.
6
+ - Selection restore and caret coordinate ranges now use the editor element's owner document, keeping the DOM integration correct in isolated roots and embedded documents.
7
+
3
8
  ## 0.2.1 — 2026-09-09
4
9
 
5
10
  - Rails editor now renders inside Shadow DOM so host application CSS cannot alter the SMEditor toolbar or editing surface.
@@ -763,14 +763,14 @@ class Editor {
763
763
  */
764
764
  coordsAtPoint(point) {
765
765
  var _a;
766
- if (!this.element || typeof document === "undefined")
766
+ if (!this.element)
767
767
  return null;
768
768
  const deep = (_a = this.options.deepSelection) !== null && _a !== void 0 ? _a : false;
769
769
  const loc = domNodeFromPoint(point, this.element, deep);
770
770
  if (!loc)
771
771
  return null;
772
772
  try {
773
- const range = document.createRange();
773
+ const range = this.element.ownerDocument.createRange();
774
774
  const offset = Math.min(loc.offset, lengthOf(loc.node));
775
775
  range.setStart(loc.node, offset);
776
776
  range.collapse(true);
@@ -1243,9 +1243,7 @@ class Editor {
1243
1243
  var _a, _b;
1244
1244
  if (this.updatingDOM || !this.element)
1245
1245
  return;
1246
- if (typeof document === "undefined")
1247
- return;
1248
- const domSel = document.getSelection();
1246
+ const domSel = selectionForElement(this.element);
1249
1247
  if (!domSel)
1250
1248
  return;
1251
1249
  if (!this.element.contains(domSel.anchorNode))
@@ -1267,9 +1265,9 @@ class Editor {
1267
1265
  }
1268
1266
  readSelectionFromDOM() {
1269
1267
  var _a;
1270
- if (!this.element || typeof document === "undefined")
1268
+ if (!this.element)
1271
1269
  return null;
1272
- const sel = document.getSelection();
1270
+ const sel = selectionForElement(this.element);
1273
1271
  if (!sel || sel.rangeCount === 0)
1274
1272
  return null;
1275
1273
  const deep = (_a = this.options.deepSelection) !== null && _a !== void 0 ? _a : false;
@@ -1290,10 +1288,10 @@ class Editor {
1290
1288
  }
1291
1289
  applySelectionToDOM() {
1292
1290
  var _a;
1293
- if (!this.selection || !this.element || typeof document === "undefined") {
1291
+ if (!this.selection || !this.element) {
1294
1292
  return;
1295
1293
  }
1296
- const sel = document.getSelection();
1294
+ const sel = selectionForElement(this.element);
1297
1295
  if (!sel)
1298
1296
  return;
1299
1297
  const deep = (_a = this.options.deepSelection) !== null && _a !== void 0 ? _a : false;
@@ -1302,7 +1300,7 @@ class Editor {
1302
1300
  if (!anchorNode || !headNode)
1303
1301
  return;
1304
1302
  try {
1305
- const range = document.createRange();
1303
+ const range = this.element.ownerDocument.createRange();
1306
1304
  range.setStart(anchorNode.node, Math.min(anchorNode.offset, lengthOf(anchorNode.node)));
1307
1305
  range.setEnd(headNode.node, Math.min(headNode.offset, lengthOf(headNode.node)));
1308
1306
  sel.removeAllRanges();
@@ -1353,6 +1351,30 @@ class Editor {
1353
1351
  // ============================================================================
1354
1352
  // Helpers (module-private)
1355
1353
  // ============================================================================
1354
+ /**
1355
+ * Return the Selection object that actually owns the editor caret.
1356
+ *
1357
+ * `document.getSelection()` is not sufficient for editors mounted inside an
1358
+ * open ShadowRoot: Chromium exposes a composed selection on the document whose
1359
+ * anchor can be the shadow host instead of the text node inside the editor.
1360
+ * Reading that selection produces a null/wrong editor position; the next DOM
1361
+ * render then loses the caret (most visibly when typing spaces).
1362
+ *
1363
+ * Both Document and Chromium's ShadowRoot expose getSelection(). Prefer the
1364
+ * editor's root and fall back to its owner document for browsers that do not
1365
+ * expose ShadowRoot#getSelection.
1366
+ */
1367
+ function selectionForElement(element) {
1368
+ var _a, _b, _c, _d;
1369
+ const root = (_a = element.getRootNode) === null || _a === void 0 ? void 0 : _a.call(element);
1370
+ const rootedGetSelection = root === null || root === void 0 ? void 0 : root.getSelection;
1371
+ if (root && typeof rootedGetSelection === "function") {
1372
+ const selection = rootedGetSelection.call(root);
1373
+ if (selection)
1374
+ return selection;
1375
+ }
1376
+ return (_d = (_c = (_b = element.ownerDocument) === null || _b === void 0 ? void 0 : _b.getSelection) === null || _c === void 0 ? void 0 : _c.call(_b)) !== null && _d !== void 0 ? _d : null;
1377
+ }
1356
1378
  /**
1357
1379
  * Strip noise and unsafe elements from pasted HTML.
1358
1380
  *
@@ -2,6 +2,6 @@
2
2
 
3
3
  module SMEditor
4
4
  module Rails
5
- VERSION = "0.2.1"
5
+ VERSION = "0.2.2"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smeditor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - SMEditor contributors
@@ -96,7 +96,7 @@ metadata:
96
96
  source_code_uri: https://github.com/sCruze/smeditor/tree/main/gems/smeditor
97
97
  changelog_uri: https://github.com/sCruze/smeditor/blob/main/gems/smeditor/CHANGELOG.md
98
98
  bug_tracker_uri: https://github.com/sCruze/smeditor/issues
99
- documentation_uri: https://rubydoc.info/gems/smeditor/0.2.1
99
+ documentation_uri: https://rubydoc.info/gems/smeditor/0.2.2
100
100
  rubygems_mfa_required: 'true'
101
101
  rdoc_options: []
102
102
  require_paths: