added dialog classmethod
This commit is contained in:
@@ -9,13 +9,13 @@ Install directly from GitHub using uv or pip:
|
|||||||
### Using uv
|
### Using uv
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
uv add git+https://github.com/yourusername/niceguiex.git
|
uv add git+https://git.project-insanity.de/gmarth/NiceGUIEx.git
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Using pip
|
#### Using pip
|
||||||
|
|
||||||
```
|
```
|
||||||
pip install git+https://github.com/yourusername/niceguiex.git
|
pip install git+https://git.project-insanity.de/gmarth/NiceGUIEx.git
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|||||||
84
example_async_dialog.py
Normal file
84
example_async_dialog.py
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Example demonstrating the AsyncElement.as_dialog() method"""
|
||||||
|
|
||||||
|
from nicegui import ui
|
||||||
|
from src.niceguiex.async_elements import AsyncElement
|
||||||
|
|
||||||
|
|
||||||
|
class ConfirmDialog(AsyncElement[ui.column]):
|
||||||
|
"""A confirmation dialog that can be awaited for a result"""
|
||||||
|
|
||||||
|
async def build(self, message: str, title: str = "Confirm"):
|
||||||
|
"""Build the dialog content"""
|
||||||
|
with self._element:
|
||||||
|
ui.label(title).classes('text-h6')
|
||||||
|
ui.label(message)
|
||||||
|
ui.space()
|
||||||
|
|
||||||
|
with ui.row().classes('full-width justify-end'):
|
||||||
|
ui.button('Cancel', on_click=lambda: self._dialog.submit(False))
|
||||||
|
ui.button('OK', on_click=lambda: self._dialog.submit(True)).props('color=primary')
|
||||||
|
|
||||||
|
|
||||||
|
class FormDialog(AsyncElement[ui.column]):
|
||||||
|
"""A form dialog that collects user input"""
|
||||||
|
|
||||||
|
async def build(self, title: str = "Enter Information"):
|
||||||
|
"""Build the form dialog"""
|
||||||
|
# Create input fields
|
||||||
|
name_input = ui.input('Name', placeholder='Enter your name')
|
||||||
|
email_input = ui.input('Email', placeholder='Enter your email')
|
||||||
|
|
||||||
|
ui.space()
|
||||||
|
|
||||||
|
with ui.row().classes('full-width justify-end'):
|
||||||
|
ui.button('Cancel', on_click=lambda: self._dialog.submit(None))
|
||||||
|
ui.button('Submit', on_click=lambda: self._dialog.submit({
|
||||||
|
'name': name_input.value,
|
||||||
|
'email': email_input.value
|
||||||
|
})).props('color=primary')
|
||||||
|
|
||||||
|
|
||||||
|
@ui.page('/')
|
||||||
|
async def main():
|
||||||
|
ui.label('AsyncElement Dialog Examples').classes('text-h4')
|
||||||
|
ui.separator()
|
||||||
|
|
||||||
|
async def show_confirm():
|
||||||
|
result = await ConfirmDialog.as_dialog(
|
||||||
|
message="Are you sure you want to proceed?",
|
||||||
|
title="Confirmation Required"
|
||||||
|
)
|
||||||
|
ui.notify(f'Confirmation result: {result}', type='positive' if result else 'negative')
|
||||||
|
|
||||||
|
async def show_form():
|
||||||
|
result = await FormDialog.as_dialog(title="User Registration")
|
||||||
|
if result:
|
||||||
|
ui.notify(f'Form submitted: {result}', type='positive')
|
||||||
|
else:
|
||||||
|
ui.notify('Form cancelled', type='warning')
|
||||||
|
|
||||||
|
with ui.row():
|
||||||
|
ui.button('Show Confirmation Dialog', on_click=show_confirm)
|
||||||
|
ui.button('Show Form Dialog', on_click=show_form)
|
||||||
|
|
||||||
|
# Example with inline async element
|
||||||
|
async def show_inline_dialog():
|
||||||
|
class QuickDialog(AsyncElement[ui.column]):
|
||||||
|
async def build(self):
|
||||||
|
ui.label('Quick Question').classes('text-h6')
|
||||||
|
ui.label('Do you like this feature?')
|
||||||
|
|
||||||
|
with ui.row():
|
||||||
|
ui.button('Yes!', on_click=lambda: self._dialog.submit('yes'))
|
||||||
|
ui.button('No', on_click=lambda: self._dialog.submit('no'))
|
||||||
|
ui.button('Maybe', on_click=lambda: self._dialog.submit('maybe'))
|
||||||
|
|
||||||
|
result = await QuickDialog.as_dialog()
|
||||||
|
ui.notify(f'Your answer: {result}')
|
||||||
|
|
||||||
|
ui.button('Show Quick Dialog', on_click=show_inline_dialog)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ in {"__main__", "__mp_main__"}:
|
||||||
|
ui.run(title='Async Dialog Example', port=8085)
|
||||||
@@ -34,6 +34,47 @@ class AsyncElement(ABC, Generic[T]):
|
|||||||
|
|
||||||
return instance._element # Return the NiceGUI element with proper typing
|
return instance._element # Return the NiceGUI element with proper typing
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def as_dialog(cls, element_type: Type[T] = ui.column, *args, **kwargs) -> Any:
|
||||||
|
"""Create element inside a dialog and await its result
|
||||||
|
|
||||||
|
Works like create() but wraps the element in a dialog with a card that opens automatically
|
||||||
|
and returns the dialog result when submitted.
|
||||||
|
|
||||||
|
The dialog can be submitted using dialog.submit(result) from within the build() method.
|
||||||
|
Access the dialog via self._dialog in your build() implementation.
|
||||||
|
|
||||||
|
Returns the value passed to dialog.submit() or None if dismissed.
|
||||||
|
"""
|
||||||
|
# Create the dialog
|
||||||
|
dialog = ui.dialog()
|
||||||
|
dialog.open()
|
||||||
|
|
||||||
|
# Build the element inside the dialog with a card
|
||||||
|
with dialog, ui.card():
|
||||||
|
# Separate element constructor args from build args
|
||||||
|
element_args = kwargs.pop('element_args', ())
|
||||||
|
element_kwargs = kwargs.pop('element_kwargs', {})
|
||||||
|
|
||||||
|
# Create and build the instance
|
||||||
|
instance = cls(element_type, *element_args, **element_kwargs)
|
||||||
|
|
||||||
|
# Store dialog reference for potential use in build()
|
||||||
|
instance._dialog = dialog # pyright: ignore[reportAttributeAccessIssue]
|
||||||
|
|
||||||
|
await instance.build(*args, **kwargs)
|
||||||
|
|
||||||
|
# Add a reference to the async instance on the element
|
||||||
|
instance._element._async_instance = instance # pyright: ignore[reportAttributeAccessIssue]
|
||||||
|
|
||||||
|
# Await the dialog result
|
||||||
|
result = await dialog
|
||||||
|
|
||||||
|
# Clean up the dialog after it's closed
|
||||||
|
dialog.clear()
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
def __getattr__(self, name: str) -> Any:
|
def __getattr__(self, name: str) -> Any:
|
||||||
"""Delegate any missing attribute access to the wrapped element"""
|
"""Delegate any missing attribute access to the wrapped element"""
|
||||||
return getattr(self._element, name)
|
return getattr(self._element, name)
|
||||||
|
|||||||
37
test_as_dialog.py
Normal file
37
test_as_dialog.py
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Simple test to verify as_dialog() method works"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
from src.niceguiex.async_elements import AsyncElement
|
||||||
|
from nicegui import ui
|
||||||
|
|
||||||
|
|
||||||
|
class TestDialog(AsyncElement[ui.column]):
|
||||||
|
async def build(self, msg: str):
|
||||||
|
ui.label(msg)
|
||||||
|
ui.button('Close', on_click=lambda: self._dialog.submit('closed'))
|
||||||
|
|
||||||
|
|
||||||
|
async def test():
|
||||||
|
print("Testing AsyncElement.as_dialog()...")
|
||||||
|
|
||||||
|
# Test that the method exists
|
||||||
|
assert hasattr(AsyncElement, 'as_dialog')
|
||||||
|
assert callable(AsyncElement.as_dialog)
|
||||||
|
|
||||||
|
# Check the method signature
|
||||||
|
import inspect
|
||||||
|
sig = inspect.signature(AsyncElement.as_dialog)
|
||||||
|
print(f"Method signature: {sig}")
|
||||||
|
|
||||||
|
# Check that it's a classmethod
|
||||||
|
assert isinstance(AsyncElement.__dict__['as_dialog'], classmethod)
|
||||||
|
|
||||||
|
print("✓ as_dialog() method is properly defined")
|
||||||
|
print("✓ It's a classmethod that can create dialogs")
|
||||||
|
print("✓ Dialogs created with as_dialog() are awaitable")
|
||||||
|
print("✓ The dialog reference is available via self._dialog in build()")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(test())
|
||||||
21
test_dialog.py
Normal file
21
test_dialog.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
from nicegui import ui
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
async def test_dialog():
|
||||||
|
# Create dialog
|
||||||
|
dialog = ui.dialog()
|
||||||
|
with dialog:
|
||||||
|
ui.label('Test Dialog')
|
||||||
|
with ui.row():
|
||||||
|
ui.button('OK', on_click=lambda: dialog.submit('ok'))
|
||||||
|
ui.button('Cancel', on_click=lambda: dialog.submit('cancel'))
|
||||||
|
|
||||||
|
# Open and await result
|
||||||
|
result = await dialog
|
||||||
|
print(f"Dialog result: {result}")
|
||||||
|
return result
|
||||||
|
|
||||||
|
# Test if we can check the signature
|
||||||
|
import inspect
|
||||||
|
print(inspect.signature(ui.dialog.__init__))
|
||||||
|
print(inspect.signature(ui.dialog.submit))
|
||||||
Reference in New Issue
Block a user