Text justify has become text align

This commit is contained in:
Darren Burns
2022-08-26 15:33:42 +01:00
parent 3b155216f0
commit ad803a7753
13 changed files with 134 additions and 118 deletions

View File

@@ -1,21 +1,21 @@
#one {
text-justify: left;
text-align: left;
background: lightblue;
}
#two {
text-justify: center;
text-align: center;
background: indianred;
}
#three {
text-justify: right;
text-align: right;
background: palegreen;
}
#four {
text-justify: full;
text-align: justify;
background: palevioletred;
}

View File

@@ -10,19 +10,19 @@ TEXT = (
)
class TextJustify(App):
class TextAlign(App):
def compose(self) -> ComposeResult:
left = Static("[b]Left justified[/]\n" + TEXT, id="one")
left = Static("[b]Left aligned[/]\n" + TEXT, id="one")
yield left
right = Static("[b]Center justified[/]\n" + TEXT, id="two")
right = Static("[b]Center aligned[/]\n" + TEXT, id="two")
yield right
center = Static("[b]Right justified[/]\n" + TEXT, id="three")
center = Static("[b]Right aligned[/]\n" + TEXT, id="three")
yield center
full = Static("[b]Full justified[/]\n" + TEXT, id="four")
full = Static("[b]Justified[/]\n" + TEXT, id="four")
yield full
app = TextJustify(css_path="text_justify.css")
app = TextAlign(css_path="text_align.css")

57
docs/styles/text_align.md Normal file
View File

@@ -0,0 +1,57 @@
# Text-align
The `text-align` rule aligns text within a widget.
## Syntax
```
text-align: [left|start|center|right|end|justify];
```
### Values
| Value | Description |
|-----------|----------------------------------|
| `left` | Left aligns text in the widget |
| `start` | Left aligns text in the widget |
| `center` | Center aligns text in the widget |
| `right` | Right aligns text in the widget |
| `end` | Right aligns text in the widget |
| `justify` | Justifies text in the widget |
## Example
This example shows, from top to bottom: `left`, `center`, `right`, and `justify` text alignments.
=== "text_align.py"
```python
--8<-- "docs/examples/styles/text_align.py"
```
=== "text_align.css"
```css
--8<-- "docs/examples/styles/text_align.css"
```
=== "Output"
```{.textual path="docs/examples/styles/text_align.py"}
```
## CSS
```sass
/* Set text in all Widgets to be right aligned */
Widget {
text-align: right;
}
```
## Python
```python
# Set text in the widget to be right aligned
widget.styles.text_align = "right"
```

View File

@@ -1,57 +0,0 @@
# Text-justify
The `text-justify` rule justifies text within a widget.
This property is not the same as the `text-justify` property in browser CSS.
## Syntax
```
text-justify: [left|center|right|full];
```
### Values
| Value | Description |
|----------|-------------------------------------|
| `left` | Left justifies text in the widget |
| `center` | Center justifies text in the widget |
| `right` | Right justifies text in the widget |
| `full` | Fully justifies text in the widget |
## Example
This example shows, from top to bottom: `left`, `center`, `right`, and `full` justified text.
=== "text_justify.py"
```python
--8<-- "docs/examples/styles/text_justify.py"
```
=== "text_justify.css"
```css
--8<-- "docs/examples/styles/text_justify.css"
```
=== "Output"
```{.textual path="docs/examples/styles/text_justify.py"}
```
## CSS
```sass
/* Set text in all Widgets to be right justified */
Widget {
text-justify: right;
}
```
## Python
```python
# Set text in the widget to be right justified
widget.styles.text_justify = "right"
```

View File

@@ -56,7 +56,7 @@ nav:
- "styles/scrollbar.md"
- "styles/scrollbar_gutter.md"
- "styles/scrollbar_size.md"
- "styles/text_justify.md"
- "styles/text_align.md"
- "styles/text_style.md"
- "styles/tint.md"
- "styles/visibility.md"

View File

@@ -12,22 +12,22 @@ TEXT = (
)
class TextJustify(App):
class TextAlign(App):
def compose(self) -> ComposeResult:
left = Static("[b]Left justified[/]\n" + TEXT, id="one")
left = Static("[b]Left aligned[/]\n" + TEXT, id="one")
yield left
right = Static("[b]Center justified[/]\n" + TEXT, id="two")
right = Static("[b]Center aligned[/]\n" + TEXT, id="two")
yield right
center = Static("[b]Right justified[/]\n" + TEXT, id="three")
center = Static("[b]Right aligned[/]\n" + TEXT, id="three")
yield center
full = Static("[b]Full justified[/]\n" + TEXT, id="four")
full = Static("[b]Fully justified[/]\n" + TEXT, id="four")
yield full
app = TextJustify(css_path="text_justify.scss", watch_css=True)
app = TextAlign(css_path="text_align.scss", watch_css=True)
if __name__ == "__main__":
app.run()

View File

@@ -1,21 +1,21 @@
#one {
text-justify: left;
text-align: left;
background: lightblue;
}
#two {
text-justify: center;
text-align: center;
background: indianred;
}
#three {
text-justify: right;
text-align: right;
background: palegreen;
}
#four {
text-justify: full;
text-align: justify;
background: palevioletred;
}

View File

@@ -13,7 +13,7 @@ from textual.css.constants import (
VALID_ALIGN_HORIZONTAL,
VALID_ALIGN_VERTICAL,
VALID_STYLE_FLAGS,
VALID_JUSTIFY,
VALID_TEXT_ALIGN,
)
if sys.version_info >= (3, 8):
@@ -649,31 +649,31 @@ def align_help_text() -> HelpText:
)
def text_justify_help_text(context: str) -> HelpText:
"""Help text to show when the user supplies an invalid value for the text-justify property
def text_align_help_text(context: str) -> HelpText:
"""Help text to show when the user supplies an invalid value for the text-align property
Returns:
HelpText: Renderable for displaying the help text for this property.
"""
return HelpText(
summary="Invalid value for the [i]text-justify[/] property.",
summary="Invalid value for the [i]text-align[/] property.",
bullets=[
*ContextSpecificBullets(
css=[
Bullet(
f"The [i]text-justify[/] property must be one of {friendly_list(VALID_JUSTIFY)}",
f"The [i]text-align[/] property must be one of {friendly_list(VALID_TEXT_ALIGN)}",
examples=[
Example("text-justify: center;"),
Example("text-justify: right;"),
Example("text-align: center;"),
Example("text-align: right;"),
],
)
],
inline=[
Bullet(
f"The [i]text_justify[/] property must be one of {friendly_list(VALID_JUSTIFY)}",
f"The [i]text_align[/] property must be one of {friendly_list(VALID_TEXT_ALIGN)}",
examples=[
Example("widget.styles.text_justify = 'center'"),
Example("widget.styles.text_justify = 'right'"),
Example("widget.styles.text_align = 'center'"),
Example("widget.styles.text_align = 'right'"),
],
)
],

View File

@@ -24,7 +24,7 @@ from ._help_text import (
property_invalid_value_help_text,
scrollbar_size_property_help_text,
scrollbar_size_single_axis_help_text,
text_justify_help_text,
text_align_help_text,
)
from .constants import (
VALID_ALIGN_HORIZONTAL,
@@ -37,7 +37,7 @@ from .constants import (
VALID_VISIBILITY,
VALID_STYLE_FLAGS,
VALID_SCROLLBAR_GUTTER,
VALID_JUSTIFY,
VALID_TEXT_ALIGN,
)
from .errors import DeclarationError, StyleValueError
from .model import Declaration
@@ -620,19 +620,19 @@ class StylesBuilder:
style_definition = " ".join(token.value for token in tokens)
self.styles.text_style = style_definition
def process_text_justify(self, name: str, tokens: list[Token]) -> None:
"""Process a text-justify declaration"""
def process_text_align(self, name: str, tokens: list[Token]) -> None:
"""Process a text-align declaration"""
if not tokens:
return
if len(tokens) > 1 or tokens[0].value not in VALID_JUSTIFY:
if len(tokens) > 1 or tokens[0].value not in VALID_TEXT_ALIGN:
self.error(
name,
tokens[0],
text_justify_help_text("css"),
text_align_help_text("css"),
)
self.styles._rules["text_justify"] = tokens[0].value
self.styles._rules["text_align"] = tokens[0].value
def process_dock(self, name: str, tokens: list[Token]) -> None:
if not tokens:

View File

@@ -38,7 +38,7 @@ VALID_BOX_SIZING: Final = {"border-box", "content-box"}
VALID_OVERFLOW: Final = {"scroll", "hidden", "auto"}
VALID_ALIGN_HORIZONTAL: Final = {"left", "center", "right"}
VALID_ALIGN_VERTICAL: Final = {"top", "middle", "bottom"}
VALID_JUSTIFY: Final = {"left", "center", "right", "full"}
VALID_TEXT_ALIGN: Final = {"start", "end", "left", "right", "center", "justify"}
VALID_SCROLLBAR_GUTTER: Final = {"auto", "stable"}
VALID_STYLE_FLAGS: Final = {
"none",

View File

@@ -31,7 +31,6 @@ from ._style_properties import (
SpacingProperty,
StringEnumProperty,
StyleFlagsProperty,
StyleProperty,
TransitionsProperty,
)
from .constants import (
@@ -42,7 +41,7 @@ from .constants import (
VALID_OVERFLOW,
VALID_SCROLLBAR_GUTTER,
VALID_VISIBILITY,
VALID_JUSTIFY,
VALID_TEXT_ALIGN,
)
from .scalar import Scalar, ScalarOffset, Unit
from .scalar_animation import ScalarAnimation
@@ -145,7 +144,7 @@ class RulesMap(TypedDict, total=False):
content_align_horizontal: AlignHorizontal
content_align_vertical: AlignVertical
text_justify: TextJustify
text_align: TextJustify
RULE_NAMES = list(RulesMap.__annotations__.keys())
@@ -254,7 +253,7 @@ class StylesBase(ABC):
content_align_vertical = StringEnumProperty(VALID_ALIGN_VERTICAL, "top")
content_align = AlignProperty()
text_justify = StringEnumProperty(VALID_JUSTIFY, "left")
text_align = StringEnumProperty(VALID_TEXT_ALIGN, "start")
def __eq__(self, styles: object) -> bool:
"""Check that Styles contains the same rules."""

View File

@@ -1,14 +1,11 @@
from __future__ import annotations
from asyncio import Lock
from itertools import islice
from fractions import Fraction
from itertools import islice
from operator import attrgetter
from typing import (
TYPE_CHECKING,
Any,
Awaitable,
Callable,
ClassVar,
Collection,
Iterable,
@@ -16,8 +13,7 @@ from typing import (
)
import rich.repr
from rich.console import Console, RenderableType
from rich.console import Console, RenderableType, JustifyMethod
from rich.measure import Measurement
from rich.segment import Segment
from rich.style import Style
@@ -33,13 +29,13 @@ from ._segment_tools import align_lines
from ._styles_cache import StylesCache
from ._types import Lines
from .box_model import BoxModel, get_box_model
from .css.constants import VALID_TEXT_ALIGN
from .dom import DOMNode
from .dom import NoScreen
from .geometry import Offset, Region, Size, Spacing, clamp
from .layouts.vertical import VerticalLayout
from .message import Message
from .reactive import Reactive
from .dom import NoScreen
if TYPE_CHECKING:
from .app import App, ComposeResult
@@ -1215,13 +1211,15 @@ class Widget(DOMNode):
"""
if isinstance(renderable, str):
renderable = Text.from_markup(renderable, justify=self.styles.text_justify)
justify = _get_rich_justify(self.styles.text_align)
renderable = Text.from_markup(renderable, justify=justify)
rich_style = self.rich_style
if isinstance(renderable, Text):
renderable.stylize(rich_style)
if not renderable.justify:
renderable.justify = self.styles.text_justify
justify = _get_rich_justify(self.styles.text_align)
renderable.justify = justify
else:
renderable = Styled(renderable, rich_style)
@@ -1579,3 +1577,22 @@ class Widget(DOMNode):
self.scroll_page_up()
return True
return False
def _get_rich_justify(css_align: str) -> JustifyMethod:
"""Given the value for CSS text-align, return the analogous argument
for the Rich text `justify` parameter.
Args:
css_align: The value of text-align CSS property.
Returns:
JustifyMethod: The Rich JustifyMethod that corresponds to the text-align
value
"""
assert css_align in VALID_TEXT_ALIGN
return {
"start": "left",
"end": "right",
"justify": "full",
}.get(css_align, css_align)

View File

@@ -1134,14 +1134,14 @@ class TestParsePadding:
class TestParseTextJustify:
@pytest.mark.parametrize("valid_justify", ["left", "center", "full", "right"])
def test_text_justify(self, valid_justify):
css = f"#foo {{ text-justify: {valid_justify} }}"
def test_text_align(self, valid_justify):
css = f"#foo {{ text-align: {valid_justify} }}"
stylesheet = Stylesheet()
stylesheet.add_source(css)
assert stylesheet.rules[0].styles.text_justify == valid_justify
assert stylesheet.rules[0].styles.text_align == valid_justify
def test_text_justify_invalid(self):
css = "#foo { text-justify: invalid-value; }"
def test_text_align_invalid(self):
css = "#foo { text-align: invalid-value; }"
stylesheet = Stylesheet()
with pytest.raises(StylesheetParseError):
stylesheet.add_source(css)
@@ -1149,8 +1149,8 @@ class TestParseTextJustify:
rules = stylesheet._parse_rules(css, "foo")
assert rules[0].errors
def test_text_justify_empty_uses_default(self):
css = "#foo { text-justify: ; }"
def test_text_align_empty_uses_default(self):
css = "#foo { text-align: ; }"
stylesheet = Stylesheet()
stylesheet.add_source(css)
assert stylesheet.rules[0].styles.text_justify == "left"
assert stylesheet.rules[0].styles.text_align == "left"