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

@judo/app-shell

v0.1.1

Published

> Admin dashboard application shell with multi-level navigation, multi-actor support, theme management, and badge notifications

Readme

@judo/app-shell

Admin dashboard application shell with multi-level navigation, multi-actor support, theme management, and badge notifications

Purpose

The Layer 5 (UI) entry point that orchestrates layout, routing, theming, navigation, user menu, actor switching, error boundaries, and the full runtime bootstrap. Supports both vertical (sidebar drawer) and horizontal (top bar) menu layouts, configurable via the Application.defaultMenuLayout model property or the menuLayout prop. Depends on nearly every other package in the monorepo.

Architecture Layer

Layer 5 (UI) — the top-level shell consumed by standalone and application-level code.

Dependencies

| Workspace | External (Peer) | | -------------------- | -------------------------------------------------------------- | | @judo/actions | @emotion/react, @emotion/styled | | @judo/auth | @mui/icons-material, @mui/material | | @judo/components | @mui/x-data-grid-pro (optional), @mui/x-license (optional) | | @judo/core | react, react-router | | @judo/expressions | | | @judo/feedback | | | @judo/guards | | | @judo/i18n | | | @judo/model-api | | | @judo/model-loader | | | @judo/test-ids | |

File Structure

src/
├── index.ts                          # Public API barrel
├── AppShell.tsx                       # Main shell wrapper (ThemeProvider + AppErrorBoundary + AppShellLayout)
├── actors/
│   └── ActorSelector.tsx              # Multi-actor dropdown with realm-change confirmation
├── errors/
│   └── AppErrorBoundary.tsx           # Root class-based error boundary
├── hooks/
│   ├── use-navigation-badge.ts        # Badge hook (stub — always returns null)
│   └── use-theme.ts                   # Singleton ThemeStore + useTheme hook + initializeThemeStore
├── layout/
│   ├── AppBar.tsx                     # Top app bar (menu toggle, logo, actor selector, locale, theme, hero)
│   ├── AppShellLayout.tsx             # Main layout (drawer + bar + content + footer + dialog host)
│   ├── Breadcrumbs.tsx                # Breadcrumb trail from NavigationContext page stack
│   ├── Footer.tsx                     # Application footer (model name or custom footerText)
│   ├── PageDialogHost.tsx             # Dialog stack renderer (all mounted, only topmost interactive)
│   └── layout-constants.ts           # Drawer width constants (DRAWER_WIDTH_EXPANDED/COLLAPSED)
├── locale/
│   └── LocaleSwitcher.tsx             # AppBar locale dropdown (globe icon, 2+ locales required)
├── navigation/
│   ├── NavigationDrawer.tsx           # Persistent sidebar drawer (vertical mode)
│   ├── NavigationItemRenderer.tsx     # Recursive vertical menu item with badge/icon/tooltip
│   ├── HorizontalNavigation.tsx       # Top-bar nav container (horizontal mode)
│   ├── HorizontalNavigationItem.tsx   # Recursive horizontal nav item + cascading sub-menus
│   ├── navigation-utils.ts           # Route generation, filtering, localStorage persistence
│   └── dashboard-utils.ts            # Dashboard route resolution from navigation tree
├── routes/
│   ├── generate-routes.tsx            # Route tree generation from Application model
│   ├── DefaultGuestPage.tsx           # Built-in guest access page (sign-in CTA)
│   ├── DefaultSettingsPage.tsx        # Built-in settings placeholder
│   ├── PageRoute.tsx                  # Single page route wrapper with transfer ID generation
│   └── RedirectPage.tsx               # /_redirect route — renders customizable RedirectHandler
├── runtime/
│   ├── types.ts                       # All config/props/state types
│   ├── JudoRuntime.tsx                # Zero-boilerplate bootstrap (includes inlined AuthBridge, AuthTokenSync, NavigationProviderBridge, ApplicationRoutes)
│   ├── PrincipalBridge.tsx            # Wires PrincipalProvider with API client
│   ├── DefaultLoadingScreen.tsx       # Loading spinner screen
│   ├── DefaultErrorScreen.tsx         # Error + retry screen
│   └── index.ts                       # Runtime barrel exports
├── theme/
│   ├── ThemeProvider.tsx              # MUI ThemeProvider wrapper (mode, colors, density, muiThemeOptions)
│   ├── ThemeToggle.tsx                # Light → dark → system toggle button
│   └── density.ts                     # Density level theme options (compact/comfortable/standard)
└── user/
    ├── DefaultHeroComponent.tsx        # Built-in authenticated hero (avatar, profile, settings, logout)
    └── UserMenu.tsx                   # Legacy user avatar dropdown (separate from DefaultHeroComponent)

Exports Summary

Runtime Bootstrap

| Export | Kind | Description | | ---------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | JudoRuntime | component | Zero-boilerplate bootstrap. Loads model via loader, creates registry, builds REST API client, wires full provider tree, and auto-generates routes. Shows loading/error screens during init. Supports retry. | | JudoRuntimeConfig | interface | Aggregates: model, auth, api, theme, features, i18n, router, muiProLicenseKey, menuLayout. | | JudoRuntimeProps | interface | Props for JudoRuntimeconfig, modelSource, logo, appBarExtra, loadingComponent, errorComponent, children, customizations. | | JudoRuntimeState | interface | Internal state: phase (initializing/loading/ready/error) + error. | | ModelConfig | interface | Model URL or async loader + which app to activate. | | AuthConfig | interface | OIDC / skip-auth config. | | ApiConfig | interface | REST API endpoint config (baseUrl, timeout, headers). | | ThemeConfig | interface | Theme customization (defaultMode, colors, muiThemeOptions, density). | | FeaturesConfig | interface | Feature flags (guards, forceShowTotalCountForLazyTables, headerFilters). | | I18nConfig | interface | Locale config (locales, localeLoader, translationKeyMap, persistLocale). | | RouterConfig | interface | Router type (browser/hash/memory) and basePath. | | DefaultLoadingScreen | component | Full-viewport centered CircularProgress + "Loading application..." text. | | DefaultErrorScreen | component | Full-viewport error display with optional retry button. | | DefaultGuestPage | component | Built-in guest access page. Centered Paper with app title, instructional text, and "Sign In" button. Used as fallback when no custom guestComponent is set. Receives GuestPageProps. |

Application Shell

| Export | Kind | Description | | ------------------ | --------- | --------------------------------------------------------------------------------------------------------- | | AppShell | component | Wraps children in ThemeProvider + AppErrorBoundary + AppShellLayout. Requires ApplicationContext. | | AppErrorBoundary | component | Root React error boundary. Catches unhandled errors, displays error + "Refresh Page" button. |

Layout

| Export | Kind | Description | | ---------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | AppShellLayout | component | Main dashboard layout. In vertical mode (default): drawer open/collapsed state + NavigationDrawer. In horizontal mode: no drawer, navigation embedded in AppBar. Includes Footer and PageDialogHost. Accepts optional menuLayout prop overriding model's Application.defaultMenuLayout. | | AppBar | component | Fixed top bar with menu toggle (vertical only), logo/app name, ActorSelector, HorizontalNavigation (horizontal only), LocaleSwitcher, ThemeToggle, and DefaultHeroComponent (auth-required apps). Resolves profilePictureUrl and settings/profile navigation. | | Breadcrumbs | component | Breadcrumb trail from NavigationContext page stack. Clickable entries navigate back. Uses useModelLabel and usePageTitle for translated labels. | | PageDialogHost | component | Renders dialog stack from NavigationContext. All dialogs mounted simultaneously — non-topmost hidden via CSS. Each dialog is a SinglePageDialog with full provider tree (PageProvider, ValidationProvider, DispatchProvider, etc.). |

Navigation

| Export | Kind | Description | | ------------------------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | NavigationDrawer | component | Persistent MUI Drawer with collapse toggle, search filter, and recursive item list. Persists expanded state to localStorage. Applies menu customizer from customizations. Vertical mode only. | | NavigationItemRenderer | component | Recursive vertical nav item with icon (via IconRenderer), badge, active-state highlighting, expand/collapse, tooltip when collapsed. Uses useModelLabel for translated labels. | | HorizontalNavigation | component | Top-bar navigation container rendering items as a flex row of buttons. Applies menu customizer. No search. Horizontal mode only. | | HorizontalNavigationItem | component | Recursive horizontal nav item. Top-level: toolbar Button with dropdown Menu for children. Nested: cascading MenuItem sub-menus via HorizontalNavigationSubItem. Supports N-deep nesting, badges, icons, active-state. | | filterNavigationItems(items, query) | function | Recursively filters nav items by label/name matching (case-insensitive). | | getRouteForPage(pageRef) | function | Generates a URL path from a PageDefinition (resolved or string reference). Uses container type for route suffix. | | getDashboardRoute(application) | function | Finds the first isDashboard page referenced in navigation, returns its route. Falls back to "/". |

Routing

| Export | Kind | Description | | ----------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | generateRoutes(props) | function | Generates a React Router route tree from Application. Adds dashboard route, maps each page to PageRoute, adds /_redirect, /settings, optional customRoutes, and 404 catch-all. Accepts GenerateRoutesProps. | | PageRoute | component | Wraps a page in PageProvider + PageActionOverridesProvider + VisualPropertiesProvider. Generates stable transfer IDs for TABLE/VIEW pages. Extracts signedIdentifier from URL params. Renders PageRenderer. | | RedirectPage | component | Rendered at /_redirect. Looks up redirectHandler from customizations and renders it; shows fallback message if none configured. | | DefaultSettingsPage | component | Built-in placeholder settings page at /settings. Uses i18n for labels. Replaced when CustomizationsConfig.settingsPage is provided. |

Locale

| Export | Kind | Description | | ---------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | LocaleSwitcher | component | Globe icon button + dropdown menu for switching locales. Only renders when 2+ locales configured. Uses useLocaleOptional() for safe fallback outside I18nProvider. Positioned before ThemeToggle in AppBar. |

Theme

| Export | Kind | Description | | ---------------------------------------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------- | | ThemeProvider | component | Creates MUI theme from config (mode, colors, density, muiThemeOptions) and wraps children in MuiThemeProvider + CssBaseline. | | ThemeToggle | component | IconButton cycling light → dark → system → light. Shows next-mode icon. | | useTheme() | hook | Returns current theme config and setter. Backed by singleton LocalThemeStore via useSyncExternalStore. | | initializeThemeStore(config, useSystemPreference?) | function | Called by JudoRuntime before rendering. Applies runtime config. Preserves user's saved localStorage preference. | | hasUserThemePreference() | function | Returns true if user has saved a theme mode or system preference to localStorage. | | createDensityThemeOptions(density) | function | Returns MUI ThemeOptions for the given DensityLevel (compact/comfortable/standard). Applied as base layer before muiThemeOptions. | | DensityLevel | type | Union type: "compact" \| "comfortable" \| "standard". |

Actors & User

| Export | Kind | Description | | ---------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ActorSelector | component | MUI Select dropdown for switching between applications/actors. Hidden when ≤1 app. Uses useActorSwitch for realm-change confirmation. Navigates to dashboard after switch. | | DefaultHeroComponent | component | Built-in hero for authenticated actors. Avatar button + dropdown with user info, Profile (conditional on profilePage), Settings (always), and Log Out. Uses i18n for labels, supports profilePictureUrl. Rendered by AppBar when no custom heroComponent configured. | | UserMenu | component | Standalone user avatar button + dropdown. Not used by AppBar (which uses DefaultHeroComponent instead). Kept for custom layouts. |

Hooks

| Hook | Description | | -------------------------- | -------------------------------------------------------------------------------- | | useTheme() | Theme config access via useSyncExternalStore over singleton LocalThemeStore. | | useNavigationBadge(item) | Stub — always returns null. Reserved for future badge service. |

Key Patterns

  • Dual menu layout: AppShellLayout reads Application.defaultMenuLayout from the model (or accepts menuLayout prop override). VERTICAL renders NavigationDrawer sidebar with search/collapse/expand. HORIZONTAL hides the drawer, hides the hamburger toggle, and embeds HorizontalNavigation inside the AppBar toolbar with cascading dropdown sub-menus. Both modes use the same NavigationController model and support N-deep menu trees.
  • Singleton external store for theme: LocalThemeStore class with subscribe/getSnapshot avoids React context for theme state; supports OS preference via matchMedia and localStorage persistence
  • Provider tree composition: JudoRuntime assembles the entire provider stack in fixed order (Customizations → Theme → Feedback → API → RuntimeConfig → MuiPro → Application → Expressions → I18n → Auth → Data → Router → Navigation → AppShellLayout)
  • Model-driven routing: generateRoutes + getRouteForPage + PageRoute derive URL paths entirely from PageDefinition objects and their resolved containers (TABLE/FORM/VIEW)
  • Dialog-as-page: PageDialogHost reads dialog state from NavigationContext and renders a full page inside a MUI Dialog with its own PageProvider, ValidationProvider, DispatchProvider, and SelectorSelectionProvider
  • Stable transfer IDs: Both PageRoute and PageDialogHost generate deterministic transfer IDs (page::, dialog::, transfer::) to key data store entries
  • Class-based error boundary: AppErrorBoundary uses React class component lifecycle since function components can't catch render errors
  • User preference preservation: initializeThemeStore checks localStorage before applying runtime config, ensuring user's chosen mode is never overwritten
  • Multi-actor support with realm safety: ActorSelector uses useActorSwitch for confirmation when switching between actors with different OIDC realms
  • Menu customizer: Both NavigationDrawer and HorizontalNavigation apply the menuCustomizer function from CustomizationsConfig to transform navigation items before rendering
  • Hero component pattern: AppBar renders DefaultHeroComponent for authenticated actors by default; apps can replace it via CustomizationsConfig.heroComponent. Both receive HeroComponentProps.
  • Density theming: createDensityThemeOptions provides three preset density levels that adjust spacing, font sizes, and component sizes across the entire UI
  • Footer: AppShellLayout includes a Footer component at the bottom that displays either custom footerText from CustomizationsConfig or a default © {year} {modelName} string
  • Lazy code splitting: Container renderers are lazy-loaded via React.lazy in PageRenderer