lexxy 0.9.10.beta → 0.9.11.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: 2024c70d60976f4adb581f6159aabff11b43b0ebc4f9ac97ed0cc8abb274b6a5
4
- data.tar.gz: debcaecfaaa76add426101adcdace209a627fbf28cc64fa3c23e7606e018a498
3
+ metadata.gz: ef69b926b8319017e570cf09c7350d7f9c57661f0619858200bc91e734084acc
4
+ data.tar.gz: 596bfbfcc0698ddde22d64b7b3c5f1ae9bd61f230729242d0f784667411aac7c
5
5
  SHA512:
6
- metadata.gz: 78ad7f015a4f7572411625e02e0ebc3454822f417500ac7a7dcdc431f8985e481543472eaa719e959faf159d141d2247818858dc3027465b13e751be1d3e25b8
7
- data.tar.gz: 2d4d79a3d49de53d52c7a6284d2cac605cc152d8e86831af14ac76e2b7eea21e163549640369571c29d7a2da49b7a91213a6e52e411448c652b569f0f876e87b
6
+ metadata.gz: efcf8ed40d96b16bee9c19e6a65b2ec461e9d498213ded2f9aa5e8b0c87222da464ae370c43d5c7d07b102bd4f27e67a12f288fba34bdffca29587bbb8c0dd16
7
+ data.tar.gz: 8a6694608d8a43e8a994d2d31960839580d71e591aa4866187f018796544c03b3e397eb275a672752de37d108b555062ba3acf887d1776106298fcf960fc9c66
@@ -6786,15 +6786,23 @@ class LexicalToolbarElement extends HTMLElement {
6786
6786
  #setButtonPressed(name, isPressed) {
6787
6787
  const button = this.querySelector(`[name="${name}"]`);
6788
6788
  if (button) {
6789
- button.setAttribute("aria-pressed", isPressed.toString());
6789
+ const next = isPressed.toString();
6790
+ if (button.getAttribute("aria-pressed") !== next) {
6791
+ button.setAttribute("aria-pressed", next);
6792
+ }
6790
6793
  }
6791
6794
  }
6792
6795
 
6793
6796
  #setButtonDisabled(name, isDisabled) {
6794
6797
  const button = this.querySelector(`[name="${name}"]`);
6795
6798
  if (button) {
6796
- button.disabled = isDisabled;
6797
- button.setAttribute("aria-disabled", isDisabled.toString());
6799
+ if (button.disabled !== isDisabled) {
6800
+ button.disabled = isDisabled;
6801
+ }
6802
+ const next = isDisabled.toString();
6803
+ if (button.getAttribute("aria-disabled") !== next) {
6804
+ button.setAttribute("aria-disabled", next);
6805
+ }
6798
6806
  }
6799
6807
  }
6800
6808
 
@@ -7411,6 +7419,18 @@ class LexxyExtension {
7411
7419
  initializeToolbar(_lexxyToolbar) {
7412
7420
 
7413
7421
  }
7422
+
7423
+ dispose() {
7424
+ }
7425
+ }
7426
+
7427
+ function $containsRangeSelection(node, selection = $r()) {
7428
+ if (wr(selection)) {
7429
+ const { commonAncestor } = Al(selection.focus.getNode(), selection.anchor.getNode());
7430
+ return Xs(commonAncestor, parent => parent.is(node))
7431
+ } else {
7432
+ return false
7433
+ }
7414
7434
  }
7415
7435
 
7416
7436
  function $createNodeSelectionWith(...nodes) {
@@ -9196,17 +9216,12 @@ class CommandDispatcher {
9196
9216
  this.editor = editorElement.editor;
9197
9217
  this.selection = editorElement.selection;
9198
9218
  this.contents = editorElement.contents;
9199
- this.clipboard = editorElement.clipboard;
9200
9219
 
9201
9220
  this.#registerCommands();
9202
9221
  this.#registerKeyboardCommands();
9203
9222
  this.#registerDragAndDropHandlers();
9204
9223
  }
9205
9224
 
9206
- dispatchPaste(event) {
9207
- return this.clipboard.paste(event)
9208
- }
9209
-
9210
9225
  dispatchBold() {
9211
9226
  this.editor.dispatchCommand(me$2, "bold");
9212
9227
  }
@@ -9433,8 +9448,6 @@ class CommandDispatcher {
9433
9448
  const methodName = `dispatch${capitalize(command)}`;
9434
9449
  this.#registerCommandHandler(command, 0, this[methodName].bind(this));
9435
9450
  }
9436
-
9437
- this.#registerCommandHandler(ge$3, Gi, this.dispatchPaste.bind(this));
9438
9451
  }
9439
9452
 
9440
9453
  #registerCommandHandler(command, priority, handler) {
@@ -9795,6 +9808,11 @@ class Selection {
9795
9808
  return $isActionTextAttachmentNode(firstNode) && firstNode.isPreviewableImage
9796
9809
  }
9797
9810
 
9811
+ get isAtNodeStart() {
9812
+ const { anchorNode, offset } = this.#getCollapsedSelectionData();
9813
+ return anchorNode && offset === 0
9814
+ }
9815
+
9798
9816
  get nodeAfterCursor() {
9799
9817
  const { anchorNode, offset } = this.#getCollapsedSelectionData();
9800
9818
  if (!anchorNode) return null
@@ -10969,8 +10987,9 @@ class Uploader {
10969
10987
  return new UploaderKlass(editorElement, files)
10970
10988
  }
10971
10989
 
10972
- constructor(editorElement, files) {
10990
+ constructor(editorElement, files, options = {}) {
10973
10991
  this.#files = files;
10992
+ this.options = options;
10974
10993
 
10975
10994
  this.editorElement = editorElement;
10976
10995
  this.contents = editorElement.contents;
@@ -11012,10 +11031,10 @@ class GalleryUploader extends Uploader {
11012
11031
  #gallery
11013
11032
 
11014
11033
  static handle(editorElement, files) {
11015
- return this.#isMultipleImageUpload(files) || this.#gallerySelection(editorElement.selection)
11034
+ return this.isMultipleImageUpload(files) || this.gallerySelection(editorElement.selection)
11016
11035
  }
11017
11036
 
11018
- static #isMultipleImageUpload(files) {
11037
+ static isMultipleImageUpload(files) {
11019
11038
  let imageFileCount = 0;
11020
11039
  for (const file of files) {
11021
11040
  if (isPreviewableImage(file.type)) imageFileCount++;
@@ -11024,11 +11043,12 @@ class GalleryUploader extends Uploader {
11024
11043
  return false
11025
11044
  }
11026
11045
 
11027
- static #gallerySelection(selection) {
11028
- if (selection.isOnPreviewableImage) return true
11046
+ static gallerySelection(selection) {
11047
+ return selection.isOnPreviewableImage || this.selectionIsAfterGalleryEdge(selection)
11048
+ }
11029
11049
 
11030
- const { node: selectedNode } = selection.selectedNodeWithOffset();
11031
- return St$3(selectedNode, ImageGalleryNode) !== null
11050
+ static selectionIsAfterGalleryEdge(selection) {
11051
+ return selection.isAtNodeStart && ImageGalleryNode.canCollapseWith(selection.nodeBeforeCursor)
11032
11052
  }
11033
11053
 
11034
11054
  $insertUploadNodes() {
@@ -11040,18 +11060,26 @@ class GalleryUploader extends Uploader {
11040
11060
  #findOrCreateGallery() {
11041
11061
  if (this.selection.isOnPreviewableImage) {
11042
11062
  this.#gallery = $findOrCreateGalleryForImage(this.#selectedNode);
11063
+ } else if (this.#selectionIsAfterGalleryEdge) {
11064
+ this.#gallery = $findOrCreateGalleryForImage(this.selection.nodeBeforeCursor);
11043
11065
  } else {
11044
11066
  this.#gallery = $createImageGalleryNode();
11045
11067
  this.contents.insertAtCursor(this.#gallery);
11046
11068
  }
11047
11069
  }
11048
11070
 
11071
+ get #selectionIsAfterGalleryEdge() {
11072
+ return this.constructor.selectionIsAfterGalleryEdge(this.selection)
11073
+ }
11074
+
11049
11075
  get #selectedNode() {
11050
11076
  const { node } = this.selection.selectedNodeWithOffset();
11051
11077
  return node
11052
11078
  }
11053
11079
 
11054
11080
  get #galleryInsertPosition() {
11081
+ if (this.#selectionIsAfterGalleryEdge) return this.#gallery.getChildrenSize()
11082
+
11055
11083
  const anchor = $r()?.anchor;
11056
11084
  const galleryHasElementSelection = anchor?.getNode().is(this.#gallery);
11057
11085
  if (galleryHasElementSelection) return anchor.offset
@@ -11851,10 +11879,22 @@ ${e}</tr>
11851
11879
  Please report this to https://github.com/markedjs/marked.`,e){let r="<p>An error occurred:</p><pre>"+w(n.message+"",true)+"</pre>";return t?Promise.resolve(r):r}if(t)return Promise.reject(n);throw n}}};var _=new B;function k(u,e){return _.parse(u,e)}k.options=k.setOptions=function(u){return _.setOptions(u),k.defaults=_.defaults,G(k.defaults),k};k.getDefaults=L;k.defaults=T;k.use=function(...u){return _.use(...u),k.defaults=_.defaults,G(k.defaults),k};k.walkTokens=function(u,e){return _.walkTokens(u,e)};k.parseInline=_.parseInline;k.Parser=b;k.parser=b.parse;k.Renderer=P;k.TextRenderer=$;k.Lexer=x;k.lexer=x.lex;k.Tokenizer=y;k.Hooks=S;k.parse=k;k.options;k.setOptions;k.use;k.walkTokens;k.parseInline;b.parse;x.lex;
11852
11880
 
11853
11881
  class Clipboard {
11882
+ #listeners = new ListenerBin()
11883
+
11854
11884
  constructor(editorElement) {
11855
11885
  this.editorElement = editorElement;
11856
11886
  this.editor = editorElement.editor;
11857
11887
  this.contents = editorElement.contents;
11888
+
11889
+ this.#registerPasteCommands();
11890
+ }
11891
+
11892
+ dispose() {
11893
+ this.editorElement = null;
11894
+ this.editor = null;
11895
+ this.contents = null;
11896
+
11897
+ this.#listeners.dispose();
11858
11898
  }
11859
11899
 
11860
11900
  paste(event) {
@@ -11879,6 +11919,25 @@ class Clipboard {
11879
11919
  return handled
11880
11920
  }
11881
11921
 
11922
+ #registerPasteCommands() {
11923
+ this.#listeners.track(
11924
+ this.editor.registerCommand(ge$3, this.paste.bind(this), Xi),
11925
+ this.editor.registerCommand(
11926
+ ie$4,
11927
+ (payload) => this.#handleParsedClipboardNodes(payload),
11928
+ Xi
11929
+ )
11930
+ );
11931
+ }
11932
+
11933
+ #handleParsedClipboardNodes({ nodes, selection }) {
11934
+ const url = $bareUrlFromSingleLink(nodes);
11935
+ if (!url) return false
11936
+
11937
+ this.#insertSingleLinkAt(selection, url);
11938
+ return true
11939
+ }
11940
+
11882
11941
  #isPlainTextOrURLPasted(clipboardData) {
11883
11942
  return this.#isOnlyPlainTextPasted(clipboardData) || this.#isOnlyURLPasted(clipboardData)
11884
11943
  }
@@ -11941,6 +12000,24 @@ class Clipboard {
11941
12000
  });
11942
12001
  }
11943
12002
 
12003
+ #insertSingleLinkAt(selection, url) {
12004
+ if (!wr(selection)) return
12005
+
12006
+ if (!selection.isCollapsed()) {
12007
+ Q$1(null);
12008
+ Q$1(url);
12009
+ return
12010
+ }
12011
+
12012
+ const linkNode = $$1(url).append(pr(url));
12013
+ selection.insertNodes([ linkNode ]);
12014
+
12015
+ // Defer the lexxy:insert-link event until after the active update commits;
12016
+ // listeners may run editor mutations of their own.
12017
+ const nodeKey = linkNode.getKey();
12018
+ Promise.resolve().then(() => this.#dispatchLinkInsertEvent(nodeKey, { url }));
12019
+ }
12020
+
11944
12021
  #dispatchLinkInsertEvent(nodeKey, payload) {
11945
12022
  const linkManipulationMethods = {
11946
12023
  replaceLinkWith: (html, options) => this.contents.replaceNodeWithHTML(nodeKey, html, options),
@@ -12032,6 +12109,28 @@ class Clipboard {
12032
12109
  }
12033
12110
  }
12034
12111
 
12112
+ function $bareUrlFromSingleLink(nodes) {
12113
+ if (nodes.length !== 1) return null
12114
+
12115
+ const node = nodes[0];
12116
+ if (z$3(node)) return $bareUrlFromLink(node)
12117
+
12118
+ if (qi(node)) {
12119
+ const children = node.getChildren();
12120
+ if (children.length === 1 && z$3(children[0])) {
12121
+ return $bareUrlFromLink(children[0])
12122
+ }
12123
+ }
12124
+
12125
+ return null
12126
+ }
12127
+
12128
+ function $bareUrlFromLink(linkNode) {
12129
+ const url = linkNode.getURL();
12130
+ if (!url) return null
12131
+ return linkNode.getTextContent() === url ? url : null
12132
+ }
12133
+
12035
12134
  class Extensions {
12036
12135
 
12037
12136
  constructor(lexxyElement) {
@@ -12052,6 +12151,12 @@ class Extensions {
12052
12151
  this.#addExtensionToolbarButtons(toolbar);
12053
12152
  }
12054
12153
 
12154
+ dispose() {
12155
+ while (this.enabledExtensions.length) {
12156
+ this.enabledExtensions.pop().dispose();
12157
+ }
12158
+ }
12159
+
12055
12160
  #clearPreviousExtensionToolbarButtons(toolbar) {
12056
12161
  toolbar.querySelectorAll("[data-lexxy-extension]").forEach(el => el.remove());
12057
12162
  }
@@ -12457,9 +12562,15 @@ class TablesExtension extends LexxyExtension {
12457
12562
  yn(editor);
12458
12563
 
12459
12564
  return ic(
12460
- // Register Lexical table plugins
12461
12565
  $n(editor),
12462
- Mn(editor, true),
12566
+
12567
+ // Lexxy registers extensions before setRootElement(), but table
12568
+ // drag-selection needs a root before wiring its pointer handlers.
12569
+ editor.registerRootListener((rootElement) => {
12570
+ if (rootElement) {
12571
+ return Mn(editor, true)
12572
+ }
12573
+ }),
12463
12574
 
12464
12575
  // Bug fix: Prevent hardcoded background color (Lexical #8089)
12465
12576
  editor.registerNodeTransform(Ke$1, (node) => {
@@ -13167,7 +13278,8 @@ class FormatEscapeExtension extends LexxyExtension {
13167
13278
  we$1,
13168
13279
  (event) => $handleArrowDownInCodeBlock(event),
13169
13280
  Xi
13170
- )
13281
+ ),
13282
+ editor.registerNodeTransform(Ft$2, $ensureQuoteHasParagraphChild)
13171
13283
  )
13172
13284
  }
13173
13285
  })
@@ -13220,6 +13332,13 @@ function $handleArrowDownInCodeBlock(event) {
13220
13332
  return false
13221
13333
  }
13222
13334
 
13335
+ function $ensureQuoteHasParagraphChild(quoteNode) {
13336
+ if (!quoteNode.isEmpty()) return
13337
+
13338
+ quoteNode.append(Yi());
13339
+ if ($containsRangeSelection(quoteNode)) quoteNode.getFirstChild().select();
13340
+ }
13341
+
13223
13342
  class LinkOpenerExtension extends LexxyExtension {
13224
13343
  get enabled() {
13225
13344
  return this.editorElement.supportsRichText
@@ -13307,6 +13426,7 @@ class LexicalEditorElement extends HTMLElement {
13307
13426
  this.id ||= generateDomId("lexxy-editor");
13308
13427
  this.config = new EditorConfiguration(this);
13309
13428
  this.extensions = new Extensions(this);
13429
+ this.#disposables.push(this.extensions);
13310
13430
 
13311
13431
  this.editor = this.#createEditor();
13312
13432
  this.#disposables.push(this.editor);
@@ -13319,6 +13439,8 @@ class LexicalEditorElement extends HTMLElement {
13319
13439
  this.#disposables.push(this.selection);
13320
13440
 
13321
13441
  this.clipboard = new Clipboard(this);
13442
+ this.#disposables.push(this.clipboard);
13443
+
13322
13444
  this.adapter = new BrowserAdapter();
13323
13445
 
13324
13446
  const commandDispatcher = CommandDispatcher.configureFor(this);
@@ -14283,7 +14405,10 @@ class HighlightDropdown extends ToolbarDropdown {
14283
14405
 
14284
14406
  this.#colorButtons.forEach(button => {
14285
14407
  const matchesSelection = button.dataset.value === textColor || button.dataset.value === backgroundColor;
14286
- button.setAttribute("aria-pressed", matchesSelection);
14408
+ const next = matchesSelection.toString();
14409
+ if (button.getAttribute("aria-pressed") !== next) {
14410
+ button.setAttribute("aria-pressed", next);
14411
+ }
14287
14412
  });
14288
14413
 
14289
14414
  const hasHighlight = textColor !== NO_STYLE || backgroundColor !== NO_STYLE;
@@ -14691,7 +14816,7 @@ class LexicalPromptElement extends HTMLElement {
14691
14816
  }
14692
14817
 
14693
14818
  #selectOption(listItem) {
14694
- this.#clearSelection();
14819
+ this.#clearListItemSelection();
14695
14820
  listItem.toggleAttribute("aria-selected", true);
14696
14821
  listItem.scrollIntoView({ block: "nearest", behavior: "smooth" });
14697
14822
  listItem.focus();
@@ -14701,18 +14826,28 @@ class LexicalPromptElement extends HTMLElement {
14701
14826
  this.#editorElement.focus();
14702
14827
  });
14703
14828
 
14704
- this.#editorContentElement.setAttribute("aria-controls", this.popoverElement.id);
14705
- this.#editorContentElement.setAttribute("aria-activedescendant", listItem.id);
14706
- this.#editorContentElement.setAttribute("aria-haspopup", "listbox");
14829
+ this.#setEditorAssociationAttribute("aria-controls", this.popoverElement.id);
14830
+ this.#setEditorAssociationAttribute("aria-activedescendant", listItem.id);
14831
+ this.#setEditorAssociationAttribute("aria-haspopup", "listbox");
14707
14832
  }
14708
14833
 
14709
- #clearSelection() {
14834
+ #clearListItemSelection() {
14710
14835
  this.#listItemElements.forEach((item) => { item.toggleAttribute("aria-selected", false); });
14836
+ }
14837
+
14838
+ #clearSelection() {
14839
+ this.#clearListItemSelection();
14711
14840
  this.#editorContentElement.removeAttribute("aria-controls");
14712
14841
  this.#editorContentElement.removeAttribute("aria-activedescendant");
14713
14842
  this.#editorContentElement.removeAttribute("aria-haspopup");
14714
14843
  }
14715
14844
 
14845
+ #setEditorAssociationAttribute(name, value) {
14846
+ if (this.#editorContentElement.getAttribute(name) !== value) {
14847
+ this.#editorContentElement.setAttribute(name, value);
14848
+ }
14849
+ }
14850
+
14716
14851
  #positionPopover() {
14717
14852
  const { x, y, fontSize } = this.#selection.cursorPosition;
14718
14853
  const editorRect = this.#editorElement.getBoundingClientRect();
@@ -15906,13 +16041,11 @@ function highlightElement(preElement) {
15906
16041
  code = new DOMParser().parseFromString(code, "text/html").body.textContent || "";
15907
16042
 
15908
16043
  const highlightedHtml = Prism$1.highlight(code, grammar, language);
15909
- const codeElement = createElement("code", { "data-language": language, innerHTML: highlightedHtml });
16044
+ preElement.innerHTML = highlightedHtml;
15910
16045
 
15911
16046
  if (highlights.length > 0) {
15912
- applyHighlightRanges(codeElement, highlights);
16047
+ applyHighlightRanges(preElement, highlights);
15913
16048
  }
15914
-
15915
- preElement.replaceChildren(codeElement);
15916
16049
  }
15917
16050
 
15918
16051
  // Walk the DOM tree inside a <pre> element and build a list of
Binary file
Binary file