lexxy 0.1.19.beta → 0.1.20.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0edf37852f38dc8deb59194838075da7752d5a54fa8d56e3d483b640d2afb950
4
- data.tar.gz: 61e0232d676d0358fc605e56d494bf981c38ba6586f9901b2eea77d51d5415f4
3
+ metadata.gz: 28ddded3fff65c55a5e194a1ba8246411fad9193b32ab319cc5a6330ab999420
4
+ data.tar.gz: 98a6bf19a11687400a21baed5117d65de05f02e595f3d7684f1fb70f8c8ffeea
5
5
  SHA512:
6
- metadata.gz: 8d68a219385971dd5cead807b78144911ab3fc89224d5493cc3706e4ecca0ce2cbf965966ab016c4bfa872c234be5c1d5be9e12fc9e273a561b7324a47f0bb11
7
- data.tar.gz: 7f70f60e226d2dc13d29aa754a0b04ad54c784c1d66785a5754848a1cafe0e5f5d7553b727c581637e8c60faba6cd087e2fa18d68bb59d2cf18ebb556df382f9
6
+ metadata.gz: 00025443273a087c88de7463ab211f85e1e887ee3e33958f4813101c370f6f5949d79e88ba1c3e4347f77d4a5aaebf0231215f2af86e3fdaab35ce230572927f
7
+ data.tar.gz: ebb4db2b79be6937eca5af5e77aa62c8efd41a8e5bb6af0576865dd2f415f6d8de26f2e8c476e60c5f648ef0ce37cd1333e2490efd5c8c4fc5b4f28367d0f870
@@ -6208,8 +6208,10 @@ class CommandDispatcher {
6208
6208
 
6209
6209
  dispatchInsertHorizontalDivider() {
6210
6210
  this.editor.update(() => {
6211
- this.contents.insertAtCursor(new HorizontalDividerNode());
6211
+ this.contents.insertAtCursorEnsuringLineBelow(new HorizontalDividerNode());
6212
6212
  });
6213
+
6214
+ this.editor.focus();
6213
6215
  }
6214
6216
 
6215
6217
  dispatchRotateHeadingFormat() {
@@ -6421,6 +6423,52 @@ class Selection {
6421
6423
  });
6422
6424
  }
6423
6425
 
6426
+ selectedNodeWithOffset() {
6427
+ const selection = Lr();
6428
+ if (!selection) return { node: null, offset: 0 }
6429
+
6430
+ if (yr(selection)) {
6431
+ return {
6432
+ node: selection.anchor.getNode(),
6433
+ offset: selection.anchor.offset
6434
+ }
6435
+ } else if (xr(selection)) {
6436
+ const [ node ] = selection.getNodes();
6437
+ return {
6438
+ node,
6439
+ offset: 0
6440
+ }
6441
+ }
6442
+
6443
+ return { node: null, offset: 0 }
6444
+ }
6445
+
6446
+ preservingSelection(fn) {
6447
+ let selectionState = null;
6448
+
6449
+ this.editor.getEditorState().read(() => {
6450
+ const selection = Lr();
6451
+ if (selection && yr(selection)) {
6452
+ selectionState = {
6453
+ anchor: { key: selection.anchor.key, offset: selection.anchor.offset },
6454
+ focus: { key: selection.focus.key, offset: selection.focus.offset }
6455
+ };
6456
+ }
6457
+ });
6458
+
6459
+ fn();
6460
+
6461
+ if (selectionState) {
6462
+ this.editor.update(() => {
6463
+ const selection = Lr();
6464
+ if (selection && yr(selection)) {
6465
+ selection.anchor.set(selectionState.anchor.key, selectionState.anchor.offset, "text");
6466
+ selection.focus.set(selectionState.focus.key, selectionState.focus.offset, "text");
6467
+ }
6468
+ });
6469
+ }
6470
+ }
6471
+
6424
6472
  get hasSelectedWordsInSingleLine() {
6425
6473
  const selection = Lr();
6426
6474
  if (!yr(selection)) return false
@@ -7378,6 +7426,11 @@ class Contents {
7378
7426
  });
7379
7427
  }
7380
7428
 
7429
+ insertAtCursorEnsuringLineBelow(node) {
7430
+ this.insertAtCursor(node);
7431
+ this.#insertLineBelowIfLastNode(node);
7432
+ }
7433
+
7381
7434
  insertNodeWrappingEachSelectedLine(newNodeFn) {
7382
7435
  this.editor.update(() => {
7383
7436
  const selection = Lr();
@@ -7662,6 +7715,17 @@ class Contents {
7662
7715
  return this.editorElement.selection
7663
7716
  }
7664
7717
 
7718
+ #insertLineBelowIfLastNode(node) {
7719
+ this.editor.update(() => {
7720
+ const nextSibling = node.getNextSibling();
7721
+ if (!nextSibling) {
7722
+ const newParagraph = Li();
7723
+ node.insertAfter(newParagraph);
7724
+ newParagraph.selectStart();
7725
+ }
7726
+ });
7727
+ }
7728
+
7665
7729
  #unwrap(node) {
7666
7730
  const children = node.getChildren();
7667
7731
 
@@ -8004,7 +8068,8 @@ class Contents {
8004
8068
  lastInsertedNode.insertAfter(textNodeAfter);
8005
8069
 
8006
8070
  this.#appendLineBreakIfNeeded(textNodeAfter.getParentOrThrow());
8007
- textNodeAfter.select(0, 0);
8071
+ const cursorOffset = textAfterCursor ? 0 : 1;
8072
+ textNodeAfter.select(cursorOffset, cursorOffset);
8008
8073
  }
8009
8074
 
8010
8075
  #insertReplacementNodes(startNode, replacementNodes) {
@@ -8866,6 +8931,14 @@ class LexicalPromptElement extends HTMLElement {
8866
8931
  return this.hasAttribute("supports-space-in-searches")
8867
8932
  }
8868
8933
 
8934
+ get open() {
8935
+ return this.popoverElement?.classList?.contains("lexxy-prompt-menu--visible")
8936
+ }
8937
+
8938
+ get closed() {
8939
+ return !this.open
8940
+ }
8941
+
8869
8942
  get #doesSpaceSelect() {
8870
8943
  return !this.supportsSpaceInSearches
8871
8944
  }
@@ -8886,20 +8959,14 @@ class LexicalPromptElement extends HTMLElement {
8886
8959
  #addTriggerListener() {
8887
8960
  const unregister = this.#editor.registerUpdateListener(() => {
8888
8961
  this.#editor.read(() => {
8889
- const selection = Lr();
8890
- if (!selection) return
8891
- let node;
8892
- if (yr(selection)) {
8893
- node = selection.anchor.getNode();
8894
- } else if (xr(selection)) {
8895
- [ node ] = selection.getNodes();
8896
- }
8962
+ const { node, offset } = this.#selection.selectedNodeWithOffset();
8963
+ if (!node) return
8897
8964
 
8898
- if (node && lr(node)) {
8899
- const text = node.getTextContent().trim();
8900
- const lastChar = [ ...text ].pop();
8965
+ if (lr(node) && offset > 0) {
8966
+ const fullText = node.getTextContent();
8967
+ const charBeforeCursor = fullText[offset - 1];
8901
8968
 
8902
- if (lastChar === this.trigger) {
8969
+ if (charBeforeCursor === this.trigger) {
8903
8970
  unregister();
8904
8971
  this.#showPopover();
8905
8972
  }
@@ -8908,6 +8975,38 @@ class LexicalPromptElement extends HTMLElement {
8908
8975
  });
8909
8976
  }
8910
8977
 
8978
+ #addCursorPositionListener() {
8979
+ this.cursorPositionListener = this.#editor.registerUpdateListener(() => {
8980
+ if (this.closed) return
8981
+
8982
+ this.#editor.read(() => {
8983
+ const { node, offset } = this.#selection.selectedNodeWithOffset();
8984
+ if (!node) return
8985
+
8986
+ if (lr(node) && offset > 0) {
8987
+ const fullText = node.getTextContent();
8988
+ const textBeforeCursor = fullText.slice(0, offset);
8989
+ const lastTriggerIndex = textBeforeCursor.lastIndexOf(this.trigger);
8990
+
8991
+ // If trigger is not found, or cursor is at or before the trigger position, hide popover
8992
+ if (lastTriggerIndex === -1 || offset <= lastTriggerIndex) {
8993
+ this.#hidePopover();
8994
+ }
8995
+ } else {
8996
+ // Cursor is not in a text node or at offset 0, hide popover
8997
+ this.#hidePopover();
8998
+ }
8999
+ });
9000
+ });
9001
+ }
9002
+
9003
+ #removeCursorPositionListener() {
9004
+ if (this.cursorPositionListener) {
9005
+ this.cursorPositionListener();
9006
+ this.cursorPositionListener = null;
9007
+ }
9008
+ }
9009
+
8911
9010
  get #editor() {
8912
9011
  return this.#editorElement.editor
8913
9012
  }
@@ -8931,6 +9030,7 @@ class LexicalPromptElement extends HTMLElement {
8931
9030
  this.#editorElement.addEventListener("lexxy:change", this.#filterOptions);
8932
9031
 
8933
9032
  this.#registerKeyListeners();
9033
+ this.#addCursorPositionListener();
8934
9034
  }
8935
9035
 
8936
9036
  #registerKeyListeners() {
@@ -8941,6 +9041,22 @@ class LexicalPromptElement extends HTMLElement {
8941
9041
  if (this.#doesSpaceSelect) {
8942
9042
  this.keyListeners.push(this.#editor.registerCommand(be$1, this.#handleSelectedOption.bind(this), Bi));
8943
9043
  }
9044
+
9045
+ // Register arrow keys with HIGH priority to prevent Lexical's selection handlers from running
9046
+ this.keyListeners.push(this.#editor.registerCommand(ke$1, this.#handleArrowUp.bind(this), Bi));
9047
+ this.keyListeners.push(this.#editor.registerCommand(Te$1, this.#handleArrowDown.bind(this), Bi));
9048
+ }
9049
+
9050
+ #handleArrowUp(event) {
9051
+ this.#moveSelectionUp();
9052
+ event.preventDefault();
9053
+ return true
9054
+ }
9055
+
9056
+ #handleArrowDown(event) {
9057
+ this.#moveSelectionDown();
9058
+ event.preventDefault();
9059
+ return true
8944
9060
  }
8945
9061
 
8946
9062
  #selectFirstOption() {
@@ -8958,8 +9074,14 @@ class LexicalPromptElement extends HTMLElement {
8958
9074
  #selectOption(listItem) {
8959
9075
  this.#clearSelection();
8960
9076
  listItem.toggleAttribute("aria-selected", true);
9077
+ listItem.scrollIntoView({ block: "nearest", behavior: "smooth" });
8961
9078
  listItem.focus();
8962
- this.#editorElement.focus();
9079
+
9080
+ // Preserve selection to prevent cursor jump
9081
+ this.#selection.preservingSelection(() => {
9082
+ this.#editorElement.focus();
9083
+ });
9084
+
8963
9085
  this.#editorContentElement.setAttribute("aria-controls", this.popoverElement.id);
8964
9086
  this.#editorContentElement.setAttribute("aria-activedescendant", listItem.id);
8965
9087
  this.#editorContentElement.setAttribute("aria-haspopup", "listbox");
@@ -9008,6 +9130,7 @@ class LexicalPromptElement extends HTMLElement {
9008
9130
  this.#editorElement.removeEventListener("keydown", this.#handleKeydownOnPopover);
9009
9131
 
9010
9132
  this.#unregisterKeyListeners();
9133
+ this.#removeCursorPositionListener();
9011
9134
 
9012
9135
  await nextFrame();
9013
9136
  this.#addTriggerListener();
@@ -9026,6 +9149,7 @@ class LexicalPromptElement extends HTMLElement {
9026
9149
 
9027
9150
  if (this.#editorContents.containsTextBackUntil(this.trigger)) {
9028
9151
  await this.#showFilteredOptions();
9152
+ await nextFrame();
9029
9153
  this.#positionPopover();
9030
9154
  } else {
9031
9155
  this.#hidePopover();
@@ -9066,15 +9190,8 @@ class LexicalPromptElement extends HTMLElement {
9066
9190
  this.#hidePopover();
9067
9191
  this.#editorElement.focus();
9068
9192
  event.stopPropagation();
9069
- } else if (event.key === "ArrowDown") {
9070
- this.#moveSelectionDown();
9071
- event.preventDefault();
9072
- event.stopPropagation();
9073
- } else if (event.key === "ArrowUp") {
9074
- this.#moveSelectionUp();
9075
- event.preventDefault();
9076
- event.stopPropagation();
9077
9193
  }
9194
+ // Arrow keys are now handled via Lexical commands with HIGH priority
9078
9195
  }
9079
9196
 
9080
9197
  #moveSelectionDown() {
Binary file
Binary file