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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@pcnv/txs-react

v0.1.1

Published

Easy way to manage user transaction status on your dapp

Readme

aaaaaa

Concave txs

A plug and play, customizable way to manage user transaction status on your dapp

  • ✅ Out-of-the-box status notifications on top of @zag-js/toast (totally optional)
  • 🎉 Easily customizable, or create your own with simple react hooks
  • 🔥 Using ethers and wagmi
  • ✨ Framework agnostic core at @pcnv/txs-core
  • 📦 Tiny tiny, less than 3 kB gzipped

Install

pnpm add @pcnv/txs-react viem wagmi @zag-js/react @zag-js/toast

# zag is not required if you want to create your own notification components
pnpm add @pcnv/txs-react viem wagmi

Usage

Check the examples folder for a complete implementation

import {
  createTransactionsStore,
  ToastsViewport,
  TransactionsStoreProvider,
  TransactionStatusToastProps,
} from '@pcnv/txs-react'

// import a builtin toast component or create your own
import { ClassicToast } from '@pcnv/txs-react/toasts/ClassicToast'
import '@pcnv/txs-react/toasts/ClassicToast/styles.css'

const transactionsStore = createTransactionsStore()

...

// Add the provider to your app
// make sure its a children of WagmiConfig
<WagmiConfig client={...}>
  <TransactionsStoreProvider store={transactionsStore}>
    <ToastsViewport
      TransactionStatusComponent={ClassicToast}
      placement="top-end"
     />
    ...

And in your component

  import { usePrepareContractWrite, useContractWrite } from 'wagmi'
  import { useAddRecentTransaction } from '@pcnv/txs-react'

  ...

  const addTransaction = useAddRecentTransaction()
  const { writeContract } = useWriteContract()

  ...

  writeContract(
    {
      address: ...,
      abi: ...,
      functionName: ...,
    },
    {
      onSuccess: (hash) => {
        addTransaction({
          hash,
          meta: {
            // more on meta below
            description: `Wrapping ${amount} ETH`,
          },
        })
      },
    },
  )

Hooks

useRecentTransactions

returns all transactions stored for the connected user in the connected chain

const recentTransactions = useRecentTransactions()

It also accepts a selector

// this component will only rerender when a new transaction is set as completed
const completedTransactions = useRecentTransactions((txs) =>
  txs.filter(({ status }) => status === 'completed'),
)

useAddRecentTransaction

Adds a transaction to be tracked, to the connected user/chain

const addTransaction = useAddRecentTransaction()
...
addTransaction({
  hash: '0x your transaciton hash',
  meta: {
    // metadata about the transaciton, description, type etc, more on the meta field below
  }
})

useRemoveRecentTransaction

Removes a connected user transaction by hash

const removeTransaction = useRemoveRecentTransaction()
...
removeTransaction(hash)

useClearRecentTransactions

Clears all transactions stored on the current connected user/chain

const clearTransactions = useClearRecentTransactions()
...
clearTransactions()

useTransactionsStoreEvent

Listens for an event from the store to execute a callback

useTransactionsStoreEvent(
  'added',
  useCallback((tx) => {
    // a new transaction was added, do something
  }, []),
)

Supported events are added, updated, removed, cleared, mounted

Useful if you are building your own notification solution

Maybe you want to display a confirmation dialog on transaction confimed. that could look something like this

useTransactionsStoreEvent(
  'updated',
  useCallback(
    (tx) => {
      if (tx.status === 'confirmed') displayTxConfirmedDialog(tx)
    },
    [displayTxConfirmedDialog],
  ),
)

Built in Components

Both detect prefers-color-scheme and style light/dark accordingly, you can force by passing a colorScheme prop, default is system

import { EmojiToast } from '@pcnv/txs-react/toasts/EmojiToast'
import '@pcnv/txs-react/toasts/EmojiToast/styles.css'

EmojiToast

import { ClassicToast } from '@pcnv/txs-react/toasts/ClassicToast'
import '@pcnv/txs-react/toasts/ClassicToast/styles.css'

ClassicToast

Some Defaults

The following can be configured thru props on ToastsViewport

  • showPendingOnReopen: should pop up the pending notification when the user closes and opens the app again while still pending? defaults to true
  • staleTime: if the user closed the app without a status update, for how long it's still relevant to display the update on reopen
  • stuckTime: transactions are considered stuck after 30min without a confirmation/rejection

Meta field

The meta field accepts anything serializable really, for example, instead of a single description you may want to have custom description for pending, completed and failed

Here's an example of how that could work

import {
  StoredTransaction,
  ToastsViewport,
  TransactionStatusToastProps,
  TypedUseAddRecentTransaction,
  TypedUseRecentTransactions,
} from '@pcnv/txs-react'

// add your custom fields to the global namespace Txs.Meta
declare global {
  namespace Txs {
    export interface Meta {
      pending: string
      success: string
      reverted: string
    }
  }
}

const MyCustomNotification = (props: TransactionStatusToastProps<TransactionMeta>) => {
  const tx = props.transaction
  return <EmojiToast {...props} description={tx.meta[tx.status]} />
}

...

<ToastsViewport TransactionStatusComponent={MyCustomNotification} />

...

// and in you component ts will enforce this usage
const addTransaction = useAddRecentTransaction()
...
addTransaction({
  hash: tx.hash,
  meta: {
    pending: '...',
    completed: '...',
    failed: '...',
   },
})

Note Beware that everything included as meta will be saved to LocalStorage

Another example

This time only some properties are saved to localstorage based on the transaction type

type TransactionType = { type: 'approve'; amount: string; token: string } // | { ...more types }

declare global {
  namespace Txs {
    export interface Meta extends TransactionType {}
  }
}

type TransactionMetaToStatusLabel = {
  [Meta in TransactionType as Meta['type']]: (
    meta: Omit<Meta, 'type'>,
  ) => Record<StoredTransaction['status'], string>
}

const typeToStatusDescription = {
  approve: ({ amount, token }) => ({
    pending: `Approving ${amount} ${token}`,
    confirmed: `Successfully approved ${amount} ${token}`,
    failed: `Failed to approve ${amount} ${token}`,
  }),
} satisfies TransactionMetaToStatusLabel

const MyCustomNotification = (props: TransactionStatusToastProps<TransactionType>) => {
  const { meta, status } = props.transaction
  const description = typeToStatusDescription[meta.type](meta)[status]
  return <EmojiToast {...props} description={description} />
}

...

const addTransaction = useAddRecentTransaction()
addTransaction({
  hash: tx.hash,
  meta: {
    type: 'approve', // typescript can auto suggest all available types and their required properties
    amount: 1,
    token: 'CNV'
   },
})

Enter & Exit Animations

Check Zagjs Docs

More

Check how's it being used it the concave repo