Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions assets/docs/components/dialog.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,10 @@ import uuid

import reflex as rx
from reflex.components.component import ComponentNamespace
from reflex_components_core.el import Div
from reflex_components_core.el import (
Dialog as BaseDialog,
Div,
)

from ..core.core import CoreComponent, cn

Expand Down Expand Up @@ -130,7 +133,10 @@ class DialogTrigger(CoreComponent):
return rx.el.div(*children, **props)


class DialogPopup(Div, CoreComponent):
class DialogPopup(BaseDialog, CoreComponent):
on_close: rx.EventHandler = None
on_cancel: rx.EventHandler = None

@classmethod
def create(
cls,
Expand Down Expand Up @@ -177,7 +183,7 @@ class DialogPopup(Div, CoreComponent):
else:
props["on_mount"] = close_on_backdrop_script

return rx.el.dialog(*children, **props)
return super().create(*children, **props)


class DialogClose(CoreComponent):
Expand Down
12 changes: 9 additions & 3 deletions components/ui/dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

import reflex as rx
from reflex.components.component import ComponentNamespace
from reflex_components_core.el import Div
from reflex_components_core.el import (
Dialog as BaseDialog,
Div,
)

from ..core.core import CoreComponent, cn

Expand Down Expand Up @@ -66,7 +69,10 @@ def create(cls, *children, **props) -> rx.Component:
return rx.el.div(*children, **props)


class DialogPopup(Div, CoreComponent):
class DialogPopup(BaseDialog, CoreComponent):
on_close: rx.EventHandler = None
on_cancel: rx.EventHandler = None

@classmethod
def create(
cls,
Expand Down Expand Up @@ -113,7 +119,7 @@ def create(
else:
props["on_mount"] = close_on_backdrop_script

return rx.el.dialog(*children, **props)
return super().create(*children, **props)


class DialogClose(CoreComponent):
Expand Down
53 changes: 53 additions & 0 deletions tests/test_dialog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
"""Regression coverage for the dialog popup crash when ``dismissible=False``
or ``on_open_change=...`` was passed to ``dialog.popup(...)``.

Both options previously raised at component-construction time:

ValueError: The Dialog does not take in an 'on_cancel' event trigger
ValueError: The Dialog does not take in an 'on_close' event trigger

because ``DialogPopup`` wired ``on_cancel`` / ``on_close`` into ``props`` and
passed them to ``rx.el.dialog(...)``, whose underlying element does not declare
those triggers. The tests pin the four contracts the fix restored:
``DialogPopup`` declares ``on_close`` / ``on_cancel`` as class-level triggers,
the popup renders a native ``<dialog>`` with ``data-slot="dialog-content"``,
``dismissible=False`` wires ``on_cancel`` only, and ``on_open_change=`` wires
``on_close`` only. See bug #4 and PR #23.
"""

import reflex as rx
from reflex_components_core.el.elements.other import Dialog

from components.ui.dialog import DialogPopup, dialog


class _DialogState(rx.State): # pyright: ignore [reportUntypedBaseClass]
open: bool = True

def set_open(self, *, value: bool) -> None:
self.open = value


def test_dialog_popup_declares_on_close_and_on_cancel_triggers():
triggers = DialogPopup.get_event_triggers()
assert "on_close" in triggers
assert "on_cancel" in triggers


def test_popup_is_a_dialog_element_with_data_slot():
popup = dialog.popup(dialog.title("title"), dismissible=False)
assert isinstance(popup, Dialog)
assert popup.tag == "dialog"
assert popup.custom_attrs.get("data-slot") == "dialog-content"


def test_dismissible_false_wires_on_cancel():
popup = dialog.popup(dialog.title("title"), dismissible=False)
assert "on_cancel" in popup.event_triggers
assert "on_close" not in popup.event_triggers


def test_on_open_change_wires_on_close():
popup = dialog.popup(dialog.title("title"), on_open_change=_DialogState.set_open)
assert "on_close" in popup.event_triggers
assert "on_cancel" not in popup.event_triggers