Skip to content

Configure the Screen

An app's global setup lives on the Screen — the shared services it can reach, the keys the framework binds, and how it drives the terminal — all set before run().

Overview

The Screen builder is where anything app-wide is configured: register shared services for any component to resolve, remap the keys Phui binds for itself, and set terminal options, then call run().

Register services

Share objects that are not UI state — an API client, a repository, a config — by binding them on the screen and looking them up in any component. A service lives outside the component tree: one place owns it for the app's lifetime, and any component resolves it by class, so shared dependencies aren't threaded down through props to reach a deep child.

Register a service

Bind instances before running the app:

php
Screen::mount(App::class)
    ->service(Api::class, new Api($apiKey))
    ->service(TaskStore::class, new TaskStore)
    ->run();

Resolve it in a component

$this->get() returns the exact instance you registered, by class name:

php
public function onMount(): void
{
    $this->get(Api::class)->prefetch();
}

get() is a service locator — one shared object per class, with no construction or injection. Asking for a class that was never registered throws MissingServiceException, so a forgotten service() fails at the lookup rather than as a null somewhere later.

Guard an optional service

For a dependency that may not be registered, check with has() first:

php
if ($this->has(Api::class)) {
    $this->get(Api::class)->prefetch();
}

What belongs in a service

Anything cross-cutting that is not UI state — clients, repositories, config, and shared stores that async work writes into. UI state itself belongs in #[State] and props; Phui cannot track changes made inside a service, so state smuggled through one will not rebuild the component on its own.

Remap the built-in keys

Phui binds a few keys for itself — Tab and Shift+Tab to move focus, Ctrl+C to quit, and F12 to toggle the debug bar. Override any of them by passing a replacement to bindings(); a null entry keeps the default, so you name only the keys you're changing:

php
use Phui\Bindings\Binding;
use Phui\Events\Keyboard\Keypress;

Screen::mount(App::class)
    ->bindings(
        quit: Binding::keypress(Keypress::ESCAPE),
        toggleDebug: Binding::keypress(Keypress::F1),
    )
    ->run();

These are the framework's own bindings; a component's own bindings() sit on top of them.

Terminal options

The same builder toggles how the screen drives the terminal, all before run():

  • mouse() — mouse reporting, and how much movement is tracked.
  • cursor(false) — hide the terminal cursor.
  • bracketedPaste() — receive a paste as one PasteEvent instead of key by key.
  • colours(...) — pin the colour depth rather than letting Phui detect it.

See the Screen reference for the full set, alongside the inline and debug toggles covered in their own guides.

Colour support

You author colours as 24-bit hex, but not every terminal can show them. Phui detects what the terminal supports at startup and degrades every colour to fit, keeping the hue rather than the exact value — a pastel pink stays pink instead of washing out to grey. Text decorations like bold and underline are never touched, whatever the mode.

Detection runs once. NO_COLOR (set to anything) or TERM=dumb forces colour off entirely, above whatever the terminal reports about itself. You may pin the mode yourself when necessary:

php
use Phui\Colours\ColourMode;

Screen::mount(App::class)
    ->colours(ColourMode::Ansi16)
    ->run();

Terminal ownership

run() puts the terminal into raw mode on its own screen and restores it on the way out — on a normal exit, on the Ctrl+C quit binding, and, with the pcntl extension installed, on SIGTERM. You get the terminal back the way you left it however the app ends.

If the process isn't attached to a terminal — its output is piped, say — run() writes a message to STDERR and exits with code 1 rather than drawing into nothing.

Released under the MIT License.