Merge pull request #868 from Textualize/document-links

Document links
This commit is contained in:
Will McGugan
2022-10-12 15:31:35 +01:00
committed by GitHub
11 changed files with 118 additions and 36 deletions

View File

@@ -0,0 +1,5 @@
#custom {
link-color: black 90%;
link-background: dodgerblue;
link-style: bold italic underline;
}

View 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
View 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.)

View File

@@ -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"

View File

@@ -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

View File

@@ -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"""

View File

@@ -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"}

View File

@@ -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

View File

@@ -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:

View File

@@ -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;
}

View File

@@ -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,
)