npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

promise-portal

v1.2.1

Published

use component as a promisd-like function

Downloads

15

Readme

promise-portal

use component as a promisd-like function

Installation

// pnpm
pnpm add promise-portal

// npm
npm install promise-portal

// yarn
yarn add promise-portal

Online Demo

https://codesandbox.io/p/github/tjyuanpeng/promise-portal

Motivation

like element-plus, the modal is a vue component

in development, we want use modal like a function

no show property to control show/hide, gettting result is more explicit

easier to control workflow, and easier to handle life-cycles

so you can use Promise-Portal to save your life-time

before

use as a component, with ref value to control visibility and life-cycles

<script setup lang="ts">
import Comp from './components/name.vue'
const show = ref(false)
const onClick = () => {
  show.value = true
}
const onClosed = () => {
  show.value = false
}
</script>
<template>
  <el-button @click="onClick"> click to open the Dialog </el-button>
  <Comp v-model="show" @closed="onClosed"> a dialog content </Comp>
</template>

after

use as a normal promise-style function, so happy to develop

<script setup lang="ts">
import Comp from './components/name.vue'
const func = definePortal(Comp)
const onClick = async () => {
  const data = await func()
  console.log(data)
}
</script>
<template>
  <el-button @click="onClick"> open the Dialog </el-button>
</template>

Use Case

create promise-portal instance in the entry file

// ./main.ts
import { createApp } from 'vue'
import { createPromisePortal } from 'promise-portal'

const app = createApp(App)
app.use(
  createPromisePortal({
    unmountDelay: 200,
  })
)

use ContextProvider to set context globally

<!-- ./App.vue -->
<script setup lang="ts">
import locale from 'ant-design-vue/es/locale/zh_CN'
import { ContextProvider } from 'promise-portal'
</script>
<template>
  <a-config-provider :locale="locale">
    <ContextProvider>
      <router-view></router-view>
    </ContextProvider>
  </a-config-provider>
</template>

in component, use usePortalContext to use portal context

<!-- ./components/comp.vue -->
<script setup lang="ts">
import { usePortalContext } from 'promise-portal'
export interface Output {
  confirm: boolean
}
export interface Output {
  input: string
}
const props = defineProps<Input>()
const { resolve, show } = usePortalContext<Output>()
const onCancel = () => {
  resolve({ confirm: false })
}
</script>
<template>
  <a-modal v-model:open="show" @cancel="resolve">{{ props.input }}</a-modal>
</template>

define portal in anywhere, then use it like a promise-style function

// ./App.vue
import { definePortal } from 'promise-portal'
import Comp, { Input, Output } from './components/comp.vue'
const [func] = definePortal<Output, Input>(Comp)
const onClick = async () => {
  const result = await func({
    input: 'foo',
  })
  console.log(result)
}

API Reference

createPromisePortal

create promise-portal instance, set to vue instance

const instance = createPromisePortal()
app.use(instance)

you can set default options to instance

const instance = createPromisePortal({
  // set a time gap before portal unmount,
  // in general, it is to wait for animation effect
  unmountDelay: 200,

  // initial value to property show, default value is true
  initialShowValue: true,
})

getActiveInstance

get active promise-portal instance

const instance = getActiveInstance()

setActiveInstance

set active promise-portal instance

setActiveInstance(instance)

ContextProvider

a component to set context globally

<script setup lang="ts">
import locale from 'ant-design-vue/es/locale/zh_CN'
import { ContextProvider } from 'promise-portal'
</script>
<template>
  <a-config-provider :locale="locale">
    <ContextProvider>
      <router-view></router-view>
    </ContextProvider>
  </a-config-provider>
</template>

usePortalContext

a vue composition api, use in portal component to get context of portal

const { resolve } = usePortalContext()

// detail
const {
  resolve, // promise resolve handler
  reject, // promise reject handler
  el, // portal base element, injecting to body element
  vnode, // portal base vue vnode
  setUnmountDelay, // set delay to unmount
  show, // a ref value to use in modal component
} = usePortalContext({
  // set a time gap before portal unmount,
  // in general, it is to wait for animation effect
  unmountDelay: 200,

  // initial value to property show above, default value is true
  initialShowValue: true,
})

you can use typescript generic types to promise fulfilled result

export interface Output {
  confirm: boolean
}
const { resolve } = usePortalContext<Output>()
resolve({
  confirm: true,
})

you can use show to control modal component

before unmount, show.value = false will be setted

use initialShowValue to set inital value, default inital value is true

<script setup lang="ts">
const { resolve, show } = usePortalContext<Output>({ initialShowValue: true })
</script>
<template>
  <a-modal v-model:open="show" @cancel="resolve"></a-modal>
</template>

definePortal

define a portal, return a portal function

import Comp from './component.vue'
const portalFunc = definePortal(Comp)
portalFunc()

you can define generic types to check input object and output object

// component.vue
export interface Input {
  firstName: string
  lastName: string
}

export interface Output {
  fullName: string
  confirm: boolean
}

const props = defineProps<Input>()
const { resolve } = usePortalContext<Output>()

// App.vue
import Comp, { Input, Output } from './component.vue'
const portal = definePortal<Output, Input>(Comp)
const output = await portal({
  firstName: 'joe',
  lastName: 'watson',
})

define a portal with empty parameter

// component.vue
export interface Output {
  fullName: string
  confirm: boolean
}

const { resolve } = usePortalContext<Output>()

// App.vue
import Comp, { Output } from './component.vue'
const portal = definePortal<Output, void>(Comp)
const output = await portal() // only allow empty parameter

you can set a options to definePortal

definePortal(Comp, {
  // set a time gap before portal unmount,
  unmountDelay: 200,

  // initial value to property show
  initialShowValue: true,

  // set promise-portal instance explicitly to render this portal
  instance: promisePortalInstance,
})

detectPromisePortalInstance

detect whether the instance has been properly destroyed

// main.ts
if (import.meta.env.DEV) {
  detectPromisePortalInstance()
}

the return value is a function to stop detecting

const stopHandler = detectPromisePortalInstance()
stopHandler() // stop detecting

You can pass in other values to customize it.

detectPromisePortalInstance({
  text: 'Detected unreleased promise-portal instance',
  style: ' /styles you like/ ',
})

Relative Resourece