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

@arclux/prism

v1.2.2

Published

Auto-generate framework wrappers (React, Vue, Svelte, Angular, Solid, Preact) and HTML/CSS examples from Lit web components

Downloads

463

Readme

@arclux/prism

CI npm license node

Auto-generate framework wrappers and HTML/CSS examples from Lit web components.

Write your component once as a Lit custom element. Prism reads the source and generates idiomatic wrappers for React, Vue, Svelte, Angular, Solid, and Preact — plus standalone HTML/CSS snippets with optional design-token resolution. No AST libraries, no build step, just regex-based parsing that ships as plain ESM.

What it does

Given a Lit component like this:

class ArcButton extends LitElement {
  static properties = {
    variant: { type: String, reflect: true },
    disabled: { type: Boolean, reflect: true },
  };

  constructor() {
    super();
    this.variant = 'primary';
    this.disabled = false;
  }

  static styles = css`
    :host { display: inline-flex; }
    :host([variant="primary"]) { background: var(--arc-color-primary); }
    :host([variant="secondary"]) { background: var(--arc-color-secondary); }
  `;

  render() {
    return html`<button class="btn"><slot></slot></button>`;
  }
}
customElements.define('arc-button', ArcButton);

Prism generates:

| Output | What you get | |--------|-------------| | React | TypeScript wrapper using @lit/react createComponent with a typed ButtonProps interface and 'primary' \| 'secondary' enum for variant | | Vue 3 | .vue SFC with defineProps generics and withDefaults | | Svelte 5 | .svelte component using $props() runes | | Angular | Standalone component with @Input() decorators and CUSTOM_ELEMENTS_SCHEMA | | Solid | .tsx component using splitProps() for reactivity-safe forwarding | | Preact | .tsx component with native custom element support | | HTML | Static snippet wrapped in a <span> or <div> (based on host display), slots replaced with placeholder text | | Inline HTML | Same snippet with all var() tokens resolved to literal values and styles inlined | | CSS | Shadow DOM CSS transformed to light DOM (:host.arc-button, scoped inner selectors) | | CSS bundle | All components combined into a single arc-ui.css with design tokens |

Enum values are auto-detected from :host([variant="value"]) patterns in the CSS. Props, defaults, types, events, and interactivity level are all extracted automatically.

Installation

npm i -D @arclux/prism

Requires Node.js 18+. No peer dependencies — the only runtime dependency is chokidar for watch mode.

Usage

# Generate all components defined in prism.config.js
npx prism

# Watch mode — regenerate when source files change
npx prism --watch

# Process a single component file
npx prism path/to/button.js

# Use a custom config path
npx prism --config ./custom.config.js

All flags also have short forms: -w for --watch, -c for --config.

Configuration

Create a prism.config.js in your project root. Every section except components and tiers is optional — include only the outputs you need:

export default {
  // ── Source ────────────────────────────────────────
  prefix: 'arc',
  components: 'packages/web-components/src',
  tiers: ['content', 'reactive', 'application'],
  ignore: ['**/index.js', '**/shared-styles.js', '**/icons/**'],

  // ── Framework wrappers (all optional) ─────────────
  react: {
    outDir: 'packages/react/src',
    wcPackage: '@arclux/arc-ui',
    barrels: true,
  },

  vue: {
    outDir: 'packages/vue/src',
    wcPackage: '@arclux/arc-ui',
    barrels: true,
  },

  svelte: {
    outDir: 'packages/svelte/src',
    wcPackage: '@arclux/arc-ui',
    barrels: true,
  },

  angular: {
    outDir: 'packages/angular/src',
    wcPackage: '@arclux/arc-ui',
    barrels: true,
  },

  solid: {
    outDir: 'packages/solid/src',
    wcPackage: '@arclux/arc-ui',
    barrels: true,
  },

  preact: {
    outDir: 'packages/preact/src',
    wcPackage: '@arclux/arc-ui',
    barrels: true,
  },

  // ── HTML/CSS outputs (optional) ───────────────────
  html: {
    outDir: 'packages/html/examples',
    baseCSS: 'shared/tokens.css',
    inlineVariant: true,
  },

  css: {
    outDir: 'packages/html/css',
    baseCSS: 'shared/tokens.css',
  },
};

Source options

| Option | Type | Default | Description | |--------|------|---------|-------------| | prefix | string | 'arc' | Component tag prefix. Controls tag stripping (arc-buttonButton), CSS bundle filename (arc-ui.css), and custom event detection. Change this to match your own design system prefix. | | components | string | required | Root directory containing Lit component source files | | tiers | string[] | required | Subdirectories within components to scan (e.g. ['content', 'reactive']) | | ignore | string[] | [] | Patterns to skip — bare filenames (index.js), prefixed (**/index.js), or directory globs (**/icons/**) |

Framework options

Each framework section (react, vue, svelte, angular, solid, preact) accepts:

| Option | Type | Default | Description | |--------|------|---------|-------------| | outDir | string | required | Output directory for generated wrappers | | wcPackage | string | '@{prefix}/{prefix}-ui' | Package name used in import statements for the web component | | barrels | boolean | false | Append exports to tier-level and root-level barrel (index) files |

HTML options

| Option | Type | Default | Description | |--------|------|---------|-------------| | html.outDir | string | required | Output directory for HTML snippet files | | html.baseCSS | string | — | Path to design tokens CSS (used by inline variant to resolve var() references) | | html.inlineVariant | boolean | false | Also generate .inline.html files with all tokens resolved and styles inlined |

CSS options

| Option | Type | Default | Description | |--------|------|---------|-------------| | css.outDir | string | required | Output directory for per-component CSS files and {prefix}-ui.css bundle | | css.baseCSS | string | — | Path to design tokens CSS (included as :root block in the bundle) |

How parsing works

Prism uses regex-based parsing (no AST library) to extract metadata from Lit source files:

  1. Tag + class name from customElements.define('arc-button', ArcButton)
  2. Properties from static properties = { ... } — extracts name, type, and reflect
  3. Defaults from constructor() { this.variant = 'primary'; }
  4. CSS from css`...` template literals
  5. Enum values from :host([prop="value"]) patterns in the CSS
  6. Template from render() { return html...; } — supports variable inlining when templates are built from multiple html`` blocks
  7. Events from dispatchEvent(new CustomEvent('name')) calls
  8. Host display from :host { display: ... } — determines whether HTML output uses <div> or <span> wrapper
  9. Interactivity level — see below

Interactivity detection

Prism classifies each component to determine whether it can be represented as static HTML/CSS or requires JavaScript:

| Level | Meaning | HTML/CSS output? | |-------|---------|:---:| | static | Pure display, no JS needed | Yes | | hybrid | Visual works without JS, JS adds features | Yes | | interactive | Requires JS to function | No |

All components get framework wrappers regardless of interactivity level. The classification only affects HTML/CSS output.

Auto-detection

Prism looks for these signals in the source:

  • @click=, @input=, @change=, etc. in template → interactive
  • dispatchEvent(new CustomEvent(...))interactive
  • this.shadowRoot.querySelectorinteractive
  • :host { display: none }interactive
  • None of the above → static

Auto-detection is binary (static or interactive). The hybrid level requires a manual override.

Manual overrides

Add an @arc-prism JSDoc tag to the class comment:

/**
 * Code block with copy-to-clipboard button.
 * @arc-prism hybrid — renders without JS; copy button requires JS
 */
class ArcCodeBlock extends LitElement { ... }

Valid values: static, hybrid, interactive. The override is checked before auto-detection, so it always wins.

CSS transformation

The css and html outputs convert shadow DOM CSS to light DOM equivalents:

| Shadow DOM | Light DOM | |-----------|-----------| | :host | .arc-button | | :host([variant="primary"]) | .arc-button[data-variant="primary"] | | :host([disabled]) | .arc-button[disabled] | | :host(:hover) | .arc-button:hover | | :host(::before) | .arc-button::before | | :host(:not([variant="primary"])) | .arc-button:not([data-variant="primary"]) | | .btn (inner selector) | .arc-button .btn |

The inline HTML variant further resolves all var(--token) references using your design tokens CSS, and inlines the computed styles directly onto elements. Pseudo-state rules (:hover, :focus, etc.) that can't be inlined are placed in a <style> block.

Safety guarantees

  • Header check — every generated file starts with // Auto-generated by @arclux/prism — do not edit manually (or the comment equivalent for HTML/CSS). If a file exists without this header, Prism assumes it was manually written and never overwrites it.
  • Append-only barrels — barrel file updates only append new export lines. Existing exports are never removed, reordered, or modified.

Programmatic API

The parser, CSS transform, and token resolver are available as package exports:

import { parseComponent } from '@arclux/prism/parser';
import { shadowToLight } from '@arclux/prism/css-transform';
import { loadTokenMap, resolveTokens } from '@arclux/prism/resolve-tokens';

const meta = parseComponent(source, filePath, 'arc');
const lightCSS = shadowToLight(meta.css, meta.tag);

Contributing

See CONTRIBUTING.md for development setup, code style, and PR guidelines.

License

MIT © Arclight Digital, LLC