artisanal_widgets 0.4.2 copy "artisanal_widgets: ^0.4.2" to clipboard
artisanal_widgets: ^0.4.2 copied to clipboard

Widget system for composable TUI components, built on top of the artisanal terminal toolkit.

artisanal_widgets #

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

This is the package for widget-first apps. Widget APIs, runners, and test helpers are owned here; the core artisanal package does not re-export them.

Table of Contents #

Installation #

dependencies:
  artisanal_widgets: ^0.4.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.

WidgetTester remains view-only by default. For an opt-in final production cell frame, pass enableRenderer: true and enableNativeFrameCapture: true; read the resulting tester.latestNativeFrame. Native-frame recording copies cells and does not include drawable payloads.

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 runWidgetApp(
    ArtisanalApp(
      title: 'Hello widgets',
      home: HelloApp(),
    ),
  );
}

runWidgetApp() defaults 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. Setting only mouse: true enables MouseMode.cellMotion instead.

Flutter-style component ports #

  • Chips: Chip, ActionChip, ChoiceChip, FilterChip, InputChip
  • Menus: DropdownButton, DropdownMenuItem, PopupMenuButton, PopupMenuItem, CheckedPopupMenuItem, PopupMenuDivider
  • Sliders: Slider, RangeSlider, RangeValues
  • Indicators: LinearProgressIndicator, CircularProgressIndicator
  • Data display: DataTable.cells with column spans and alignment, MonthlyCalendar, and terminal-cell Shadow presets
  • Charts: SparklineChart, LineChart, BarChart, HeatmapChart, PieChart, RibbonChart with optional in-chart legends

The example/widget_features app combines these components with a fixed terminal viewport, UV subtree filters, and world-coordinate canvas shapes. For a focused effects walkthrough, run dart run example/uv_effects/main.dart; it compares an ordinary widget tree with a CellFilter-processed copy and includes a composed filter stack.

For a production-style primary-screen example, run dart run example/inline_build_monitor/main.dart. It keeps a responsive build dashboard pinned at the bottom while staged command output streams into native terminal scrollback. Press p to pause, r to rebuild, e to simulate a failure, or q to quit.

Charts The OpenCode CLI app is self-contained under apps/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/tui.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/tui.dart API docs for full interceptor/replay details.

Tests #

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

For reusable captures, artisanal_capture exposes captureWidget(..., mode: WidgetCaptureMode.renderedFrame). Its default WidgetCaptureMode.view is cheaper and captures the portable view text; rendered-frame mode exercises the production UV renderer and requires native frame capture. This distinction matters for styled-cell fidelity.

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().

Demo captures #

Recordings of some of the more consequential examples, regenerated from the VHS tapes in example/.vhs/ with task widgets-demos. Every recorded example also has a page with a preview and its full source on the documentation site.

Widget app shell (example/artisanal_app/main.dart):

Widget app demo

Charting (example/charting/main.dart):

Charting demo

Git diff viewer (example/git-diff/main.dart):

Git diff demo

Data table (example/data_table/main.dart):

Data table demo

Command palette (example/command_palette/main.dart):

Command palette demo

Code editor (example/code-editor/main.dart):

Code editor demo

Markdown editor (example/markdown-editor/main.dart):

Markdown editor demo

Data visualization (example/dataviz/main.dart):

DataViz demo

Debug console (example/debug_console/main.dart):

Debug console demo

OpenCode chat UI (apps/opencode/bin/opencode.dart):

OpenCode demo

Buttons & badges (example/buttons/main.dart):

Buttons demo

Form inputs (example/inputs/main.dart):

Inputs demo

Text field (example/text-field/main.dart):

Text field demo

Text area (example/text-area/main.dart):

Text area demo

Tree view (example/tree_view/main.dart):

Tree view demo

Tabs & breadcrumbs (example/tabs_nav/main.dart):

Tabs demo

Text selection (example/selection/main.dart):

Selection demo

Progress & spinner (example/progress_spinner/main.dart):

Progress spinner demo

Slider (example/slider/main.dart):

Slider demo

Scrolling (example/scroll/main.dart):

Scroll demo

File picker (example/file_picker/main.dart):

File picker demo

Help view (example/help_view/main.dart):

Help view demo

1
likes
160
points
4.92k
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Widget system for composable TUI components, built on top of the artisanal terminal toolkit.

Repository (GitHub)
View/report issues

Topics

#cli #tui #terminal #widget

Funding

Consider supporting this project:

www.buymeacoffee.com

License

MIT (license)

Dependencies

artisanal, image, listen, meta

More

Packages that depend on artisanal_widgets