@37signals/lexxy 0.9.6-beta.bc0 → 0.9.7-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/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  A modern rich text editor for Rails.
4
4
 
5
5
  > [!IMPORTANT]
6
- > This is an early beta. It hasn't been battle-tested yet. Please try it out and report any issues you find.
6
+ > This is a beta. It hasn't been battle-tested yet. Please try it out and report any issues you find.
7
7
 
8
8
  **[Try it out!](https://basecamp.github.io/lexxy/try-it)**
9
9
 
@@ -26,7 +26,7 @@ Visit the **[documentation site](https://basecamp.github.io/lexxy)**.
26
26
 
27
27
  ## Roadmap
28
28
 
29
- This is an early beta. Here's what's coming next:
29
+ This is a beta. Here's what's coming next:
30
30
 
31
31
  - [x] Configurable editors in Action Text: Choose your editor like you choose your database.
32
32
  - [x] More editing features:
package/dist/lexxy.esm.js CHANGED
@@ -2186,7 +2186,7 @@ class CommandDispatcher {
2186
2186
 
2187
2187
  dispatchInsertUnorderedList() {
2188
2188
  const selection = $getSelection();
2189
- if (!selection) return
2189
+ if (!$isRangeSelection(selection)) return
2190
2190
 
2191
2191
  const anchorNode = selection.anchor.getNode();
2192
2192
 
@@ -2199,7 +2199,7 @@ class CommandDispatcher {
2199
2199
 
2200
2200
  dispatchInsertOrderedList() {
2201
2201
  const selection = $getSelection();
2202
- if (!selection) return
2202
+ if (!$isRangeSelection(selection)) return
2203
2203
 
2204
2204
  const anchorNode = selection.anchor.getNode();
2205
2205
 
@@ -2491,6 +2491,15 @@ function capitalize(str) {
2491
2491
  return str.charAt(0).toUpperCase() + str.slice(1)
2492
2492
  }
2493
2493
 
2494
+ function debounce(fn, wait) {
2495
+ let timeout;
2496
+
2497
+ return (...args) => {
2498
+ clearTimeout(timeout);
2499
+ timeout = setTimeout(() => fn(...args), wait);
2500
+ }
2501
+ }
2502
+
2494
2503
  function debounceAsync(fn, wait) {
2495
2504
  let timeout;
2496
2505
 
@@ -5914,9 +5923,9 @@ class AttachmentDragAndDrop {
5914
5923
  // -- Event handlers --------------------------------------------------------
5915
5924
 
5916
5925
  #handleDragStart(event) {
5917
- if (event.target.closest("textarea")) return false
5926
+ if (event.target.closest?.("textarea")) return false
5918
5927
 
5919
- const figure = event.target.closest("figure.attachment[data-lexical-node-key]");
5928
+ const figure = event.target.closest?.("figure.attachment[data-lexical-node-key]");
5920
5929
  if (!figure) return false
5921
5930
 
5922
5931
  this.#draggedNodeKey = figure.dataset.lexicalNodeKey;
@@ -7507,6 +7516,8 @@ class BaseSource {
7507
7516
  }
7508
7517
  }
7509
7518
 
7519
+ const MAX_RENDERED_SUGGESTIONS$1 = 100;
7520
+
7510
7521
  class LocalFilterSource extends BaseSource {
7511
7522
  async buildListItems(filter = "") {
7512
7523
  const promptItems = await this.fetchPromptItems();
@@ -7525,7 +7536,10 @@ class LocalFilterSource extends BaseSource {
7525
7536
  #buildListItemsFromPromptItems(promptItems, filter) {
7526
7537
  const listItems = [];
7527
7538
  this.promptItemByListItem = new WeakMap();
7528
- promptItems.forEach((promptItem) => {
7539
+
7540
+ for (const promptItem of promptItems) {
7541
+ if (listItems.length >= MAX_RENDERED_SUGGESTIONS$1) break
7542
+
7529
7543
  const searchableText = promptItem.getAttribute("search");
7530
7544
 
7531
7545
  if (!filter || filterMatches(searchableText, filter)) {
@@ -7533,7 +7547,7 @@ class LocalFilterSource extends BaseSource {
7533
7547
  this.promptItemByListItem.set(listItem, promptItem);
7534
7548
  listItems.push(listItem);
7535
7549
  }
7536
- });
7550
+ }
7537
7551
 
7538
7552
  return listItems
7539
7553
  }
@@ -7566,6 +7580,7 @@ class DeferredPromptSource extends LocalFilterSource {
7566
7580
  }
7567
7581
 
7568
7582
  const DEBOUNCE_INTERVAL = 200;
7583
+ const MAX_RENDERED_SUGGESTIONS = 100;
7569
7584
 
7570
7585
  class RemoteFilterSource extends BaseSource {
7571
7586
  constructor(url) {
@@ -7599,6 +7614,8 @@ class RemoteFilterSource extends BaseSource {
7599
7614
  this.promptItemByListItem = new WeakMap();
7600
7615
 
7601
7616
  for (const promptItem of promptItems) {
7617
+ if (listItems.length >= MAX_RENDERED_SUGGESTIONS) break
7618
+
7602
7619
  const listItem = this.buildListItemElementFor(promptItem);
7603
7620
  this.promptItemByListItem.set(listItem, promptItem);
7604
7621
  listItems.push(listItem);
@@ -7609,10 +7626,12 @@ class RemoteFilterSource extends BaseSource {
7609
7626
  }
7610
7627
 
7611
7628
  const NOTHING_FOUND_DEFAULT_MESSAGE = "Nothing found";
7629
+ const FILTER_DEBOUNCE_INTERVAL = 50;
7612
7630
 
7613
7631
  class LexicalPromptElement extends HTMLElement {
7614
7632
  #globalListeners = new ListenerBin()
7615
7633
  #popoverListeners = new ListenerBin()
7634
+ #debouncedFilterOptions = debounce(() => this.#filterOptions(), FILTER_DEBOUNCE_INTERVAL)
7616
7635
 
7617
7636
  constructor() {
7618
7637
  super();
@@ -7770,7 +7789,7 @@ class LexicalPromptElement extends HTMLElement {
7770
7789
 
7771
7790
  this.#popoverListeners.track(
7772
7791
  registerEventListener(this.#editorElement, "keydown", this.#handleKeydownOnPopover),
7773
- registerEventListener(this.#editorElement, "lexxy:change", this.#filterOptions)
7792
+ registerEventListener(this.#editorElement, "lexxy:change", this.#debouncedFilterOptions)
7774
7793
  );
7775
7794
 
7776
7795
  this.#registerKeyListeners();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@37signals/lexxy",
3
- "version": "0.9.6-beta.bc0",
3
+ "version": "0.9.7-beta",
4
4
  "description": "Lexxy - A modern rich text editor for Rails.",
5
5
  "module": "dist/lexxy.esm.js",
6
6
  "type": "module",