瀏覽代碼

Drawer inherits ValueElement (#4334)

https://github.com/zauberzeug/nicegui/discussions/4320

Drawer/LeftDrawer/RightDrawer does not currently inherit from
`ValueElement` and so property binding here does not work.

This PR updates Drawer component to inherit from ValueElement and
changes it's toggle/hide/show methods to use `value` property instead of
calling the Q elements show/hide/toggle.

Example

```py
from nicegui import ui

with ui.header():
    ui.label("Fancy App")

with ui.left_drawer(value=True, elevated=True) as left_drawer:
    ui.label("Left Drawer Content")

with ui.right_drawer(value=True, elevated=True) as right_drawer:
    ui.label("Right Drawer Content")

with ui.row():
    with ui.card():
        ui.label("Left Drawer")
        ui.button("Show", on_click=lambda: left_drawer.show())
        ui.button("Hide", on_click=lambda: left_drawer.hide())
        ui.button("Toggle", on_click=lambda: left_drawer.toggle())

    with ui.card():
        ui.label("Right Drawer")
        ui.button("Show", on_click=lambda: right_drawer.show())
        ui.button("Hide", on_click=lambda: right_drawer.hide())
        ui.button("Toggle", on_click=lambda: right_drawer.toggle())

ui.checkbox("Left Drawer State").bind_value(left_drawer, "value")
ui.checkbox("Right Drawer State").bind_value(right_drawer, "value")

ui.run(port=9001)
```

---------

Co-authored-by: Falko Schindler <falko@zauberzeug.com>
Alex Pilon 2 月之前
父節點
當前提交
d64cb9fa15
共有 1 個文件被更改,包括 23 次插入9 次删除
  1. 23 9
      nicegui/page_layout.py

+ 23 - 9
nicegui/page_layout.py

@@ -83,7 +83,7 @@ class Header(ValueElement, default_classes='nicegui-header'):
         self.value = False
 
 
-class Drawer(Element, default_classes='nicegui-drawer'):
+class Drawer(ValueElement, default_classes='nicegui-drawer'):
 
     def __init__(self,
                  side: DrawerSides, *,
@@ -102,6 +102,10 @@ class Drawer(Element, default_classes='nicegui-drawer'):
         Note: Depending on the side, the drawer is automatically placed above or below the main page container in the DOM to improve accessibility.
         To change the order, use the `move` method.
 
+        A value of ``None`` will automatically open or close the drawer depending on the current layout width (breakpoint: >=1024 px).
+        On the auto-index page, the value will remain ``None`` until the drawer is opened, closed or toggled.
+        On other pages, the value will be requested from the client when the websocket connection is established.
+
         :param side: side of the page where the drawer should be placed (`left` or `right`)
         :param value: whether the drawer is already opened (default: `None`, i.e. if layout width is above threshold)
         :param fixed: whether the drawer is fixed or scrolls with the content (default: `True`)
@@ -112,11 +116,8 @@ class Drawer(Element, default_classes='nicegui-drawer'):
         """
         _check_current_slot(self)
         with context.client.layout:
-            super().__init__('q-drawer')
-        if value is None:
-            self._props['show-if-above'] = True
-        else:
-            self._props['model-value'] = value
+            super().__init__(tag='q-drawer', value=value, on_value_change=None)
+        self._props['show-if-above'] = value is None
         self._props['side'] = side
         self._props['bordered'] = bordered
         self._props['elevated'] = elevated
@@ -129,17 +130,30 @@ class Drawer(Element, default_classes='nicegui-drawer'):
         page_container_index = self.client.layout.default_slot.children.index(self.client.page_container)
         self.move(target_index=page_container_index if side == 'left' else page_container_index + 1)
 
+        if value is None and not self.client.is_auto_index_client:
+            async def _request_value() -> None:
+                js_code = f'!getHtmlElement({self.id}).parentElement.classList.contains("q-layout--prevent-focus")'
+                self.value = await context.client.run_javascript(js_code)
+            self.client.on_connect(_request_value)
+
     def toggle(self) -> None:
         """Toggle the drawer"""
-        self.run_method('toggle')
+        if self.value is None:
+            self.run_method('toggle')
+        else:
+            self.value = not self.value
 
     def show(self) -> None:
         """Show the drawer"""
-        self.run_method('show')
+        self.value = True
 
     def hide(self) -> None:
         """Hide the drawer"""
-        self.run_method('hide')
+        self.value = False
+
+    def _handle_value_change(self, value: bool) -> None:
+        super()._handle_value_change(value)
+        self._props['show-if-above'] = value is None
 
 
 class LeftDrawer(Drawer):