Browse Source

add set_clipboard method (#1230)

Thomas Brandého 1 year ago
parent
commit
d9e4d6d130

+ 6 - 0
pynecone/.templates/web/utils/state.js

@@ -125,6 +125,12 @@ export const applyEvent = async (event, router, socket) => {
     return false;
     return false;
   }
   }
 
 
+  if (event.name == "_set_clipboard") {
+    const content = event.payload.content;
+    navigator.clipboard.writeText(content);
+    return false;
+  }
+
   if (event.name == "_alert") {
   if (event.name == "_alert") {
     alert(event.payload.message);
     alert(event.payload.message);
     return false;
     return false;

+ 1 - 0
pynecone/__init__.py

@@ -23,6 +23,7 @@ from .event import EventChain as EventChain
 from .event import FileUpload as upload_files
 from .event import FileUpload as upload_files
 from .event import console_log as console_log
 from .event import console_log as console_log
 from .event import redirect as redirect
 from .event import redirect as redirect
+from .event import set_clipboard as set_clipboard
 from .event import set_cookie as set_cookie
 from .event import set_cookie as set_cookie
 from .event import set_focus as set_focus
 from .event import set_focus as set_focus
 from .event import set_local_storage as set_local_storage
 from .event import set_local_storage as set_local_storage

+ 28 - 2
pynecone/components/datadisplay/code.py

@@ -3,7 +3,11 @@
 from typing import Dict
 from typing import Dict
 
 
 from pynecone.components.component import Component
 from pynecone.components.component import Component
+from pynecone.components.forms import Button
+from pynecone.components.layout import Box
 from pynecone.components.libs.chakra import ChakraComponent
 from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.components.media import Icon
+from pynecone.event import set_clipboard
 from pynecone.style import Style
 from pynecone.style import Style
 from pynecone.utils import imports
 from pynecone.utils import imports
 from pynecone.vars import ImportVar, Var
 from pynecone.vars import ImportVar, Var
@@ -49,11 +53,13 @@ class CodeBlock(Component):
         return merged_imports
         return merged_imports
 
 
     @classmethod
     @classmethod
-    def create(cls, *children, **props):
+    def create(cls, *children, can_copy=False, copy_button=None, **props):
         """Create a text component.
         """Create a text component.
 
 
         Args:
         Args:
             *children: The children of the component.
             *children: The children of the component.
+            can_copy: Whether a copy button should appears.
+            copy_button: A custom copy button to override the default one.
             **props: The props to pass to the component.
             **props: The props to pass to the component.
 
 
         Returns:
         Returns:
@@ -62,18 +68,38 @@ class CodeBlock(Component):
         # This component handles style in a special prop.
         # This component handles style in a special prop.
         custom_style = props.pop("custom_style", {})
         custom_style = props.pop("custom_style", {})
 
 
+        if can_copy:
+            code = children[0]
+            copy_button = (
+                copy_button
+                if copy_button is not None
+                else Button.create(
+                    Icon.create(tag="copy"),
+                    on_click=set_clipboard(code),
+                    style={"position": "absolute", "top": "0.5em", "right": "0"},
+                )
+            )
+            custom_style.update({"padding": "1em 3.2em 1em 1em"})
+        else:
+            copy_button = None
+
         # Transfer style props to the custom style prop.
         # Transfer style props to the custom style prop.
         for key, value in props.items():
         for key, value in props.items():
             if key not in cls.get_fields():
             if key not in cls.get_fields():
                 custom_style[key] = value
                 custom_style[key] = value
 
 
         # Create the component.
         # Create the component.
-        return super().create(
+        code_block = super().create(
             *children,
             *children,
             **props,
             **props,
             custom_style=Style(custom_style),
             custom_style=Style(custom_style),
         )
         )
 
 
+        if copy_button:
+            return Box.create(code_block, copy_button, position="relative")
+        else:
+            return code_block
+
     def _add_style(self, style):
     def _add_style(self, style):
         self.custom_style = self.custom_style or {}
         self.custom_style = self.custom_style or {}
         self.custom_style.update(style)  # type: ignore
         self.custom_style.update(style)  # type: ignore

+ 16 - 0
pynecone/event.py

@@ -272,6 +272,22 @@ def set_local_storage(key: str, value: str) -> EventSpec:
     )
     )
 
 
 
 
+def set_clipboard(content: str) -> EventSpec:
+    """Set the text in content in the clipboard.
+
+    Args:
+        content: The text to add to clipboard.
+
+    Returns:
+        EventSpec: An event to set some content in the clipboard.
+    """
+    return server_side(
+        "_set_clipboard",
+        get_fn_signature(set_clipboard),
+        content=content,
+    )
+
+
 def get_event(state, event):
 def get_event(state, event):
     """Get the event from the given state.
     """Get the event from the given state.