Kaynağa Gözat

code review

Falko Schindler 1 yıl önce
ebeveyn
işleme
2d62887105

+ 46 - 35
nicegui/elements/scroll_area.py

@@ -1,57 +1,68 @@
-from dataclasses import fields
-from typing import Optional, Callable, Any, Dict, Union, Literal
+from typing import Any, Callable, Dict, Literal, Optional
 
 from ..element import Element
-from ..events import ScrollEventArguments, ScrollInfo
+from ..events import ScrollEventArguments, handle_event
 
 
 class ScrollArea(Element):
 
-    def __init__(self, *,
-                 on_scroll: Optional[Callable[..., Any]] = None) -> None:
+    def __init__(self, *, on_scroll: Optional[Callable[..., Any]] = None) -> None:
         """Scroll Area
 
         A way of customizing the scrollbars by encapsulating your content.
-        This element exposes the Quasar `ScrollArea <https://quasar.dev/vue-components/scroll-area/>`_ component
+        This element exposes the Quasar `ScrollArea <https://quasar.dev/vue-components/scroll-area/>`_ component.
+
+        :param on_scroll: function to be called when the scroll position changes
         """
         super().__init__('q-scroll-area')
-        self._classes = ['nicegui-scroll']
+        self._classes = ['nicegui-scroll-area']
 
         if on_scroll:
-            self.on('scroll',
-                    lambda x: self._handle_scroll(on_scroll=on_scroll, msg=x), args=[x.name for x in fields(ScrollInfo)]
-                    )
+            self.on('scroll', lambda msg: self._handle_scroll(on_scroll, msg), args=[
+                'verticalPosition',
+                'verticalPercentage',
+                'verticalSize',
+                'verticalContainerSize',
+                'horizontalPosition',
+                'horizontalPercentage',
+                'horizontalSize',
+                'horizontalContainerSize',
+            ])
 
-    def _handle_scroll(self, on_scroll: Callable, msg: Dict):
-        on_scroll(ScrollEventArguments(
+    def _handle_scroll(self, on_scroll: Callable[..., Any], msg: Dict) -> None:
+        handle_event(on_scroll, ScrollEventArguments(
             sender=self,
             client=self.client,
-            info=ScrollInfo(**msg['args'])
+            vertical_position=msg['args']['verticalPosition'],
+            vertical_percentage=msg['args']['verticalPercentage'],
+            vertical_size=msg['args']['verticalSize'],
+            vertical_container_size=msg['args']['verticalContainerSize'],
+            horizontal_position=msg['args']['horizontalPosition'],
+            horizontal_percentage=msg['args']['horizontalPercentage'],
+            horizontal_size=msg['args']['horizontalSize'],
+            horizontal_container_size=msg['args']['horizontalContainerSize'],
         ))
 
-    def set_scroll_position(self, offset: Union[int, float], *,
-                            axis: Literal['vertical', 'horizontal'] = 'vertical', duration_ms: int = 0
-                            ) -> None:
-        """
-        Set the scroll area position in percentage (float) or pixel number (int).
+    def scroll_to(self, *,
+                  pixels: Optional[float] = None,
+                  percent: Optional[float] = None,
+                  axis: Literal['vertical', 'horizontal'] = 'vertical',
+                  duration: float = 0.0,
+                  ) -> None:
+        """Set the scroll area position in percentage (float) or pixel number (int).
+
         You can add a delay to the actual scroll action with the `duration_ms` parameter.
 
-        :param offset: Scroll position offset from top in pixels or percentage (0.0 <= x <= 1.0) of the total scrolling
-                        size
-        :param axis: Scroll axis to set
-        :param duration_ms: Duration (in milliseconds) enabling animated scroll
+        :param pixels: scroll position offset from top in pixels
+        :param percent: scroll position offset from top in percentage of the total scrolling size
+        :param axis: scroll axis
+        :param duration: animation duration (in seconds, default: 0.0 means no animation)
         """
-        if offset < 0:
-            raise ValueError(f'scroll offset must be positive. Got: {offset}')
-
-        if type(offset) == int:
-            self.run_method('setScrollPosition', axis, offset, duration_ms)
-
-        elif type(offset) == float and offset > 1.0:
-            raise ValueError(f'a percentage scroll offset must be 0.0 <= x <= 1.0. Got: {offset}')
-
-        elif type(offset) == float and offset <= 1.0:
-            self.run_method('setScrollPercentage', axis, offset, duration_ms)
-
+        if pixels is not None and percent is not None:
+            raise ValueError('You can only specify one of pixels or percent')
+        if pixels is not None:
+            self.run_method('setScrollPosition', axis, pixels, 1000 * duration)
+        elif percent is not None:
+            self.run_method('setScrollPercentage', axis, percent, 1000 * duration)
         else:
-            raise ValueError(f'Got unsupported offset: {offset}')
+            raise ValueError('You must specify one of pixels or percent')

+ 9 - 13
nicegui/events.py

@@ -268,21 +268,17 @@ class KeyEventArguments(EventArguments):
     modifiers: KeyboardModifiers
 
 
-@dataclass(**KWONLY_SLOTS)
-class ScrollInfo:
-    verticalPosition: float
-    verticalPercentage: float
-    verticalSize: int
-    verticalContainerSize: int
-    horizontalPosition: float
-    horizontalPercentage: float
-    horizontalSize: int
-    horizontalContainerSize: int
-
-
 @dataclass(**KWONLY_SLOTS)
 class ScrollEventArguments(EventArguments):
-    info: ScrollInfo
+    vertical_position: float
+    vertical_percentage: float
+    vertical_size: float
+    vertical_container_size: float
+    horizontal_position: float
+    horizontal_percentage: float
+    horizontal_size: float
+    horizontal_container_size: float
+
 
 def handle_event(handler: Optional[Callable[..., Any]],
                  arguments: Union[EventArguments, Dict], *,

+ 3 - 3
nicegui/static/nicegui.css

@@ -64,9 +64,9 @@
   width: 100%;
   height: 16rem;
 }
-.nicegui-scroll {
-  width: 200px;
-  height: 200px;
+.nicegui-scroll-area {
+  width: 100%;
+  height: 16rem;
 }
 .nicegui-log {
   padding: 0.25rem;

+ 22 - 32
website/more_documentation/scroll_area_documentation.py

@@ -5,12 +5,11 @@ from ..documentation_tools import text_demo
 
 def main_demo() -> None:
     with ui.row():
-        with ui.card().classes('w-48 h-32'):
-            with ui.scroll_area().classes('w-full'):
-                ui.label('I will scroll... ' * 10)
-
-        with ui.card().classes('w-48 h-32'):
-            ui.label('I will not scroll... ' * 10)
+        with ui.card().classes('w-32 h-32'):
+            with ui.scroll_area():
+                ui.label('I scroll. ' * 20)
+        with ui.card().classes('w-32 h-32'):
+            ui.label('I will not scroll. ' * 10)
 
 
 def more() -> None:
@@ -19,38 +18,29 @@ def more() -> None:
         You can use the `on_scroll` argument in `ui.scroll_area` to handle scroll events.
         The callback receives a `ScrollEventArguments` object with the following attributes:
 
-        - `sender`: the scroll_area object that generated the event
+        - `sender`: the scroll area that generated the event
         - `client`: the matching client
-        - `info`: the scroll area information as described in Quasar documentation ScrollArea API   
-          
-        The scroll info is represented as a `ScrollInfo` dataclass
+        - additional arguments as described in [Quasar's documentation for the ScrollArea API](https://quasar.dev/vue-components/scroll-area/#qscrollarea-api)
     ''')
     def scroll_events():
-        number = ui.number(label='scroll position: ')
-        with ui.card().classes('w-48 h-32'):
-            with ui.scroll_area(on_scroll=lambda x: number.set_value(x.info.verticalPercentage)).classes('w-full'):
-                ui.label('I will scroll... ' * 10)
+        position = ui.number('scroll position:').props('readonly')
+        with ui.card().classes('w-32 h-32'):
+            with ui.scroll_area(on_scroll=lambda e: position.set_value(e.vertical_percentage)):
+                ui.label('I scroll. ' * 20)
 
     @text_demo('Setting the scroll position', '''
-        You can use the `set_scroll_position` method of `ui.scroll_area` to programmatically set the scroll position.
-        This can be useful for navigation or synchronization of multiple scroll_area elements
+        You can use `scroll_to` to programmatically set the scroll position.
+        This can be useful for navigation or synchronization of multiple scroll areas.
     ''')
     def scroll_events():
-        with ui.row():
-            with ui.column().classes('w-32'):
-                number = ui.number(label='scroll position', value=0, min=0, max=1,
-                                   on_change=lambda x: sa1.set_scroll_position(x.value)).classes('w-full')
-                ui.button(icon='add', on_click=lambda: number.set_value(number.value + 0.1))
-                ui.button(icon='remove', on_click=lambda: number.set_value(number.value - 0.1))
-
-            with ui.card().classes('w-48 h-48'):
-                with ui.scroll_area(
-                        on_scroll=lambda x: sa2.set_scroll_position(x.info.verticalPercentage)
-                ).classes('w-full') as sa1:
-                    ui.label('I will scroll... ' * 100)
-
-            with ui.card().classes('w-48 h-48'):
-                with ui.scroll_area().classes('w-full') as sa2:
-                    ui.label('I will scroll... ' * 100)
+        ui.number('position', value=0, min=0, max=1, step=0.1,
+                  on_change=lambda e: area1.scroll_to(percent=e.value)).classes('w-32')
 
+        with ui.row():
+            with ui.card().classes('w-32 h-48'):
+                with ui.scroll_area(on_scroll=lambda e: area2.scroll_to(percent=e.vertical_percentage)) as area1:
+                    ui.label('I scroll. ' * 20)
 
+            with ui.card().classes('w-32 h-48'):
+                with ui.scroll_area() as area2:
+                    ui.label('I scroll. ' * 20)