-
QuestionHello, I am new to NiceGUI and not very familiar with Javascript. I wanted to ask how to implement a draggable dialog. I found this Quasar thread with an implementation in javascript (quasarframework/quasar#15316) that has the behavior I'm looking for, but I'm not sure how to translate that into NiceGUI. I would appreciate any help. Thank you in advance! Below is my current dialog code. from nicegui import ui
with ui.dialog().props("seamless persistent") as dialog:
with ui.card().classes("p-0 w-[20lvw]"):
with ui.column().classes("w-full"):
with ui.row().classes("w-full bg-slate-400"):
ui.space()
ui.button(icon="close", on_click=lambda: dialog.submit("No")).props("dense flat text-color='white'")
ui.label('Select "Yes", "No", or close the dialog.').classes("p-2")
with ui.row().classes("w-full p-2"):
ui.space()
ui.button('Yes', color="positive", on_click=lambda: dialog.submit('Yes'))
ui.button('No', color="negative", on_click=lambda: dialog.submit('No'))
async def show():
result = await dialog
ui.notify(f'You chose {result}')
ui.button('Await a dialog', on_click=show)
ui.run() |
Beta Was this translation helpful? Give feedback.
Replies: 4 comments 5 replies
-
You could try gsap |
Beta Was this translation helpful? Give feedback.
-
This is my attempt to implement a draggable dialog without gsap. But there's a duplicate card in the bottom right while dragging. And it snaps back to the original position when dropping. Maybe someone wants to give it a try and fix these issues? with ui.dialog(value=True):
with ui.card() \
.on('drag', lambda e: card.style(f'transform: translate({e.args["x"]}px, {e.args["y"]}px)')) \
.props('draggable') \
.style('user-select: none') as card:
ui.label('Dialog') |
Beta Was this translation helpful? Give feedback.
-
This might be of interest? It's a css-only solution: https://codepen.io/chriscoyier/pen/xxwVrGW And here's a nicegui version of it: from nicegui import ui
resizer = 'width: 100px; height: 100px; overflow: hidden; opacity: 0; resize: both;'
wrap = 'width: min-content; position: relative;'
x = 'pointer-events: none; position: absolute; bottom: -10px; left: calc(100% - 20px); line-height: 0; color: red; font-size: 50px'
span = 'white-space: nowrap; vertical-align: middle; color: black; text-transform: uppercase; font: 600 15px/1 system-ui, sans-serif; display: inline-block; transform: translate(45px, -10px);'
with ui.element('div').style(wrap):
with ui.element('div').style(resizer):
pass
with ui.element('div').style(x):
ui.label('X')
with ui.element('div').style(span):
ui.label('Drag Me!')
ui.run() It's a bit limited in that the draggable area is just the (hidden) resize widget, but might provide some inspiration. |
Beta Was this translation helpful? Give feedback.
-
Thanks everyone for your help on this! I've settled with the below code using gsap for now, even though it doesn't limit the draggable area to just the top bar of the dialog. from nicegui import ui
ui.add_head_html("""
<script src="https://unpkg.com/gsap@3.12.5/dist/gsap.min.js"></script>
<script src="https://unpkg.com/gsap@3.12.5/dist/Draggable.min.js"></script>
""")
ui.add_body_html("""
<script>
function initDraggableClass() {
Draggable.create(".draggable", {
type: "x,y",
dragClickables: false,
allowEventDefault: true,
});
};
window.addEventListener("DOMContentLoaded", (event) => {
gsap.registerPlugin(Draggable);
initDraggableClass();
});
</script>
""")
with ui.dialog().props("seamless persistent").classes("draggable") as dialog:
with ui.card().classes("p-0 w-[20lvw]"):
with ui.column().classes("w-full"):
with ui.row(align_items="center").classes(
"w-full bg-slate-400 text-white pl-2"
):
ui.label("Dialog Title")
ui.space()
ui.button(icon="close", on_click=lambda: dialog.submit("No")).props(
"dense flat text-color='white'"
)
ui.label('Select "Yes", "No", or close the dialog.').classes("p-2")
with ui.row().classes("w-full p-2"):
ui.space()
ui.button(
"Yes", color="positive", on_click=lambda: dialog.submit("Yes")
)
ui.button("No", color="negative", on_click=lambda: dialog.submit("No"))
async def show():
ui.run_javascript("initDraggableClass();")
result = await dialog
ui.notify(f"You chose {result}")
ui.button("Await a dialog", on_click=show)
ui.label("Draggable Label via GSAP").classes("draggable")
ui.run() |
Beta Was this translation helpful? Give feedback.
Thanks everyone for your help on this! I've settled with the below code using gsap for now, even though it doesn't limit the draggable area to just the top bar of the dialog.