Files
WRNexusJS/packages/ui
ClintchizandClaude Opus 5.5 1bed8e4b74 feat(ui): component redesign pass and fixes, release ui 0.8.87
Redesign
- Shared field foundation rules (duplicated across 15 form components and
  emitted globally) are now identical everywhere, so later copies no longer
  silently override earlier redesigns.
- Drawn checkbox and radio controls, white switch thumbs (the thumb was the
  text colour, a black blob in light mode), recessed field wells, keycap
  actions in Modal, Drawer, Popover, Toaster, Pagination, Stepper, DataTable.
- Menus (Dropdown, ContextMenu, Popover, Select dropdown, Navbar panels) share
  one flat raised panel with neutral hover rows and mono section labels.
- Alerts with an accent rail and icon chip; card headers without the grey
  band; accordion, collapse, list, list group, timeline, stats, metrics,
  chat, skeleton, avatar group, clipboard, splitter, section, sidebar,
  navbar and upload progress restyled.
- Chart rebuilt: nice y-axis ticks, gridlines, rounded bars, line and area
  modes, hover tooltips, hidden series leave the scale.

Fixes
- Checkbox and radio labels toggle their input again (empty for="" broke it).
- TimePicker kept every clicked time pressed; only the chosen hour and
  minute are pressed now, and nothing is pressed before a value exists.
- ColorPicker hex readout now follows the picked colour.
- Disabled FileInput no longer shows the native file-input text.
- Date and time panels float instead of pushing content.
- ContextMenu opened at the pointer closes on scroll.
- Drawer left/top/bottom placements slide from their own edge again.
- Image-only Card no longer renders an empty body strip.
- Timeline supports item.time, current/upcoming states, sizes and
  compact/alternate variants; showcase demos use distinct variants.
- ChatBubble: delivery receipts (sending/sent/delivered/read/failed/error)
  and meta aligned to its bubble.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 16:18:13 +05:30
..

@wrnexus/ui

First-party WrNexus UI component library — a set of themeable .wrn components plus a single tokenized stylesheet.

Part of the WrNexus framework — an SSR-first, Bun-native full-stack web framework.

Overview

@wrnexus/ui ships a library of server-rendered .wrn components (layout, form controls, and feedback UI) together with one themeable stylesheet, ui.css. The components are auto-discovered by the framework router — you don't import them in code. Once the package's component directory is on the router's scan path, you mount any component in a page with data-component="<name>". Every visual is driven by var(--wrn-*) theme tokens, so components restyle instantly when the theme changes. The tiny JS surface (src/index.ts) exists only so the toolchain (CLI build + dev server) can locate the component directory and stylesheet.

The complete catalog currently contains 102 components. The generated COMPONENTS.md and component-reference.json files document every mount name, prop, inferred type, default/required status, slot, event, category, and source file directly from the packaged .wrn source.

Installation

bun add @wrnexus/ui

Private package — the machine must be authenticated to the wrnexus npm org (a read token in ~/.npmrc). Requires Bun (Node is not supported).

In practice you rarely install this directly: @wrnexus/cli and @wrnexus/dev-server already depend on it and wrn it into the router for you (see Auto-discovery).

Components

Components live as .wrn files under packages/ui/components/. The canonical mount name comes from the component declaration (for example, component Button mounts as data-component="Button"). Component lookup is case-insensitive, so existing lowercase mounts continue to work. Each component accepts a class prop (appended to its root element), and most render their body from either a named prop or the default slot.

Layout

Name Purpose Key props
container Max-width centered content wrapper class
stack Vertical column with gap gap (0–8)
hstack Horizontal row with gap gap (0–8)
grid CSS grid container see source
divider Horizontal rule class
spacer Flexible/empty spacing element see source

Core / feedback

Name Purpose Key props
button Button label, variant (default|primary|danger|ghost), size (sm|md|lg), type
input Text input see source
textarea Multi-line input see source
checkbox Checkbox see source
badge Small status badge label, variant
alert Callout box variant (info|success|danger|warning), title, message
card Padded, bordered surface class
avatar User avatar see source
spinner Loading indicator see source
disclosure Expandable details/summary see source
theme-toggle Theme switch button (binds data-wrn-theme-toggle) label

Additional controls & data display

Also shipped: select, radio, switch, progress, tag, skeleton, tooltip, table, FAQAccordion, AnnouncementBar, and BackToTop.

The PDF-defined minimum release and essential build-first set also includes typed typography, form primitives, loading actions, combobox and multi-select, time/date-time and recurring schedule controls, confirmation dialogs, data tables, filters, desktop/mobile navigation, mega menus, marketing/product/legal page shells, product and metric cards, FAQ composition, pricing comparison, SDK tabs, legal navigation, and cookie preferences.

Seo and StructuredData remain framework/page concerns rather than body components: use the native page seo { ... } block and document-head APIs so metadata is emitted in <head> instead of invalid component markup.

The authoritative, always-current list is uiComponentNames() (below), which reads the component directory at runtime.

For the full catalog, see COMPONENTS.md. The machine-readable equivalent is exported as @wrnexus/ui/component-reference.json.

Typed Navbar items

Keep navigation data in a shared TypeScript module and validate it with the package contract. NavbarItem is a discriminated union of link, dropdown, and mega; a mega item accepts every MegaMenu layout option.

import type { NavbarItem } from "@wrnexus/ui";

export const navigation = [
  { type: "link", label: "Pricing", href: "/pricing" },
  {
    type: "dropdown",
    label: "Company",
    items: [
      { label: "About", href: "/about" },
      { label: "Contact", href: "/contact" },
    ],
  },
  {
    type: "mega",
    label: "Products",
    mega: {
      variant: "icon-grid",
      panelWidth: "2xl",
      columnCount: 3,
      rail: [{ label: "All products", href: "/products" }],
      columns: [
        {
          heading: "Work",
          items: [
            {
              label: "Projects",
              href: "/products/projects",
              icon: "icon-[lucide--folders]",
              description: "Plan and deliver work",
              badge: "New",
            },
          ],
        },
      ],
      featured: {
        title: "What's new",
        actionLabel: "Explore",
        actionHref: "/new",
      },
      actionLabel: "View all products",
      actionHref: "/products",
    },
  },
] satisfies NavbarItem[];

Importing from @wrnexus/ui/navigation is also supported. Existing untyped Navbar data using children remains accepted at runtime for migration.

API

The JS module (@wrnexus/ui) exposes five helpers used by the build tooling to locate the component assets. There is no component code to import — the components are .wrn files rendered server-side.

Export Signature Returns
uiComponentsDir () => string Absolute path to the .wrn component directory (feed to buildRouter's componentDirs).
uiCssPath () => string Absolute path to ui.css.
uiCss () => string The ui.css file contents (all .wrn-* classes, themed via tokens).
uiComponentNames () => string[] Sorted list of declared built-in component names.
uiComponentPath (name: string) => string Absolute source path for a declared component name or case-insensitive alias.

./ui.css asset export

package.json also exposes the raw stylesheet as a subpath asset:

"exports": {
  ".": "./src/index.ts",
  "./ui.css": "./ui.css"
}

The framework serves this stylesheet once at /__wrnexus/ui.css, so pages get all component styles from a single request.

Component styles and motion

Components own their BEM styles in local style {} blocks and do not require a Tailwind scan. ui.css supplies only global tokens, resets, and shared primitives. Applications can still use Tailwind independently in their own source files.

The shared stylesheet gives all component boundaries consistent, GPU-friendly entry and interaction motion. Override --wrn-motion-fast, --wrn-motion-base, --wrn-motion-slow, --wrn-ease-standard, or --wrn-ease-emphasized to tune it. Hover lift is limited to precise pointing devices and prefers-reduced-motion is honored automatically.

Using the selected theme in application UI

The active theme and palette are not limited to @wrnexus/ui components. The framework exposes the resolved values as semantic CSS custom properties, so pages and custom .wrn components can use the same contract:

.account-card {
  background: var(--wrn-color-surface);
  color: var(--wrn-color-text);
  border: 1px solid var(--wrn-color-border);
}

.account-card__action {
  background: var(--wrn-color-primary);
  color: var(--wrn-color-primary-contrast);
}

Stable no-spacing helper classes are also available: wrn-bg-page, wrn-bg-surface, wrn-bg-surface-2, wrn-bg-primary, wrn-bg-secondary, wrn-text, wrn-text-muted, wrn-text-primary, wrn-text-success, wrn-text-warning, wrn-text-danger, and wrn-border.

Tailwind-authored custom markup can continue using the palette families already used by packaged components. indigo-* and violet-* resolve to primary, blue-* to info, emerald-*/green-* to success, amber-* to warning, and red-*/rose-* to danger. These aliases live at :root, so they work outside a [data-component] boundary too.

Usage

Auto-discovery

The router scans extra componentDirs (in addition to the app's own app/components) and keys components by name. Library dirs are scanned first and app/components last, so an app component of the same name shadows the library's. The CLI build (@wrnexus/cli) and dev server (@wrnexus/dev-server) both wrn the UI directory in for you:

import { buildRouter } from "@wrnexus/router";
import { uiComponentsDir } from "@wrnexus/ui";

const router = buildRouter(appDir, { componentDirs: [uiComponentsDir()] });

Mounting components in a page

Once discovered, mount any component by name via data-component. Quoted attributes (other than data-component) become string props:

<div data-component="card">
  <div data-component="badge" label="New"></div>
  <button data-component="button" label="Save" variant="primary" size="lg"></button>
  <div data-component="alert" variant="success" title="Done" message="Saved."></div>
</div>

Overrides

Ways to customize the components, in increasing order of power:

  1. Theme tokens — override CSS custom properties such as --wrn-color-primary, --wrn-color-surface, --wrn-radius-sm, etc. Every component style resolves through var(--wrn-*), so changing a token restyles everything instantly (including across theme switches).
  2. App CSS — redefine a .wrn-* class in your own stylesheet, which is loaded after ui.css and therefore wins.
  3. class prop — pass a class prop to a component; it is appended to the component's root element, letting you add per-instance classes without touching the base styles.
  4. wrnexus eject <name> — copy the component's .wrn source into your app/components, where (because app components shadow library ones) you fully own and can edit it. Use uiComponentNames() for the list of ejectable names.

Requirements / Notes

  • Bun-only — the package uses standard fs/path/url APIs but is published and consumed within the Bun-native WrNexus toolchain (Node is not supported).
  • Peer packages: components are discovered and rendered by @wrnexus/router (via componentDirs) and served by @wrnexus/dev-server / built by @wrnexus/cli.
  • Depends on @wrnexus/core (dependencies).
  • theme-toggle relies on the framework's theme runtime, which binds the data-wrn-theme-toggle attribute — no per-component JS is required.