artisanal 0.2.0+1
artisanal: ^0.2.0+1 copied to clipboard
A full-stack terminal toolkit for Dart featuring Lip Gloss styling, Bubble Tea TUI architecture, and Ultraviolet rendering.
Artisanal #
About this project:
This library is a faithful port of Charm's TUI libraries (Lip Gloss, Bubble Tea, Bubbles) to Dart. We aim to port as much functionality as possible. In some scenarios, things may not work as expected—please report any issues you discover so we can adjust where necessary.
Many of the included examples were generated and may contain issues or not reflect the latest API. If you find a broken or outdated example, please let us know!
⚠️ Work in Progress:
This library is under active development and its API may change. Some examples may be broken or require updates to match the latest state of the package. If you discover any broken or outdated examples, please report them or open an issue. Thank you for your understanding!
A full-stack terminal toolkit for Dart, inspired by popular Go terminal libraries: Lip Gloss (styling), Bubble Tea (TUI framework), and Bubbles (reusable widgets).
Build everything from rich command-line tools to complex interactive TUI applications with a consistent, idiomatic Dart API.
Features #
| Feature | Description |
|---|---|
| CLI I/O | High-level Console helpers for status lines, tables, tasks, prompts, and styled output |
| Styling | Fluent, immutable Style API with colors, borders, padding, margins, and themes |
| TUI Runtime | Elm Architecture (Model/Msg/Cmd) with a full-featured Program event loop |
| Bubbles | 20+ reusable widgets: inputs, lists, tables, spinners, progress bars, file pickers, etc. |
| Ultraviolet (UV) | High-performance cell-buffer renderer with diff-based updates and graphics support |
| Terminal + Renderer | Unified terminal abstraction, ANSI helpers, and renderer backends |
| Markdown | ANSI Markdown renderer plus Glamour high-fidelity output |
| Charting | Sparklines, line/ribbon charts, histograms, heatmaps, and pie charts |
Installation #
dependencies:
artisanal: ^0.2.0
Note: This package uses workspace resolution. Use a path or git reference in standalone projects.
🖼️ Screenshots #
Library Exports #
| Import | Purpose |
|---|---|
package:artisanal/artisanal.dart |
Full CLI kit (Console, Style, Terminal, Layout) |
package:artisanal/args.dart |
Command runner utilities (CommandRunner, Command) |
package:artisanal/style.dart |
Styling, Layout, Colors, Borders, Themes |
package:artisanal/tui.dart |
TUI runtime: Model, Msg, Cmd, Program |
package:artisanal/bubbles.dart |
Reusable interactive widgets |
package:artisanal/terminal.dart |
Terminal abstraction, ANSI codes, Keys |
package:ultraviolet/ultraviolet.dart |
Low-level cell-buffer renderer |
package:artisanal/uv.dart |
Compatibility re-export for UV (package:ultraviolet/ultraviolet.dart) |
package:artisanal/markdown.dart |
Markdown to ANSI renderer |
package:artisanal/glamour.dart |
High-fidelity Markdown renderer |
package:artisanal/charting.dart |
Charting primitives |
Documentation #
See the in-repo docs for full coverage:
docs/DOCS_INDEX.md
Quick Start: CLI Output #
import 'package:artisanal/artisanal.dart';
Future<void> main() async {
final io = Console();
io.title('My App');
io.section('Setup');
io.info('Checking configuration...');
await io.task('Running migrations', run: () async {
await Future.delayed(const Duration(milliseconds: 200));
return TaskResult.success;
});
io.table(
headers: ['ID', 'Name', 'Status'],
rows: [
[1, 'users', io.style.success('DONE')],
[2, 'posts', io.style.warning('PENDING')],
],
);
final proceed = io.confirm('Continue?', defaultValue: true);
if (!proceed) return;
io.success('All good.');
}
Quick Start: Styling (Lip Gloss) #
import 'package:artisanal/style.dart';
final style = Style()
.bold()
.foreground(Colors.purple)
.padding(1, 2)
.border(Border.rounded);
print(style.render('Hello, Artisanal!'));
Style Capabilities #
- Text effects:
bold(),italic(),underline(),strikethrough(),dim(),inverse(),blink() - Colors: ANSI 16, ANSI 256, TrueColor (RGB),
AdaptiveColor(light/dark aware) - Spacing:
padding(),margin() - Borders:
rounded,thick,double,hidden, custom - Alignment:
align(),alignVertical() - Dimensions:
width(),height(),maxWidth(),maxHeight() - Themes:
ThemePalettewith presets (dark, light, ocean, nord, dracula, monokai, solarized)
Quick Start: TUI (Elm Architecture) #
import 'package:artisanal/tui.dart';
class CounterModel implements Model {
final int count;
const CounterModel([this.count = 0]);
@override
Cmd? init() => null;
@override
(Model, Cmd?) update(Msg msg) {
return switch (msg) {
KeyMsg(key: Key(type: KeyType.up)) => (CounterModel(count + 1), null),
KeyMsg(key: Key(type: KeyType.down)) => (CounterModel(count - 1), null),
KeyMsg(key: Key(type: KeyType.runes, runes: [0x71])) => (this, Cmd.quit()),
_ => (this, null),
};
}
@override
String view() => 'Count: \$count\n\nUse ↑/↓ to change, q to quit';
}
Future<void> main() async {
await runProgram(CounterModel());
}
Replay + Trace Debugging #
The TUI runtime supports deterministic replay (ProgramReplay) and built-in
file tracing (TuiTrace) for debugging and profiling.
Enable tracing for any TUI app:
ARTISANAL_TUI_TRACE=1 ARTISANAL_TUI_TRACE_CAPTURE=1 \
ARTISANAL_TUI_TRACE_PATH=traces/my-run.log \
dart run your_app.dart
Structured app/domain events can be emitted via TuiTrace.event(...) and are
preserved in replay conversion when they use stable typed type names.
Full replay and tracing documentation: docs/TUI.md.
Bubbles (Reusable Widgets) #
| Widget | Description |
|---|---|
TextInputModel |
Single-line text input |
TextAreaModel |
Multi-line text editing |
ListModel |
Filterable list selection |
TableModel |
Interactive tables |
ViewportModel |
Scrollable content pane |
ProgressModel |
Progress bars with ETA |
SpinnerModel |
Animated loading spinners |
FilePickerModel |
File/directory browser |
AnticipateModel |
Autocomplete with suggestions |
WizardModel |
Multi-step form wizard |
SelectModel<T> |
Single-choice selection prompt |
MultiSelectModel<T> |
Multiple-choice selection |
PasswordModel |
Masked password input |
TimerModel |
Countdown timer |
StopwatchModel |
Elapsed time tracking |
PaginatorModel |
Pagination controls |
HelpModel |
Key binding help views |
Command Runner #
Build CLI tools with styled help and nested commands:
import 'package:artisanal/args.dart';
class HelloCommand extends Command {
@override
String get name => 'hello';
@override
String get description => 'Say hello';
@override
void run() {
io.success('Hello, world!');
}
}
void main(List<String> args) {
final runner = CommandRunner('my-cli', 'A great CLI');
runner.addCommand(HelloCommand());
runner.run(args);
}
Ultraviolet Renderer #
High-performance rendering with diff-based updates for flicker-free TUI applications:
await runProgram(
MyModel(),
options: const ProgramOptions(
useUltravioletRenderer: true,
useUltravioletInputDecoder: true,
altScreen: true,
mouse: true,
),
);
UV Features #
- 2D cell buffer with styled cells
- Diff-based terminal updates (minimal redraws)
- Layer composition and hit-testing
- Mouse support and focus events
- Graphics: Kitty, Sixel, iTerm2, half-block drawing
Console Methods #
| Category | Methods |
|---|---|
| Output | writeln(), write(), title(), section() |
| Messages | line(), info(), comment(), question(), warn(), error(), note(), caution(), alert(), verbose(), debug() |
| Layout | table(), tree(), listing(), twoColumnDetail(), text() |
| Interactive | ask(), confirm(), choice(), secret(), selectChoice(), multiSelectChoice(), menu(), search() |
| Progress | task(), spin(), progress(), progressIterate() |
Examples #
See the example/ directory for comprehensive demos:
main.dart– Full feature showcasefluent_style_example.dart– Style API patternsspinner_demo.dart– Various spinner typeslipgloss_table.dart– Styled tableslog_viewer_demo.dart– Monitoring dashboardcommand_center_demo.dart– Multi-panel layouts- UV-specific demos now live in
pkgs/ultraviolet/example/