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

@vantageos/mosaic

v0.3.1

Published

Fleet-wide MCP UI design system — 6-category taxonomy, Zod-validated, registry-gated, streaming-ready, cross-runtime (React 19 + Preact 10).

Readme

@vantageos/mosaic

Fleet-wide MCP UI design system. Zod-validated, taxonomy-organized (6 categories: progress, input, display, artifacts, confirmation, media), streaming-ready, cross-runtime React 19 + Preact 10. Built for MCP Apps (SEP-1865 extension).

Install

# React 19
npm install @vantageos/mosaic@^0.2.0 @vantageos/mosaic-tokens@^0.2.0 react react-dom

# Preact 10
npm install @vantageos/mosaic@^0.2.0 @vantageos/mosaic-tokens@^0.2.0 preact

All runtime peers are marked optional via peerDependenciesMeta — install only what your runtime needs.

Build

pnpm --filter @vantageos/mosaic build

The build script prefixes NODE_OPTIONS=--max-old-space-size=8192 automatically — no manual env export required.

Why 8 GB heap? tsup runs multiple parallel DTS (declaration emit) configs for cross-runtime outputs (React 19, Preact 10, server, tokens). Each TypeScript compiler worker holds the full type graph in memory. The combined peak exceeds Node's default 2 GB V8 limit, causing OOM crashes (FATAL ERROR: Reached heap limit Allocation failed). 8 GB gives adequate headroom on a standard CI runner (ubuntu-latest provides 16 GB RAM).

This constraint is codified locally via the build script (the NODE_OPTIONS prefix above), so it applies anywhere the script runs — including CI. Wiring it as an explicit job-level env: NODE_OPTIONS in .github/workflows/ci.yml for the build-bearing jobs (build-parity-cross-runtime, peer-resolution-smoke, npm-publish) is planned but not yet present.

Surface

| Subpath | Runtime | Use case | |---|---|---| | @vantageos/mosaic | React 19 (back-compat) | v0.1.x consumers (Sigma VP, Theta CRM) | | @vantageos/mosaic/<cat> | React 19 (back-compat) | Tree-shakable category imports v0.1.x style | | @vantageos/mosaic/react | React 19 | New v0.2.0+ React consumers — explicit runtime opt-in | | @vantageos/mosaic/react/<cat> | React 19 | Tree-shakable category imports under explicit react/ prefix | | @vantageos/mosaic/preact | Preact 10 | Mu vantage-bridge iframe, Chi gptpowerups (LLM-host target) | | @vantageos/mosaic/preact/<cat> | Preact 10 | Tree-shakable category imports under preact/ prefix | | @vantageos/mosaic/tokens | runtime-free | Re-export of @vantageos/mosaic-tokens | | @vantageos/mosaic/server | Node | createMosaicResource() MCP UI builder (runtime-agnostic) |

<cat> = progress | input | display | artifacts | confirmation | media.

Quick start

// React 19 — preferred v0.2.0+ surface
import { ProgressBar } from "@vantageos/mosaic/react/progress";
import { ConfirmDialog } from "@vantageos/mosaic/react/confirmation";
import "@vantageos/mosaic-tokens/css"; // declares --mosaic-* vars on :root

export function MyComponent({ progress, label }: { progress: number; label: string }) {
  return <ProgressBar value={progress} label={label} locale="en" />;
}
// Preact 10 — same components, preact/compat alias at build time
import { ProgressBar } from "@vantageos/mosaic/preact/progress";
import "@vantageos/mosaic-tokens/css";

export function MyComponent({ progress, label }: { progress: number; label: string }) {
  return <ProgressBar value={progress} label={label} locale="en" />;
}

Forms (v0.3.0-alpha.1)

@vantageos/mosaic/{react,preact}/forms — composite form primitives wrapping react-hook-form + @hookform/resolvers/zod. Default validation mode is onBlur (Chi co-validated, Day 102 DM). Cross-runtime: same imports, React 19 path or Preact 10 path.

Install peers

npm install react-hook-form@^7.54.0 @hookform/resolvers@^3.10.0

Both peers are declared optional in peerDependenciesMeta — only install them if you use the forms surface.

Quick start

import { z } from "zod";
import {
  useMosaicForm,
  FormProvider,
  FormField,
  ErrorDisplay,
  SubmitButton,
} from "@vantageos/mosaic/react/forms";

const schema = z.object({
  email: z.string().email("Invalid email"),
  age: z.number().min(18, "Must be 18+"),
});

export function SignupForm({ onSubmit }: { onSubmit: (data: z.infer<typeof schema>) => void }) {
  const form = useMosaicForm({
    schema,
    defaultValues: { email: "", age: 0 },
    // mode defaults to "onBlur" — Mosaic doctrine
  });

  return (
    <FormProvider form={form}>
      <form onSubmit={form.handleSubmit(onSubmit)}>
        <FormField name="email">
          {({ field, fieldState }) => (
            <label>
              Email
              <input {...field} value={(field.value as string) ?? ""} />
              <ErrorDisplay error={fieldState.error} />
            </label>
          )}
        </FormField>
        <SubmitButton label="Sign up" />
      </form>
    </FormProvider>
  );
}

Surface

| Export | Purpose | |---|---| | useMosaicForm({ schema, defaultValues, mode? }) | Wrapper around useForm + zodResolver. Returns RHF's UseFormReturn extended with mosaicSchema + mosaicMode. | | <FormProvider form={...}> | Wraps RHF's FormProvider AND a Mosaic-specific context. Use useMosaicFormContext() inside descendants. | | <FormField name="...">{({ field, fieldState, formState }) => ...}</FormField> | Render-prop wrapper around RHF's Controller. | | <ErrorDisplay error={...} messageMap={...} /> | Single-field error formatter. Renders nothing when no error. Priority: error.messagemessageMap[type] → generic fallback. | | <SubmitButton label="..." loadingLabel="..." /> | Bound to the surrounding FormProvider. Disabled while invalid OR submitting. | | <Input name="..." type="text\|email\|password\|number\|url" label="..." placeholder? disabled? autoComplete? /> | Single-field <input> bound to the surrounding FormProvider. label is required (consumer-driven i18n). Emits aria-invalid + aria-describedby on validation error. |

Field primitives (Textarea, Select, Checkbox, MultiSelect, RadioGroup, FieldArray) land in T12-T20 — see docs/v0.3.0-plan.md §7. | <Textarea name="..." rows? maxLength? autoResize? placeholder? disabled? label? /> | Multi-line text input field primitive. rows default 3, maxLength enforced via shared logic gate, optional autoResize grows to content. aria-invalid + aria-describedby on error. |

Remaining field primitives (Input shipped T11, Select, Checkbox, MultiSelect, RadioGroup, FieldArray) land in T13-T20 — see docs/v0.3.0-plan.md §7. | useFieldArray({ name, control? }) | Thin wrapper around RHF's useFieldArray. Returns { fields, append, remove, move, swap } + the rest of RHF's native return for advanced cases. Reads control from FormProvider when omitted. | | <FieldArray name="...">{({ field, index }, { append, remove, move, swap, fields }) => ...}</FieldArray> | Render-prop wrapper around useFieldArray. Emits role="list" shell + role="listitem" per row, keyed by RHF's stable field.id (NOT array index). Powers PromptForm Add Variable, Hermes variable mappings, Demeter filter chips. |

| <Checkbox name="..." label="..." indeterminate? description? disabled? /> | Boolean checkbox primitive. indeterminate=truearia-checked="mixed" + DOM .indeterminate=true via ref. description wired via aria-describedby. aria-invalid + aria-describedby on error. | | <RadioGroup name="..." label="..." options={[...]} orientation? disabled? /> | WCAG-AA radiogroup. Roving tabIndex, Arrow key selection sync, Home/End, Space/Enter. |

Remaining field primitives (Input, Textarea, Select, MultiSelect) land in T11-T15 + T18-T20 — see docs/v0.3.0-plan.md §7.

RadioGroup

Mutually exclusive single-choice field. Keyboard navigation follows WAI-ARIA radiogroup pattern (§3.10): Arrow keys move focus AND select simultaneously (roving tabindex). Disabled options are skipped during navigation.

import { z } from "zod";
import {
  useMosaicForm,
  FormProvider,
  RadioGroup,
} from "@vantageos/mosaic/react/forms";

const schema = z.object({
  plan: z.string().min(1, "Please select a plan"),
});

export function PlanSelector() {
  const form = useMosaicForm({
    schema,
    defaultValues: { plan: "" },
  });

  return (
    <FormProvider form={form}>
      <form onSubmit={form.handleSubmit(console.log)}>
        <RadioGroup
          name="plan"
          label="Select a plan"
          options={[
            { value: "free", label: "Free", description: "Up to 3 projects" },
            { value: "pro", label: "Pro", description: "Unlimited projects" },
            { value: "team", label: "Team", description: "Multi-user", disabled: false },
          ]}
          orientation="vertical"
        />
      </form>
    </FormProvider>
  );
}

WCAG-AA contract:

  • role="radiogroup" + aria-labelledby on container
  • role="radio" + aria-checked + roving tabIndex per option
  • aria-labelledby per option → its visible label span
  • aria-describedby per option → its description span (when present)
  • aria-disabled on disabled options; disabled options skipped in arrow nav
  • aria-orientation reflects orientation prop

Field primitives (Textarea, Select, MultiSelect, RadioGroup, FieldArray) land in T12-T20 — see docs/v0.3.0-plan.md §7. | <MultiSelect name="..." label="..." options={...} placeholder? disabled? searchable? maxItems? /> | Multi-value dropdown. RHF value is string[]. Selected items render as removable chips (Backspace/Delete on trigger removes last, per-chip × removes specific). WCAG-AA combobox (role=combobox aria-multiselectable=true), Arrow/Enter keyboard nav, optional case-insensitive search, optional maxItems cap. |

Remaining field primitives (Input + Textarea + MultiSelect shipped T11/T12/T15; Select, Checkbox, RadioGroup, FieldArray) land in T13-T20 — see docs/v0.3.0-plan.md §7. | <Select name="..." label="..." options={[...]} /> | Single-select dropdown (combobox+listbox APG). Optional searchable prop enables in-popup filter. Full keyboard nav + type-ahead. WCAG-AA strict. |

Field primitives (Input, Textarea, Checkbox, MultiSelect, RadioGroup, FieldArray) land in T11, T14-T20 — see docs/v0.3.0-plan.md §7.

Server (MCP UI)

import { createMosaicResource } from "@vantageos/mosaic/server";

const resource = createMosaicResource({
  componentId: "ProgressBar",
  props: { value: 42, label: "Loading…", locale: "en" },
});
// returns a SEP-1865-compliant MCP UI resource with text/html;profile=mcp-app MIME

Components

Display

VirtualList

Generic virtualized list for large datasets. Uses @tanstack/react-virtual v3 (already bundled via TableView). Cross-runtime: React 19 + Preact 10.

import { VirtualList } from "@vantageos/mosaic/react/display";
// Preact: import { VirtualList } from "@vantageos/mosaic/preact/display";

type Task = { id: string; title: string; status: string };

<VirtualList<Task>
  items={tasks}
  itemHeight={56}               // fixed px height
  renderItem={(task, index) => (
    <div key={task.id}>
      <span>{task.title}</span>
      <span>{task.status}</span>
    </div>
  )}
  onRowClick={(task, index) => router.push('/tasks/' + task.id)}
  overscan={5}                  // rows outside viewport (default 5)
  className="task-list"
  locale="en"                   // "en" | "fr"
/>

Props

| Prop | Type | Default | Description | |---|---|---|---| | items | T[] | required | Items to render | | itemHeight | number | -- | Fixed row height px (mutually exclusive with estimateSize) | | estimateSize | (index) => number | -- | Variable height estimator | | renderItem | (item: T, index: number) => ReactNode | required | Row renderer | | onRowClick | (item: T, index: number) => void | undefined | Click handler — triggers WCAG-AA a11y (role=button + tabIndex=0 + Enter/Space) | | overscan | number | 5 | Rows outside visible area | | className | string | undefined | CSS class on scroll container | | locale | "en" or "fr" | "en" | Built-in string locale |

Doctrine

  • Pattern 1 (Zod runtime validation) — every component validates props at the MCP host boundary; invalid props render an a11y fallback (role="alert"), never white-screen.
  • Pattern 2 (6-category taxonomy) — components live under exactly one category. Bilingual category.meta.json per category.
  • Pattern 3 (Registry-gated)registry.yaml declares every component; CI gate ensures parity between source and registry.
  • Pattern 4 (Streaming-hydration ready) — components opt-in to MCP Apps streaming via getStreamFor() callbacks.

See Mosaic Architecture Standard v1.1 §3 for the 4 patterns détails.

i18n

Consumer-driven i18n contract: components NEVER render raw alphabetic text as JSXText children. All user-visible strings flow in as props from the host app. Enforced by the no-hardcode-strings.test.ts vitest AST gate.

// Good — caller provides the localized label
<ProgressBar value={50} label={t("upload.progress")} locale={i18n.language} />

// Bad — AST scan blocks this at CI
// <ProgressBar value={50} label="Uploading…" />

Bundle sizes (v0.2.0)

| Surface | gz | |---|---| | @vantageos/mosaic-tokens/dist/index.js | 649 B (87% under the 5 KB gate) | | @vantageos/mosaic-tokens/src/tokens.css | 560 B (81% under the 3 KB gate) | | Per-component subpath (React) | tree-shakeable, see size-limit.json |

License

MIT. © VantageOS / ElPi Corp.

Changelog

See repo root CHANGELOG.md.