Skip to content

Token Amount

Install this component.

1.2345ETH$3,456.78

Controls

Installation

npx shadcn@latest add https://ui.monark.io/r/token-amount.json

Source

"use client"

import * as React from "react"

import { cn } from "@/lib/utils"

function formatBaseUnits(
  value: bigint | string | number,
  decimals: number,
  maxFractionDigits: number,
  locale?: string
) {
  const raw = typeof value === "bigint" ? value : BigInt(value)
  const negative = raw < 0n
  const abs = negative ? -raw : raw
  const base = 10n ** BigInt(decimals)
  const whole = abs / base
  const frac = abs % base

  const wholeStr = new Intl.NumberFormat(locale).format(whole)
  if (frac === 0n || maxFractionDigits === 0) {
    return `${negative ? "-" : ""}${wholeStr}`
  }
  const fracStr = frac
    .toString()
    .padStart(decimals, "0")
    .slice(0, maxFractionDigits)
    .replace(/0+$/, "")
  return fracStr
    ? `${negative ? "-" : ""}${wholeStr}.${fracStr}`
    : `${negative ? "-" : ""}${wholeStr}`
}

function formatUsd(
  value: number,
  currency: string,
  locale?: string,
  fractionDigits = 2
) {
  return new Intl.NumberFormat(locale, {
    style: "currency",
    currency,
    maximumFractionDigits: fractionDigits,
    minimumFractionDigits: fractionDigits,
  }).format(value)
}

function TokenAmount({
  value,
  decimals = 18,
  symbol,
  fractionDigits = 4,
  locale,
  usdValue,
  usdCurrency = "USD",
  className,
  ...props
}: React.HTMLAttributes<HTMLSpanElement> & {
  value: bigint | string | number
  decimals?: number
  symbol?: string
  fractionDigits?: number
  locale?: string
  usdValue?: number
  usdCurrency?: string
}) {
  const formatted = formatBaseUnits(value, decimals, fractionDigits, locale)

  return (
    <span
      data-slot="token-amount"
      className={cn("inline-flex flex-col leading-tight", className)}
      {...props}
    >
      <span className="inline-flex items-baseline gap-1 font-mono tabular-nums">
        <span>{formatted}</span>
        {symbol && (
          <span className="text-muted-foreground text-[0.85em] font-sans">
            {symbol}
          </span>
        )}
      </span>
      {typeof usdValue === "number" && (
        <span className="text-muted-foreground text-xs tabular-nums">
          {formatUsd(usdValue, usdCurrency, locale)}
        </span>
      )}
    </span>
  )
}

export { TokenAmount, formatBaseUnits, formatUsd }