sugarcraft / candy-kit
PHP port of charmbracelet/fang — opinionated CLI presentation helpers: StatusLine (✓/✗/⚠/ℹ), Banner, Section header, Stage step, HelpText page, and 6 stock themes (ansi/plain/charm/dracula/nord/catppuccin).
Requires
- php: ^8.3
- sugarcraft/candy-core: dev-master
- sugarcraft/candy-sprinkles: dev-master
Requires (Dev)
- phpunit/phpunit: ^10.5
- sugarcraft/candy-testing: dev-master
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-03 15:31:42 UTC
README
CandyKit
composer require sugarcraft/candy-kit
PHP port of charmbracelet/fang — opinionated CLI presentation helpers that turn ordinary command- line output into something that matches the rest of the SugarCraft stack. CandyKit is library-only — drop it into any Composer project, no Symfony Console requirement.
use SugarCraft\Kit\StatusLine; use SugarCraft\Kit\Banner; use SugarCraft\Kit\Theme; echo Banner::title('CandyApp', 'v0.1.0'), "\n\n"; echo StatusLine::info('connecting to https://example.com'), "\n"; echo StatusLine::success('done in 0.4s'), "\n"; echo StatusLine::warn('disk almost full'), "\n"; echo StatusLine::error('connection refused'), "\n";
Components
Theme— palette ofSprinkles\Styleobjects keyed by status level (success / error / warn / info / prompt / accent / muted).Theme::ansi()ships the colourful palette; bring your own theme by passing styles to the constructor (orTheme::build()).Theme::detect()is theansi()palette downgraded to what the output can show, via candy-core'sColorProfile::detect(): no escape bytes at all when STDOUT is not a tty (myapp --help | less), colour dropped but bold kept underNO_COLORon a terminal, full colour forced byCLICOLOR_FORCE/FORCE_COLOR. As in upstreamcolorprofile, tty-ness is checked beforeNO_COLOR, so a pipe gets plain text whether or notNO_COLORis set. Every presenter called without a theme usesTheme::detect(); an explicitly passed theme is rendered as given — apply the same downgrade to any preset with$theme->withColorProfile(ColorProfile::detect(null, STDOUT)).StatusLine—success/error/warn/infostatic helpers returning a glyph + message string styled per the active theme.Banner— render a bordered title block with optional subtitle, rounded by default. Useful for app intros /--versionoutput.Logo— ASCII-art logo renderer withLogo::sugarcraft()built-in preset andLogo::fromAscii($art)for custom art. Chain->withColor($hex)to apply foreground color.Section— one-line themed dividers:header()label + fill rule, barerule(), and indentedsubHeader()for nesting under a parent. An explicitwidthis a hard cap: an over-long label is cut with…rather than overflowing the line.Stage— per-line step renderers for progressive CLI output:step()(numbered),subStep(), andsubStepWithProgress()(bar or spinner).HelpText— fang-style--helppage:USAGE, an optional description, and titled two-columnKEY descriptionsections. Wraps towidth(default 80,null= never wrap): long descriptions continue at the description column, and switch to a stacked layout (description under the key) when the key column leaves fewer than 16 cells.Frame— full-screen application chrome: a double-line box that fills the terminal exactly (Frame::new()->withTitle($bar) ->withStatus($bar)->render($body, $cols, $rows)), with a centred title bar, dividers, and a status bar. Normalises the body to a constant line count and pads ANSI-width-aware so it never overflows the terminal — safe for a TEA program whose frame-diff renderer owns the screen.
Demos
CLI page
Test
cd candy-kit && composer install && vendor/bin/phpunit
Snapshot tests
Presenter output is pinned via candy-testing's assertGoldenAnsi golden-file
snapshots. Any change to the ANSI slide output must be intentional — re-record
the fixtures with UPDATE_GOLDENS=1 vendor/bin/phpunit to accept a new
canonical render.
