lexxy 0.1.22.beta → 0.1.23.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: 300853e23fb45102dd5be55c70d1c5c36891882bb787adac45304ffd1b001aba
4
- data.tar.gz: 0e562198705634dae94466b83257e2bf21ed8f26ec119c7fe99ea62c23896acd
3
+ metadata.gz: b5e24e1f63d5326e3e547318b82607fa12501063e01a96a3f4f0ef8d95e83f65
4
+ data.tar.gz: 1fb43727dbbe03923a6790d26559a99d94a6875c8e1518905b77e2f0c98415a9
5
5
  SHA512:
6
- metadata.gz: 623e32dc5dcb797072274e32691ef84e9d9f5c741a87c13114b40d937d4ec4480352b976af7526dc0eabb83bfa7a375c47d85a9de003fbc11e333d41c4d355f4
7
- data.tar.gz: c4b7df3f7e77c5a8c7a4fa02f12833e6900d9ea5f09e5378a392797a40c357ffe77db391a8b8c02954a44639b826f639bf166e26f37ed07b122a462aee2cc9c5
6
+ metadata.gz: 0b505bfd213d3dd6a484b139ee74f26088bcb20e9bbbc802065127be14a49e857f29f7a7ca1e49d0b5e95058d62a6fc4bda6d8eb52cfe06ae2f68be864446602
7
+ data.tar.gz: 4a4cf0fcca002437b316b8f0e77996f90a1948ac4252437f5d1e9f18e726e78a42fc166ceaf25fea140f816b62ba15863b2a941be46cab68f5dbf88190a27755
data/README.md CHANGED
@@ -23,7 +23,7 @@ A modern rich text editor for Rails.
23
23
  Add this line to your application's Gemfile:
24
24
 
25
25
  ```ruby
26
- gem 'lexxy', '~> 0.1.21.beta' # Need to specify the version since it's a pre-release
26
+ gem 'lexxy', '~> 0.1.22.beta' # Need to specify the version since it's a pre-release
27
27
  ```
28
28
 
29
29
  And then execute:
@@ -5223,6 +5223,8 @@ function hasHighlightStyles(cssOrStyles) {
5223
5223
  }
5224
5224
 
5225
5225
  class LexicalToolbarElement extends HTMLElement {
5226
+ static observedAttributes = [ "connected" ]
5227
+
5226
5228
  constructor() {
5227
5229
  super();
5228
5230
  this.internals = this.attachInternals();
@@ -5241,6 +5243,13 @@ class LexicalToolbarElement extends HTMLElement {
5241
5243
  this._resizeObserver.disconnect();
5242
5244
  this._resizeObserver = null;
5243
5245
  }
5246
+ this.#unbindHotkeys();
5247
+ }
5248
+
5249
+ attributeChangedCallback(name, oldValue, newValue) {
5250
+ if (name === "connected" && this.isConnected && oldValue != null && oldValue !== newValue) {
5251
+ requestAnimationFrame(() => this.#reconnect());
5252
+ }
5244
5253
  }
5245
5254
 
5246
5255
  setEditor(editorElement) {
@@ -5248,7 +5257,8 @@ class LexicalToolbarElement extends HTMLElement {
5248
5257
  this.editor = editorElement.editor;
5249
5258
  this.#bindButtons();
5250
5259
  this.#bindHotkeys();
5251
- this.#assignButtonTabindex();
5260
+ this.#setTabIndexValues();
5261
+ this.#setItemPositionValues();
5252
5262
  this.#monitorSelectionChanges();
5253
5263
  this.#monitorHistoryChanges();
5254
5264
  this.#refreshToolbarOverflow();
@@ -5256,10 +5266,9 @@ class LexicalToolbarElement extends HTMLElement {
5256
5266
  this.toggleAttribute("connected", true);
5257
5267
  }
5258
5268
 
5259
- get #dialogs() {
5260
- const dialogButtons = this.querySelectorAll("[data-dialog-target]");
5261
- const dialogTags = Array.from(dialogButtons).map(button => `lexxy-${button.dataset.dialogTarget}`);
5262
- return Array.from(this.querySelectorAll(dialogTags))
5269
+ #reconnect() {
5270
+ this.disconnectedCallback();
5271
+ this.connectedCallback();
5263
5272
  }
5264
5273
 
5265
5274
  #bindButtons() {
@@ -5268,7 +5277,6 @@ class LexicalToolbarElement extends HTMLElement {
5268
5277
 
5269
5278
  #handleButtonClicked({ target }) {
5270
5279
  this.#handleTargetClicked(target, "[data-command]", this.#dispatchButtonCommand.bind(this));
5271
- this.#handleTargetClicked(target, "[data-dialog-target]", this.#toggleDialog.bind(this));
5272
5280
  }
5273
5281
 
5274
5282
  #handleTargetClicked(target, selector, callback) {
@@ -5283,38 +5291,23 @@ class LexicalToolbarElement extends HTMLElement {
5283
5291
  this.editor.dispatchCommand(command, payload);
5284
5292
  }
5285
5293
 
5286
- // Not using popover because of CSS anchoring still not widely available.
5287
- #toggleDialog(button) {
5288
- const dialogTarget = button.dataset.dialogTarget;
5289
- const dialog = this.querySelector("lexxy-" + dialogTarget);
5290
- if (!dialog) return
5291
-
5292
- if (dialog.open) {
5293
- dialog.close();
5294
- } else {
5295
- this.#closeOpenDialogs();
5296
- dialog.show(button);
5297
- }
5294
+ #bindHotkeys() {
5295
+ this.editorElement.addEventListener("keydown", this.#handleHotkey);
5298
5296
  }
5299
5297
 
5300
- #closeOpenDialogs() {
5301
- const openDialogs = this.querySelectorAll("dialog[open]");
5302
- openDialogs.forEach(openDialog => {
5303
- openDialog.closest(".lexxy-dialog").close();
5304
- });
5298
+ #unbindHotkeys() {
5299
+ this.editorElement?.removeEventListener("keydown", this.#handleHotkey);
5305
5300
  }
5306
5301
 
5307
- #bindHotkeys() {
5308
- this.editorElement.addEventListener("keydown", (event) => {
5309
- const buttons = this.querySelectorAll("[data-hotkey]");
5310
- buttons.forEach((button) => {
5311
- const hotkeys = button.dataset.hotkey.toLowerCase().split(/\s+/);
5312
- if (hotkeys.includes(this.#keyCombinationFor(event))) {
5313
- event.preventDefault();
5314
- event.stopPropagation();
5315
- button.click();
5316
- }
5317
- });
5302
+ #handleHotkey = (event) => {
5303
+ const buttons = this.querySelectorAll("[data-hotkey]");
5304
+ buttons.forEach((button) => {
5305
+ const hotkeys = button.dataset.hotkey.toLowerCase().split(/\s+/);
5306
+ if (hotkeys.includes(this.#keyCombinationFor(event))) {
5307
+ event.preventDefault();
5308
+ event.stopPropagation();
5309
+ button.click();
5310
+ }
5318
5311
  });
5319
5312
  }
5320
5313
 
@@ -5330,10 +5323,9 @@ class LexicalToolbarElement extends HTMLElement {
5330
5323
  return [ ...modifiers, pressedKey ].join("+")
5331
5324
  }
5332
5325
 
5333
- #assignButtonTabindex() {
5334
- const baseTabIndex = parseInt(this.editorElement.editorContentElement.getAttribute("tabindex") ?? "0");
5335
- this.#buttons.forEach((button, index) => {
5336
- button.setAttribute("tabindex", `${baseTabIndex + index + 1}`);
5326
+ #setTabIndexValues() {
5327
+ this.#buttons.forEach((button) => {
5328
+ button.setAttribute("tabindex", 0);
5337
5329
  });
5338
5330
  }
5339
5331
 
@@ -5341,7 +5333,6 @@ class LexicalToolbarElement extends HTMLElement {
5341
5333
  this.editor.registerUpdateListener(() => {
5342
5334
  this.editor.getEditorState().read(() => {
5343
5335
  this.#updateButtonStates();
5344
- this.#updateDialogStates();
5345
5336
  });
5346
5337
  });
5347
5338
  }
@@ -5396,10 +5387,6 @@ class LexicalToolbarElement extends HTMLElement {
5396
5387
  this.#updateUndoRedoButtonStates();
5397
5388
  }
5398
5389
 
5399
- #updateDialogStates() {
5400
- this.#dialogs.forEach(dialog => dialog.updateStateCallback());
5401
- }
5402
-
5403
5390
  #isInList(node) {
5404
5391
  let current = node;
5405
5392
  while (current) {
@@ -5448,22 +5435,8 @@ class LexicalToolbarElement extends HTMLElement {
5448
5435
  this.toggleAttribute("overflowing", isOverflowing);
5449
5436
  }
5450
5437
 
5451
- get #overflow() {
5452
- return this.querySelector(".lexxy-editor__toolbar-overflow")
5453
- }
5454
-
5455
- get #overflowMenu() {
5456
- return this.querySelector(".lexxy-editor__toolbar-overflow-menu")
5457
- }
5458
-
5459
- #resetToolbar() {
5460
- while (this.#overflowMenu.children.length > 0) {
5461
- this.insertBefore(this.#overflowMenu.children[0], this.#overflow);
5462
- }
5463
- }
5464
-
5465
5438
  #compactMenu() {
5466
- const buttons = this.#buttonsWithSeparator.reverse();
5439
+ const buttons = this.#buttons.reverse();
5467
5440
  let movedToOverflow = false;
5468
5441
 
5469
5442
  for (const button of buttons) {
@@ -5477,12 +5450,42 @@ class LexicalToolbarElement extends HTMLElement {
5477
5450
  }
5478
5451
  }
5479
5452
 
5453
+ #resetToolbar() {
5454
+ const items = Array.from(this.#overflowMenu.children);
5455
+ items.sort((a, b) => this.#itemPosition(b) - this.#itemPosition(a));
5456
+
5457
+ items.forEach((item) => {
5458
+ const nextItem = this.querySelector(`[data-position="${this.#itemPosition(item) + 1}"]`) ?? this.#overflow;
5459
+ this.insertBefore(item, nextItem);
5460
+ });
5461
+ }
5462
+
5463
+ #itemPosition(item) {
5464
+ return parseInt(item.dataset.position ?? "999")
5465
+ }
5466
+
5467
+ #setItemPositionValues() {
5468
+ this.#toolbarItems.forEach((item, index) => {
5469
+ if (item.dataset.position === undefined) {
5470
+ item.dataset.position = index;
5471
+ }
5472
+ });
5473
+ }
5474
+
5475
+ get #overflow() {
5476
+ return this.querySelector(".lexxy-editor__toolbar-overflow")
5477
+ }
5478
+
5479
+ get #overflowMenu() {
5480
+ return this.querySelector(".lexxy-editor__toolbar-overflow-menu")
5481
+ }
5482
+
5480
5483
  get #buttons() {
5481
5484
  return Array.from(this.querySelectorAll(":scope > button"))
5482
5485
  }
5483
5486
 
5484
- get #buttonsWithSeparator() {
5485
- return Array.from(this.querySelectorAll(":scope > button, :scope > [role=separator]"))
5487
+ get #toolbarItems() {
5488
+ return Array.from(this.querySelectorAll(":scope > *:not(.lexxy-editor__toolbar-overflow)"))
5486
5489
  }
5487
5490
 
5488
5491
  static get defaultTemplate() {
@@ -5501,35 +5504,31 @@ class LexicalToolbarElement extends HTMLElement {
5501
5504
  </svg>
5502
5505
  </button>
5503
5506
 
5504
- <lexxy-highlight-dialog class="lexxy-dialog lexxy-highlight-dialog">
5505
- <dialog class="highlight-dialog">
5506
- <div class="lexxy-highlight-dialog-content">
5507
- <div data-button-group="color" data-values="var(--highlight-1); var(--highlight-2); var(--highlight-3); var(--highlight-4); var(--highlight-5); var(--highlight-6); var(--highlight-7); var(--highlight-8); var(--highlight-9)"></div>
5508
- <div data-button-group="background-color" data-values="var(--highlight-bg-1); var(--highlight-bg-2); var(--highlight-bg-3); var(--highlight-bg-4); var(--highlight-bg-5); var(--highlight-bg-6); var(--highlight-bg-7); var(--highlight-bg-8); var(--highlight-bg-9)"></div>
5509
- <button data-command="removeHighlight" class="lexxy-highlight-dialog-reset">Remove all coloring</button>
5510
- </div>
5511
- </dialog>
5512
- </lexxy-highlight-dialog>
5513
-
5514
- <button class="lexxy-editor__toolbar-button" type="button" name="highlight" title="Color highlight" data-dialog-target="highlight-dialog">
5515
- <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M7.65422 0.711575C7.1856 0.242951 6.42579 0.242951 5.95717 0.711575C5.48853 1.18021 5.48853 1.94 5.95717 2.40864L8.70864 5.16011L2.85422 11.0145C1.44834 12.4204 1.44833 14.6998 2.85422 16.1057L7.86011 21.1115C9.26599 22.5174 11.5454 22.5174 12.9513 21.1115L19.6542 14.4087C20.1228 13.94 20.1228 13.1802 19.6542 12.7115L11.8544 4.91171L11.2542 4.31158L7.65422 0.711575ZM4.55127 12.7115L10.4057 6.85716L17.1087 13.56H4.19981C4.19981 13.253 4.31696 12.9459 4.55127 12.7115ZM23.6057 20.76C23.6057 22.0856 22.5311 23.16 21.2057 23.16C19.8802 23.16 18.8057 22.0856 18.8057 20.76C18.8057 19.5408 19.8212 18.5339 20.918 17.4462C21.0135 17.3516 21.1096 17.2563 21.2057 17.16C21.3018 17.2563 21.398 17.3516 21.4935 17.4462C22.5903 18.5339 23.6057 19.5408 23.6057 20.76Z"/></svg>
5516
- </button>
5507
+ <details class="lexxy-editor__toolbar-dropdown" name="lexxy-dropdown">
5508
+ <summary class="lexxy-editor__toolbar-button" name="highlight" title="Color highlight">
5509
+ <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M7.65422 0.711575C7.1856 0.242951 6.42579 0.242951 5.95717 0.711575C5.48853 1.18021 5.48853 1.94 5.95717 2.40864L8.70864 5.16011L2.85422 11.0145C1.44834 12.4204 1.44833 14.6998 2.85422 16.1057L7.86011 21.1115C9.26599 22.5174 11.5454 22.5174 12.9513 21.1115L19.6542 14.4087C20.1228 13.94 20.1228 13.1802 19.6542 12.7115L11.8544 4.91171L11.2542 4.31158L7.65422 0.711575ZM4.55127 12.7115L10.4057 6.85716L17.1087 13.56H4.19981C4.19981 13.253 4.31696 12.9459 4.55127 12.7115ZM23.6057 20.76C23.6057 22.0856 22.5311 23.16 21.2057 23.16C19.8802 23.16 18.8057 22.0856 18.8057 20.76C18.8057 19.5408 19.8212 18.5339 20.918 17.4462C21.0135 17.3516 21.1096 17.2563 21.2057 17.16C21.3018 17.2563 21.398 17.3516 21.4935 17.4462C22.5903 18.5339 23.6057 19.5408 23.6057 20.76Z"/></svg>
5510
+ </summary>
5511
+ <lexxy-highlight-dropdown class="lexxy-editor__toolbar-dropdown-content">
5512
+ <div data-button-group="color" data-values="var(--highlight-1); var(--highlight-2); var(--highlight-3); var(--highlight-4); var(--highlight-5); var(--highlight-6); var(--highlight-7); var(--highlight-8); var(--highlight-9)"></div>
5513
+ <div data-button-group="background-color" data-values="var(--highlight-bg-1); var(--highlight-bg-2); var(--highlight-bg-3); var(--highlight-bg-4); var(--highlight-bg-5); var(--highlight-bg-6); var(--highlight-bg-7); var(--highlight-bg-8); var(--highlight-bg-9)"></div>
5514
+ <button data-command="removeHighlight" class="lexxy-editor__toolbar-dropdown-reset">Remove all coloring</button>
5515
+ </lexxy-highlight-dropdown>
5516
+ </details>
5517
5517
 
5518
- <lexxy-link-dialog class="lexxy-dialog lexxy-link-dialog">
5519
- <dialog class="link-dialog">
5518
+ <details class="lexxy-editor__toolbar-dropdown" name="lexxy-dropdown">
5519
+ <summary class="lexxy-editor__toolbar-button" name="link" title="Link" data-hotkey="cmd+k ctrl+k">
5520
+ <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12.111 9.546a1.5 1.5 0 012.121 0 5.5 5.5 0 010 7.778l-2.828 2.828a5.5 5.5 0 01-7.778 0 5.498 5.498 0 010-7.777l2.828-2.83a1.5 1.5 0 01.355-.262 6.52 6.52 0 00.351 3.799l-1.413 1.414a2.499 2.499 0 000 3.535 2.499 2.499 0 003.535 0l2.83-2.828a2.5 2.5 0 000-3.536 1.5 1.5 0 010-2.121z"/><path d="M12.111 3.89a5.5 5.5 0 117.778 7.777l-2.828 2.829a1.496 1.496 0 01-.355.262 6.522 6.522 0 00-.351-3.8l1.413-1.412a2.5 2.5 0 10-3.536-3.535l-2.828 2.828a2.5 2.5 0 000 3.536 1.5 1.5 0 01-2.122 2.12 5.5 5.5 0 010-7.777l2.83-2.829z"/></svg>
5521
+ </summary>
5522
+ <lexxy-link-dropdown class="lexxy-editor__toolbar-dropdown-content">
5520
5523
  <form method="dialog">
5521
- <input type="url" placeholder="Enter a URL…" class="input" required>
5522
- <div class="lexxy-dialog-actions">
5524
+ <input type="url" placeholder="Enter a URL…" class="input">
5525
+ <div class="lexxy-editor__toolbar-dropdown-actions">
5523
5526
  <button type="submit" class="btn" value="link">Link</button>
5524
5527
  <button type="button" class="btn" value="unlink">Unlink</button>
5525
5528
  </div>
5526
5529
  </form>
5527
- </dialog>
5528
- </lexxy-link-dialog>
5529
-
5530
- <button class="lexxy-editor__toolbar-button" type="button" name="link" title="Link" data-dialog-target="link-dialog" data-hotkey="cmd+k ctrl+k">
5531
- <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12.111 9.546a1.5 1.5 0 012.121 0 5.5 5.5 0 010 7.778l-2.828 2.828a5.5 5.5 0 01-7.778 0 5.498 5.498 0 010-7.777l2.828-2.83a1.5 1.5 0 01.355-.262 6.52 6.52 0 00.351 3.799l-1.413 1.414a2.499 2.499 0 000 3.535 2.499 2.499 0 003.535 0l2.83-2.828a2.5 2.5 0 000-3.536 1.5 1.5 0 010-2.121z"/><path d="M12.111 3.89a5.5 5.5 0 117.778 7.777l-2.828 2.829a1.496 1.496 0 01-.355.262 6.522 6.522 0 00-.351-3.8l1.413-1.412a2.5 2.5 0 10-3.536-3.535l-2.828 2.828a2.5 2.5 0 000 3.536 1.5 1.5 0 01-2.122 2.12 5.5 5.5 0 010-7.777l2.83-2.829z"/></svg>
5532
- </button>
5530
+ </lexxy-link-dropdown>
5531
+ </details>
5533
5532
 
5534
5533
  <button class="lexxy-editor__toolbar-button" type="button" name="quote" data-command="insertQuoteBlock" title="Quote">
5535
5534
  <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M6.5 5C8.985 5 11 7.09 11 9.667c0 2.694-.962 5.005-2.187 6.644-.613.82-1.3 1.481-1.978 1.943-.668.454-1.375.746-2.022.746a.563.563 0 01-.52-.36.602.602 0 01.067-.57l.055-.066.009-.009.041-.048a4.25 4.25 0 00.168-.21c.143-.188.336-.47.53-.84a6.743 6.743 0 00.75-2.605C3.705 13.994 2 12.038 2 9.667 2 7.089 4.015 5 6.5 5zM17.5 5C19.985 5 22 7.09 22 9.667c0 2.694-.962 5.005-2.187 6.644-.613.82-1.3 1.481-1.978 1.943-.668.454-1.375.746-2.023.746a.563.563 0 01-.52-.36.602.602 0 01.068-.57l.055-.066.009-.009.041-.048c.039-.045.097-.115.168-.21a6.16 6.16 0 00.53-.84 6.745 6.745 0 00.75-2.605C14.705 13.994 13 12.038 13 9.667 13 7.089 15.015 5 17.5 5z"/></svg>
@@ -7134,6 +7133,7 @@ class CommandDispatcher {
7134
7133
  this.highlighter = editorElement.highlighter;
7135
7134
 
7136
7135
  this.#registerCommands();
7136
+ this.#registerKeyboardCommands();
7137
7137
  this.#registerDragAndDropHandlers();
7138
7138
  }
7139
7139
 
@@ -7298,15 +7298,8 @@ class CommandDispatcher {
7298
7298
  this.editor.registerCommand(command, handler, priority);
7299
7299
  }
7300
7300
 
7301
- // Not using TOGGLE_LINK_COMMAND because it's not handled unless you use React/LinkPlugin
7302
- #toggleLink(url) {
7303
- this.editor.update(() => {
7304
- if (url === null) {
7305
- J$1(null);
7306
- } else {
7307
- J$1(url);
7308
- }
7309
- });
7301
+ #registerKeyboardCommands() {
7302
+ this.editor.registerCommand(Me$1, this.#handleListIndentation.bind(this), Ri);
7310
7303
  }
7311
7304
 
7312
7305
  #registerDragAndDropHandlers() {
@@ -7355,6 +7348,29 @@ class CommandDispatcher {
7355
7348
 
7356
7349
  this.editor.focus();
7357
7350
  }
7351
+
7352
+ #handleListIndentation(event) {
7353
+ if (this.selection.isInsideList) {
7354
+ event.preventDefault();
7355
+ if (event.shiftKey) {
7356
+ return this.editor.dispatchCommand(De$1, undefined)
7357
+ } else {
7358
+ return this.editor.dispatchCommand(Pe$1, undefined)
7359
+ }
7360
+ }
7361
+ return false
7362
+ }
7363
+
7364
+ // Not using TOGGLE_LINK_COMMAND because it's not handled unless you use React/LinkPlugin
7365
+ #toggleLink(url) {
7366
+ this.editor.update(() => {
7367
+ if (url === null) {
7368
+ J$1(null);
7369
+ } else {
7370
+ J$1(url);
7371
+ }
7372
+ });
7373
+ }
7358
7374
  }
7359
7375
 
7360
7376
  function capitalize(str) {
@@ -9545,6 +9561,10 @@ class LexicalEditorElement extends HTMLElement {
9545
9561
  return this.getAttribute("attachments") !== "false"
9546
9562
  }
9547
9563
 
9564
+ get contentTabIndex() {
9565
+ return parseInt(this.editorContentElement?.getAttribute("tabindex") ?? "0")
9566
+ }
9567
+
9548
9568
  focus() {
9549
9569
  this.editor.focus();
9550
9570
  }
@@ -9858,39 +9878,26 @@ class LexicalEditorElement extends HTMLElement {
9858
9878
 
9859
9879
  #reconnect() {
9860
9880
  this.disconnectedCallback();
9881
+ this.valueBeforeDisconnect = null;
9861
9882
  this.connectedCallback();
9862
9883
  }
9863
9884
  }
9864
9885
 
9865
9886
  customElements.define("lexxy-editor", LexicalEditorElement);
9866
9887
 
9867
- class ToolbarDialog extends HTMLElement {
9888
+ class ToolbarDropdown extends HTMLElement {
9868
9889
  connectedCallback() {
9869
- this.dialog = this.querySelector("dialog");
9870
- if ("closedBy" in this.dialog.constructor.prototype) {
9871
- this.dialog.closedBy = "any";
9872
- }
9873
- this.#registerHandlers();
9874
- }
9875
-
9876
- disconnectedCallback() {
9877
- this.#removeClickOutsideHandler();
9878
- }
9879
-
9880
- updateStateCallback() { }
9890
+ this.container = this.closest("details");
9881
9891
 
9882
- show(triggerButton) {
9883
- if (this.preventImmediateReopen) { return }
9892
+ this.container.addEventListener("toggle", this.#handleToggle.bind(this));
9893
+ this.container.addEventListener("keydown", this.#handleKeyDown.bind(this));
9884
9894
 
9885
- this.triggerButton = triggerButton;
9886
- this.#positionDialog();
9887
- this.dialog.show();
9888
-
9889
- this.#setupClickOutsideHandler();
9895
+ this.#setTabIndexValues();
9890
9896
  }
9891
9897
 
9892
- close() {
9893
- this.dialog.close();
9898
+ disconnectedCallback() {
9899
+ this.#removeClickOutsideHandler();
9900
+ this.container.removeEventListener("keydown", this.#handleKeyDown.bind(this));
9894
9901
  }
9895
9902
 
9896
9903
  get toolbar() {
@@ -9901,32 +9908,32 @@ class ToolbarDialog extends HTMLElement {
9901
9908
  return this.toolbar.editor
9902
9909
  }
9903
9910
 
9904
- get open() { return this.dialog.open }
9905
-
9906
- #registerHandlers() {
9907
- this.#setupKeydownHandler();
9908
- this.dialog.addEventListener("cancel", this.#handleCancel.bind(this));
9909
- this.dialog.addEventListener("close", this.#handleClose.bind(this));
9911
+ close() {
9912
+ this.container.removeAttribute("open");
9910
9913
  }
9911
9914
 
9912
- #handleClose() {
9913
- this.#removeClickOutsideHandler();
9914
- this.triggerButton = null;
9915
- this.editor.focus();
9915
+ #handleToggle(event) {
9916
+ if (this.container.open) {
9917
+ this.#handleOpen(event.target);
9918
+ } else {
9919
+ this.#handleClose();
9920
+ }
9916
9921
  }
9917
9922
 
9918
- #handleCancel() {
9919
- this.preventImmediateReopen = true;
9920
- requestAnimationFrame(() => this.preventImmediateReopen = undefined);
9923
+ #handleOpen(trigger) {
9924
+ this.trigger = trigger;
9925
+ this.#interactiveElements[0].focus();
9926
+ this.#setupClickOutsideHandler();
9921
9927
  }
9922
9928
 
9923
- #positionDialog() {
9924
- const left = this.triggerButton.offsetLeft;
9925
- this.dialog.style.insetInlineStart = `${left}px`;
9929
+ #handleClose() {
9930
+ this.trigger = null;
9931
+ this.#removeClickOutsideHandler();
9932
+ this.editor.focus();
9926
9933
  }
9927
9934
 
9928
9935
  #setupClickOutsideHandler() {
9929
- if (this.#browserHandlesClose || this.clickOutsideHandler) return
9936
+ if (this.clickOutsideHandler) return
9930
9937
 
9931
9938
  this.clickOutsideHandler = this.#handleClickOutside.bind(this);
9932
9939
  document.addEventListener("click", this.clickOutsideHandler, true);
@@ -9940,22 +9947,7 @@ class ToolbarDialog extends HTMLElement {
9940
9947
  }
9941
9948
 
9942
9949
  #handleClickOutside({ target }) {
9943
- if (!this.dialog.open) return
9944
-
9945
- const isClickInsideDialog = this.dialog.contains(target);
9946
- const isClickOnTrigger = this.triggerButton.contains(target);
9947
-
9948
- if (!isClickInsideDialog && !isClickOnTrigger) {
9949
- this.close();
9950
- }
9951
- }
9952
-
9953
- #setupKeydownHandler() {
9954
- if (!this.#browserHandlesClose) { this.addEventListener("keydown", this.#handleKeyDown.bind(this)); }
9955
- }
9956
-
9957
- get #browserHandlesClose() {
9958
- return this.dialog.closedBy === "any"
9950
+ if (this.container.open && !this.container.contains(target)) this.close();
9959
9951
  }
9960
9952
 
9961
9953
  #handleKeyDown(event) {
@@ -9964,9 +9956,20 @@ class ToolbarDialog extends HTMLElement {
9964
9956
  this.close();
9965
9957
  }
9966
9958
  }
9959
+
9960
+ async #setTabIndexValues() {
9961
+ await nextFrame();
9962
+ this.#interactiveElements.forEach((element) => {
9963
+ element.setAttribute("tabindex", 0);
9964
+ });
9965
+ }
9966
+
9967
+ get #interactiveElements() {
9968
+ return Array.from(this.querySelectorAll("button, input"))
9969
+ }
9967
9970
  }
9968
9971
 
9969
- class LinkDialog extends ToolbarDialog {
9972
+ class LinkDropdown extends ToolbarDropdown {
9970
9973
  connectedCallback() {
9971
9974
  super.connectedCallback();
9972
9975
  this.input = this.querySelector("input");
@@ -9974,23 +9977,21 @@ class LinkDialog extends ToolbarDialog {
9974
9977
  this.#registerHandlers();
9975
9978
  }
9976
9979
 
9977
- updateStateCallback() {
9978
- this.input.value = this.#selectedLinkUrl;
9979
- }
9980
-
9981
9980
  #registerHandlers() {
9982
- this.dialog.addEventListener("beforetoggle", this.#handleBeforeToggle.bind(this));
9983
- this.dialog.addEventListener("submit", this.#handleSubmit.bind(this));
9981
+ this.container.addEventListener("toggle", this.#handleToggle.bind(this));
9982
+ this.addEventListener("submit", this.#handleSubmit.bind(this));
9984
9983
  this.querySelector("[value='unlink']").addEventListener("click", this.#handleUnlink.bind(this));
9985
9984
  }
9986
9985
 
9987
- #handleBeforeToggle({ newState }) {
9986
+ #handleToggle({ newState }) {
9987
+ this.input.value = this.#selectedLinkUrl;
9988
9988
  this.input.required = newState === "open";
9989
9989
  }
9990
9990
 
9991
9991
  #handleSubmit(event) {
9992
9992
  const command = event.submitter?.value;
9993
9993
  this.editor.dispatchCommand(command, this.input.value);
9994
+ this.close();
9994
9995
  }
9995
9996
 
9996
9997
  #handleUnlink() {
@@ -10019,9 +10020,7 @@ class LinkDialog extends ToolbarDialog {
10019
10020
  }
10020
10021
  }
10021
10022
 
10022
- // We should extend the native dialog and avoid the intermediary <dialog> but not
10023
- // supported by Safari yet: customElements.define("lexxy-link-dialog", LinkDialog, { extends: "dialog" })
10024
- customElements.define("lexxy-link-dialog", LinkDialog);
10023
+ customElements.define("lexxy-link-dropdown", LinkDropdown);
10025
10024
 
10026
10025
  const APPLY_HIGHLIGHT_SELECTOR = "button.lexxy-highlight-button";
10027
10026
  const REMOVE_HIGHLIGHT_SELECTOR = "[data-command='removeHighlight']";
@@ -10031,7 +10030,7 @@ const REMOVE_HIGHLIGHT_SELECTOR = "[data-command='removeHighlight']";
10031
10030
  // see https://github.com/facebook/lexical/issues/8013
10032
10031
  const NO_STYLE = Symbol("no_style");
10033
10032
 
10034
- class HighlightDialog extends ToolbarDialog {
10033
+ class HighlightDropdown extends ToolbarDropdown {
10035
10034
  connectedCallback() {
10036
10035
  super.connectedCallback();
10037
10036
 
@@ -10039,13 +10038,10 @@ class HighlightDialog extends ToolbarDialog {
10039
10038
  this.#registerHandlers();
10040
10039
  }
10041
10040
 
10042
- updateStateCallback() {
10043
- this.#updateColorButtonStates(Lr());
10044
- }
10045
-
10046
10041
  #registerHandlers() {
10047
- this.querySelector(REMOVE_HIGHLIGHT_SELECTOR).addEventListener("click", this.#handleRemoveHighlightClick.bind(this));
10042
+ this.container.addEventListener("toggle", this.#handleToggle.bind(this));
10048
10043
  this.#colorButtons.forEach(button => button.addEventListener("click", this.#handleColorButtonClick.bind(this)));
10044
+ this.querySelector(REMOVE_HIGHLIGHT_SELECTOR).addEventListener("click", this.#handleRemoveHighlightClick.bind(this));
10049
10045
  }
10050
10046
 
10051
10047
  #setUpButtons() {
@@ -10072,6 +10068,14 @@ class HighlightDialog extends ToolbarDialog {
10072
10068
  return button
10073
10069
  }
10074
10070
 
10071
+ #handleToggle({ newState }) {
10072
+ if (newState === "open") {
10073
+ this.editor.getEditorState().read(() => {
10074
+ this.#updateColorButtonStates(Lr());
10075
+ });
10076
+ }
10077
+ }
10078
+
10075
10079
  #handleColorButtonClick(event) {
10076
10080
  event.preventDefault();
10077
10081
 
@@ -10117,9 +10121,7 @@ class HighlightDialog extends ToolbarDialog {
10117
10121
  }
10118
10122
  }
10119
10123
 
10120
- // We should extend the native dialog and avoid the intermediary <dialog> but not
10121
- // supported by Safari yet: customElements.define("lexxy-hightlight-dialog", HighlightDialog, { extends: "dialog" })
10122
- customElements.define("lexxy-highlight-dialog", HighlightDialog);
10124
+ customElements.define("lexxy-highlight-dropdown", HighlightDropdown);
10123
10125
 
10124
10126
  class BaseSource {
10125
10127
  // Template method to override
@@ -10264,10 +10266,13 @@ class LexicalPromptElement extends HTMLElement {
10264
10266
  this.keyListeners = [];
10265
10267
  }
10266
10268
 
10269
+ static observedAttributes = [ "connected" ]
10270
+
10267
10271
  connectedCallback() {
10268
10272
  this.source = this.#createSource();
10269
10273
 
10270
10274
  this.#addTriggerListener();
10275
+ this.toggleAttribute("connected", true);
10271
10276
  }
10272
10277
 
10273
10278
  disconnectedCallback() {
@@ -10275,6 +10280,13 @@ class LexicalPromptElement extends HTMLElement {
10275
10280
  this.popoverElement = null;
10276
10281
  }
10277
10282
 
10283
+
10284
+ attributeChangedCallback(name, oldValue, newValue) {
10285
+ if (name === "connected" && this.isConnected && oldValue != null && oldValue !== newValue) {
10286
+ requestAnimationFrame(() => this.#reconnect());
10287
+ }
10288
+ }
10289
+
10278
10290
  get name() {
10279
10291
  return this.getAttribute("name")
10280
10292
  }
@@ -10644,6 +10656,11 @@ class LexicalPromptElement extends HTMLElement {
10644
10656
  this.#optionWasSelected();
10645
10657
  }
10646
10658
  }
10659
+
10660
+ #reconnect() {
10661
+ this.disconnectedCallback();
10662
+ this.connectedCallback();
10663
+ }
10647
10664
  }
10648
10665
 
10649
10666
  customElements.define("lexxy-prompt", LexicalPromptElement);
Binary file
Binary file