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

@openinary/ui

v0.8.1

Published

Openinary's dashboard UI components, hooks and design primitives as a standalone, embeddable React package.

Readme

@openinary/ui

Openinary's dashboard UI components, hooks, and design primitives as a standalone, embeddable React package. Extracted from apps/web so the dashboard design can be reused outside this monorepo (e.g. in a closed-source SaaS built on top of Openinary).

Install

npm install @openinary/ui

Peer dependencies (install alongside, matching versions your app already uses):

npm install react react-dom @tanstack/react-query sonner

react-query and sonner must be peers, not just installed anywhere in the tree — components read from your app's QueryClientProvider and <Toaster /> by identity. If a different copy of either package gets resolved for this package, queries silently miss the client and toasts silently never render.

Setup

Wrap your app in OpeninaryProvider, inside your existing QueryClientProvider. This package does not create its own QueryClient — it uses whichever one is already above it in the tree, so upload/delete/create mutations that call invalidateStorage(queryClient) invalidate the same cache your own queries read from.

import { QueryClientProvider } from "@tanstack/react-query";
import { OpeninaryProvider, Toaster } from "@openinary/ui";

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <QueryClientProvider client={queryClient}>
      <OpeninaryProvider apiBaseUrl="https://media.example.com/api">
        {children}
        <Toaster />
      </OpeninaryProvider>
    </QueryClientProvider>
  );
}

OpeninaryProvider is a client component. If you render it from a Next.js Server Component (e.g. a root layout.tsx), only pass serializable props — strings are fine, but a custom fetch override is a function and can't cross the RSC boundary. If you need a custom fetch (auth headers, retries, tracing), render OpeninaryProvider from your own "use client" wrapper instead of a Server Component.

Tailwind

Components use Tailwind utility classes but ship no compiled CSS — your app's Tailwind config already applies to them once it can see the class names. Add an explicit @source so Tailwind's scanner doesn't skip node_modules:

/* your globals.css, after @import "tailwindcss"; */
@source "../node_modules/@openinary/ui/dist";

(Path is relative to the CSS file — adjust the ../ depth for your project.) Without this, every class this package uses gets purged from your build.

Theming is inherited, not duplicated: components resolve the same shadcn/ui CSS variables (--primary, --radius, --background, …) your app already defines. If your app follows the shadcn/ui neutral-palette convention, this package's components render identically to your own.

Two entry points

  • @openinary/ui — the full client surface (components, hooks, provider). Carries a "use client" boundary; safe to import from Server Components, but the imported bindings are client references.
  • @openinary/ui/server — pure, stateless exports only (types, cn, getMediaType, formatFileSize/formatDate/getFileType, Spinner). RSC Server Components can import from here directly without crossing a client boundary at all.

What's included

The full media browser — MediaGrid (virtualized grid/list views, folder navigation, context menus, bulk selection, drag-free move/copy/rename/delete) plus its building blocks (dialogs, rename, upload, folder management, asset details sidebar with transform-URL previews), the video processing queue UI, the presigned-upload FileUploader, and the data hooks that back all of it (useStorageLevel, useQueueEvents, useVideoStatus, …). All data hooks read their API base URL from OpeninaryProvider context — nothing reads process.env directly.

MediaGrid doesn't own folder navigation state — pass folderPath and onFolderPathChange (or omit both to stay pinned to the root folder). This keeps the package router-agnostic; wire it to your own URL state (nuqs, React Router, etc.) the same way you already do for AssetDetailsSidebar's assetId/onAssetIdChange.

Also included: a composable SettingsDialog shell (nav sidebar + content pane layout, no tab state or tab content of its own — you pass nav, tab/onTabChange, and children) plus two ready-made tabs, AppearanceTab (theme switcher, hide-thumbnails toggle) and StorageTab (usage stats, clear cache). AppearanceTab needs a next-themes ThemeProvider above it in the tree (next-themes is a peer dependency, same reasoning as react-query).

Toaster is Openinary's themed sonner wrapper (dark, pill-shaped toasts, custom action/cancel/close styling) — render it instead of importing Toaster from sonner directly, so toasts look the same as the dashboard.

BorderBeam is re-exported from border-beam untouched, so it keeps its full prop surface (colorVariant, strength, brightness, duration, hueRange, …). MediaGrid uses it around the empty state's upload button; pass beamProps to restyle that one, or active: false to stop it animating:

<MediaGrid
  onMediaSelect={handleSelect}
  beamProps={{ colorVariant: "sunset", strength: 0.2 }}
/>

It renders its own <style> inline, so there is no stylesheet to import.

Not included, by design — these are coupled to Openinary's self-hosted, single-admin auth model and don't generalize to other apps' auth: authentication UI (login/API-key management) and anything importing better-auth.