fix: admin/fs: couldn't close file dialog after save button in "base address" dialog

Massimo Melina committed Apr 14, 2024 at 16:16 UTC b83384152fa8f1aaa37abd3544aaefe77b50cd5b
1 file changed +16 -5
shared/dialogs.ts
+16 -5
@@ -3,7 +3,7 @@
3 import { createElement as h, Fragment, FunctionComponent, isValidElement, ReactNode, useEffect, useRef,
4 HTMLAttributes, useState } from 'react'
5 import { proxy, ref, useSnapshot } from 'valtio'
6 -import { domOn, isPrimitive, objSameKeys } from '.'
6 +import { domOn, isPrimitive, objSameKeys, wait } from '.'
7
8 export interface DialogOptions {
9 Content: FunctionComponent<any>,
@@ -26,6 +26,7 @@ export interface DialogOptions {
26
27 const dialogs = proxy<DialogOptions[]>([])
28 const focusBak: (Element | null)[] = []
29 +const { history } = window
30
31 export const dialogsDefaults: Partial<DialogOptions> = {
32 closableProps: { children: 'x', 'aria-label': "Close", },
@@ -66,14 +67,22 @@ function isDescendant(child: Node | null, parent: Node) {
67 let ignorePopState = false
68 function back() {
69 ignorePopState = true
69 - window.history.back()
70 + history.back()
71 }
72
73 +;(async () => {
74 + while (history.state.$dialog) { // it happens if the user reloads the browser leaving open dialogs
75 + history.back()
76 + await wait(1) // history.state is not changed without this, on chrome123
77 + }
78 +})()
79 +
80 +
81 export function Dialogs(props: HTMLAttributes<HTMLDivElement>) {
82 useEffect(() => domOn('popstate', () => {
83 if (ignorePopState)
84 return ignorePopState = false
76 - const { $dialog } = window.history.state
85 + const { $dialog } = history.state
86 if ($dialog && !dialogs.find(x => x.$id === $dialog)) // it happens if the user, after closing a dialog, goes forward in the history
87 return back()
88 closeDialog(undefined, true)
@@ -169,12 +178,14 @@ export function newDialog(options: DialogOptions) {
178 options = objSameKeys(options, x => isValidElement(x) ? ref(x) : x) as typeof options // encapsulate elements as react will try to write, but valtio makes them readonly
179 dialogs.push(options)
180 if (options.closable !== false)
172 - window.history.pushState({ $dialog: $id, ts }, '')
181 + history.pushState({ $dialog: $id, ts, idx: history.state.idx + 1 }, '')
182 return { close }
183
184 function close(v?:any) {
185 const i = dialogs.findIndex(x => (x as any).$id === $id)
186 if (i < 0) return
187 + if (history.state.$dialog === $id)
188 + back()
189 return closeDialogAt(i, v)
190 }
191 }
@@ -187,7 +198,7 @@ export function closeDialog(v?:any, skipHistory=false) {
198 if (d.reserveClosing)
199 continue
200 if (!skipHistory) {
190 - if (window.history.state.$dialog !== d.$id) return
201 + if (history.state.$dialog !== d.$id) return
202 back()
203 }
204 closeDialogAt(i, v)