diff --git a/shared/components/rstack-space-switcher.ts b/shared/components/rstack-space-switcher.ts index d9413dc..c184322 100644 --- a/shared/components/rstack-space-switcher.ts +++ b/shared/components/rstack-space-switcher.ts @@ -27,6 +27,10 @@ export class RStackSpaceSwitcher extends HTMLElement { #shadow: ShadowRoot; #spaces: SpaceInfo[] = []; #loaded = false; + // Preserved create-form state across open/close + #createFormOpen = false; + #createName = ''; + #createVisibility = 'public'; constructor() { super(); @@ -107,11 +111,27 @@ export class RStackSpaceSwitcher extends HTMLElement { if (!this.#loaded) { await this.#loadSpaces(); this.#renderMenu(menu, current); + } else { + // Restore create form state if it was open + this.#restoreCreateFormState(menu); } + } else { + // Preserve create form state before closing + this.#saveCreateFormState(menu); } }); - document.addEventListener("click", () => menu.classList.remove("open")); + // Close menu only when clicking outside both trigger and menu + document.addEventListener("click", (e) => { + if (!menu.classList.contains("open")) return; + const path = e.composedPath(); + if (path.includes(menu) || path.includes(trigger)) return; + this.#saveCreateFormState(menu); + menu.classList.remove("open"); + }); + + // Prevent clicks inside menu from closing it + menu.addEventListener("click", (e) => e.stopPropagation()); } #visibilityInfo(s: SpaceInfo): { cls: string; label: string } { @@ -397,10 +417,11 @@ export class RStackSpaceSwitcher extends HTMLElement { name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 40); toggle.addEventListener("click", (e) => { - e.stopPropagation(); e.preventDefault(); - const showing = popout.classList.toggle("hidden"); - if (!showing) nameInput.focus(); + const wasHidden = popout.classList.contains("hidden"); + popout.classList.toggle("hidden"); + this.#createFormOpen = wasHidden; + if (wasHidden) nameInput.focus(); }); nameInput.addEventListener("input", () => { @@ -408,18 +429,17 @@ export class RStackSpaceSwitcher extends HTMLElement { slugPreview.textContent = slug ? `slug: ${slug}` : ""; }); - nameInput.addEventListener("click", (e) => e.stopPropagation()); - - cancelBtn.addEventListener("click", (e) => { - e.stopPropagation(); + cancelBtn.addEventListener("click", () => { popout.classList.add("hidden"); nameInput.value = ""; slugPreview.textContent = ""; status.textContent = ""; + this.#createFormOpen = false; + this.#createName = ''; + this.#createVisibility = 'public'; }); - submitBtn.addEventListener("click", async (e) => { - e.stopPropagation(); + submitBtn.addEventListener("click", async () => { const name = nameInput.value.trim(); if (!name) { status.textContent = "Name required"; return; } @@ -479,6 +499,43 @@ export class RStackSpaceSwitcher extends HTMLElement { } } + #saveCreateFormState(menu: HTMLElement) { + const popout = menu.querySelector("#create-popout") as HTMLElement; + if (!popout) return; + this.#createFormOpen = !popout.classList.contains("hidden"); + const nameInput = menu.querySelector("#create-name") as HTMLInputElement; + if (nameInput) this.#createName = nameInput.value; + const checkedRadio = menu.querySelector('input[name="create-vis"]:checked') as HTMLInputElement; + if (checkedRadio) this.#createVisibility = checkedRadio.value; + } + + #restoreCreateFormState(menu: HTMLElement) { + const popout = menu.querySelector("#create-popout") as HTMLElement; + const nameInput = menu.querySelector("#create-name") as HTMLInputElement; + const slugPreview = menu.querySelector("#create-slug") as HTMLElement; + if (!popout || !nameInput) return; + + if (this.#createFormOpen) { + popout.classList.remove("hidden"); + } + if (this.#createName) { + nameInput.value = this.#createName; + const toSlug = (name: string) => + name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 40); + if (slugPreview) { + const slug = toSlug(this.#createName); + slugPreview.textContent = slug ? `slug: ${slug}` : ""; + } + } + if (this.#createVisibility !== 'public') { + const radio = menu.querySelector(`input[name="create-vis"][value="${this.#createVisibility}"]`) as HTMLInputElement; + if (radio) radio.checked = true; + } + if (this.#createFormOpen) { + requestAnimationFrame(() => nameInput.focus()); + } + } + #showRequestAccessModal(slug: string, spaceName: string) { if (document.querySelector(".rstack-auth-overlay")) return;