lexxy 0.9.2.beta → 0.9.3.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: a8ee9866b0433459ec013e80632d58c956e8183ac5fe33b42d046195714e943e
4
- data.tar.gz: f7801f5dec0979471d9b6e079632ed8b17b23564b13b3cebd5ea85609366f871
3
+ metadata.gz: 3ca2c3eeb9fff2ac0a2a3db6b68fc9bda7868fde5a36158ea77ac61d0eaea40d
4
+ data.tar.gz: c0390bfc97b15a212dd6cc07b273c21da5d641c37232fc039c2fde9c5c772d43
5
5
  SHA512:
6
- metadata.gz: fd915f18f31b55b22500c2c9d7a749fcb9cbe7cba02ec835f773ea697853d5c9a90617e1509bf5802664285adb4c31bc716fc70c99bcbf701a8fb79167ccbaf9
7
- data.tar.gz: 43e49d501e92e3fca8338ab1f09a9ae449f4e6ad733d4a6b4542ec9e3be3676cdc20780a87f476e0c804b61fea2be88220c888ea4b13bf49ca1b1eb3322891c9
6
+ metadata.gz: ab64196f9538299e4c731b4d0be010455f14b705b3fe2f3936091f9c33387957b8d74ac2f7a3aa03a7044224ebb32574a26dae33c563a878a77f00b8c6e79c58
7
+ data.tar.gz: 790f9af92cb872bdc45b68e55976e54f23b75a83f1cb95ac93218294cd5f44415fde9d8d53e02f752577d74c648e73dd86d3799bf40fbab2524b77fa32d00e7d
@@ -7688,6 +7688,24 @@ function isSelectionHighlighted(selection) {
7688
7688
  }
7689
7689
  }
7690
7690
 
7691
+ function getHighlightStyles(selection) {
7692
+ if (!wr(selection)) return null
7693
+
7694
+ let styles = b$3(selection.style);
7695
+ if (!styles.color && !styles["background-color"]) {
7696
+ const anchorNode = selection.anchor.getNode();
7697
+ if (yr(anchorNode)) {
7698
+ styles = b$3(anchorNode.getStyle());
7699
+ }
7700
+ }
7701
+
7702
+ const color = styles.color || null;
7703
+ const backgroundColor = styles["background-color"] || null;
7704
+ if (!color && !backgroundColor) return null
7705
+
7706
+ return { color, backgroundColor }
7707
+ }
7708
+
7691
7709
  function hasHighlightStyles(cssOrStyles) {
7692
7710
  const styles = typeof cssOrStyles === "string" ? b$3(cssOrStyles) : cssOrStyles;
7693
7711
  return !!(styles.color || styles["background-color"])
@@ -8250,6 +8268,7 @@ const COMMANDS = [
8250
8268
  "insertOrderedList",
8251
8269
  "insertQuoteBlock",
8252
8270
  "insertCodeBlock",
8271
+ "setCodeLanguage",
8253
8272
  "insertHorizontalDivider",
8254
8273
  "uploadImage",
8255
8274
  "uploadFile",
@@ -8325,7 +8344,14 @@ class CommandDispatcher {
8325
8344
  }
8326
8345
 
8327
8346
  dispatchUnlink() {
8328
- this.#toggleLink(null);
8347
+ this.editor.update(() => {
8348
+ // Let adapters signal whether unlink should target a frozen link key.
8349
+ if (this.editorElement.adapter.unlinkFrozenNode?.()) {
8350
+ return
8351
+ }
8352
+
8353
+ Z$1(null);
8354
+ });
8329
8355
  }
8330
8356
 
8331
8357
  dispatchInsertUnorderedList() {
@@ -8416,6 +8442,17 @@ class CommandDispatcher {
8416
8442
  }
8417
8443
  }
8418
8444
 
8445
+ dispatchSetCodeLanguage(language) {
8446
+ this.editor.update(() => {
8447
+ if (!this.selection.isInsideCodeBlock) return
8448
+
8449
+ const codeNode = this.selection.nearestNodeOfType(U$1);
8450
+ if (!codeNode) return
8451
+
8452
+ codeNode.setLanguage(language);
8453
+ });
8454
+ }
8455
+
8419
8456
  dispatchInsertHorizontalDivider() {
8420
8457
  this.contents.insertAtCursorEnsuringLineBelow(new HorizontalDividerNode());
8421
8458
  this.editor.focus();
@@ -8614,16 +8651,6 @@ class CommandDispatcher {
8614
8651
  return wr(selection) && selection.isCollapsed()
8615
8652
  }
8616
8653
 
8617
- // Not using TOGGLE_LINK_COMMAND because it's not handled unless you use React/LinkPlugin
8618
- #toggleLink(url) {
8619
- this.editor.update(() => {
8620
- if (url === null) {
8621
- Z$1(null);
8622
- } else {
8623
- Z$1(url);
8624
- }
8625
- });
8626
- }
8627
8654
  }
8628
8655
 
8629
8656
  function capitalize(str) {
@@ -8850,8 +8877,8 @@ class ActionTextAttachmentNode extends Fi {
8850
8877
  return null
8851
8878
  }
8852
8879
 
8853
- createAttachmentFigure() {
8854
- const figure = createAttachmentFigure(this.contentType, this.isPreviewableAttachment, this.fileName);
8880
+ createAttachmentFigure(previewable = this.isPreviewableAttachment) {
8881
+ const figure = createAttachmentFigure(this.contentType, previewable, this.fileName);
8855
8882
  figure.draggable = true;
8856
8883
  figure.dataset.lexicalNodeKey = this.__key;
8857
8884
 
@@ -9936,9 +9963,12 @@ class ActionTextAttachmentUploadNode extends ActionTextAttachmentNode {
9936
9963
  // node is reloaded from saved state such as from history.
9937
9964
  this.#startUploadIfNeeded();
9938
9965
 
9939
- const figure = this.createAttachmentFigure();
9966
+ // Bridge-managed uploads (uploadUrl is null) don't have file data to show
9967
+ // an image preview, so always show the file icon during upload.
9968
+ const canPreviewFile = this.isPreviewableAttachment && this.uploadUrl != null;
9969
+ const figure = this.createAttachmentFigure(canPreviewFile);
9940
9970
 
9941
- if (this.isPreviewableAttachment) {
9971
+ if (canPreviewFile) {
9942
9972
  const img = figure.appendChild(this.#createDOMForImage());
9943
9973
 
9944
9974
  // load file locally to set dimensions and prevent vertical shifting
@@ -10038,6 +10068,7 @@ class ActionTextAttachmentUploadNode extends ActionTextAttachmentNode {
10038
10068
 
10039
10069
  async #startUploadIfNeeded() {
10040
10070
  if (this.#uploadStarted) return
10071
+ if (!this.uploadUrl) return // Bridge-managed upload — skip DirectUpload
10041
10072
 
10042
10073
  this.#setUploadStarted();
10043
10074
 
@@ -10054,7 +10085,9 @@ class ActionTextAttachmentUploadNode extends ActionTextAttachmentNode {
10054
10085
  this.#handleUploadError(error);
10055
10086
  } else {
10056
10087
  this.#dispatchEvent("lexxy:upload-end", { file: this.file, error: null });
10057
- this.#showUploadedAttachment(blob);
10088
+ this.editor.update(() => {
10089
+ this.showUploadedAttachment(blob);
10090
+ }, { tag: this.#backgroundUpdateTags });
10058
10091
  }
10059
10092
  });
10060
10093
  }
@@ -10098,17 +10131,15 @@ class ActionTextAttachmentUploadNode extends ActionTextAttachmentNode {
10098
10131
  }, { tag: this.#backgroundUpdateTags });
10099
10132
  }
10100
10133
 
10101
- #showUploadedAttachment(blob) {
10102
- const editorHasFocus = this.#editorHasFocus;
10134
+ showUploadedAttachment(blob) {
10135
+ const replacementNode = this.#toActionTextAttachmentNodeWith(blob);
10136
+ this.replace(replacementNode);
10103
10137
 
10104
- this.editor.update(() => {
10105
- const replacementNode = this.#toActionTextAttachmentNodeWith(blob);
10106
- this.replace(replacementNode);
10138
+ if (xs(replacementNode.getParent())) {
10139
+ replacementNode.selectNext();
10140
+ }
10107
10141
 
10108
- if (editorHasFocus && xs(replacementNode.getParent())) {
10109
- replacementNode.selectNext();
10110
- }
10111
- }, { tag: this.#backgroundUpdateTags });
10142
+ return replacementNode.getKey()
10112
10143
  }
10113
10144
 
10114
10145
  // Upload lifecycle methods (progress, completion, errors) run asynchronously and may
@@ -10710,6 +10741,53 @@ class Contents {
10710
10741
  });
10711
10742
  }
10712
10743
 
10744
+ insertPendingAttachment(file) {
10745
+ if (!this.editorElement.supportsAttachments) return null
10746
+
10747
+ let nodeKey = null;
10748
+ this.editor.update(() => {
10749
+ const uploadNode = new ActionTextAttachmentUploadNode({
10750
+ file,
10751
+ uploadUrl: null,
10752
+ blobUrlTemplate: this.editorElement.blobUrlTemplate,
10753
+ editor: this.editor
10754
+ });
10755
+ this.insertAtCursor(uploadNode);
10756
+ nodeKey = uploadNode.getKey();
10757
+ }, { tag: Wn });
10758
+
10759
+ if (!nodeKey) return null
10760
+
10761
+ const editor = this.editor;
10762
+ return {
10763
+ setAttributes(blob) {
10764
+ editor.update(() => {
10765
+ const node = Mo(nodeKey);
10766
+ if (!(node instanceof ActionTextAttachmentUploadNode)) return
10767
+
10768
+ const replacementNodeKey = node.showUploadedAttachment(blob);
10769
+ if (replacementNodeKey) {
10770
+ nodeKey = replacementNodeKey;
10771
+ }
10772
+ }, { tag: Wn });
10773
+ },
10774
+ setUploadProgress(progress) {
10775
+ editor.update(() => {
10776
+ const node = Mo(nodeKey);
10777
+ if (!(node instanceof ActionTextAttachmentUploadNode)) return
10778
+
10779
+ node.getWritable().progress = progress;
10780
+ }, { tag: Wn });
10781
+ },
10782
+ remove() {
10783
+ editor.update(() => {
10784
+ const node = Mo(nodeKey);
10785
+ if (node) node.remove();
10786
+ });
10787
+ }
10788
+ }
10789
+ }
10790
+
10713
10791
  replaceNodeWithHTML(nodeKey, html, options = {}) {
10714
10792
  this.editor.update(() => {
10715
10793
  const node = Mo(nodeKey);
@@ -11266,6 +11344,18 @@ class Extensions {
11266
11344
  }
11267
11345
  }
11268
11346
 
11347
+ class BrowserAdapter {
11348
+ frozenLinkKey = null
11349
+
11350
+ dispatchAttributesChange(attributes, linkHref, highlight, headingTag) {}
11351
+ dispatchEditorInitialized(detail) {}
11352
+ freeze() {}
11353
+ thaw() {}
11354
+ unlinkFrozenNode() {
11355
+ return false
11356
+ }
11357
+ }
11358
+
11269
11359
  // Custom TextNode exportDOM that avoids redundant bold/italic wrapping.
11270
11360
  //
11271
11361
  // Lexical's built-in TextNode.exportDOM() calls createDOM() which produces semantic tags
@@ -12317,6 +12407,7 @@ class LexicalEditorElement extends HTMLElement {
12317
12407
 
12318
12408
  #initialValue = ""
12319
12409
  #validationTextArea = document.createElement("textarea")
12410
+ #editorInitializedRafId = null
12320
12411
  #disposables = []
12321
12412
 
12322
12413
  constructor() {
@@ -12326,7 +12417,7 @@ class LexicalEditorElement extends HTMLElement {
12326
12417
  }
12327
12418
 
12328
12419
  connectedCallback() {
12329
- this.id ??= generateDomId("lexxy-editor");
12420
+ this.id ||= generateDomId("lexxy-editor");
12330
12421
  this.config = new EditorConfiguration(this);
12331
12422
  this.extensions = new Extensions(this);
12332
12423
 
@@ -12340,13 +12431,14 @@ class LexicalEditorElement extends HTMLElement {
12340
12431
  this.#disposables.push(this.selection);
12341
12432
 
12342
12433
  this.clipboard = new Clipboard(this);
12434
+ this.adapter = new BrowserAdapter();
12343
12435
 
12344
12436
  const commandDispatcher = CommandDispatcher.configureFor(this);
12345
12437
  this.#disposables.push(commandDispatcher);
12346
12438
 
12347
12439
  this.#initialize();
12348
12440
 
12349
- requestAnimationFrame(() => dispatch(this, "lexxy:initialize"));
12441
+ this.#scheduleEditorInitializedDispatch();
12350
12442
  this.toggleAttribute("connected", true);
12351
12443
 
12352
12444
  this.#handleAutofocus();
@@ -12355,6 +12447,7 @@ class LexicalEditorElement extends HTMLElement {
12355
12447
  }
12356
12448
 
12357
12449
  disconnectedCallback() {
12450
+ this.#cancelEditorInitializedDispatch();
12358
12451
  this.valueBeforeDisconnect = this.value;
12359
12452
  this.#reset(); // Prevent hangs with Safari when morphing
12360
12453
  }
@@ -12451,6 +12544,32 @@ class LexicalEditorElement extends HTMLElement {
12451
12544
  return this.config.get("richText")
12452
12545
  }
12453
12546
 
12547
+ registerAdapter(adapter) {
12548
+ this.adapter = adapter;
12549
+
12550
+ if (!this.editor) return
12551
+
12552
+ this.#cancelEditorInitializedDispatch();
12553
+ this.#dispatchEditorInitialized();
12554
+ this.#dispatchAttributesChange();
12555
+ }
12556
+
12557
+ freezeSelection() {
12558
+ this.adapter.freeze();
12559
+ }
12560
+
12561
+ thawSelection() {
12562
+ this.adapter.thaw();
12563
+ }
12564
+
12565
+ dispatchAttributesChange() {
12566
+ this.#dispatchAttributesChange();
12567
+ }
12568
+
12569
+ dispatchEditorInitialized() {
12570
+ this.#dispatchEditorInitialized();
12571
+ }
12572
+
12454
12573
  // TODO: Deprecate `single-line` attribute
12455
12574
  get isSingleLineMode() {
12456
12575
  return this.hasAttribute("single-line")
@@ -12575,6 +12694,7 @@ class LexicalEditorElement extends HTMLElement {
12575
12694
  const editorContentElement = createElement("div", {
12576
12695
  classList: "lexxy-editor__content",
12577
12696
  contenteditable: true,
12697
+ autocapitalize: "none",
12578
12698
  role: "textbox",
12579
12699
  "aria-multiline": true,
12580
12700
  "aria-label": this.#labelText,
@@ -12636,6 +12756,7 @@ class LexicalEditorElement extends HTMLElement {
12636
12756
  this.#internalFormValue = this.value;
12637
12757
  this.#toggleEmptyStatus();
12638
12758
  this.#setValidity();
12759
+ this.#dispatchAttributesChange();
12639
12760
  }));
12640
12761
  }
12641
12762
 
@@ -12731,6 +12852,7 @@ class LexicalEditorElement extends HTMLElement {
12731
12852
 
12732
12853
  #handleFocusIn(event) {
12733
12854
  if (this.#elementInEditorOrToolbar(event.target) && !this.currentlyFocused) {
12855
+ this.#dispatchAttributesChange();
12734
12856
  dispatch(this, "lexxy:focus");
12735
12857
  this.currentlyFocused = true;
12736
12858
  }
@@ -12811,7 +12933,112 @@ class LexicalEditorElement extends HTMLElement {
12811
12933
  }
12812
12934
  }
12813
12935
 
12936
+ #dispatchAttributesChange() {
12937
+ let attributes = null;
12938
+ let linkHref = null;
12939
+ let highlight = null;
12940
+ let headingTag = null;
12941
+
12942
+ this.editor.getEditorState().read(() => {
12943
+ const selection = $r();
12944
+ if (!wr(selection)) return
12945
+
12946
+ const format = this.selection.getFormat();
12947
+ if (Object.keys(format).length === 0) return
12948
+
12949
+ const anchorNode = selection.anchor.getNode();
12950
+ const linkNode = vt$4(anchorNode, E$3);
12951
+
12952
+ attributes = {
12953
+ bold: { active: format.isBold, enabled: true },
12954
+ italic: { active: format.isItalic, enabled: true },
12955
+ strikethrough: { active: format.isStrikethrough, enabled: true },
12956
+ code: { active: format.isInCode, enabled: true },
12957
+ highlight: { active: format.isHighlight, enabled: true },
12958
+ link: { active: format.isInLink, enabled: true },
12959
+ quote: { active: format.isInQuote, enabled: true },
12960
+ heading: { active: format.isInHeading, enabled: true },
12961
+ "unordered-list": { active: format.isInList && format.listType === "bullet", enabled: true },
12962
+ "ordered-list": { active: format.isInList && format.listType === "number", enabled: true },
12963
+ undo: { active: false, enabled: this.historyState?.undoStack.length > 0 },
12964
+ redo: { active: false, enabled: this.historyState?.redoStack.length > 0 }
12965
+ };
12966
+
12967
+ linkHref = linkNode ? linkNode.getURL() : null;
12968
+ highlight = format.isHighlight ? getHighlightStyles(selection) : null;
12969
+ headingTag = format.headingTag ?? null;
12970
+ });
12971
+
12972
+ if (attributes) {
12973
+ this.adapter.dispatchAttributesChange(attributes, linkHref, highlight, headingTag);
12974
+ }
12975
+ }
12976
+
12977
+ #dispatchEditorInitialized() {
12978
+ if (!this.adapter) return
12979
+
12980
+ this.adapter.dispatchEditorInitialized({
12981
+ highlightColors: this.#resolvedHighlightColors,
12982
+ headingFormats: this.#supportedHeadingFormats
12983
+ });
12984
+ }
12985
+
12986
+ #scheduleEditorInitializedDispatch() {
12987
+ this.#cancelEditorInitializedDispatch();
12988
+ this.#editorInitializedRafId = requestAnimationFrame(() => {
12989
+ this.#editorInitializedRafId = null;
12990
+ if (!this.isConnected || !this.adapter) return
12991
+
12992
+ dispatch(this, "lexxy:initialize");
12993
+ this.#dispatchEditorInitialized();
12994
+ });
12995
+ }
12996
+
12997
+ #cancelEditorInitializedDispatch() {
12998
+ if (this.#editorInitializedRafId == null) return
12999
+
13000
+ cancelAnimationFrame(this.#editorInitializedRafId);
13001
+ this.#editorInitializedRafId = null;
13002
+ }
13003
+
13004
+ get #resolvedHighlightColors() {
13005
+ const buttons = this.config.get("highlight.buttons");
13006
+ if (!buttons) return null
13007
+
13008
+ const colors = this.#resolveColors("color", buttons.color || []);
13009
+ const backgroundColors = this.#resolveColors("background-color", buttons["background-color"] || []);
13010
+ return { colors, backgroundColors }
13011
+ }
13012
+
13013
+ get #supportedHeadingFormats() {
13014
+ if (!this.supportsRichText) return []
13015
+
13016
+ return [
13017
+ { label: "Normal", command: "setFormatParagraph", tag: null },
13018
+ { label: "Large heading", command: "setFormatHeadingLarge", tag: "h2" },
13019
+ { label: "Medium heading", command: "setFormatHeadingMedium", tag: "h3" },
13020
+ { label: "Small heading", command: "setFormatHeadingSmall", tag: "h4" },
13021
+ ]
13022
+ }
13023
+
13024
+ #resolveColors(property, cssValues) {
13025
+ const resolver = document.createElement("span");
13026
+ resolver.style.display = "none";
13027
+ this.appendChild(resolver);
13028
+
13029
+ const resolved = cssValues.map(cssValue => {
13030
+ resolver.style.setProperty(property, cssValue);
13031
+ const value = window.getComputedStyle(resolver).getPropertyValue(property);
13032
+ resolver.style.removeProperty(property);
13033
+ return { name: cssValue, value }
13034
+ });
13035
+
13036
+ resolver.remove();
13037
+ return resolved
13038
+ }
13039
+
12814
13040
  #reset() {
13041
+ this.#cancelEditorInitializedDispatch();
12815
13042
  this.#dispose();
12816
13043
  this.editorContentElement?.remove();
12817
13044
  this.editorContentElement = null;
@@ -12823,6 +13050,7 @@ class LexicalEditorElement extends HTMLElement {
12823
13050
 
12824
13051
  #dispose() {
12825
13052
  this.#unregisterHandlers();
13053
+ this.adapter = null;
12826
13054
  document.removeEventListener("turbo:before-cache", this.#handleTurboBeforeCache);
12827
13055
 
12828
13056
  while (this.#disposables.length) {
@@ -13728,10 +13956,13 @@ class LexicalPromptElement extends HTMLElement {
13728
13956
  }
13729
13957
 
13730
13958
  class CodeLanguagePicker extends HTMLElement {
13959
+ #abortController = null
13960
+
13731
13961
  connectedCallback() {
13732
13962
  this.editorElement = this.closest("lexxy-editor");
13733
13963
  this.editor = this.editorElement.editor;
13734
13964
  this.classList.add("lexxy-floating-controls");
13965
+ this.#abortController = new AbortController();
13735
13966
 
13736
13967
  this.#attachLanguagePicker();
13737
13968
  this.#hide();
@@ -13743,13 +13974,27 @@ class CodeLanguagePicker extends HTMLElement {
13743
13974
  }
13744
13975
 
13745
13976
  dispose() {
13977
+ this.#abortController?.abort();
13978
+ this.#abortController = null;
13746
13979
  this.unregisterUpdateListener?.();
13747
13980
  this.unregisterUpdateListener = null;
13748
13981
  }
13749
13982
 
13750
13983
  #attachLanguagePicker() {
13751
13984
  this.languagePickerElement = this.#findLanguagePicker() ?? this.#createLanguagePicker();
13752
- this.append(this.languagePickerElement);
13985
+
13986
+ const signal = this.#abortController.signal;
13987
+
13988
+ this.languagePickerElement.addEventListener("change", () => {
13989
+ this.#updateCodeBlockLanguage(this.languagePickerElement.value);
13990
+ }, { signal });
13991
+
13992
+ this.languagePickerElement.addEventListener("mousedown", (event) => {
13993
+ this.#dispatchOpenEvent(event);
13994
+ }, { signal });
13995
+
13996
+ this.languagePickerElement.setAttribute("nonce", getNonce());
13997
+ this.appendChild(this.languagePickerElement);
13753
13998
  }
13754
13999
 
13755
14000
  #findLanguagePicker() {
@@ -13766,12 +14011,6 @@ class CodeLanguagePicker extends HTMLElement {
13766
14011
  selectElement.appendChild(option);
13767
14012
  }
13768
14013
 
13769
- selectElement.addEventListener("change", () => {
13770
- this.#updateCodeBlockLanguage(this.languagePickerElement.value);
13771
- });
13772
-
13773
- selectElement.setAttribute("nonce", getNonce());
13774
-
13775
14014
  return selectElement
13776
14015
  }
13777
14016
 
@@ -13794,6 +14033,21 @@ class CodeLanguagePicker extends HTMLElement {
13794
14033
  return Object.fromEntries([ plainEntry, ...sortedEntries ])
13795
14034
  }
13796
14035
 
14036
+ #dispatchOpenEvent(event) {
14037
+ const handled = !dispatch(this.editorElement, "lexxy:code-language-picker-open", {
14038
+ languages: this.#bridgeLanguages,
14039
+ currentLanguage: this.languagePickerElement.value
14040
+ }, true);
14041
+
14042
+ if (handled) {
14043
+ event.preventDefault();
14044
+ }
14045
+ }
14046
+
14047
+ get #bridgeLanguages() {
14048
+ return Object.entries(this.#languages).map(([ key, name ]) => ({ key, name }))
14049
+ }
14050
+
13797
14051
  #updateCodeBlockLanguage(language) {
13798
14052
  this.editor.update(() => {
13799
14053
  const codeNode = this.#getCurrentCodeNode();
@@ -14789,10 +15043,108 @@ function collectTextNodes(root) {
14789
15043
  return nodes
14790
15044
  }
14791
15045
 
15046
+ class NativeAdapter {
15047
+ frozenLinkKey = null
15048
+
15049
+ constructor(editorElement) {
15050
+ this.editorElement = editorElement;
15051
+ this.editorContentElement = editorElement.editorContentElement;
15052
+ }
15053
+
15054
+ dispatchAttributesChange(attributes, linkHref, highlight, headingTag) {
15055
+ dispatch(this.editorElement, "lexxy:attributes-change", {
15056
+ attributes,
15057
+ link: linkHref ? { href: linkHref } : null,
15058
+ highlight,
15059
+ headingTag
15060
+ });
15061
+ }
15062
+
15063
+ dispatchEditorInitialized(detail) {
15064
+ dispatch(this.editorElement, "lexxy:editor-initialized", detail);
15065
+ }
15066
+
15067
+ freeze() {
15068
+ let frozenLinkKey = null;
15069
+ this.editorElement.editor?.getEditorState().read(() => {
15070
+ const selection = $r();
15071
+ if (!wr(selection)) return
15072
+
15073
+ const linkNode = vt$4(selection.anchor.getNode(), E$3);
15074
+ if (linkNode) {
15075
+ frozenLinkKey = linkNode.getKey();
15076
+ }
15077
+ });
15078
+
15079
+ this.frozenLinkKey = frozenLinkKey;
15080
+ this.editorContentElement.contentEditable = "false";
15081
+ }
15082
+
15083
+ thaw() {
15084
+ this.editorContentElement.contentEditable = "true";
15085
+ }
15086
+
15087
+ unlinkFrozenNode() {
15088
+ const key = this.frozenLinkKey;
15089
+ if (!key) return false
15090
+
15091
+ const linkNode = Mo(key);
15092
+ if (!B$2(linkNode)) {
15093
+ this.frozenLinkKey = null;
15094
+ return false
15095
+ }
15096
+
15097
+ const children = linkNode.getChildren();
15098
+ for (const child of children) {
15099
+ linkNode.insertBefore(child);
15100
+ }
15101
+ linkNode.remove();
15102
+
15103
+ // Select the former link text so a follow-up createLink can re-wrap it.
15104
+ const firstText = this.#findFirstTextDescendant(children);
15105
+ const lastText = this.#findLastTextDescendant(children);
15106
+ if (firstText && lastText) {
15107
+ const selection = $r();
15108
+ if (wr(selection)) {
15109
+ selection.anchor.set(firstText.getKey(), 0, "text");
15110
+ selection.focus.set(lastText.getKey(), lastText.getTextContent().length, "text");
15111
+ }
15112
+ }
15113
+
15114
+ this.frozenLinkKey = null;
15115
+ return true
15116
+ }
15117
+
15118
+ #findFirstTextDescendant(nodes) {
15119
+ for (const node of nodes) {
15120
+ if (yr(node)) return node
15121
+ if (Pi(node)) {
15122
+ const nestedTextNode = this.#findFirstTextDescendant(node.getChildren());
15123
+ if (nestedTextNode) return nestedTextNode
15124
+ }
15125
+ }
15126
+
15127
+ return null
15128
+ }
15129
+
15130
+ #findLastTextDescendant(nodes) {
15131
+ for (let index = nodes.length - 1; index >= 0; index--) {
15132
+ const node = nodes[index];
15133
+ if (yr(node)) return node
15134
+ if (Pi(node)) {
15135
+ const nestedTextNode = this.#findLastTextDescendant(node.getChildren());
15136
+ if (nestedTextNode) return nestedTextNode
15137
+ }
15138
+ }
15139
+
15140
+ return null
15141
+ }
15142
+ }
15143
+
14792
15144
  const configure = Lexxy.configure;
14793
15145
 
14794
15146
  // Pushing elements definition to after the current call stack to allow global configuration to take place first
14795
15147
  setTimeout(defineElements, 0);
14796
15148
 
14797
- export { $createActionTextAttachmentNode, $createActionTextAttachmentUploadNode, $isActionTextAttachmentNode, ActionTextAttachmentNode, ActionTextAttachmentUploadNode, CustomActionTextAttachmentNode, LexxyExtension as Extension, HorizontalDividerNode, configure, highlightCode as highlightAll, highlightCode };
15149
+ export { $createActionTextAttachmentNode, $createActionTextAttachmentUploadNode, $isActionTextAttachmentNode, ActionTextAttachmentNode, ActionTextAttachmentUploadNode, CustomActionTextAttachmentNode, LexxyExtension as Extension, HorizontalDividerNode, NativeAdapter, configure, highlightCode as highlightAll, highlightCode };
14798
15150
  //# sourceMappingURL=lexxy.js.map
Binary file
Binary file