mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
eol
This commit is contained in:
@@ -12,6 +12,7 @@ App > DockView {
|
||||
layer: panels;
|
||||
border-right: outer #09312e;
|
||||
offset-x: -50%;
|
||||
transition: offset-x 1.2s in_cubic 200ms, offset-y 1s linear;
|
||||
}
|
||||
|
||||
#header {
|
||||
|
||||
@@ -14,6 +14,7 @@ class BasicApp(App):
|
||||
footer=Widget(),
|
||||
sidebar=Widget(),
|
||||
)
|
||||
self.panic(self.query("#sidebar").first().styles)
|
||||
|
||||
|
||||
BasicApp.run(log="textual.log", css_file="basic.css")
|
||||
|
||||
6
poetry.lock
generated
6
poetry.lock
generated
@@ -547,7 +547,7 @@ python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "rich"
|
||||
version = "10.14.0"
|
||||
version = "10.15.2"
|
||||
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
|
||||
category = "main"
|
||||
optional = false
|
||||
@@ -995,8 +995,8 @@ regex = [
|
||||
{file = "regex-2021.8.21.tar.gz", hash = "sha256:faf08b0341828f6a29b8f7dd94d5cf8cc7c39bfc3e67b78514c54b494b66915a"},
|
||||
]
|
||||
rich = [
|
||||
{file = "rich-10.14.0-py3-none-any.whl", hash = "sha256:ab9cbfd7a3802d8c6f0fa91e974630e2a69447972dcbb9dfe9b01016dd95e38e"},
|
||||
{file = "rich-10.14.0.tar.gz", hash = "sha256:8bfe4546d56b4131298d3a9e571a0742de342f1593770bd0d4707299f772a0af"},
|
||||
{file = "rich-10.15.2-py3-none-any.whl", hash = "sha256:43b2c6ad51f46f6c94992aee546f1c177719f4e05aff8f5ea4d2efae3ebdac89"},
|
||||
{file = "rich-10.15.2.tar.gz", hash = "sha256:1dded089b79dd042b3ab5cd63439a338e16652001f0c16e73acdcf4997ad772d"},
|
||||
]
|
||||
six = [
|
||||
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
|
||||
|
||||
@@ -17,6 +17,7 @@ from .scalar import (
|
||||
from ..geometry import Offset, Spacing, SpacingDimensions
|
||||
from .constants import NULL_SPACING, VALID_EDGE
|
||||
from .errors import StyleTypeError, StyleValueError
|
||||
from .transition import Transition
|
||||
from ._error_tools import friendly_list
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -49,7 +50,7 @@ class ScalarProperty:
|
||||
if value is None:
|
||||
new_value = None
|
||||
elif isinstance(value, float):
|
||||
new_value = Scalar(value, Unit.CELLS, Unit.WIDTH)
|
||||
new_value = Scalar(float(value), Unit.CELLS, Unit.WIDTH)
|
||||
elif isinstance(value, Scalar):
|
||||
new_value = value
|
||||
elif isinstance(value, str):
|
||||
@@ -64,7 +65,7 @@ class ScalarProperty:
|
||||
f"{self.name} units must be one of {friendly_list(get_symbols(self.units))}"
|
||||
)
|
||||
if new_value is not None and new_value.is_percent:
|
||||
new_value = Scalar(new_value.value, self.percent_unit, Unit.WIDTH)
|
||||
new_value = Scalar(float(new_value.value), self.percent_unit, Unit.WIDTH)
|
||||
setattr(obj, self.internal_name, new_value)
|
||||
return value
|
||||
|
||||
@@ -277,12 +278,12 @@ class OffsetProperty:
|
||||
scalar_x = (
|
||||
Scalar.parse(x, Unit.WIDTH)
|
||||
if isinstance(x, str)
|
||||
else Scalar(x, Unit.CELLS, Unit.WIDTH)
|
||||
else Scalar(float(x), Unit.CELLS, Unit.WIDTH)
|
||||
)
|
||||
scalar_y = (
|
||||
Scalar.parse(y, Unit.HEIGHT)
|
||||
if isinstance(y, str)
|
||||
else Scalar(y, Unit.CELLS, Unit.HEIGHT)
|
||||
else Scalar(float(y), Unit.CELLS, Unit.HEIGHT)
|
||||
)
|
||||
_offset = ScalarOffset(scalar_x, scalar_y)
|
||||
setattr(obj, self._internal_name, _offset)
|
||||
@@ -419,3 +420,14 @@ class StyleFlagsProperty:
|
||||
style = Style.parse(" ".join(words))
|
||||
setattr(obj, self._internal_name, style)
|
||||
return style_flags
|
||||
|
||||
|
||||
class TransitionsProperty:
|
||||
def __set_name__(self, owner: Styles, name: str) -> None:
|
||||
self._name = name
|
||||
self._internal_name = f"_rule_{name}"
|
||||
|
||||
def __get__(
|
||||
self, obj: Styles, objtype: type[Styles] | None = None
|
||||
) -> dict[str, Transition]:
|
||||
return getattr(obj, self._internal_name, None) or {}
|
||||
|
||||
@@ -12,7 +12,7 @@ from ._error_tools import friendly_list
|
||||
from .._easing import EASING
|
||||
from ..geometry import Offset, Spacing, SpacingDimensions
|
||||
from .model import Declaration
|
||||
from .scalar import Scalar, ScalarOffset, Unit, ScalarParseError
|
||||
from .scalar import Scalar, ScalarOffset, Unit, ScalarError
|
||||
from .styles import DockGroup, Styles
|
||||
from .types import Edge, Display, Visibility
|
||||
from .tokenize import Token
|
||||
@@ -53,7 +53,7 @@ class StylesBuilder:
|
||||
try:
|
||||
process_method(declaration.name, tokens)
|
||||
except DeclarationError as error:
|
||||
self.error(error.name, error.token, error.message)
|
||||
raise
|
||||
except Exception as error:
|
||||
self.error(declaration.name, declaration.token, str(error))
|
||||
|
||||
@@ -389,26 +389,30 @@ class StylesBuilder:
|
||||
self.error(name, token, "expected time")
|
||||
try:
|
||||
duration = Scalar.parse(token.value).resolve_time()
|
||||
except ScalarParseError as error:
|
||||
except ScalarError as error:
|
||||
self.error(name, token, str(error))
|
||||
|
||||
token = next(iter_tokens)
|
||||
if token.name != "token":
|
||||
if token.value not in EASING:
|
||||
self.error(
|
||||
name,
|
||||
token,
|
||||
f"expected easing function; found {token.value!r}",
|
||||
)
|
||||
easing = token.value
|
||||
self.error(name, token, "easing function expected")
|
||||
|
||||
if token.value not in EASING:
|
||||
self.error(
|
||||
name,
|
||||
token,
|
||||
f"expected easing function; found {token.value!r}",
|
||||
)
|
||||
easing = token.value
|
||||
|
||||
token = next(iter_tokens)
|
||||
if token.name != "scalar":
|
||||
self.error(name, token, "expected time")
|
||||
try:
|
||||
delay = Scalar.parse(token.value).resolve_time()
|
||||
except ScalarParseError as error:
|
||||
except ScalarError as error:
|
||||
self.error(name, token, str(error))
|
||||
except StopIteration:
|
||||
pass
|
||||
transitions[css_property] = Transition(duration, easing, delay)
|
||||
|
||||
self.styles._rule_transitions = transitions
|
||||
|
||||
@@ -9,11 +9,15 @@ import rich.repr
|
||||
from ..geometry import Offset
|
||||
|
||||
|
||||
class ScalarResolveError(Exception):
|
||||
class ScalarError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class ScalarParseError(Exception):
|
||||
class ScalarResolveError(ScalarError):
|
||||
pass
|
||||
|
||||
|
||||
class ScalarParseError(ScalarError):
|
||||
pass
|
||||
|
||||
|
||||
@@ -99,7 +103,7 @@ class Scalar(NamedTuple):
|
||||
|
||||
@classmethod
|
||||
def from_number(cls, value: float) -> Scalar:
|
||||
return cls(value, Unit.CELLS, Unit.WIDTH)
|
||||
return cls(float(value), Unit.CELLS, Unit.WIDTH)
|
||||
|
||||
@classmethod
|
||||
def parse(cls, token: str, percent_unit: Unit = Unit.WIDTH) -> Scalar:
|
||||
@@ -130,7 +134,7 @@ class Scalar(NamedTuple):
|
||||
try:
|
||||
return RESOLVE_MAP[unit](value, size, viewport)
|
||||
except KeyError:
|
||||
raise ScalarResolveError(f"unable to resolve {self!r} as dimensions")
|
||||
raise ScalarResolveError(f"expected dimensions; found {str(self)!r}")
|
||||
|
||||
def resolve_time(self) -> float:
|
||||
value, unit, _ = self
|
||||
@@ -138,7 +142,7 @@ class Scalar(NamedTuple):
|
||||
return value / 1000.0
|
||||
elif unit == Unit.SECONDS:
|
||||
return value
|
||||
raise ScalarResolveError(f"unable to resolve {self!r} as time")
|
||||
raise ScalarResolveError(f"expected time; found {str(self)!r}")
|
||||
|
||||
|
||||
@rich.repr.auto(angular=True)
|
||||
@@ -147,8 +151,8 @@ class ScalarOffset(NamedTuple):
|
||||
y: Scalar
|
||||
|
||||
def __rich_repr__(self) -> rich.repr.Result:
|
||||
yield str(self.x)
|
||||
yield str(self.y)
|
||||
yield None, str(self.x)
|
||||
yield None, str(self.y)
|
||||
|
||||
def resolve(self, size: tuple[int, int], viewport: tuple[int, int]) -> Offset:
|
||||
x, y = self
|
||||
|
||||
@@ -19,6 +19,7 @@ from .constants import (
|
||||
)
|
||||
from ..geometry import NULL_OFFSET, Offset, Spacing
|
||||
from .scalar import Scalar, ScalarOffset, Unit
|
||||
from .transition import Transition
|
||||
from ._style_properties import (
|
||||
BorderProperty,
|
||||
BoxProperty,
|
||||
@@ -33,6 +34,7 @@ from ._style_properties import (
|
||||
StringProperty,
|
||||
StyleProperty,
|
||||
StyleFlagsProperty,
|
||||
TransitionsProperty,
|
||||
)
|
||||
from .types import Display, Edge, Visibility
|
||||
|
||||
@@ -88,6 +90,8 @@ class Styles:
|
||||
_rule_layers: tuple[str, ...] | None = None
|
||||
_rule_layer: str | None = None
|
||||
|
||||
_rule_transitions: dict[str, Transition] | None = None
|
||||
|
||||
important: set[str] = field(default_factory=set)
|
||||
|
||||
display = StringProperty(VALID_DISPLAY, "block")
|
||||
@@ -125,6 +129,7 @@ class Styles:
|
||||
|
||||
layer = NameProperty()
|
||||
layers = NameListProperty()
|
||||
transitions = TransitionsProperty()
|
||||
|
||||
@property
|
||||
def has_border(self) -> bool:
|
||||
@@ -282,6 +287,14 @@ class Styles:
|
||||
append_declaration("min-width", str(self.min_width))
|
||||
if self._rule_min_height is not None:
|
||||
append_declaration("min-height", str(self.min_height))
|
||||
if self._rule_transitions is not None:
|
||||
append_declaration(
|
||||
"transition",
|
||||
", ".join(
|
||||
f"{name} {transition}"
|
||||
for name, transition in self.transitions.items()
|
||||
),
|
||||
)
|
||||
|
||||
lines.sort()
|
||||
return lines
|
||||
|
||||
@@ -44,7 +44,7 @@ expect_declaration_content = Expect(
|
||||
declaration_end=r"\n|;",
|
||||
whitespace=r"\s+",
|
||||
comment_start=r"\/\*",
|
||||
scalar=r"\-?\d+\.?\d*(?:fr|%|w|h|vw|vh)?",
|
||||
scalar=r"\-?\d+\.?\d*(?:fr|%|w|h|vw|vh|s|ms)?",
|
||||
color=r"\#[0-9a-fA-F]{6}|color\([0-9]{1,3}\)|rgb\(\d{1,3}\,\s?\d{1,3}\,\s?\d{1,3}\)",
|
||||
key_value=r"[a-zA-Z_-][a-zA-Z0-9_-]*=[0-9a-zA-Z_\-\/]+",
|
||||
token="[a-zA-Z_-]+",
|
||||
|
||||
@@ -5,3 +5,12 @@ class Transition(NamedTuple):
|
||||
duration: float = 1.0
|
||||
easing: str = "linear"
|
||||
delay: float = 0.0
|
||||
|
||||
def __str__(self) -> str:
|
||||
duration, easing, delay = self
|
||||
if delay:
|
||||
return f"{duration:.1f}s {easing} {delay:.1f}"
|
||||
elif easing != "linear":
|
||||
return f"{duration:.1f}s {easing}"
|
||||
else:
|
||||
return f"{duration:.1f}s"
|
||||
|
||||
Reference in New Issue
Block a user