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

@mappoh/nova

v0.19.0

Published

Nova — a lightweight web engine built on Web Components

Readme

Nova

A lightweight web engine built on Web Components. Zero dependencies.

npm install @mappoh/nova

Modules

Core

| Module | Import | Description | |--------|--------|-------------| | Component | @mappoh/nova/component | Web Components base class with generic typed state (Component<S>), ES2022 class field support, reactive props, lifecycle hooks, and template engine | | Router | @mappoh/nova/router | SPA router with path params, guards, layouts, loaders, and view transitions | | Store | @mappoh/nova/store | Reactive signals, computed values, effects, and batched updates | | Theme | @mappoh/nova/theme | CSS custom property management with dark/light mode switching |

Component Utilities

All utilities auto-cleanup when the component disconnects.

import {
  classMap, styleMap,     // template helpers
  createRef,              // DOM refs
  useComputed,            // memoization
  useInterval,            // non-pausing interval
  useScroll,              // Shadow DOM scroll fix
  afterRender,            // post-paint callback
  createPortal, usePortal,// render outside shadow root
  slotStyles,             // deep slot styling
} from '@mappoh/nova/component';

| Utility | Description | |---------|-------------| | classMap({ active: true }) | Build class strings from boolean maps | | styleMap({ fontSize: 16 }) | Build style strings with auto px and kebab-case | | createRef() | DOM element ref that survives re-renders | | useComputed(this, fn, deps) | Memoize expensive render calculations | | useInterval(this, fn, ms) | Interval that keeps running when tab is hidden | | useScroll(this, selector) | Fix wheel events for Shadow DOM scroll containers | | afterRender(this, fn) | Callback after browser paint (via rAF) | | this.on(event, selector, handler) | Declarative event delegation with auto-cleanup | | createPortal(content) | Render outside shadow root (tooltips, dropdowns) | | slotStyles(this, css) | Deep slot styling beyond ::slotted() | | useClickOutside(this, fn) | Detect clicks outside component (Shadow DOM–aware) | | useResize(this, fn) | ResizeObserver with auto-cleanup | | usePatch(this, selector, fn) | Surgical text node update without re-render |

Component Static Flags

class MyComponent extends Component {
  static tag = 'my-component';
  static scrollFix = true;     // auto-fix wheel events in Shadow DOM
  static debugRender = true;   // log render triggers to console
}

Template Bindings

The html tagged template supports declarative bindings:

render() {
  return html`
    <input
      type="text"
      value=${this.name}
      .value=${this.name}
      class=${classMap({ active: this.isActive })}
      @input=${(e: Event) => this.name = (e.target as HTMLInputElement).value}
      @keydown=${this._onKey}
      ref=${this.inputRef}
    />
    <button @click=${() => this.save()}>Save</button>
  `;
}

| Syntax | Description | |--------|-------------| | attr=${value} | Set HTML attribute (strings, numbers, booleans) | | .prop=${value} | Set DOM property directly (bypasses attribute) | | @event=${handler} | Declarative event listener — re-bound efficiently on each render | | ref=${createRef()} | Capture DOM element reference | | class=${classMap({})} | Conditional class strings | | style=${styleMap({})} | Conditional style strings |

Event handlers (@click, @input, etc.) are automatically managed by the template engine — they are added on first render and updated in place on re-renders without creating duplicate listeners. For delegation across many similar elements, use this.on(event, selector, handler) instead.

Data & State

| Module | Import | Description | |--------|--------|-------------| | Query | @mappoh/nova/query | SWR-style data fetching with stale-while-revalidate and tag-based invalidation | | Idempotent | @mappoh/nova/query/idempotent | Ensures identical operations execute once within a TTL window | | Query Pagination | @mappoh/nova/query/pagination | Offset-based pagination with fetch integration and deduplication | | State Machine | @mappoh/nova/machine | Finite state machine with enter/exit actions | | WebSocket | @mappoh/nova/websocket | Reconnecting WebSocket with heartbeat and backoff | | Event Bus | @mappoh/nova/event-bus | Typed publish/subscribe | | Cache | @mappoh/nova/cache | LRU cache with optional TTL | | Context | @mappoh/nova/context | Dependency injection via DOM events | | HTTP | @mappoh/nova/http | Fetch wrapper with interceptors, retries, timeout | | Persistent State | @mappoh/nova/persistent-state | IndexedDB-backed persistent store | | IndexedDB Store | @mappoh/nova/state/idb | IndexedDB persistence adapter with field filtering and validation | | Offline Query | @mappoh/nova/query/offline | Offline-aware SWR query with auto-retry on reconnection | | Convex | @mappoh/nova/convex | Reactive Convex query subscriptions with synchronous cache delivery |

UI Components

| Component | Import | Description | |-----------|--------|-------------| | Modal | @mappoh/nova/modal | Accessible dialog with focus trap and scroll lock | | Toast | @mappoh/nova/toast | Notification toasts with auto-dismiss | | Tooltip | @mappoh/nova/tooltip | Positioned tooltips with flip/shift | | Popover | @mappoh/nova/popover | Positioned popovers with click/hover/focus triggers | | Dropdown | @mappoh/nova/dropdown | Accessible dropdown menu | | Accordion | @mappoh/nova/accordion | Collapsible panels with ARIA | | Tabs | @mappoh/nova/tabs | Tab panel switcher with keyboard nav | | Stepper | @mappoh/nova/stepper | Multi-step wizard with validation | | Carousel | @mappoh/nova/carousel | CSS scroll-snap carousel with drag | | Pagination | @mappoh/nova/pagination | Page navigation with ellipsis | | Switch | @mappoh/nova/switch | Toggle switch | | Radio Group | @mappoh/nova/radio-group | Radio group with roving tabindex | | Slider | @mappoh/nova/slider | Custom slider with pointer drag | | Rating | @mappoh/nova/rating | Star rating | | Alert | @mappoh/nova/alert | Alert/banner with variants | | Badge | @mappoh/nova/badge | Inline badge | | Avatar | @mappoh/nova/avatar | Image with initials fallback | | Progress | @mappoh/nova/progress | Linear and circular progress bars | | Skeleton | @mappoh/nova/skeleton | Shimmer loading placeholder | | Spinner | @mappoh/nova/spinner | Loading spinner | | Breadcrumb | @mappoh/nova/breadcrumb | Navigation breadcrumbs | | Command Palette | @mappoh/nova/command-palette | Cmd+K searchable command overlay with custom positioning | | Editor | @mappoh/nova/editor | Markdown editor with split/write/preview modes | | Navbar | @mappoh/nova/navbar | Responsive navbar with hamburger menu, mobile drawer, drawerClass, and rich content cloning | | Notification Center | @mappoh/nova/notification-center | Notification drawer with badge count | | Bottom Sheet | @mappoh/nova/bottom-sheet | Mobile-first slide-up overlay with snap points and drag-to-dismiss | | Toolbar | @mappoh/nova/toolbar | Premium action bar with overflow, roving tabindex, responsive sizing | | Button | @mappoh/nova/button | Styled button with variants, loading state, and spring press animation | | Input | @mappoh/nova/input | Text input with label, helper text, error state, and icons | | Textarea | @mappoh/nova/textarea | Multi-line input with auto-resize and character counter | | Select | @mappoh/nova/select | Custom dropdown select with search, keyboard nav, and option groups | | Checkbox | @mappoh/nova/checkbox | Animated checkbox with indeterminate state and label | | Link | @mappoh/nova/link | Styled anchor with underline variants and external indicator | | Card | @mappoh/nova/card | Content card with header/body/footer, tilt interaction, and elevation | | Divider | @mappoh/nova/divider | Horizontal/vertical divider with label support | | Text | @mappoh/nova/text | Typography primitive with semantic scale and truncation | | Tag | @mappoh/nova/tag | Inline tag/chip with color variants and dismiss | | Kbd | @mappoh/nova/kbd | Keyboard shortcut display with platform-aware symbols | | Stat | @mappoh/nova/stat | Statistic display with label, value, and trend indicator | | Empty State | @mappoh/nova/empty-state | Empty content placeholder with icon, text, and action | | Dialog | @mappoh/nova/dialog | Native dialog modal with confirm/alert variants and DialogHandle for external cleanup | | Segmented Control | @mappoh/nova/segmented-control | Animated tablist with sliding indicator | | Drawer | @mappoh/nova/drawer | Slide-in side panel with left/right placement | | Banner | @mappoh/nova/banner | Full-width notification bar with variants and dismiss | | Callout | @mappoh/nova/callout | Highlighted content block with collapsible mode | | List | @mappoh/nova/list | Interactive list with selection and keyboard nav | | Meter | @mappoh/nova/meter | Value meter with threshold colors and animated fill | | Chart | @mappoh/nova/chart | Bar, line, pie/donut charts with SVG rendering and CSS animations | | Combobox | @mappoh/nova/combobox | Searchable combobox with single/multi-select and keyboard nav | | Data Table | @mappoh/nova/data-table | Sortable, paginated data table with selection | | Date Picker | @mappoh/nova/date-picker | Calendar date picker with locale support | | Color Picker | @mappoh/nova/color-picker | Canvas color picker with hex/RGB/HSL input | | File Upload | @mappoh/nova/file-upload | Drag-and-drop file upload with validation | | Tree View | @mappoh/nova/tree-view | Hierarchical tree with expand/collapse and checkboxes |

Layout

| Component | Import | Description | |-----------|--------|-------------| | Stack | @mappoh/nova/layout | Vertical/horizontal flex layout with gap control | | Grid | @mappoh/nova/layout | Responsive CSS Grid with auto-fit or explicit columns | | Cluster | @mappoh/nova/layout | Inline flex for wrapping groups (tags, buttons, chips) |

Forms

| Module | Import | Description | |--------|--------|-------------| | Form Engine | @mappoh/nova/forms | Schema-driven forms with validation, touched/dirty tracking, and micro-interactions (shake, checkmark, pulse, formFx) | | WASM Validators | @mappoh/nova/forms/wasm-validators | Email, URL, credit card, IBAN validation (WASM + TS fallback) |

Animation & Canvas

| Module | Import | Description | |--------|--------|-------------| | Spring | @mappoh/nova/animation/spring | Physics-based spring animation | | Stagger | @mappoh/nova/animation/stagger | Staggered animations across element arrays | | FLIP | @mappoh/nova/animation/flip | First-Last-Invert-Play layout transitions | | Scroll Animate | @mappoh/nova/animation/scroll-animate | CSS animation-timeline with fallback | | Parallax | @mappoh/nova/animation/parallax | Scroll-driven parallax layers | | Text Reveal | @mappoh/nova/text-reveal | Staggered word/line entrance | | Particles | @mappoh/nova/canvas/particles | 2D particle system | | Dot Grid | @mappoh/nova/canvas/dot-grid | Interactive dot grid | | Noise | @mappoh/nova/canvas/noise | Simplex/Perlin noise rendering | | Virtual List | @mappoh/nova/virtual-list | DOM-recycling virtual scroller |

i18n

| Module | Import | Description | |--------|--------|-------------| | i18n | @mappoh/nova/i18n | Reactive i18n with ICU pluralization, formatNumber, formatDate, formatRelative |

Utilities

| Module | Import | Description | |--------|--------|-------------| | Utils | @mappoh/nova/utils | debounce, throttle, deepEqual, clamp, lerp, remap, uniqueId, isBrowser, isMac, isTouch, backoffDelay, wait | | A11y | @mappoh/nova/a11y | trapFocus, rovingTabIndex, announce, skipLink | | Clipboard | @mappoh/nova/clipboard | Copy/read text and HTML | | Search | @mappoh/nova/search | Full-text search with WASM fuzzy matching, themeable via CSS custom properties, headless createSearchEngine() for custom UIs | | Gesture | @mappoh/nova/gesture | Swipe, pinch, pan, long-press, tap with Pointer Events | | Drag | @mappoh/nova/drag | Sortable lists with keyboard support | | Responsive | @mappoh/nova/responsive | Breakpoint hooks, container queries, responsive CSS utilities | | Shortcuts | @mappoh/nova/shortcuts | Keyboard shortcut registry | | Lazy Load | @mappoh/nova/lazy | IntersectionObserver lazy loading | | Infinite Scroll | @mappoh/nova/infinite-scroll | Infinite scroll loading | | Scale | @mappoh/nova/theme | Mathematical type scale via CSS custom properties | | Service Worker | @mappoh/nova/sw | SW generation with caching strategies | | SW Cache | @mappoh/nova/sw/cache | Runtime cache management from main thread | | Devtools | @mappoh/nova/devtools | Component inspector and render debugging |

WASM Bridge

| Module | Import | Description | |--------|--------|-------------| | Worker Pool | @mappoh/nova/wasm | Web Worker pool for offloading WASM ops off the main thread | | Shared Buffer | @mappoh/nova/wasm | Zero-copy SharedArrayBuffer data sharing between JS and WASM workers | | Streaming Compile | @mappoh/nova/wasm | compileStreaming with module caching and precompileWasm |

WASM Accelerators

Optional Rust-compiled modules. Each has a pure TypeScript fallback.

| Module | Import | Description | |--------|--------|-------------| | Markdown | @mappoh/nova/markdown/wasm | CommonMark + GFM parser | | Noise | @mappoh/nova/canvas/noise-wasm | Batch noise with FBM | | Validation | @mappoh/nova/forms/wasm-validators | Email, credit card, IBAN, password strength | | Image | @mappoh/nova/image/wasm | Grayscale, blur, sharpen, crop, rotate, resize | | Physics | @mappoh/nova/canvas/physics-wasm | 2D particle dynamics | | Crypto | @mappoh/nova/security/wasm-crypto | Argon2id, bcrypt, PBKDF2-SHA256 | | Diff | @mappoh/nova/component/diff-wasm | LIS-based keyed list reconciliation |

SSR

| Module | Import | Description | |--------|--------|-------------| | SSR | @mappoh/nova/ssr | Declarative Shadow DOM rendering, renderToString, renderComponent, renderPage, renderWithMarkers, hydration | | Hydration | @mappoh/nova/component | hydrateTemplate() — adoptive hydration that wakes up SSR DOM with live bindings |

Testing

| Module | Import | Description | |--------|--------|-------------| | Test | @mappoh/nova/test | mount, simulate, flush, shadowSnapshot, shadowHTML, withMount, prop/state helpers |

Quick Start

import { Component, html, classMap, createRef } from '@mappoh/nova/component';
import { createNovaStore } from '@mappoh/nova/store';

const { signal } = createNovaStore();
const count = signal(0);

class Counter extends Component {
  static tag = 'my-counter';
  static styles = `
    button { padding: 8px 16px; border-radius: 6px; background: #333; color: #fff; }
    .active { background: #0066ff; }
  `;

  private ref = createRef<HTMLButtonElement>();

  render() {
    const value = count();
    return html`
      <button
        ref=${this.ref}
        class=${classMap({ active: value > 0 })}
        @click=${() => count.update(n => n + 1)}
      >
        Count: ${value}
      </button>
    `;
  }
}

Counter.define();

See CHANGELOG.md for release notes.