Skip to content

daguanren21/vue-template-promise

 
 

Repository files navigation

vue-template-promise

NPM version

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>

Features

  • 👨‍💻 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

Install

npm i vue-template-promise

Usage

useTemplatePromise 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 type

In 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>

The 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.

Passing Arguments

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) // Pr

And 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

Thanks to @johnsoncodehk for making Volar and the help to make it type safe.

FAQ

VueUse?

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.

Sponsors

License

MIT License © 2022 Anthony Fu

About

Template as Promise in Vue

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • TypeScript 59.3%
  • Vue 29.1%
  • HTML 11.6%