{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "ordfs-image",
  "title": "ORDFS Image",
  "author": "Satchmo",
  "description": "Image element for on-chain ORDFS content that routes through the host image optimizer. Ships Vercel, Cloudflare, and ORDFS-thumbnail loaders, and renders the original unchanged when none is configured.",
  "dependencies": [],
  "registryDependencies": [
    "https://registry.bigblocks.dev/r/bigblocks-provider.json"
  ],
  "files": [
    {
      "path": "registry/new-york/blocks/ordfs-image/index.tsx",
      "content": "\"use client\"\n\nimport { useContext } from \"react\"\nimport { BigBlocksContext } from \"@/registry/new-york/blocks/bigblocks-provider\"\nimport {\n  DEFAULT_IMAGE_QUALITY,\n  DEFAULT_IMAGE_WIDTHS,\n  type OrdfsImageLoader,\n} from \"./loaders\"\n\n// ---------------------------------------------------------------------------\n// Re-exports\n// ---------------------------------------------------------------------------\n\nexport type { OrdfsImageLoader, OrdfsImageLoaderArgs } from \"./loaders\"\nexport {\n  createCloudflareImageLoader,\n  createOrdfsImageLoader,\n  DEFAULT_IMAGE_QUALITY,\n  DEFAULT_IMAGE_WIDTHS,\n  vercelImageLoader,\n} from \"./loaders\"\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface OrdfsImageProps\n  extends Omit<\n    React.ImgHTMLAttributes<HTMLImageElement>,\n    \"src\" | \"srcSet\" | \"loading\"\n  > {\n  /** Absolute URL of the original ORDFS content */\n  src: string\n  /** Alternative text. Required — inscriptions are content, not decoration. */\n  alt: string\n  /** Responsive size hint, e.g. \"(min-width: 1280px) 25vw, 50vw\" */\n  sizes?: string\n  /** Quality hint passed to the loader, 1-100 */\n  quality?: number\n  /** Widths to generate in `srcSet` */\n  widths?: number[]\n  /** Native lazy-loading behaviour */\n  loading?: \"lazy\" | \"eager\"\n  /** Loader override for this image, taking precedence over the provider */\n  loader?: OrdfsImageLoader\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\n/**\n * An `<img>` for on-chain ORDFS content that routes through whatever image\n * optimizer the host provides.\n *\n * Without a loader configured this renders the original inscription unchanged,\n * so it is safe to use everywhere. Configure `imageLoader` on\n * `BigBlocksProvider` to opt an entire app into optimization at once.\n *\n * @example\n * ```tsx\n * <BigBlocksProvider imageLoader={vercelImageLoader}>\n *   <OrdfsImage\n *     src=\"https://ordfs.network/content/abc_0\"\n *     alt=\"Ordinal #1\"\n *     sizes=\"(min-width: 768px) 25vw, 50vw\"\n *   />\n * </BigBlocksProvider>\n * ```\n */\nexport function OrdfsImage({\n  src,\n  alt,\n  sizes,\n  quality = DEFAULT_IMAGE_QUALITY,\n  widths = DEFAULT_IMAGE_WIDTHS,\n  loading = \"lazy\",\n  loader,\n  onLoad,\n  ...imgProps\n}: OrdfsImageProps) {\n  // Read the context directly rather than through useBigBlocks(), which throws\n  // outside a provider — these blocks are usable standalone.\n  const context = useContext(BigBlocksContext)\n  const resolved = loader ?? context?.imageLoader\n\n  // With no optimizer configured every srcSet entry would be the same URL, so\n  // emit a bare src instead of misleading the browser into picking between them.\n  const srcSet = resolved\n    ? widths.map((w) => `${resolved({ src, width: w, quality })} ${w}w`).join(\", \")\n    : undefined\n\n  const displaySrc = resolved\n    ? resolved({ src, width: widths[widths.length - 1] ?? 1920, quality })\n    : src\n\n  return (\n    <img\n      // A cached image can finish loading before React attaches onLoad, which\n      // would strand any skeleton the caller is showing. Catch that on mount.\n      ref={(node) => {\n        if (node?.complete && node.naturalWidth > 0) {\n          onLoad?.({ currentTarget: node } as React.SyntheticEvent<HTMLImageElement>)\n        }\n      }}\n      src={displaySrc}\n      srcSet={srcSet}\n      sizes={sizes}\n      alt={alt}\n      loading={loading}\n      decoding=\"async\"\n      onLoad={onLoad}\n      {...imgProps}\n    />\n  )\n}\n",
      "type": "registry:block",
      "target": "~/components/blocks/ordfs-image/index.tsx"
    },
    {
      "path": "registry/new-york/blocks/ordfs-image/loaders.ts",
      "content": "export interface OrdfsImageLoaderArgs {\n  /** Absolute URL of the original ORDFS content */\n  src: string\n  /** Target width in pixels */\n  width: number\n  /** Quality hint, 1-100 */\n  quality: number\n}\n\n/**\n * Rewrites an ORDFS content URL to an optimized one.\n *\n * ORDFS serves inscriptions at their original size — a single NFT is routinely\n * several megabytes — so a grid of them is the dominant cost in any wallet or\n * marketplace UI. A loader points that URL at whatever optimizer the host\n * already provides, which keeps these blocks plain React with no\n * framework-specific imports that would break a Vite or Astro consumer.\n */\nexport type OrdfsImageLoader = (args: OrdfsImageLoaderArgs) => string\n\n/**\n * Widths used to build `srcSet`. Mirrors the common device-size ladder so a\n * host optimizer that caches per width sees a small, predictable key space.\n */\nexport const DEFAULT_IMAGE_WIDTHS = [64, 128, 256, 384, 640, 828, 1200, 1920]\n\n/** Default quality passed to loaders when a caller does not specify one */\nexport const DEFAULT_IMAGE_QUALITY = 75\n\n/**\n * Routes through Vercel's image optimizer.\n *\n * This targets the `/_next/image` endpoint directly rather than importing\n * `next/image`, so it works from any framework deployed on Vercel and keeps\n * the blocks installable in Vite, Remix, and Astro projects.\n *\n * The ORDFS host must be allowlisted in `next.config`:\n *\n * ```js\n * images: {\n *   remotePatterns: [{ protocol: \"https\", hostname: \"ordfs.network\" }],\n * }\n * ```\n *\n * @example\n * ```tsx\n * <BigBlocksProvider imageLoader={vercelImageLoader}>\n * ```\n */\nexport const vercelImageLoader: OrdfsImageLoader = ({ src, width, quality }) =>\n  `/_next/image?url=${encodeURIComponent(src)}&w=${width}&q=${quality}`\n\n/**\n * Routes through Cloudflare Image Resizing.\n *\n * Requires Image Resizing enabled on the zone serving your site.\n *\n * @param zone - Origin to prefix the transform path with. Defaults to a\n *   same-origin path, which is correct when your site is on the same zone.\n */\nexport function createCloudflareImageLoader(zone = \"\"): OrdfsImageLoader {\n  return ({ src, width, quality }) =>\n    `${zone}/cdn-cgi/image/width=${width},quality=${quality},format=auto/${src}`\n}\n\n/**\n * Routes through an ORDFS gateway's `/image` transform endpoint.\n *\n * Preferred when available: one shared cache serves every consumer, so no\n * individual app pays per-image transformation costs, and the gateway\n * negotiates AVIF or WebP from the browser's own Accept header.\n *\n * @param base - Gateway origin, e.g. `https://ordfs.network`\n * @param options - Optional fit mode and gravity, matching the gateway's\n *   Cloudinary-style vocabulary. Defaults to `limit`, which fits within the\n *   width without upscaling.\n */\nexport function createOrdfsImageLoader(\n  base: string,\n  options: { fit?: \"limit\" | \"fit\" | \"fill\" | \"pad\" | \"scale\"; gravity?: string } = {}\n): OrdfsImageLoader {\n  const origin = base.replace(/\\/$/, \"\")\n  return ({ src, width, quality }) => {\n    const pointer = src.split(\"/content/\").pop() ?? src.split(\"/\").pop() ?? src\n    const params = new URLSearchParams({ w: String(width), q: String(quality) })\n    if (options.fit) params.set(\"fit\", options.fit)\n    if (options.gravity) params.set(\"g\", options.gravity)\n    return `${origin}/image/${pointer}?${params}`\n  }\n}\n",
      "type": "registry:component",
      "target": "~/components/blocks/ordfs-image/loaders.ts"
    }
  ],
  "categories": [
    "infrastructure"
  ],
  "type": "registry:block"
}