@imc0nt0/mirror
v0.1.6
Published
[](https://badge.fury.io/js/%40imc0nt0%2Fmirror) [](https://opensource.org/licenses/MIT) [ - Border color changes on hover (
#d4f1fd) - Focus highlight border (
#b8e8fd) - Optimized for performance (no motion effects)
IconButton
Icon-only button component using Bootstrap Icons.
import { IconButton } from '@imc0nt0/mirror';
// Basic usage
<IconButton icon="bi-heart-fill" variant="primary" />
<IconButton icon="bi-trash-fill" variant="danger" />
<IconButton icon="bi-search" variant="ghost" size="small" />
// Custom styling
<IconButton
icon="bi-settings"
variant="secondary"
size="large"
rounded={false}
onClick={handleSettings}
/>Props:
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| icon | string | - | Bootstrap Icons class name (e.g., 'bi-heart-fill') |
| variant | 'primary' \| 'secondary' \| 'ghost' \| 'danger' | 'ghost' | Button style variant |
| size | 'small' \| 'medium' \| 'large' | 'medium' | Button size |
| disabled | boolean | false | Disable button interaction |
| rounded | boolean | true | Use fully rounded shape |
| onClick | function | - | Click event handler |
Variants:
primary: Light blue background (#b8e8fd)secondary: Light purple background (#f4f4fe)ghost: White background with gray hover effectdanger: Transparent background with red icon
ListRow
Flexible list item component for creating structured lists and menus.
import { ListRow, ColorBlock, ListSection } from '@imc0nt0/mirror';
// Basic row with color indicator
<ListRow
left={<ColorBlock color="#ff6b6b" />}
title="List Item"
description="Item description"
showArrow
onClick={() => console.log('Clicked')}
/>
// Row with icon and switch
<ListRow
left={<i className="bi bi-bell-fill"></i>}
title="Notification Settings"
right={<Switch />}
/>
// Grouped in section
<ListSection title="Card Management">
<ListRow title="Credit Card 1" showArrow />
<ListRow title="Credit Card 2" showArrow />
<ListRow title="Debit Card 1" showArrow />
</ListSection>ListRow Props:
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| left | ReactNode | - | Left content (icons, color blocks, etc.) |
| title | string | - | Required. Main title text |
| description | string | - | Optional description text |
| right | ReactNode | - | Right content (icons, switches, text, etc.) |
| showArrow | boolean | false | Show right navigation arrow |
| divider | boolean | true | Show bottom divider line |
| onClick | function | - | Click event handler |
| disabled | boolean | false | Disable interaction |
ColorBlock Props:
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| color | string | '#b8e8fd' | Background color |
| size | number | 44 | Size in pixels |
ListSection Props:
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| title | string | - | Section title |
| children | ReactNode | - | ListRow components |
Toast
Non-blocking notification system with automatic dismissal and animations.
ToastProvider (Recommended)
Declare once at the top level of your app:
import { ToastProvider, useToast } from '@imc0nt0/mirror';
function App() {
return (
<ToastProvider>
<YourApp />
</ToastProvider>
);
}
function YourApp() {
const toast = useToast();
const handleClick = () => {
toast.success('Operation completed successfully!');
toast.error('Something went wrong!');
toast.warning('Please check your input!');
toast.info('New update available!');
};
return <button onClick={handleClick}>Show Toast</button>;
}useToast Hook:
success(message, options)- Success notificationerror(message, options)- Error notificationwarning(message, options)- Warning notificationinfo(message, options)- Info notificationshowToast(options)- Custom notificationtoast.showToast({ message: 'Custom message', type: 'success', position: 'top', duration: 5000 });
Options:
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| position | 'top' \| 'center' \| 'bottom' | 'bottom' | Toast position |
| duration | number | 3000 | Display duration in milliseconds |
Features:
- Single Toast Display - New toast replaces the previous one instantly
- Type-based Icons & Colors - Automatic icon and color assignment
- Smooth Animations - Animation plays for each new toast
Icons:
- Success:
bi-check-circle-fill(Check circle) - Error:
bi-x-circle-fill(X circle) - Warning:
bi-exclamation-triangle-fill(Warning triangle) - Info:
bi-info-circle-fill(Info circle)
Animation System:
- Spring-based bounce effects
- Icon rotation + scale animation
- Text fade-in + slide animation
- Unique animations for each display (using unique keys)
Toast Component (Direct Usage)
For individual usage without the provider:
import { Toast } from '@imc0nt0/mirror';
<Toast
message="Operation completed!"
type="success"
position="top"
duration={3000}
isOpen={isToastOpen}
onClose={() => setIsToastOpen(false)}
/>Toast Component Props:
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| message | string | - | Required. Toast message |
| type | 'success' \| 'error' \| 'warning' \| 'info' | - | Toast type |
| position | 'top' \| 'center' \| 'bottom' | 'bottom' | Display position |
| duration | number | 3000 | Duration in milliseconds |
| isOpen | boolean | - | Required. Toast visibility |
| onClose | function | - | Required. Close callback |
Modal
Modal dialog component with normal and confirmation variants.
import { Modal, useModal } from '@imc0nt0/mirror';
function App() {
const { isOpen, openModal, closeModal } = useModal();
return (
<div>
<button onClick={openModal}>Open Modal</button>
{/* Normal Modal */}
<Modal
isOpen={isOpen}
onClose={closeModal}
title="Notification"
type="normal"
>
<p>This is the modal content.</p>
</Modal>
{/* Confirmation Modal */}
<Modal
isOpen={isOpen}
onClose={closeModal}
title="Delete Confirmation"
type="confirm"
confirmText="Delete"
cancelText="Cancel"
onConfirm={() => console.log('Deleted')}
>
<p>Are you sure you want to delete this item?</p>
</Modal>
</div>
);
}Modal Props:
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| isOpen | boolean | - | Required. Modal visibility |
| onClose | function | - | Required. Close callback |
| title | string | - | Modal title |
| children | ReactNode | - | Modal content |
| type | 'normal' \| 'confirm' | 'normal' | Modal type |
| confirmText | string | 'Confirm' | Confirm button text |
| cancelText | string | 'Cancel' | Cancel button text |
| onConfirm | function | - | Confirm button callback (confirm type only) |
| showCloseButton | boolean | true | Show X close button |
Features:
- ESC key to close - Press escape to dismiss
- Click outside to close - Click overlay to dismiss
- Scroll prevention - Body scroll disabled when modal is open
- Spring animations - Smooth enter/exit transitions
useModal Hook:
| Method | Type | Description |
|--------|------|-------------|
| isOpen | boolean | Modal open state |
| openModal() | function | Open the modal |
| closeModal() | function | Close the modal |
🎬 Animation System
Mirror provides a comprehensive animation system built on Framer Motion with predefined motion presets.
Motion Presets
Pre-defined animations for common use cases.
import { Animate, AnimateOnView, AnimateStagger, motions } from '@imc0nt0/mirror';
// Basic animations
<Animate motion="fadeIn">
<div>Fade in animation</div>
</Animate>
<Animate motion="slideUp" delay={0.2}>
<div>Slide up with delay</div>
</Animate>Available Motion Presets:
fadeIn,fadeOut- Fade effectsslideUp,slideDown,slideLeft,slideRight- Slide effectsscaleIn,scaleOut,scaleBounce- Scale effectsrotateIn- Rotation effectsblurIn- Blur effectsentrance- Combined slide + fade + blur effectpop- Pop effect with bounce
AnimateOnView
Trigger animations when elements enter the viewport.
<AnimateOnView motion="slideUp" once={true}>
<div>Appears when scrolled into view</div>
</AnimateOnView>
<AnimateOnView motion="fadeIn" delay={0.3} amount={0.5}>
<div>Animated after 50% is visible</div>
</AnimateOnView>Props:
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| motion | string | - | Motion preset name |
| delay | number | 0 | Animation delay in seconds |
| once | boolean | true | Animate only once |
| amount | number | 0.3 | Visibility threshold (0-1) |
AnimateStagger
Animate child elements sequentially with staggered delays.
<AnimateStagger motion="fadeIn" staggerDelay={0.1}>
{items.map(item => (
<div key={item.id}>{item.name}</div>
))}
</AnimateStagger>
<AnimateStagger motion="slideUp" staggerDelay={0.05}>
<Card>First card</Card>
<Card>Second card</Card>
<Card>Third card</Card>
</AnimateStagger>Props:
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| motion | string | - | Motion preset name |
| staggerDelay | number | 0.1 | Delay between child animations (seconds) |
useAnimation Hook
Programmatically control animations with advanced sequencing.
import { useAnimation, motions } from '@imc0nt0/mirror';
function MyComponent() {
const { scope, play, serial, parallel, stagger, timeline } = useAnimation();
const handleClick = async () => {
// Single execution
await play('.target', motions.fadeIn);
// Sequential execution
await serial([
{ target: '.item1', motion: motions.fadeIn },
{ target: '.item2', motion: motions.slideUp },
]);
// Parallel execution
await parallel([
{ target: '.item1', motion: motions.fadeIn },
{ target: '.item2', motion: motions.fadeIn },
]);
// Staggered execution
await stagger([
{ target: '.item1', motion: motions.fadeIn },
{ target: '.item2', motion: motions.fadeIn },
], 0.1);
// Timeline composition
await timeline([
{ type: 'parallel', animations: [
{ target: '.header', motion: motions.slideDown },
{ target: '.sidebar', motion: motions.slideLeft }
]},
{ type: 'wait', duration: 0.5 },
{ type: 'serial', animations: [
{ target: '.content', motion: motions.fadeIn },
{ target: '.footer', motion: motions.slideUp }
]},
]);
};
return (
<div ref={scope}>
<div className="target">Animation target</div>
<button onClick={handleClick}>Start Animation</button>
</div>
);
}Methods:
| Method | Description |
|--------|-------------|
| play(target, motion, options) | Execute single motion |
| serial(animations) | Execute animations sequentially |
| parallel(animations) | Execute animations simultaneously |
| stagger(animations, delayBetween) | Execute with staggered delays |
| timeline(sequence) | Execute complex timeline |
Custom Motions
Create your own motion definitions for specific use cases.
import { createMotion, easings } from '@imc0nt0/mirror';
// Define custom motion
const customMotion = createMotion({
from: { opacity: 0, y: 20, scale: 0.9 },
to: { opacity: 1, y: 0, scale: 1 },
duration: 0.6,
ease: easings.toss,
});
// Use custom motion
<Animate motion={customMotion}>
<div>Custom animation</div>
</Animate>
// Complex custom motion
const complexMotion = createMotion({
from: {
opacity: 0,
rotate: -180,
scale: 0.5,
filter: "blur(10px)"
},
to: {
opacity: 1,
rotate: 0,
scale: 1,
filter: "blur(0px)"
},
duration: 0.8,
ease: easings.springBouncy,
});Available Easing Functions:
- Linear:
linear - Standard:
ease,easeIn,easeOut,easeInOut - Spring:
spring,springBouncy,springSoft - Special:
toss,smooth,bounce,anticipate
Motion Composition
Combine multiple motion presets for complex animations.
import { combineMotions, motions } from '@imc0nt0/mirror';
// Combine fade and slide effects
const fadeSlideMotion = combineMotions(
motions.fadeIn,
motions.slideUp
);
// Combine multiple effects
const complexMotion = combineMotions(
motions.scaleIn,
motions.rotateIn,
motions.fadeIn
);
// Use combined motion
<Animate motion={fadeSlideMotion}>
<div>Combined animation effect</div>
</Animate>📚 Advanced Usage
Performance Optimization
Mirror is optimized for performance with several built-in features:
- Tree Shaking: Import only the components you need
- Lazy Loading: Components are loaded on demand
- Motion Optimization: Animations use GPU acceleration when possible
- Bundle Size: Minimal overhead with efficient bundling
// Import only what you need
import { Button, TextField } from '@imc0nt0/mirror';
// Instead of importing everything
// import * as Mirror from '@imc0nt0/mirror'; // ❌ Don't do thisTheming & Customization
Override default styles using CSS variables:
:root {
--mirror-primary: #your-primary-color;
--mirror-secondary: #your-secondary-color;
--mirror-border-radius: 8px;
--mirror-font-family: 'Your Font', sans-serif;
}Accessibility
All Mirror components follow WCAG 2.1 guidelines:
- Keyboard Navigation: Full keyboard support
- Screen Readers: Proper ARIA labels and descriptions
- Focus Management: Visible focus indicators
- Color Contrast: AA compliant color ratios
🛠️ Development
Prerequisites
- Node.js 16+
- React 18+
- TypeScript 4.5+ (optional but recommended)
Peer Dependencies
{
"react": ">=18.0.0",
"react-dom": ">=18.0.0",
"framer-motion": ">=10.0.0",
"bootstrap-icons": ">=1.10.0"
}📝 Changelog
See CHANGELOG.md for version history.
🐛 Issues & Support
- Bug Reports: GitHub Issues
- Feature Requests: GitHub Discussions
📄 License
MIT License - see the LICENSE file for details.
Made with ❤️ by the HOSHLAB IN KOREA
