Add ui.custom() for custom hook components with keyboard focus

- Add custom() to HookUIContext: returns { close, requestRender }
- Component receives keyboard input via handleInput()
- CustomMessageComponent default rendering now limits to 5 lines when collapsed
- Add snake.ts example hook with /snake command
This commit is contained in:
Mario Zechner 2025-12-27 03:17:38 +01:00
parent a8866d7a83
commit 14ad8d6228
9 changed files with 315 additions and 2 deletions

View file

@ -75,6 +75,14 @@ export class CustomMessageComponent extends Container {
.join("\n");
}
// Limit lines when collapsed
if (!this._expanded) {
const lines = text.split("\n");
if (lines.length > 5) {
text = `${lines.slice(0, 5).join("\n")}\n...`;
}
}
this.box.addChild(
new Markdown(text, 0, 0, getMarkdownTheme(), {
color: (text: string) => theme.fg("customMessageText", text),

View file

@ -443,6 +443,7 @@ export class InteractiveMode {
confirm: (title, message) => this.showHookConfirm(title, message),
input: (title, placeholder) => this.showHookInput(title, placeholder),
notify: (message, type) => this.showHookNotify(message, type),
custom: (component) => this.showHookCustom(component),
};
}
@ -539,6 +540,42 @@ export class InteractiveMode {
}
}
/**
* Show a custom component with keyboard focus.
* Returns a function to call when done.
*/
private showHookCustom(component: Component & { dispose?(): void }): {
close: () => void;
requestRender: () => void;
} {
// Store current editor content
const savedText = this.editor.getText();
// Replace editor with custom component
this.editorContainer.clear();
this.editorContainer.addChild(component);
this.ui.setFocus(component);
this.ui.requestRender();
// Return control object
return {
close: () => {
// Call dispose if available
component.dispose?.();
// Restore editor
this.editorContainer.clear();
this.editorContainer.addChild(this.editor);
this.editor.setText(savedText);
this.ui.setFocus(this.editor);
this.ui.requestRender();
},
requestRender: () => {
this.ui.requestRender();
},
};
}
/**
* Show a hook error in the UI.
*/