Files
WRNexusJS/packages/ui/README.md
T
2026-07-12 15:55:18 +05:30

157 lines
8.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# @wrnexus/ui
> First-party Wire 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(--wire-*)` 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.
## Installation
```bash
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 wire it into the router for you
(see [Auto-discovery](#auto-discovery)).
## Components
Components live as `.wrn` files under `packages/ui/components/`. The mount name
is the **lowercase file basename** (e.g. `button.wrn``data-component="button"`).
Each 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` (08) |
| `hstack` | Horizontal row with gap | `gap` (08) |
| `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-wire-theme-toggle`) | `label` |
### Additional controls & data display
Also shipped: `select`, `radio`, `switch`, `progress`, `tag`, `skeleton`,
`tooltip`, and `table`.
The authoritative, always-current list is `uiComponentNames()` (below), which reads
the component directory at runtime.
## API
The JS module (`@wrnexus/ui`) exposes four 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 `.wire-*` classes, themed via tokens). |
| `uiComponentNames` | `() => string[]` | Sorted list of built-in component names (e.g. for `wrnexus eject` listing). |
### `./ui.css` asset export
`package.json` also exposes the raw stylesheet as a subpath asset:
```json
"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.
## 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 wire the UI directory in for you:
```ts
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:
```html
<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 `--wire-color-primary`,
`--wire-color-surface`, `--wire-radius-sm`, etc. Every component style resolves
through `var(--wire-*)`, so changing a token restyles everything instantly
(including across theme switches).
2. **App CSS** — redefine a `.wire-*` 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`](../router) (via `componentDirs`) and served by
[`@wrnexus/dev-server`](../dev-server) / built by [`@wrnexus/cli`](../cli).
- Depends on [`@wrnexus/core`](../core) (`dependencies`).
- `theme-toggle` relies on the framework's theme runtime, which binds the
`data-wire-theme-toggle` attribute — no per-component JS is required.