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

toasterhea

v1.0.4

Published

Promise-driven toast poppin' library.

Downloads

378

Readme

toasterhea 🍞

Promise-driven toast-poppin' library.

Installation

npm i toasterhea

Peer dependencies

This package relies on the following dependencies:

eventemitter3 >= 4
lodash >= 0.1.0
react >= 16.8 <= 18
react-dom >= 16.8 <= 18

Make sure you have them installed, too!

Key elements

[Inline]Container(props: { id: string } & …): JSX.Element

It's a React component responsible for rendering toastables.

import { Container, InlineContainer } from 'toasterhea'

function App() {
  return (
    <>
      {/* …codecodecode… */}
      <Container id="FOO" />
      <InlineContainer id="BAR" />
      {/* …codecodecode… */}
    </>
  )
}

Regular containers are rendered at the end of document.body through React's portals. If you'd like to render yours in a specific place use InlineContainer instead.

It may be worth mentioning that you can render multiple containers with the same id. As a result you'll get multiple instances of your toastables. I'm yet to find a good usecase for that, buy yeah, it's possible, even if just for fun.

useDiscardableEffect(fn?: (discard: () => void | Promise<void>) => void): void

It's a React hook responsible for letting containers know when exacly a toastable can be discarded. Everything you turn into a toast will have to utilize this hook.

Note that although the use of this hook is necessary, the callback is optional. If the callback isn't defined, the library will discard a toastable immediately after its promise is settled.

import { useDiscardableEffect } from 'toasterhea'

interface Props {
  onResolve?: () => void
}

function FooToThePowerOfBar({ onResolve }: Props) {
  useDiscardableEffect((discard) => {
    // Discard the component after 10s.
    setTimeout(() => void discard(), 10000)
  })

  return (
    <button
      type="button"
      onClick={() => {
        /**
         * Calling `onResolve` resolves the underlying promise. The component will remain
         * mounted for another 10s (see above). UIs can be disabled here, and/or
         * animations triggered.
         */
        onResolve?.()
      }}
    >
      Let's go!
    </button>
  )
}

toaster<T>(component: T, containerId: string): Toaster<T>

It turns components into toastables and gives you two methods to control their behaviour:

  1. async pop(props?: ComponentProps<T>) – mounts or rerenders the component using given props, and
  2. discard() which rejects the internal promise.
import { toaster, Toaster } from 'toasterhea'

function MasterOfAllFoos() {
  const fooRef = useRef(toaster(FooToThePowerOfBar, "FOO"))

  return (
    <>
      <button
        type="button"
        onClick={async () => {
          try {
            await fooRef.current.pop()
          } catch (e) {
            /**
             * `FooToThePowerOfBar` does not reject explicitly. There's no UI for it. Few
             * things can cause a rejection, still, though. See `Reason` section for details.
             */
            console.warn('…and then this happened!', e)
          }
        }}
      >
        Let's foo that bar!
      </button>
      <button
        type="button"
        onClick={() => void fooRef.current.discard()}
      >
        Nah
      </button>
    </>
  )
}

Reason

Some rejection scenarios are predefined and either are used internally or can be used from the outside to control the flow.

Reason.Update

Happens when the user calls pop on a toast that's already "popped" (got displayed). Any piece of code waiting for the previous call to pop will receive a rejection.

Reason.Unmount

Happens when the Container itself gets unmounted. The library rejects all outstanding promises and removes their associated DOM elements.

Reason.Host

Happens when Toaster<T>.discard() is called.

An example of how you can utilize them is shown below.

import { Reason } from 'toasterhea'

try {
  // pop!
} catch (e) {
  switch (e) {
    case Reason.Update:
      console.info('Your toastable got updated!')
      break
    case Reason.Unmount:
      console.info('Your toastable got unmounted along with the entire `Container`.')
      break
    case Reason.Host:
      console.info('Your toastable got interrupted from the outside (someone called its `discard`).')
      break
    default:
      throw e
  }
}

And, naturally, you can define and use your own rejection reasons.

Examples

Toast

Alert

Modal dialog