Skip to content

Commit

Permalink
Add react dropzone
Browse files Browse the repository at this point in the history
  • Loading branch information
picklelo committed Mar 4, 2023
1 parent 8955287 commit d94787b
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 12 deletions.
Binary file modified pynecone/.templates/web/bun.lockb
Binary file not shown.
1 change: 1 addition & 0 deletions pynecone/.templates/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"react": "^17.0.2",
"react-copy-to-clipboard": "^5.1.0",
"react-dom": "^17.0.2",
"react-dropzone": "^14.2.3",
"react-markdown": "^8.0.3",
"react-plotly.js": "^2.6.0",
"react-syntax-highlighter": "^15.5.0",
Expand Down
2 changes: 1 addition & 1 deletion pynecone/.templates/web/pynecone.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"version": "0.1.19"
}
}
4 changes: 2 additions & 2 deletions pynecone/compiler/templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,9 @@ def format_state(
).format
UPLOAD_FN = join(
[
"const File = event => {set_state}({{",
"const File = files => {set_state}({{",
" ...{state},",
" files: event.target.files,",
" files,",
"}})",
]
).format
Expand Down
5 changes: 4 additions & 1 deletion pynecone/components/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ class Component(Base, ABC):
# The class name for the component.
class_name: Any = None

# Special component props.
special_props: Set[Var] = set()

@classmethod
def __init_subclass__(cls, **kwargs):
"""Set default properties.
Expand Down Expand Up @@ -290,7 +293,7 @@ def _render(self) -> Tag:
# Create the base tag.
alias = self.get_alias()
name = alias if alias is not None else self.tag
tag = Tag(name=name)
tag = Tag(name=name, special_props=self.special_props)

# Add component props to the tag.
props = {attr: getattr(self, attr) for attr in self.get_props()}
Expand Down
5 changes: 4 additions & 1 deletion pynecone/components/datadisplay/table.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,10 @@ def create(cls, *children, cell_type: str = "", cells=None, **props) -> Componen
types = {"header": Th, "data": Td}
cell_cls = types.get(cell_type)
if len(children) == 0 and cell_cls:
children = [cell_cls.create(cell) for cell in cells or []]
if isinstance(cells, Var):
children = [Foreach.create(cells, cell_cls.create)]
else:
children = [cell_cls.create(cell) for cell in cells or []]
return super().create(*children, **props)


Expand Down
39 changes: 34 additions & 5 deletions pynecone/components/forms/upload.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
"""A file upload component."""

from pynecone.components.component import Component
from typing import Dict

from pynecone.components.component import EVENT_ARG, Component
from pynecone.components.forms.input import Input
from pynecone.components.layout.box import Box
from pynecone.event import EventChain
from pynecone.var import BaseVar, Var

upload_file = BaseVar(name="e => File(e)", type_=EventChain)


class Upload(Input):
class Upload(Component):
"""A file upload component."""

# The type of input.
type_: Var[str] = "file" # type: ignore
library = "react-dropzone"

tag = "ReactDropzone"

@classmethod
def create(cls, *children, **props) -> Component:
Expand All @@ -25,4 +29,29 @@ def create(cls, *children, **props) -> Component:
Returns:
The upload component.
"""
return super().create(*children, **props, on_change=upload_file)
# The file input to use.
upload = Input.create(type_="file")
upload.special_props = {BaseVar(name="{...getInputProps()}", type_=None)}

# The dropzone to use.
zone = Box.create(upload, *children, **props)
zone.special_props = {BaseVar(name="{...getRootProps()}", type_=None)}

# Create the component.
return super().create(zone, on_drop=upload_file)

@classmethod
def get_controlled_triggers(cls) -> Dict[str, Var]:
"""Get the event triggers that pass the component's value to the handler.
Returns:
A dict mapping the event trigger to the var that is passed to the handler.
"""
return {
"on_drop": EVENT_ARG,
}

def _render(self):
out = super()._render()
out.args = ("getRootProps", "getInputProps")
return out
21 changes: 19 additions & 2 deletions pynecone/components/tags/tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import json
import os
import re
from typing import TYPE_CHECKING, Any, Dict, Optional, Union
from typing import TYPE_CHECKING, Any, Dict, Optional, Set, Tuple, Union

from plotly.graph_objects import Figure
from plotly.io import to_json
Expand All @@ -31,6 +31,12 @@ class Tag(Base):
# The inner contents of the tag.
contents: str = ""

# Args to pass to the tag.
args: Optional[Tuple[str]] = None

# Special props that aren't key value pairs.
special_props: Set[Var] = set()

def __init__(self, *args, **kwargs):
"""Initialize the tag.
Expand Down Expand Up @@ -132,17 +138,28 @@ def __str__(self) -> str:
"""
# Get the tag props.
props_str = self.format_props()

# Add the special props.
props_str += " ".join([str(prop) for prop in self.special_props])

# Add a space if there are props.
if len(props_str) > 0:
props_str = " " + props_str

if len(self.contents) == 0:
# If there is no inner content, we don't need a closing tag.
tag_str = utils.wrap(f"{self.name}{props_str}/", "<")
else:
if self.args is not None:
# If there are args, wrap the tag in a function call.
args_str = ", ".join(self.args)
contents = f"{{({{{args_str}}}) => ({self.contents})}}"
else:
contents = self.contents
# Otherwise wrap it in opening and closing tags.
open = utils.wrap(f"{self.name}{props_str}", "<")
close = utils.wrap(f"/{self.name}", "<")
tag_str = utils.wrap(self.contents, open, close)
tag_str = utils.wrap(contents, open, close)

return tag_str

Expand Down

0 comments on commit d94787b

Please sign in to comment.