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

@cinesend/ui-kit

v0.2.0

Published

Shared React components, design tokens, and CSS for CineSend apps.

Readme

CineSend UI kit

Shared React components, tokens, and CSS for CineSend apps. This is not an app: no product screens, no API calls, no app logic.

Published to npm as @cinesend/ui-kit. The GitHub repo is BitCine/cinesend-ui-kit. There is no BitCine/ui-kit repo.

Install

npm install @cinesend/ui-kit
import { Button, TextField } from "@cinesend/ui-kit";
import "@cinesend/ui-kit/styles.css";

The stylesheet is a separate entry point and must be imported once, near your app root. It is not bundled into the JS entry.

Local development (clone this repo next to the app):

"@cinesend/ui-kit": "file:../cinesend-ui-kit"

Installing from a file: path serves the built dist/, so run npm run build here after changing the kit.

Installing from git

The older path still works while apps migrate:

"@cinesend/ui-kit": "github:BitCine/cinesend-ui-kit#staging"

dist/ is not committed, so a git install builds the kit on install via the prepare script. That means the consumer downloads this package's devDependencies and runs a full build on every npm ci. Prefer the npm release; this path exists so apps are not forced to migrate in lockstep.

Peer dependencies

Apps must provide:

  • react and react-dom (>=18.2 <20)
  • @phosphor-icons/react ^2.1.10
  • sonner ^2.0.7

Runtime dependency: @base-ui/react.

Data-dense components

Most of this kit is tile- and file-oriented, which is what Files and Screeners needed. Table, Pagination, Badge and the page states are for data-dense internal tools, and they share one rule worth stating once: they describe a page of server-held data, and never reinterpret it.

The Table component

Sorted, with row selection and a real control in each cell, light and dark:

Table with sorting and selection

The same table in dark mode

  • Table sorts nothing. A sortable header reports the sort it wants through onSortChange; whoever owns the query answers. The rows handed to it are one page of a larger set, so ordering them in the component would sort the page rather than the data, and disagree with both the total underneath and the next page. Selection is controlled for the same reason, and select-all covers only the keys on screen.

    caption is required: it is the table's accessible name and it is visually hidden. Without it a screen reader announces "table" and nothing else.

    onRowClick is a pointer shortcut, not the row's only route. Rows keep their row role, so they are not focusable and are not announced as controls — put a real link or button in one of the cells and let the row click duplicate it. Clicks that start on that control (or any other interactive element in the row) do not also run the row shortcut, so the action fires once rather than twice. The obvious alternative, role="button" plus tabIndex on the <tr>, is deliberately avoided: it overrides the implicit row role, leaves every cell without a valid row owner, breaks table navigation for a screen reader, and nests the selection checkbox inside a button.

    stickyHeader needs the height bound on the table root itself, which is what className is for:

    <Table stickyHeader className="h-[32rem]" … />

    Not on a wrapper around it. .cs-table carries overflow-x, and when one axis is not visible the other computes to auto — so .cs-table is the nearest scroll container. Bound a wrapper instead and the header scrolls out of view along with the table, which looks exactly like the prop not working.

    Virtualization is deliberately out of scope. Every row given is rendered. That is comfortable into the high hundreds, which covers a paged admin list. A screen that needs tens of thousands of rows at once wants a different component, not a flag on this one.

  • Pagination takes counts, not a response envelope — every backend spells its pagination differently, and a component that understands one framework's meta is one the next app works around.

  • Badge takes a semantic tone, not a status. Map your own vocabulary onto the five tones at the call site and fall back to neutral for anything unrecognised, so an unfamiliar status is still displayed rather than dropped. (WorkspaceBadge is the decorative initial beside a workspace name; it is aria-hidden and is not this.)

  • LoadingState / EmptyState / ErrorState are three renders, never one. "There is nothing here" and "we could not find out" lead to opposite actions. ErrorState takes a message string rather than an error object: turning a failure into a sentence needs to know which status codes your API uses for "come back later" versus "this is gone", which the kit cannot know.

Choosing which state to show is the caller's job — that depends on a data layer this kit has no opinion about.

Local kit work

Node 24 (see .nvmrc) — nvm use picks it up. The build toolchain needs Node 20.19+ or 22.12+; on anything older the build dies with a confusing node:util / styleText module error rather than a version complaint.

nvm use
npm install
npm test
npm run catalog:check
npm run catalog

The catalogue in catalog/ documents this package. It is not the Files demo.

Releasing

Releases are published from CI by .github/workflows/release.yml using npm Trusted Publishing (OIDC). There is no NPM_TOKEN secret — npmjs.com is configured to trust this repo's release.yml workflow.

Provenance is off (publishConfig.provenance). Trusted publishing turns it on by default, and npm does not accept provenance from a private source repository, which this one is — so leaving it on fails the publish outright. Turn it back on if the repo ever goes public.

To cut a release, bump version in package.json as part of the PR. Merging to staging runs typecheck, tests and the build, publishes, and tags the commit v<version>.

A merge that did not bump the version publishes nothing: the workflow asks npm whether that version exists and stops if it does, so an ordinary merge is a no-op rather than a failed publish. Pushing a v* tag by hand still works and is checked against package.json.

Stack for consuming apps

React + Vite. TanStack Query for all server data. Do not add raw fetch / useEffect data loading in the apps.