@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/novaModules
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.
