from textual.app import App, ComposeResult from textual.widgets import Input, RichLog, ListItem, ListView, Label, Static, Button from textual.containers import Horizontal, Vertical, ScrollableContainer class ChatApp(App): DEFAULT_CSS = """ #contacts { width: 20; } #messages { height: 1fr; padding: 0 0 0 1; background: $background; } #input-row { height: auto; } #input-row > Input { width: 1fr; } #input-row > Button { width: 10; margin-right: 1; } """ def send(self): input_box = self.query_one("#input-box", Input) message = input_box.value if message.strip(): self.query_one("#messages").mount(ListItem(Label(message))) input_box.clear() def compose(self) -> ComposeResult: with Horizontal(): yield ListView( ListItem(Label("One")), ListItem(Label("Two")), ListItem(Label("Three")), id="contacts", ) with Vertical(): yield ListView(id="messages") with Horizontal(id="input-row"): yield Input(placeholder="Message...", id="input-box") yield Button("Send", id="send-btn", disabled=True) def on_input_submitted(self, event: Input.Submitted) -> None: if event.input.id == "input-box": self.send() def on_button_pressed(self, event: Button.Pressed) -> None: if event.button.id == "send-btn": self.send() def on_input_changed(self, event: Input.Changed) -> None: if event.input.id == "input-box": self.query_one("#send-btn", Button).disabled = not event.value.strip() def on_mount(self) -> None: self.query_one(Input).focus() print(self.query_one(Button)) ChatApp().run()