lexxy 0.9.25 → 0.9.27

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: 92ba1a84cc251d9d9b65ab65cb2dbd24fb1e8180456855cc32620efa0d3b5e85
4
- data.tar.gz: 5f2f17fe5d328e1e8961067cd297692d87fa70901c81b9c55527cb5ac3887503
3
+ metadata.gz: 1ef504d8ff6c3ee45519815bb36ea8c2d21316f8032c87967602138c88f4457b
4
+ data.tar.gz: 95e79bbbccdffe031d6938acce662d7d466fc248c63b609d0b6a058e9f586da1
5
5
  SHA512:
6
- metadata.gz: b281de9a7ad1d3ca00bee0ddb2f5841eda6db4747d20421d127fb375f01d20b509052bb006cd168a8def21ff59c1c2f71cd0362817cca70aa7881caf6883e1b2
7
- data.tar.gz: bf512346a4f6bfab93053150eda97fa1f0c04915a29fc2c06a1187ce76b295bd3c5cfb0dc72d14698d6a0cf7631af9ffa6a2e5edb10ae4627693502877d14f6d
6
+ metadata.gz: d600ab9f59fa036b56143d081ecadecde64c24f674639d64067add0bebb276ab4da142c0022802e6cfe5c656902f866ae4fecc80a37ba63e8385d567e3517caa
7
+ data.tar.gz: a0eb4b38a69a6f436a611f5023e078bfff26b37152603f2f3d923256c1e57672845c0bed337cec6c38989582e400be3a24ff7d9e803782d0c56dc94bb5f7995f
data/README.md CHANGED
@@ -21,6 +21,7 @@ A modern rich text editor for Rails.
21
21
 
22
22
  - Bug reports and pull requests are welcome on [GitHub Issues](https://github.com/basecamp/lexxy/issues). Help is especially welcome with [those tagged as "Help Wanted"](https://github.com/basecamp/lexxy/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22help%20wanted%22).
23
23
  - For questions and general Lexxy discussion, please use the [Discussions section](https://github.com/basecamp/lexxy/discussions)
24
+ - To build with a development version of Lexical, use `bin/link-to-local-lexical`.
24
25
 
25
26
  ## License
26
27
 
@@ -11085,10 +11085,34 @@ class Selection {
11085
11085
 
11086
11086
  this.editor.registerCommand(ie$4, () => {
11087
11087
  this.#syncSelectedClasses();
11088
- }, io)
11088
+ }, io),
11089
+
11090
+ this.editor.registerCommand(ie$4, () => {
11091
+ this.#preserveFocusOfOtherFields();
11092
+ return false
11093
+ }, lo)
11089
11094
  );
11090
11095
  }
11091
11096
 
11097
+ // Firefox (152+) keeps window.getSelection() anchored inside the editor after focus
11098
+ // moves to another field, and fires document selectionchange for every keystroke
11099
+ // typed there. Lexical reads that stale selection, reconciles, and pulls focus back
11100
+ // into the editor — stealing it mid-typing. When another text-entry field owns focus,
11101
+ // tag the update so Lexical leaves the DOM selection (and with it, focus) alone.
11102
+ #preserveFocusOfOtherFields() {
11103
+ if (this.#anotherFieldIsFocused) {
11104
+ Os(qn);
11105
+ }
11106
+ }
11107
+
11108
+ get #anotherFieldIsFocused() {
11109
+ const rootElement = this.editor.getRootElement();
11110
+ const activeElement = rootElement?.ownerDocument.activeElement;
11111
+
11112
+ return activeElement && !rootElement.contains(activeElement) &&
11113
+ (activeElement.tagName === "INPUT" || activeElement.tagName === "TEXTAREA" || activeElement.isContentEditable)
11114
+ }
11115
+
11092
11116
  #listenForNodeSelections() {
11093
11117
  this.#listeners.track(this.editor.registerCommand(se$5, ({ target }) => {
11094
11118
  if (!qs(target)) return false
@@ -12485,6 +12509,7 @@ class PastedContentFormatter {
12485
12509
  this.#stripStyleElements();
12486
12510
  this.#unwrapPlaceholderAnchors();
12487
12511
  this.#stripTableCellColorStyles();
12512
+ this.#unwrapWrappedListChildren();
12488
12513
  this.#nestStrayListChildren();
12489
12514
  this.#stripStrayListChildren();
12490
12515
  return this.doc
@@ -12526,6 +12551,29 @@ class PastedContentFormatter {
12526
12551
  }
12527
12552
  }
12528
12553
 
12554
+ // Some sources wrap runs of <li>s in a stray element (e.g. a <div> directly
12555
+ // inside the list). Dissolve such wrappers so their items become direct
12556
+ // list children and any nested list they hide becomes visible to
12557
+ // #nestStrayListChildren below.
12558
+ #unwrapWrappedListChildren() {
12559
+ for (const list of this.doc.querySelectorAll("ol, ul")) {
12560
+ let wrapper = this.#wrappedListChild(list);
12561
+ while (wrapper) {
12562
+ wrapper.replaceWith(...wrapper.childNodes);
12563
+ wrapper = this.#wrappedListChild(list);
12564
+ }
12565
+ }
12566
+ }
12567
+
12568
+ #wrappedListChild(list) {
12569
+ for (const child of list.children) {
12570
+ if (child.tagName !== "LI" && !this.#isNestedList(child) && this.#containsListItems(child)) {
12571
+ return child
12572
+ }
12573
+ }
12574
+ return null
12575
+ }
12576
+
12529
12577
  // Some sources (e.g. Gmail) nest a sublist as a direct child of the parent
12530
12578
  // <ol>/<ul> instead of inside a <li>. Move each nested list into its
12531
12579
  // preceding <li> so the import preserves the nesting instead of dropping it.
@@ -12542,16 +12590,41 @@ class PastedContentFormatter {
12542
12590
  }
12543
12591
  }
12544
12592
 
12545
- // Only <li> is a valid child of a list; drop stray <br>/whitespace so the
12546
- // import doesn't wrap them into an empty leading item.
12593
+ // Only <li> is a valid child of a list. Unwrap remaining stray children
12594
+ // that still hold list items (a nested list with no preceding <li> to nest
12595
+ // under) so the items survive, and drop stray <br>/whitespace so the import
12596
+ // doesn't wrap them into an empty leading item.
12547
12597
  #stripStrayListChildren() {
12548
12598
  for (const list of this.doc.querySelectorAll("ol, ul")) {
12549
- for (const child of Array.from(list.childNodes)) {
12550
- if (child.nodeType === Node.ELEMENT_NODE && child.tagName === "LI") continue
12551
- list.removeChild(child);
12599
+ let stray = this.#firstStrayListChild(list);
12600
+ while (stray) {
12601
+ if (this.#containsListItems(stray)) {
12602
+ stray.replaceWith(...stray.childNodes);
12603
+ } else {
12604
+ stray.remove();
12605
+ }
12606
+
12607
+ stray = this.#firstStrayListChild(list);
12552
12608
  }
12553
12609
  }
12554
12610
  }
12611
+
12612
+ #firstStrayListChild(list) {
12613
+ for (const child of list.childNodes) {
12614
+ if (child.nodeType !== Node.ELEMENT_NODE || child.tagName !== "LI") {
12615
+ return child
12616
+ }
12617
+ }
12618
+ return null
12619
+ }
12620
+
12621
+ #isNestedList(node) {
12622
+ return node.nodeType === Node.ELEMENT_NODE && (node.tagName === "OL" || node.tagName === "UL")
12623
+ }
12624
+
12625
+ #containsListItems(node) {
12626
+ return node.nodeType === Node.ELEMENT_NODE && node.querySelector("li") !== null
12627
+ }
12555
12628
  }
12556
12629
 
12557
12630
  class Contents {
Binary file
Binary file