# @moduletrace/twui A modular skeletal React component framework for Tailwind CSS v4. ## Install The package is published to the Moduletrace Gitea registry. Add this to your project's `.npmrc`: ```ini @moduletrace:registry=https://git.tben.me/api/packages/moduletrace/npm/ ``` Then install the package with its required peers: ```sh bun add @moduletrace/twui react react-dom lucide-react tailwindcss ``` ### Optional peers Only install these if you use the matching components: | Feature | Packages | | ------------------------------------------------------- | ------------------------------------------------ | | `editors/AceEditor` | `ace-builds` | | `elements/RemoteCodeBlock`, `mdx/markdown/*` | `next-mdx-remote`, `remark-gfm`, `rehype-prism-plus` | | `mdx/mdx-components`, `next-js/hooks/useMDXComponents` | `@types/mdx` (dev) | | `elements/ai/*` | `openai` (types), `react-markdown` | `editors/TinyMCE` loads TinyMCE from a URL at runtime. Set it with the `base_url` prop, or with the `NEXT_PUBLIC_TINYMCE_BASE_URL` / `BUNEXT_PUBLIC_TINYMCE_BASE_URL` public env vars. ## CSS Import `base.css` once in your main stylesheet. It includes `@import "tailwindcss"`, the default theme tokens, and an `@source` rule so Tailwind generates the classes the components use. Override tokens in your own `@theme inline` block: ```css @import "@moduletrace/twui/base.css"; @theme inline { --color-primary: #e2b433; --color-primary-hover: #9e7503; --color-primary-dark: #e2b433; --color-primary-dark-hover: #f7cc59; /* ...see base.css for the full list of tokens */ } .twui-button-general { @apply rounded-full; } ``` ## Usage Import from the root entry: ```tsx import { Button, Stack, Row, useStatus } from "@moduletrace/twui"; ``` Or use deep imports, which mirror the source folder layout: ```tsx import Button from "@moduletrace/twui/layout/Button"; import Input from "@moduletrace/twui/form/Input"; import TinyMCEEditor from "@moduletrace/twui/editors/TinyMCE"; ``` Editors, MDX, Next.js helpers, the AI blocks and `RemoteCodeBlock` are **deep-import only**, so the root entry never pulls in optional peers. Component modules are marked `"use client"`, so they work in the Next.js App Router. ## Development ```sh bun install bun run typecheck bun test src bun run compile # tsc → dist/, then scripts/post-compile.ts ``` ### Playground `dev/` is a local [bunext](https://git.tben.me/Moduletrace/bunext) app that imports the library straight from `src/` (through the committed `dev/twui` symlink and a tsconfig path alias), so component edits hot-reload without running `tsc`. It has its own `node_modules` and is excluded from the published package by the `files` whitelist. ```sh cd dev bun install cd .. bun run dev # http://localhost:7010 ``` Install the library dependencies at the repo root first: the symlinked sources resolve `react`, `tailwind-merge`, `lucide-react` and the optional peers from the root `node_modules`. Other useful scripts: ```sh bun run dev:types # tsc --watch, for consumers working against dist/ bun run dev:typecheck # typecheck the playground pages and the sources they import ``` ### Publishing ```sh export GITBEN_NPM_TOKEN=... ./publish.sh "Commit message" ``` `publish.sh` typechecks, tests, compiles, commits, pushes, and runs `bun publish`. Bump `version` in `package.json` first.