mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
5
docs/examples/styles/links.css
Normal file
5
docs/examples/styles/links.css
Normal file
@@ -0,0 +1,5 @@
|
||||
#custom {
|
||||
link-color: black 90%;
|
||||
link-background: dodgerblue;
|
||||
link-style: bold italic underline;
|
||||
}
|
||||
18
docs/examples/styles/links.py
Normal file
18
docs/examples/styles/links.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.widgets import Static
|
||||
|
||||
TEXT = """\
|
||||
Here is a [@click='app.bell']link[/] which you can click!
|
||||
"""
|
||||
|
||||
|
||||
class LinksApp(App):
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Static(TEXT)
|
||||
yield Static(TEXT, id="custom")
|
||||
|
||||
|
||||
app = LinksApp(css_path="links.css")
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run()
|
||||
57
docs/styles/links.md
Normal file
57
docs/styles/links.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# Links
|
||||
|
||||
Textual supports the concept of inline "links" embedded in text which trigger an action when pressed.
|
||||
|
||||
There are a number of styles which influence the appearance of these links within a widget.
|
||||
|
||||
| Property | Description |
|
||||
|-------------------------|-------------------------------------------------------------|
|
||||
| `link-color` | The color of link text. |
|
||||
| `link-background` | The background color of link text. |
|
||||
| `link-style` | The style of link text (e.g. underline). |
|
||||
| `link-hover-color` | The color of link text with the cursor above it. |
|
||||
| `link-hover-background` | The background color of link text with the cursor above it. |
|
||||
| `link-hover-style` | The style of link text with the cursor above it. |
|
||||
|
||||
## Syntax
|
||||
|
||||
```scss
|
||||
link-color: <COLOR>;
|
||||
link-background: <COLOR>;
|
||||
link-style: <TEXT STYLE> ...;
|
||||
link-hover-color: <COLOR>;
|
||||
link-hover-background: <COLOR>;
|
||||
link-hover-style: <TEXT STYLE> ...;
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
In the example below, the first `Static` illustrates default link styling.
|
||||
The second `Static` uses CSS to customize the link color, background, and style.
|
||||
|
||||
=== "Output"
|
||||
|
||||
```{.textual path="docs/examples/styles/links.py"}
|
||||
```
|
||||
|
||||
=== "links.py"
|
||||
|
||||
```python
|
||||
--8<-- "docs/examples/styles/links.py"
|
||||
```
|
||||
|
||||
=== "links.css"
|
||||
|
||||
```sass
|
||||
--8<-- "docs/examples/styles/links.css"
|
||||
```
|
||||
|
||||
## Additional Notes
|
||||
|
||||
* Inline links are not widgets, and thus cannot be focused.
|
||||
|
||||
## See Also
|
||||
|
||||
* An [introduction to links](../guide/actions.md#links) in the Actions guide.
|
||||
|
||||
[//]: # (TODO: Links are documented twice in the guide, and one will likely be removed. Check the link above still works after that.)
|
||||
@@ -68,6 +68,7 @@ nav:
|
||||
- "styles/layer.md"
|
||||
- "styles/layers.md"
|
||||
- "styles/layout.md"
|
||||
- "styles/links.md"
|
||||
- "styles/margin.md"
|
||||
- "styles/max_height.md"
|
||||
- "styles/max_width.md"
|
||||
@@ -96,7 +97,7 @@ nav:
|
||||
- "widgets/input.md"
|
||||
- "widgets/static.md"
|
||||
- "widgets/tree_control.md"
|
||||
- Reference:
|
||||
- Reference:
|
||||
- "reference/app.md"
|
||||
- "reference/button.md"
|
||||
- "reference/color.md"
|
||||
|
||||
@@ -27,7 +27,7 @@ from ._help_text import (
|
||||
string_enum_help_text,
|
||||
color_property_help_text,
|
||||
)
|
||||
from .._border import INVISIBLE_EDGE_TYPES, normalize_border_value
|
||||
from .._border import normalize_border_value
|
||||
from ..color import Color, ColorParseError
|
||||
from ._error_tools import friendly_list
|
||||
from .constants import NULL_SPACING, VALID_STYLE_FLAGS
|
||||
|
||||
@@ -60,7 +60,7 @@ from .scalar import (
|
||||
from .styles import Styles
|
||||
from .tokenize import Token
|
||||
from .transition import Transition
|
||||
from .types import BoxSizing, Display, Edge, EdgeType, Overflow, Visibility
|
||||
from .types import BoxSizing, Display, EdgeType, Overflow, Visibility
|
||||
|
||||
|
||||
def _join_tokens(tokens: Iterable[Token], joiner: str = "") -> str:
|
||||
@@ -580,6 +580,7 @@ class StylesBuilder:
|
||||
color: Color | None = None
|
||||
alpha: float | None = None
|
||||
|
||||
self.styles._rules[f"auto_{name}"] = False
|
||||
for token in tokens:
|
||||
if (
|
||||
"background" not in name
|
||||
@@ -622,8 +623,8 @@ class StylesBuilder:
|
||||
|
||||
process_link_color = process_color
|
||||
process_link_background = process_color
|
||||
process_hover_color = process_color
|
||||
process_hover_background = process_color
|
||||
process_link_hover_color = process_color
|
||||
process_link_hover_background = process_color
|
||||
|
||||
def process_text_style(self, name: str, tokens: list[Token]) -> None:
|
||||
for token in tokens:
|
||||
@@ -639,7 +640,7 @@ class StylesBuilder:
|
||||
self.styles._rules[name.replace("-", "_")] = style_definition
|
||||
|
||||
process_link_style = process_text_style
|
||||
process_hover_style = process_text_style
|
||||
process_link_hover_style = process_text_style
|
||||
|
||||
def process_text_align(self, name: str, tokens: list[Token]) -> None:
|
||||
"""Process a text-align declaration"""
|
||||
|
||||
@@ -32,7 +32,7 @@ VALID_BORDER: Final[set[EdgeType]] = {
|
||||
"wide",
|
||||
}
|
||||
VALID_EDGE: Final = {"top", "right", "bottom", "left"}
|
||||
VALID_LAYOUT: Final = {"vertical", "horizontal", "center", "grid"}
|
||||
VALID_LAYOUT: Final = {"vertical", "horizontal", "grid"}
|
||||
|
||||
VALID_BOX_SIZING: Final = {"border-box", "content-box"}
|
||||
VALID_OVERFLOW: Final = {"scroll", "hidden", "auto"}
|
||||
|
||||
@@ -164,10 +164,10 @@ class RulesMap(TypedDict, total=False):
|
||||
link_background: Color
|
||||
link_style: Style
|
||||
|
||||
hover_color: Color
|
||||
auto_hover_color: bool
|
||||
hover_background: Color
|
||||
hover_style: Style
|
||||
link_hover_color: Color
|
||||
auto_link_hover_color: bool
|
||||
link_hover_background: Color
|
||||
link_hover_style: Style
|
||||
|
||||
|
||||
RULE_NAMES = list(RulesMap.__annotations__.keys())
|
||||
@@ -208,8 +208,8 @@ class StylesBase(ABC):
|
||||
"scrollbar_background_active",
|
||||
"link_color",
|
||||
"link_background",
|
||||
"hover_color",
|
||||
"hover_background",
|
||||
"link_hover_color",
|
||||
"link_hover_background",
|
||||
}
|
||||
|
||||
node: DOMNode | None = None
|
||||
@@ -301,10 +301,10 @@ class StylesBase(ABC):
|
||||
link_background = ColorProperty("transparent")
|
||||
link_style = StyleFlagsProperty()
|
||||
|
||||
hover_color = ColorProperty("transparent")
|
||||
auto_hover_color = BooleanProperty(False)
|
||||
hover_background = ColorProperty("transparent")
|
||||
hover_style = StyleFlagsProperty()
|
||||
link_hover_color = ColorProperty("transparent")
|
||||
auto_link_hover_color = BooleanProperty(False)
|
||||
link_hover_background = ColorProperty("transparent")
|
||||
link_hover_style = StyleFlagsProperty()
|
||||
|
||||
def __eq__(self, styles: object) -> bool:
|
||||
"""Check that Styles contains the same rules."""
|
||||
@@ -902,12 +902,12 @@ class Styles(StylesBase):
|
||||
if has_rule("link_style"):
|
||||
append_declaration("link-style", str(self.link_style))
|
||||
|
||||
if has_rule("hover_color"):
|
||||
append_declaration("hover-color", self.hover_color.css)
|
||||
if has_rule("hover_background"):
|
||||
append_declaration("hover-background", self.hover_background.css)
|
||||
if has_rule("hover_style"):
|
||||
append_declaration("hover-style", str(self.hover_style))
|
||||
if has_rule("link_hover_color"):
|
||||
append_declaration("link-hover-color", self.link_hover_color.css)
|
||||
if has_rule("link_hover_background"):
|
||||
append_declaration("link-hover-background", self.link_hover_background.css)
|
||||
if has_rule("link_hover_style"):
|
||||
append_declaration("link-hover-style", str(self.link_hover_style))
|
||||
|
||||
lines.sort()
|
||||
return lines
|
||||
|
||||
@@ -16,7 +16,6 @@ from rich.syntax import Syntax
|
||||
from rich.text import Text
|
||||
|
||||
from .. import messages
|
||||
from .._profile import timer
|
||||
from ..dom import DOMNode
|
||||
from ..widget import Widget
|
||||
from .errors import StylesheetError
|
||||
@@ -368,6 +367,7 @@ class Stylesheet:
|
||||
rules = [rule for rule in reversed(self.rules) if rule in limit_rules]
|
||||
else:
|
||||
rules = reversed(self.rules)
|
||||
|
||||
# Collect the rules defined in the stylesheet
|
||||
node._has_hover_style = False
|
||||
for rule in rules:
|
||||
|
||||
@@ -192,9 +192,9 @@ class ScrollBar(Widget):
|
||||
|
||||
DEFAULT_CSS = """
|
||||
ScrollBar {
|
||||
hover-color: ;
|
||||
hover-background:;
|
||||
hover-style: ;
|
||||
link-hover-color: ;
|
||||
link-hover-background:;
|
||||
link-hover-style: ;
|
||||
link-color: transparent;
|
||||
link-background: transparent;
|
||||
}
|
||||
|
||||
@@ -133,12 +133,12 @@ class Widget(DOMNode):
|
||||
scrollbar-corner-color: $panel-darken-1;
|
||||
scrollbar-size-vertical: 2;
|
||||
scrollbar-size-horizontal: 1;
|
||||
link-background:;
|
||||
link-background:;
|
||||
link-color: $text;
|
||||
link-style: underline;
|
||||
hover-background: $accent;
|
||||
hover-color: $text;
|
||||
hover-style: bold not underline;
|
||||
link-hover-background: $accent;
|
||||
link-hover-color: $text;
|
||||
link-hover-style: bold not underline;
|
||||
}
|
||||
"""
|
||||
COMPONENT_CLASSES: ClassVar[set[str]] = set()
|
||||
@@ -930,13 +930,13 @@ class Widget(DOMNode):
|
||||
"""Style of links with mouse hover."""
|
||||
styles = self.styles
|
||||
_, background = self.background_colors
|
||||
hover_background = background + styles.hover_background
|
||||
hover_background = background + styles.link_hover_background
|
||||
hover_color = hover_background + (
|
||||
hover_background.get_contrast_text(styles.hover_color.a)
|
||||
if styles.auto_hover_color
|
||||
else styles.hover_color
|
||||
hover_background.get_contrast_text(styles.link_hover_color.a)
|
||||
if styles.auto_link_hover_color
|
||||
else styles.link_hover_color
|
||||
)
|
||||
style = styles.hover_style + Style.from_color(
|
||||
style = styles.link_hover_style + Style.from_color(
|
||||
hover_color.rich_color,
|
||||
hover_background.rich_color,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user