Repository: zauberzeug/nicegui
Pull request #1774 (2023-10-09 07:24:03)

Support slots in `ui.chat_message`
Following up on the discussion #1772, this PR tries to add slot support to `ui.chat_messages`:

```py
with ui.chat_message():
    ui.spinner('dots')
```

While the current implementation works in a standalone app, some demos are rendered blank and some pytests are broken. 🫤


Patch:
diff --git a/nicegui/elements/chat_message.js b/nicegui/elements/chat_message.js
deleted file mode 100644
index 33030a6b..00000000
--- a/nicegui/elements/chat_message.js
+++ /dev/null
@@ -1,3 +0,0 @@
-export default {
-  template: `<q-chat-message v-bind="$attrs" />`,
-};
diff --git a/nicegui/elements/chat_message.py b/nicegui/elements/chat_message.py
index 523d1555..2aeb740a 100644
--- a/nicegui/elements/chat_message.py
+++ b/nicegui/elements/chat_message.py
@@ -2,12 +2,13 @@ import html
 from typing import List, Optional, Union
 
 from ..element import Element
+from .html import Html
 
 
-class ChatMessage(Element, component='chat_message.js'):
+class ChatMessage(Element):
 
     def __init__(self,
-                 text: Union[str, List[str]], *,
+                 text: Union[str, List[str]] = ..., *,
                  name: Optional[str] = None,
                  label: Optional[str] = None,
                  stamp: Optional[str] = None,
@@ -27,15 +28,15 @@ class ChatMessage(Element, component='chat_message.js'):
         :param sent: render as a sent message (so from current user) (default: False)
         :param text_html: render text as HTML (default: False)
         """
-        super().__init__()
+        super().__init__('q-chat-message')
 
+        if text is ...:
+            text = []
         if isinstance(text, str):
             text = [text]
         if not text_html:
             text = [html.escape(part) for part in text]
             text = [part.replace('\n', '<br />') for part in text]
-        self._props['text'] = text
-        self._props['text-html'] = True
 
         if name is not None:
             self._props['name'] = name
@@ -46,3 +47,7 @@ class ChatMessage(Element, component='chat_message.js'):
         if avatar is not None:
             self._props['avatar'] = avatar
         self._props['sent'] = sent
+
+        with self:
+            for line in text:
+                Html(line)
diff --git a/website/more_documentation/chat_message_documentation.py b/website/more_documentation/chat_message_documentation.py
index 3ad650bc..7565b53a 100644
--- a/website/more_documentation/chat_message_documentation.py
+++ b/website/more_documentation/chat_message_documentation.py
@@ -29,3 +29,11 @@ def more() -> None:
     ''')
     def multiple_messages():
         ui.chat_message(['Hi! 😀', 'How are you?'])
+
+    @text_demo('Chat message with child elements', '''
+        You can add child elements to a chat message.
+    ''')
+    def child_elements():
+        with ui.chat_message():
+            ui.label('Guess where I am!')
+            ui.image('https://picsum.photos/id/249/640/360').classes('w-64')


Test patch:
diff --git a/tests/test_chat.py b/tests/test_chat.py
index 448f0d76..c32caf4b 100644
--- a/tests/test_chat.py
+++ b/tests/test_chat.py
@@ -25,3 +25,11 @@ def test_newline(screen: Screen):
 
     screen.open('/')
     assert screen.find('Hello').find_element(By.TAG_NAME, 'br')
+
+
+def test_slot(screen: Screen):
+    with ui.chat_message():
+        ui.label('slot')
+
+    screen.open('/')
+    screen.should_contain('slot')