Skip to content

Commit 87392ee

Browse files
authored
Merge pull request #6094 from Textualize/flat-buttons
flat buttons
2 parents f59e89f + 88fc25c commit 87392ee

File tree

11 files changed

+306
-150
lines changed

11 files changed

+306
-150
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](http://keepachangelog.com/)
66
and this project adheres to [Semantic Versioning](http://semver.org/).
77

8+
# Unreleased
9+
10+
### Added
11+
12+
- Added `Button.flat` boolean to enable flat button style https://github.com/Textualize/textual/pull/6094
13+
- Added `namespaces` parameter to `run_action` https://github.com/Textualize/textual/pull/6094
14+
- Added "block" border style https://github.com/Textualize/textual/pull/6094
15+
816
# [6.0.0] - 2025-08-31
917

1018
### Fixed

docs/examples/widgets/button.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,22 @@ def compose(self) -> ComposeResult:
2424
Button.warning("Warning!", disabled=True),
2525
Button.error("Error!", disabled=True),
2626
),
27+
VerticalScroll(
28+
Static("Flat Buttons", classes="header"),
29+
Button("Default", flat=True),
30+
Button("Primary!", variant="primary", flat=True),
31+
Button.success("Success!", flat=True),
32+
Button.warning("Warning!", flat=True),
33+
Button.error("Error!", flat=True),
34+
),
35+
VerticalScroll(
36+
Static("Disabled Flat Buttons", classes="header"),
37+
Button("Default", disabled=True, flat=True),
38+
Button("Primary!", variant="primary", disabled=True, flat=True),
39+
Button.success("Success!", disabled=True, flat=True),
40+
Button.warning("Warning!", disabled=True, flat=True),
41+
Button.error("Error!", disabled=True, flat=True),
42+
),
2743
)
2844

2945
def on_button_pressed(self, event: Button.Pressed) -> None:

src/textual/_border.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@
8787
("█", " ", "█"),
8888
("█", "▄", "█"),
8989
),
90+
"block": (
91+
("▄", "▄", "▄"),
92+
("█", " ", "█"),
93+
("▀", "▀", "▀"),
94+
),
9095
"hkey": (
9196
("▔", "▔", "▔"),
9297
(" ", " ", " "),
@@ -190,6 +195,11 @@
190195
(0, 0, 0),
191196
(0, 0, 0),
192197
),
198+
"block": (
199+
(1, 1, 1),
200+
(0, 0, 0),
201+
(1, 1, 1),
202+
),
193203
"hkey": (
194204
(0, 0, 0),
195205
(0, 0, 0),

src/textual/app.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
Generic,
4242
Iterable,
4343
Iterator,
44+
Mapping,
4445
NamedTuple,
4546
Sequence,
4647
TextIO,
@@ -3969,12 +3970,17 @@ def escape_to_minimize(self) -> bool:
39693970
)
39703971

39713972
def _parse_action(
3972-
self, action: str | ActionParseResult, default_namespace: DOMNode
3973+
self,
3974+
action: str | ActionParseResult,
3975+
default_namespace: DOMNode,
3976+
namespaces: Mapping[str, DOMNode] | None = None,
39733977
) -> tuple[DOMNode, str, tuple[object, ...]]:
39743978
"""Parse an action.
39753979
39763980
Args:
39773981
action: An action string.
3982+
default_namespace: Namespace to user when none is supplied in the action.
3983+
namespaces: Mapping of namespaces.
39783984
39793985
Raises:
39803986
ActionError: If there are any errors parsing the action string.
@@ -3987,8 +3993,10 @@ def _parse_action(
39873993
else:
39883994
destination, action_name, params = actions.parse(action)
39893995

3990-
action_target: DOMNode | None = None
3991-
if destination:
3996+
action_target: DOMNode | None = (
3997+
None if namespaces is None else namespaces.get(destination)
3998+
)
3999+
if destination and action_target is None:
39924000
if destination not in self._action_targets:
39934001
raise ActionError(f"Action namespace {destination} is not known")
39944002
action_target = getattr(self, destination, None)
@@ -4021,6 +4029,7 @@ async def run_action(
40214029
self,
40224030
action: str | ActionParseResult,
40234031
default_namespace: DOMNode | None = None,
4032+
namespaces: Mapping[str, DOMNode] | None = None,
40244033
) -> bool:
40254034
"""Perform an [action](/guide/actions).
40264035
@@ -4030,12 +4039,13 @@ async def run_action(
40304039
action: Action encoded in a string.
40314040
default_namespace: Namespace to use if not provided in the action,
40324041
or None to use app.
4042+
namespaces: Mapping of namespaces.
40334043
40344044
Returns:
40354045
True if the event has been handled.
40364046
"""
40374047
action_target, action_name, params = self._parse_action(
4038-
action, self if default_namespace is None else default_namespace
4048+
action, self if default_namespace is None else default_namespace, namespaces
40394049
)
40404050
if action_target.check_action(action_name, params):
40414051
return await self._dispatch_action(action_target, action_name, params)

src/textual/css/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"tall",
2525
"tab",
2626
"thick",
27+
"block",
2728
"vkey",
2829
"wide",
2930
}

src/textual/css/types.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"round",
1717
"solid",
1818
"thick",
19+
"block",
1920
"double",
2021
"dashed",
2122
"heavy",

src/textual/widget.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
Collection,
2020
Generator,
2121
Iterable,
22+
Mapping,
2223
NamedTuple,
2324
Sequence,
2425
TypeVar,
@@ -4304,13 +4305,16 @@ def _render(self) -> Visual:
43044305
self._layout_cache[cache_key] = visual
43054306
return visual
43064307

4307-
async def run_action(self, action: str) -> None:
4308+
async def run_action(
4309+
self, action: str, namespaces: Mapping[str, DOMNode] | None = None
4310+
) -> None:
43084311
"""Perform a given action, with this widget as the default namespace.
43094312
43104313
Args:
43114314
action: Action encoded as a string.
4315+
namespaces: Mapping of namespaces.
43124316
"""
4313-
await self.app.run_action(action, self)
4317+
await self.app.run_action(action, self, namespaces)
43144318

43154319
def post_message(self, message: Message) -> bool:
43164320
"""Post a message to this widget.

0 commit comments

Comments
 (0)