lexxy 0.1.25.beta → 0.1.26.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: dad8a8750fa3768dec22db124d53c86c503c0e22a8a161f9255f7b7d693bcdfe
4
- data.tar.gz: 8d890586e2d4f4579945b0c236fdfefe7d4ac91e005d923781297c776d7badf6
3
+ metadata.gz: ff57bf7093680549f0e8a16c40c9d2e3b9c399ddea811fb8164b0915e6c869d4
4
+ data.tar.gz: 2e95ef8aedf887e717f9a7c8ea5b086ed0de1dc7840057fe50f2a4349ceba3d2
5
5
  SHA512:
6
- metadata.gz: 6e6d60e274a8b0a3cb91dc3ca5f45ee62b27a35058cc4be2a028626d9293ddf8c03489837a568ed611f29c3bfb671d69b7884f0652b6e5bbbb6b832b2b73fb97
7
- data.tar.gz: c945dff9eea87287117e078cc21bfd3da2c6644c07ba09ae19b61600a8efb17ce2baaae2764646b1cfdc80c698554bc6e3693be05d88e7df242461d1df56729d
6
+ metadata.gz: 8eb3289e99dd46a96dc938b4e6b5a3b184b89dcb7650b9dab3ac256229151a74756e5d0d91d175bb4e38c82ead28a4dccfa5bcd31fbbcd7f4c69a270ee4d0e38
7
+ data.tar.gz: 946690466243ccec4590977b68a00948001c58b2e82f0e77f63b2293d4b850ef3c382b0e6006bd53ae95f0e0a32e8ca58cb304e19fd47ccc4509974998ab9ec1
@@ -6337,6 +6337,93 @@ function hasHighlightStyles(cssOrStyles) {
6337
6337
  return !!(styles.color || styles["background-color"])
6338
6338
  }
6339
6339
 
6340
+ function handleRollingTabIndex(elements, event) {
6341
+ const previousActiveElement = document.activeElement;
6342
+
6343
+ if (elements.includes(previousActiveElement)) {
6344
+ const finder = new NextElementFinder(elements, event.key);
6345
+
6346
+ if (finder.selectNext(previousActiveElement)) {
6347
+ event.preventDefault();
6348
+ }
6349
+ }
6350
+ }
6351
+
6352
+ class NextElementFinder {
6353
+ constructor(elements, key) {
6354
+ this.elements = elements;
6355
+ this.key = key;
6356
+ }
6357
+
6358
+ selectNext(fromElement) {
6359
+ const nextElement = this.#findNextElement(fromElement);
6360
+
6361
+ if (nextElement) {
6362
+ const inactiveElements = this.elements.filter(element => element !== nextElement);
6363
+ this.#unsetTabIndex(inactiveElements);
6364
+ this.#focusWithActiveTabIndex(nextElement);
6365
+ return true
6366
+ }
6367
+
6368
+ return false
6369
+ }
6370
+
6371
+ #findNextElement(fromElement) {
6372
+ switch (this.key) {
6373
+ case "ArrowRight":
6374
+ case "ArrowDown":
6375
+ return this.#findNextSibling(fromElement)
6376
+
6377
+ case "ArrowLeft":
6378
+ case "ArrowUp":
6379
+ return this.#findPreviousSibling(fromElement)
6380
+
6381
+ case "Home":
6382
+ return this.#findFirst()
6383
+
6384
+ case "End":
6385
+ return this.#findLast()
6386
+ }
6387
+ }
6388
+
6389
+ #findFirst(elements = this.elements) {
6390
+ return elements.find(isActiveAndVisible)
6391
+ }
6392
+
6393
+ #findLast(elements = this.elements) {
6394
+ return elements.findLast(isActiveAndVisible)
6395
+ }
6396
+
6397
+ #findNextSibling(element) {
6398
+ const afterElements = this.elements.slice(this.#indexOf(element) + 1);
6399
+ return this.#findFirst(afterElements)
6400
+ }
6401
+
6402
+ #findPreviousSibling(element) {
6403
+ const beforeElements = this.elements.slice(0, this.#indexOf(element));
6404
+ return this.#findLast(beforeElements)
6405
+ }
6406
+
6407
+ #indexOf(element) {
6408
+ return this.elements.indexOf(element)
6409
+ }
6410
+
6411
+ #focusWithActiveTabIndex(element) {
6412
+ if (isActiveAndVisible(element)) {
6413
+ element.tabIndex = 0;
6414
+ element.focus();
6415
+ }
6416
+ }
6417
+
6418
+ #unsetTabIndex(elements) {
6419
+ elements.forEach(element => element.tabIndex = -1);
6420
+ }
6421
+ }
6422
+
6423
+ function isActiveAndVisible(element) {
6424
+ return element && !element.disabled && element.checkVisibility()
6425
+ }
6426
+
6340
6427
  class LexicalToolbarElement extends HTMLElement {
6341
6428
  static observedAttributes = [ "connected" ]
6342
6429
 
@@ -6348,17 +6435,14 @@ class LexicalToolbarElement extends HTMLElement {
6348
6435
 
6349
6436
  connectedCallback() {
6350
6437
  requestAnimationFrame(() => this.#refreshToolbarOverflow());
6351
-
6352
- this._resizeObserver = new ResizeObserver(() => this.#refreshToolbarOverflow());
6353
- this._resizeObserver.observe(this);
6438
+ this.setAttribute("role", "toolbar");
6439
+ this.#installResizeObserver();
6354
6440
  }
6355
6441
 
6356
6442
  disconnectedCallback() {
6357
- if (this._resizeObserver) {
6358
- this._resizeObserver.disconnect();
6359
- this._resizeObserver = null;
6360
- }
6443
+ this.#uninstallResizeObserver();
6361
6444
  this.#unbindHotkeys();
6445
+ this.#unbindFocusListeners();
6362
6446
  }
6363
6447
 
6364
6448
  attributeChangedCallback(name, oldValue, newValue) {
@@ -6372,11 +6456,12 @@ class LexicalToolbarElement extends HTMLElement {
6372
6456
  this.editor = editorElement.editor;
6373
6457
  this.#bindButtons();
6374
6458
  this.#bindHotkeys();
6375
- this.#setTabIndexValues();
6459
+ this.#resetTabIndexValues();
6376
6460
  this.#setItemPositionValues();
6377
6461
  this.#monitorSelectionChanges();
6378
6462
  this.#monitorHistoryChanges();
6379
6463
  this.#refreshToolbarOverflow();
6464
+ this.#bindFocusListeners();
6380
6465
 
6381
6466
  this.toggleAttribute("connected", true);
6382
6467
  }
@@ -6386,24 +6471,39 @@ class LexicalToolbarElement extends HTMLElement {
6386
6471
  this.connectedCallback();
6387
6472
  }
6388
6473
 
6474
+ #installResizeObserver() {
6475
+ this.resizeObserver = new ResizeObserver(() => this.#refreshToolbarOverflow());
6476
+ this.resizeObserver.observe(this);
6477
+ }
6478
+
6479
+ #uninstallResizeObserver() {
6480
+ if (this.resizeObserver) {
6481
+ this.resizeObserver.disconnect();
6482
+ this.resizeObserver = null;
6483
+ }
6484
+ }
6485
+
6389
6486
  #bindButtons() {
6390
6487
  this.addEventListener("click", this.#handleButtonClicked.bind(this));
6391
6488
  }
6392
6489
 
6393
- #handleButtonClicked({ target }) {
6394
- this.#handleTargetClicked(target, "[data-command]", this.#dispatchButtonCommand.bind(this));
6490
+ #handleButtonClicked(event) {
6491
+ this.#handleTargetClicked(event, "[data-command]", this.#dispatchButtonCommand.bind(this));
6395
6492
  }
6396
6493
 
6397
- #handleTargetClicked(target, selector, callback) {
6398
- const button = target.closest(selector);
6494
+ #handleTargetClicked(event, selector, callback) {
6495
+ const button = event.target.closest(selector);
6399
6496
  if (button) {
6400
- callback(button);
6497
+ callback(event, button);
6401
6498
  }
6402
6499
  }
6403
6500
 
6404
- #dispatchButtonCommand(button) {
6405
- const { command, payload } = button.dataset;
6406
- this.editor.dispatchCommand(command, payload);
6501
+ #dispatchButtonCommand(event, { dataset: { command, payload } }) {
6502
+ const isKeyboard = event instanceof PointerEvent && event.pointerId === -1;
6503
+
6504
+ this.editor.update(() => {
6505
+ this.editor.dispatchCommand(command, payload);
6506
+ }, { tag: isKeyboard ? zn : undefined } );
6407
6507
  }
6408
6508
 
6409
6509
  #bindHotkeys() {
@@ -6438,9 +6538,38 @@ class LexicalToolbarElement extends HTMLElement {
6438
6538
  return [ ...modifiers, pressedKey ].join("+")
6439
6539
  }
6440
6540
 
6441
- #setTabIndexValues() {
6442
- this.#buttons.forEach((button) => {
6443
- button.setAttribute("tabindex", 0);
6541
+ #bindFocusListeners() {
6542
+ this.editorElement.addEventListener("lexxy:focus", this.#handleFocus);
6543
+ this.editorElement.addEventListener("lexxy:blur", this.#handleFocusOut);
6544
+ this.addEventListener("focusout", this.#handleFocusOut);
6545
+ this.addEventListener("keydown", this.#handleKeydown);
6546
+ }
6547
+
6548
+ #unbindFocusListeners() {
6549
+ this.editorElement.removeEventListener("lexxy:focus", this.#handleFocus);
6550
+ this.editorElement.removeEventListener("lexxy:blur", this.#handleFocusOut);
6551
+ this.removeEventListener("focusout", this.#handleFocusOut);
6552
+ this.removeEventListener("keydown", this.#handleKeydown);
6553
+ }
6554
+
6555
+ #handleFocus = () => {
6556
+ this.#resetTabIndexValues();
6557
+ this.#focusableItems[0].tabIndex = 0;
6558
+ }
6559
+
6560
+ #handleFocusOut = () => {
6561
+ if (!this.contains(document.activeElement)) {
6562
+ this.#resetTabIndexValues();
6563
+ }
6564
+ }
6565
+
6566
+ #handleKeydown = (event) => {
6567
+ handleRollingTabIndex(this.#focusableItems, event);
6568
+ }
6569
+
6570
+ #resetTabIndexValues() {
6571
+ this.#focusableItems.forEach((button) => {
6572
+ button.tabIndex = -1;
6444
6573
  });
6445
6574
  }
6446
6575
 
@@ -6550,6 +6679,7 @@ class LexicalToolbarElement extends HTMLElement {
6550
6679
 
6551
6680
  const isOverflowing = this.#overflowMenu.children.length > 0;
6552
6681
  this.toggleAttribute("overflowing", isOverflowing);
6682
+ this.#overflowMenu.toggleAttribute("disabled", !isOverflowing);
6553
6683
  }
6554
6684
 
6555
6685
  #compactMenu() {
@@ -6601,6 +6731,10 @@ class LexicalToolbarElement extends HTMLElement {
6601
6731
  return Array.from(this.querySelectorAll(":scope > button"))
6602
6732
  }
6603
6733
 
6734
+ get #focusableItems() {
6735
+ return Array.from(this.querySelectorAll(":scope button, :scope > details > summary"))
6736
+ }
6737
+
6604
6738
  get #toolbarItems() {
6605
6739
  return Array.from(this.querySelectorAll(":scope > *:not(.lexxy-editor__toolbar-overflow)"))
6606
6740
  }
@@ -7598,7 +7732,7 @@ class CommandDispatcher {
7598
7732
  }
7599
7733
 
7600
7734
  #registerKeyboardCommands() {
7601
- this.editor.registerCommand(Me$2, this.#handleListIndentation.bind(this), Ri);
7735
+ this.editor.registerCommand(Me$2, this.#handleTabKey.bind(this), Ri);
7602
7736
  }
7603
7737
 
7604
7738
  #registerDragAndDropHandlers() {
@@ -7648,18 +7782,28 @@ class CommandDispatcher {
7648
7782
  this.editor.focus();
7649
7783
  }
7650
7784
 
7651
- #handleListIndentation(event) {
7785
+ #handleTabKey(event) {
7652
7786
  if (this.selection.isInsideList) {
7653
- event.preventDefault();
7654
- if (event.shiftKey) {
7655
- return this.editor.dispatchCommand(De$2, undefined)
7656
- } else {
7657
- return this.editor.dispatchCommand(Pe$2, undefined)
7658
- }
7787
+ return this.#handleTabForList(event)
7788
+ } else if (this.selection.isInsideCodeBlock) {
7789
+ return this.#handleTabForCode()
7659
7790
  }
7660
7791
  return false
7661
7792
  }
7662
7793
 
7794
+ #handleTabForList(event) {
7795
+ if (event.shiftKey && !this.selection.isIndentedList) return false
7796
+
7797
+ event.preventDefault();
7798
+ const command = event.shiftKey? De$2 : Pe$2;
7799
+ return this.editor.dispatchCommand(command)
7800
+ }
7801
+
7802
+ #handleTabForCode() {
7803
+ const selection = Lr();
7804
+ return yr(selection) && selection.isCollapsed()
7805
+ }
7806
+
7663
7807
  // Not using TOGGLE_LINK_COMMAND because it's not handled unless you use React/LinkPlugin
7664
7808
  #toggleLink(url) {
7665
7809
  this.editor.update(() => {
@@ -7836,6 +7980,29 @@ class Selection {
7836
7980
  return getNearestListItemNode(anchorNode) !== null
7837
7981
  }
7838
7982
 
7983
+ get isIndentedList() {
7984
+ const selection = Lr();
7985
+ if (!yr(selection)) return false
7986
+
7987
+ const nodes = selection.getNodes();
7988
+ for (const node of nodes) {
7989
+ const closestListNode = wt$5(node, lt$3);
7990
+ if (closestListNode && W$4(closestListNode) > 1) {
7991
+ return true
7992
+ }
7993
+ }
7994
+
7995
+ return false
7996
+ }
7997
+
7998
+ get isInsideCodeBlock() {
7999
+ const selection = Lr();
8000
+ if (!yr(selection)) return false
8001
+
8002
+ const anchorNode = selection.anchor.getNode();
8003
+ return wt$5(anchorNode, q$1) !== null
8004
+ }
8005
+
7839
8006
  get nodeAfterCursor() {
7840
8007
  const { anchorNode, offset } = this.#getCollapsedSelectionData();
7841
8008
  if (!anchorNode) return null
@@ -10255,8 +10422,6 @@ class ToolbarDropdown extends HTMLElement {
10255
10422
 
10256
10423
  this.container.addEventListener("toggle", this.#handleToggle.bind(this));
10257
10424
  this.container.addEventListener("keydown", this.#handleKeyDown.bind(this));
10258
-
10259
- this.#setTabIndexValues();
10260
10425
  }
10261
10426
 
10262
10427
  disconnectedCallback() {
@@ -10284,14 +10449,14 @@ class ToolbarDropdown extends HTMLElement {
10284
10449
  }
10285
10450
  }
10286
10451
 
10287
- #handleOpen(trigger) {
10288
- this.trigger = trigger;
10452
+ #handleOpen() {
10289
10453
  this.#interactiveElements[0].focus();
10290
10454
  this.#setupClickOutsideHandler();
10455
+
10456
+ this.#resetTabIndexValues();
10291
10457
  }
10292
10458
 
10293
10459
  #handleClose() {
10294
- this.trigger = null;
10295
10460
  this.#removeClickOutsideHandler();
10296
10461
  this.editor.focus();
10297
10462
  }
@@ -10321,16 +10486,20 @@ class ToolbarDropdown extends HTMLElement {
10321
10486
  }
10322
10487
  }
10323
10488
 
10324
- async #setTabIndexValues() {
10489
+ async #resetTabIndexValues() {
10325
10490
  await nextFrame();
10326
- this.#interactiveElements.forEach((element) => {
10327
- element.setAttribute("tabindex", 0);
10491
+ this.#buttons.forEach((element, index) => {
10492
+ element.setAttribute("tabindex", index === 0 ? 0 : "-1");
10328
10493
  });
10329
10494
  }
10330
10495
 
10331
10496
  get #interactiveElements() {
10332
10497
  return Array.from(this.querySelectorAll("button, input"))
10333
10498
  }
10499
+
10500
+ get #buttons() {
10501
+ return Array.from(this.querySelectorAll("button"))
10502
+ }
10334
10503
  }
10335
10504
 
10336
10505
  class LinkDropdown extends ToolbarDropdown {
@@ -10526,15 +10695,19 @@ class TableHandler extends HTMLElement {
10526
10695
  return Ue$1(currentCell)
10527
10696
  }
10528
10697
 
10698
+ get #tableHandlerButtons() {
10699
+ return Array.from(this.buttonsContainer.querySelectorAll("button, details > summary"))
10700
+ }
10701
+
10529
10702
  #registerKeyboardShortcuts() {
10530
- this.unregisterKeyboardShortcuts = this.#editor.registerCommand(me$1, this.#handleKeyDown.bind(this), Bi);
10703
+ this.unregisterKeyboardShortcuts = this.#editor.registerCommand(me$1, this.#handleKeyDown, Bi);
10531
10704
  }
10532
10705
 
10533
10706
  #unregisterKeyboardShortcuts() {
10534
10707
  this.unregisterKeyboardShortcuts();
10535
10708
  }
10536
10709
 
10537
- #handleKeyDown(event) {
10710
+ #handleKeyDown = (event) => {
10538
10711
  if ((event.ctrlKey || event.metaKey) && event.shiftKey && event.key === "F10") {
10539
10712
  const firstButton = this.buttonsContainer?.querySelector("button, [tabindex]:not([tabindex='-1'])");
10540
10713
  this.#setFocusStateOnSelectedCell();
@@ -10552,6 +10725,14 @@ class TableHandler extends HTMLElement {
10552
10725
  }
10553
10726
  }
10554
10727
 
10728
+ #handleTableHandlerKeydown = (event) => {
10729
+ if (event.key === "Escape") {
10730
+ this.#editor.focus();
10731
+ } else {
10732
+ handleRollingTabIndex(this.#tableHandlerButtons, event);
10733
+ }
10734
+ }
10735
+
10555
10736
  #setUpButtons() {
10556
10737
  this.buttonsContainer = createElement("div", {
10557
10738
  className: "lexxy-table-handle-buttons"
@@ -10562,6 +10743,7 @@ class TableHandler extends HTMLElement {
10562
10743
 
10563
10744
  this.moreMenu = this.#createMoreMenu();
10564
10745
  this.buttonsContainer.appendChild(this.moreMenu);
10746
+ this.buttonsContainer.addEventListener("keydown", this.#handleTableHandlerKeydown);
10565
10747
 
10566
10748
  this.#editorElement.appendChild(this.buttonsContainer);
10567
10749
  }
@@ -11674,3 +11856,4 @@ function highlightElement(preElement) {
11674
11856
  }
11675
11857
 
11676
11858
  export { highlightAll };
11859
+ //# sourceMappingURL=lexxy.js.map
Binary file
Binary file