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

@campfire-interactive/help-panel

v0.3.1

Published

In-app product help panel for Campfire Suite apps — docked and expanded reading surfaces, search, screen blueprints, and an Ask chat. Chrome only; the host wires the content source.

Readme

@campfire-interactive/help-panel

In-app product help for Campfire Suite apps: a drawer docked beside the page, an expanded reading surface with a contents tree and screen blueprints, and an optional Ask chat.

Chrome only. The package owns presentation and panel state; the host wires the content source, the current route, its strings, and its chat endpoint. Same split as the bug-report modal in shell-header.

Install

npm install @campfire-interactive/help-panel

Peers: react, react-dom, @tanstack/react-query. No CSS import — the stylesheet is injected by the bundle.

Wiring

import {
  HelpPanelProvider, HelpDrawer, HelpOverlay, useHelpMode,
  type HelpContentSource,
} from '@campfire-interactive/help-panel';

const contentSource: HelpContentSource = {
  cacheKey: 'myapp',
  getToc:      () => apiGet('/v1/help/myapp'),
  getPage:     (slug) => apiGet(`/v1/help/myapp/${slug}`),
  getForRoute: (path) => apiGet('/v1/help/myapp/for-route', { path }),
  search:      (q) => apiGet('/v1/help/myapp/search', { q }),
  // Omit `chat` and there is no Ask tab. That is the feature switch.
  chat:        (vars) => apiPost('/v1/help/myapp/chat', vars),
};

<HelpPanelProvider
  contentSource={contentSource}
  currentPath={useLocation().pathname}
  namespaceLabel={(ns) => NAMESPACE_LABELS[ns] ?? ns}
  t={useTranslation('help').t}
  urlSync={mySearchParamsUrlSync}
  chatStarters={[{ key: 'chat.starter.quote', text: 'How do I create a quote?' }]}
>
  <AppShell />
</HelpPanelProvider>

Then render both surfaces inside the provider, and open from anywhere with useHelpMode().openHelp().

Two host requirements the package cannot ship

1. min-width: 0 on your main content. The drawer is a flex sibling of your page, not an overlay — that is what lets the page reflow beside it and stay clickable while help is open. A flex item's default min-width: auto refuses to shrink below its content, so without this the page shoves the drawer off the right edge instead of making room:

<div style={{ display: 'flex', flex: 1, overflow: 'hidden' }}>
  <Sidebar />
  <main style={{ minWidth: 0, flex: 1, overflowY: 'auto' }}>{children}</main>
  <HelpDrawer />
  <HelpOverlay />
</div>

2. If you use react-router, supply your own urlSync. Do not use the exported historyApiUrlSync() — react-router's BrowserRouter keeps its own history object and does not observe an external replaceState, so the panel's write would desync it and your next navigation would drop ?help=. Ten lines instead:

const [params, setParams] = useSearchParams();
const urlSync = useMemo(() => ({
  read: () => {
    const page = params.get('help');
    if (!page) return null;
    const anchor = window.location.hash.replace(/^#/, '');
    return anchor ? { page, anchor } : { page };
  },
  write: (v) => setParams((p) => {
    if (v) p.set('help', v.page); else p.delete('help');
    return p;
  }, { replace: true }),   // replace, never push
  subscribe: () => () => {},   // react-router re-renders on its own
}), [params, setParams]);

replace, not push, is the point: help sits over the reader's own work, so a history entry per help page would make Back mean "the previous help page" while they are looking at their screen behind the panel. Omitting urlSync entirely is fine — the panel simply is not linkable.

Resizing the drawer

The docked drawer opens at 336px and the reader drags its left edge to whatever width suits the task; the width is remembered in that browser. Arrow keys on the edge (a focusable separator) move it too, Shift for bigger steps, Home resets, End goes to the widest allowed. Double-click resets. The drawer never covers the page: it stops at the row's width minus 320px, and never goes below 280px or above 1200px. Nothing to configure on the host side — the only requirement is the min-width: 0 above, which is what lets the page reflow as the drawer grows. The expand control is unchanged: it is a different act (the whole reading surface, over the page), not a wide drawer.

Theming

Every colour goes through a --cfi-hp-* custom property with the shipped value as its fallback. Override on .cfi-hp-root, or globally:

:root {
  --cfi-hp-accent: #0f766e;      /* the Ask surface */
  --cfi-hp-frame:  #1e293b;      /* the expanded panel's border — match your shell */
}

--cfi-hp-frame is worth setting: it defaults to the sidebar colour of the first consuming app, so the expanded panel reads as that app's chrome closing around it.

i18n

t is optional. Every string carries an English default at its call site, so omitting t renders correct English and the package ships no translation machinery. Pass useTranslation('help').t (or any (key, fallback, vars) => string) to translate.

Content contract

Page shapes mirror the platform guide contract registered in nextgen CONTRACTS.md ("Help guide bundle"). Two properties matter for consumers:

  • Anchors are authored, not derived. They arrive on the page payload as sections, and the markdown does not contain them. That is what lets a heading be reworded without orphaning every citation and deep link pointing at it.
  • Slugs and anchors are stable identifiers. Citations address them, so moving one is a breaking change even though no field changes.