@@ -9536,6 +9536,10 @@ class LexicalEditorElement extends HTMLElement {
95369536 return this.getAttribute("attachments") !== "false"
95379537 }
95389538
9539+ get contentTabIndex() {
9540+ return parseInt(this.editorContentElement?.getAttribute("tabindex") ?? "0")
9541+ }
9542+
95399543 focus() {
95409544 this.editor.focus();
95419545 }
@@ -9856,35 +9860,23 @@ class LexicalEditorElement extends HTMLElement {
98569860
98579861customElements.define("lexxy-editor", LexicalEditorElement);
98589862
9859- class ToolbarDialog extends HTMLElement {
9863+ class ToolbarDropdown extends HTMLElement {
98609864 connectedCallback() {
9861- this.dialog = this.querySelector("dialog");
9862- if ("closedBy" in this.dialog.constructor.prototype) {
9863- this.dialog.closedBy = "any";
9864- }
9865- this.#registerHandlers();
9865+ this.container = this.closest("details");
9866+
9867+ this.container.addEventListener("toggle", this.#handleToggle.bind(this));
9868+ this.container.addEventListener("keydown", this.#handleKeyDown.bind(this));
9869+
9870+ this.#assignTabIndexes();
98669871 }
98679872
98689873 disconnectedCallback() {
98699874 this.#removeClickOutsideHandler();
9875+ this.container.removeEventListener("keydown", this.#handleKeyDown.bind(this));
98709876 }
98719877
98729878 updateStateCallback() { }
98739879
9874- show(triggerButton) {
9875- if (this.preventImmediateReopen) { return }
9876-
9877- this.triggerButton = triggerButton;
9878- this.#positionDialog();
9879- this.dialog.show();
9880-
9881- this.#setupClickOutsideHandler();
9882- }
9883-
9884- close() {
9885- this.dialog.close();
9886- }
9887-
98889880 get toolbar() {
98899881 return this.closest("lexxy-toolbar")
98909882 }
@@ -9893,32 +9885,42 @@ class ToolbarDialog extends HTMLElement {
98939885 return this.toolbar.editor
98949886 }
98959887
9896- get open() { return this.dialog.open }
9897-
9898- #registerHandlers() {
9899- this.#setupKeydownHandler();
9900- this.dialog.addEventListener("cancel", this.#handleCancel.bind(this));
9901- this.dialog.addEventListener("close", this.#handleClose.bind(this));
9888+ open(triggerButton) {
9889+ this.triggerButton = triggerButton;
9890+ this.#interactiveElements[0].focus();
9891+ this.#setupClickOutsideHandler();
99029892 }
99039893
9904- #handleClose () {
9894+ close () {
99059895 this.#removeClickOutsideHandler();
99069896 this.triggerButton = null;
99079897 this.editor.focus();
9898+
9899+ this.container.removeAttribute("open");
9900+ }
9901+
9902+ #handleToggle(event) {
9903+ if (this.container.open) {
9904+ this.open(event.target);
9905+ } else {
9906+ this.close();
9907+ }
99089908 }
99099909
9910- #handleCancel() {
9911- this.preventImmediateReopen = true;
9912- requestAnimationFrame(() => this.preventImmediateReopen = undefined);
9910+ #assignTabIndexes() {
9911+ requestAnimationFrame(() => {
9912+ this.#interactiveElements.forEach((element) => {
9913+ element.setAttribute("tabindex", 0);
9914+ });
9915+ });
99139916 }
99149917
9915- #positionDialog() {
9916- const left = this.triggerButton.offsetLeft;
9917- this.dialog.style.insetInlineStart = `${left}px`;
9918+ get #interactiveElements() {
9919+ return Array.from(this.querySelectorAll("button, input"))
99189920 }
99199921
99209922 #setupClickOutsideHandler() {
9921- if (this.#browserHandlesClose || this. clickOutsideHandler) return
9923+ if (this.clickOutsideHandler) return
99229924
99239925 this.clickOutsideHandler = this.#handleClickOutside.bind(this);
99249926 document.addEventListener("click", this.clickOutsideHandler, true);
@@ -9932,24 +9934,16 @@ class ToolbarDialog extends HTMLElement {
99329934 }
99339935
99349936 #handleClickOutside({ target }) {
9935- if (!this.dialog .open) return
9937+ if (!this.container .open) return
99369938
9937- const isClickInsideDialog = this.dialog .contains(target);
9939+ const isClickInsideDropdown = this.contains(target);
99389940 const isClickOnTrigger = this.triggerButton.contains(target);
99399941
9940- if (!isClickInsideDialog && !isClickOnTrigger) {
9942+ if (!isClickInsideDropdown && !isClickOnTrigger) {
99419943 this.close();
99429944 }
99439945 }
99449946
9945- #setupKeydownHandler() {
9946- if (!this.#browserHandlesClose) { this.addEventListener("keydown", this.#handleKeyDown.bind(this)); }
9947- }
9948-
9949- get #browserHandlesClose() {
9950- return this.dialog.closedBy === "any"
9951- }
9952-
99539947 #handleKeyDown(event) {
99549948 if (event.key === "Escape") {
99559949 event.stopPropagation();
@@ -9958,7 +9952,7 @@ class ToolbarDialog extends HTMLElement {
99589952 }
99599953}
99609954
9961- class LinkDialog extends ToolbarDialog {
9955+ class LinkDropdown extends ToolbarDropdown {
99629956 connectedCallback() {
99639957 super.connectedCallback();
99649958 this.input = this.querySelector("input");
@@ -9971,8 +9965,8 @@ class LinkDialog extends ToolbarDialog {
99719965 }
99729966
99739967 #registerHandlers() {
9974- this.dialog. addEventListener("beforetoggle", this.#handleBeforeToggle.bind(this));
9975- this.dialog. addEventListener("submit", this.#handleSubmit.bind(this));
9968+ this.addEventListener("beforetoggle", this.#handleBeforeToggle.bind(this));
9969+ this.addEventListener("submit", this.#handleSubmit.bind(this));
99769970 this.querySelector("[value='unlink']").addEventListener("click", this.#handleUnlink.bind(this));
99779971 }
99789972
@@ -9983,6 +9977,7 @@ class LinkDialog extends ToolbarDialog {
99839977 #handleSubmit(event) {
99849978 const command = event.submitter?.value;
99859979 this.editor.dispatchCommand(command, this.input.value);
9980+ this.close();
99869981 }
99879982
99889983 #handleUnlink() {
@@ -10011,9 +10006,7 @@ class LinkDialog extends ToolbarDialog {
1001110006 }
1001210007}
1001310008
10014- // We should extend the native dialog and avoid the intermediary <dialog> but not
10015- // supported by Safari yet: customElements.define("lexxy-link-dialog", LinkDialog, { extends: "dialog" })
10016- customElements.define("lexxy-link-dialog", LinkDialog);
10009+ customElements.define("lexxy-dropdown-link", LinkDropdown);
1001710010
1001810011const APPLY_HIGHLIGHT_SELECTOR = "button.lexxy-highlight-button";
1001910012const REMOVE_HIGHLIGHT_SELECTOR = "[data-command='removeHighlight']";
@@ -10023,7 +10016,7 @@ const REMOVE_HIGHLIGHT_SELECTOR = "[data-command='removeHighlight']";
1002310016// see https://github.com/facebook/lexical/issues/8013
1002410017const NO_STYLE = Symbol("no_style");
1002510018
10026- class HighlightDialog extends ToolbarDialog {
10019+ class HighlightDropdown extends ToolbarDropdown {
1002710020 connectedCallback() {
1002810021 super.connectedCallback();
1002910022
@@ -10109,9 +10102,7 @@ class HighlightDialog extends ToolbarDialog {
1010910102 }
1011010103}
1011110104
10112- // We should extend the native dialog and avoid the intermediary <dialog> but not
10113- // supported by Safari yet: customElements.define("lexxy-hightlight-dialog", HighlightDialog, { extends: "dialog" })
10114- customElements.define("lexxy-highlight-dialog", HighlightDialog);
10105+ customElements.define("lexxy-dropdown-highlight", HighlightDropdown);
1011510106
1011610107class BaseSource {
1011710108 // Template method to override
0 commit comments