lexxy 0.1.15.beta → 0.1.17.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: 187dcf79d54b9eb899cf698c415bd9fd9f8b237425d26c91d040389ea4abb103
4
- data.tar.gz: 9fdc17d5b30839019fd7a30c6ea7d916198fcd301cd3fcfca3a7849db9688796
3
+ metadata.gz: 4110accda8b3076f07bc48ae4d079733e7972198cd2b8c6801073b99a2af27a1
4
+ data.tar.gz: b3a5df5347125312a746dbc4d1a2ad961f642cd1506abcb7610a3eafd70588a9
5
5
  SHA512:
6
- metadata.gz: '049f7df42895c9d3836198ab095978a9265306663f7782d15d2ff04553094ff7830d3d016f795a65c67e7f86b2b4a725d39bd88a9c6a7e8fd3c169802d0f165c'
7
- data.tar.gz: 45e059de86a63bbe4f3470ea2b3ec2c56706562ddf5ddaf7fa7d01aac637821af4bb2d2a45489725956a67fbc576d4ee0818705051fdc8d9884b2fb4490752d2
6
+ metadata.gz: c06e2386dcd78237df5381b138511dfe40d23240fb222ce5610e58cd505002a2561f435350f2fd250af0624b6f1fba2a15d5c0a9c554b8f9d3aa78e8435c34c5
7
+ data.tar.gz: 974cb1bd0ae568f224f006a37d98ba4bcc5a2c4dcd718f91027cbab9b045c6479a939b321fd0704ceecfcd38b76f7095733246efcdb6cb89a827836963d1270e
@@ -6132,7 +6132,19 @@ class CommandDispatcher {
6132
6132
  }
6133
6133
 
6134
6134
  dispatchLink(url) {
6135
- this.#toggleLink(url);
6135
+ this.editor.update(() => {
6136
+ const selection = Lr();
6137
+ if (!yr(selection)) return
6138
+
6139
+ if (selection.isCollapsed()) {
6140
+ const autoLinkNode = I$1(url);
6141
+ const textNode = sr(url);
6142
+ autoLinkNode.append(textNode);
6143
+ selection.insertNodes([ autoLinkNode ]);
6144
+ } else {
6145
+ J$1(url);
6146
+ }
6147
+ });
6136
6148
  }
6137
6149
 
6138
6150
  dispatchUnlink() {
@@ -6166,7 +6178,7 @@ class CommandDispatcher {
6166
6178
  }
6167
6179
 
6168
6180
  dispatchInsertQuoteBlock() {
6169
- this.contents.toggleNodeWrappingAllSelectedLines((node) => Ot$1(node), () => _t$1());
6181
+ this.contents.toggleNodeWrappingAllSelectedNodes((node) => Ot$1(node), () => _t$1());
6170
6182
  }
6171
6183
 
6172
6184
  dispatchInsertCodeBlock() {
@@ -7033,10 +7045,292 @@ class CustomActionTextAttachmentNode extends ki {
7033
7045
  }
7034
7046
  }
7035
7047
 
7048
+ class FormatEscaper {
7049
+ constructor(editorElement) {
7050
+ this.editorElement = editorElement;
7051
+ this.editor = editorElement.editor;
7052
+ }
7053
+
7054
+ monitor() {
7055
+ this.editor.registerCommand(
7056
+ Ne$1,
7057
+ (event) => this.#handleEnterKey(event),
7058
+ Bi
7059
+ );
7060
+ }
7061
+
7062
+ #handleEnterKey(event) {
7063
+ const selection = Lr();
7064
+ if (!yr(selection)) return false
7065
+
7066
+ const anchorNode = selection.anchor.getNode();
7067
+
7068
+ if (!this.#isInsideBlockquote(anchorNode)) return false
7069
+
7070
+ return this.#handleLists(event, anchorNode)
7071
+ || this.#handleBlockquotes(event, anchorNode)
7072
+ }
7073
+
7074
+ #handleLists(event, anchorNode) {
7075
+ if (this.#shouldEscapeFromEmptyListItem(anchorNode) || this.#shouldEscapeFromEmptyParagraphInListItem(anchorNode)) {
7076
+ event.preventDefault();
7077
+ this.#escapeFromList(anchorNode);
7078
+ return true
7079
+ }
7080
+
7081
+ return false
7082
+ }
7083
+
7084
+ #handleBlockquotes(event, anchorNode) {
7085
+ if (this.#shouldEscapeFromEmptyParagraphInBlockquote(anchorNode)) {
7086
+ event.preventDefault();
7087
+ this.#escapeFromBlockquote(anchorNode);
7088
+ return true
7089
+ }
7090
+
7091
+ return false
7092
+ }
7093
+
7094
+ #isInsideBlockquote(node) {
7095
+ let currentNode = node;
7096
+
7097
+ while (currentNode) {
7098
+ if (Ot$1(currentNode)) {
7099
+ return true
7100
+ }
7101
+ currentNode = currentNode.getParent();
7102
+ }
7103
+
7104
+ return false
7105
+ }
7106
+
7107
+ #shouldEscapeFromEmptyListItem(node) {
7108
+ const listItem = this.#getListItemNode(node);
7109
+ if (!listItem) return false
7110
+
7111
+ return this.#isNodeEmpty(listItem)
7112
+ }
7113
+
7114
+ #shouldEscapeFromEmptyParagraphInListItem(node) {
7115
+ const paragraph = this.#getParagraphNode(node);
7116
+ if (!paragraph) return false
7117
+
7118
+ if (!this.#isNodeEmpty(paragraph)) return false
7119
+
7120
+ const parent = paragraph.getParent();
7121
+ return parent && ot$2(parent)
7122
+ }
7123
+
7124
+ #isNodeEmpty(node) {
7125
+ if (node.getTextContent().trim() !== "") return false
7126
+
7127
+ const children = node.getChildren();
7128
+ if (children.length === 0) return true
7129
+
7130
+ return children.every(child => {
7131
+ if (jn(child)) return true
7132
+ return this.#isNodeEmpty(child)
7133
+ })
7134
+ }
7135
+
7136
+ #getListItemNode(node) {
7137
+ let currentNode = node;
7138
+
7139
+ while (currentNode) {
7140
+ if (ot$2(currentNode)) {
7141
+ return currentNode
7142
+ }
7143
+ currentNode = currentNode.getParent();
7144
+ }
7145
+
7146
+ return null
7147
+ }
7148
+
7149
+ #escapeFromList(anchorNode) {
7150
+ const listItem = this.#getListItemNode(anchorNode);
7151
+ if (!listItem) return
7152
+
7153
+ const parentList = listItem.getParent();
7154
+ if (!parentList || !dt$1(parentList)) return
7155
+
7156
+ const blockquote = parentList.getParent();
7157
+ const isInBlockquote = blockquote && Ot$1(blockquote);
7158
+
7159
+ if (isInBlockquote) {
7160
+ const listItemsAfter = this.#getListItemSiblingsAfter(listItem);
7161
+ const nonEmptyListItems = listItemsAfter.filter(item => !this.#isNodeEmpty(item));
7162
+
7163
+ if (nonEmptyListItems.length > 0) {
7164
+ this.#splitBlockquoteWithList(blockquote, parentList, listItem, nonEmptyListItems);
7165
+ return
7166
+ }
7167
+ }
7168
+
7169
+ const paragraph = Li();
7170
+ parentList.insertAfter(paragraph);
7171
+
7172
+ listItem.remove();
7173
+ paragraph.selectStart();
7174
+ }
7175
+
7176
+ #shouldEscapeFromEmptyParagraphInBlockquote(node) {
7177
+ const paragraph = this.#getParagraphNode(node);
7178
+ if (!paragraph) return false
7179
+
7180
+ if (!this.#isNodeEmpty(paragraph)) return false
7181
+
7182
+ const parent = paragraph.getParent();
7183
+ return parent && Ot$1(parent)
7184
+ }
7185
+
7186
+ #getParagraphNode(node) {
7187
+ let currentNode = node;
7188
+
7189
+ while (currentNode) {
7190
+ if (Ii(currentNode)) {
7191
+ return currentNode
7192
+ }
7193
+ currentNode = currentNode.getParent();
7194
+ }
7195
+
7196
+ return null
7197
+ }
7198
+
7199
+ #escapeFromBlockquote(anchorNode) {
7200
+ const paragraph = this.#getParagraphNode(anchorNode);
7201
+ if (!paragraph) return
7202
+
7203
+ const blockquote = paragraph.getParent();
7204
+ if (!blockquote || !Ot$1(blockquote)) return
7205
+
7206
+ const siblingsAfter = this.#getSiblingsAfter(paragraph);
7207
+ const nonEmptySiblings = siblingsAfter.filter(sibling => !this.#isNodeEmpty(sibling));
7208
+
7209
+ if (nonEmptySiblings.length > 0) {
7210
+ this.#splitBlockquote(blockquote, paragraph, nonEmptySiblings);
7211
+ } else {
7212
+ const newParagraph = Li();
7213
+ blockquote.insertAfter(newParagraph);
7214
+ paragraph.remove();
7215
+ newParagraph.selectStart();
7216
+ }
7217
+ }
7218
+
7219
+ #getSiblingsAfter(node) {
7220
+ const siblings = [];
7221
+ let sibling = node.getNextSibling();
7222
+
7223
+ while (sibling) {
7224
+ siblings.push(sibling);
7225
+ sibling = sibling.getNextSibling();
7226
+ }
7227
+
7228
+ return siblings
7229
+ }
7230
+
7231
+ #getListItemSiblingsAfter(listItem) {
7232
+ const siblings = [];
7233
+ let sibling = listItem.getNextSibling();
7234
+
7235
+ while (sibling) {
7236
+ if (ot$2(sibling)) {
7237
+ siblings.push(sibling);
7238
+ }
7239
+ sibling = sibling.getNextSibling();
7240
+ }
7241
+
7242
+ return siblings
7243
+ }
7244
+
7245
+ #splitBlockquoteWithList(blockquote, parentList, emptyListItem, listItemsAfter) {
7246
+ const blockquoteSiblingsAfterList = this.#getSiblingsAfter(parentList);
7247
+ const nonEmptyBlockquoteSiblings = blockquoteSiblingsAfterList.filter(sibling => !this.#isNodeEmpty(sibling));
7248
+
7249
+ const middleParagraph = Li();
7250
+ blockquote.insertAfter(middleParagraph);
7251
+
7252
+ const newList = ht$3(parentList.getListType());
7253
+
7254
+ const newBlockquote = _t$1();
7255
+ middleParagraph.insertAfter(newBlockquote);
7256
+ newBlockquote.append(newList);
7257
+
7258
+ listItemsAfter.forEach(item => {
7259
+ newList.append(item);
7260
+ });
7261
+
7262
+ nonEmptyBlockquoteSiblings.forEach(sibling => {
7263
+ newBlockquote.append(sibling);
7264
+ });
7265
+
7266
+ emptyListItem.remove();
7267
+
7268
+ this.#removeTrailingEmptyListItems(parentList);
7269
+ this.#removeTrailingEmptyNodes(newBlockquote);
7270
+
7271
+ if (parentList.getChildrenSize() === 0) {
7272
+ parentList.remove();
7273
+
7274
+ if (blockquote.getChildrenSize() === 0) {
7275
+ blockquote.remove();
7276
+ }
7277
+ } else {
7278
+ this.#removeTrailingEmptyNodes(blockquote);
7279
+ }
7280
+
7281
+ middleParagraph.selectStart();
7282
+ }
7283
+
7284
+ #removeTrailingEmptyListItems(list) {
7285
+ const items = list.getChildren();
7286
+ for (let i = items.length - 1; i >= 0; i--) {
7287
+ const item = items[i];
7288
+ if (ot$2(item) && this.#isNodeEmpty(item)) {
7289
+ item.remove();
7290
+ } else {
7291
+ break
7292
+ }
7293
+ }
7294
+ }
7295
+
7296
+ #removeTrailingEmptyNodes(blockquote) {
7297
+ const children = blockquote.getChildren();
7298
+ for (let i = children.length - 1; i >= 0; i--) {
7299
+ const child = children[i];
7300
+ if (this.#isNodeEmpty(child)) {
7301
+ child.remove();
7302
+ } else {
7303
+ break
7304
+ }
7305
+ }
7306
+ }
7307
+
7308
+ #splitBlockquote(blockquote, emptyParagraph, siblingsAfter) {
7309
+ const newParagraph = Li();
7310
+ blockquote.insertAfter(newParagraph);
7311
+
7312
+ const newBlockquote = _t$1();
7313
+ newParagraph.insertAfter(newBlockquote);
7314
+
7315
+ siblingsAfter.forEach(sibling => {
7316
+ newBlockquote.append(sibling);
7317
+ });
7318
+
7319
+ emptyParagraph.remove();
7320
+
7321
+ this.#removeTrailingEmptyNodes(blockquote);
7322
+ this.#removeTrailingEmptyNodes(newBlockquote);
7323
+
7324
+ newParagraph.selectStart();
7325
+ }
7326
+ }
7327
+
7036
7328
  class Contents {
7037
7329
  constructor(editorElement) {
7038
7330
  this.editorElement = editorElement;
7039
7331
  this.editor = editorElement.editor;
7332
+
7333
+ new FormatEscaper(editorElement).monitor();
7040
7334
  }
7041
7335
 
7042
7336
  insertHtml(html) {
@@ -7097,20 +7391,23 @@ class Contents {
7097
7391
  if (isFormatAppliedFn(topLevelElement)) {
7098
7392
  this.removeFormattingFromSelectedLines();
7099
7393
  } else {
7100
- this.insertNodeWrappingAllSelectedLines(newNodeFn);
7394
+ this.#insertNodeWrappingAllSelectedLines(newNodeFn);
7101
7395
  }
7102
7396
  });
7103
7397
  }
7104
7398
 
7105
- insertNodeWrappingAllSelectedLines(newNodeFn) {
7399
+ toggleNodeWrappingAllSelectedNodes(isFormatAppliedFn, newNodeFn) {
7106
7400
  this.editor.update(() => {
7107
7401
  const selection = Lr();
7108
7402
  if (!yr(selection)) return
7109
7403
 
7110
- if (selection.isCollapsed()) {
7111
- this.#wrapCurrentLine(selection, newNodeFn);
7404
+ const topLevelElement = selection.anchor.getNode().getTopLevelElementOrThrow();
7405
+
7406
+ // Check if format is already applied
7407
+ if (isFormatAppliedFn(topLevelElement)) {
7408
+ this.#unwrap(topLevelElement);
7112
7409
  } else {
7113
- this.#wrapMultipleSelectedLines(selection, newNodeFn);
7410
+ this.#insertNodeWrappingAllSelectedNodes(newNodeFn);
7114
7411
  }
7115
7412
  });
7116
7413
  }
@@ -7351,6 +7648,80 @@ class Contents {
7351
7648
  return this.editorElement.selection
7352
7649
  }
7353
7650
 
7651
+ #unwrap(node) {
7652
+ const children = node.getChildren();
7653
+
7654
+ children.forEach((child) => {
7655
+ node.insertBefore(child);
7656
+ });
7657
+
7658
+ node.remove();
7659
+ }
7660
+
7661
+ #insertNodeWrappingAllSelectedNodes(newNodeFn) {
7662
+ this.editor.update(() => {
7663
+ const selection = Lr();
7664
+ if (!yr(selection)) return
7665
+
7666
+ const selectedNodes = selection.extract();
7667
+ if (selectedNodes.length === 0) return
7668
+
7669
+ const topLevelElements = new Set();
7670
+ selectedNodes.forEach((node) => {
7671
+ const topLevel = node.getTopLevelElementOrThrow();
7672
+ topLevelElements.add(topLevel);
7673
+ });
7674
+
7675
+ const elements = this.#removeTrailingEmptyParagraphs(Array.from(topLevelElements));
7676
+ if (elements.length === 0) return
7677
+
7678
+ const wrappingNode = newNodeFn();
7679
+ elements[0].insertBefore(wrappingNode);
7680
+ elements.forEach((element) => {
7681
+ wrappingNode.append(element);
7682
+ });
7683
+
7684
+ wo(null);
7685
+ });
7686
+ }
7687
+
7688
+ #removeTrailingEmptyParagraphs(elements) {
7689
+ let lastNonEmptyIndex = elements.length - 1;
7690
+
7691
+ // Find the last non-empty paragraph
7692
+ while (lastNonEmptyIndex >= 0) {
7693
+ const element = elements[lastNonEmptyIndex];
7694
+ if (!Ii(element) || !this.#isElementEmpty(element)) {
7695
+ break
7696
+ }
7697
+ lastNonEmptyIndex--;
7698
+ }
7699
+
7700
+ return elements.slice(0, lastNonEmptyIndex + 1)
7701
+ }
7702
+
7703
+ #isElementEmpty(element) {
7704
+ // Check text content first
7705
+ if (element.getTextContent().trim() !== "") return false
7706
+
7707
+ // Check if it only contains line breaks
7708
+ const children = element.getChildren();
7709
+ return children.length === 0 || children.every(child => jn(child))
7710
+ }
7711
+
7712
+ #insertNodeWrappingAllSelectedLines(newNodeFn) {
7713
+ this.editor.update(() => {
7714
+ const selection = Lr();
7715
+ if (!yr(selection)) return
7716
+
7717
+ if (selection.isCollapsed()) {
7718
+ this.#wrapCurrentLine(selection, newNodeFn);
7719
+ } else {
7720
+ this.#wrapMultipleSelectedLines(selection, newNodeFn);
7721
+ }
7722
+ });
7723
+ }
7724
+
7354
7725
  #wrapCurrentLine(selection, newNodeFn) {
7355
7726
  const anchorNode = selection.anchor.getNode();
7356
7727
  const topLevelElement = anchorNode.getTopLevelElementOrThrow();
@@ -7751,7 +8122,7 @@ class Clipboard {
7751
8122
 
7752
8123
  if (!clipboardData) return false
7753
8124
 
7754
- if (this.#isOnlyPlainTextPasted(clipboardData)) {
8125
+ if (this.#isOnlyPlainTextPasted(clipboardData) && !this.#isPastingIntoCodeBlock()) {
7755
8126
  this.#pastePlainText(clipboardData);
7756
8127
  event.preventDefault();
7757
8128
  return true
@@ -7765,6 +8136,27 @@ class Clipboard {
7765
8136
  return types.length === 1 && types[0] === "text/plain"
7766
8137
  }
7767
8138
 
8139
+ #isPastingIntoCodeBlock() {
8140
+ let result = false;
8141
+
8142
+ this.editor.getEditorState().read(() => {
8143
+ const selection = Lr();
8144
+ if (!yr(selection)) return
8145
+
8146
+ let currentNode = selection.anchor.getNode();
8147
+
8148
+ while (currentNode) {
8149
+ if (X$1(currentNode)) {
8150
+ result = true;
8151
+ return
8152
+ }
8153
+ currentNode = currentNode.getParent();
8154
+ }
8155
+ });
8156
+
8157
+ return result
8158
+ }
8159
+
7768
8160
  #pastePlainText(clipboardData) {
7769
8161
  const item = clipboardData.items[0];
7770
8162
  item.getAsString((text) => {
@@ -8501,8 +8893,8 @@ class LexicalPromptElement extends HTMLElement {
8501
8893
 
8502
8894
  async #showPopover() {
8503
8895
  this.popoverElement ??= await this.#buildPopover();
8896
+ this.#resetPopoverPosition();
8504
8897
  await this.#filterOptions();
8505
- this.#positionPopover();
8506
8898
  this.popoverElement.classList.toggle("lexxy-prompt-menu--visible", true);
8507
8899
  this.#selectFirstOption();
8508
8900
 
@@ -8557,19 +8949,29 @@ class LexicalPromptElement extends HTMLElement {
8557
8949
  const contentRect = this.#editorContentElement.getBoundingClientRect();
8558
8950
  const verticalOffset = contentRect.top - editorRect.top;
8559
8951
 
8560
- this.popoverElement.style.left = `${x}px`;
8952
+ if (!this.popoverElement.hasAttribute("data-anchored")) {
8953
+ this.popoverElement.style.left = `${x}px`;
8954
+ this.popoverElement.toggleAttribute("data-anchored", true);
8955
+ }
8956
+
8561
8957
  this.popoverElement.style.top = `${y + verticalOffset}px`;
8562
8958
  this.popoverElement.style.bottom = "auto";
8563
8959
 
8564
8960
  const popoverRect = this.popoverElement.getBoundingClientRect();
8565
8961
  const isClippedAtBottom = popoverRect.bottom > window.innerHeight;
8566
8962
 
8567
- if (isClippedAtBottom) {
8568
- this.popoverElement.style.bottom = `${y - verticalOffset + fontSize}px`;
8569
- this.popoverElement.style.top = "auto";
8963
+ if (isClippedAtBottom || this.popoverElement.hasAttribute("data-clipped-at-bottom")) {
8964
+ this.popoverElement.style.top = `${y + verticalOffset - popoverRect.height - fontSize}px`;
8965
+ this.popoverElement.style.bottom = "auto";
8966
+ this.popoverElement.toggleAttribute("data-clipped-at-bottom", true);
8570
8967
  }
8571
8968
  }
8572
8969
 
8970
+ #resetPopoverPosition() {
8971
+ this.popoverElement.removeAttribute("data-clipped-at-bottom");
8972
+ this.popoverElement.removeAttribute("data-anchored");
8973
+ }
8974
+
8573
8975
  async #hidePopover() {
8574
8976
  this.#clearSelection();
8575
8977
  this.popoverElement.classList.toggle("lexxy-prompt-menu--visible", false);
@@ -8595,6 +8997,7 @@ class LexicalPromptElement extends HTMLElement {
8595
8997
 
8596
8998
  if (this.#editorContents.containsTextBackUntil(this.trigger)) {
8597
8999
  await this.#showFilteredOptions();
9000
+ this.#positionPopover();
8598
9001
  } else {
8599
9002
  this.#hidePopover();
8600
9003
  }
Binary file
Binary file