rogue

API

Six entry points. Everything below has TypeScript declarations in node_modules/@jjordy/rogue/**/*.d.ts when you install.

@jjordy/rogue

The runtime. Import in any component file.

import {
  signal, effect, memo, untrack, batch,
  onCleanup, onMount,
  createContext, provide, useContext,
  defineComponent, emit,
  For,
} from '@jjordy/rogue'

Reactivity

  • signal(initial: T): [() => T, (next: T | (prev: T) => T) => void]
  • effect(fn: () => void): () => void — returns dispose
  • memo(fn: () => T): () => T
  • untrack(fn: () => T): T
  • batch(fn: () => T): T
  • onCleanup(fn: () => void): void
  • onMount(fn: () => void): void — fires after render's DOM is connected

Components

  • defineComponent(name?, render, options?)name is optional; inferred from filename if omitted.
  • emit(host, name, detail?, opts?) — dispatches a CustomEvent that bubbles + composed by default (crosses shadow boundaries).
  • For({ each, by, children }) — keyed list reconciliation.

Context

  • createContext(default): Context
  • provide(context, value) — call inside a render
  • useContext(context) — walks ancestor chain across shadow boundaries

@jjordy/rogue/router

import { useRoute, navigate, mount } from '@jjordy/rogue/router'
  • useRoute(): { url, params, query, data } — all signal getters
  • navigate(path, opts?: { replace?: boolean; scroll?: boolean }): void — scrolls to top by default; pass scroll: false for filter/tab UIs
  • mount(target, opts?) — pushState + popstate + click capture; hydrates if target has SSR'd content and initialData is passed

@jjordy/rogue/forms

import {
  useForm, defineActions,
  redirect, invalid, formError,
} from '@jjordy/rogue/forms'
  • useForm(action, options?) — returns a FormApi with spreaders (props, field) and reactive accessors (errors, formError, submitting, values, touched, validating) plus submit() + reset()
  • defineActions(map) — wraps an actions map so each entry knows its name (required for server-action dispatch)
  • redirect(path, opts?) — return from run() to navigate after success
  • invalid({ field: message }) — return to surface server-side field errors
  • formError(message) — return to surface a form-level error not tied to any field

See the Forms + mutations guide for the full walkthrough.

@jjordy/rogue/testing

import { setupDOM, mount, fireEvent, query, tick } from '@jjordy/rogue/testing'
  • setupDOM(opts?) — installs a linkedom-backed DOM on globalThis. Idempotent.
  • mount(tag, attrs?): HTMLElement
  • fireEvent(el, type, init?): boolean
  • query/queryAll(el, selector) — pierces shadow DOM
  • tick(): Promise — drain two microtask turns

@jjordy/rogue/vite

import { rogue, rogueRouter, rogueSsr } from '@jjordy/rogue/vite'
  • rogue() — compiles JSX/TSX into custom-element registrations
  • rogueRouter() — file-system routing + per-page ./.types codegen
  • rogueSsr() — runs SSR + the server-action handler inside vite dev, so npm run dev behaves like production (HTML rendered server-side, form POSTs dispatched). Add this if you want full SSR during development; skip it for client-only setups.

@jjordy/rogue/server

import { render, handleAction } from '@jjordy/rogue/server'

// GET request:
const { html, status } = await render(url, vite, { request })

// POST request with ?_action=:
const out = await handleAction(url, vite, request)
// out: { status, headers, body }
  • render(url, vite, opts?) — SSR a route. opts = { request, prefetchedData, form }. Returns { html, status }.
  • handleAction(url, vite, request) — dispatches an action POST. Parses FormData, runs the schema, calls action.run(), content-negotiates JSON (with-JS) vs HTML re-render (no-JS). Returns { status, headers, body }.