- refactor state structure to include app, layout, navigation, owner, program, session, and user - add slices for managing program, session, owner, user, layout, navigation, and app states - create context provider for global state with automatic fetching and throttling - implement persistence using IndexedDB with localStorage fallback - add comprehensive README documentation for usage and API
364 lines
9.0 KiB
Markdown
364 lines
9.0 KiB
Markdown
# @warkypublic/oranguru
|
|
|
|
A React component library providing enhanced Mantine-based components with advanced features and state management capabilities.
|
|
|
|
## Overview
|
|
|
|
Oranguru is a comprehensive component library that extends Mantine's component ecosystem. Named after the wise Orangutan Pokémon known for its intelligence and strategic thinking, this library provides enhanced components with advanced positioning, custom rendering, and sophisticated state management capabilities.
|
|
|
|
Currently featuring advanced menu components, Oranguru is designed to grow into a full suite of enhanced Mantine components that offer more flexibility and power than their standard counterparts.
|
|
|
|
## Components
|
|
|
|
### MantineBetterMenu
|
|
|
|
Enhanced context menus with better positioning and visibility control
|
|
|
|
### Gridler
|
|
|
|
Powerful data grid component with sorting, filtering, and pagination
|
|
|
|
### Former
|
|
|
|
Form component with React Hook Form integration and validation
|
|
|
|
### FormerControllers
|
|
|
|
Pre-built form input controls for use with Former
|
|
|
|
### Boxer
|
|
|
|
Advanced combobox/select with virtualization and server-side data support
|
|
|
|
### ErrorBoundary
|
|
|
|
React error boundary components for graceful error handling
|
|
|
|
### GlobalStateStore
|
|
|
|
Zustand-based global state management with automatic persistence
|
|
|
|
## Core Features
|
|
|
|
- **State Management**: Zustand-based store for component state management
|
|
- **TypeScript Support**: Full TypeScript definitions included
|
|
- **Portal-based Rendering**: Proper z-index handling through React portals
|
|
- **Extensible Architecture**: Designed to support additional Mantine component enhancements
|
|
|
|
## Installation
|
|
|
|
```bash
|
|
npm install @warkypublic/oranguru
|
|
```
|
|
|
|
### Peer Dependencies
|
|
|
|
This package requires the following peer dependencies:
|
|
|
|
```bash
|
|
npm install react@">= 19.0.0" zustand@">= 5.0.0" @mantine/core@"^8.3.1" @mantine/hooks@"^8.3.1" @warkypublic/artemis-kit@"^1.0.10" @warkypublic/zustandsyncstore@"^0.0.4" use-sync-external-store@">= 1.4.0"
|
|
```
|
|
|
|
## Usage
|
|
|
|
### MantineBetterMenu
|
|
|
|
```tsx
|
|
import { MantineBetterMenusProvider, useMantineBetterMenus } from '@warkypublic/oranguru';
|
|
|
|
// Wrap app with provider
|
|
<MantineBetterMenusProvider>
|
|
<App />
|
|
</MantineBetterMenusProvider>
|
|
|
|
// Use in components
|
|
const { show, hide } = useMantineBetterMenus();
|
|
show('menu-id', {
|
|
x: e.clientX,
|
|
y: e.clientY,
|
|
items: [
|
|
{ label: 'Edit', onClick: () => {} },
|
|
{ isDivider: true },
|
|
{ label: 'Async', onClickAsync: async () => {} }
|
|
]
|
|
});
|
|
```
|
|
|
|
### Gridler
|
|
|
|
```tsx
|
|
import { Gridler } from '@warkypublic/oranguru';
|
|
|
|
// Local data
|
|
<Gridler columns={columns} uniqueid="my-grid">
|
|
<Gridler.LocalDataAdaptor data={data} />
|
|
</Gridler>
|
|
|
|
// API data
|
|
<Gridler columns={columns} uniqueid="my-grid">
|
|
<Gridler.APIAdaptorForGoLangv2 apiURL="/api/data" />
|
|
</Gridler>
|
|
|
|
// With inline editing form
|
|
<Gridler columns={columns} uniqueid="editable-grid" ref={gridRef}>
|
|
<Gridler.APIAdaptorForGoLangv2 url="/api/data" />
|
|
<Gridler.FormAdaptor
|
|
changeOnActiveClick={true}
|
|
descriptionField="name"
|
|
onRequestForm={(request, data) => {
|
|
setFormProps({ opened: true, request, values: data });
|
|
}}
|
|
/>
|
|
</Gridler>
|
|
|
|
<FormerDialog
|
|
former={{ request: formProps.request, values: formProps.values }}
|
|
opened={formProps.opened}
|
|
onClose={() => setFormProps({ opened: false })}
|
|
>
|
|
<TextInputCtrl label="Name" name="name" />
|
|
<NativeSelectCtrl label="Type" name="type" data={["A", "B"]} />
|
|
</FormerDialog>
|
|
|
|
// Columns definition
|
|
const columns = [
|
|
{ id: 'name', title: 'Name', width: 200 },
|
|
{ id: 'email', title: 'Email', width: 250 }
|
|
];
|
|
```
|
|
|
|
### Former
|
|
|
|
```tsx
|
|
import { Former, FormerDialog } from '@warkypublic/oranguru';
|
|
|
|
const formRef = useRef<FormerRef>(null);
|
|
|
|
<Former
|
|
ref={formRef}
|
|
onSave={async (data) => { /* save logic */ }}
|
|
primeData={{ name: '', email: '' }}
|
|
wrapper={FormerDialog}
|
|
>
|
|
{/* Form content */}
|
|
</Former>
|
|
|
|
// Methods: formRef.current.show(), .save(), .reset()
|
|
```
|
|
|
|
### FormerControllers
|
|
|
|
```tsx
|
|
import {
|
|
TextInputCtrl,
|
|
PasswordInputCtrl,
|
|
NativeSelectCtrl,
|
|
TextAreaCtrl,
|
|
SwitchCtrl,
|
|
ButtonCtrl
|
|
} from '@warkypublic/oranguru';
|
|
|
|
<Former>
|
|
<TextInputCtrl name="username" label="Username" />
|
|
<PasswordInputCtrl name="password" label="Password" />
|
|
<NativeSelectCtrl name="role" data={['Admin', 'User']} />
|
|
<SwitchCtrl name="active" label="Active" />
|
|
<ButtonCtrl type="submit">Save</ButtonCtrl>
|
|
</Former>
|
|
```
|
|
|
|
### Boxer
|
|
|
|
```tsx
|
|
import { Boxer } from '@warkypublic/oranguru';
|
|
|
|
// Local data
|
|
<Boxer
|
|
data={[{ label: 'Apple', value: 'apple' }]}
|
|
dataSource="local"
|
|
value={value}
|
|
onChange={setValue}
|
|
searchable
|
|
clearable
|
|
/>
|
|
|
|
// Server-side data
|
|
<Boxer
|
|
dataSource="server"
|
|
onAPICall={async ({ page, pageSize, search }) => ({
|
|
data: [...],
|
|
total: 100
|
|
})}
|
|
value={value}
|
|
onChange={setValue}
|
|
/>
|
|
|
|
// Multi-select
|
|
<Boxer multiSelect value={values} onChange={setValues} />
|
|
```
|
|
|
|
### ErrorBoundary
|
|
|
|
```tsx
|
|
import { ReactErrorBoundary, ReactBasicErrorBoundary } from '@warkypublic/oranguru';
|
|
|
|
// Full-featured error boundary
|
|
<ReactErrorBoundary
|
|
namespace="my-component"
|
|
reportAPI="/api/errors"
|
|
onResetClick={() => {}}
|
|
>
|
|
<App />
|
|
</ReactErrorBoundary>
|
|
|
|
// Basic error boundary
|
|
<ReactBasicErrorBoundary>
|
|
<App />
|
|
</ReactBasicErrorBoundary>
|
|
```
|
|
|
|
### GlobalStateStore
|
|
|
|
```tsx
|
|
import {
|
|
GlobalStateStoreProvider,
|
|
useGlobalStateStore,
|
|
GlobalStateStore
|
|
} from '@warkypublic/oranguru';
|
|
|
|
// Wrap app
|
|
<GlobalStateStoreProvider
|
|
apiURL="https://api.example.com"
|
|
fetchOnMount={true}
|
|
throttleMs={5000}
|
|
>
|
|
<App />
|
|
</GlobalStateStoreProvider>
|
|
|
|
// Use in components
|
|
const { program, session, user, layout } = useGlobalStateStore();
|
|
const { refetch } = useGlobalStateStoreContext();
|
|
|
|
// Outside React
|
|
GlobalStateStore.getState().setAuthToken('token');
|
|
const apiURL = GlobalStateStore.getState().session.apiURL;
|
|
```
|
|
|
|
## API Reference
|
|
|
|
**MantineBetterMenu**
|
|
|
|
- Provider: `MantineBetterMenusProvider`
|
|
- Hook: `useMantineBetterMenus()` returns `{ show, hide, menus, setInstanceState }`
|
|
- Key Props: `items[]`, `x`, `y`, `visible`, `menuProps`, `renderer`
|
|
|
|
**Gridler**
|
|
|
|
- Main Component: `Gridler`
|
|
- Adaptors: `LocalDataAdaptor`, `APIAdaptorForGoLangv2`, `FormAdaptor`
|
|
- Store Hook: `useGridlerStore()`
|
|
- Key Props: `uniqueid`, `columns[]`, `data`
|
|
|
|
**Former**
|
|
|
|
- Main Component: `Former`
|
|
- Wrappers: `FormerDialog`, `FormerModel`, `FormerPopover`
|
|
- Ref Methods: `show()`, `close()`, `save()`, `reset()`, `validate()`
|
|
- Key Props: `primeData`, `onSave`, `wrapper`
|
|
|
|
**FormerControllers**
|
|
|
|
- Controls: `TextInputCtrl`, `PasswordInputCtrl`, `TextAreaCtrl`, `NativeSelectCtrl`, `SwitchCtrl`, `ButtonCtrl`, `IconButtonCtrl`
|
|
- Common Props: `name` (required), `label`, `disabled`
|
|
|
|
**Boxer**
|
|
|
|
- Provider: `BoxerProvider`
|
|
- Store Hook: `useBoxerStore()`
|
|
- Data Sources: `local`, `server`
|
|
- Key Props: `data`, `dataSource`, `onAPICall`, `multiSelect`, `searchable`, `clearable`
|
|
|
|
**ErrorBoundary**
|
|
|
|
- Components: `ReactErrorBoundary`, `ReactBasicErrorBoundary`
|
|
- Key Props: `namespace`, `reportAPI`, `onResetClick`, `onRetryClick`
|
|
|
|
**GlobalStateStore**
|
|
|
|
- Provider: `GlobalStateStoreProvider`
|
|
- Hook: `useGlobalStateStore()` returns `{ program, session, owner, user, layout, navigation, app }`
|
|
- Store Methods: `setAuthToken()`, `setApiURL()`, `fetchData()`, `login()`, `logout()`
|
|
- Key Props: `apiURL`, `autoFetch`, `fetchOnMount`, `throttleMs`
|
|
|
|
## MCP Server
|
|
|
|
Oranguru includes a Model Context Protocol (MCP) server for AI-assisted development.
|
|
|
|
**Configuration:**
|
|
|
|
Add to `~/.claude/mcp_settings.json`:
|
|
|
|
```json
|
|
{
|
|
"mcpServers": {
|
|
"oranguru-docs": {
|
|
"command": "npx",
|
|
"args": ["-y", "@warkypublic/oranguru", "mcp"]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
**Tools:**
|
|
|
|
- `list_components` - List all components
|
|
- `get_component_docs` - Get component documentation
|
|
- `get_component_example` - Get code examples
|
|
|
|
**Resources:**
|
|
|
|
- `oranguru://docs/readme` - Full documentation
|
|
- `oranguru://docs/components` - Component list
|
|
|
|
See `mcp/README.md` for details.
|
|
|
|
## Development
|
|
|
|
### Scripts
|
|
|
|
- `pnpm dev`: Start development server
|
|
- `pnpm build`: Build the library
|
|
- `pnpm lint`: Run ESLint
|
|
- `pnpm typecheck`: Run TypeScript type checking
|
|
- `pnpm clean`: Clean node_modules and dist folders
|
|
- `pnpm mcp`: Run MCP server
|
|
|
|
### Building
|
|
|
|
The library is built using Vite and outputs both ESM and CommonJS formats:
|
|
|
|
- ESM: `dist/lib.es.js`
|
|
- CommonJS: `dist/lib.cjs.js`
|
|
- Types: `dist/lib.d.ts`
|
|
|
|
## License
|
|
|
|
See [LICENSE](LICENSE) file for details.
|
|
|
|
## About the Name
|
|
|
|
Oranguru is named after the Orangutan Pokémon (オランガ Oranga), a Normal/Psychic-type Pokémon introduced in Generation VII. Known as the "Sage Pokémon," Oranguru is characterized by its wisdom, intelligence, and ability to use tools strategically.
|
|
|
|
In the Pokémon world, Oranguru is known for:
|
|
|
|
- Its exceptional intelligence and strategic thinking
|
|
- Living deep in forests and rarely showing itself to humans
|
|
- Using its psychic powers to control other Pokémon with its fan
|
|
- Being highly territorial but also caring for other Pokémon in its domain
|
|
|
|
Just as Oranguru the Pokémon enhances and controls its environment with wisdom and strategic tools, this library aims to enhance and extend Mantine components with intelligent, well-designed solutions.
|
|
|
|
## Author
|
|
|
|
Warky Devs
|