@darksnow-ui/commander v1.0.5
@darksnow-ui/commander
๐ Enterprise-grade command system for React applications with Command Palette integration
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?
๐ฏ The Problem
- Scattered actions across your app with no centralized control
- No unified way to execute operations programmatically + via UI
- Command Palettes that require manual registration and maintenance
- Poor discoverability of available actions for power users
๐ก The Solution
// 1. Register commands anywhere in your app
useCustomCommand({
key: 'file:save',
label: 'Save File',
shortcut: 'ctrl+s',
handle: async () => saveCurrentFile()
});
// 2. Execute programmatically with full type safety
const saveFile = useInvoker<SaveInput, SaveResult>('file:save');
const result = await saveFile({ filename: 'document.txt' });
// 3. Users find it instantly in Command Palette (Ctrl+Shift+P)
// 4. Command auto-removes when component unmounts๐ Features
๐๏ธ Core Architecture
- ๐ฏ Command Pattern - Centralized command management with O(1) lookups
- ๐ Intelligent Search - Hierarchical scoring algorithm with fuzzy matching
- โจ๏ธ Keyboard First - Built-in shortcut support with conflict resolution
- ๐ท๏ธ Smart Organization - Categories, tags, owners, and priority system
- ๐ Event-Driven - Comprehensive lifecycle events for monitoring and analytics
โ๏ธ React Integration
- ๐จ Zero Boilerplate - Context Provider handles everything automatically
- โก Temporary Commands - Components register/unregister commands automatically
- ๐ก๏ธ Type Safety - Full TypeScript with generics for inputs/outputs
- ๐ช Specialized Hooks - 10 purpose-built hooks for every use case
- ๐ฅ Hot Reload Friendly - Commands survive React Fast Refresh
๐๏ธ Advanced Features
- ๐ Execution Tracking - History, analytics, and recent commands
- ๐ Conditional Availability - Commands appear/disappear based on context
- โฑ๏ธ Timeout Handling - Automatic timeouts with graceful error handling
- ๐ ๏ธ Dev Tools - Built-in debugging commands and global access
- ๐ Performance - Optimized for apps with hundreds of commands
๐ฆ Installation
npm install @darksnow-ui/commander
# or
yarn add @darksnow-ui/commander
# or
pnpm add @darksnow-ui/commanderโก Quick Start
1. Setup Provider (one time in your app root)
import { CommanderProvider, Commander } from '@darksnow-ui/commander';
// Create your commander instance (usually in src/core/commander.ts)
const commander = new Commander();
function App() {
return (
<CommanderProvider
commander={commander}
enableDevTools
onReady={(commander) => {
console.log('Commander ready with', commander.commands().length, 'commands');
}}
>
<MyApp />
</CommanderProvider>
);
}2. Register Commands (in any component)
import { useCustomCommand } from '@darksnow-ui/commander';
function FileEditor({ file }) {
// Command automatically appears in Command Palette!
useCustomCommand({
key: `file:save:${file.id}`,
label: `Save ${file.name}`,
icon: '๐พ',
shortcut: 'ctrl+s',
when: () => file.isDirty, // Only when file has changes
handle: async () => {
await saveFile(file);
return { saved: true, filename: file.name };
}
});
return <div>Your file editor UI...</div>;
}3. Execute Commands (programmatically)
import { useInvoker } from '@darksnow-ui/commander';
function ActionButton() {
const saveFile = useInvoker<SaveInput, SaveResult>('file:save');
const handleSave = async () => {
try {
const result = await saveFile({ filename: 'document.txt' });
toast.success(`Saved: ${result.filename}`);
} catch (error) {
toast.error('Save failed');
}
};
return <button onClick={handleSave}>Save File</button>;
}๐ฃ React Hooks
Core Hooks
useCommander()
Access the complete Commander API:
const { commander, search, invoke, commands, has, getCommand } = useCommander();
// Search for commands
const results = await search('save');
// Execute any command
await invoke('file:save', { filename: 'test.txt' });
// Get all commands
const allCommands = commands();
// Check if command exists
if (has('file:save')) {
const saveCommand = getCommand('file:save');
}useCustomCommand()
Register temporary commands that auto-cleanup:
useCustomCommand({
key: 'my-command',
label: 'My Command',
description: 'Does something awesome',
category: 'actions',
icon: '๐',
shortcut: 'ctrl+shift+a',
tags: ['quick', 'action'],
priority: 10,
when: () => isFeatureEnabled(), // Conditional availability
handle: async (input) => {
// Your command logic
return { success: true };
}
});Execution Hooks
useCommand()
Full-featured command execution with state tracking:
const command = useCommand<Input, Output>('my-command', {
throwOnError: true,
source: 'api',
onSuccess: (result) => console.log('Success:', result),
onError: (error) => console.error('Error:', error)
});
// Execute with various methods
await command.invoke({ data: 'test' }); // throws on error
const result = await command.attempt({ data: 'test' }); // returns ExecutionResult
await command.execute({ data: 'test' }, {
onSuccess: (result) => toast.success('Done!'),
onError: (error) => toast.error(error.message)
});
// Access state
console.log(command.isLoading);
console.log(command.lastResult);
console.log(command.lastError);
console.log(command.executionCount);
// Check availability
if (command.isAvailable) {
// Show UI
}useInvoker()
Direct function execution (simplified):
const saveFile = useInvoker<Input, Output>('file:save');
// Direct invocation - returns a function!
const result = await saveFile({ data: 'test' });
// With options
const saveWithOptions = useInvoker('file:save', {
throwOnError: false,
onSuccess: (result) => toast.success('Saved!')
});Specialized Hooks
useAction()
For commands without parameters:
const logout = useAction('auth:logout');
const refresh = useAction('app:refresh');
// Simple execution
await logout();
await refresh();useCommandState()
Always returns the CommandInvoker object (alias for useCommand):
const command = useCommandState('my-command');
// Access state and methods
console.log(command.isLoading);
console.log(command.lastResult);
await command.invoke(data);useSafeInvoker()
Non-throwing execution with ExecutionResult:
const saveFile = useSafeInvoker<Input, Output>('file:save');
const result = await saveFile({ filename: 'test.txt' });
if (result.success) {
console.log('Saved:', result.result);
} else {
console.error('Failed:', result.error);
}useBoundInvoker()
Pre-configured command execution:
// Always saves as PDF
const savePdf = useBoundInvoker('file:save', { format: 'pdf' });
await savePdf({ filename: 'document' }); // format is already bounduseToggleInvoker()
For boolean toggle commands:
const toggleDarkMode = useToggleInvoker('ui:dark-mode');
const toggleSidebar = useToggleInvoker('ui:sidebar');
// Toggle state
await toggleDarkMode(true);
await toggleSidebar(); // toggles current stateuseBatchInvoker()
Sequential execution with progress tracking:
const deployPipeline = useBatchInvoker(
['build', 'test', 'deploy'],
{
stopOnError: true,
onProgress: (step, total) => console.log(`${step}/${total}`)
}
);
const results = await deployPipeline([
{ target: 'production' },
{ suite: 'all' },
{ env: 'prod' }
]);useParallelInvoker()
Parallel execution with Promise.allSettled:
const loadDashboard = useParallelInvoker([
'stats:revenue',
'stats:users',
'stats:orders'
]);
const results = await loadDashboard([
{ period: '30d' },
{ status: 'active' },
{ status: 'pending' }
]);๐๏ธ Core Concepts
Commander Instance
The heart of the system - manages all commands:
// Create and configure
const commander = new Commander();
commander.maxHistorySize = 200;
commander.maxRecentSize = 15;
// Register system commands
commander.add({
key: 'app:refresh',
label: 'Refresh Application',
handle: async () => location.reload()
});Command Structure
Commands are the building blocks:
interface Command<TInput, TOutput> {
key: CommandKey; // Unique identifier
label: string; // Human-readable name
handle: (input?: TInput) => Promise<TOutput>; // The actual function
description?: string; // Detailed description
category?: CommandCategory; // Organization
icon?: string; // Visual indicator
shortcut?: string; // Keyboard shortcut
when?: () => boolean | Promise<boolean>; // Conditional availability
tags?: string[]; // Search tags
priority?: number; // Search ranking
owner?: string; // Who registered it
source?: CommandSource; // Where it came from
}Command Builder
Fluent API for command creation:
import { CommandBuilder } from '@darksnow-ui/commander';
const saveCommand = CommandBuilder
.create<SaveInput, SaveOutput>('file:save')
.label('Save File')
.description('Save the current file to disk')
.category('file')
.icon('๐พ')
.shortcut('ctrl+s')
.tags(['file', 'save', 'disk'])
.priority(100)
.handle(async (input) => {
const result = await saveFile(input);
return { success: true, path: result.path };
})
.build();
commander.add(saveCommand);Search System
Intelligent hierarchical scoring:
const results = await commander.search('save file', {
category: 'file', // Filter by category
owner: 'editor', // Filter by owner
tags: ['important'], // Filter by tags
limit: 10 // Limit results
});
// Results are scored by:
// 1. Exact key match (highest)
// 2. Label match
// 3. Description match
// 4. Tag match
// 5. Fuzzy match (lowest)Event System
Monitor command lifecycle:
// Listen to events
commander.on('commandRegistered', (command) => {
console.log('New command:', command.key);
});
commander.on('beforeExecute', ({ command, input }) => {
analytics.track('command_execute', { key: command.key });
});
commander.on('afterExecute', ({ command, result, duration }) => {
console.log(`Command ${command.key} took ${duration}ms`);
});
commander.on('executionError', ({ command, error }) => {
errorReporter.log(error);
});๐ Documentation
๐ Guides
- Getting Started - Complete setup guide
- Hooks Guide - Deep dive into all React hooks
- useCustomCommand Examples - 30+ real-world examples
- useCommand Guide - Advanced state management
- useInvoker Guide - Command execution patterns
- Commander Algorithm - Core architecture deep dive
๐ฏ Examples
function TextEditor({ document }) {
const [content, setContent] = useState(document.content);
const [isDirty, setIsDirty] = useState(false);
// Save command - only available when dirty
useCustomCommand({
key: `doc:save:${document.id}`,
label: `Save ${document.name}`,
category: 'file',
icon: '๐พ',
shortcut: 'ctrl+s',
when: () => isDirty,
handle: async () => {
await saveDocument(document.id, content);
setIsDirty(false);
return { saved: true };
}
});
// Format command
useCustomCommand({
key: `doc:format:${document.id}`,
label: `Format ${document.name}`,
category: 'edit',
icon: 'โจ',
shortcut: 'shift+alt+f',
handle: async () => {
const formatted = await formatText(content);
setContent(formatted);
setIsDirty(true);
return { formatted: true };
}
});
return (
<textarea
value={content}
onChange={(e) => {
setContent(e.target.value);
setIsDirty(true);
}}
/>
);
}function ProductList({ products }) {
// Register command for each product
products.forEach(product => {
useCustomCommand({
key: `product:edit:${product.id}`,
label: `Edit ${product.name}`,
description: `SKU: ${product.sku}`,
category: 'products',
icon: 'โ๏ธ',
tags: ['product', 'edit', product.category],
searchKeywords: [product.name, product.sku, product.brand],
handle: async () => {
await openProductEditor(product.id);
return { opened: true };
}
});
});
// Bulk operations
const bulkDelete = useInvoker<{ ids: string[] }>('products:bulk-delete');
const handleBulkDelete = async (selectedIds: string[]) => {
const result = await bulkDelete({ ids: selectedIds });
if (result.success) {
toast.success(`Deleted ${result.count} products`);
}
};
return <ProductGrid products={products} onBulkDelete={handleBulkDelete} />;
}function GameControls() {
const [isPaused, setIsPaused] = useState(false);
// Game actions
useCustomCommand({
key: 'game:pause',
label: isPaused ? 'Resume Game' : 'Pause Game',
icon: isPaused ? 'โถ๏ธ' : 'โธ๏ธ',
shortcut: 'space',
handle: async () => {
setIsPaused(!isPaused);
return { paused: !isPaused };
}
});
useCustomCommand({
key: 'game:save',
label: 'Quick Save',
icon: '๐พ',
shortcut: 'f5',
when: () => !isPaused,
handle: async () => {
const slot = await saveGame();
return { slot };
}
});
useCustomCommand({
key: 'game:load',
label: 'Quick Load',
icon: '๐',
shortcut: 'f9',
handle: async () => {
await loadLastSave();
return { loaded: true };
}
});
return <GameUI paused={isPaused} />;
}๐ Comparison
| Feature | @darksnow-ui/commander | cmdk | kbar | Custom Solution |
|---|---|---|---|---|
| TypeScript | โ Full generics | โ Basic | โ Good | ๐คท Depends |
| React Hooks | โ 10 specialized hooks | โ None | โ Limited | ๐คท Depends |
| Auto Cleanup | โ Automatic | โ Manual | โ Manual | โ Manual |
| Conditional Commands | โ
Built-in when() | โ Manual | โ Manual | ๐คท Depends |
| State Management | โ Built-in tracking | โ None | โ None | ๐คท Depends |
| Event System | โ Full lifecycle | โ None | โ Limited | ๐คท Depends |
| Search Algorithm | โ Hierarchical scoring | โ Fuzzy | โ Fuzzy | ๐คท Depends |
| Batch Execution | โ Built-in hooks | โ None | โ None | ๐คท Depends |
| Performance | โ O(1) operations | โ ๏ธ O(n) | โ ๏ธ O(n) | ๐คท Depends |
| Bundle Size | ๐ฆ ~50KB | ๐ฆ ~40KB | ๐ฆ ~45KB | ๐คท Depends |
๐ Performance
Built for scale with real-world optimization:
- โก O(1) Operations: Command lookup, registration, and removal
- ๐ Efficient Search: Optimized scoring algorithm
- ๐ง Smart Memoization: React renders optimized automatically
- ๐ฆ Memory Bounded: Automatic cleanup of history and listeners
- ๐ฏ Lazy Evaluation: Commands only checked when needed
- ๐ Battle Tested: Used in production with 500+ commands
๐ก๏ธ TypeScript
First-class TypeScript support with advanced patterns:
// Strongly typed commands
interface SaveFileInput {
filename: string;
content: string;
format?: 'utf8' | 'binary';
}
interface SaveFileOutput {
success: boolean;
path: string;
size: number;
}
// Type-safe registration
useCustomCommand<SaveFileInput, SaveFileOutput>({
key: 'file:save',
label: 'Save File',
handle: async (input) => {
// input is typed as SaveFileInput
const result = await fs.writeFile(input.filename, input.content);
// Must return SaveFileOutput
return {
success: true,
path: result.path,
size: input.content.length
};
}
});
// Type-safe execution
const saveFile = useInvoker<SaveFileInput, SaveFileOutput>('file:save');
const result = await saveFile({
filename: 'test.txt',
content: 'Hello world'
}); // result is typed as SaveFileOutput๐งช Testing
Comprehensive test coverage with 192 tests:
import { renderHook } from '@testing-library/react';
import { CommanderProvider, useCustomCommand } from '@darksnow-ui/commander';
test('command registration and execution', async () => {
const { result } = renderHook(
() => {
useCustomCommand({
key: 'test:command',
label: 'Test Command',
handle: async (input: { value: number }) => {
return { doubled: input.value * 2 };
}
});
return useInvoker<{ value: number }, { doubled: number }>('test:command');
},
{
wrapper: ({ children }) => (
<CommanderProvider commander={new Commander()}>
{children}
</CommanderProvider>
)
}
);
const output = await result.current({ value: 5 });
expect(output.doubled).toBe(10);
});๐ง Configuration
Commander Options
const commander = new Commander({
maxHistorySize: 200, // Maximum execution history entries
maxRecentSize: 15, // Maximum recent commands to track
executionTimeout: 30000, // Default timeout for commands (ms)
enableDevTools: true, // Enable debugging features
});Provider Options
<CommanderProvider
commander={commander}
enableDevTools={true}
onReady={(commander) => {
// Called when commander is ready
console.log('Commander initialized');
}}
>
{children}
</CommanderProvider>๐ License
MIT ยฉ Anderson Rosa
๐ค Contributing
We love contributions! See our Contributing Guide for details.
๐ฌ Community & Support
- ๐ Bug Reports: GitHub Issues
- ๐ก Feature Requests: GitHub Discussions
- ๐ Full Documentation: View all docs
โญ Show Your Support
If Commander helps your project, please consider:
- โญ Starring this repository
- ๐ฆ Sharing on social media
- ๐ Writing about your experience
- ๐ค Contributing to the project
Built with โค๏ธ by Anderson Rosa
Part of the DarkSnow UI ecosystem
โญ Star on GitHub โข ๐ Read the Docs โข ๐ View Examples