File size: 1,750 Bytes
f500658 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | import type { Component } from "@earendil-works/pi-tui";
import { Box, Container, Spacer, Text } from "@earendil-works/pi-tui";
import type { EntryRenderer } from "../../../core/extensions/types.ts";
import type { CustomEntry } from "../../../core/session-manager.ts";
import { theme } from "../theme/theme.ts";
/**
* Component that renders a custom session entry from extensions.
* The host owns transcript spacing; renderer output should provide only its content.
*/
export class CustomEntryComponent extends Container {
private entry: CustomEntry<unknown>;
private renderer: EntryRenderer;
private customComponent?: Component;
private _expanded = false;
constructor(entry: CustomEntry<unknown>, renderer: EntryRenderer) {
super();
this.entry = entry;
this.renderer = renderer;
this.rebuild();
}
hasContent(): boolean {
return this.customComponent !== undefined;
}
setExpanded(expanded: boolean): void {
if (this._expanded !== expanded) {
this._expanded = expanded;
this.rebuild();
}
}
override invalidate(): void {
super.invalidate();
this.rebuild();
}
private rebuild(): void {
this.clear();
this.customComponent = undefined;
let component: Component | undefined;
try {
component = this.renderer(this.entry, { expanded: this._expanded }, theme);
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
const box = new Box(1, 1, (text) => theme.bg("customMessageBg", text));
box.addChild(new Text(theme.fg("error", `[${this.entry.customType}] renderer failed: ${message}`), 0, 0));
component = box;
}
if (!component) {
return;
}
this.customComponent = component;
this.addChild(new Spacer(1));
this.addChild(component);
}
}
|