empty class

This commit is contained in:
Will McGugan
2025-07-29 14:44:06 +01:00
parent 34fbad791b
commit ac2d2a6796
6 changed files with 17 additions and 90 deletions

View File

@@ -5,8 +5,21 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## Unrleeased
### Added
- Added `empty` pseudo class, which applies when a widget has no displayed children https://github.com/Textualize/textual/pull/5999
- Added `Screen.action_focus` https://github.com/Textualize/textual/pull/5999
### Changed
- `last-child`, `last-of-type`, `first-child`, and `first-of-type` apply to displayed children only https://github.com/Textualize/textual/pull/5999
- `textual.compose` is now public https://github.com/Textualize/textual/pull/5999
## [5.0.1] - 2025-07-25
### Fixed
- Fixed appending to Markdown widgets that were constructed with an existing document https://github.com/Textualize/textual/pull/5990

View File

@@ -194,6 +194,7 @@ nav:
- "api/command.md"
- "api/constants.md"
- "api/containers.md"
- "api/compose.md"
- "api/content.md"
- "api/coordinate.md"
- "api/dom_node.md"

View File

@@ -1,83 +0,0 @@
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from textual.app import App, ComposeResult
from textual.widget import Widget
def compose(
node: App | Widget, compose_result: ComposeResult | None = None
) -> list[Widget]:
"""Compose child widgets.
Args:
node: The parent node.
compose_result: A compose result, or `None` to call `node.compose()`.
Returns:
A list of widgets.
"""
_rich_traceback_omit = True
from textual.widget import MountError, Widget
app = node.app
nodes: list[Widget] = []
compose_stack: list[Widget] = []
composed: list[Widget] = []
app._compose_stacks.append(compose_stack)
app._composed.append(composed)
iter_compose = iter(
compose_result if compose_result is not None else node.compose()
)
is_generator = hasattr(iter_compose, "throw")
try:
while True:
try:
child = next(iter_compose)
except StopIteration:
break
if not isinstance(child, Widget):
mount_error = MountError(
f"Can't mount {type(child)}; expected a Widget instance."
)
if is_generator:
iter_compose.throw(mount_error) # type: ignore
else:
raise mount_error from None
try:
child.id
except AttributeError:
mount_error = MountError(
"Widget is missing an 'id' attribute; did you forget to call super().__init__()?"
)
if is_generator:
iter_compose.throw(mount_error) # type: ignore
else:
raise mount_error from None
if composed:
nodes.extend(composed)
composed.clear()
if compose_stack:
try:
compose_stack[-1].compose_add_child(child)
except Exception as error:
if is_generator:
# So the error is raised inside the generator
# This will generate a more sensible traceback for the dev
iter_compose.throw(error) # type: ignore
else:
raise
else:
nodes.append(child)
if composed:
nodes.extend(composed)
composed.clear()
finally:
app._compose_stacks.pop()
app._composed.pop()
return nodes

View File

@@ -75,7 +75,6 @@ from textual._ansi_sequences import SYNC_END, SYNC_START
from textual._ansi_theme import ALABASTER, MONOKAI
from textual._callback import invoke
from textual._compat import cached_property
from textual._compose import compose
from textual._compositor import CompositorUpdate
from textual._context import active_app, active_message_pump
from textual._context import message_hook as message_hook_context_var
@@ -94,6 +93,7 @@ from textual.await_complete import AwaitComplete
from textual.await_remove import AwaitRemove
from textual.binding import Binding, BindingsMap, BindingType, Keymap
from textual.command import CommandListItem, CommandPalette, Provider, SimpleProvider
from textual.compose import compose
from textual.css.errors import StylesheetError
from textual.css.query import NoMatches
from textual.css.stylesheet import RulesMap, Stylesheet

View File

@@ -866,11 +866,6 @@ class StringEnumProperty(Generic[EnumType]):
parent=self._refresh_parent,
)
# if obj.node and (
# obj.node._has_order_style or obj.node._has_odd_or_even
# ):
# obj.node.call_later(obj.node._update_styles)
class OverflowProperty(StringEnumProperty):
"""Descriptor for overflow styles that forces widgets to refresh scrollbars."""

View File

@@ -49,7 +49,6 @@ if TYPE_CHECKING:
from textual import constants, errors, events, messages
from textual._animator import DEFAULT_EASING, Animatable, BoundAnimator, EasingFunction
from textual._arrange import DockArrangeResult, arrange
from textual._compose import compose
from textual._context import NoActiveAppError
from textual._debug import get_caller_file_and_line
from textual._dispatch_key import dispatch_key
@@ -62,6 +61,7 @@ from textual.await_remove import AwaitRemove
from textual.box_model import BoxModel
from textual.cache import FIFOCache
from textual.color import Color
from textual.compose import compose
from textual.content import Content, ContentType
from textual.css.match import match
from textual.css.parse import parse_selectors
@@ -1394,6 +1394,7 @@ class Widget(DOMNode):
return await_mount
def _refresh_styles(self) -> None:
"""Request refresh of styles on idle."""
self._refresh_styles_required = True
self.check_idle()