lexxy 1.0.2 → 1.0.3
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 +150 -29
- 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 +1 -1
- 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 +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f90f12597c2b6b34e544760455df98d3c4a8273230b159ff57e6ba693175a72b
|
|
4
|
+
data.tar.gz: 1ed0a3faa6d8ebc6bb810c102817ad281a7e638630d9c2f242d6c85c97276412
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 47ecc7aedf386f5d58e9e72f86eb4d81e4c61a44d858becf2096459fc64c8cfc016c80f68b737d4ecc82307be76e3508e7f3c48557d7177afe229286f1cc36a4
|
|
7
|
+
data.tar.gz: 6b40a63ef8cf45c5451e3190c4feee447358e1c224f259d370d5337e1b2a1f2a70126e98b307e51fa4247289cfecf0c5b4c50cb5267dbaf5d0b56d18c34b9581
|
|
@@ -7754,8 +7754,17 @@ class LexicalToolbarElement extends HTMLElement {
|
|
|
7754
7754
|
|
|
7755
7755
|
#updateButtonStates() {
|
|
7756
7756
|
const selection = Qr();
|
|
7757
|
-
if (!Fr(selection)) return
|
|
7758
7757
|
|
|
7758
|
+
this.#setButtonDisabled("link", Ir(selection) && !this.selection.hasLinkableAttachment);
|
|
7759
|
+
|
|
7760
|
+
if (Ir(selection)) {
|
|
7761
|
+
this.#setButtonPressed("link", this.selection.isInLink);
|
|
7762
|
+
} else if (Fr(selection)) {
|
|
7763
|
+
this.#updateFormatButtonStates(selection);
|
|
7764
|
+
}
|
|
7765
|
+
}
|
|
7766
|
+
|
|
7767
|
+
#updateFormatButtonStates(selection) {
|
|
7759
7768
|
const anchorNode = selection.anchor.getNode();
|
|
7760
7769
|
if (!anchorNode.getParent()) { return }
|
|
7761
7770
|
|
|
@@ -8138,7 +8147,7 @@ class ToolbarDropdown extends HTMLElement {
|
|
|
8138
8147
|
#handleTriggerClick = (event) => {
|
|
8139
8148
|
if (this.isOpen) {
|
|
8140
8149
|
this.close({ focusEditor: false });
|
|
8141
|
-
} else {
|
|
8150
|
+
} else if (this.trigger.ariaDisabled !== "true") {
|
|
8142
8151
|
this.#shouldReturnFocusToTrigger = this.#isOpenedFromHost(event);
|
|
8143
8152
|
this.host?.closeDropdowns({ except: this });
|
|
8144
8153
|
this.open();
|
|
@@ -9751,9 +9760,11 @@ function $consecutiveSiblingGroups(blocks) {
|
|
|
9751
9760
|
return groups
|
|
9752
9761
|
}
|
|
9753
9762
|
|
|
9754
|
-
// Payload: Record<nodeKey, { patch?, replace? }>
|
|
9763
|
+
// Payload: Record<nodeKey, { patch?, replace?, replaceInHistory? }>
|
|
9755
9764
|
// - patch: plain object, shallow-merged into the existing node's properties
|
|
9756
9765
|
// - replace: a LexicalNode instance that replaces the node
|
|
9766
|
+
// - replaceInHistory: builds each history entry's replacement from the node
|
|
9767
|
+
// that entry holds, so edits made between entries survive; defaults to replace
|
|
9757
9768
|
const REWRITE_HISTORY_COMMAND = re$5("REWRITE_HISTORY_COMMAND");
|
|
9758
9769
|
|
|
9759
9770
|
class RewritableHistoryExtension extends LexxyExtension {
|
|
@@ -9813,14 +9824,14 @@ class RewritableHistoryExtension extends LexxyExtension {
|
|
|
9813
9824
|
|
|
9814
9825
|
const editorState = entry.editorState = safeCloneEditorState(entry.editorState);
|
|
9815
9826
|
|
|
9816
|
-
for (const [ nodeKey, { patch, replace } ] of Object.entries(rewrites)) {
|
|
9827
|
+
for (const [ nodeKey, { patch, replace, replaceInHistory } ] of Object.entries(rewrites)) {
|
|
9817
9828
|
const node = editorState._nodeMap.get(nodeKey);
|
|
9818
9829
|
if (!node) continue
|
|
9819
9830
|
|
|
9820
9831
|
if (patch) {
|
|
9821
9832
|
this.#patchNodeInEditorState(editorState, node, patch);
|
|
9822
9833
|
} else if (replace) {
|
|
9823
|
-
this.#replaceNodeInEditorState(editorState, node, replace);
|
|
9834
|
+
this.#replaceNodeInEditorState(editorState, node, replaceInHistory?.(node) ?? replace);
|
|
9824
9835
|
}
|
|
9825
9836
|
}
|
|
9826
9837
|
}
|
|
@@ -9894,6 +9905,7 @@ class ActionTextAttachmentNode extends Ji {
|
|
|
9894
9905
|
conversion: (attachment) => ({
|
|
9895
9906
|
node: new ActionTextAttachmentNode({
|
|
9896
9907
|
sgid: attachment.getAttribute("sgid"),
|
|
9908
|
+
href: attachment.getAttribute("href"),
|
|
9897
9909
|
src: attachment.getAttribute("url"),
|
|
9898
9910
|
previewable: attachment.getAttribute("previewable"),
|
|
9899
9911
|
altText: attachment.getAttribute("alt"),
|
|
@@ -9948,10 +9960,11 @@ class ActionTextAttachmentNode extends Ji {
|
|
|
9948
9960
|
return Lexxy.global.get("attachmentTagName")
|
|
9949
9961
|
}
|
|
9950
9962
|
|
|
9951
|
-
constructor({ sgid, src, previewSrc, previewable, previewStatusUrl, pendingPreview, altText, caption, contentType, fileName, fileSize, width, height, uploadError } = {}, key) {
|
|
9963
|
+
constructor({ sgid, href, src, previewSrc, previewable, previewStatusUrl, pendingPreview, altText, caption, contentType, fileName, fileSize, width, height, uploadError } = {}, key) {
|
|
9952
9964
|
super(key);
|
|
9953
9965
|
|
|
9954
9966
|
this.sgid = sgid;
|
|
9967
|
+
this.href = href || null;
|
|
9955
9968
|
this.src = src;
|
|
9956
9969
|
this.previewSrc = previewSrc;
|
|
9957
9970
|
this.previewable = parseBoolean(previewable);
|
|
@@ -10024,6 +10037,7 @@ class ActionTextAttachmentNode extends Ji {
|
|
|
10024
10037
|
exportDOM() {
|
|
10025
10038
|
const attachment = createElement(ActionTextAttachmentNode.TAG_NAME, {
|
|
10026
10039
|
sgid: this.sgid,
|
|
10040
|
+
href: this.href,
|
|
10027
10041
|
previewable: this.previewable || null,
|
|
10028
10042
|
url: this.src,
|
|
10029
10043
|
alt: this.altText,
|
|
@@ -10044,6 +10058,7 @@ class ActionTextAttachmentNode extends Ji {
|
|
|
10044
10058
|
type: "action_text_attachment",
|
|
10045
10059
|
version: 1,
|
|
10046
10060
|
sgid: this.sgid,
|
|
10061
|
+
href: this.href,
|
|
10047
10062
|
src: this.src,
|
|
10048
10063
|
previewable: this.previewable,
|
|
10049
10064
|
previewStatusUrl: this.previewStatusUrl,
|
|
@@ -10115,9 +10130,9 @@ class ActionTextAttachmentNode extends Ji {
|
|
|
10115
10130
|
});
|
|
10116
10131
|
}
|
|
10117
10132
|
|
|
10118
|
-
replaceAndRewriteHistory(node) {
|
|
10133
|
+
replaceAndRewriteHistory(node, replaceInHistory) {
|
|
10119
10134
|
this.editor.dispatchCommand(REWRITE_HISTORY_COMMAND, {
|
|
10120
|
-
[this.getKey()]: { replace: node }
|
|
10135
|
+
[this.getKey()]: { replace: node, replaceInHistory }
|
|
10121
10136
|
});
|
|
10122
10137
|
}
|
|
10123
10138
|
|
|
@@ -10313,6 +10328,12 @@ function $isActionTextAttachmentNode(node) {
|
|
|
10313
10328
|
return node instanceof ActionTextAttachmentNode
|
|
10314
10329
|
}
|
|
10315
10330
|
|
|
10331
|
+
// Only images can carry a link: Action Text keeps an attachment's `href`, and a
|
|
10332
|
+
// host's blob partial can wrap the image in it.
|
|
10333
|
+
function $isLinkableAttachmentNode(node) {
|
|
10334
|
+
return $isActionTextAttachmentNode(node) && node.isPreviewableImage
|
|
10335
|
+
}
|
|
10336
|
+
|
|
10316
10337
|
async function loadFileIntoImage(file, image) {
|
|
10317
10338
|
return new Promise((resolve) => {
|
|
10318
10339
|
const reader = new FileReader();
|
|
@@ -10562,14 +10583,20 @@ class ActionTextAttachmentUploadNode extends ActionTextAttachmentNode {
|
|
|
10562
10583
|
$showUploadedAttachment(blob) {
|
|
10563
10584
|
const previewSrc = this.isPreviewableImage && this.#canPreviewLocally ? URL.createObjectURL(this.file) : null;
|
|
10564
10585
|
|
|
10565
|
-
const replacementNode = this.#toActionTextAttachmentNodeWith(blob, previewSrc);
|
|
10566
|
-
this.replaceAndRewriteHistory(replacementNode);
|
|
10586
|
+
const replacementNode = this.#toActionTextAttachmentNodeWith(this.#latest, blob, previewSrc);
|
|
10587
|
+
this.replaceAndRewriteHistory(replacementNode, (uploadNode) => this.#toActionTextAttachmentNodeWith(uploadNode, blob, previewSrc));
|
|
10567
10588
|
|
|
10568
10589
|
return replacementNode.getKey()
|
|
10569
10590
|
}
|
|
10570
10591
|
|
|
10571
|
-
|
|
10572
|
-
|
|
10592
|
+
// The node the upload started from, as edited since. It is gone when the
|
|
10593
|
+
// attachment was removed mid-upload, and only history entries still hold it.
|
|
10594
|
+
get #latest() {
|
|
10595
|
+
return Yo(this.getKey()) ?? this
|
|
10596
|
+
}
|
|
10597
|
+
|
|
10598
|
+
#toActionTextAttachmentNodeWith(uploadNode, blob, previewSrc) {
|
|
10599
|
+
const conversion = new AttachmentNodeConversion(uploadNode, blob, previewSrc);
|
|
10573
10600
|
return conversion.toAttachmentNode()
|
|
10574
10601
|
}
|
|
10575
10602
|
|
|
@@ -12057,17 +12084,11 @@ class CommandDispatcher {
|
|
|
12057
12084
|
this.selection.placeCursorInsideAdjacentLink();
|
|
12058
12085
|
|
|
12059
12086
|
const selection = Qr();
|
|
12060
|
-
if (!Fr(selection)) return
|
|
12061
|
-
|
|
12062
|
-
const anchorNode = selection.anchor.getNode();
|
|
12063
12087
|
|
|
12064
|
-
if (selection
|
|
12065
|
-
|
|
12066
|
-
|
|
12067
|
-
|
|
12068
|
-
selection.insertNodes([ autoLinkNode ]);
|
|
12069
|
-
} else {
|
|
12070
|
-
Q$5(url);
|
|
12088
|
+
if (Ir(selection)) {
|
|
12089
|
+
$setHrefOnSelectedImages(selection, url);
|
|
12090
|
+
} else if (Fr(selection)) {
|
|
12091
|
+
$linkSelectedText(url, selection);
|
|
12071
12092
|
}
|
|
12072
12093
|
});
|
|
12073
12094
|
}
|
|
@@ -12081,7 +12102,13 @@ class CommandDispatcher {
|
|
|
12081
12102
|
return
|
|
12082
12103
|
}
|
|
12083
12104
|
|
|
12084
|
-
|
|
12105
|
+
const selection = Qr();
|
|
12106
|
+
|
|
12107
|
+
if (Ir(selection)) {
|
|
12108
|
+
$setHrefOnSelectedImages(selection, null);
|
|
12109
|
+
} else {
|
|
12110
|
+
Q$5(null);
|
|
12111
|
+
}
|
|
12085
12112
|
});
|
|
12086
12113
|
}
|
|
12087
12114
|
|
|
@@ -12429,6 +12456,25 @@ class CommandDispatcher {
|
|
|
12429
12456
|
|
|
12430
12457
|
}
|
|
12431
12458
|
|
|
12459
|
+
function $setHrefOnSelectedImages(selection, href) {
|
|
12460
|
+
for (const node of selection.getNodes()) {
|
|
12461
|
+
if ($isLinkableAttachmentNode(node)) node.getWritable().href = href;
|
|
12462
|
+
}
|
|
12463
|
+
}
|
|
12464
|
+
|
|
12465
|
+
function $linkSelectedText(url, selection) {
|
|
12466
|
+
const anchorNode = selection.anchor.getNode();
|
|
12467
|
+
|
|
12468
|
+
if (selection.isCollapsed() && !At$2(anchorNode, F$4)) {
|
|
12469
|
+
const autoLinkNode = H$5(url);
|
|
12470
|
+
const textNode = kr(url);
|
|
12471
|
+
autoLinkNode.append(textNode);
|
|
12472
|
+
selection.insertNodes([ autoLinkNode ]);
|
|
12473
|
+
} else {
|
|
12474
|
+
Q$5(url);
|
|
12475
|
+
}
|
|
12476
|
+
}
|
|
12477
|
+
|
|
12432
12478
|
function capitalize(str) {
|
|
12433
12479
|
return str.charAt(0).toUpperCase() + str.slice(1)
|
|
12434
12480
|
}
|
|
@@ -12525,7 +12571,7 @@ class Selection {
|
|
|
12525
12571
|
isStrikethrough: selection.hasFormat("strikethrough"),
|
|
12526
12572
|
isUnderline: selection.hasFormat("underline"),
|
|
12527
12573
|
isHighlight: isSelectionHighlighted(selection),
|
|
12528
|
-
isInLink: this.
|
|
12574
|
+
isInLink: this.isInLink,
|
|
12529
12575
|
isInQuote: Mt$2(topLevelElement),
|
|
12530
12576
|
isInHeading: headingNode !== null,
|
|
12531
12577
|
isInCode: this.#isInCode(selection, anchorNode),
|
|
@@ -12536,8 +12582,18 @@ class Selection {
|
|
|
12536
12582
|
}
|
|
12537
12583
|
}
|
|
12538
12584
|
|
|
12585
|
+
get isInLink() {
|
|
12586
|
+
return this.linkUrl !== null
|
|
12587
|
+
}
|
|
12588
|
+
|
|
12539
12589
|
get linkUrl() {
|
|
12540
|
-
|
|
12590
|
+
const { node } = this.selectedNodeWithOffset();
|
|
12591
|
+
|
|
12592
|
+
if ($isActionTextAttachmentNode(node)) {
|
|
12593
|
+
return $isLinkableAttachmentNode(node) ? node.href : null
|
|
12594
|
+
} else {
|
|
12595
|
+
return this.linkAtCursor?.getURL() ?? null
|
|
12596
|
+
}
|
|
12541
12597
|
}
|
|
12542
12598
|
|
|
12543
12599
|
get linkAtCursor() {
|
|
@@ -12545,6 +12601,11 @@ class Selection {
|
|
|
12545
12601
|
return At$2(anchorNode, F$4) ?? this.#linkEndingAtCursor()
|
|
12546
12602
|
}
|
|
12547
12603
|
|
|
12604
|
+
get hasLinkableAttachment() {
|
|
12605
|
+
const selection = Qr();
|
|
12606
|
+
return Ir(selection) && selection.getNodes().some($isLinkableAttachmentNode)
|
|
12607
|
+
}
|
|
12608
|
+
|
|
12548
12609
|
nearestNodeOfType(nodeType) {
|
|
12549
12610
|
const anchorNode = Qr()?.anchor?.getNode();
|
|
12550
12611
|
return At$2(anchorNode, nodeType)
|
|
@@ -17025,7 +17086,7 @@ function customAttachmentBesideAnchor(selection) {
|
|
|
17025
17086
|
}
|
|
17026
17087
|
|
|
17027
17088
|
const ATTACHMENT_ATTRIBUTES = [ "alt", "caption", "content", "content-type", "data-direct-upload-id",
|
|
17028
|
-
"data-sgid", "filename", "filesize", "height", "presentation", "previewable", "sgid", "url", "width" ];
|
|
17089
|
+
"data-sgid", "filename", "filesize", "height", "href", "presentation", "previewable", "sgid", "url", "width" ];
|
|
17029
17090
|
|
|
17030
17091
|
class AttachmentsExtension extends LexxyExtension {
|
|
17031
17092
|
#uploadsCount = 0
|
|
@@ -19506,14 +19567,51 @@ class LexicalPromptElement extends HTMLElement {
|
|
|
19506
19567
|
|
|
19507
19568
|
const forceTop = this.verticalDirection === "top";
|
|
19508
19569
|
const forceBottom = this.verticalDirection === "bottom";
|
|
19509
|
-
const overflowsWindow = popoverRect.bottom > window.innerHeight;
|
|
19510
19570
|
|
|
19511
|
-
if (!forceBottom && (forceTop ||
|
|
19571
|
+
if (!forceBottom && (forceTop || this.#fitsBetterAbove(popoverRect, fontSize))) {
|
|
19512
19572
|
this.#setPopoverOffsetY(contentRect.height - y + fontSize);
|
|
19513
19573
|
this.popoverElement.toggleAttribute("data-clipped-at-bottom", true);
|
|
19514
19574
|
}
|
|
19515
19575
|
}
|
|
19516
19576
|
|
|
19577
|
+
#fitsBetterAbove(popoverRect, fontSize) {
|
|
19578
|
+
const { top, bottom } = this.#visibleBounds();
|
|
19579
|
+
const overflowsBelow = popoverRect.bottom > bottom;
|
|
19580
|
+
const roomAbove = popoverRect.top - fontSize - top;
|
|
19581
|
+
const roomBelow = bottom - popoverRect.top;
|
|
19582
|
+
|
|
19583
|
+
return overflowsBelow && roomAbove > roomBelow
|
|
19584
|
+
}
|
|
19585
|
+
|
|
19586
|
+
// A scroll container or modal around the editor clips the menu at its scrollport before the
|
|
19587
|
+
// window does, so the visible area is the window narrowed by every clipping ancestor. A fixed
|
|
19588
|
+
// ancestor escapes the clipping of everything up to its containing block: the window, or the
|
|
19589
|
+
// nearest ancestor that a transform, filter or containment makes contain fixed descendants.
|
|
19590
|
+
// A top-layer ancestor, such as a modal dialog, escapes everything outside it.
|
|
19591
|
+
#visibleBounds() {
|
|
19592
|
+
let top = 0;
|
|
19593
|
+
let bottom = window.innerHeight;
|
|
19594
|
+
let escapingToContainingBlock = false;
|
|
19595
|
+
|
|
19596
|
+
for (let node = this.#editorElement; node && node !== document.body; node = node.parentElement) {
|
|
19597
|
+
const style = getComputedStyle(node);
|
|
19598
|
+
|
|
19599
|
+
if (style.display !== "contents" && (!escapingToContainingBlock || containsFixedDescendants(style))) {
|
|
19600
|
+
escapingToContainingBlock = style.position === "fixed";
|
|
19601
|
+
|
|
19602
|
+
if (clipsDescendants(style)) {
|
|
19603
|
+
const scrollport = scrollportBounds(node);
|
|
19604
|
+
top = Math.max(top, scrollport.top);
|
|
19605
|
+
bottom = Math.min(bottom, scrollport.bottom);
|
|
19606
|
+
}
|
|
19607
|
+
}
|
|
19608
|
+
|
|
19609
|
+
if (node.matches(":modal, :popover-open")) break
|
|
19610
|
+
}
|
|
19611
|
+
|
|
19612
|
+
return { top, bottom }
|
|
19613
|
+
}
|
|
19614
|
+
|
|
19517
19615
|
#setPopoverOffsetX(value) {
|
|
19518
19616
|
this.popoverElement.style.setProperty("--lexxy-prompt-offset-x", `${value}px`);
|
|
19519
19617
|
}
|
|
@@ -19799,6 +19897,29 @@ class LexicalPromptElement extends HTMLElement {
|
|
|
19799
19897
|
}
|
|
19800
19898
|
}
|
|
19801
19899
|
|
|
19900
|
+
function clipsDescendants(style) {
|
|
19901
|
+
return style.overflowY !== "visible" || /paint|strict|content/.test(style.contain) || style.contentVisibility === "auto"
|
|
19902
|
+
}
|
|
19903
|
+
|
|
19904
|
+
// The bounding rect is in viewport coordinates, already scaled by any transform, while
|
|
19905
|
+
// clientTop and clientHeight are untransformed layout sizes, so they're scaled to match.
|
|
19906
|
+
function scrollportBounds(element) {
|
|
19907
|
+
const rect = element.getBoundingClientRect();
|
|
19908
|
+
const scale = rect.height / element.offsetHeight || 1;
|
|
19909
|
+
const top = rect.top + element.clientTop * scale;
|
|
19910
|
+
|
|
19911
|
+
return { top, bottom: top + element.clientHeight * scale }
|
|
19912
|
+
}
|
|
19913
|
+
|
|
19914
|
+
function containsFixedDescendants(style) {
|
|
19915
|
+
return [ style.transform, style.translate, style.rotate, style.scale, style.perspective, style.filter, style.backdropFilter ]
|
|
19916
|
+
.some(value => value && value !== "none") ||
|
|
19917
|
+
/transform|translate|rotate|scale|perspective|filter/.test(style.willChange) ||
|
|
19918
|
+
/paint|layout|strict|content/.test(style.contain) ||
|
|
19919
|
+
/size/.test(style.containerType) ||
|
|
19920
|
+
style.contentVisibility === "auto"
|
|
19921
|
+
}
|
|
19922
|
+
|
|
19802
19923
|
class CodeLanguagePicker extends HTMLElement {
|
|
19803
19924
|
#abortController = null
|
|
19804
19925
|
#listeners = new ListenerBin()
|
|
@@ -21862,5 +21983,5 @@ queueMicrotask(() => {
|
|
|
21862
21983
|
}
|
|
21863
21984
|
});
|
|
21864
21985
|
|
|
21865
|
-
export { $createActionTextAttachmentNode, $createActionTextAttachmentUploadNode, $isActionTextAttachmentNode, $isCustomActionTextAttachmentNode, ActionTextAttachmentNode, ActionTextAttachmentUploadNode, CustomActionTextAttachmentNode, EditorSanitizer, LexxyExtension as Extension, HorizontalDividerNode, Lexical_prod as Lexical, NativeAdapter, REWRITE_HISTORY_COMMAND, configure, highlightCode, highlightElement };
|
|
21986
|
+
export { $createActionTextAttachmentNode, $createActionTextAttachmentUploadNode, $isActionTextAttachmentNode, $isCustomActionTextAttachmentNode, $isLinkableAttachmentNode, ActionTextAttachmentNode, ActionTextAttachmentUploadNode, CustomActionTextAttachmentNode, EditorSanitizer, LexxyExtension as Extension, HorizontalDividerNode, Lexical_prod as Lexical, NativeAdapter, REWRITE_HISTORY_COMMAND, configure, highlightCode, highlightElement };
|
|
21866
21987
|
//# sourceMappingURL=lexxy.js.map
|
|
Binary file
|
|
Binary file
|