@mounaji_npm/ui
v0.4.2
Published
Token-driven primitive UI components for Mounaji-based projects
Maintainers
Readme
@mounaji_npm/ui
Token-driven primitive UI components for Mounaji-based projects. All styling is controlled by CSS variables from @mounaji_npm/tokens — no hardcoded colors, no Tailwind dependency.
Install
npm install @mounaji_npm/tokens @mounaji_npm/uiQuick Start
import { TokensProvider } from '@mounaji_npm/tokens';
import { Button, Card, CardBody, Input, Badge, Avatar } from '@mounaji_npm/ui';
export default function App() {
return (
<TokensProvider>
<Card>
<CardBody>
<Avatar name="Alice" size="md" />
<Badge variant="success">Active</Badge>
<Input label="Name" placeholder="Enter your name" />
<Button variant="primary">Save</Button>
</CardBody>
</Card>
</TokensProvider>
);
}
TokensProvidermust wrap your app (or the component tree using these components). Without it, CSS variables are not set and components render unstyled.
Components
Button
import { Button } from '@mounaji_npm/ui';
<Button variant="primary" size="md" onClick={handleClick}>Save</Button>
<Button variant="outline" size="sm">Cancel</Button>
<Button variant="ghost">Skip</Button>
<Button variant="destructive">Delete</Button>
<Button variant="gradient">Get Started</Button>
<Button loading>Saving...</Button>
<Button disabled>Unavailable</Button>| Prop | Type | Default | Values |
|---|---|---|---|
| variant | string | 'primary' | primary outline ghost destructive gradient |
| size | string | 'md' | sm md lg |
| loading | boolean | false | Shows spinner, disables click |
| disabled | boolean | false | — |
| onClick | function | — | — |
Card / CardHeader / CardBody / CardFooter
import { Card, CardHeader, CardBody, CardFooter } from '@mounaji_npm/ui';
<Card variant="glass">
<CardHeader>
<h3>Title</h3>
</CardHeader>
<CardBody>
Content goes here
</CardBody>
<CardFooter>
<Button>Action</Button>
</CardFooter>
</Card>| Prop | Type | Default | Values |
|---|---|---|---|
| variant | string | 'default' | default glass outline |
Input / Textarea
import { Input, Textarea } from '@mounaji_npm/ui';
<Input
label="Email"
placeholder="[email protected]"
leftIcon={<MailIcon />}
error="Invalid email"
/>
<Textarea
label="Message"
placeholder="Write your message..."
rows={4}
/>| Prop | Type | Description |
|---|---|---|
| label | string | Label above the input |
| placeholder | string | Placeholder text |
| leftIcon | ReactNode | Icon rendered on the left |
| rightIcon | ReactNode | Icon rendered on the right |
| error | string | Error message shown below |
| disabled | boolean | Disabled state |
All native <input> / <textarea> props are forwarded.
Badge
import { Badge } from '@mounaji_npm/ui';
<Badge variant="success">Active</Badge>
<Badge variant="warning">Pending</Badge>
<Badge variant="danger">Error</Badge>
<Badge variant="primary">New</Badge>
<Badge variant="accent">Beta</Badge>
<Badge variant="outline">Draft</Badge>| Prop | Type | Default | Values |
|---|---|---|---|
| variant | string | 'default' | default primary success warning danger accent outline |
Avatar
import { Avatar } from '@mounaji_npm/ui';
// Image
<Avatar src="/user.jpg" name="John Doe" size="md" />
// Initials fallback (when src is missing or fails to load)
<Avatar name="John Doe" size="lg" />
// Sizes
<Avatar name="A" size="sm" /> // 24px
<Avatar name="B" size="md" /> // 36px
<Avatar name="C" size="lg" /> // 48px
<Avatar name="D" size="xl" /> // 64px| Prop | Type | Default | Description |
|---|---|---|---|
| src | string | — | Image URL |
| name | string | '' | Used for initials fallback and alt |
| size | string | 'md' | sm md lg xl |
Progress
import { Progress } from '@mounaji_npm/ui';
<Progress value={65} label="Upload" showPercent />
<Progress value={90} color="danger" />
<Progress value={30} color="success" label="Storage" />| Prop | Type | Default | Description |
|---|---|---|---|
| value | number | 0 | 0–100 |
| label | string | — | Label above the bar |
| showPercent | boolean | false | Show 65% at end |
| color | string | 'primary' | primary success warning danger |
Skeleton
Loading placeholder with shimmer animation.
import { Skeleton } from '@mounaji_npm/ui';
<Skeleton variant="line" width="200px" />
<Skeleton variant="circle" width="40px" height="40px" />
<Skeleton variant="rect" width="100%" height="120px" />
// Compose to match your layout
<div>
<Skeleton variant="circle" width="40px" height="40px" />
<div>
<Skeleton variant="line" width="140px" />
<Skeleton variant="line" width="80px" />
</div>
</div>| Prop | Type | Default | Description |
|---|---|---|---|
| variant | string | 'line' | line circle rect |
| width | string | '100%' | CSS width |
| height | string | (auto) | CSS height |
Switch
Accessible toggle.
import { Switch } from '@mounaji_npm/ui';
import { useState } from 'react';
function Example() {
const [on, setOn] = useState(false);
return (
<Switch
checked={on}
onChange={setOn}
label="Enable notifications"
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
| checked | boolean | false | Controlled state |
| onChange | function | — | (value: boolean) => void |
| label | string | — | Label next to switch |
| disabled | boolean | false | — |
Utility: buildInlineTokens
Generate an inline style object with only the token CSS variables you need — useful for scoped overrides without a provider.
import { buildInlineTokens } from '@mounaji_npm/ui';
const style = buildInlineTokens({ colorPrimary: '#FF5733', radiusMd: '12px' });
// → { '--mn-color-primary': '#FF5733', '--mn-radius-md': '12px' }
<div style={style}>
<Button>Scoped override</Button>
</div>Theming
All components use --mn-* CSS variables. Override them via TokensProvider tokens or directly in CSS:
:root {
--mn-color-primary: #7C3AED;
--mn-radius-md: 10px;
--mn-font-family: 'Poppins', sans-serif;
}Per-instance token override (no extra provider needed):
import { buildInlineTokens } from '@mounaji_npm/ui';
<div style={buildInlineTokens({ colorPrimary: '#EF4444' })}>
<Button variant="primary">Danger zone</Button>
</div>