lexxy 0.9.19.alpha.3 → 0.9.19
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 +337 -33
- data/app/assets/javascript/lexxy.js.br +0 -0
- data/app/assets/javascript/lexxy.js.gz +0 -0
- data/app/assets/javascript/lexxy.js.map +1 -1
- 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/app/assets/stylesheets/lexxy-editor.css +17 -1
- data/lib/lexxy/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b6868388203b7cfd6a7026208872b75268aafab61e5e29abc57ed35825dfdb8d
|
|
4
|
+
data.tar.gz: cdbb2c3702b5d204c2820a8a0fdf5c2c851c4d8272b1aa32e9dd8680adae409d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6a0ced04355235c795d5329b620f75e39ead9abfb64e4111939c2ce40c0a099b6d8aeed6222105d9e17aa909be1cc1e7a83037b2b9ff2fc8c49849f61f21a346
|
|
7
|
+
data.tar.gz: 26d5669519354092c672bc86bfe37f0939c16bc24336f3242e87ef4d9a5e7416bd856b275238c1bca32b5dd20a98f2c20784aee6c064a86033cc6edb34ced695
|
|
@@ -7650,7 +7650,8 @@ class CustomActionTextAttachmentNode extends Ji {
|
|
|
7650
7650
|
}
|
|
7651
7651
|
|
|
7652
7652
|
createDOM() {
|
|
7653
|
-
const figure = createElement(this.tagName, { "content-type": this.contentType, "data-lexxy-decorator": true });
|
|
7653
|
+
const figure = createElement(this.tagName, { "content-type": this.contentType, "data-lexxy-decorator": true, draggable: true });
|
|
7654
|
+
figure.dataset.lexicalNodeKey = this.__key;
|
|
7654
7655
|
|
|
7655
7656
|
figure.insertAdjacentHTML("beforeend", sanitize(this.innerHtml));
|
|
7656
7657
|
|
|
@@ -7703,6 +7704,10 @@ class CustomActionTextAttachmentNode extends Ji {
|
|
|
7703
7704
|
}
|
|
7704
7705
|
}
|
|
7705
7706
|
|
|
7707
|
+
function $isCustomActionTextAttachmentNode(node) {
|
|
7708
|
+
return node instanceof CustomActionTextAttachmentNode
|
|
7709
|
+
}
|
|
7710
|
+
|
|
7706
7711
|
function dasherize(value) {
|
|
7707
7712
|
return value.replace(/([A-Z])/g, (_, char) => `-${char.toLowerCase()}`)
|
|
7708
7713
|
}
|
|
@@ -10254,7 +10259,7 @@ class CommandDispatcher {
|
|
|
10254
10259
|
}
|
|
10255
10260
|
|
|
10256
10261
|
#isInternalDrag(event) {
|
|
10257
|
-
return event.dataTransfer?.types.
|
|
10262
|
+
return event.dataTransfer?.types.some((type) => type.startsWith("application/x-lexxy-"))
|
|
10258
10263
|
}
|
|
10259
10264
|
|
|
10260
10265
|
#handleTabKey(event) {
|
|
@@ -10308,14 +10313,14 @@ class Selection {
|
|
|
10308
10313
|
}
|
|
10309
10314
|
|
|
10310
10315
|
get cursorPosition() {
|
|
10311
|
-
let position =
|
|
10316
|
+
let position = null;
|
|
10312
10317
|
|
|
10313
10318
|
this.editor.getEditorState().read(() => {
|
|
10314
10319
|
const range = this.#getValidSelectionRange();
|
|
10315
10320
|
if (!range) return
|
|
10316
10321
|
|
|
10317
10322
|
const rect = this.#getReliableRectFromRange(range);
|
|
10318
|
-
if (
|
|
10323
|
+
if (this.#isRectUnreliable(rect)) return
|
|
10319
10324
|
|
|
10320
10325
|
position = this.#calculateCursorPosition(rect, range);
|
|
10321
10326
|
});
|
|
@@ -11885,7 +11890,7 @@ class ShadowRootNodeInserter extends BaseNodeInserter {
|
|
|
11885
11890
|
|
|
11886
11891
|
class NodeSelectionNodeInserter extends BaseNodeInserter {
|
|
11887
11892
|
static handles(selection) {
|
|
11888
|
-
return Ir(selection)
|
|
11893
|
+
return Ir(selection) && selection.getNodes().length > 0
|
|
11889
11894
|
}
|
|
11890
11895
|
|
|
11891
11896
|
insertNodes(nodes) {
|
|
@@ -12083,8 +12088,15 @@ class Contents {
|
|
|
12083
12088
|
}, { tag });
|
|
12084
12089
|
}
|
|
12085
12090
|
|
|
12091
|
+
insertText(text, { tag } = {}) {
|
|
12092
|
+
this.editor.update(() => {
|
|
12093
|
+
const paragraph = eo().append(kr(text));
|
|
12094
|
+
this.insertAtCursor(paragraph);
|
|
12095
|
+
}, { tag });
|
|
12096
|
+
}
|
|
12097
|
+
|
|
12086
12098
|
insertAtCursor(...nodes) {
|
|
12087
|
-
const selection =
|
|
12099
|
+
const selection = this.#insertableSelection();
|
|
12088
12100
|
const inserter = BaseNodeInserter.for(selection);
|
|
12089
12101
|
|
|
12090
12102
|
inserter.insertNodes(nodes);
|
|
@@ -12278,14 +12290,13 @@ class Contents {
|
|
|
12278
12290
|
replaceTextBackUntil(stringToReplace, replacementNodes) {
|
|
12279
12291
|
replacementNodes = Array.isArray(replacementNodes) ? replacementNodes : [ replacementNodes ];
|
|
12280
12292
|
|
|
12281
|
-
const selection = Qr();
|
|
12282
12293
|
const { anchorNode, offset } = this.#getTextAnchorData();
|
|
12283
12294
|
if (!anchorNode) return
|
|
12284
12295
|
|
|
12285
12296
|
const lastIndex = this.#findReplacementStart(anchorNode, offset, stringToReplace);
|
|
12286
12297
|
if (lastIndex === -1) return
|
|
12287
12298
|
|
|
12288
|
-
this.#performTextReplacement(anchorNode,
|
|
12299
|
+
this.#performTextReplacement(anchorNode, lastIndex, stringToReplace, replacementNodes);
|
|
12289
12300
|
}
|
|
12290
12301
|
|
|
12291
12302
|
uploadFiles(files, { selectLast } = {}) {
|
|
@@ -12425,6 +12436,15 @@ class Contents {
|
|
|
12425
12436
|
});
|
|
12426
12437
|
}
|
|
12427
12438
|
|
|
12439
|
+
#insertableSelection() {
|
|
12440
|
+
const selection = Qr();
|
|
12441
|
+
if (Ir(selection) && selection.getNodes().length === 0) {
|
|
12442
|
+
return Zo().selectEnd()
|
|
12443
|
+
}
|
|
12444
|
+
|
|
12445
|
+
return selection ?? Zo().selectEnd()
|
|
12446
|
+
}
|
|
12447
|
+
|
|
12428
12448
|
#formatPastedDOM(doc) {
|
|
12429
12449
|
new PastedContentFormatter(doc).format();
|
|
12430
12450
|
}
|
|
@@ -12608,13 +12628,13 @@ class Contents {
|
|
|
12608
12628
|
}
|
|
12609
12629
|
}
|
|
12610
12630
|
|
|
12611
|
-
#performTextReplacement(anchorNode,
|
|
12631
|
+
#performTextReplacement(anchorNode, startIndex, stringToReplace, replacementNodes) {
|
|
12612
12632
|
const fullText = anchorNode.getTextContent();
|
|
12613
12633
|
const textBeforeString = fullText.slice(0, startIndex);
|
|
12614
12634
|
const textAfterString = fullText.slice(startIndex + stringToReplace.length);
|
|
12615
12635
|
|
|
12616
|
-
const textNodeBefore = this.#cloneTextNodeFormatting(anchorNode,
|
|
12617
|
-
const textNodeAfter = this.#cloneTextNodeFormatting(anchorNode,
|
|
12636
|
+
const textNodeBefore = this.#cloneTextNodeFormatting(anchorNode, textBeforeString);
|
|
12637
|
+
const textNodeAfter = this.#cloneTextNodeFormatting(anchorNode, textAfterString || " ");
|
|
12618
12638
|
|
|
12619
12639
|
anchorNode.replace(textNodeBefore);
|
|
12620
12640
|
|
|
@@ -12626,18 +12646,12 @@ class Contents {
|
|
|
12626
12646
|
textNodeAfter.select(cursorOffset, cursorOffset);
|
|
12627
12647
|
}
|
|
12628
12648
|
|
|
12629
|
-
#cloneTextNodeFormatting(anchorNode,
|
|
12630
|
-
const parent = anchorNode.getParent();
|
|
12631
|
-
const fallbackFormat = parent?.getTextFormat?.() || 0;
|
|
12632
|
-
const fallbackStyle = parent?.getTextStyle?.() || "";
|
|
12633
|
-
const format = Fr(selection) && selection.format ? selection.format : (anchorNode.getFormat() || fallbackFormat);
|
|
12634
|
-
const style = Fr(selection) && selection.style ? selection.style : (anchorNode.getStyle() || fallbackStyle);
|
|
12635
|
-
|
|
12649
|
+
#cloneTextNodeFormatting(anchorNode, text) {
|
|
12636
12650
|
return kr(text)
|
|
12637
|
-
.setFormat(
|
|
12651
|
+
.setFormat(anchorNode.getFormat())
|
|
12638
12652
|
.setDetail(anchorNode.getDetail())
|
|
12639
12653
|
.setMode(anchorNode.getMode())
|
|
12640
|
-
.setStyle(
|
|
12654
|
+
.setStyle(anchorNode.getStyle())
|
|
12641
12655
|
}
|
|
12642
12656
|
|
|
12643
12657
|
#insertReplacementNodes(startNode, replacementNodes) {
|
|
@@ -12927,14 +12941,31 @@ class Clipboard {
|
|
|
12927
12941
|
#pasteMarkdown(text) {
|
|
12928
12942
|
const html = k(text, { breaks: true });
|
|
12929
12943
|
const doc = parseHtml(html);
|
|
12930
|
-
const detail = Object.freeze({
|
|
12931
|
-
markdown: text,
|
|
12932
|
-
document: doc,
|
|
12933
|
-
addBlockSpacing: () => addBlockSpacing(doc)
|
|
12934
|
-
});
|
|
12935
12944
|
|
|
12936
|
-
|
|
12937
|
-
|
|
12945
|
+
if (this.#isPlainTextWithoutMarkdown(doc)) {
|
|
12946
|
+
this.contents.insertText(text, { tag: jn });
|
|
12947
|
+
} else {
|
|
12948
|
+
const detail = Object.freeze({
|
|
12949
|
+
markdown: text,
|
|
12950
|
+
document: doc,
|
|
12951
|
+
addBlockSpacing: () => addBlockSpacing(doc)
|
|
12952
|
+
});
|
|
12953
|
+
|
|
12954
|
+
dispatch(this.editorElement, "lexxy:insert-markdown", detail);
|
|
12955
|
+
this.contents.insertDOM(doc, { tag: jn });
|
|
12956
|
+
}
|
|
12957
|
+
}
|
|
12958
|
+
|
|
12959
|
+
// Markdown conversion collapses runs of whitespace and unescapes backslashes,
|
|
12960
|
+
// silently corrupting plain text such as Windows/UNC file paths. When the text
|
|
12961
|
+
// carries no Markdown structure, paste it verbatim instead.
|
|
12962
|
+
#isPlainTextWithoutMarkdown(doc) {
|
|
12963
|
+
const elements = Array.from(doc.body.children);
|
|
12964
|
+
if (elements.length !== 1) return false
|
|
12965
|
+
|
|
12966
|
+
const paragraph = elements[0];
|
|
12967
|
+
return paragraph.nodeName === "P"
|
|
12968
|
+
&& Array.from(paragraph.childNodes).every((node) => node.nodeType === Node.TEXT_NODE)
|
|
12938
12969
|
}
|
|
12939
12970
|
|
|
12940
12971
|
#pasteRichText(clipboardData) {
|
|
@@ -13542,7 +13573,7 @@ class TablesExtension extends LexxyExtension {
|
|
|
13542
13573
|
}
|
|
13543
13574
|
}
|
|
13544
13575
|
|
|
13545
|
-
const MIME_TYPE = "application/x-lexxy-node-key";
|
|
13576
|
+
const MIME_TYPE$1 = "application/x-lexxy-node-key";
|
|
13546
13577
|
|
|
13547
13578
|
class AttachmentDragAndDrop {
|
|
13548
13579
|
#editor
|
|
@@ -13589,7 +13620,7 @@ class AttachmentDragAndDrop {
|
|
|
13589
13620
|
if (!figure) return false
|
|
13590
13621
|
|
|
13591
13622
|
this.#draggedNodeKey = figure.dataset.lexicalNodeKey;
|
|
13592
|
-
event.dataTransfer.setData(MIME_TYPE, this.#draggedNodeKey);
|
|
13623
|
+
event.dataTransfer.setData(MIME_TYPE$1, this.#draggedNodeKey);
|
|
13593
13624
|
event.dataTransfer.effectAllowed = "move";
|
|
13594
13625
|
|
|
13595
13626
|
// Add dragging class after a tick so it doesn't affect the drag image
|
|
@@ -14369,6 +14400,268 @@ class PreventLexicalTripleClickExtension extends LexxyExtension {
|
|
|
14369
14400
|
}
|
|
14370
14401
|
}
|
|
14371
14402
|
|
|
14403
|
+
function caretRect(node, offset) {
|
|
14404
|
+
const range = document.createRange();
|
|
14405
|
+
range.setStart(node, offset);
|
|
14406
|
+
range.collapse(true);
|
|
14407
|
+
|
|
14408
|
+
const rect = range.getBoundingClientRect();
|
|
14409
|
+
if (rect.height > 0) {
|
|
14410
|
+
return rect
|
|
14411
|
+
} else {
|
|
14412
|
+
return null
|
|
14413
|
+
}
|
|
14414
|
+
}
|
|
14415
|
+
|
|
14416
|
+
function caretFromPoint(clientX, clientY) {
|
|
14417
|
+
if (document.caretPositionFromPoint) {
|
|
14418
|
+
const position = document.caretPositionFromPoint(clientX, clientY);
|
|
14419
|
+
if (position) return { node: position.offsetNode, offset: position.offset }
|
|
14420
|
+
} else if (document.caretRangeFromPoint) {
|
|
14421
|
+
const range = document.caretRangeFromPoint(clientX, clientY);
|
|
14422
|
+
if (range) return { node: range.startContainer, offset: range.startOffset }
|
|
14423
|
+
}
|
|
14424
|
+
|
|
14425
|
+
return null
|
|
14426
|
+
}
|
|
14427
|
+
|
|
14428
|
+
const MIME_TYPE = "application/x-lexxy-custom-attachment-key";
|
|
14429
|
+
|
|
14430
|
+
// Custom inline attachments reorder by dropping at a text caret, unlike block
|
|
14431
|
+
// attachments which insert between blocks or into galleries.
|
|
14432
|
+
class CustomAttachmentDragAndDrop {
|
|
14433
|
+
#editor
|
|
14434
|
+
#draggedNodeKey = null
|
|
14435
|
+
#draggingRafId = null
|
|
14436
|
+
#dragOverRafId = null
|
|
14437
|
+
#dropIndicator = null
|
|
14438
|
+
#listeners = new ListenerBin()
|
|
14439
|
+
|
|
14440
|
+
constructor(editor) {
|
|
14441
|
+
this.#editor = editor;
|
|
14442
|
+
|
|
14443
|
+
// Register at HIGH priority to intercept before the base @lexical/rich-text
|
|
14444
|
+
// handlers, which consume drag events. The block-attachment handler also
|
|
14445
|
+
// registers here but bails for inline custom attachments, so we get our turn.
|
|
14446
|
+
this.#listeners.track(
|
|
14447
|
+
editor.registerCommand(Be$2, (event) => this.#handleDragStart(event), so),
|
|
14448
|
+
editor.registerCommand(ze$2, (event) => this.#handleDrop(event), so)
|
|
14449
|
+
);
|
|
14450
|
+
|
|
14451
|
+
this.#listeners.track(editor.registerRootListener((root, prevRoot) => {
|
|
14452
|
+
if (prevRoot) {
|
|
14453
|
+
prevRoot.removeEventListener("dragover", this.#onDragOver);
|
|
14454
|
+
prevRoot.removeEventListener("dragend", this.#onDragEnd);
|
|
14455
|
+
}
|
|
14456
|
+
if (root) {
|
|
14457
|
+
root.addEventListener("dragover", this.#onDragOver);
|
|
14458
|
+
root.addEventListener("dragend", this.#onDragEnd);
|
|
14459
|
+
}
|
|
14460
|
+
}));
|
|
14461
|
+
}
|
|
14462
|
+
|
|
14463
|
+
destroy() {
|
|
14464
|
+
this.#cleanup();
|
|
14465
|
+
this.#dropIndicator?.remove();
|
|
14466
|
+
this.#dropIndicator = null;
|
|
14467
|
+
this.#listeners.dispose();
|
|
14468
|
+
}
|
|
14469
|
+
|
|
14470
|
+
#handleDragStart(event) {
|
|
14471
|
+
const attachment = this.#customAttachmentElementFrom(event.target);
|
|
14472
|
+
if (!attachment) return false
|
|
14473
|
+
|
|
14474
|
+
this.#draggedNodeKey = attachment.dataset.lexicalNodeKey;
|
|
14475
|
+
event.dataTransfer.setData(MIME_TYPE, this.#draggedNodeKey);
|
|
14476
|
+
event.dataTransfer.effectAllowed = "move";
|
|
14477
|
+
|
|
14478
|
+
this.#draggingRafId = requestAnimationFrame(() => {
|
|
14479
|
+
this.#draggingRafId = null;
|
|
14480
|
+
attachment.classList.add("lexxy-dragging");
|
|
14481
|
+
});
|
|
14482
|
+
|
|
14483
|
+
return true
|
|
14484
|
+
}
|
|
14485
|
+
|
|
14486
|
+
#onDragOver = (event) => {
|
|
14487
|
+
if (!this.#draggedNodeKey) return
|
|
14488
|
+
|
|
14489
|
+
event.preventDefault();
|
|
14490
|
+
event.dataTransfer.dropEffect = "move";
|
|
14491
|
+
|
|
14492
|
+
if (!this.#dragOverRafId) {
|
|
14493
|
+
this.#dragOverRafId = requestAnimationFrame(() => {
|
|
14494
|
+
this.#dragOverRafId = null;
|
|
14495
|
+
this.#updateDropIndicator(event);
|
|
14496
|
+
});
|
|
14497
|
+
}
|
|
14498
|
+
}
|
|
14499
|
+
|
|
14500
|
+
#onDragEnd = () => {
|
|
14501
|
+
this.#cleanup();
|
|
14502
|
+
}
|
|
14503
|
+
|
|
14504
|
+
#handleDrop(event) {
|
|
14505
|
+
if (!this.#draggedNodeKey) return false
|
|
14506
|
+
|
|
14507
|
+
event.preventDefault();
|
|
14508
|
+
|
|
14509
|
+
const dropPoint = this.#resolveDropPoint(event);
|
|
14510
|
+
const draggedKey = this.#draggedNodeKey;
|
|
14511
|
+
this.#cleanup();
|
|
14512
|
+
|
|
14513
|
+
if (dropPoint) {
|
|
14514
|
+
this.#moveAttachment(draggedKey, dropPoint);
|
|
14515
|
+
}
|
|
14516
|
+
|
|
14517
|
+
return true
|
|
14518
|
+
}
|
|
14519
|
+
|
|
14520
|
+
#resolveDropPoint(event) {
|
|
14521
|
+
const rootElement = this.#editor.getRootElement();
|
|
14522
|
+
if (!rootElement) return null
|
|
14523
|
+
|
|
14524
|
+
const caret = caretFromPoint(event.clientX, event.clientY);
|
|
14525
|
+
if (!caret || !rootElement.contains(caret.node)) return null
|
|
14526
|
+
|
|
14527
|
+
// A caret on the root itself points between blocks. Mentions behave like text:
|
|
14528
|
+
// they only drop onto an existing line, so snap to the nearest one.
|
|
14529
|
+
if (caret.node === rootElement) {
|
|
14530
|
+
return this.#nearestLineCaret(rootElement, event.clientY)
|
|
14531
|
+
} else {
|
|
14532
|
+
return caret
|
|
14533
|
+
}
|
|
14534
|
+
}
|
|
14535
|
+
|
|
14536
|
+
#nearestLineCaret(rootElement, clientY) {
|
|
14537
|
+
let nearestLine = null;
|
|
14538
|
+
let nearestDistance = Infinity;
|
|
14539
|
+
|
|
14540
|
+
for (const line of rootElement.children) {
|
|
14541
|
+
const rect = line.getBoundingClientRect();
|
|
14542
|
+
const distance = Math.min(Math.abs(clientY - rect.top), Math.abs(clientY - rect.bottom));
|
|
14543
|
+
if (distance < nearestDistance) {
|
|
14544
|
+
nearestDistance = distance;
|
|
14545
|
+
nearestLine = line;
|
|
14546
|
+
}
|
|
14547
|
+
}
|
|
14548
|
+
|
|
14549
|
+
if (!nearestLine) return null
|
|
14550
|
+
|
|
14551
|
+
const rect = nearestLine.getBoundingClientRect();
|
|
14552
|
+
if (clientY < rect.top) {
|
|
14553
|
+
return { node: nearestLine, offset: 0 }
|
|
14554
|
+
} else {
|
|
14555
|
+
return { node: nearestLine, offset: nearestLine.childNodes.length }
|
|
14556
|
+
}
|
|
14557
|
+
}
|
|
14558
|
+
|
|
14559
|
+
#moveAttachment(draggedKey, dropPoint) {
|
|
14560
|
+
this.#editor.update(() => {
|
|
14561
|
+
const draggedNode = Yo(draggedKey);
|
|
14562
|
+
if (!$isCustomActionTextAttachmentNode(draggedNode)) return
|
|
14563
|
+
|
|
14564
|
+
const selection = Gr({
|
|
14565
|
+
anchorNode: dropPoint.node,
|
|
14566
|
+
anchorOffset: dropPoint.offset,
|
|
14567
|
+
focusNode: dropPoint.node,
|
|
14568
|
+
focusOffset: dropPoint.offset
|
|
14569
|
+
}, this.#editor);
|
|
14570
|
+
if (!selection) return
|
|
14571
|
+
|
|
14572
|
+
es(selection);
|
|
14573
|
+
|
|
14574
|
+
draggedNode.remove();
|
|
14575
|
+
selection.insertNodes([ draggedNode ]);
|
|
14576
|
+
});
|
|
14577
|
+
}
|
|
14578
|
+
|
|
14579
|
+
#updateDropIndicator(event) {
|
|
14580
|
+
this.#hideCaret();
|
|
14581
|
+
|
|
14582
|
+
const dropPoint = this.#resolveDropPoint(event);
|
|
14583
|
+
if (dropPoint) this.#showCaret(this.#caretRectFor(dropPoint));
|
|
14584
|
+
}
|
|
14585
|
+
|
|
14586
|
+
#caretRectFor({ node, offset }) {
|
|
14587
|
+
const rect = caretRect(node, offset);
|
|
14588
|
+
if (rect) return rect
|
|
14589
|
+
|
|
14590
|
+
// A blank line has no text to measure, so fall back to the line's own box.
|
|
14591
|
+
const line = node.nodeType === Node.TEXT_NODE ? node.parentElement : node;
|
|
14592
|
+
if (!line) return null
|
|
14593
|
+
|
|
14594
|
+
const lineRect = line.getBoundingClientRect();
|
|
14595
|
+
return { left: lineRect.left, top: lineRect.top, height: lineRect.height }
|
|
14596
|
+
}
|
|
14597
|
+
|
|
14598
|
+
#showCaret(rect) {
|
|
14599
|
+
if (!rect) return
|
|
14600
|
+
|
|
14601
|
+
const caret = this.#ensureCaretIndicator();
|
|
14602
|
+
caret.style.blockSize = `${rect.height}px`;
|
|
14603
|
+
caret.style.insetInlineStart = `${rect.left}px`;
|
|
14604
|
+
caret.style.insetBlockStart = `${rect.top}px`;
|
|
14605
|
+
}
|
|
14606
|
+
|
|
14607
|
+
#ensureCaretIndicator() {
|
|
14608
|
+
this.#dropIndicator ||= createElement("div", { className: "lexxy-drop-caret" });
|
|
14609
|
+
|
|
14610
|
+
this.#editorElement().appendChild(this.#dropIndicator);
|
|
14611
|
+
this.#dropIndicator.style.display = "block";
|
|
14612
|
+
return this.#dropIndicator
|
|
14613
|
+
}
|
|
14614
|
+
|
|
14615
|
+
#editorElement() {
|
|
14616
|
+
return this.#editor.getRootElement().closest("lexxy-editor")
|
|
14617
|
+
}
|
|
14618
|
+
|
|
14619
|
+
#hideCaret() {
|
|
14620
|
+
if (this.#dropIndicator) this.#dropIndicator.style.display = "none";
|
|
14621
|
+
}
|
|
14622
|
+
|
|
14623
|
+
#customAttachmentElementFrom(target) {
|
|
14624
|
+
return target?.closest?.("[data-lexxy-decorator][data-lexical-node-key]")
|
|
14625
|
+
}
|
|
14626
|
+
|
|
14627
|
+
#cleanup() {
|
|
14628
|
+
if (this.#draggedNodeKey) {
|
|
14629
|
+
const rootElement = this.#editor.getRootElement();
|
|
14630
|
+
const attachment = rootElement?.querySelector(`[data-lexical-node-key="${this.#draggedNodeKey}"]`);
|
|
14631
|
+
attachment?.classList.remove("lexxy-dragging");
|
|
14632
|
+
}
|
|
14633
|
+
|
|
14634
|
+
this.#hideCaret();
|
|
14635
|
+
this.#draggedNodeKey = null;
|
|
14636
|
+
|
|
14637
|
+
if (this.#draggingRafId) {
|
|
14638
|
+
cancelAnimationFrame(this.#draggingRafId);
|
|
14639
|
+
this.#draggingRafId = null;
|
|
14640
|
+
}
|
|
14641
|
+
|
|
14642
|
+
if (this.#dragOverRafId) {
|
|
14643
|
+
cancelAnimationFrame(this.#dragOverRafId);
|
|
14644
|
+
this.#dragOverRafId = null;
|
|
14645
|
+
}
|
|
14646
|
+
}
|
|
14647
|
+
}
|
|
14648
|
+
|
|
14649
|
+
class CustomAttachmentDragAndDropExtension extends LexxyExtension {
|
|
14650
|
+
get enabled() {
|
|
14651
|
+
return this.editorElement.supportsRichText
|
|
14652
|
+
}
|
|
14653
|
+
|
|
14654
|
+
get lexicalExtension() {
|
|
14655
|
+
return dc({
|
|
14656
|
+
name: "lexxy/custom-attachment-drag-and-drop",
|
|
14657
|
+
register: (editor) => {
|
|
14658
|
+
const dragAndDrop = new CustomAttachmentDragAndDrop(editor);
|
|
14659
|
+
return () => dragAndDrop.destroy()
|
|
14660
|
+
}
|
|
14661
|
+
})
|
|
14662
|
+
}
|
|
14663
|
+
}
|
|
14664
|
+
|
|
14372
14665
|
class LexicalEditorElement extends HTMLElement {
|
|
14373
14666
|
static formAssociated = true
|
|
14374
14667
|
static debug = false
|
|
@@ -14525,7 +14818,8 @@ class LexicalEditorElement extends HTMLElement {
|
|
|
14525
14818
|
AttachmentsExtension,
|
|
14526
14819
|
FormatEscapeExtension,
|
|
14527
14820
|
LinkOpenerExtension,
|
|
14528
|
-
PreventLexicalTripleClickExtension
|
|
14821
|
+
PreventLexicalTripleClickExtension,
|
|
14822
|
+
CustomAttachmentDragAndDropExtension
|
|
14529
14823
|
]
|
|
14530
14824
|
}
|
|
14531
14825
|
|
|
@@ -15561,7 +15855,9 @@ class LexicalPromptElement extends HTMLElement {
|
|
|
15561
15855
|
if (!node) return
|
|
15562
15856
|
|
|
15563
15857
|
if (this.#cursorIsTypingSearchTerm(node, offset)) {
|
|
15564
|
-
|
|
15858
|
+
if (!this.popoverElement.hasAttribute("data-anchored")) {
|
|
15859
|
+
this.#positionPopover();
|
|
15860
|
+
}
|
|
15565
15861
|
} else {
|
|
15566
15862
|
this.#hidePopover();
|
|
15567
15863
|
}
|
|
@@ -15692,8 +15988,16 @@ class LexicalPromptElement extends HTMLElement {
|
|
|
15692
15988
|
}
|
|
15693
15989
|
}
|
|
15694
15990
|
|
|
15991
|
+
// Right after a Turbo history restore the editor reconnects before the DOM selection
|
|
15992
|
+
// is re-established, so the cursor geometry is momentarily unavailable. Anchoring then
|
|
15993
|
+
// would pin the menu to the editor's left edge for the rest of the open cycle, so we
|
|
15994
|
+
// skip it and let a later reposition anchor it once the selection is ready. The menu
|
|
15995
|
+
// stays hidden until anchored (see the `[data-anchored]` rule in the stylesheet).
|
|
15695
15996
|
#positionPopover() {
|
|
15696
|
-
const
|
|
15997
|
+
const cursorPosition = this.#selection.cursorPosition;
|
|
15998
|
+
if (!cursorPosition) return
|
|
15999
|
+
|
|
16000
|
+
const { x, y, fontSize } = cursorPosition;
|
|
15697
16001
|
const editorRect = this.#editorElement.getBoundingClientRect();
|
|
15698
16002
|
const contentRect = this.#editorContentElement.getBoundingClientRect();
|
|
15699
16003
|
const verticalOffset = contentRect.top - editorRect.top;
|
|
@@ -17132,5 +17436,5 @@ const configure = Lexxy.configure;
|
|
|
17132
17436
|
// Pushing elements definition to after the current call stack to allow global configuration to take place first
|
|
17133
17437
|
setTimeout(defineElements, 0);
|
|
17134
17438
|
|
|
17135
|
-
export { $createActionTextAttachmentNode, $createActionTextAttachmentUploadNode, $isActionTextAttachmentNode, ActionTextAttachmentNode, ActionTextAttachmentUploadNode, CustomActionTextAttachmentNode, LexxyExtension as Extension, HorizontalDividerNode, NativeAdapter, configure, highlightCode, highlightElement };
|
|
17439
|
+
export { $createActionTextAttachmentNode, $createActionTextAttachmentUploadNode, $isActionTextAttachmentNode, $isCustomActionTextAttachmentNode, ActionTextAttachmentNode, ActionTextAttachmentUploadNode, CustomActionTextAttachmentNode, LexxyExtension as Extension, HorizontalDividerNode, NativeAdapter, configure, highlightCode, highlightElement };
|
|
17136
17440
|
//# sourceMappingURL=lexxy.js.map
|
|
Binary file
|
|
Binary file
|