@aracreate/arm-ui
v4.0.0
Published
A modern, lightweight, and customizable React UI library built with TypeScript, UnoCSS, and Storybook
Maintainers
Readme
ARM UI Library
The shared React component library for the ARM platform, published to npm as
@aracreate/arm-ui. It is the single
source of the platform's design system — 42 components plus the UnoCSS preset that carries the brand
scales — consumed by arm-core-fe, the calendar frontend and the admin frontend so all three look
like one product.
- Ships the components and the UnoCSS preset (
ac_preset) that generates their classes; a consuming app installs both or the components render unstyled - Purpose-built for ARM rather than general-purpose: the catalogue is calendar-, auth- and
dashboard-shaped (
SyncDetailsDialog,ImportCalendarsDialog,BigCalendarView,OtpVerifyStep) - Every component has a colocated test, and all 42 are covered by axe accessibility tests
- Storybook is the browsable catalogue and the place to develop a component in isolation
This library is consumed as a pinned npm dependency, not a workspace link. A change here has to be published and the version bumped in each consuming app before it is visible to them — a library change and a consumer change cannot land in one commit, and a new prop will compile silently against the previously published types until the bump happens.
Stack
| Layer | Tool |
| --- | --- |
| Framework | React 19 (peer: >=18) |
| Bundler | tsup — ESM + CJS + .d.ts |
| Styling | UnoCSS, shipped as the ac_preset preset and a pre-built style.css |
| Primitives | Radix Themes and @radix-ui/react-icons, re-exported from this package |
| Calendar grid | react-big-calendar, with brand overrides shipped separately |
| Catalogue | Storybook |
| Tests | Vitest — two configs (components, Storybook) — plus axe accessibility tests |
| Release | By hand: VERSION, CHANGELOG.md, then npm publish |
| Language | TypeScript |
| Package manager | pnpm |
Architecture
src/
├── index.ts ← Public entry — re-exports components, types, theme and class helpers
├── components/ ← The 42 components, each with a colocated *.test.tsx
│ ├── index.ts ← Named exports; this file defines the public component API
│ ├── tokens.css ← Design tokens, shipped to consumers as /tokens.css
│ └── big-calendar-overrides.css ← react-big-calendar brand overrides, shipped separately
├── preset.ts ← ac_preset — wraps presetWind4 and adds the brand scales
├── styles/ ← radix-brand-tokens.css, theme.css
├── lib/ ← theme object, get_color, and the class-building helpers
├── types/ ← Shared prop types (Size, Variant, polymorphic helpers)
└── stories/ ← Storybook storiesPackage exports
| Entry | Contents |
| --- | --- |
| . | Components, types, theme/get_color/colors, class helpers |
| ./preset | ac_preset for a consuming app's uno.config.ts |
| ./style.css | Pre-built stylesheet — the alternative to scanning library sources |
| ./tokens.css | Design tokens alone |
| ./big-calendar-overrides.css | react-big-calendar brand overrides |
Only dist/ is published (files: ["dist"]), so anything a consumer needs must be exported from
src/index.ts or emitted by the CSS build — a file that exists in src/ but is not reachable
through an export does not ship.
The component catalogue
Grouped by what they are for; src/components/index.ts is the authoritative list, and Storybook
is the way to actually look at them.
| Group | Components |
| --- | --- |
| Calendar | BigCalendarView, CalendarMergedView, MonthGrid, MiniMonthPicker, CalendarToolbar, CalendarDayHeader, CalendarPickList, EventBlock |
| Sync & accounts | SyncDetailsDialog, SyncPreviewRail, ImportCalendarsDialog, AccountCalendarsDialog, ConnectedAccountCard, AccountCard, AddAccountMenu, ConnectProviderList, ConnectProviderRows, PausedBadge |
| Auth & onboarding | AuthCard, BrandPanel, OtpInput, OtpVerifyStep, OnboardingStepDots, WizardStepper |
| Shell | Sidebar, Topbar, SearchOverlay |
| Data display | DataTableRow, MetricCard, AppCard, ActivityRow, AccentHeader, CardFooter, IconTile |
| Feedback & state | Toast, ConfirmDialog, Skeleton, EmptyCard, DashboardErrorCard |
| Disclosure & sheets | Accordion (+ AccordionItem, AccordionTrigger, AccordionContent), Drawer (+ DrawerContent, DrawerHeader, DrawerTitle, DrawerDescription, DrawerClose, DrawerDefaultClose) — built on the Radix primitives Radix Themes lacks |
| Icons | ProviderIcon, GoogleIcon, MicrosoftIcon, plus the whole Radix icon set (Cross2Icon, ChevronDownIcon, …) |
| Basics | The Radix Themes components, re-exported — see below |
The basics
Button, Text, Flex, TextField, Dialog, Select and the rest of the basic Radix Themes
components are exported from this package too — import them from @aracreate/arm-ui, not from
@radix-ui/themes. So are all the Radix icons.
They are the identical Radix objects, not wrappers, so behaviour and props are Radix's own and its
docs apply. src/components/primitives.ts is the list; a component becomes a real wrapper only when ARM
needs something Radix does not give, and that edit is then made here alone.
Two names differ from Radix. Radix Link is exported as TextLink (react-router's Link shares
files with it). Skeleton is this library's own, not Radix's. Theme is not exported at all —
UIProvider owns it. primitives.test.ts fails on any Radix export that is neither re-exported nor
named there, so upgrading Radix cannot add a component silently.
Installation and setup in a consuming app
pnpm add @aracreate/arm-uiPeer dependencies: react and react-dom (>=18), react-router-dom (>=7), unocss,
@unocss/preset-wind4, @unocss/preset-attributify (all >=0.60), and @radix-ui/react-icons
(>=1).
Then wire the preset into the app's uno.config.ts:
import { defineConfig } from "unocss";
import { ac_preset } from "@aracreate/arm-ui/preset";
export default defineConfig({
presets: [ac_preset()],
content: {
pipeline: {
include: [
"src/**/*.{ts,tsx}",
// Scan library sources so UnoCSS generates every class the components use
"node_modules/@aracreate/arm-ui/src/**/*.{ts,tsx}",
],
},
},
});The library scan path is not optional. UnoCSS only generates CSS for class names it finds in scanned files, and the components' classes live in library sources the app never imports directly — omit the path and components render unstyled. The alternative is to skip scanning and import the pre-built stylesheet instead:
import "@aracreate/arm-ui/style.css";Use ac_preset(), never a bare presetWind4() — the preset is what adds the brand scales, and the
consuming apps' ESLint configs fail the build on a direct @unocss/preset-wind4 import and on
stock-palette classes (text-gray-500, bg-blue-600) for exactly this reason.
Commands
The Makefile is the entry point (make help lists the targets); the targets
run the package.json scripts below.
make install # pnpm install --frozen-lockfile
make setup # install, and use the repo's git hooks (scripts/hooks)
make dev # build CSS once, then tsup --watch
make build # build:js (tsup) + build:css (UnoCSS + token CSS copy)
make test # component tests (vitest.components.config.ts)
make lint # eslint src, check only
make storybook # Storybook on :6006 — the component catalogue
make release # check VERSION, package.json and CHANGELOG.md agree; print the steps
make clean # remove dist/ and other build output
make conventions-check # the ARM repo rulesScripts with no target of their own:
pnpm test:storybook # Storybook tests (vitest.config.ts) — a genuinely separate suite
pnpm type-check # tsc --noEmit
pnpm check:dist # the built ESM bundle's export list
pnpm format # prettier --writeprepublishOnly runs clean, build and check:dist, so a publish cannot ship a stale dist/.
Conventions
Repo conventions (file headers, naming, versioning, Makefile targets) follow
aracreate-conventions, with ARM's own
rules in arm-docs docs/TEMPLATE-CONFORMANCE.md; make conventions-check checks them. VERSION is
the version's single source, bumped by hand with its CHANGELOG.md entry.
Project-specific rules:
- Every class a component renders must be reachable by the CSS build. A class assembled at
runtime from fragments UnoCSS cannot see will not exist in
style.css. - Add a colocated
*.test.tsxwith the component, including its axe accessibility assertion. - Bump and publish before a consumer can use a change — see the pinned-dependency note above.
Deeper internals — the tsup build, why there are two Vitest configs, how to add a component, the
token system, and the publishing flow — are in docs/developer.md, which this README
deliberately does not duplicate.
License
Proprietary — see LICENSE, Copyright (C) 2026, araCreate Group.
