diff --git a/ipyvuetify/extra/file_input.py b/ipyvuetify/extra/file_input.py
index 30fb52b5..f38fd7eb 100644
--- a/ipyvuetify/extra/file_input.py
+++ b/ipyvuetify/extra/file_input.py
@@ -7,6 +7,8 @@
import IPython
import nest_asyncio
import traitlets
+from ipywidgets import widget_serialization
+from traitlets import Any, Bool, Dict, Float, Int, List, Unicode, Union
import ipyvuetify as v
@@ -148,26 +150,177 @@ def readall(self):
class FileInput(v.VuetifyTemplate):
- template = traitlets.Unicode(load_template("file_input.vue")).tag(sync=True)
- data = traitlets.Unicode("{myfiles: undefined}").tag(sync=True)
-
- file_info = traitlets.List().tag(sync=True)
- version = traitlets.Int(0).tag(sync=True)
- multiple = traitlets.Bool(True).tag(sync=True)
- disabled = traitlets.Bool(False).tag(sync=True)
- directory = traitlets.Bool(False).tag(sync=True)
- accept = traitlets.Unicode().tag(sync=True)
- total_progress = traitlets.Int(0).tag(sync=True)
- show_progress = traitlets.Bool(True).tag(sync=True)
- progress_indeterminate = traitlets.Bool(False).tag(sync=True)
+ append_icon = Unicode(None, allow_none=True).tag(sync=True)
+
+ append_outer_icon = Unicode(None, allow_none=True).tag(sync=True)
+
+ autofocus = Bool(None, allow_none=True).tag(sync=True)
+
+ background_color = Unicode(None, allow_none=True).tag(sync=True)
+
+ chips = Bool(None, allow_none=True).tag(sync=True)
+
+ clear_icon = Unicode(None, allow_none=True).tag(sync=True)
+
+ clearable = Bool(None, allow_none=True).tag(sync=True)
+
+ color = Unicode(None, allow_none=True).tag(sync=True)
+
+ counter = Union([Bool(), Float(), Unicode()], default_value=None, allow_none=True).tag(
+ sync=True
+ )
+
+ counter_size_string = Unicode(None, allow_none=True).tag(sync=True)
+
+ counter_string = Unicode(None, allow_none=True).tag(sync=True)
+
+ dark = Bool(None, allow_none=True).tag(sync=True)
+
+ dense = Bool(None, allow_none=True).tag(sync=True)
+
+ disabled = Bool(None, allow_none=True).tag(sync=True)
+
+ error = Bool(None, allow_none=True).tag(sync=True)
+
+ error_count = Union([Float(), Unicode()], default_value=None, allow_none=True).tag(sync=True)
+
+ error_messages = Union([Unicode(), List(Any())], default_value=None, allow_none=True).tag(
+ sync=True
+ )
+
+ filled = Bool(None, allow_none=True).tag(sync=True)
+
+ flat = Bool(None, allow_none=True).tag(sync=True)
+
+ full_width = Bool(None, allow_none=True).tag(sync=True)
+
+ height = Union([Float(), Unicode()], default_value=None, allow_none=True).tag(sync=True)
+
+ hide_details = Union([Bool(), Unicode()], default_value=None, allow_none=True).tag(sync=True)
+
+ # Missing Vuetify prop: hide-input
+
+ hint = Unicode(None, allow_none=True).tag(sync=True)
+
+ id = Unicode(None, allow_none=True).tag(sync=True)
+
+ label = Unicode(None, allow_none=True).tag(sync=True)
+
+ light = Bool(None, allow_none=True).tag(sync=True)
+
+ loader_height = Union([Float(), Unicode()], default_value=None, allow_none=True).tag(sync=True)
+
+ loading = Union([Bool(), Unicode()], default_value=None, allow_none=True).tag(sync=True)
+
+ messages = Union([Unicode(), List(Any())], default_value=None, allow_none=True).tag(sync=True)
+
+ multiple = Bool(None, allow_none=True).tag(sync=True)
+
+ outlined = Bool(None, allow_none=True).tag(sync=True)
+
+ persistent_hint = Bool(None, allow_none=True).tag(sync=True)
+
+ # Missing Vuetify prop: persistent-placeholder
+
+ placeholder = Unicode(None, allow_none=True).tag(sync=True)
+
+ prefix = Unicode(None, allow_none=True).tag(sync=True)
+
+ prepend_icon = Unicode(None, allow_none=True).tag(sync=True)
+
+ prepend_inner_icon = Unicode(None, allow_none=True).tag(sync=True)
+
+ readonly = Bool(None, allow_none=True).tag(sync=True)
+
+ reverse = Bool(None, allow_none=True).tag(sync=True)
+
+ rounded = Bool(None, allow_none=True).tag(sync=True)
+
+ rules = List(Any(), default_value=None, allow_none=True).tag(sync=True)
+
+ shaped = Bool(None, allow_none=True).tag(sync=True)
+
+ show_size = Union([Bool(), Float()], default_value=None, allow_none=True).tag(sync=True)
+
+ single_line = Bool(None, allow_none=True).tag(sync=True)
+
+ small_chips = Bool(None, allow_none=True).tag(sync=True)
+
+ solo = Bool(None, allow_none=True).tag(sync=True)
+
+ solo_inverted = Bool(None, allow_none=True).tag(sync=True)
+
+ success = Bool(None, allow_none=True).tag(sync=True)
+
+ success_messages = Union([Unicode(), List(Any())], default_value=None, allow_none=True).tag(
+ sync=True
+ )
+
+ suffix = Unicode(None, allow_none=True).tag(sync=True)
+
+ truncate_length = Union([Float(), Unicode()], default_value=None, allow_none=True).tag(
+ sync=True
+ )
+
+ type = Unicode(None, allow_none=True).tag(sync=True)
+
+ validate_on_blur = Bool(None, allow_none=True).tag(sync=True)
+
+ value = Any(None, allow_none=True).tag(sync=True)
+
+ # VueWidget props
+
+ v_model = List(Dict(), allow_none=True)
+
+ style_ = Unicode(None, allow_none=True).tag(sync=True)
+
+ class_ = Unicode(None, allow_none=True).tag(sync=True)
+
+ attributes = Dict(None, allow_none=True).tag(sync=True)
+
+ v_slots = List(Dict()).tag(sync=True, **widget_serialization)
+
+ v_on = Unicode(None, allow_none=True).tag(sync=True)
+
+ # Component-specific props
+
+ template = Unicode(load_template("file_input.vue")).tag(sync=True)
+
+ file_info = List(Dict(), allow_none=True).tag(sync=True)
+
+ version = Int(0).tag(sync=True)
+
+ total_progress = Int(0).tag(sync=True)
+
+ progress_indeterminate = Bool(False).tag(sync=True)
total_progress_inner = 0
total_size_inner = 0
- def __init__(self, **kwargs):
+ def __init__(self, *args, **kwargs):
self.chunk_listeners = {}
self.stats = []
- super().__init__(**kwargs)
+
+ # Keep default behaviour
+ kwargs.setdefault("multiple", True)
+ kwargs.setdefault("clearable", True)
+
+ attributes = kwargs.setdefault("attributes", {})
+ if "accept" in kwargs:
+ attributes["accept"] = kwargs["accept"]
+ del kwargs["accept"]
+ if "directory" in kwargs:
+ attributes["directory"] = kwargs["directory"]
+ del kwargs["directory"]
+ if "show_progress" in kwargs:
+ kwargs.setdefault("loading", kwargs["show_progress"])
+ del kwargs["show_progress"]
+ if "file_info" in kwargs:
+ del kwargs["file_info"]
+ if "v_model" in kwargs:
+ del kwargs["v_model"]
+
+ super().__init__(*args, **kwargs)
if not hasattr(IPython.get_ipython(), "kernel"):
return
@@ -175,10 +328,41 @@ def __init__(self, **kwargs):
if kernel.implementation == "ipython":
nest_asyncio.apply()
+ @property
+ def accept(self):
+ if "accept" in self.attributes:
+ return self.attributes["accept"]
+ return ""
+
+ @accept.setter
+ def accept(self, value):
+ self.attributes = {**self.attributes, "accept": value}
+
+ @property
+ def directory(self):
+ if "directory" in self.attributes:
+ return self.attributes["directory"]
+ return False
+
+ @directory.setter
+ def directory(self, value):
+ self.attributes = {**self.attributes, "directory": value}
+
+ @property
+ def show_progress(self):
+ if self.loading is not None:
+ return self.loading
+ return True
+
+ @show_progress.setter
+ def show_progress(self, value):
+ self.loading = value
+
@traitlets.observe("file_info")
def _file_info_changed(self, _):
self.version += 1
self.reset_stats()
+ self.v_model = self.get_files()
def update_stats(self, file_index, bytes_read):
self.stats[file_index] += bytes_read
@@ -191,7 +375,7 @@ def update_stats(self, file_index, bytes_read):
def get_files(self, timeout=30):
files = []
for index, file in enumerate(self.file_info):
- file = copy.deepcopy(self.file_info[index])
+ file = copy.deepcopy(file)
file["file_obj"] = ClientSideFile(self, index, timeout=timeout)
files.append(file)
return files
diff --git a/ipyvuetify/extra/file_input.vue b/ipyvuetify/extra/file_input.vue
index 6d8a8401..abb2dd04 100644
--- a/ipyvuetify/extra/file_input.vue
+++ b/ipyvuetify/extra/file_input.vue
@@ -1,40 +1,360 @@
-
-
-
-
+
+
+
+
+
+
+
+
+
+