Keep modal state in a plain module instead of a rune file (#514)
This commit is contained in:
parent
c50be161d2
commit
2464389e2b
8 changed files with 35 additions and 45 deletions
|
|
@ -20,7 +20,7 @@ export default [
|
|||
},
|
||||
},
|
||||
{
|
||||
files: ["**/*.svelte", "**/*.svelte.ts"],
|
||||
files: ["**/*.svelte"],
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
parser: ts.parser,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
import SpeechBanner from "@app/components/SpeechBanner.svelte"
|
||||
import PrimaryNav from "@app/components/PrimaryNav.svelte"
|
||||
import {app} from "@app/core"
|
||||
import {getModal} from "@app/modal.svelte"
|
||||
import {getModal} from "@app/modal"
|
||||
|
||||
type Props = {
|
||||
children: Snippet
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@
|
|||
import {mount, unmount, untrack} from "svelte"
|
||||
import Drawer from "@lib/components/Drawer.svelte"
|
||||
import Dialog from "@lib/components/Dialog.svelte"
|
||||
import {popModal} from "@app/modal"
|
||||
import {getModal, getModalStack} from "@app/modal.svelte"
|
||||
import {getModal, getModalStack, popModal} from "@app/modal"
|
||||
|
||||
const closeModal = () => {
|
||||
const modal = getModal()
|
||||
|
|
|
|||
|
|
@ -15,8 +15,7 @@
|
|||
import Search from "@app/components/Search.svelte"
|
||||
import SpaceMenuDrawer from "@app/components/SpaceMenuDrawer.svelte"
|
||||
import {PLATFORM_RELAYS} from "@app/env"
|
||||
import {popModal, pushModal} from "@app/modal"
|
||||
import {getModal} from "@app/modal.svelte"
|
||||
import {getModal, popModal, pushModal} from "@app/modal"
|
||||
import {notifications} from "@app/notifications"
|
||||
import {userSpaceUrls} from "@app/rooms"
|
||||
import {goToChat, lastSpaceUrl, makeSpacePath} from "@app/routes"
|
||||
|
|
|
|||
|
|
@ -1,31 +0,0 @@
|
|||
import type {Component} from "svelte"
|
||||
import {last} from "@welshman/lib"
|
||||
import {page} from "$app/state"
|
||||
import type {DialogSize} from "@lib/components/Dialog.svelte"
|
||||
|
||||
export type ModalOptions = {
|
||||
drawer?: boolean
|
||||
nested?: boolean
|
||||
noEscape?: boolean
|
||||
fullscreen?: boolean
|
||||
size?: DialogSize
|
||||
replaceState?: boolean
|
||||
path?: string
|
||||
}
|
||||
|
||||
export type Modal = {
|
||||
id: string
|
||||
component: Component
|
||||
props: Record<string, any>
|
||||
options: ModalOptions
|
||||
}
|
||||
|
||||
export const modals = $state<Record<string, Modal>>({})
|
||||
|
||||
// Open modal ids live in SvelteKit's page state (shallow routing): each modal owns a history entry
|
||||
// without a navigation, and any `goto` that doesn't pass `state` along closes them.
|
||||
const modalStack = $derived((page.state.modals ?? []).map(id => modals[id]).filter(Boolean))
|
||||
|
||||
export const getModalStack = () => modalStack
|
||||
|
||||
export const getModal = () => last(modalStack)
|
||||
|
|
@ -1,23 +1,47 @@
|
|||
import type {Component} from "svelte"
|
||||
import {randomId, Emitter} from "@welshman/lib"
|
||||
import {randomId, last, Emitter} from "@welshman/lib"
|
||||
import {goto, pushState, replaceState} from "$app/navigation"
|
||||
import {page} from "$app/state"
|
||||
import {modals, type ModalOptions} from "@app/modal.svelte"
|
||||
import type {DialogSize} from "@lib/components/Dialog.svelte"
|
||||
|
||||
export type ModalOptions = {
|
||||
drawer?: boolean
|
||||
nested?: boolean
|
||||
noEscape?: boolean
|
||||
fullscreen?: boolean
|
||||
size?: DialogSize
|
||||
replaceState?: boolean
|
||||
path?: string
|
||||
}
|
||||
|
||||
export type Modal = {
|
||||
id: string
|
||||
component: Component
|
||||
props: Record<string, any>
|
||||
options: ModalOptions
|
||||
}
|
||||
|
||||
export const emitter = new Emitter()
|
||||
|
||||
const modals: Record<string, Modal> = {}
|
||||
|
||||
// Open modal ids live in SvelteKit page state (shallow routing): each modal owns a history entry
|
||||
// without a navigation, and any `goto` that does not pass `state` along closes them.
|
||||
export const getModalStack = () => (page.state.modals ?? []).map(id => modals[id]).filter(Boolean)
|
||||
|
||||
export const getModal = () => last(getModalStack())
|
||||
|
||||
export type NavigateOptions = Parameters<typeof goto>[1] & {keepModal?: boolean}
|
||||
|
||||
// An open modal owns the current history entry, so a navigation that drops it takes that entry over
|
||||
export const navigate = (path: string, {keepModal, ...options}: NavigateOptions = {}) => {
|
||||
const ids = page.state.modals ?? []
|
||||
const modalIsOpen = ids.length > 0
|
||||
|
||||
if (keepModal && modalIsOpen) {
|
||||
if (keepModal && ids.length > 0) {
|
||||
return goto(path, {...options, state: {modals: ids}, replaceState: true})
|
||||
}
|
||||
|
||||
return goto(path, {...options, replaceState: options.replaceState || modalIsOpen})
|
||||
return goto(path, {...options, replaceState: options.replaceState || ids.length > 0})
|
||||
}
|
||||
|
||||
export const pushModal = (
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
import Dialog from "@lib/components/Dialog.svelte"
|
||||
import SpaceInviteAccept from "@app/components/SpaceInviteAccept.svelte"
|
||||
import {goToHome} from "@app/routes"
|
||||
import {getModal} from "@app/modal.svelte"
|
||||
import {getModal} from "@app/modal"
|
||||
|
||||
const children = {
|
||||
component: SpaceInviteAccept,
|
||||
|
|
|
|||
|
|
@ -21,8 +21,7 @@
|
|||
import {deriveRelayAuthError} from "@app/access"
|
||||
import {relays, roomLists, user} from "@app/core"
|
||||
import {userSpaceUrls} from "@app/rooms"
|
||||
import {pushModal} from "@app/modal"
|
||||
import {getModal} from "@app/modal.svelte"
|
||||
import {getModal, pushModal} from "@app/modal"
|
||||
import {relaysPendingTrust} from "@app/policies"
|
||||
import {decodeRelay} from "@app/relays"
|
||||
import {makeSpacePath} from "@app/routes"
|
||||
|
|
|
|||
Loading…
Reference in a new issue