> ## Documentation Index
> Fetch the complete documentation index at: https://klyx.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Screens & Navigation

> Register composable screens and navigate between them

Extensions can register custom screens that appear in Klyx's navigation system. Screens are Jetpack Compose composables identified by a `ScreenId`. Navigation is handled through the `Navigator` service.

## ScreenRegistry

Register screens during `onLoad()` and unregister them in `onUnload()`. Registration uses Kotlin context receivers — you do not pass the plugin instance explicitly.

### Register a screen

```kotlin theme={null}
private val screens: ScreenRegistry by plugin()

// Inside a KlyxPlugin method:
screens.register(
    Screen(
        id = ScreenId("myext.main"),
        content = { MainScreen() }
    )
)
```

The `ScreenId` is a value class wrapping a string. By convention, use reverse-DNS notation:

```
"com.myext.screenname"
```

### Unregister a screen

```kotlin theme={null}
screens.unregister(ScreenId("myext.main"))
```

### Set screen content

Replace an existing screen's composable without unregistering:

```kotlin theme={null}
screens[ScreenId("myext.main")] = { UpdatedMainScreen() }
```

### Get screen content

Retrieve a registered screen's composable:

```kotlin theme={null}
val content: Content? = screens[ScreenId("myext.main")]
```

### Check ownership

```kotlin theme={null}
val ownerPluginId: String? = screens.ownerOf(ScreenId("myext.main"))
```

### Transient screens

`setTransient` registers short-lived content that **shadows** any previously registered screen for the same id. `unregisterTransient` removes it and restores the previous registration. The host auto-unregisters transient screens when their navigation entry is popped, so you normally don't need to clean them up manually — see [openScreen](#open-a-screen-with-inline-content).

```kotlin theme={null}
screens.setTransient(ScreenId("myext.preview")) { PreviewScreen(uri) }

// Optional; the host also removes it when the screen is popped:
screens.unregisterTransient(ScreenId("myext.preview"))
```

Use `register` for screens that should persist for the plugin's lifetime, and `setTransient` for one-shot screens opened on demand.

## Navigation

Use the `Navigator` service to navigate between destinations.

```kotlin theme={null}
private val navigator: Navigator by plugin()
```

### Navigate to a destination

```kotlin theme={null}
navigator.navigateTo(NavDestination.Home)
navigator.navigateTo(NavDestination.Settings)
navigator.navigateTo(NavDestination.Terminal)
navigator.navigateTo(NavDestination.Custom(ScreenId("myext.main")))
```

You can also use the convenience extension:

```kotlin theme={null}
navigator.navigateTo(ScreenId("myext.main"))
```

### Open a screen with inline content

Open a screen directly from a composable, without pre-registering it. Because the content is a closure, it can capture any data the screen needs — a file, a URI, a result object — giving custom screens the same payload support that custom editor tabs have:

```kotlin theme={null}
navigator.openScreen(ScreenId("myext.html.preview")) {
    HtmlPreviewScreen(uri = fileUri)
}
```

The screen is registered as a *transient* screen: the host **auto-unregisters it when its navigation entry is popped**, so no cleanup is required. `openScreen` also returns a `ScreenRegistration` if you want to remove it earlier:

```kotlin theme={null}
val registration = navigator.openScreen(ScreenId("myext.preview")) { PreviewScreen(uri) }
// ...
registration.unregister()
```

This works from any plugin code — toolbar actions, settings, lifecycle methods. File runners use the same API via their `FileRunnerContext`.

### Navigate back

```kotlin theme={null}
navigator.navigateBack()
```

## NavDestination

A sealed class representing destinations within the app.

| Destination                       | Description                     |
| --------------------------------- | ------------------------------- |
| `NavDestination.Home`             | The main Klyx home screen       |
| `NavDestination.Settings`         | The application settings screen |
| `NavDestination.Terminal`         | The integrated terminal screen  |
| `NavDestination.Custom(ScreenId)` | A screen registered by a plugin |

## SpecialScreens

Pre-built `ScreenId` constants for core destinations:

```kotlin theme={null}
SpecialScreens.Home       // ScreenId("<klyx-home>")
SpecialScreens.Settings   // ScreenId("<klyx-settings>")
SpecialScreens.Terminal   // ScreenId("<klyx-terminal>")
```

## API reference

### ScreenId

| Element        | Type          | Description                             |
| -------------- | ------------- | --------------------------------------- |
| `ScreenId(id)` | `value class` | Wraps a unique screen identifier string |

### Screen

| Property  | Type                     | Description                      |
| --------- | ------------------------ | -------------------------------- |
| `id`      | `ScreenId`               | Unique identifier for the screen |
| `content` | `@Composable () -> Unit` | The Compose UI content           |

### ScreenRegistration

| Method         | Description                          |
| -------------- | ------------------------------------ |
| `unregister()` | Removes the screen from the registry |

### ScreenRegistry

| Method                      | Returns              | Description                                                       |
| --------------------------- | -------------------- | ----------------------------------------------------------------- |
| `register(screen)`          | `ScreenRegistration` | Register a screen (requires `KlyxPlugin` context)                 |
| `unregister(id)`            |                      | Unregister a screen by ID                                         |
| `set(id, content)`          |                      | Update screen content via operator (removes any transient screen) |
| `setTransient(id, content)` |                      | Register short-lived content, shadowing any previous registration |
| `unregisterTransient(id)`   |                      | Remove a transient screen, restoring the previous registration    |
| `get(id)`                   | `Content?`           | Get screen content via operator (transient takes precedence)      |
| `ownerOf(id)`               | `String?`            | Get the owning plugin ID                                          |

### Navigator

| Method                          | Returns              | Description                                                                                        |
| ------------------------------- | -------------------- | -------------------------------------------------------------------------------------------------- |
| `navigateTo(destination)`       |                      | Navigate to a destination                                                                          |
| `navigateBack()`                |                      | Go back to the previous screen                                                                     |
| `openScreen(screenId, content)` | `ScreenRegistration` | Register the composable for the id and navigate to it; auto-unregistered when the screen is popped |

### LocalTabs

A `CompositionLocal` providing access to the `Tabs` service for managing workspace tabs.

## Example

Register multiple screens during `onLoad()`:

```kotlin theme={null}
screens[ScreenId("demo.main")] = { MainDemoScreen(...) }
screens[ScreenId("demo.process")] = { ProcessDemoScreen(fileSystem) }
screens[ScreenId("demo.filesystem")] = { FileSystemDemoScreen(fileSystem) }
screens[ScreenId("demo.editor")] = { EditorDemoScreen(fileSystem) }
screens[ScreenId("demo.services")] = { ServiceDemoScreen() }
screens[ScreenId("demo.terminal")] = { TerminalDemoScreen() }
screens[ScreenId("demo.events")] = { EventDemoScreen() }
screens[ScreenId("demo.utilities")] = { UtilityDemoScreen() }
```

Each screen is a Composable function that receives the services it needs as parameters. Toolbar actions navigate to these screens:

```kotlin theme={null}
toolbar.register(ToolbarAction(
    id = "demo.show_main",
    label = "Sample Plugin",
    onClick = { navigator.navigateTo(ScreenId("demo.main")) }
) {})
```
