lexxy 0.1.15.beta → 0.1.16.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: 2e4b2ba7be7dc40772a5d88716d907113e742771a1ebd83d24e8361823681516
4
+ data.tar.gz: 3a5533d0ca719b02923597e638968594986c89bc0dcb2284abf835b00c208a24
5
5
  SHA512:
6
- metadata.gz: '049f7df42895c9d3836198ab095978a9265306663f7782d15d2ff04553094ff7830d3d016f795a65c67e7f86b2b4a725d39bd88a9c6a7e8fd3c169802d0f165c'
7
- data.tar.gz: 45e059de86a63bbe4f3470ea2b3ec2c56706562ddf5ddaf7fa7d01aac637821af4bb2d2a45489725956a67fbc576d4ee0818705051fdc8d9884b2fb4490752d2
6
+ metadata.gz: 8ee0059a0a1849194bbfe200da4e00a802dd93784b33029d0f9de3cc82a64b6c0b87dfa49de03570bb71259d3cab9a4874c83810d45e92b9f8cbf778086f00ca
7
+ data.tar.gz: d7508eb4457d066ebaeb3b3e75ff536c1b955bcf361ba9501645d16c47aafad8687758939c18dce86809ef23e91163dd4e729fa30521d0443d5f094d8d6e4dea
@@ -6166,7 +6166,7 @@ class CommandDispatcher {
6166
6166
  }
6167
6167
 
6168
6168
  dispatchInsertQuoteBlock() {
6169
- this.contents.toggleNodeWrappingAllSelectedLines((node) => Ot$1(node), () => _t$1());
6169
+ this.contents.toggleNodeWrappingAllSelectedNodes((node) => Ot$1(node), () => _t$1());
6170
6170
  }
6171
6171
 
6172
6172
  dispatchInsertCodeBlock() {
@@ -7033,10 +7033,277 @@ class CustomActionTextAttachmentNode extends ki {
7033
7033
  }
7034
7034
  }
7035
7035
 
7036
+ class FormatEscaper {
7037
+ constructor(editorElement) {
7038
+ this.editorElement = editorElement;
7039
+ this.editor = editorElement.editor;
7040
+ }
7041
+
7042
+ monitor() {
7043
+ this.editor.registerCommand(
7044
+ Ne$1,
7045
+ (event) => this.#handleEnterKey(event),
7046
+ Bi
7047
+ );
7048
+ }
7049
+
7050
+ #handleEnterKey(event) {
7051
+ const selection = Lr();
7052
+ if (!yr(selection)) return false
7053
+
7054
+ const anchorNode = selection.anchor.getNode();
7055
+
7056
+ return this.#handleLists(event, anchorNode)
7057
+ || this.#handleBlockquotes(event, anchorNode)
7058
+ }
7059
+
7060
+ #handleLists(event, anchorNode) {
7061
+ if (this.#shouldEscapeFromEmptyListItem(anchorNode) || this.#shouldEscapeFromEmptyParagraphInListItem(anchorNode)) {
7062
+ event.preventDefault();
7063
+ this.#escapeFromList(anchorNode);
7064
+ return true
7065
+ }
7066
+
7067
+ return false
7068
+ }
7069
+
7070
+ #handleBlockquotes(event, anchorNode) {
7071
+ if (this.#shouldEscapeFromEmptyParagraphInBlockquote(anchorNode)) {
7072
+ event.preventDefault();
7073
+ this.#escapeFromBlockquote(anchorNode);
7074
+ return true
7075
+ }
7076
+
7077
+ return false
7078
+ }
7079
+
7080
+ #shouldEscapeFromEmptyListItem(node) {
7081
+ const listItem = this.#getListItemNode(node);
7082
+ if (!listItem) return false
7083
+
7084
+ return this.#isNodeEmpty(listItem)
7085
+ }
7086
+
7087
+ #shouldEscapeFromEmptyParagraphInListItem(node) {
7088
+ const paragraph = this.#getParagraphNode(node);
7089
+ if (!paragraph) return false
7090
+
7091
+ if (!this.#isNodeEmpty(paragraph)) return false
7092
+
7093
+ const parent = paragraph.getParent();
7094
+ return parent && ot$2(parent)
7095
+ }
7096
+
7097
+ #isNodeEmpty(node) {
7098
+ if (node.getTextContent().trim() !== "") return false
7099
+
7100
+ const children = node.getChildren();
7101
+ if (children.length === 0) return true
7102
+
7103
+ return children.every(child => {
7104
+ if (jn(child)) return true
7105
+ return this.#isNodeEmpty(child)
7106
+ })
7107
+ }
7108
+
7109
+ #getListItemNode(node) {
7110
+ let currentNode = node;
7111
+
7112
+ while (currentNode) {
7113
+ if (ot$2(currentNode)) {
7114
+ return currentNode
7115
+ }
7116
+ currentNode = currentNode.getParent();
7117
+ }
7118
+
7119
+ return null
7120
+ }
7121
+
7122
+ #escapeFromList(anchorNode) {
7123
+ const listItem = this.#getListItemNode(anchorNode);
7124
+ if (!listItem) return
7125
+
7126
+ const parentList = listItem.getParent();
7127
+ if (!parentList || !dt$1(parentList)) return
7128
+
7129
+ const blockquote = parentList.getParent();
7130
+ const isInBlockquote = blockquote && Ot$1(blockquote);
7131
+
7132
+ if (isInBlockquote) {
7133
+ const listItemsAfter = this.#getListItemSiblingsAfter(listItem);
7134
+ const nonEmptyListItems = listItemsAfter.filter(item => !this.#isNodeEmpty(item));
7135
+
7136
+ if (nonEmptyListItems.length > 0) {
7137
+ this.#splitBlockquoteWithList(blockquote, parentList, listItem, nonEmptyListItems);
7138
+ return
7139
+ }
7140
+ }
7141
+
7142
+ const paragraph = Li();
7143
+ parentList.insertAfter(paragraph);
7144
+
7145
+ listItem.remove();
7146
+ paragraph.selectStart();
7147
+ }
7148
+
7149
+ #shouldEscapeFromEmptyParagraphInBlockquote(node) {
7150
+ const paragraph = this.#getParagraphNode(node);
7151
+ if (!paragraph) return false
7152
+
7153
+ if (!this.#isNodeEmpty(paragraph)) return false
7154
+
7155
+ const parent = paragraph.getParent();
7156
+ return parent && Ot$1(parent)
7157
+ }
7158
+
7159
+ #getParagraphNode(node) {
7160
+ let currentNode = node;
7161
+
7162
+ while (currentNode) {
7163
+ if (Ii(currentNode)) {
7164
+ return currentNode
7165
+ }
7166
+ currentNode = currentNode.getParent();
7167
+ }
7168
+
7169
+ return null
7170
+ }
7171
+
7172
+ #escapeFromBlockquote(anchorNode) {
7173
+ const paragraph = this.#getParagraphNode(anchorNode);
7174
+ if (!paragraph) return
7175
+
7176
+ const blockquote = paragraph.getParent();
7177
+ if (!blockquote || !Ot$1(blockquote)) return
7178
+
7179
+ const siblingsAfter = this.#getSiblingsAfter(paragraph);
7180
+ const nonEmptySiblings = siblingsAfter.filter(sibling => !this.#isNodeEmpty(sibling));
7181
+
7182
+ if (nonEmptySiblings.length > 0) {
7183
+ this.#splitBlockquote(blockquote, paragraph, nonEmptySiblings);
7184
+ } else {
7185
+ const newParagraph = Li();
7186
+ blockquote.insertAfter(newParagraph);
7187
+ paragraph.remove();
7188
+ newParagraph.selectStart();
7189
+ }
7190
+ }
7191
+
7192
+ #getSiblingsAfter(node) {
7193
+ const siblings = [];
7194
+ let sibling = node.getNextSibling();
7195
+
7196
+ while (sibling) {
7197
+ siblings.push(sibling);
7198
+ sibling = sibling.getNextSibling();
7199
+ }
7200
+
7201
+ return siblings
7202
+ }
7203
+
7204
+ #getListItemSiblingsAfter(listItem) {
7205
+ const siblings = [];
7206
+ let sibling = listItem.getNextSibling();
7207
+
7208
+ while (sibling) {
7209
+ if (ot$2(sibling)) {
7210
+ siblings.push(sibling);
7211
+ }
7212
+ sibling = sibling.getNextSibling();
7213
+ }
7214
+
7215
+ return siblings
7216
+ }
7217
+
7218
+ #splitBlockquoteWithList(blockquote, parentList, emptyListItem, listItemsAfter) {
7219
+ const blockquoteSiblingsAfterList = this.#getSiblingsAfter(parentList);
7220
+ const nonEmptyBlockquoteSiblings = blockquoteSiblingsAfterList.filter(sibling => !this.#isNodeEmpty(sibling));
7221
+
7222
+ const middleParagraph = Li();
7223
+ blockquote.insertAfter(middleParagraph);
7224
+
7225
+ const newList = ht$3(parentList.getListType());
7226
+
7227
+ const newBlockquote = _t$1();
7228
+ middleParagraph.insertAfter(newBlockquote);
7229
+ newBlockquote.append(newList);
7230
+
7231
+ listItemsAfter.forEach(item => {
7232
+ newList.append(item);
7233
+ });
7234
+
7235
+ nonEmptyBlockquoteSiblings.forEach(sibling => {
7236
+ newBlockquote.append(sibling);
7237
+ });
7238
+
7239
+ emptyListItem.remove();
7240
+
7241
+ this.#removeTrailingEmptyListItems(parentList);
7242
+ this.#removeTrailingEmptyNodes(newBlockquote);
7243
+
7244
+ if (parentList.getChildrenSize() === 0) {
7245
+ parentList.remove();
7246
+
7247
+ if (blockquote.getChildrenSize() === 0) {
7248
+ blockquote.remove();
7249
+ }
7250
+ } else {
7251
+ this.#removeTrailingEmptyNodes(blockquote);
7252
+ }
7253
+
7254
+ middleParagraph.selectStart();
7255
+ }
7256
+
7257
+ #removeTrailingEmptyListItems(list) {
7258
+ const items = list.getChildren();
7259
+ for (let i = items.length - 1; i >= 0; i--) {
7260
+ const item = items[i];
7261
+ if (ot$2(item) && this.#isNodeEmpty(item)) {
7262
+ item.remove();
7263
+ } else {
7264
+ break
7265
+ }
7266
+ }
7267
+ }
7268
+
7269
+ #removeTrailingEmptyNodes(blockquote) {
7270
+ const children = blockquote.getChildren();
7271
+ for (let i = children.length - 1; i >= 0; i--) {
7272
+ const child = children[i];
7273
+ if (this.#isNodeEmpty(child)) {
7274
+ child.remove();
7275
+ } else {
7276
+ break
7277
+ }
7278
+ }
7279
+ }
7280
+
7281
+ #splitBlockquote(blockquote, emptyParagraph, siblingsAfter) {
7282
+ const newParagraph = Li();
7283
+ blockquote.insertAfter(newParagraph);
7284
+
7285
+ const newBlockquote = _t$1();
7286
+ newParagraph.insertAfter(newBlockquote);
7287
+
7288
+ siblingsAfter.forEach(sibling => {
7289
+ newBlockquote.append(sibling);
7290
+ });
7291
+
7292
+ emptyParagraph.remove();
7293
+
7294
+ this.#removeTrailingEmptyNodes(blockquote);
7295
+ this.#removeTrailingEmptyNodes(newBlockquote);
7296
+
7297
+ newParagraph.selectStart();
7298
+ }
7299
+ }
7300
+
7036
7301
  class Contents {
7037
7302
  constructor(editorElement) {
7038
7303
  this.editorElement = editorElement;
7039
7304
  this.editor = editorElement.editor;
7305
+
7306
+ new FormatEscaper(editorElement).monitor();
7040
7307
  }
7041
7308
 
7042
7309
  insertHtml(html) {
@@ -7097,20 +7364,23 @@ class Contents {
7097
7364
  if (isFormatAppliedFn(topLevelElement)) {
7098
7365
  this.removeFormattingFromSelectedLines();
7099
7366
  } else {
7100
- this.insertNodeWrappingAllSelectedLines(newNodeFn);
7367
+ this.#insertNodeWrappingAllSelectedLines(newNodeFn);
7101
7368
  }
7102
7369
  });
7103
7370
  }
7104
7371
 
7105
- insertNodeWrappingAllSelectedLines(newNodeFn) {
7372
+ toggleNodeWrappingAllSelectedNodes(isFormatAppliedFn, newNodeFn) {
7106
7373
  this.editor.update(() => {
7107
7374
  const selection = Lr();
7108
7375
  if (!yr(selection)) return
7109
7376
 
7110
- if (selection.isCollapsed()) {
7111
- this.#wrapCurrentLine(selection, newNodeFn);
7377
+ const topLevelElement = selection.anchor.getNode().getTopLevelElementOrThrow();
7378
+
7379
+ // Check if format is already applied
7380
+ if (isFormatAppliedFn(topLevelElement)) {
7381
+ this.#unwrap(topLevelElement);
7112
7382
  } else {
7113
- this.#wrapMultipleSelectedLines(selection, newNodeFn);
7383
+ this.#insertNodeWrappingAllSelectedNodes(newNodeFn);
7114
7384
  }
7115
7385
  });
7116
7386
  }
@@ -7351,6 +7621,80 @@ class Contents {
7351
7621
  return this.editorElement.selection
7352
7622
  }
7353
7623
 
7624
+ #unwrap(node) {
7625
+ const children = node.getChildren();
7626
+
7627
+ children.forEach((child) => {
7628
+ node.insertBefore(child);
7629
+ });
7630
+
7631
+ node.remove();
7632
+ }
7633
+
7634
+ #insertNodeWrappingAllSelectedNodes(newNodeFn) {
7635
+ this.editor.update(() => {
7636
+ const selection = Lr();
7637
+ if (!yr(selection)) return
7638
+
7639
+ const selectedNodes = selection.extract();
7640
+ if (selectedNodes.length === 0) return
7641
+
7642
+ const topLevelElements = new Set();
7643
+ selectedNodes.forEach((node) => {
7644
+ const topLevel = node.getTopLevelElementOrThrow();
7645
+ topLevelElements.add(topLevel);
7646
+ });
7647
+
7648
+ const elements = this.#removeTrailingEmptyParagraphs(Array.from(topLevelElements));
7649
+ if (elements.length === 0) return
7650
+
7651
+ const wrappingNode = newNodeFn();
7652
+ elements[0].insertBefore(wrappingNode);
7653
+ elements.forEach((element) => {
7654
+ wrappingNode.append(element);
7655
+ });
7656
+
7657
+ wo(null);
7658
+ });
7659
+ }
7660
+
7661
+ #removeTrailingEmptyParagraphs(elements) {
7662
+ let lastNonEmptyIndex = elements.length - 1;
7663
+
7664
+ // Find the last non-empty paragraph
7665
+ while (lastNonEmptyIndex >= 0) {
7666
+ const element = elements[lastNonEmptyIndex];
7667
+ if (!Ii(element) || !this.#isElementEmpty(element)) {
7668
+ break
7669
+ }
7670
+ lastNonEmptyIndex--;
7671
+ }
7672
+
7673
+ return elements.slice(0, lastNonEmptyIndex + 1)
7674
+ }
7675
+
7676
+ #isElementEmpty(element) {
7677
+ // Check text content first
7678
+ if (element.getTextContent().trim() !== "") return false
7679
+
7680
+ // Check if it only contains line breaks
7681
+ const children = element.getChildren();
7682
+ return children.length === 0 || children.every(child => jn(child))
7683
+ }
7684
+
7685
+ #insertNodeWrappingAllSelectedLines(newNodeFn) {
7686
+ this.editor.update(() => {
7687
+ const selection = Lr();
7688
+ if (!yr(selection)) return
7689
+
7690
+ if (selection.isCollapsed()) {
7691
+ this.#wrapCurrentLine(selection, newNodeFn);
7692
+ } else {
7693
+ this.#wrapMultipleSelectedLines(selection, newNodeFn);
7694
+ }
7695
+ });
7696
+ }
7697
+
7354
7698
  #wrapCurrentLine(selection, newNodeFn) {
7355
7699
  const anchorNode = selection.anchor.getNode();
7356
7700
  const topLevelElement = anchorNode.getTopLevelElementOrThrow();
@@ -7751,7 +8095,7 @@ class Clipboard {
7751
8095
 
7752
8096
  if (!clipboardData) return false
7753
8097
 
7754
- if (this.#isOnlyPlainTextPasted(clipboardData)) {
8098
+ if (this.#isOnlyPlainTextPasted(clipboardData) && !this.#isPastingIntoCodeBlock()) {
7755
8099
  this.#pastePlainText(clipboardData);
7756
8100
  event.preventDefault();
7757
8101
  return true
@@ -7765,6 +8109,27 @@ class Clipboard {
7765
8109
  return types.length === 1 && types[0] === "text/plain"
7766
8110
  }
7767
8111
 
8112
+ #isPastingIntoCodeBlock() {
8113
+ let result = false;
8114
+
8115
+ this.editor.getEditorState().read(() => {
8116
+ const selection = Lr();
8117
+ if (!yr(selection)) return
8118
+
8119
+ let currentNode = selection.anchor.getNode();
8120
+
8121
+ while (currentNode) {
8122
+ if (X$1(currentNode)) {
8123
+ result = true;
8124
+ return
8125
+ }
8126
+ currentNode = currentNode.getParent();
8127
+ }
8128
+ });
8129
+
8130
+ return result
8131
+ }
8132
+
7768
8133
  #pastePlainText(clipboardData) {
7769
8134
  const item = clipboardData.items[0];
7770
8135
  item.getAsString((text) => {
@@ -8501,8 +8866,8 @@ class LexicalPromptElement extends HTMLElement {
8501
8866
 
8502
8867
  async #showPopover() {
8503
8868
  this.popoverElement ??= await this.#buildPopover();
8869
+ this.#resetPopoverPosition();
8504
8870
  await this.#filterOptions();
8505
- this.#positionPopover();
8506
8871
  this.popoverElement.classList.toggle("lexxy-prompt-menu--visible", true);
8507
8872
  this.#selectFirstOption();
8508
8873
 
@@ -8557,19 +8922,29 @@ class LexicalPromptElement extends HTMLElement {
8557
8922
  const contentRect = this.#editorContentElement.getBoundingClientRect();
8558
8923
  const verticalOffset = contentRect.top - editorRect.top;
8559
8924
 
8560
- this.popoverElement.style.left = `${x}px`;
8925
+ if (!this.popoverElement.hasAttribute("data-anchored")) {
8926
+ this.popoverElement.style.left = `${x}px`;
8927
+ this.popoverElement.toggleAttribute("data-anchored", true);
8928
+ }
8929
+
8561
8930
  this.popoverElement.style.top = `${y + verticalOffset}px`;
8562
8931
  this.popoverElement.style.bottom = "auto";
8563
8932
 
8564
8933
  const popoverRect = this.popoverElement.getBoundingClientRect();
8565
8934
  const isClippedAtBottom = popoverRect.bottom > window.innerHeight;
8566
8935
 
8567
- if (isClippedAtBottom) {
8568
- this.popoverElement.style.bottom = `${y - verticalOffset + fontSize}px`;
8569
- this.popoverElement.style.top = "auto";
8936
+ if (isClippedAtBottom || this.popoverElement.hasAttribute("data-clipped-at-bottom")) {
8937
+ this.popoverElement.style.top = `${y + verticalOffset - popoverRect.height - fontSize}px`;
8938
+ this.popoverElement.style.bottom = "auto";
8939
+ this.popoverElement.toggleAttribute("data-clipped-at-bottom", true);
8570
8940
  }
8571
8941
  }
8572
8942
 
8943
+ #resetPopoverPosition() {
8944
+ this.popoverElement.removeAttribute("data-clipped-at-bottom");
8945
+ this.popoverElement.removeAttribute("data-anchored");
8946
+ }
8947
+
8573
8948
  async #hidePopover() {
8574
8949
  this.#clearSelection();
8575
8950
  this.popoverElement.classList.toggle("lexxy-prompt-menu--visible", false);
@@ -8595,6 +8970,7 @@ class LexicalPromptElement extends HTMLElement {
8595
8970
 
8596
8971
  if (this.#editorContents.containsTextBackUntil(this.trigger)) {
8597
8972
  await this.#showFilteredOptions();
8973
+ this.#positionPopover();
8598
8974
  } else {
8599
8975
  this.#hidePopover();
8600
8976
  }
Binary file
Binary file