clix 1.0.0
clix: ^1.0.0 copied to clipboard
A comprehensive CLI development toolkit for Dart - Build beautiful, interactive command-line applications with ease. Features prompts, styling, logging, progress indicators, and configuration management.
Clix #
A comprehensive CLI development toolkit for Dart - Build beautiful, interactive command-line applications with ease.
Features #
- π― Unified Solution - All CLI tools in one package, no multiple dependencies needed
- πͺ Type Safe - Full Dart null safety with comprehensive type support
- π§ͺ Testing Ready - Built-in mock I/O for easy testing, unlike manual setup alternatives
- β Rich Validation - Flexible validator system for all input types
- β‘ Modern API - Clean
.interact()syntax throughout, not verbose method calls - π’ Smart Numbers β - Dedicated
NumberandDecimalprompts with range validation - π Advanced Search β - Interactive search through large datasets with auto-completion
- π¨ Advanced Styling - Colors, themes, and sophisticated text formatting
- π Smart Logging - Multi-level logging with timestamps and visual indicators
- βοΈ Config Management - JSON/YAML with automatic validation, not manual file handling
- π¬ Progress Indicators - Spinners and progress bars with full customization
- π Data Display - Beautiful tables and structured output formatting
Quick Start #
dart pub add clix
Or add to your pubspec.yaml:
dependencies:
clix: ^1.0.0
import 'package:clix/clix.dart';
void main() async {
// Interactive prompts
final name = await Input('Enter your name').interact();
final confirmed = await Confirm('Continue?').interact();
// Logging with style
final logger = CliLogger.defaults();
logger.success('Welcome $name!');
// Progress indication
final spinner = Spinner('Processing...');
spinner.start();
await Future.delayed(Duration(seconds: 2));
spinner.complete('Done!');
}
Interactive Prompts #
β Unique Features:
Number,Decimal, andSearchprompts are exclusive to Clix - not found in other CLI packages!
Confirm #
// Basic confirmation
final proceed = await Confirm('Continue with installation?').interact();
// With default value
final useDefaults = await Confirm(
'Use default settings?',
defaultValue: true, // Press Enter = Yes
).interact();
Decimal β #
// Floating-point input with precision control
final price = await Decimal(
'Enter price',
min: 0.0,
max: 999.99,
defaultValue: 10.0,
).interact();
Input #
// Basic input
final name = await Input('Enter your name').interact();
// With validation
final email = await Input(
'Email address',
validator: (value) {
if (!value.contains('@')) return 'Invalid email format';
return null;
},
).interact();
// With default value
final username = await Input(
'Username',
defaultValue: 'guest',
).interact();

MultiSelect #
// Multiple selection
final features = await MultiSelect(
'Select features:',
['Auth', 'Database', 'API', 'Testing'],
defaults: [0, 3], // Pre-select first and fourth
).interact();
Number β #
// Integer input with built-in range validation
final age = await Number(
'Enter your age',
min: 0,
max: 120,
defaultValue: 25,
).interact();
Password #
// Basic password
final password = await Password('Enter password').interact();
// With confirmation and validation
final newPassword = await Password(
'Create password',
validator: (pwd) => pwd.length < 8 ? 'At least 8 characters' : null,
confirmation: true,
).interact();
Search β #

// Search in static list with auto-selection
final country = await Search(
'Search country',
options: ['USA', 'UK', 'Germany', 'France', 'Japan'],
).interact();
// Search with dynamic function (API calls, databases, etc.)
final result = await Search(
'Search users',
options: (query) async {
return await searchUsers(query); // Returns List<String>
},
minQueryLength: 2,
maxResults: 5,
).interact();
Select #
// Single selection
final framework = await Select('Choose framework:', [
'Flutter', 'React Native', 'Ionic', 'Xamarin'
]).interact();
// With default selection
final env = await Select(
'Environment:',
['Development', 'Staging', 'Production'],
defaultIndex: 0,
).interact();
Styling and Colors #
Basic Colors #
print(CliColor.red('Error message'));
print(CliColor.green('Success'));
print(CliColor.blue('Information'));
print(CliColor.yellow('Warning'));
// Custom colors
print(CliColor.rgb(255, 100, 50)('Custom orange'));
print(CliColor.hex('#FF6B35')('Hex color'));
Advanced Styling #
final style = CliStyle()
.withColor(CliColor.cyan)
.makeBold()
.makeUnderline();
print(style.format('Styled text'));
// Using themes
final theme = CliTheme.defaultTheme();
print(theme.success('Operation completed'));
print(theme.error('Something went wrong'));
Logging #

// Quick setup and usage
final logger = CliLogger.defaults();
logger.info('App started');
logger.successIcon('Task completed successfully');
logger.onSuccess('Operation finished', padding: Padding.medium);
Setup #
CliLogger.defaults()- Simple logger with default settingsCliLogger.create(showTimestamps: true, minimumLevel: LogLevel.info)- Custom configuration
Core Methods #
debug()- Debug information (filtered in production)info()- General information and status updateswarn()- Warnings and potential issueserror()- Critical errors and failuressuccess()- Positive outcomes and completionsplain()- Unstyled raw output
Color Methods #
red()- Red textgreen()- Green textblue()- Blue textyellow()- Yellow textcyan()- Cyan textwhite()- White textprimary()- Primary theme colorsecondary()- Secondary theme color
Background Colors #
onRed()- Red backgroundonGreen()- Green backgroundonBlue()- Blue backgroundonYellow()- Yellow backgroundonWhite()- White backgroundonBlack()- Black backgroundonSuccess()- Success backgroundonError()- Error backgroundonWarning()- Warning backgroundonInfo()- Info background
Icon Methods #
successIcon()- Success message with β iconerrorIcon()- Error message with β iconwarnIcon()- Warning message with β οΈ iconinfoIcon()- Info message with βΉοΈ iconideaIcon()- Tip message with π‘ iconwithIcon(message, icon: CliIcons.star)- Custom predefined iconwithIconCustom(message, icon: 'π')- Custom emoji icon
Structure and Formatting #
tree()- Tree structure with symbolspoint()- Bullet points and listslines()- Multiple lines with same levelnewLine()- Empty line spacingpromptResult()- Display prompt results- All methods support
indent: IndentLevel.level1parameter
Progress Integration #
logger.progress(total: 100)- Create progress barlogger.spinner('Loading...')- Create spinnerlogger.multiSpinner()- Create multi-spinnerlogger.table()- Create formatted table
Configuration Management #
JSON Configuration #
final config = CliConfig.fromJson('config.json');
await config.load();
final apiUrl = config.getValue<String>('api.url');
final timeout = config.getValue<int>('api.timeout', defaultValue: 30);
final features = config.getValue<List>('features', defaultValue: []);
// Validation
final errors = config.validate();
if (errors.isNotEmpty) {
logger.error('Config errors: ${errors.join(', ')}');
}
YAML Configuration #
final config = CliConfig.fromYaml('database.yaml');
await config.load();
final host = config.getValue<String>('database.host');
final port = config.getValue<int>('database.port');
Progress Indicators #

Spinners #
final spinner = Spinner('Loading data...');
spinner.start();
// Update message
spinner.update('Processing...');
await Future.delayed(Duration(seconds: 2));
// Complete
spinner.complete('Data loaded successfully');
// or spinner.fail('Failed to load data');
Spinner Types #
Spinner('Working...', type: SpinnerType.dots); // β β β Ήβ Έβ Όβ ΄β ¦β §β β
Spinner('Working...', type: SpinnerType.line); // |/-\
Spinner('Working...', type: SpinnerType.pipe); // β€ββ΄ββββ¬β
Spinner('Working...', type: SpinnerType.star); // βΆβΈβΉβΊβΉβ·
Testing #
import 'package:test/test.dart';
import 'package:clix/clix.dart';
test('prompt interaction', () async {
final mockIO = MockIO();
final theme = CliTheme.defaultTheme();
// Setup mock responses
mockIO.setInput(['John Doe', 'y']);
// Test prompts
final name = await Input('Name').interact(mockIO, theme);
final confirmed = await Confirm('Continue?').interact(mockIO, theme);
expect(name, equals('John Doe'));
expect(confirmed, isTrue);
// Verify output
final output = mockIO.getOutput();
expect(output, contains('Name:'));
});
Complete Example #
import 'package:clix/clix.dart';
void main() async {
final logger = CliLogger.defaults();
logger.primary('Project Setup Wizard');
logger.newLine();
try {
// Gather information
final projectName = await Input(
'Project name',
validator: (name) {
if (name.isEmpty) return 'Name required';
if (!RegExp(r'^[a-z][a-z0-9_]*$').hasMatch(name)) {
return 'Invalid format';
}
return null;
},
).interact();
final framework = await Select('Framework:', [
'Flutter', 'Dart Console', 'Web App'
]).interact();
final features = await MultiSelect(
'Features:',
['Auth', 'Database', 'API', 'Testing'],
defaults: [3], // Pre-select Testing
).interact();
// Confirm and create
final shouldCreate = await Confirm(
'Create project with these settings?'
).interact();
if (shouldCreate) {
final spinner = Spinner('Creating project...');
spinner.start();
await Future.delayed(Duration(seconds: 2));
spinner.update('Installing dependencies...');
await Future.delayed(Duration(seconds: 1));
spinner.complete('Project created! π');
logger.newLine();
logger.success('Project: $projectName');
logger.info('Framework: $framework');
logger.info('Features: ${features.join(', ')}');
} else {
logger.warn('Setup cancelled');
}
} catch (e) {
logger.error('Setup failed: $e');
}
}
Examples #
Run example applications:
# Basic prompts
dart example/prompts/all_prompts_example.dart
# Icon logging
dart example/prompts/icon_methods_example.dart
# Configuration
dart example/config/basic_usage.dart
# Password handling
dart example/prompts/password_example.dart
License #
MIT License - see LICENSE file for details.
