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

@tamatashwin/boxcutter

v0.0.19

Published

Boxcutter is a powerful web development tool designed for snipping PDF documents with ease. It integrates seamlessly with React and Tailwind CSS to create highly responsive web applications.

Readme

Boxcutter

Boxcutter is a powerful web development tool designed for snipping PDF documents with ease. It integrates seamlessly with React and Tailwind CSS to create highly responsive web applications.

Key Features

  • PDF Handling: Use Boxcutter to display and interact with PDFs within your application. The tool leverages pdfjs-dist to facilitate efficient PDF rendering and manipulation.
  • React Components: Easily integrate with React using the provided Boxcutter component.
  • Tailwind CSS: Styled by default with Tailwind CSS for modern and responsive design.

Installation

To install Boxcutter, ensure you have Node.js installed, then run the following command to add it to your project:

npm install boxcutter

Essential Scripts

  • Development: Start a development server using Vite with npm run dev.
  • Production Build: Compile your application for production with npm run build.
  • Preview: Preview a production build with npm run preview.
  • Lint: Run ESLint on the project with npm run lint.

Usage Example

Here's a basic example of how you might use the Boxcutter component in a React application:

import React, { useState, useEffect } from "react";
import { BoxCutter } from "@tamatashwin/boxcutter";
import "@tamatashwin/boxcutter/styles.css"

function App() {
  let [pdf, setPdf] = useState(null);
  let [snippets, setSnippets] = useState([]);
  let [toc, setTOC] = useState([]);

  useEffect(() => {
    let loadPdf = async () => {
      // Convert the Response to bytes; browsers expose arrayBuffer()
      const data = await fetch("/example.pdf").then((r) => r.arrayBuffer());
      setPdf(data);
    };

    loadPdf();
  }, []);

  return (
    <div className="w-full h-full flex flex-col gap-8 overflow-auto">
      <BoxCutter
        pdf={pdf}
        snippets={snippets}
        onSnippetsChange={setSnippets}
        toc={toc}
        onTOCChange={setTOC}
        onReady={({ totalPages, currentPage, scale, pageSize, jumpToPage }) => {
          // Called once the first page is rendered and interactions are ready
          console.log("Boxcutter ready:", {
            totalPages,
            currentPage,
            scale,
            pageSize,
          });

          // Example: jump to page 3 on ready
          if (totalPages >= 3) {
            jumpToPage(3);
          }
        }}
        showSnippetsCollection
      />
    </div>
  );
}

export default App;

Next.js (Client Components)

Use the client-only subpath to avoid SSR DOM errors in Next.js App Router.

  • Import components from @tamatashwin/boxcutter/client.
  • Import styles from @tamatashwin/boxcutter/styles.css.
  • Transpile the package in next.config.js with transpilePackages.

Example:

// app/page.tsx (a Server Component)
import "@tamatashwin/boxcutter/styles.css";

export default function Page() {
  return (
    <div>
      {/* Use a Client Component wrapper for BoxCutter */}
      <ClientDemo />
    </div>
  );
}

// app/client-demo.tsx
"use client";
import { useState } from "react";
import { BoxCutter } from "@tamatashwin/boxcutter/client";

export function ClientDemo() {
  const [pdf, setPdf] = useState<ArrayBuffer | null>(null);
  // ...fetch and set the PDF bytes
  return <BoxCutter pdf={pdf} snippets={[]} onSnippetsChange={()=>{}} toc={[]} onTOCChange={()=>{}} />;
}

next.config.js:

// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  transpilePackages: ["@tamatashwin/boxcutter"],
};
module.exports = nextConfig;

If you accidentally import @tamatashwin/boxcutter in a Server Component, you’ll see a helpful error directing you to use the /client subpath instead.

Configure the pdf.js worker (Next.js)

Next.js’ server build can’t resolve relative asset imports from libraries. To avoid worker resolution errors like:

Module not found: Can't resolve './assets/pdf.worker.min-*.js'

configure the pdf.js worker on the client by pointing to a public URL in your app:

  1. Copy the worker to public (once):
cp node_modules/pdfjs-dist/build/pdf.worker.min.mjs public/
  1. Initialize the worker in a client entry before rendering BoxCutter:
// app/providers.tsx (client component), or your top-level client page/component
"use client";
import { useEffect } from "react";
import { initPdfjsWorker } from "@tamatashwin/boxcutter/client";

export function Providers({ children }: { children: React.ReactNode }) {
  useEffect(() => {
    // Tell pdf.js where to load the worker from (public URL)
    initPdfjsWorker({ url: "/pdf.worker.min.mjs" });
  }, []);
  return <>{children}</>;
}

Alternatively, you may set it directly via pdf.js APIs:

import * as pdfjsLib from "pdfjs-dist";
pdfjsLib.GlobalWorkerOptions.workerSrc = "/pdf.worker.min.mjs";

This avoids bundling the worker file from the package and prevents Next.js from trying to resolve a relative asset at build time.

Dark Mode

This package uses semantic Tailwind classes backed by CSS variables. Theme tokens are defined under :root and .dark in @tamatashwin/boxcutter/styles.css.

  • Background/foreground: bg-background, text-foreground, border-border.
  • Accents and subtle: bg-accent, text-accent-foreground, bg-muted, text-muted-foreground.
  • Surfaces: bg-card/text-card-foreground, bg-popover/text-popover-foreground.

To toggle dark mode, add or remove the dark class on document.documentElement and persist to localStorage:

// Simple theme toggle
function toggleTheme() {
  const root = document.documentElement;
  const next = root.classList.toggle("dark") ? "dark" : "light";
  localStorage.setItem("theme", next);
}

// Initialize on load
if (typeof window !== "undefined") {
  const saved = localStorage.getItem("theme");
  if (saved === "dark") document.documentElement.classList.add("dark");
}

When styling your app around the component, avoid hardcoded grays (e.g. text-gray-500). Use the semantic classes listed above for consistent theming.

If you use Next.js (App Router), import the client entry so the component renders only on the client and avoids SSR-only errors like "DOMMatrix is not defined":

// app/(any)/page.tsx or a Client Component in your tree
"use client";

import { useState } from "react";
import { BoxCutter } from "@tamatashwin/boxcutter/client";
import "@tamatashwin/boxcutter/styles.css";

export default function Page() {
  const [snippets, setSnippets] = useState([]);
  const [toc, setToc] = useState([]);

  return (
    <BoxCutter
      pdf={null}
      snippets={snippets}
      onSnippetsChange={setSnippets}
      toc={toc}
      onTOCChange={setToc}
    />
  );
}

Notes:

  • Import from @tamatashwin/boxcutter/client (which contains a "use client" directive) to ensure client-side rendering.
  • Do not import @tamatashwin/boxcutter directly from a Server Component; that can cause SSR to evaluate DOM APIs and produce errors like DOMMatrix is not defined.
  • Alternative: you can also dynamically import with SSR disabled if needed:
import dynamic from "next/dynamic";

const BoxCutter = dynamic(
  () => import("@tamatashwin/boxcutter/client").then((m) => m.BoxCutter),
  { ssr: false }
);

License

Boxcutter is licensed under the MIT License. See the LICENSE file for more details.

Contributing

Contributions are welcome! Please see the issues page for guidelines on how to contribute to this project.

Support

For any issues or feature requests, please visit our GitHub repository.