mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
CSS focus-within
This commit is contained in:
@@ -1,3 +1,7 @@
|
|||||||
|
App.-show-focus *:focus {
|
||||||
|
tint: #8bc34a 50%;
|
||||||
|
}
|
||||||
|
|
||||||
#uber1 {
|
#uber1 {
|
||||||
layout: vertical;
|
layout: vertical;
|
||||||
background: green;
|
background: green;
|
||||||
@@ -5,8 +9,12 @@
|
|||||||
border: heavy white;
|
border: heavy white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#uber1:focus-within {
|
||||||
|
background: darkslateblue;
|
||||||
|
}
|
||||||
|
|
||||||
.list-item {
|
.list-item {
|
||||||
height: 8;
|
height: 10;
|
||||||
color: #12a0;
|
color: #12a0;
|
||||||
background: #ffffff00;
|
background: #ffffff00;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,15 +15,16 @@ class BasicApp(App):
|
|||||||
self.bind("d", "dump")
|
self.bind("d", "dump")
|
||||||
self.bind("t", "log_tree")
|
self.bind("t", "log_tree")
|
||||||
self.bind("p", "print")
|
self.bind("p", "print")
|
||||||
self.bind("o", "toggle_visibility")
|
self.bind("v", "toggle_visibility")
|
||||||
self.bind("p", "toggle_display")
|
self.bind("x", "toggle_display")
|
||||||
self.bind("f", "modify_focussed")
|
self.bind("f", "modify_focussed")
|
||||||
self.bind("b", "toggle_border")
|
self.bind("b", "toggle_border")
|
||||||
|
|
||||||
async def on_mount(self):
|
async def on_mount(self):
|
||||||
"""Build layout here."""
|
"""Build layout here."""
|
||||||
|
first_child = Placeholder(id="child1", classes="list-item")
|
||||||
uber1 = Widget(
|
uber1 = Widget(
|
||||||
|
first_child,
|
||||||
Placeholder(id="child1", classes="list-item"),
|
Placeholder(id="child1", classes="list-item"),
|
||||||
Placeholder(id="child2", classes="list-item"),
|
Placeholder(id="child2", classes="list-item"),
|
||||||
Placeholder(id="child3", classes="list-item"),
|
Placeholder(id="child3", classes="list-item"),
|
||||||
@@ -32,6 +33,8 @@ class BasicApp(App):
|
|||||||
Placeholder(classes="list-item"),
|
Placeholder(classes="list-item"),
|
||||||
)
|
)
|
||||||
self.mount(uber1=uber1)
|
self.mount(uber1=uber1)
|
||||||
|
self.first_child = first_child
|
||||||
|
self.uber = uber1
|
||||||
|
|
||||||
async def on_key(self, event: events.Key) -> None:
|
async def on_key(self, event: events.Key) -> None:
|
||||||
await self.dispatch_key(event)
|
await self.dispatch_key(event)
|
||||||
@@ -51,8 +54,7 @@ class BasicApp(App):
|
|||||||
self.screen.tree,
|
self.screen.tree,
|
||||||
sep=" - ",
|
sep=" - ",
|
||||||
)
|
)
|
||||||
print(1234, 5678)
|
self.app.set_focus(None)
|
||||||
sys.stdout.write("abcdef")
|
|
||||||
|
|
||||||
def action_modify_focussed(self):
|
def action_modify_focussed(self):
|
||||||
"""Increment height of focussed child, randomise border and bg color"""
|
"""Increment height of focussed child, randomise border and bg color"""
|
||||||
|
|||||||
@@ -536,16 +536,19 @@ class App(Generic[ReturnType], DOMNode):
|
|||||||
# No focus, so blur currently focused widget if it exists
|
# No focus, so blur currently focused widget if it exists
|
||||||
if self.focused is not None:
|
if self.focused is not None:
|
||||||
self.focused.post_message_no_wait(events.Blur(self))
|
self.focused.post_message_no_wait(events.Blur(self))
|
||||||
|
self.focused.emit_no_wait(events.DescendantBlur(self))
|
||||||
self.focused = None
|
self.focused = None
|
||||||
elif widget.can_focus:
|
elif widget.can_focus:
|
||||||
if self.focused != widget:
|
if self.focused != widget:
|
||||||
if self.focused is not None:
|
if self.focused is not None:
|
||||||
# Blur currently focused widget
|
# Blur currently focused widget
|
||||||
self.focused.post_message_no_wait(events.Blur(self))
|
self.focused.post_message_no_wait(events.Blur(self))
|
||||||
|
self.focused.emit_no_wait(events.DescendantBlur(self))
|
||||||
# Change focus
|
# Change focus
|
||||||
self.focused = widget
|
self.focused = widget
|
||||||
# Send focus event
|
# Send focus event
|
||||||
widget.post_message_no_wait(events.Focus(self))
|
widget.post_message_no_wait(events.Focus(self))
|
||||||
|
widget.emit_no_wait(events.DescendantFocus(self))
|
||||||
|
|
||||||
async def _set_mouse_over(self, widget: Widget | None) -> None:
|
async def _set_mouse_over(self, widget: Widget | None) -> None:
|
||||||
"""Called when the mouse is over another widget.
|
"""Called when the mouse is over another widget.
|
||||||
|
|||||||
@@ -393,3 +393,11 @@ class Focus(Event, bubble=False):
|
|||||||
|
|
||||||
class Blur(Event, bubble=False):
|
class Blur(Event, bubble=False):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class DescendantFocus(Event, bubble=True):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class DescendantBlur(Event, bubble=True):
|
||||||
|
pass
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ class Widget(DOMNode):
|
|||||||
auto_width = Reactive(True)
|
auto_width = Reactive(True)
|
||||||
auto_height = Reactive(True)
|
auto_height = Reactive(True)
|
||||||
has_focus = Reactive(False)
|
has_focus = Reactive(False)
|
||||||
|
descendant_has_focus = Reactive(False)
|
||||||
mouse_over = Reactive(False)
|
mouse_over = Reactive(False)
|
||||||
scroll_x = Reactive(0.0, repaint=False)
|
scroll_x = Reactive(0.0, repaint=False)
|
||||||
scroll_y = Reactive(0.0, repaint=False)
|
scroll_y = Reactive(0.0, repaint=False)
|
||||||
@@ -424,6 +425,8 @@ class Widget(DOMNode):
|
|||||||
yield "hover"
|
yield "hover"
|
||||||
if self.has_focus:
|
if self.has_focus:
|
||||||
yield "focus"
|
yield "focus"
|
||||||
|
if self.descendant_has_focus:
|
||||||
|
yield "focus-within"
|
||||||
|
|
||||||
def watch(self, attribute_name, callback: Callable[[Any], Awaitable[None]]) -> None:
|
def watch(self, attribute_name, callback: Callable[[Any], Awaitable[None]]) -> None:
|
||||||
watch(self, attribute_name, callback)
|
watch(self, attribute_name, callback)
|
||||||
@@ -721,11 +724,19 @@ class Widget(DOMNode):
|
|||||||
self.mouse_over = True
|
self.mouse_over = True
|
||||||
|
|
||||||
def on_focus(self, event: events.Focus) -> None:
|
def on_focus(self, event: events.Focus) -> None:
|
||||||
|
self.emit_no_wait(events.DescendantFocus(self))
|
||||||
self.has_focus = True
|
self.has_focus = True
|
||||||
|
|
||||||
def on_blur(self, event: events.Blur) -> None:
|
def on_blur(self, event: events.Blur) -> None:
|
||||||
|
self.emit_no_wait(events.DescendantBlur(self))
|
||||||
self.has_focus = False
|
self.has_focus = False
|
||||||
|
|
||||||
|
def on_descendant_focus(self, event: events.DescendantFocus) -> None:
|
||||||
|
self.descendant_has_focus = True
|
||||||
|
|
||||||
|
def on_descendant_blur(self, event: events.DescendantBlur) -> None:
|
||||||
|
self.descendant_has_focus = False
|
||||||
|
|
||||||
def on_mouse_scroll_down(self, event) -> None:
|
def on_mouse_scroll_down(self, event) -> None:
|
||||||
if self.is_container:
|
if self.is_container:
|
||||||
self.scroll_down(animate=False)
|
self.scroll_down(animate=False)
|
||||||
|
|||||||
Reference in New Issue
Block a user