diff --git a/poetry.lock b/poetry.lock index 0bdbd738c..c1d1edef8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -52,7 +52,7 @@ python-versions = ">=3.5" [[package]] name = "atomicwrites" -version = "1.4.0" +version = "1.4.1" description = "Atomic file writes." category = "dev" optional = false @@ -208,7 +208,7 @@ dev = ["twine", "markdown", "flake8", "wheel"] [[package]] name = "griffe" -version = "0.21.0" +version = "0.22.0" description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." category = "dev" optional = false @@ -345,7 +345,7 @@ mkdocs = ">=1.1" [[package]] name = "mkdocs-material" -version = "8.3.8" +version = "8.3.9" description = "Documentation that simply works" category = "dev" optional = false @@ -713,7 +713,7 @@ python-versions = ">=3.6" [[package]] name = "typing-extensions" -version = "4.2.0" +version = "4.3.0" description = "Backported and Experimental Type Hints for Python 3.7+" category = "main" optional = false @@ -721,7 +721,7 @@ python-versions = ">=3.7" [[package]] name = "virtualenv" -version = "20.15.0" +version = "20.15.1" description = "Virtual Python Environment builder" category = "dev" optional = false @@ -869,10 +869,7 @@ asynctest = [ {file = "asynctest-0.13.0-py3-none-any.whl", hash = "sha256:5da6118a7e6d6b54d83a8f7197769d046922a44d2a99c21382f0a6e4fadae676"}, {file = "asynctest-0.13.0.tar.gz", hash = "sha256:c27862842d15d83e6a34eb0b2866c323880eb3a75e4485b079ea11748fd77fac"}, ] -atomicwrites = [ - {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, - {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, -] +atomicwrites = [] attrs = [ {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"}, {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"}, @@ -1042,10 +1039,7 @@ ghp-import = [ {file = "ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"}, {file = "ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619"}, ] -griffe = [ - {file = "griffe-0.21.0-py3-none-any.whl", hash = "sha256:e9fb5eeb7c721e1d84804452bdc742bd57b120b13aba663157668ae2d217088a"}, - {file = "griffe-0.21.0.tar.gz", hash = "sha256:61ab3bc02b09afeb489f1aef44c646a09f1837d9cdf15943ac6021903a4d3984"}, -] +griffe = [] identify = [ {file = "identify-2.5.1-py2.py3-none-any.whl", hash = "sha256:0dca2ea3e4381c435ef9c33ba100a78a9b40c0bab11189c7cf121f75815efeaa"}, {file = "identify-2.5.1.tar.gz", hash = "sha256:3d11b16f3fe19f52039fb7e39c9c884b21cb1b586988114fbe42671f03de3e82"}, @@ -1124,10 +1118,7 @@ mkdocs-autorefs = [ {file = "mkdocs-autorefs-0.4.1.tar.gz", hash = "sha256:70748a7bd025f9ecd6d6feeba8ba63f8e891a1af55f48e366d6d6e78493aba84"}, {file = "mkdocs_autorefs-0.4.1-py3-none-any.whl", hash = "sha256:a2248a9501b29dc0cc8ba4c09f4f47ff121945f6ce33d760f145d6f89d313f5b"}, ] -mkdocs-material = [ - {file = "mkdocs-material-8.3.8.tar.gz", hash = "sha256:b9cd305c3c29ef758931dae06e4aea0ca9f8bcc8ac6b2d45f10f932a015d6b83"}, - {file = "mkdocs_material-8.3.8-py2.py3-none-any.whl", hash = "sha256:949c75fa934d4b9ecc7b519964e58f0c9fc29f2ceb04736c85809cdbc403dfb5"}, -] +mkdocs-material = [] mkdocs-material-extensions = [ {file = "mkdocs-material-extensions-1.0.3.tar.gz", hash = "sha256:bfd24dfdef7b41c312ede42648f9eb83476ea168ec163b613f9abd12bbfddba2"}, {file = "mkdocs_material_extensions-1.0.3-py3-none-any.whl", hash = "sha256:a82b70e533ce060b2a5d9eb2bc2e1be201cf61f901f93704b4acf6e3d5983a44"}, @@ -1468,14 +1459,8 @@ typed-ast = [ {file = "typed_ast-1.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:0fdbcf2fef0ca421a3f5912555804296f0b0960f0418c440f5d6d3abb549f3e1"}, {file = "typed_ast-1.5.4.tar.gz", hash = "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2"}, ] -typing-extensions = [ - {file = "typing_extensions-4.2.0-py3-none-any.whl", hash = "sha256:6657594ee297170d19f67d55c05852a874e7eb634f4f753dbd667855e07c1708"}, - {file = "typing_extensions-4.2.0.tar.gz", hash = "sha256:f1c24655a0da0d1b67f07e17a5e6b2a105894e6824b92096378bb3668ef02376"}, -] -virtualenv = [ - {file = "virtualenv-20.15.0-py2.py3-none-any.whl", hash = "sha256:804cce4de5b8a322f099897e308eecc8f6e2951f1a8e7e2b3598dff865f01336"}, - {file = "virtualenv-20.15.0.tar.gz", hash = "sha256:4c44b1d77ca81f8368e2d7414f9b20c428ad16b343ac6d226206c5b84e2b4fcc"}, -] +typing-extensions = [] +virtualenv = [] watchdog = [ {file = "watchdog-2.1.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a735a990a1095f75ca4f36ea2ef2752c99e6ee997c46b0de507ba40a09bf7330"}, {file = "watchdog-2.1.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b17d302850c8d412784d9246cfe8d7e3af6bcd45f958abb2d08a6f8bedf695d"}, diff --git a/reference/box.monopic b/reference/box.monopic new file mode 100644 index 000000000..064eb03e4 Binary files /dev/null and b/reference/box.monopic differ diff --git a/sandbox/buttons.css b/sandbox/buttons.css index cedf20ded..0d34ebf9e 100644 --- a/sandbox/buttons.css +++ b/sandbox/buttons.css @@ -1,4 +1,6 @@ + Button { - padding-left: 1; - padding-right: 1; + box-sizing: border-box; + margin: 1; + width: 100%; } diff --git a/sandbox/will/basic.css b/sandbox/will/basic.css index 0624e0846..3046a1018 100644 --- a/sandbox/will/basic.css +++ b/sandbox/will/basic.css @@ -6,14 +6,6 @@ transition: color 300ms linear, background 300ms linear; } -* { - scrollbar-background: $panel-darken-2; - scrollbar-background-hover: $panel-darken-3; - scrollbar-color: $system; - scrollbar-color-active: $accent-darken-1; - scrollbar-size-horizontal: 1; - scrollbar-size-vertical: 2; -} *:hover { /* tint: 30% red; @@ -74,8 +66,8 @@ DataTable { } #header { - color: $text-primary-darken-1; - background: $primary-darken-1; + color: $text-primary-background-darken-1; + background: $primary-background-darken-1; height: 3; content-align: center middle; } @@ -92,7 +84,7 @@ Tweet { height:12; width: 100%; - margin: 1 3; + background: $panel; color: $text-panel; layout: vertical; @@ -117,7 +109,6 @@ Tweet { .code { height: auto; - } @@ -172,7 +163,7 @@ Tweet.scroll-horizontal TweetBody { color: $text-accent; background: $accent; height: 1; - border-top: hkey $accent-darken-2; + content-align: center middle; } @@ -191,12 +182,12 @@ OptionItem { OptionItem:hover { height: 3; - color: $accent; + color: $secondary; background: $primary-background-darken-1; /* border-top: hkey $accent2-darken-3; border-bottom: hkey $accent2-darken-3; */ text-style: bold; - border-left: outer $accent-darken-2; + border-left: outer $secondary-darken-2; } Error { @@ -204,10 +195,10 @@ Error { height:3; background: $error; color: $text-error; - border-top: hkey $error-darken-2; - border-bottom: hkey $error-darken-2; - margin: 1 3; - + border-top: wide $error-darken-1; + border-bottom: wide $error-darken-1; + + padding: 0; text-style: bold; align-horizontal: center; } @@ -217,9 +208,9 @@ Warning { height:3; background: $warning; color: $text-warning-fade-1; - border-top: hkey $warning-darken-2; - border-bottom: hkey $warning-darken-2; - margin: 1 2; + border-top: wide $warning-darken-1; + border-bottom: wide $warning-darken-1; + text-style: bold; align-horizontal: center; } @@ -229,13 +220,14 @@ Success { width:90%; height:auto; box-sizing: border-box; - background: $success-lighten-3; - color: $text-success-lighten-3-fade-1; + background: $success; + color: $text-success; - border-top: hkey $success; - border-bottom: hkey $success; + border-top: hkey $success-darken-1; + border-bottom: hkey $success-darken-1; + + text-style: bold underline; - text-style: bold; align-horizontal: center; } diff --git a/sandbox/will/basic.py b/sandbox/will/basic.py index 98d186b41..12fcb8846 100644 --- a/sandbox/will/basic.py +++ b/sandbox/will/basic.py @@ -88,7 +88,7 @@ class Warning(Widget): class Success(Widget): def render(self) -> Text: - return Text("This\nis\na\nsuccess\n message", justify="center") + return Text("This is a success message", justify="center") class BasicApp(App, css_path="basic.css"): diff --git a/src/textual/_styles_cache.py b/src/textual/_styles_cache.py index dde15bf72..e9b467166 100644 --- a/src/textual/_styles_cache.py +++ b/src/textual/_styles_cache.py @@ -225,8 +225,7 @@ class StylesCache: from_color = Style.from_color - rich_style = styles.rich_style - inner = from_color(bgcolor=background.rich_color) + rich_style + inner = from_color(bgcolor=(base_background + background).rich_color) outer = from_color(bgcolor=base_background.rich_color) def post(segments: Iterable[Segment]) -> list[Segment]: @@ -265,9 +264,7 @@ class StylesCache: elif (pad_top and y < gutter.top) or ( pad_bottom and y >= height - gutter.bottom ): - background_style = from_color( - color=rich_style.color, bgcolor=background.rich_color - ) + background_style = from_color(bgcolor=background.rich_color) left_style = from_color(color=border_left_color.rich_color) left = get_box(border_left, inner, outer, left_style)[1][0] right_style = from_color(color=border_right_color.rich_color) diff --git a/src/textual/app.py b/src/textual/app.py index 3b575e566..156b2a16b 100644 --- a/src/textual/app.py +++ b/src/textual/app.py @@ -85,12 +85,13 @@ DEFAULT_COLORS = ColorSystem( secondary="#ffa62b", warning="#ffa62b", error="#ba3c5b", - success="#6d9f71", - accent="#ffa62b", + success="#4EBF71", + accent="#1A75B4", system="#5a4599", dark_surface="#292929", ) + ComposeResult = Iterable[Widget] diff --git a/src/textual/box_model.py b/src/textual/box_model.py index 3f75e61f3..0acbfe134 100644 --- a/src/textual/box_model.py +++ b/src/textual/box_model.py @@ -62,7 +62,7 @@ def get_box_model( else: # An explicit width content_width = styles.width.resolve_dimension( - sizing_container, viewport, fraction_unit + sizing_container - styles.margin.totals, viewport, fraction_unit ) if is_border_box: content_width -= gutter.width diff --git a/src/textual/css/_style_properties.py b/src/textual/css/_style_properties.py index e3ffd4141..101125bf8 100644 --- a/src/textual/css/_style_properties.py +++ b/src/textual/css/_style_properties.py @@ -834,10 +834,10 @@ class ColorProperty: _rich_traceback_omit = True if color is None: if obj.clear_rule(self.name): - obj.refresh() + obj.refresh(children=True) elif isinstance(color, Color): if obj.set_rule(self.name, color): - obj.refresh() + obj.refresh(children=True) elif isinstance(color, str): try: parsed_color = Color.parse(color) @@ -849,7 +849,7 @@ class ColorProperty: ), ) if obj.set_rule(self.name, parsed_color): - obj.refresh() + obj.refresh(children=True) else: raise StyleValueError(f"Invalid color value {color}") diff --git a/src/textual/css/constants.py b/src/textual/css/constants.py index 102e7eb42..d8784c519 100644 --- a/src/textual/css/constants.py +++ b/src/textual/css/constants.py @@ -43,6 +43,7 @@ VALID_STYLE_FLAGS: Final = { "none", "not", "bold", + "blink", "italic", "underline", "overline", @@ -50,7 +51,9 @@ VALID_STYLE_FLAGS: Final = { "b", "i", "u", + "uu", "o", + "reverse", } NULL_SPACING: Final = Spacing.all(0) diff --git a/src/textual/css/styles.py b/src/textual/css/styles.py index 4d0ab347d..333f62d3c 100644 --- a/src/textual/css/styles.py +++ b/src/textual/css/styles.py @@ -178,6 +178,8 @@ class StylesBase(ABC): "scrollbar_background_active", } + node: DOMNode | None = None + display = StringEnumProperty(VALID_DISPLAY, "block", layout=True) visibility = StringEnumProperty(VALID_VISIBILITY, "visible") layout = LayoutProperty() @@ -325,11 +327,12 @@ class StylesBase(ABC): """ @abstractmethod - def refresh(self, *, layout: bool = False) -> None: + def refresh(self, *, layout: bool = False, children: bool = False) -> None: """Mark the styles as requiring a refresh. Args: layout (bool, optional): Also require a layout. Defaults to False. + children (bool, opional): Also refresh children. Defaults to False. """ @abstractmethod @@ -439,7 +442,6 @@ class StylesBase(ABC): class Styles(StylesBase): node: DOMNode | None = None - _rules: RulesMap = field(default_factory=dict) important: set[str] = field(default_factory=set) @@ -486,9 +488,12 @@ class Styles(StylesBase): def get_rule(self, rule: str, default: object = None) -> object: return self._rules.get(rule, default) - def refresh(self, *, layout: bool = False) -> None: + def refresh(self, *, layout: bool = False, children: bool = False) -> None: if self.node is not None: self.node.refresh(layout=layout) + if children: + for child in self.node.walk_children(with_self=False): + child.refresh(layout=layout) def reset(self) -> None: """Reset the rules to initial state.""" @@ -783,8 +788,8 @@ class RenderStyles(StylesBase): if self.has_rule(rule_name): yield rule_name, getattr(self, rule_name) - def refresh(self, *, layout: bool = False) -> None: - self._inline_styles.refresh(layout=layout) + def refresh(self, *, layout: bool = False, children: bool = False) -> None: + self._inline_styles.refresh(layout=layout, children=children) def merge(self, other: Styles) -> None: """Merge values from another Styles. diff --git a/src/textual/css/tokenizer.py b/src/textual/css/tokenizer.py index 958d1ca32..0860e3d25 100644 --- a/src/textual/css/tokenizer.py +++ b/src/textual/css/tokenizer.py @@ -143,7 +143,7 @@ class Token(NamedTuple): yield "name", self.name yield "value", self.value yield "path", self.path - yield "code", self.code + yield "code", self.code if len(self.code) < 40 else self.code[:40] + "..." yield "location", self.location yield "referenced_by", self.referenced_by, None diff --git a/src/textual/layout.py b/src/textual/layout.py index 4c900a593..82db0e7da 100644 --- a/src/textual/layout.py +++ b/src/textual/layout.py @@ -7,6 +7,7 @@ class Vertical(Widget): CSS = """ Vertical { layout: vertical; + overflow: auto; } """ @@ -17,5 +18,6 @@ class Horizontal(Widget): CSS = """ Horizontal { layout: horizontal; + overflow: auto; } """ diff --git a/src/textual/scrollbar.py b/src/textual/scrollbar.py index fb4f810dd..d70faca32 100644 --- a/src/textual/scrollbar.py +++ b/src/textual/scrollbar.py @@ -212,18 +212,16 @@ class ScrollBar(Widget): def render(self) -> RenderableType: styles = self.parent.styles - scrollbar_style = Style( - bgcolor=( - styles.scrollbar_background_hover.rich_color - if self.mouse_over - else styles.scrollbar_background.rich_color - ), - color=( - styles.scrollbar_color_active.rich_color - if self.grabbed - else styles.scrollbar_color.rich_color - ), + background = ( + styles.scrollbar_background_hover + if self.mouse_over + else styles.scrollbar_background ) + color = ( + styles.scrollbar_color_active if self.grabbed else styles.scrollbar_color + ) + color = background + color + scrollbar_style = Style.from_color(color.rich_color, background.rich_color) return ScrollBarRender( virtual_size=self.window_virtual_size, window_size=self.window_size, diff --git a/src/textual/widget.py b/src/textual/widget.py index d2bd56a5b..e3d2dac5f 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -16,9 +16,11 @@ import rich.repr from rich.align import Align from rich.console import Console, RenderableType from rich.measure import Measurement -from rich.padding import Padding + from rich.segment import Segment from rich.style import Style +from rich.styled import Styled +from rich.text import Text from . import errors, events, messages from ._animator import BoundAnimator @@ -72,10 +74,9 @@ class Widget(DOMNode): scrollbar-background: $panel-darken-2; scrollbar-background-hover: $panel-darken-3; scrollbar-color: $system; - scrollbar-color-active: $secondary-darken-1; + scrollbar-color-active: $warning-darken-1; scrollbar-size-vertical: 2; scrollbar-size-horizontal: 1; - } """ @@ -879,54 +880,7 @@ class Widget(DOMNode): def watch(self, attribute_name, callback: Callable[[Any], Awaitable[None]]) -> None: watch(self, attribute_name, callback) - def _style_renderable(self, renderable: RenderableType) -> RenderableType: - """Applies CSS styles to a renderable by wrapping it in another renderable. - - Args: - renderable (RenderableType): Renderable to apply styles to. - - Returns: - RenderableType: An updated renderable. - """ - (base_background, base_color), (background, color) = self.colors - styles = self.styles - - content_align = (styles.content_align_horizontal, styles.content_align_vertical) - if content_align != ("left", "top"): - horizontal, vertical = content_align - renderable = Align(renderable, horizontal, vertical=vertical) - - renderable = Padding( - renderable, - styles.padding, - style=Style.from_color(color.rich_color, background.rich_color), - ) - - if styles.border: - renderable = Border( - renderable, - styles.border, - inner_color=background, - outer_color=base_background, - ) - - if styles.outline: - renderable = Border( - renderable, - styles.outline, - inner_color=styles.background, - outer_color=base_background, - outline=True, - ) - - if styles.tint.a != 0: - renderable = Tint(renderable, styles.tint) - if styles.opacity != 1.0: - renderable = Opacity(renderable, opacity=styles.opacity) - - return renderable - - def render_styled(self) -> RenderableType: + def _render_styled(self) -> RenderableType: """Applies style attributes to the default renderable. Returns: @@ -934,8 +888,21 @@ class Widget(DOMNode): """ renderable = self.render() + + if isinstance(renderable, str): + renderable = Text.from_markup(renderable) + + rich_style = self.rich_style + if isinstance(renderable, Text): + renderable.stylize(rich_style) + else: + renderable = Styled(renderable, rich_style) + styles = self.styles - content_align = (styles.content_align_horizontal, styles.content_align_vertical) + content_align = ( + styles.content_align_horizontal, + styles.content_align_vertical, + ) if content_align != ("left", "top"): horizontal, vertical = content_align renderable = Align(renderable, horizontal, vertical=vertical) @@ -977,11 +944,11 @@ class Widget(DOMNode): def _render_content(self) -> None: """Render all lines.""" width, height = self.size - renderable = self.render_styled() + renderable = self._render_styled() options = self.console.options.update_dimensions(width, height).update( highlight=False ) - lines = self.console.render_lines(renderable, options, style=self.rich_style) + lines = self.console.render_lines(renderable, options) self._render_cache = RenderCache(self.size, lines) self._dirty_regions.clear() diff --git a/src/textual/widgets/_button.py b/src/textual/widgets/_button.py index c8f90f834..e9856d949 100644 --- a/src/textual/widgets/_button.py +++ b/src/textual/widgets/_button.py @@ -33,145 +33,96 @@ class Button(Widget, can_focus=True): Button { width: auto; height: 3; - background: $primary; - color: $text-primary; - border: tall $primary-lighten-3; + color: $text-primary; + border: none; + border-top: tall $primary-lighten-2; + border-bottom: tall $primary-darken-3; + content-align: center middle; + text-style: bold; + } - content-align: center middle; - margin: 1 0; - align: center middle; - text-style: bold; - - transition: background 0.1;/* for "active" effect */ + Button:focus { + text-style: bold underline; } Button:hover { + border-top: tall $primary-lighten-1; background: $primary-darken-2; - color: $text-primary-darken-2; - border: tall $primary-lighten-1; + color: $text-primary-darken-2; } Button.-active { - background: $primary-lighten-1; + background: $primary; + border-bottom: tall $primary-lighten-2; + border-top: tall $primary-darken-2; } - .-dark-mode Button { - background: $background; - color: $primary-lighten-2; - border: tall white $primary-lighten-2; - } - - .-dark-mode Button:hover { - background: $surface; - } - - .-dark-mode Button.-active { - background: $background-lighten-3; - } /* Success variant */ Button.-success { background: $success; color: $text-success; - border: tall $success-lighten-3; + border-top: tall $success-lighten-2; + border-bottom: tall $success-darken-3; + } Button.-success:hover { - background: $success-darken-1; - color: $text-success-darken-1; - border: tall $success-lighten-2; + background: $success-darken-2; + color: $text-success-darken-2; + } Button.-success.-active { - background: $success-lighten-1; - } - - .-dark-mode Button.-success { background: $success; - color: $text-success; - border: tall $success-lighten-3; - } - - .-dark-mode Button.-success:hover { - background: $success-darken-1; - color: $text-success-darken-1; - border: tall $success-lighten-3; - } - - .-dark-mode Button.-success.-active { - background: $success-lighten-1; + border-bottom: tall $success-lighten-2; + border-top: tall $success-darken-2; } + /* Warning variant */ Button.-warning { background: $warning; - color: $text-warning; - border: tall $warning-lighten-3; + color: $text-warning; + border-top: tall $warning-lighten-2; + border-bottom: tall $warning-darken-3; } Button.-warning:hover { - background: $warning-darken-1; + background: $warning-darken-2; color: $text-warning-darken-1; - border: tall $warning-lighten-3; + } Button.-warning.-active { background: $warning; + border-bottom: tall $warning-lighten-2; + border-top: tall $warning-darken-2; } - - .-dark-mode Button.-warning { - background: $warning; - color: $text-warning; - border: tall $warning-lighten-3; - } - - .-dark-mode Button.-warning:hover { - background: $warning-darken-1; - color: $text-warning-darken-1; - border: tall $warning-lighten-3; - } - - .-dark-mode Button.-warning.-active { - background: $warning-lighten-1; - } + /* Error variant */ Button.-error { background: $error; color: $text-error; - border: tall $error-lighten-3; + border-top: tall $error-lighten-2; + border-bottom: tall $error-darken-3; + } Button.-error:hover { background: $error-darken-1; - color: $text-error-darken-1; - border: tall $error-lighten-3; + color: $text-error-darken-2; + } Button.-error.-active { background: $error; + border-bottom: tall $error-lighten-2; + border-top: tall $error-darken-2; } - .-dark-mode Button.-error { - background: $error; - color: $text-error; - border: tall $error-lighten-3; - } - - .-dark-mode Button.-error:hover { - background: $error-darken-1; - color: $text-error-darken-1; - border: tall $error-lighten-3; - } - - .-dark-mode Button.-error.-active { - background: $error; - } - - App.-show-focus Button:focus { - tint: $accent 20%; - } """ ACTIVE_EFFECT_DURATION = 0.3 diff --git a/src/textual/widgets/_data_table.py b/src/textual/widgets/_data_table.py index 472c98bc1..ba955ed16 100644 --- a/src/textual/widgets/_data_table.py +++ b/src/textual/widgets/_data_table.py @@ -113,8 +113,8 @@ class DataTable(ScrollView, Generic[CellType]): } DataTable > .datatable--header { text-style: bold; - background: $primary; - color: $text-primary; + background: $primary-darken-1; + color: $text-primary-darken-1; } DataTable > .datatable--fixed { text-style: bold; diff --git a/tests/test_box_model.py b/tests/test_box_model.py index 63f20a3ce..31bfc3212 100644 --- a/tests/test_box_model.py +++ b/tests/test_box_model.py @@ -49,7 +49,7 @@ def test_width(): def get_auto_width(container: Size, parent: Size) -> int: return 10 - def get_auto_height(container: Size, parent: Size) -> int: + def get_auto_height(container: Size, parent: Size, width: int) -> int: return 10 box_model = get_box_model( @@ -88,7 +88,7 @@ def test_width(): box_model = get_box_model( styles, Size(60, 20), Size(80, 24), one, get_auto_width, get_auto_height ) - assert box_model == BoxModel(Fraction(60), Fraction(16), Spacing(1, 2, 3, 4)) + assert box_model == BoxModel(Fraction(54), Fraction(16), Spacing(1, 2, 3, 4)) styles.width = "100vw" styles.max_width = "50%" @@ -107,7 +107,7 @@ def test_height(): def get_auto_width(container: Size, parent: Size) -> int: return 10 - def get_auto_height(container: Size, parent: Size) -> int: + def get_auto_height(container: Size, parent: Size, width: int) -> int: return 10 box_model = get_box_model( @@ -139,6 +139,15 @@ def test_height(): ) assert box_model == BoxModel(Fraction(54), Fraction(20), Spacing(1, 2, 3, 4)) + styles.height = "auto" + styles.margin = 2 + + box_model = get_box_model( + styles, Size(60, 20), Size(80, 24), one, get_auto_width, get_auto_height + ) + assert box_model == BoxModel(Fraction(56), Fraction(10), Spacing(2, 2, 2, 2)) + + styles.margin = 1, 2, 3, 4 styles.height = "100vh" styles.max_height = "50%" diff --git a/tests/test_styles_cache.py b/tests/test_styles_cache.py index ea892f189..d30c1cebf 100644 --- a/tests/test_styles_cache.py +++ b/tests/test_styles_cache.py @@ -1,6 +1,7 @@ from __future__ import annotations from rich.segment import Segment +from rich.style import Style from textual.color import Color from textual.geometry import Region, Size @@ -41,10 +42,11 @@ def test_no_styles(): content.__getitem__, content_size=Size(3, 3), ) + style = Style.from_color(bgcolor=Color.parse("green").rich_color) expected = [ - [Segment("foo", styles.rich_style)], - [Segment("bar", styles.rich_style)], - [Segment("baz", styles.rich_style)], + [Segment("foo", style)], + [Segment("bar", style)], + [Segment("baz", style)], ] assert lines == expected