refactor: monorepo+pnpm (removed husky)
This commit is contained in:
189
packages/hoppscotch-app/components/smart/Modal.vue
Normal file
189
packages/hoppscotch-app/components/smart/Modal.vue
Normal file
@@ -0,0 +1,189 @@
|
||||
<template>
|
||||
<transition name="fade" appear @leave="onTransitionLeaveStart">
|
||||
<div
|
||||
ref="modal"
|
||||
class="inset-0 transition z-10 z-50 fixed hide-scrollbar overflow-y-auto"
|
||||
>
|
||||
<div
|
||||
class="flex min-h-screen text-center items-end justify-center sm:block"
|
||||
>
|
||||
<transition name="fade" appear>
|
||||
<div
|
||||
class="bg-primaryDark opacity-90 inset-0 transition fixed"
|
||||
@touchstart="!dialog ? close() : null"
|
||||
@touchend="!dialog ? close() : null"
|
||||
@mouseup="!dialog ? close() : null"
|
||||
@mousedown="!dialog ? close() : null"
|
||||
></div>
|
||||
</transition>
|
||||
<span
|
||||
v-if="placement === 'center'"
|
||||
class="hidden sm:h-screen sm:inline-block sm:align-middle"
|
||||
aria-hidden="true"
|
||||
>​</span
|
||||
>
|
||||
<transition
|
||||
appear
|
||||
enter-active-class="transition"
|
||||
enter-class="translate-y-4 scale-95"
|
||||
enter-to-class="translate-y-0 scale-100"
|
||||
leave-active-class="transition"
|
||||
leave-class="translate-y-0 scale-100"
|
||||
leave-to-class="translate-y-4 scale-95"
|
||||
>
|
||||
<div
|
||||
class="
|
||||
bg-primary
|
||||
shadow-lg
|
||||
text-left
|
||||
w-full
|
||||
transform
|
||||
transition-all
|
||||
inline-block
|
||||
align-bottom
|
||||
overflow-hidden
|
||||
sm:max-w-md sm:align-middle
|
||||
md:rounded-lg
|
||||
"
|
||||
:class="[
|
||||
{ 'mt-24 md:mb-8': placement === 'top' },
|
||||
{ 'p-4': !fullWidth },
|
||||
]"
|
||||
>
|
||||
<div
|
||||
v-if="title"
|
||||
class="flex mb-4 pl-2 items-center justify-between"
|
||||
>
|
||||
<h3 class="heading">{{ title }}</h3>
|
||||
<span class="flex">
|
||||
<slot name="actions"></slot>
|
||||
<ButtonSecondary
|
||||
v-if="dimissible"
|
||||
class="rounded"
|
||||
svg="x"
|
||||
@click.native="close"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="flex flex-col max-h-md overflow-y-auto hide-scrollbar"
|
||||
:class="{ 'py-2': !fullWidth }"
|
||||
>
|
||||
<slot name="body"></slot>
|
||||
</div>
|
||||
<div
|
||||
v-if="hasFooterSlot"
|
||||
class="flex flex-1 mt-4 p-2 items-center justify-between"
|
||||
>
|
||||
<slot name="footer"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from "@nuxtjs/composition-api"
|
||||
import { useKeybindingDisabler } from "~/helpers/keybindings"
|
||||
|
||||
const PORTAL_DOM_ID = "hoppscotch-modal-portal"
|
||||
|
||||
// Why ?
|
||||
const stack = (() => {
|
||||
const stack: number[] = []
|
||||
return {
|
||||
push: stack.push.bind(stack),
|
||||
pop: stack.pop.bind(stack),
|
||||
peek: () => (stack.length === 0 ? undefined : stack[stack.length - 1]),
|
||||
}
|
||||
})()
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
dialog: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
dimissible: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
placement: {
|
||||
type: String,
|
||||
default: "top",
|
||||
},
|
||||
fullWidth: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
const { disableKeybindings, enableKeybindings } = useKeybindingDisabler()
|
||||
|
||||
return {
|
||||
disableKeybindings,
|
||||
enableKeybindings,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
stackId: Math.random(),
|
||||
// when doesn't fire on unmount, we should manually remove the modal from DOM
|
||||
// (for example, when the parent component of this modal gets destroyed)
|
||||
shouldCleanupDomOnUnmount: true,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasFooterSlot(): boolean {
|
||||
return !!this.$slots.footer
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const $portal = this.$getPortal()
|
||||
$portal.appendChild(this.$refs.modal as any)
|
||||
stack.push(this.stackId)
|
||||
document.addEventListener("keydown", this.onKeyDown)
|
||||
this.disableKeybindings()
|
||||
},
|
||||
beforeDestroy() {
|
||||
const $modal = this.$refs.modal
|
||||
if (this.shouldCleanupDomOnUnmount && $modal) {
|
||||
this.$getPortal().removeChild($modal as any)
|
||||
}
|
||||
stack.pop()
|
||||
document.removeEventListener("keydown", this.onKeyDown)
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
this.$emit("close")
|
||||
this.enableKeybindings()
|
||||
},
|
||||
onKeyDown(e: KeyboardEvent) {
|
||||
if (e.key === "Escape" && this.stackId === stack.peek()) {
|
||||
e.preventDefault()
|
||||
this.close()
|
||||
}
|
||||
},
|
||||
onTransitionLeaveStart() {
|
||||
this.close()
|
||||
this.shouldCleanupDomOnUnmount = false
|
||||
},
|
||||
$getPortal() {
|
||||
let $el = document.querySelector("#" + PORTAL_DOM_ID)
|
||||
if ($el) {
|
||||
return $el
|
||||
}
|
||||
$el = document.createElement("DIV")
|
||||
$el.id = PORTAL_DOM_ID
|
||||
document.body.appendChild($el)
|
||||
return $el
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
Reference in New Issue
Block a user