Template as Promise in Vue. Useful for constructing custom Dialogs, Modals, Toasts, etc.
<script setup lang="ts">
import { useTemplatePromise } from 'vue-template-promise'
const TemplatePromise = useTemplatePromise<'ok' | 'cancel'>()
async function open() {
console.log('Before')
const result = await TemplatePromise.start()
console.log('After', result)
}
</script>
<template>
<button @click="open">Open</button>
<TemplatePromise v-slot="{ resolve }">
<dialog open>
<button @click="resolve('cancel')">Cancel</button>
<button @click="resolve('ok')">OK</button>
</dialog>
</TemplatePromise>
</template>- 👨💻 Programmatic - call your UI as a promise
- 🧩 Template - use Vue template to render, not a new DSL
- 🦾 TypeScript - full type safety via generic type
- ⚪️ Renderless - you take full control of the UI
npm i vue-template-promiseuseTemplatePromise returns a Vue Component that you can directly use in your template with <script setup>
import { useTemplatePromise } from 'vue-template-promise'
const TemplatePromise = useTemplatePromise()
const MyPromise = useTemplatePromise<boolean>() // with generic typeIn template, use v-slot to access the promise and resolve functions.
<template>
<TemplatePromise v-slot="{ promise, resolve, reject, args }">
<!-- you can have anything -->
<button @click="resolve('ok')">OK</button>
</TemplatePromise>
</template>Rhe slot will not be rendered initially (similar to v-if="false"), until you call the start method from the component.
const result = await TemplatePromise.start()Once resolve or reject is called in the template, the promise will be resolved or rejected, returning the value you passed in. Once resolved, the slot will be removed automatically.
You can pass arguments to the start with arguments.
import { useTemplatePromise } from 'vue-template-promise'
const TemplatePromise = useTemplatePromise<boolean, [string, number]>()const result = await TemplatePromise.start('hello', 123) // PrAnd in the template slot, you can access the arguments via args property.
<template>
<TemplatePromise v-slot="{ args, resolve }">
<div>{{ args[0] }}</div> <!-- hello -->
<div>{{ args[1] }}</div> <!-- 123 -->
<button @click="resolve(true)">OK</button>
</TemplatePromise>
</template>Thanks to @johnsoncodehk for making Volar and the help to make it type safe.
Probably. I am having this as a separate package to test how this idea works. If it ends up working well, we will consider moving it into VueUse directly.
MIT License © 2022 Anthony Fu