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

@rytass/bpm-core-react

v0.4.1

Published

BPM approval workflow React components and views for the Rytass BPM stack. Ships AuthProvider, NotificationDrawer + bell widget, host-facing hooks (useBPMMember / useBPMLogout / useBPMRoutes), and full page-body views for inbox / instances / templates / f

Readme

@rytass/bpm-core-react

React provider / hook / view components for the Rytass BPM approval workflow stack.

This package composes @mezzanine-ui/react primitives with the BPM domain logic in @rytass/bpm-core-client and @rytass/bpm-core-shared so a consumer can wire up the full BPM admin UI by re-exporting page modules from their Next.js App Router.

Status

0.4.0 (breaking) — drops the bundled navigation shell. BPM views no longer wrap themselves in an <AppLayout> / Mezzanine <Navigation>; the host owns the layout chrome and mounts BPM views inside its own sidebar / top bar. New host-facing widgets ship in the root barrel: useBPMMember, useBPMLogout, <BPMNotificationBellButton />. See CHANGELOG.md for the migration walkthrough, and docs/integration-guide.md for a host integration recipe.

Install

pnpm add @rytass/bpm-core-react @rytass/bpm-core-client @rytass/bpm-core-shared @mezzanine-ui/react @mezzanine-ui/icons

Peer requirements: React 18+, Mezzanine UI 1.1+. Next.js is required only when consuming the pages/* subpath; framework-agnostic consumers can use views/* directly with their own router adapter.

Next.js + pnpm setup

If your host uses Next.js (15+) with pnpm strict mode, add the package to transpilePackages in next.config.js. Without this, Next's Turbopack cannot resolve transitive peer-dep imports such as @rytass/bpm-core-client/workflow from inside pnpm-isolated node_modules/.pnpm/... paths.

/** @type {import('next').NextConfig} */
module.exports = {
  reactStrictMode: true,
  // Include the sibling packages too — BPM views import from
  // `@rytass/bpm-core-client/workflow`, `/organization`, `/template`,
  // `/form` and re-export shared types from `@rytass/bpm-core-shared`.
  // pnpm strict mode + Turbopack rejects the transitive resolution
  // without each entry listed explicitly.
  transpilePackages: [
    '@rytass/bpm-core-react',
    '@rytass/bpm-core-client',
    '@rytass/bpm-core-shared',
  ],
};

Usage

Host integration shape

BPM ships page bodies, providers, and widgets — never a full layout. The host wires its own <Layout> / <Navigation> (or its own design system equivalent), then drops BPM widgets and views into the slots:

// app/layout.tsx
import { BPMNextProviders } from '@rytass/bpm-core-react/next';
import { MyHostLayout } from './host-layout';

export default function RootLayout({ children }) {
  return (
    <html lang="zh-TW"><body>
      <BPMNextProviders>
        <MyHostLayout>{children}</MyHostLayout>
      </BPMNextProviders>
    </body></html>
  );
}
// app/host-layout.tsx
'use client';
import {
  BPMNotificationBellButton,
  useBPMLogout,
  useBPMMember,
  useBPMRoutes,
  useRouterAdapter,
} from '@rytass/bpm-core-react';

export function MyHostLayout({ children }) {
  const router = useRouterAdapter();
  const routes = useBPMRoutes();
  const member = useBPMMember();
  const logout = useBPMLogout();
  return (
    <div className="grid grid-cols-[240px_1fr]">
      <aside>
        <h1>My Console</h1>
        <ul>
          <li><a href={routes.dashboard()}>工作台</a></li>
          <li><a href={routes.inbox()}>我的待簽</a></li>
          {/* …host's own nav items… */}
        </ul>
        <div className="flex items-center gap-2">
          <span>{member?.name}</span>
          <BPMNotificationBellButton />
          <button onClick={() => logout()}>登出</button>
        </div>
      </aside>
      <main>{children}</main>
    </div>
  );
}

The page shims under pages/* are unchanged — they remain one-line { default, metadata } re-exports and are mounted under the host layout exactly like any other Next.js page:

// app/inbox/page.tsx
export { default, metadata } from '@rytass/bpm-core-react/pages/inbox';

For an end-to-end reference layout (with the original 4-group BPM nav structure, admin-only filtering, and member display), see apps/client/src/app/_components/host-layout.tsx in the BPMCore repo.

Framework-agnostic view

'use client';
import { useRouter, usePathname } from 'next/navigation';
import {
  AuthProvider,
  RouterAdapterProvider,
} from '@rytass/bpm-core-react';
import { LoginView } from '@rytass/bpm-core-react/views/login';

function MyLoginPage() {
  const next = useRouter();
  const pathname = usePathname();
  return (
    <RouterAdapterProvider value={{ pathname, push: next.push, replace: next.replace }}>
      <AuthProvider>
        <LoginView brandTitle="My BPM" />
      </AuthProvider>
    </RouterAdapterProvider>
  );
}

For SPA / Remix / Tanstack Router hosts, supply a RouterAdapter that bridges your router primitives.

Mounting BPM under a non-root URL prefix

If your host already owns the / namespace (Shuttle, an existing admin console, etc.), wrap the BPM tree in <BPMRoutesProvider> and override every internal cross-link to a prefixed path. The full BPMRoutes contract has 19 entries — overriding only some leaves the rest pointing at the unprefixed defaults, which usually 404s on your host. Use a small factory to keep the override exhaustive:

import {
  BPMRoutesProvider,
  createDefaultBPMRoutes,
  type BPMRoutes,
} from '@rytass/bpm-core-react/next';

function createPrefixedRoutes(prefix: string): BPMRoutes {
  const trim = prefix.replace(/\/$/, '');
  return {
    ...createDefaultBPMRoutes(), // safety net for any future routes
    dashboard:             () => `${trim}`,
    inbox:                 () => `${trim}/inbox`,
    sent:                  () => `${trim}/sent`,
    cc:                    () => `${trim}/cc`,
    search:                () => `${trim}/search`,
    delegations:           () => `${trim}/delegations`,
    notifications:         () => `${trim}/notifications`,
    caseDetail:    (id)         => `${trim}/instances/${id}`,
    caseNew:       (templateId) => templateId
      ? `${trim}/instances/new?templateId=${encodeURIComponent(templateId)}`
      : `${trim}/instances/new`,
    templates:             () => `${trim}/templates`,
    templateDesigner:   (id) => `${trim}/templates/${id}/designer`,
    templateVersions:   (id) => `${trim}/templates/${id}/versions`,
    templateCategories:    () => `${trim}/templates/categories`,
    forms:                 () => `${trim}/forms`,
    formBuilder:        (id) => `${trim}/forms/${id}/builder`,
    notificationSettings:  () => `${trim}/settings/notifications`,
    adminOrgs:             () => `${trim}/admin/orgs`,
    adminUsers:            () => `${trim}/admin/users`,
    adminDelegations:      () => `${trim}/admin/delegations`,
  };
}

// In your layout:
<BPMRoutesProvider value={createPrefixedRoutes('/operations/approval')}>
  <BPMNextProviders>{children}</BPMNextProviders>
</BPMRoutesProvider>

createDefaultBPMRoutes() is the source of truth for the route shape; spreading it first means new BPMCore versions that add routes never silently regress your host.

License

MIT