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 +4 -4
- data/app/assets/javascript/lexxy.js +140 -23
- data/app/assets/javascript/lexxy.js.br +0 -0
- data/app/assets/javascript/lexxy.js.gz +0 -0
- data/app/assets/javascript/lexxy.min.js +2 -2
- data/app/assets/javascript/lexxy.min.js.br +0 -0
- data/app/assets/javascript/lexxy.min.js.gz +0 -0
- data/lib/lexxy/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 28ddded3fff65c55a5e194a1ba8246411fad9193b32ab319cc5a6330ab999420
|
|
4
|
+
data.tar.gz: 98a6bf19a11687400a21baed5117d65de05f02e595f3d7684f1fb70f8c8ffeea
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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.
|
|
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
|
-
|
|
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
|
|
8890
|
-
if (!
|
|
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 &&
|
|
8899
|
-
const
|
|
8900
|
-
const
|
|
8965
|
+
if (lr(node) && offset > 0) {
|
|
8966
|
+
const fullText = node.getTextContent();
|
|
8967
|
+
const charBeforeCursor = fullText[offset - 1];
|
|
8901
8968
|
|
|
8902
|
-
if (
|
|
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
|
-
|
|
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
|