- Hooks: per-instance timers in useReady; cleanup for useIntersectionObserver; useWebSocket no longer reconnects after unmount/refresh, drains the queue and dispatches non-JSON messages - Modal/Popover/Dropdown: onClose only on close, Escape to close, no stray DOM props, hooks before early return, scrollbar-aware positioning, top-left/top-right dropdown positions - Elements: Toast/Search/StarRating per-instance timers, Pagination labels and empty state, Breadcrumbs titles, LinkList dividers/props, segment-wise active-link matching (new utils/link-matches-path), Table object cells - Form: Select with a default option is changeable, Input clear notifies controlled parents and copy works on textareas, Checkbox random label, NumberInputButtons runaway interval, upload prop/spread fixes - Layout: Button disabled while loading, Stack gap and Span truncate via inline styles, Img fallbackImageSrc, className/JSDoc fixes - Editors/MDX/AI: TinyMCE id/cleanup/stale handler/duplicate scripts, AceEditor debounce, markdown heights and frontmatter regex, last assistant message, AIPromptBlock prompt ref - Utils: fetchApi headers/FormData/fetchOptions/no mutation, base64 file names and read errors, slugify underscore trim, serializeQuery zero values - Tests for fetchApi, link matching, slugify and serializeQuery - AGENTS.md updated for the package layout Co-Authored-By: Claude Opus 5.5 <[email protected]>
@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:
@moduletrace:registry=https://git.tben.me/api/packages/moduletrace/npm/
Then install the package with its required peers:
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:
@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:
import { Button, Stack, Row, useStatus } from "@moduletrace/twui";
Or use deep imports, which mirror the source folder layout:
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
bun install
bun run typecheck
bun test src
bun run compile # tsc → dist/, then scripts/post-compile.ts
Publishing
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.