Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TCSS spillover #5342

Closed
Toniolo-Marco opened this issue Dec 4, 2024 · 1 comment
Closed

TCSS spillover #5342

Toniolo-Marco opened this issue Dec 4, 2024 · 1 comment

Comments

@Toniolo-Marco
Copy link

Description:
When popping one of the secondary screens, the TCSS properties of the popped screen get applied to the main screen. In this dummy example the button background color changes. This happens if the Screens share the same structure and the .tcss is defined with the widget class name. (Notice that I didn't try to use the same tcss class or the same id for widgets in different screens).

Expected Behavior:
After popping a Screen, all TCSS styles associated with it should be removed. The MainScreen's buttons should display styles defined in app.tcss without any residual styles from the popped screen.

Actual Behavior:
Button colors from second.tcss or first.tcss (secondary screen) persist and are applied to the MainScreen's buttons after the screen is dismissed.

Environment:

  • Operating System: Linux 6.13.0-rc1-1-MANJARO
  • Library Version: 0.88.0
  • Python Version: 3.12.7

app.py:

from textual import on
from textual.app import App, ComposeResult
from textual.widgets import Button, Label, Placeholder
from textual.containers import Vertical
from textual.screen import Screen
from textual.containers import (
    Horizontal,
    Vertical,
)


class Screen1(Screen):
    """Screen to create a new configuration for the application."""

    CSS_PATH = "first.tcss"

    def compose(self) -> ComposeResult:
        with Vertical():
            yield Label("Welcome to the first screen")
            yield Button("Dummy Button")
            yield Button("Dummy Button")
            yield Horizontal(
                Button.error("Cancel", id="cancel"),
            )

    @on(Button.Pressed, "#cancel")
    def on_button_pressed(self, event: Button.Pressed) -> None:
        self.app.pop_screen()


class Screen2(Screen):
    CSS_PATH = "second.tcss"

    def compose(self) -> ComposeResult:
        with Vertical():
            yield Label("Welcome to the second screen")
            yield Button("Dummy Button")
            yield Button("Dummy Button")
            yield Horizontal(
                Button.error("Cancel", id="cancel"),
            )

    @on(Button.Pressed, "#cancel")
    def on_button_pressed(self, event: Button.Pressed) -> None:
        self.app.pop_screen()


class MainScreen(Screen):
    """Main Screen of the application"""

    def compose(self) -> ComposeResult:
        yield Vertical(
            Label("Welcome to MainScreen!"),
            Button("Button 1", id="button-1"),
            Button("Button 2", id="button-2"),
        )

    def on_button_pressed(self, event: Button.Pressed) -> None:
        match event.button.id:
            case "button-1":
                self.app.push_screen("screen-1")
            case "button-2":
                self.app.push_screen("screen-2")


class MainApp(App):
    """Main Application"""

    CSS_PATH = "app.tcss"
    SCREENS = {
        "main": MainScreen,
        "screen-1": Screen1,
        "screen-2": Screen2,
    }

    async def on_mount(self) -> None:
        """Set the initial screen."""
        await self.push_screen("main")


if __name__ == "__main__":
    MainApp().run()

app.tcss:

Screen{
    align: center middle;
    content-align: center middle;
    background: gray;
}

Screen > Vertical{
    width: auto;
    height: auto;
    align: center middle;
    content-align: center middle;
    background: black;
}

Screen > Vertical > Button{
    width: 30;
    height: auto;
    margin: 1 1;
    background: gray;
}

Screen > Vertical > Label {
    min-width: 1fr;
    height: auto;
    align: center middle; 
    content-align: center middle;
}

firts.tcss:

Screen{
    align: center middle;
    content-align: center middle;
}

Screen > Vertical{
    width: auto;
    height: auto;
    align: center middle;
    content-align: center middle;
}

Screen > Vertical > Button{
    width: 30;
    height: auto;
    margin: 1 1;
    background: green;
}

Screen > Vertical > Label {
    min-width: 1fr;
    height: auto;
    align: center middle; 
    content-align: center middle;
}

second.tcss:

Screen {
    layout: grid;
    grid-size: 3 4;
    grid-rows: 1fr;
    grid-columns: 1fr;
    grid-gutter: 1;
}

Screen > Vertical{
    width: auto;
    height: auto;
    align: center middle;
    content-align: center middle;
}

Screen > Vertical > Button{
    width: 30;
    height: auto;
    margin: 1 1;
    background: blue;
}

Screen > Vertical > Label {
    min-width: 1fr;
    height: auto;
    align: center middle; 
    content-align: center middle;
}
@Toniolo-Marco Toniolo-Marco changed the title TCSS spillhover TCSS spillover Dec 4, 2024
@TomJGooding
Copy link
Contributor

I think this is unfortunately a footgun that discussed in #2744 and also noted in the docs, where the screen CSS actually applies to the whole app.

The workaround is simply scoping the CSS to your specific screen - i.e. MyScreen { ... } rather than the base Screen class.

@Textualize Textualize deleted a comment from github-actions bot Dec 5, 2024
@Textualize Textualize locked and limited conversation to collaborators Dec 5, 2024
@willmcgugan willmcgugan converted this issue into discussion #5346 Dec 5, 2024

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants