artisanal_widgets

Flutter-inspired widget framework for terminal UIs, built on top of artisanal.

This is the primary package for widget-first apps. Use the umbrella package:artisanal/... widget entrypoints only when you intentionally want the broader Artisanal toolkit from a single dependency.

Table of Contents

Installation

dependencies:
  artisanal_widgets: ^0.1.0

Import

import 'package:artisanal_widgets/app.dart';
import 'package:artisanal_widgets/widgets.dart';

Use the focused stable entrypoints when you need those modules:

  • package:artisanal_widgets/app.dart for app shells, runners, reload helpers, and hosted wrappers
  • package:artisanal_widgets/charting.dart for chart widgets
  • package:artisanal_widgets/editors.dart for TextField, TextArea, TextEditor, CodeEditor, MarkdownEditor, and the stable TextInputKeyMap / TextAreaKeyMap customization surface
  • package:artisanal_widgets/selection.dart for SelectableText and SelectionArea
  • package:artisanal_widgets/testing.dart for WidgetTester

The main package:artisanal_widgets/widgets.dart barrel also re-exports KeyMap and KeyBinding, so component-level shortcut UIs such as HelpView and zone-hit messages such as ZoneInBoundsMsg, so shortcut and pointer-aware widgets do not need an extra package:artisanal/tui.dart import.

Keep package:artisanal_widgets/artisanal_widgets.dart only when you explicitly want the broader experimental compatibility surface.

Both the local runner helpers and the hosted browser/socket helpers accept an imageAutoMode override. Hosted browser/socket runners now default Image(renderMode: auto) to session-driven capability detection, while WidgetTester keeps the portable half-block fallback for deterministic tests.

Quick start

import 'package:artisanal_widgets/app.dart';
import 'package:artisanal_widgets/widgets.dart';

class HelloApp extends StatelessWidget {
  HelloApp({super.key});

  @override
  Widget build(BuildContext context) {
    final theme = ThemeScope.of(context);
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text('Hello widgets', style: theme.titleLarge),
        Text('Press q to quit', style: theme.bodyMedium),
      ],
    );
  }
}

void main() async {
  await runArtisanalApp(
    ArtisanalApp(
      title: 'Hello widgets',
      home: HelloApp(),
    ),
  );
}

runWidgetApp() and runArtisanalApp() default to MouseMode.allMotion, so hover-driven widgets such as Tooltip, MouseRegion, and hover-aware scrollbars work without extra setup. If you call runtime.runProgram() directly, set mouseMode: runtime.MouseMode.allMotion for passive hover behavior; mouse: true alone only enables MouseMode.cellMotion.

Flutter-style component ports

  • Chips: Chip, ActionChip, ChoiceChip, FilterChip, InputChip
  • Menus: DropdownButton, DropdownMenuItem, PopupMenuButton, PopupMenuItem, CheckedPopupMenuItem, PopupMenuDivider
  • Sliders: Slider, RangeSlider, RangeValues
  • Indicators: LinearProgressIndicator, CircularProgressIndicator
  • Charts: SparklineChart, LineChart, BarChart, HeatmapChart, PieChart, RibbonChart with optional in-chart legends

Charts The OpenCode example is self-contained under example/opencode (including local data models and theme assets).

OpenCode Clone OpenCode Clone 2 Panel Box

Program Instrumentation

The core TUI runtime (Program) supports general instrumentation and automation for any app (not OpenCode-specific):

  • ProgramInterceptor for message interception/timing hooks.
  • ProgramReplay for deterministic event playback.
import 'package:artisanal/runtime.dart' as runtime;
import 'package:artisanal_widgets/app.dart';

final replay = runtime.ProgramReplay.script([
  runtime.ProgramReplayStep(
    after: Duration(milliseconds: 120),
    msg: runtime.KeyMsg(
      runtime.Key(runtime.KeyType.runes, runes: [0x61]),
    ),
  ),
  runtime.ProgramReplayStep(
    after: Duration(milliseconds: 16),
    msg: runtime.QuitMsg(),
  ),
]);

await runtime.runProgram(
  WidgetApp(MyApp()),
  options: runtime.ProgramOptions(replay: replay),
);

See the package:artisanal/runtime.dart API docs for full interceptor/replay details.

Tests

Component tests are split by widget under test/components/*_test.dart.

Useful commands:

dart test test/components
dart test
dart analyze

Command execution note

When combining commands that include runtime-managed commands (EveryCmd, StreamCmd, or helpers like every(...)), use ParallelCmd so those commands are started by Program.

Use Cmd.batch(...) for finite commands that only need execute().

Libraries

Charts

charting Charts
Stable chart widget entrypoint for terminal UIs.

Editors

editors Editors
Stable editor and text-input entrypoint for terminal widget apps.

Selection

selection Selection
Stable text selection widget entrypoint for terminal UIs.

Testing

testing Testing
Testing utilities for TUI widgets.

TUI

app TUI
Stable app-shell and runner entrypoint for terminal widget apps.
artisanal_widgets TUI
Legacy broad widget entrypoint for composable TUI components.
widgets TUI
Stable high-level widget framework for building terminal UIs.