mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Text justify has become text align
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
57
docs/styles/text_align.md
Normal 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"
|
||||
```
|
||||
@@ -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"
|
||||
```
|
||||
@@ -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"
|
||||
|
||||
@@ -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()
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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'"),
|
||||
],
|
||||
)
|
||||
],
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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."""
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user