properly close modal stack in order on escape

This commit is contained in:
Webifi 2023-06-05 16:13:40 -05:00
parent 939d69fe46
commit c672236412
10 changed files with 51 additions and 38 deletions

7
package-lock.json generated
View File

@ -28,6 +28,7 @@
"gpt-tokenizer": "^2.0.0", "gpt-tokenizer": "^2.0.0",
"postcss": "^8.4.24", "postcss": "^8.4.24",
"sass": "^1.61.0", "sass": "^1.61.0",
"stacking-order": "^2.0.0",
"svelte": "^3.58.0", "svelte": "^3.58.0",
"svelte-check": "^3.4.3", "svelte-check": "^3.4.3",
"svelte-fa": "^3.0.3", "svelte-fa": "^3.0.3",
@ -3976,6 +3977,12 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/stacking-order": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/stacking-order/-/stacking-order-2.0.0.tgz",
"integrity": "sha512-nnv68iFGwrKXYlmXJKD5qBuH8D49BEv6zAgesXoKeGqMmMit6/Hyvb6R0BG9odpjqQm35YjlTsZUyB0ffbFDrg==",
"dev": true
},
"node_modules/string.prototype.trim": { "node_modules/string.prototype.trim": {
"version": "1.2.7", "version": "1.2.7",
"resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz",

View File

@ -34,6 +34,7 @@
"gpt-tokenizer": "^2.0.0", "gpt-tokenizer": "^2.0.0",
"postcss": "^8.4.24", "postcss": "^8.4.24",
"sass": "^1.61.0", "sass": "^1.61.0",
"stacking-order": "^2.0.0",
"svelte": "^3.58.0", "svelte": "^3.58.0",
"svelte-check": "^3.4.3", "svelte-check": "^3.4.3",
"svelte-fa": "^3.0.3", "svelte-fa": "^3.0.3",

View File

@ -9,6 +9,7 @@
import NewChat from './lib/NewChat.svelte' import NewChat from './lib/NewChat.svelte'
import { chatsStorage, apiKeyStorage } from './lib/Storage.svelte' import { chatsStorage, apiKeyStorage } from './lib/Storage.svelte'
import { Modals, closeModal } from 'svelte-modals' import { Modals, closeModal } from 'svelte-modals'
import { triggerModalEsc } from './lib/Util.svelte'
// The definition of the routes with some conditions // The definition of the routes with some conditions
const routes = { const routes = {
@ -51,6 +52,10 @@
/> />
</Modals> </Modals>
<svelte:window
on:keydown={(e) => triggerModalEsc(e)}
/>
<style> <style>
.backdrop { .backdrop {
position: fixed; position: fixed;

6
src/additional-svelte-typings.d.ts vendored Normal file
View File

@ -0,0 +1,6 @@
declare namespace svelteHTML {
interface HTMLAttributes<> {
// Custom on:modal-esc event
'on:modal-esc'?: (event: any) => any
}
}

View File

@ -139,12 +139,3 @@
</div> </div>
<input style="display:none" type="file" accept=".json" on:change={(e) => importChatFromFile(e)} bind:this={chatFileInput} > <input style="display:none" type="file" accept=".json" on:change={(e) => importChatFromFile(e)} bind:this={chatFileInput} >
<svelte:window
on:keydown={(event) => {
if (event.key === 'Escape') {
event.stopPropagation()
showChatMenu = false
}
}}
/>

View File

@ -253,7 +253,7 @@
</script> </script>
<!-- svelte-ignore a11y-click-events-have-key-events --> <!-- svelte-ignore a11y-click-events-have-key-events -->
<div class="modal chat-settings" class:is-active={showSettingsModal}> <div class="modal chat-settings" class:is-active={showSettingsModal} on:modal-esc={closeSettings}>
<div class="modal-background" on:click={closeSettings} /> <div class="modal-background" on:click={closeSettings} />
<div class="modal-card wide" on:click={() => { showProfileMenu = false }}> <div class="modal-card wide" on:click={() => { showProfileMenu = false }}>
<header class="modal-card-head"> <header class="modal-card-head">
@ -322,12 +322,3 @@
</div> </div>
<input style="display:none" type="file" accept=".json" on:change={(e) => importProfileFromFile(e)} bind:this={profileFileInput} > <input style="display:none" type="file" accept=".json" on:change={(e) => importProfileFromFile(e)} bind:this={profileFileInput} >
<svelte:window
on:keydown={(event) => {
if (event.key === 'Escape') {
event.stopPropagation()
closeSettings()
}
}}
/>

View File

@ -67,12 +67,12 @@
} }
const keydown = (event:KeyboardEvent) => { const keydown = (event:KeyboardEvent) => {
if (event.key === 'Escape') { // if (event.key === 'Escape') {
event.stopPropagation() // event.stopPropagation()
event.preventDefault() // event.preventDefault()
message.content = original // message.content = original
editing = false // editing = false
} // }
} }
const scrollToMessage = (uuid:string | string[] | undefined) => { const scrollToMessage = (uuid:string | string[] | undefined) => {

View File

@ -29,7 +29,7 @@
</script> </script>
{#if isOpen} {#if isOpen}
<div class="modal is-active"> <div class="modal is-active" on:modal-esc={doCancel}>
<!-- svelte-ignore a11y-click-events-have-key-events --> <!-- svelte-ignore a11y-click-events-have-key-events -->
<div class="modal-background" on:click={doCancel} /> <div class="modal-background" on:click={doCancel} />
<div class="modal-content nomax"> <div class="modal-content nomax">
@ -59,12 +59,3 @@
</div> </div>
</div> </div>
{/if} {/if}
<svelte:window
on:keydown={(event) => {
if (event.key === 'Escape') {
event.stopPropagation()
doCancel()
}
}}
/>

View File

@ -45,7 +45,7 @@
</script> </script>
{#if isOpen} {#if isOpen}
<div class="modal is-active"> <div class="modal is-active" on:modal-esc={doClose}>
<!-- svelte-ignore a11y-click-events-have-key-events --> <!-- svelte-ignore a11y-click-events-have-key-events -->
<div class="modal-background" on:click={doClose} /> <div class="modal-background" on:click={doClose} />
<div class="modal-content nomax"> <div class="modal-content nomax">
@ -97,11 +97,11 @@
</div> </div>
{/if} {/if}
<svelte:window <!-- <svelte:window
on:keydown={(event) => { on:keydown={(event) => {
if (event.key === 'Escape') { if (event.key === 'Escape') {
event.stopPropagation() event.stopPropagation()
onClose() onClose()
} }
}} }}
/> /> -->

View File

@ -1,4 +1,5 @@
<script context="module" lang="ts"> <script context="module" lang="ts">
import { compare } from 'stacking-order'
export const sizeTextElements = () => { export const sizeTextElements = () => {
const els = document.querySelectorAll('textarea.auto-size') const els = document.querySelectorAll('textarea.auto-size')
for (let i:number = 0, l = els.length; i < l; i++) autoGrowInput(els[i] as HTMLTextAreaElement) for (let i:number = 0, l = els.length; i < l; i++) autoGrowInput(els[i] as HTMLTextAreaElement)
@ -27,4 +28,24 @@
offset offset
}) })
} }
export const triggerModalEsc = (event:KeyboardEvent|undefined):boolean|void => {
if (!event || event.key !== 'Escape') return
const stack = Array.from(document.querySelectorAll('.modal')).filter(s =>
window.getComputedStyle(s).getPropertyValue('display') !== 'none'
)
const top:HTMLElement = stack.length === 1
? stack[0]
: stack.find(m1 => {
return stack.find(m2 => {
return m1 !== m2 && compare(m1, m2) > 0 && m1
})
}) as any
if (top) {
// trigger modal-esc event on topmost modal when esc key is pressed
const e = new CustomEvent('modal-esc', { detail: top })
top.dispatchEvent(e)
}
}
</script> </script>