# Oranguru Integration Guide
## Overview
Oranguru is a React component library that provides enhanced Mantine-based components with advanced features and state management capabilities. For WhatsHooked, we'll use it to build data grids and forms for the admin interface.
## Installation
```bash
npm install @warkypublic/oranguru
```
### Peer Dependencies
```bash
npm install react zustand @mantine/core @mantine/hooks @warkypublic/artemis-kit @warkypublic/zustandsyncstore use-sync-external-store
```
## Core Concepts
### Enhanced Context Menus
Oranguru provides better menu positioning and visibility control than standard Mantine menus.
### Custom Rendering
Support for custom menu item renderers and complete menu rendering.
### State Management
Uses Zustand for component state management with sync capabilities.
## Basic Setup
```tsx
import { MantineBetterMenusProvider } from '@warkypublic/oranguru';
import { MantineProvider } from '@mantine/core';
function App() {
return (
{/* Your app content */}
);
}
```
## Using Context Menus
```tsx
import { useMantineBetterMenus } from '@warkypublic/oranguru';
function DataGrid() {
const { show, hide } = useMantineBetterMenus();
const handleContextMenu = (e: React.MouseEvent, record: any) => {
e.preventDefault();
show('record-menu', {
x: e.clientX,
y: e.clientY,
items: [
{
label: 'Edit',
onClick: () => handleEdit(record)
},
{
label: 'Delete',
onClick: () => handleDelete(record)
},
{
isDivider: true
},
{
label: 'View Details',
onClick: () => handleViewDetails(record)
}
]
});
};
return (
{records.map(record => (
handleContextMenu(e, record)}>
| {record.name} |
))}
);
}
```
## Async Actions
```tsx
const asyncMenuItem = {
label: 'Sync Data',
onClickAsync: async () => {
await fetch('/api/sync', { method: 'POST' });
// Shows loading state automatically
}
};
```
## Custom Menu Items
```tsx
const customItem = {
renderer: ({ loading }: any) => (
{loading ? (
) : (
Custom Action
)}
),
onClickAsync: async () => {
await performAction();
}
};
```
## Integration with Data Grids
While Oranguru doesn't provide a built-in data grid component yet, it works excellently with Mantine's DataTable or custom table implementations:
```tsx
import { useMantineBetterMenus } from '@warkypublic/oranguru';
import { DataTable } from '@mantine/datatable';
function UserGrid() {
const { show } = useMantineBetterMenus();
const [users, setUsers] = useState([]);
const columns = [
{ accessor: 'name', title: 'Name' },
{ accessor: 'email', title: 'Email' },
{ accessor: 'status', title: 'Status' }
];
const handleRowContextMenu = (e: React.MouseEvent, user: User) => {
e.preventDefault();
show('user-menu', {
x: e.clientX,
y: e.clientY,
items: [
{
label: 'Edit User',
onClick: () => navigate(`/users/${user.id}/edit`)
},
{
label: 'Deactivate',
onClickAsync: async () => {
await fetch(`/api/users/${user.id}/deactivate`, { method: 'POST' });
await refreshUsers();
}
},
{
isDivider: true
},
{
label: 'Delete',
onClick: () => handleDelete(user.id)
}
]
});
};
return (
handleRowContextMenu(event, record)}
/>
);
}
```
## Form Integration
For forms, use Mantine's form components with Oranguru's menu system for enhanced UX:
```tsx
import { useForm } from '@mantine/form';
import { TextInput, Select, Button } from '@mantine/core';
function UserForm() {
const form = useForm({
initialValues: {
name: '',
email: '',
role: ''
},
validate: {
email: (value) => (/^\S+@\S+$/.test(value) ? null : 'Invalid email'),
name: (value) => (value.length < 2 ? 'Name too short' : null)
}
});
const handleSubmit = async (values: typeof form.values) => {
try {
await fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(values)
});
notifications.show({ message: 'User created successfully' });
} catch (error) {
notifications.show({
message: 'Failed to create user',
color: 'red'
});
}
};
return (
);
}
```
## Best Practices
1. **Provider Placement**: Place MantineBetterMenusProvider at the root of your app
2. **Menu IDs**: Use descriptive, unique IDs for each menu type
3. **Context Menus**: Always prevent default on right-click events
4. **Loading States**: Use onClickAsync for async operations to get automatic loading states
5. **Custom Renderers**: Use custom renderers for complex menu items with icons, badges, etc.
6. **Portal Rendering**: Oranguru uses portals for proper z-index handling
7. **State Management**: Leverage Zustand store for complex menu state
8. **Accessibility**: Ensure keyboard navigation works with context menus
## Common Patterns
### Multi-Select Context Menu
```tsx
const handleBulkContextMenu = (e: React.MouseEvent, selectedIds: string[]) => {
e.preventDefault();
show('bulk-menu', {
x: e.clientX,
y: e.clientY,
items: [
{
label: `Delete ${selectedIds.length} items`,
onClickAsync: async () => {
await bulkDelete(selectedIds);
}
},
{
label: 'Export selection',
onClick: () => exportItems(selectedIds)
}
]
});
};
```
### Conditional Menu Items
```tsx
const menuItems = [
{
label: 'Edit',
onClick: () => handleEdit(record)
},
canDelete(record) && {
label: 'Delete',
onClick: () => handleDelete(record)
},
{
isDivider: true
},
isAdmin && {
label: 'Admin Actions',
onClick: () => showAdminActions(record)
}
].filter(Boolean); // Remove falsy items
```
### Nested Menus (Future Feature)
While not yet supported, Oranguru is designed to support nested menus in future versions.
## Integration with WhatsHooked
For WhatsHooked's admin interface:
1. **User Management Grid**: Use DataTable with context menus for user actions
2. **Hook Configuration**: Form with validation and async submission
3. **WhatsApp Account Management**: Grid with QR code display and pairing actions
4. **API Key Management**: Grid with copy-to-clipboard and revoke actions
5. **Event Logs**: Read-only grid with filtering and export
## References
- Official Repository: https://git.warky.dev/wdevs/oranguru
- Mantine Documentation: https://mantine.dev
- Mantine DataTable: https://icflorescu.github.io/mantine-datatable/