@senkenmaru/ui
v0.3.3
Published
Universal React / React Native components that make product-wide UX policies the default behavior (not an option to remember)
Maintainers
Readme
@senkenmaru/ui
Universal React / React Native components that make product-wide UX policies the default behavior — not an option to remember.
What this is
A design system + component library that runs on the same JSX for Web (Vite / Next.js) and Native (React Native / Expo). One API surface, one mental model, one a11y / theming story.
What makes it different
- Tier discipline (L0 → L3): every component is placed by a deterministic 4-question test. Imports flow downward only — there is no "this thing imports that thing imports this" tangle to debug.
- Composition First: higher-tier components build on lower-tier ones. When
Button's focus color changes, every place that usesButton(Pagination, Modal close, Toast close...) inherits it. No "did I update all 12 places" panic. - UX policies baked in, not opt-in: focus visibility, axe-validated contrast, aria-current page hints, keyboard escape, focus trap on modals — all configured by default. You don't have to remember to wire them.
- Light / Dark via tokens: every color is referenced through
theme.color.*. Theme switching is one variable swap, andaxe-corecolor-contrast runs in the showcase to keep both themes accessible.
Tier structure
| Tier | Directory | Role | Example |
|---|---|---|---|
| L0 Primitives | primitives/ | Single semantic atom | Button, Text, Avatar, Stack |
| L1 Combinators | combinators/ | Wraps primitives with meaning | Banner, Field, Card, Tabs |
| L2 Patterns | patterns/ | Stateful complex UI | Modal, DatePicker, Table, Combobox |
| L3 Templates | templates/ | Page-level chrome (singletons) | AppBar, GlobalNav, StickyActionBar |
The full deterministic placement rule is documented in the showcase under Guidelines → Tier.
Installation
bun add @senkenmaru/ui @senkenmaru/theme
# or pnpm / npm / yarnPeer dependencies: react >=19, react-native >=0.78, react-native-unistyles ^3.0.0 (for theming), react-native-svg ^15 (Native only, for icons).
Platform support
Most components run universally on Web and Native. The exceptions are platform-bound L3 templates:
| Component | Web | Native | Native alternative |
|---|---|---|---|
| AppBar | ✅ | — | React Navigation Stack.Navigator header |
| GlobalNav | ✅ | no-op stub | React Navigation Drawer.Navigator / Tab.Navigator |
| StickyActionBar | ✅ (sticky) | ✅ (parent flex layout) | — |
| Slider | ✅ | — | @react-native-community/slider |
| FileUpload | ✅ | — | expo-document-picker |
Native-bound platform conventions (gesture-driven nav chrome, document pickers, native sliders) intentionally route through dedicated React Native libraries — duplicating them universally would lose iOS/Android platform feel.
Setup
Wrap your app in the theme provider once:
import { SenkenmaruProvider } from '@senkenmaru/theme';
import { ToastProvider } from '@senkenmaru/ui';
export const App = () => (
<SenkenmaruProvider adaptiveThemes>
<ToastProvider>
<YourApp />
</ToastProvider>
</SenkenmaruProvider>
);Usage
import { Banner, Button, Field, Stack, TextInput } from '@senkenmaru/ui';
const SignInForm = () => {
const [email, setEmail] = useState('');
return (
<Stack direction="column" gap="md">
<Banner tone="info" icon title="メンテナンス予定">
2026-05-10 03:00-05:00 に一時停止します。
</Banner>
<Field label="メールアドレス" required>
<TextInput value={email} onChangeText={setEmail} placeholder="[email protected]" />
</Field>
<Button variant="primary" onPress={submit}>
サインイン
</Button>
</Stack>
);
};@senkenmaru/ui exports a flat barrel — never reach into @senkenmaru/ui/primitives/*. Deep paths are guarded by an import-boundary lint.
Showcase / development
Run the showcase app to see every component's variants, props, a11y status, and live demos:
bun run dev --filter=@senkenmaru/showcaseModes:
- Components: 50+ components grouped by tier with axe-core a11y validation per variant
- Guidelines: Tier rules, Spacing, Motion, Sizes, Typography, Z-Index, Colors
- Recipes: Real-world page compositions (Sign in, Settings form, Dashboard, Empty state, Error page, Profile page, Landing)
- Studio: A page builder where you compose components into a JSX export — paste it into your codebase or hand it to an AI to implement
Design philosophy quick reference
- Specifying default behavior > documenting "remember to do X": if
<Button>doesn't auto-handle focus, no contributor will hand-add it consistently. The component does it once, every consumer benefits. - One API for Web + Native: write
<Stack direction="row" gap="md">once. The same code renders flex on Web andViewon Native. No platform-specific component versions to maintain. - Tokens over magic numbers: every space / radius / color is named (
space.md,radius.lg,color.tonal.info.background). Theme switching is automatic; ad-hocpadding: 17is an anti-pattern. - Composition over duplication: if you need a new
<PageButton>, ask first — can<Button square>express it? A new component is only added when existing ones genuinely can't, and the rationale is left in JSDoc.
Status
Pre-1.0 (early access). APIs may change between minor versions until tagged stable. Feedback and issue reports during this phase are very welcome.
License
MIT
