UNPKG

@darksnow-ui/commander

Version:

Command pattern implementation with React hooks for building command palettes and keyboard-driven UIs

262 lines (196 loc) 6.53 kB
# @darksnow-ui/commander > 🚀 **Enterprise-grade command system for React applications with Command Palette integration** [![npm version](https://badge.fury.io/js/%40darksnow-ui%2Fcommander.svg)](https://badge.fury.io/js/%40darksnow-ui%2Fcommander) [![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](http://www.typescriptlang.org/) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) Transform your React app into a power-user's dream with a **VS Code-style command system**. Register commands from anywhere, execute them programmatically or via Command Palette, and watch your UX reach new levels. ## ✨ Why Commander? - **Scattered actions** across your app? Centralize with Commander - **No programmatic execution**? Full API + keyboard shortcuts - **Manual Command Palette maintenance**? Auto-register/cleanup - **Poor discoverability**? Intelligent search with fuzzy matching ```tsx // 1. Register commands anywhere useCustomCommand({ key: "file:save", label: "Save File", shortcut: "ctrl+s", handle: async () => saveCurrentFile(), }); // 2. Execute with type safety const saveFile = useInvoker<SaveInput, SaveResult>("file:save"); await saveFile({ filename: "document.txt" }); // 3. Users find it in Command Palette (Ctrl+Shift+P) // 4. Auto-cleanup on component unmount ``` ## 📦 Installation ```bash pnpm add @darksnow-ui/commander # or npm install @darksnow-ui/commander ``` ## ⚡ Quick Start ### 1. Setup Provider ```tsx import { CommanderProvider, Commander } from "@darksnow-ui/commander"; const commander = new Commander(); function App() { return ( <CommanderProvider commander={commander} enableDevTools> <MyApp /> </CommanderProvider> ); } ``` ### 2. Register Commands ```tsx import { useCustomCommand } from "@darksnow-ui/commander"; function FileEditor({ file }) { useCustomCommand({ key: `file:save:${file.id}`, label: `Save ${file.name}`, shortcut: "ctrl+s", when: () => file.isDirty, handle: async () => { await saveFile(file); return { saved: true }; }, }); return <Editor />; } ``` ### 3. Execute Commands ```tsx import { useInvoker } from "@darksnow-ui/commander"; function SaveButton() { const saveFile = useInvoker("file:save"); return <button onClick={() => saveFile()}>Save</button>; } ``` --- ## 🎣 Hooks API ### Core | Hook | Purpose | |------|---------| | `useCommander()` | Access Commander instance and methods | | `useCustomCommand(config)` | Register temporary command (auto-cleanup) | ### Execution | Hook | Purpose | |------|---------| | `useCommand(key, options)` | Full-featured with state tracking | | `useInvoker(key, options)` | Direct function execution | | `useAction(key)` | For commands without parameters | | `useSafeInvoker(key)` | Non-throwing, returns `ExecutionResult` | ### Specialized | Hook | Purpose | |------|---------| | `useBoundInvoker(key, defaults)` | Pre-configured parameters | | `useToggleInvoker(key)` | Boolean toggle commands | | `useBatchInvoker(keys, options)` | Sequential execution | | `useParallelInvoker(keys)` | Parallel execution | --- ## 🔧 Command Options ```tsx useCustomCommand({ // Required key: "namespace:action", label: "Human Readable Name", handle: async (input) => result, // Optional description: "What this command does", category: "file" | "edit" | "view" | "tools" | "debug" | "system" | "custom", icon: "💾", shortcut: "ctrl+s", tags: ["save", "file"], priority: 10, timeout: 5000, owner: "my-component", // Conditional availability when: () => canExecute, // Input validation (works with Zod, Yup, etc.) inputValidator: (input) => { if (!input?.email) { return [{ path: "email", message: "Required", code: "required" }]; } return true; }, }); ``` --- ## 🛡️ Input Validation Commands support input validation with any library: ```tsx // With Zod import { z } from "zod"; const schema = z.object({ email: z.string().email(), name: z.string().min(2), }); useCustomCommand({ key: "user:create", label: "Create User", inputValidator: (input) => { const result = schema.safeParse(input); if (result.success) return true; return result.error.issues.map((i) => ({ path: i.path.join("."), message: i.message, code: i.code, })); }, handle: async (input) => createUser(input), }); ``` Handle validation errors: ```tsx import { isInputValidationError } from "@darksnow-ui/commander"; try { await commander.invoke("user:create", { email: "" }); } catch (error) { if (isInputValidationError(error)) { console.log(error.getMissingFields()); // ["name"] console.log(error.errors); // Full error details } } ``` --- ## 🎯 useCommand vs useInvoker ```tsx // useInvoker - Simple, direct execution const save = useInvoker("file:save"); await save({ filename: "doc.txt" }); // useCommand - Full state tracking const cmd = useCommand("file:save"); cmd.isLoading; // boolean cmd.lastResult; // last successful result cmd.lastError; // last error cmd.executionCount; // number of executions await cmd.invoke({ filename: "doc.txt" }); ``` --- ## 📚 Documentation | Document | Description | |----------|-------------| | [Architecture](./docs/ARCHITECTURE.md) | Core internals, types, algorithms | | [useInvoker Guide](./docs/useInvoker-guide.md) | Deep dive into execution hooks | | [useCustomCommand Examples](./docs/useCustomCommand-examples.md) | 30+ real-world examples | --- ## 🏆 Comparison | Feature | Commander | cmdk | kbar | |---------|-----------|------|------| | TypeScript generics | Full | Basic | Good | | React hooks | 10 specialized | | Limited | | Auto cleanup | | Manual | Manual | | Conditional commands | `when()` | | | | Input validation | Built-in | | | | State tracking | | | | | Event system | Full lifecycle | | Limited | --- ## 📄 License MIT © [Anderson Rosa](https://github.com/andersondrosa) --- <div align="center"> **Built with ❤️ by [Anderson Rosa](https://github.com/andersondrosa)** _Part of the [DarkSnow UI](https://github.com/darksnow-ui/darksnow-ui) ecosystem_ [ Star on GitHub](https://github.com/darksnow-ui/darksnow-ui) [📖 Architecture](./docs/ARCHITECTURE.md) [🚀 Examples](./docs/useCustomCommand-examples.md) </div>