unoverlay-vue

image

Oh, this image is from vuejs-overlay, but he’s really cool and I’m lazy so I stole it (sorry)

中文 | English

A universal overlay (popup) Vue2/Vue3 utils

it can achieve:

  • Make Message or Dialog similar to element-plus / naiveui / vuetifyjs / vant
  • Supports two calling methods at the same time (template or js/ts)
  • Integrate and customize functions using existing component libraries (such as element-plus)

⚙️ Install

pnpm add unoverlay-vue
# Or Yarn
yarn add unoverlay-vue

Global installation makes all overlay inherit the app context

// main.js
import { createApp } from 'vue'
import unoverlay from 'unoverlay-vue'
import App from './App.vue'

const app = createApp(App)
app.use(unoverlay)
app.mount('#app')

? Usage(Basic)

define overlay component

<!-- overlay.vue -->
<script setup>
import { defineEmits, defineProps } from 'vue'
import { useOverlayMeta } from 'unoverlay-vue'
const props = defineProps({
  title: String,
  // If you want to use it as a component in template,
  // you need to define visible in props
  visible: Boolean
})

// Define the events used in the component(optional)
// This allows you to use hints in components
defineEmits(['cancel', 'confirm'])

// Get Overlay information from useOverlayMeta
const { visible, confirm, cancel } = useOverlayMeta({
  // Animation duration to avoid premature destruction of components
  // Only use component in template and no need to define
  animation: 1000
})
</script>

<template>
  <div v-if="visible" @click="confirm(`${title}:confirmed`)">
    {{ title }}
  </div>
</template>

Create a callback, call it in Javascript/Typescript

import { transformOverlay } from 'unoverlay-vue'
import OverlayComponent from './overlay.vue'

// Convert to imperative overlay
const callback = transformOverlay(OverlayComponent)
// Call the component and get the value of confirm
const value = await callback({ title: 'callbackOverlay' })
// value === "callbackOverlay:confirmed"

or use in setup

import { useOverlayCall } from 'unoverlay-vue'
import OverlayComponent from './overlay.vue'

const value = await useOverlayCall(OverlayComponent, {
  props: { title: 'useOverlay' }
})
// value === "useOverlay:confirmed"

or use in component

<!-- overlay.vue -->
<script setup>
import OverlayComponent from './overlay.vue'
const visible = ref(false)

const confirm = () => {
  // ...
}
const cancel = () => {
  // ...
}
</script>

<template>
  <overlay-component
    v-model:visible="visible"
    @confirm="confirm"
    @cancel="cancel"
  />
</template>

You can use your imagination boldly!

?️ Customized overlay

Take [email protected](dialog) as an example (of course, you can use other component libraries)

<!-- overlay.vue -->
<script setup>
import { defineEmits, defineProps } from 'vue'
import { useOverlayMeta } from 'unoverlay-vue'
const props = defineProps({
  title: String,
})

const { visible, confirm, cancel } = useOverlayMeta({
  animation: 1000
})
</script>

<template>
  <el-dialog v-model:visible="visible" :title="title" @close="cancel()">
    <!-- your content -->
    <button @click="confirm(`${title}:confirmed`)" />
  </el-dialog>
</template>

import { transformOverlay } from 'unoverlay-vue'
import OverlayComponent from './overlay.vue'

const callback = transformOverlay(OverlayComponent)
const value = await callback({ title: 'myElDialog' })
// value === "myElDialog:confirmed"

⌨️ Typescript

If you want the component to have the correct type declaration when called in the callback,

You need to extract the props into a separate file, a simple case:

export interface OverlayParams {
  title?: string
}
export type OverlayResolved = string

Reference props in .vue

<!-- index.vue -->
<script setup>
import { defineEmits, defineProps } from 'vue'
import { useOverlayMeta } from 'unoverlay-vue'
import type { OverlayParams, OverlayResolved } from './props'
const props = defineProps<OverlayParams>()
const { visible, confirm, cancel } = useOverlayMeta<OverlayResolved>({
  animation: 1000
})
</script>

<template>
  <div v-if="visible" @click="confirm('string')">
    {{ title }}
  </div>
</template>

Handle in another separate .js

import { transformOverlay } from 'unoverlay-vue'
import OverlayComponent from './overlay.vue'
import type { OverlayParams, OverlayResolved } from './define.ts'

// Convert to imperative overlay
const callback = transformOverlay<OverlayParams, OverlayResolved>(OverlayComponent)

If you have requirements for vue’s props runtime validation, you can define it like this:

import type { ExtractInferTypes } from 'vue'
// define.ts
export const overlayProps = {
  title: String
}
export type OverlayParams = ExtractInferTypes<typeof overlayProps>
export type OverlayResolved = string

<!-- index.vue -->
<script setup>
import { defineEmits, defineProps } from 'vue'
import { useOverlayMeta } from 'unoverlay-vue'
import type { OverlayResolved } from './props'
import { overlayProps } from './props'
const props = defineProps(overlayProps)
const { visible, confirm, cancel } = useOverlayMeta<OverlayResolved>({
  animation: 1000
})
</script>

<template>
  <div v-if="visible" @click="confirm('string')">
    {{ title }}
  </div>
</template>

App context inheritance

If you globally registered unoverlay-vue, it will automatically inherit your app context.

import { getCurrentInstance } from 'vue'
import Component from './overlay.vue'

// in your setup method
const { appContext } = getCurrentInstance()!
useOverlayCall(Component, {
  props: {},
  appContext
})

API descriptions

Type Declarations

interface MountOverlayOptions {
  /** The dom node that hangs when rendering */
  root?: HTMLElement
  /** Used to inherit the current application context */
  appContext?: AppContext
}
interface UseOverlayMetaOptions {
  /** Animation duration to avoid premature destruction of components */
  animation?: number
  /** whether to set visible to true immediately */
  immediate?: boolean
}

transformOverlay

Used to convert the overlay component to a callable callback

const caller = transformOverlay(Component)
caller({/* props */}, {/* MountOverlayOptions */})

useOverlayMeta

Obtaining overlay information in the overlay component component is the core function of overlay-vue

useOverlayMeta({/* UseOverlayMetaOptions */})

useOverlayCall

Call overlay component directly

useOverlayCall(Component, { props: {/* props */}, /*  MountOverlayOptions */ })

return types

interface OverlayMeta {
  /** Call resolve, change visible, and destroy when animation ends */
  cancel: Function
  /** Call reject, change visible, and destroy when animation ends */
  confirm: Function
  /** Destroy the current instance (immediately, and the call fails), only cancel is called in the template */
  vanish: Function
  /** Control overlay display and hide */
  visible: Ref<boolean>
  /** rendered vnode */
  vnode?: VNode
}

License

MIT Copyright (c) 2019-PRESENT

GitHub

View Github