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

@tooee/panels

v0.7.3

Published

First-class panels (peer command surfaces with activation and chrome) for Tooee

Downloads

1,268

Readme

@tooee/panels

First-class panels for Tooee: multiple visible regions with exactly one active, each owning its commands, local mode, and optional chrome.

Part of the Tooee monorepo. See the main repo for documentation.

Model

A PanelGroup holds peer Panels among which exactly one is active. The active panel owns keyboard input — only its useCommand/useMode children dispatch — and shows the active chrome. Panels stay mounted across switches, so local state, panel-local router stacks, and per-panel mode persist. A topmost modal overlay still suspends the whole group and returns input to the same panel on close.

Panels build on @tooee/commands' "panel" surface role: the active panel's commands dispatch, and keys it does not handle fall through to the enclosing surface in cursor/select mode, with a panel command shadowing a root command of the same hotkey while active. Insert-mode panels do not fall through: typed characters and Tab stay with the focused editor/input. See the @tooee/commands arbitration docs.

The app supplies layout (flex rows/columns); panels manage activation, command ownership, and chrome around it — not resizing or splitting.

Examples

import { PanelGroup, Panel } from "@tooee/panels";

<box flexDirection="row" width="100%" height="100%">
  <PanelGroup defaultActivePanelId="list">
    <Panel id="list" title="Streams" style={{ width: 32 }}>
      <StreamList /> {/* useCommand here dispatches only while "list" is active */}
    </Panel>
    <Panel id="detail" title="Detail" style={{ flexGrow: 1 }}>
      <StreamDetail /> {/* j/k etc. dispatch only while "detail" is active */}
    </Panel>
  </PanelGroup>
</box>;

Run any example from the repository root:

bun examples/panels.tsx
bun examples/panels-controlled.tsx
bun examples/panels-custom-chrome.tsx
bun examples/panels-disabled.tsx
  • panels.tsx — complete composition with panel-owned commands, a panel-local router, and a suspending modal.
  • panels-controlled.tsx — controlled activation, direct selection, and group state through usePanels().
  • panels-custom-chrome.tsxchrome="none", app-defined active cues, click activation, and usePanelState().
  • panels-disabled.tsx — a disabled panel, switchKeys={null}, and app-owned previous/next commands that skip it.

PanelGroup

Renders no box of its own. Owns activation (controlled or uncontrolled), Tab cycle order (source order), activation repair, and the switch commands.

| Prop | Default | Meaning | | ---------------------- | ---------------------------------------- | ------------------------------------------------------------------------------- | | id | generated | Stable group id (fine to omit for a single group). | | defaultActivePanelId | first panel | Uncontrolled initial active panel. | | activePanelId | — | Controlled active panel; null explicitly selects none. | | onActivePanelChange | — | Uncontrolled resolved changes, or controlled activation requests (non-null). | | switchKeys | { next: "tab", previous: "shift+tab" } | Switch hotkeys; null disables built-in switching. | | switchModes | ["cursor", "select"] | Modes in which the switch keys are live (so insert-mode Tab reaches editors). | | wrap | true | Wrap from last to first. | | activateOnMouseDown | true | Activate a panel on mouse-down (default chrome only). |

The panels.next / panels.previous switch commands register on every panel's local command surface. Only the active panel's pair can dispatch or appear in the effective palette, so sibling and nested groups cannot overwrite one another. Their stable ids remain remappable through keymap.

Activation repair: when the active panel unmounts or becomes disabled, the next activatable panel (else the previous, else none) takes over. A controlled group is never repaired — a missing/disabled controlled id activates no panel. In uncontrolled groups, onActivePanelChange reports the initial resolved panel, explicit activation, switching, and repair. In controlled groups it reports a valid activation request but does not echo prop changes. The callback remains a non-null API: empty groups and transitions to no active panel do not emit it; read usePanels().activePanelId to observe null.

Panel

| Prop | Default | Meaning | | ------------- | ---------- | ----------------------------------------------------------------------------------------------------------- | | id | — | Stable id; also the panel's command-surface id. | | title | — | Chrome title (rendered with a marker + borderActive when active); not a palette/which-key heading. | | disabled | false | Excluded from activation/switching; renders disabled chrome, stays mounted. | | initialMode | "cursor" | Initial local mode. | | chrome | "border" | "border" renders a themed box; "none" renders no chrome (the app draws its own from usePanelState()). | | style | — | Layout props forwarded to the chrome box. |

Chrome uses existing theme tokens only (borderActive / border / borderSubtle, textMuted, backgroundPanel) — no new theme keys.

Hooks

  • usePanelState(){ id, title?, isActive, activate } for the nearest panel.
  • usePanels(){ panelIds, activePanelId, activate, next, previous } for the nearest group.
  • usePanelActive()true when inside the active panel (or when there is no enclosing panel).

Router composition

Panels do not depend on @tooee/router. A router mounted inside a panel is navigated independently and keeps its stack across switches; effects on a leaf inside an inactive panel pause (screen focus is the enclosing panel's activity ANDed with the route-chain leaf). A router outside the group replaces the whole panel composition on navigation.