Budibase is an open-source low-code platform for creating internal apps in minutes. Supports PostgreSQL, MySQL, MSSQL, MongoDB, Rest API, Docker, K8s 🚀
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

165 lines
3.7 KiB

<script>
import "@spectrum-css/modal/dist/index-vars.css"
import "@spectrum-css/underlay/dist/index-vars.css"
import { createEventDispatcher, setContext, tick } from "svelte"
import { fade, fly } from "svelte/transition"
import Portal from "svelte-portal"
import Context from "../context"
export let fixed = false
export let inline = false
const dispatch = createEventDispatcher()
let visible = fixed || inline
let modal
$: dispatch(visible ? "show" : "hide")
export function show() {
if (visible) {
return
}
visible = true
}
export function hide() {
if (!visible || fixed || inline) {
return
}
visible = false
}
export function cancel() {
if (!visible) {
return
}
dispatch("cancel")
hide()
}
function handleKey(e) {
if (visible && e.key === "Escape") {
cancel()
}
}
async function focusModal(node) {
await tick()
// Try to focus first input
const inputs = node.querySelectorAll("input")
if (inputs?.length) {
inputs[0].focus()
}
// Otherwise try to focus confirmation button
else if (modal) {
const confirm = modal.querySelector(".confirm-wrap .spectrum-Button")
if (confirm) {
confirm.focus()
}
}
}
setContext(Context.Modal, { show, hide, cancel })
</script>
<svelte:window on:keydown={handleKey} />
{#if inline}
{#if visible}
<div use:focusModal bind:this={modal} class="spectrum-Modal inline is-open">
<slot />
</div>
{/if}
{:else}
<!--
We cannot conditionally render the portal as this leads to a missing
insertion point when using nested modals. Therefore we just conditionally
render the content of the portal.
It still breaks the modal animation, but its better than soft bricking the
screen.
-->
<Portal target=".modal-container">
{#if visible}
<div class="spectrum-Underlay is-open" on:mousedown|self={cancel}>
<div
class="background"
in:fade={{ duration: 200 }}
out:fade|local={{ duration: 200 }}
/>
<div class="modal-wrapper" on:mousedown|self={cancel}>
<div class="modal-inner-wrapper" on:mousedown|self={cancel}>
<slot name="outside" />
<div
use:focusModal
bind:this={modal}
class="spectrum-Modal is-open"
in:fly={{ y: 30, duration: 200 }}
out:fly|local={{ y: 30, duration: 200 }}
>
<slot />
</div>
</div>
</div>
</div>
{/if}
</Portal>
{/if}
<style>
.spectrum-Underlay {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
z-index: 999;
overflow: auto;
overflow-x: hidden;
background: transparent;
}
.background {
background: var(--modal-background, rgba(0, 0, 0, 0.75));
position: fixed;
top: 0;
left: 0;
height: 100vh;
width: 100vw;
opacity: 0.65;
pointer-events: none;
}
.modal-wrapper {
flex: 1 1 auto;
display: flex;
flex-direction: row;
-moz-box-pack: center;
justify-content: center;
align-items: flex-start;
max-height: 100%;
}
.modal-inner-wrapper {
flex: 1 1 auto;
display: flex;
flex-direction: row;
-moz-box-pack: center;
justify-content: center;
align-items: flex-start;
width: 0;
position: relative;
}
.spectrum-Modal {
overflow: visible;
max-height: none;
margin: 40px 0;
transform: none;
--spectrum-dialog-confirm-border-radius: var(
--spectrum-global-dimension-size-100
);
max-width: 100%;
}
:global(.spectrum--lightest .spectrum-Modal.inline) {
border: var(--border-light);
}
</style>