solara-ui 1.31.0__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (439) hide show
  1. prefix/etc/jupyter/jupyter_notebook_config.d/solara.json +7 -0
  2. prefix/etc/jupyter/jupyter_server_config.d/solara.json +7 -0
  3. solara/__init__.py +124 -0
  4. solara/__main__.py +734 -0
  5. solara/alias.py +6 -0
  6. solara/autorouting.py +546 -0
  7. solara/cache.py +303 -0
  8. solara/checks.html +71 -0
  9. solara/checks.py +224 -0
  10. solara/comm.py +28 -0
  11. solara/components/__init__.py +59 -0
  12. solara/components/alert.py +155 -0
  13. solara/components/applayout.py +393 -0
  14. solara/components/button.py +85 -0
  15. solara/components/card.py +87 -0
  16. solara/components/checkbox.py +50 -0
  17. solara/components/code_highlight_css.py +11 -0
  18. solara/components/code_highlight_css.vue +63 -0
  19. solara/components/columns.py +159 -0
  20. solara/components/component_vue.py +110 -0
  21. solara/components/cross_filter.py +335 -0
  22. solara/components/dataframe.py +546 -0
  23. solara/components/datatable.py +221 -0
  24. solara/components/datatable.vue +175 -0
  25. solara/components/details.py +21 -0
  26. solara/components/download.vue +35 -0
  27. solara/components/echarts.py +75 -0
  28. solara/components/echarts.vue +128 -0
  29. solara/components/figure_altair.py +39 -0
  30. solara/components/file_browser.py +182 -0
  31. solara/components/file_download.py +199 -0
  32. solara/components/file_drop.py +139 -0
  33. solara/components/file_drop.vue +83 -0
  34. solara/components/file_list_widget.vue +78 -0
  35. solara/components/head.py +27 -0
  36. solara/components/head_tag.py +49 -0
  37. solara/components/head_tag.vue +60 -0
  38. solara/components/image.py +173 -0
  39. solara/components/input.py +436 -0
  40. solara/components/link.py +55 -0
  41. solara/components/markdown.py +378 -0
  42. solara/components/markdown_editor.py +25 -0
  43. solara/components/markdown_editor.vue +362 -0
  44. solara/components/matplotlib.py +74 -0
  45. solara/components/meta.py +47 -0
  46. solara/components/misc.py +333 -0
  47. solara/components/pivot_table.py +258 -0
  48. solara/components/pivot_table.vue +158 -0
  49. solara/components/progress.py +47 -0
  50. solara/components/select.py +182 -0
  51. solara/components/select.vue +27 -0
  52. solara/components/slider.py +442 -0
  53. solara/components/slider_date.vue +56 -0
  54. solara/components/spinner-solara.vue +105 -0
  55. solara/components/spinner.py +30 -0
  56. solara/components/sql_code.py +33 -0
  57. solara/components/sql_code.vue +128 -0
  58. solara/components/style.py +105 -0
  59. solara/components/switch.py +68 -0
  60. solara/components/tab_navigation.py +37 -0
  61. solara/components/title.py +90 -0
  62. solara/components/title.vue +38 -0
  63. solara/components/togglebuttons.py +200 -0
  64. solara/components/tooltip.py +61 -0
  65. solara/datatypes.py +143 -0
  66. solara/express.py +241 -0
  67. solara/hooks/__init__.py +4 -0
  68. solara/hooks/dataframe.py +99 -0
  69. solara/hooks/misc.py +263 -0
  70. solara/hooks/use_reactive.py +129 -0
  71. solara/hooks/use_thread.py +129 -0
  72. solara/kitchensink.py +8 -0
  73. solara/lab/__init__.py +34 -0
  74. solara/lab/components/__init__.py +6 -0
  75. solara/lab/components/chat.py +203 -0
  76. solara/lab/components/confirmation_dialog.py +163 -0
  77. solara/lab/components/cross_filter.py +7 -0
  78. solara/lab/components/input_date.py +298 -0
  79. solara/lab/components/menu.py +181 -0
  80. solara/lab/components/menu.vue +38 -0
  81. solara/lab/components/tabs.py +274 -0
  82. solara/lab/components/theming.py +98 -0
  83. solara/lab/components/theming.vue +72 -0
  84. solara/lab/hooks/__init__.py +0 -0
  85. solara/lab/hooks/dataframe.py +12 -0
  86. solara/lab/toestand.py +3 -0
  87. solara/lab/utils/__init__.py +2 -0
  88. solara/lab/utils/cookies.py +5 -0
  89. solara/lab/utils/dataframe.py +115 -0
  90. solara/lab/utils/headers.py +5 -0
  91. solara/layout.py +44 -0
  92. solara/lifecycle.py +46 -0
  93. solara/minisettings.py +133 -0
  94. solara/py.typed +0 -0
  95. solara/reactive.py +93 -0
  96. solara/routing.py +268 -0
  97. solara/scope/__init__.py +88 -0
  98. solara/scope/types.py +55 -0
  99. solara/server/__init__.py +0 -0
  100. solara/server/app.py +491 -0
  101. solara/server/assets/custom.css +1 -0
  102. solara/server/assets/custom.js +1 -0
  103. solara/server/assets/favicon.png +0 -0
  104. solara/server/assets/favicon.svg +5 -0
  105. solara/server/assets/style.css +1665 -0
  106. solara/server/assets/theme-dark.css +437 -0
  107. solara/server/assets/theme-light.css +420 -0
  108. solara/server/assets/theme.js +3 -0
  109. solara/server/cdn_helper.py +77 -0
  110. solara/server/esm.py +69 -0
  111. solara/server/fastapi.py +5 -0
  112. solara/server/flask.py +286 -0
  113. solara/server/jupyter/__init__.py +2 -0
  114. solara/server/jupyter/cdn_handler.py +28 -0
  115. solara/server/jupyter/server_extension.py +29 -0
  116. solara/server/jupytertools.py +46 -0
  117. solara/server/kernel.py +338 -0
  118. solara/server/kernel_context.py +357 -0
  119. solara/server/patch.py +552 -0
  120. solara/server/reload.py +242 -0
  121. solara/server/server.py +456 -0
  122. solara/server/settings.py +215 -0
  123. solara/server/shell.py +251 -0
  124. solara/server/starlette.py +601 -0
  125. solara/server/static/ansi.js +270 -0
  126. solara/server/static/highlight-dark.css +82 -0
  127. solara/server/static/highlight.css +43 -0
  128. solara/server/static/main-vuetify.js +260 -0
  129. solara/server/static/main.js +163 -0
  130. solara/server/static/solara_bootstrap.py +129 -0
  131. solara/server/static/sun.svg +23 -0
  132. solara/server/static/webworker.js +42 -0
  133. solara/server/telemetry.py +212 -0
  134. solara/server/templates/index.html.j2 +1 -0
  135. solara/server/templates/loader-plain.css +11 -0
  136. solara/server/templates/loader-plain.html +20 -0
  137. solara/server/templates/loader-solara.css +111 -0
  138. solara/server/templates/loader-solara.html +40 -0
  139. solara/server/templates/plain.html +82 -0
  140. solara/server/templates/solara.html.j2 +446 -0
  141. solara/server/threaded.py +75 -0
  142. solara/server/utils.py +30 -0
  143. solara/server/websocket.py +45 -0
  144. solara/settings.py +56 -0
  145. solara/tasks.py +837 -0
  146. solara/template/button.py +16 -0
  147. solara/template/markdown.py +42 -0
  148. solara/template/portal/.flake8 +6 -0
  149. solara/template/portal/.pre-commit-config.yaml +28 -0
  150. solara/template/portal/LICENSE +21 -0
  151. solara/template/portal/Procfile +7 -0
  152. solara/template/portal/mypy.ini +3 -0
  153. solara/template/portal/pyproject.toml +26 -0
  154. solara/template/portal/solara_portal/__init__.py +4 -0
  155. solara/template/portal/solara_portal/components/__init__.py +2 -0
  156. solara/template/portal/solara_portal/components/article.py +28 -0
  157. solara/template/portal/solara_portal/components/data.py +28 -0
  158. solara/template/portal/solara_portal/components/header.py +6 -0
  159. solara/template/portal/solara_portal/components/layout.py +6 -0
  160. solara/template/portal/solara_portal/content/articles/equis-in-vidi.md +85 -0
  161. solara/template/portal/solara_portal/content/articles/substiterat-vati.md +70 -0
  162. solara/template/portal/solara_portal/data.py +60 -0
  163. solara/template/portal/solara_portal/pages/__init__.py +67 -0
  164. solara/template/portal/solara_portal/pages/article/__init__.py +26 -0
  165. solara/template/portal/solara_portal/pages/tabular.py +29 -0
  166. solara/template/portal/solara_portal/pages/viz/__init__.py +70 -0
  167. solara/template/portal/solara_portal/pages/viz/overview.py +14 -0
  168. solara/test/__init__.py +0 -0
  169. solara/test/pytest_plugin.py +697 -0
  170. solara/toestand.py +772 -0
  171. solara/util.py +308 -0
  172. solara/website/__init__.py +0 -0
  173. solara/website/assets/custom.css +468 -0
  174. solara/website/assets/images/logo-small.png +0 -0
  175. solara/website/assets/images/logo.svg +17 -0
  176. solara/website/assets/images/logo_white.svg +50 -0
  177. solara/website/assets/theme.js +8 -0
  178. solara/website/components/__init__.py +5 -0
  179. solara/website/components/algolia.vue +24 -0
  180. solara/website/components/algolia_api.vue +187 -0
  181. solara/website/components/docs.py +118 -0
  182. solara/website/components/header.py +72 -0
  183. solara/website/components/hero.py +15 -0
  184. solara/website/components/mailchimp.py +12 -0
  185. solara/website/components/mailchimp.vue +47 -0
  186. solara/website/components/markdown.py +30 -0
  187. solara/website/components/notebook.py +171 -0
  188. solara/website/pages/__init__.py +575 -0
  189. solara/website/pages/apps/__init__.py +16 -0
  190. solara/website/pages/apps/authorization/__init__.py +119 -0
  191. solara/website/pages/apps/authorization/admin.py +12 -0
  192. solara/website/pages/apps/authorization/users.py +12 -0
  193. solara/website/pages/apps/jupyter-dashboard-1.py +116 -0
  194. solara/website/pages/apps/layout-demo.py +40 -0
  195. solara/website/pages/apps/multipage/__init__.py +38 -0
  196. solara/website/pages/apps/multipage/page1.py +26 -0
  197. solara/website/pages/apps/multipage/page2.py +34 -0
  198. solara/website/pages/apps/scatter.py +136 -0
  199. solara/website/pages/apps/scrolling.py +63 -0
  200. solara/website/pages/apps/tutorial-streamlit.py +18 -0
  201. solara/website/pages/changelog/__init__.py +8 -0
  202. solara/website/pages/changelog/changelog.md +204 -0
  203. solara/website/pages/contact/__init__.py +8 -0
  204. solara/website/pages/contact/contact.md +17 -0
  205. solara/website/pages/doc_use_download.py +85 -0
  206. solara/website/pages/documentation/__init__.py +184 -0
  207. solara/website/pages/documentation/advanced/__init__.py +9 -0
  208. solara/website/pages/documentation/advanced/content/00-overview.md +1 -0
  209. solara/website/pages/documentation/advanced/content/10-howto/00-overview.md +6 -0
  210. solara/website/pages/documentation/advanced/content/10-howto/10-multipage.md +196 -0
  211. solara/website/pages/documentation/advanced/content/10-howto/20-layout.md +125 -0
  212. solara/website/pages/documentation/advanced/content/10-howto/30-testing.md +162 -0
  213. solara/website/pages/documentation/advanced/content/10-howto/31-debugging.md +69 -0
  214. solara/website/pages/documentation/advanced/content/10-howto/40-embed.md +49 -0
  215. solara/website/pages/documentation/advanced/content/10-howto/50-ipywidget_libraries.md +124 -0
  216. solara/website/pages/documentation/advanced/content/15-reference/00-overview.md +3 -0
  217. solara/website/pages/documentation/advanced/content/15-reference/40-static_files.md +31 -0
  218. solara/website/pages/documentation/advanced/content/15-reference/41-asset-files.md +36 -0
  219. solara/website/pages/documentation/advanced/content/15-reference/60-static-site-generation.md +59 -0
  220. solara/website/pages/documentation/advanced/content/15-reference/70-search.md +34 -0
  221. solara/website/pages/documentation/advanced/content/15-reference/80-reloading.md +34 -0
  222. solara/website/pages/documentation/advanced/content/15-reference/90-notebook-support.md +7 -0
  223. solara/website/pages/documentation/advanced/content/15-reference/95-caching.md +148 -0
  224. solara/website/pages/documentation/advanced/content/20-understanding/00-introduction.md +10 -0
  225. solara/website/pages/documentation/advanced/content/20-understanding/05-ipywidgets.md +35 -0
  226. solara/website/pages/documentation/advanced/content/20-understanding/06-ipyvuetify.md +42 -0
  227. solara/website/pages/documentation/advanced/content/20-understanding/10-reacton.md +28 -0
  228. solara/website/pages/documentation/advanced/content/20-understanding/12-reacton-basics.md +108 -0
  229. solara/website/pages/documentation/advanced/content/20-understanding/15-anatomy.md +23 -0
  230. solara/website/pages/documentation/advanced/content/20-understanding/17-rules-of-hooks.md +7 -0
  231. solara/website/pages/documentation/advanced/content/20-understanding/18-containers.md +166 -0
  232. solara/website/pages/documentation/advanced/content/20-understanding/20-solara.md +18 -0
  233. solara/website/pages/documentation/advanced/content/20-understanding/40-routing.md +240 -0
  234. solara/website/pages/documentation/advanced/content/20-understanding/50-solara-server.md +97 -0
  235. solara/website/pages/documentation/advanced/content/20-understanding/60-voila.md +12 -0
  236. solara/website/pages/documentation/advanced/content/30-enterprise/00-overview.md +1 -0
  237. solara/website/pages/documentation/advanced/content/30-enterprise/10-oauth.md +171 -0
  238. solara/website/pages/documentation/advanced/content/40-development/00-overview.md +0 -0
  239. solara/website/pages/documentation/advanced/content/40-development/01-contribute.md +45 -0
  240. solara/website/pages/documentation/advanced/content/40-development/10-setup.md +76 -0
  241. solara/website/pages/documentation/api/__init__.py +19 -0
  242. solara/website/pages/documentation/api/cross_filter/__init__.py +9 -0
  243. solara/website/pages/documentation/api/cross_filter/cross_filter_dataframe.py +23 -0
  244. solara/website/pages/documentation/api/cross_filter/cross_filter_report.py +22 -0
  245. solara/website/pages/documentation/api/cross_filter/cross_filter_select.py +22 -0
  246. solara/website/pages/documentation/api/cross_filter/cross_filter_slider.py +22 -0
  247. solara/website/pages/documentation/api/hooks/__init__.py +9 -0
  248. solara/website/pages/documentation/api/hooks/use_cross_filter.py +25 -0
  249. solara/website/pages/documentation/api/hooks/use_dark_effective.py +12 -0
  250. solara/website/pages/documentation/api/hooks/use_effect.md +43 -0
  251. solara/website/pages/documentation/api/hooks/use_effect.py +9 -0
  252. solara/website/pages/documentation/api/hooks/use_exception.py +33 -0
  253. solara/website/pages/documentation/api/hooks/use_memo.md +16 -0
  254. solara/website/pages/documentation/api/hooks/use_memo.py +9 -0
  255. solara/website/pages/documentation/api/hooks/use_previous.py +33 -0
  256. solara/website/pages/documentation/api/hooks/use_reactive.py +16 -0
  257. solara/website/pages/documentation/api/hooks/use_state.py +10 -0
  258. solara/website/pages/documentation/api/hooks/use_state_or_update.py +69 -0
  259. solara/website/pages/documentation/api/hooks/use_thread.md +58 -0
  260. solara/website/pages/documentation/api/hooks/use_thread.py +44 -0
  261. solara/website/pages/documentation/api/hooks/use_trait_observe.py +12 -0
  262. solara/website/pages/documentation/api/routing/__init__.py +9 -0
  263. solara/website/pages/documentation/api/routing/generate_routes.py +10 -0
  264. solara/website/pages/documentation/api/routing/generate_routes_directory.py +10 -0
  265. solara/website/pages/documentation/api/routing/resolve_path.py +35 -0
  266. solara/website/pages/documentation/api/routing/route.py +31 -0
  267. solara/website/pages/documentation/api/routing/use_route.py +80 -0
  268. solara/website/pages/documentation/api/routing/use_router.py +16 -0
  269. solara/website/pages/documentation/api/utilities/__init__.py +9 -0
  270. solara/website/pages/documentation/api/utilities/component_vue.py +10 -0
  271. solara/website/pages/documentation/api/utilities/computed.py +16 -0
  272. solara/website/pages/documentation/api/utilities/display.py +16 -0
  273. solara/website/pages/documentation/api/utilities/get_kernel_id.py +16 -0
  274. solara/website/pages/documentation/api/utilities/get_session_id.py +16 -0
  275. solara/website/pages/documentation/api/utilities/memoize.py +35 -0
  276. solara/website/pages/documentation/api/utilities/on_kernel_start.py +27 -0
  277. solara/website/pages/documentation/api/utilities/reactive.py +16 -0
  278. solara/website/pages/documentation/api/utilities/widget.py +104 -0
  279. solara/website/pages/documentation/components/__init__.py +12 -0
  280. solara/website/pages/documentation/components/advanced/__init__.py +9 -0
  281. solara/website/pages/documentation/components/advanced/link.py +27 -0
  282. solara/website/pages/documentation/components/advanced/meta.py +20 -0
  283. solara/website/pages/documentation/components/advanced/style.py +45 -0
  284. solara/website/pages/documentation/components/common.py +9 -0
  285. solara/website/pages/documentation/components/data/__init__.py +9 -0
  286. solara/website/pages/documentation/components/data/dataframe.py +44 -0
  287. solara/website/pages/documentation/components/data/pivot_table.py +81 -0
  288. solara/website/pages/documentation/components/enterprise/__init__.py +9 -0
  289. solara/website/pages/documentation/components/enterprise/avatar.py +24 -0
  290. solara/website/pages/documentation/components/enterprise/avatar_menu.py +25 -0
  291. solara/website/pages/documentation/components/input/__init__.py +9 -0
  292. solara/website/pages/documentation/components/input/button.py +23 -0
  293. solara/website/pages/documentation/components/input/checkbox.py +10 -0
  294. solara/website/pages/documentation/components/input/file_browser.py +32 -0
  295. solara/website/pages/documentation/components/input/file_drop.py +76 -0
  296. solara/website/pages/documentation/components/input/input.py +19 -0
  297. solara/website/pages/documentation/components/input/select.py +22 -0
  298. solara/website/pages/documentation/components/input/slider.py +29 -0
  299. solara/website/pages/documentation/components/input/switch.py +10 -0
  300. solara/website/pages/documentation/components/input/togglebuttons.py +21 -0
  301. solara/website/pages/documentation/components/lab/__init__.py +9 -0
  302. solara/website/pages/documentation/components/lab/chat.py +109 -0
  303. solara/website/pages/documentation/components/lab/confirmation_dialog.py +55 -0
  304. solara/website/pages/documentation/components/lab/cookies_headers.py +48 -0
  305. solara/website/pages/documentation/components/lab/input_date.py +20 -0
  306. solara/website/pages/documentation/components/lab/menu.py +22 -0
  307. solara/website/pages/documentation/components/lab/tab.py +25 -0
  308. solara/website/pages/documentation/components/lab/tabs.py +45 -0
  309. solara/website/pages/documentation/components/lab/task.py +11 -0
  310. solara/website/pages/documentation/components/lab/theming.py +72 -0
  311. solara/website/pages/documentation/components/lab/use_task.py +11 -0
  312. solara/website/pages/documentation/components/layout/__init__.py +9 -0
  313. solara/website/pages/documentation/components/layout/app_bar.py +16 -0
  314. solara/website/pages/documentation/components/layout/app_bar_title.py +16 -0
  315. solara/website/pages/documentation/components/layout/app_layout.py +24 -0
  316. solara/website/pages/documentation/components/layout/card.py +15 -0
  317. solara/website/pages/documentation/components/layout/card_actions.py +16 -0
  318. solara/website/pages/documentation/components/layout/column.py +30 -0
  319. solara/website/pages/documentation/components/layout/columns.py +27 -0
  320. solara/website/pages/documentation/components/layout/columns_responsive.py +68 -0
  321. solara/website/pages/documentation/components/layout/griddraggable.py +62 -0
  322. solara/website/pages/documentation/components/layout/gridfixed.py +21 -0
  323. solara/website/pages/documentation/components/layout/hbox.py +18 -0
  324. solara/website/pages/documentation/components/layout/row.py +30 -0
  325. solara/website/pages/documentation/components/layout/sidebar.py +24 -0
  326. solara/website/pages/documentation/components/layout/vbox.py +19 -0
  327. solara/website/pages/documentation/components/output/__init__.py +9 -0
  328. solara/website/pages/documentation/components/output/file_download.py +11 -0
  329. solara/website/pages/documentation/components/output/html.py +21 -0
  330. solara/website/pages/documentation/components/output/image.py +11 -0
  331. solara/website/pages/documentation/components/output/markdown.py +57 -0
  332. solara/website/pages/documentation/components/output/markdown_editor.py +51 -0
  333. solara/website/pages/documentation/components/output/sql_code.py +85 -0
  334. solara/website/pages/documentation/components/output/tooltip.py +11 -0
  335. solara/website/pages/documentation/components/page/__init__.py +9 -0
  336. solara/website/pages/documentation/components/page/head.py +18 -0
  337. solara/website/pages/documentation/components/page/title.py +27 -0
  338. solara/website/pages/documentation/components/status/__init__.py +9 -0
  339. solara/website/pages/documentation/components/status/error.py +40 -0
  340. solara/website/pages/documentation/components/status/info.py +40 -0
  341. solara/website/pages/documentation/components/status/progress.py +10 -0
  342. solara/website/pages/documentation/components/status/spinner.py +11 -0
  343. solara/website/pages/documentation/components/status/success.py +40 -0
  344. solara/website/pages/documentation/components/status/warning.py +47 -0
  345. solara/website/pages/documentation/components/viz/__init__.py +9 -0
  346. solara/website/pages/documentation/components/viz/altair.py +42 -0
  347. solara/website/pages/documentation/components/viz/echarts.py +75 -0
  348. solara/website/pages/documentation/components/viz/matplotlib.py +30 -0
  349. solara/website/pages/documentation/components/viz/plotly.py +63 -0
  350. solara/website/pages/documentation/components/viz/plotly_express.py +41 -0
  351. solara/website/pages/documentation/examples/__init__.py +52 -0
  352. solara/website/pages/documentation/examples/ai/__init__.py +11 -0
  353. solara/website/pages/documentation/examples/ai/chatbot.py +95 -0
  354. solara/website/pages/documentation/examples/ai/tokenizer.py +107 -0
  355. solara/website/pages/documentation/examples/basics/__init__.py +10 -0
  356. solara/website/pages/documentation/examples/basics/sine.py +28 -0
  357. solara/website/pages/documentation/examples/fullscreen/__init__.py +10 -0
  358. solara/website/pages/documentation/examples/fullscreen/authorization.py +3 -0
  359. solara/website/pages/documentation/examples/fullscreen/layout_demo.py +3 -0
  360. solara/website/pages/documentation/examples/fullscreen/multipage.py +3 -0
  361. solara/website/pages/documentation/examples/fullscreen/scatter.py +3 -0
  362. solara/website/pages/documentation/examples/fullscreen/scrolling.py +3 -0
  363. solara/website/pages/documentation/examples/fullscreen/tutorial_streamlit.py +3 -0
  364. solara/website/pages/documentation/examples/general/__init__.py +10 -0
  365. solara/website/pages/documentation/examples/general/custom_storage.py +70 -0
  366. solara/website/pages/documentation/examples/general/deploy_model.py +115 -0
  367. solara/website/pages/documentation/examples/general/live_update.py +38 -0
  368. solara/website/pages/documentation/examples/general/login_oauth.py +81 -0
  369. solara/website/pages/documentation/examples/general/mycard.vue +58 -0
  370. solara/website/pages/documentation/examples/general/pokemon_search.py +51 -0
  371. solara/website/pages/documentation/examples/general/vue_component.py +50 -0
  372. solara/website/pages/documentation/examples/ipycanvas.py +49 -0
  373. solara/website/pages/documentation/examples/libraries/__init__.py +10 -0
  374. solara/website/pages/documentation/examples/libraries/altair.py +64 -0
  375. solara/website/pages/documentation/examples/libraries/bqplot.py +39 -0
  376. solara/website/pages/documentation/examples/libraries/ipyleaflet.py +33 -0
  377. solara/website/pages/documentation/examples/libraries/ipyleaflet_advanced.py +66 -0
  378. solara/website/pages/documentation/examples/utilities/__init__.py +10 -0
  379. solara/website/pages/documentation/examples/utilities/calculator.py +157 -0
  380. solara/website/pages/documentation/examples/utilities/countdown_timer.py +64 -0
  381. solara/website/pages/documentation/examples/utilities/todo.py +196 -0
  382. solara/website/pages/documentation/examples/visualization/__init__.py +6 -0
  383. solara/website/pages/documentation/examples/visualization/annotator.py +69 -0
  384. solara/website/pages/documentation/examples/visualization/linked_views.py +84 -0
  385. solara/website/pages/documentation/examples/visualization/plotly.py +44 -0
  386. solara/website/pages/documentation/faq/__init__.py +12 -0
  387. solara/website/pages/documentation/faq/content/99-faq.md +76 -0
  388. solara/website/pages/documentation/getting_started/__init__.py +9 -0
  389. solara/website/pages/documentation/getting_started/content/00-quickstart.md +89 -0
  390. solara/website/pages/documentation/getting_started/content/01-introduction.md +125 -0
  391. solara/website/pages/documentation/getting_started/content/02-installing.md +134 -0
  392. solara/website/pages/documentation/getting_started/content/04-tutorials/00-overview.md +14 -0
  393. solara/website/pages/documentation/getting_started/content/04-tutorials/10_data_science.py +13 -0
  394. solara/website/pages/documentation/getting_started/content/04-tutorials/20-web-app.md +89 -0
  395. solara/website/pages/documentation/getting_started/content/04-tutorials/30-ipywidgets.md +124 -0
  396. solara/website/pages/documentation/getting_started/content/04-tutorials/40-streamlit.md +146 -0
  397. solara/website/pages/documentation/getting_started/content/04-tutorials/50-dash.md +144 -0
  398. solara/website/pages/documentation/getting_started/content/04-tutorials/60-jupyter-dashboard-part1.py +64 -0
  399. solara/website/pages/documentation/getting_started/content/04-tutorials/SF_crime_sample.csv.gz +0 -0
  400. solara/website/pages/documentation/getting_started/content/04-tutorials/_data_science.ipynb +445 -0
  401. solara/website/pages/documentation/getting_started/content/04-tutorials/_jupyter_dashboard_1.ipynb +1000 -0
  402. solara/website/pages/documentation/getting_started/content/05-fundamentals/00-overview.md +11 -0
  403. solara/website/pages/documentation/getting_started/content/05-fundamentals/10-components.md +223 -0
  404. solara/website/pages/documentation/getting_started/content/05-fundamentals/50-state-management.md +88 -0
  405. solara/website/pages/documentation/getting_started/content/07-deploying/00-overview.md +7 -0
  406. solara/website/pages/documentation/getting_started/content/07-deploying/10-self-hosted.md +273 -0
  407. solara/website/pages/documentation/getting_started/content/07-deploying/20-cloud-hosted.md +80 -0
  408. solara/website/pages/documentation/getting_started/content/80-what-is-lab.md +7 -0
  409. solara/website/pages/documentation/getting_started/content/90-troubleshoot.md +26 -0
  410. solara/website/pages/docutils.py +38 -0
  411. solara/website/pages/showcase/__init__.py +105 -0
  412. solara/website/pages/showcase/domino_code_assist.py +60 -0
  413. solara/website/pages/showcase/planeto_tessa.py +19 -0
  414. solara/website/pages/showcase/solara_dev.py +54 -0
  415. solara/website/pages/showcase/solarathon_2023_team_2.py +22 -0
  416. solara/website/pages/showcase/solarathon_2023_team_4.py +22 -0
  417. solara/website/pages/showcase/solarathon_2023_team_5.py +23 -0
  418. solara/website/pages/showcase/solarathon_2023_team_6.py +34 -0
  419. solara/website/pages/showcase/wanderlust.py +27 -0
  420. solara/website/public/beach.jpeg +0 -0
  421. solara/website/public/logo.svg +6 -0
  422. solara/website/public/social/discord.svg +1 -0
  423. solara/website/public/social/github.svg +1 -0
  424. solara/website/public/social/twitter.svg +3 -0
  425. solara/website/public/success.html +25 -0
  426. solara/website/templates/index.html.j2 +117 -0
  427. solara/website/utils.py +51 -0
  428. solara/widgets/__init__.py +1 -0
  429. solara/widgets/vue/gridlayout.vue +110 -0
  430. solara/widgets/vue/html.vue +4 -0
  431. solara/widgets/vue/navigator.vue +104 -0
  432. solara/widgets/vue/vegalite.vue +115 -0
  433. solara/widgets/widgets.py +66 -0
  434. solara_ui-1.31.0.data/data/etc/jupyter/jupyter_notebook_config.d/solara.json +7 -0
  435. solara_ui-1.31.0.data/data/etc/jupyter/jupyter_server_config.d/solara.json +7 -0
  436. solara_ui-1.31.0.dist-info/METADATA +158 -0
  437. solara_ui-1.31.0.dist-info/RECORD +439 -0
  438. solara_ui-1.31.0.dist-info/WHEEL +5 -0
  439. solara_ui-1.31.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,182 @@
1
+ import os
2
+ from os.path import isfile, join
3
+ from pathlib import Path
4
+ from typing import Callable, Dict, List, Optional, Union, cast
5
+
6
+ import humanize
7
+ import ipyvuetify as vy
8
+ import traitlets
9
+
10
+ import solara
11
+ from solara.components import Div
12
+
13
+
14
+ def list_dir(path, filter: Callable[[Path], bool] = lambda x: True, directory_first: bool = False) -> List[dict]:
15
+ def mk_item(n):
16
+ full_path = join(path, n)
17
+ is_file = isfile(full_path)
18
+ return {"name": n, "is_file": is_file, "size": humanize.naturalsize(os.stat(full_path).st_size) if is_file else None}
19
+
20
+ files = [mk_item(k) for k in os.listdir(path) if not k.startswith(".") if filter(Path(path) / k)]
21
+ sorted_files = sorted(files, key=lambda item: (item["is_file"] == directory_first, item["name"].lower()))
22
+
23
+ return sorted_files
24
+
25
+
26
+ class FileListWidget(vy.VuetifyTemplate):
27
+ template_file = (__file__, "file_list_widget.vue")
28
+
29
+ files = traitlets.List(cast(List[Dict], [])).tag(sync=True)
30
+ clicked = traitlets.Dict(allow_none=True, default_value=None).tag(sync=True)
31
+ double_clicked = traitlets.Dict(allow_none=True, default_value=None).tag(sync=True)
32
+ scroll_pos = traitlets.Int(allow_none=True).tag(sync=True)
33
+
34
+ def test_click(self, path: Union[Path, str], double_click=False):
35
+ """Simulate a click or double click at the Python side"""
36
+ matches = [k for k in self.files if k["name"] == str(path)]
37
+ if len(matches) == 0:
38
+ names = [k["name"] for k in self.files]
39
+ raise NameError(f"Could not find {path}, possible filenames: {names}")
40
+ item = matches[0]
41
+ if double_click:
42
+ self.double_clicked = item
43
+ else:
44
+ self.clicked = item
45
+
46
+ def __contains__(self, name):
47
+ """Test if filename/directory name is in the current directory."""
48
+ return name in [k["name"] for k in self.files]
49
+
50
+
51
+ @solara.component
52
+ def FileBrowser(
53
+ directory: Union[None, str, Path, solara.Reactive[Path]] = None,
54
+ on_directory_change: Callable[[Path], None] = None,
55
+ on_path_select: Callable[[Optional[Path]], None] = None,
56
+ on_file_open: Callable[[Path], None] = None,
57
+ filter: Callable[[Path], bool] = lambda x: True,
58
+ directory_first: bool = False,
59
+ on_file_name: Callable[[str], None] = None,
60
+ start_directory=None,
61
+ can_select=False,
62
+ ):
63
+ """File/directory browser at the server side.
64
+
65
+ There are two modes possible
66
+
67
+ * `can_select=False`
68
+ * `on_file_open`: Triggered when **single** clicking a file or directory.
69
+ * `on_path_select`: Never triggered
70
+ * `on_directory_change`: Triggered when clicking a directory
71
+ * `can_select=True`
72
+ * `on_file_open`: Triggered when **double** clicking a file or directory.
73
+ * `on_path_select`: Triggered when clicking a file or directory
74
+ * `on_directory_change`: Triggered when double clicking a directory
75
+
76
+ ## Arguments
77
+
78
+ * `directory`: The directory to start in. If `None` the current working directory is used.
79
+ * `on_directory_change`: Depends on mode, see above.
80
+ * `on_path_select`: Depends on mode, see above.
81
+ * `on_file_open`: Depends on mode, see above.
82
+ * `filter`: A function that takes a `Path` and returns `True` if the file/directory should be shown.
83
+ * `directory_first`: If `True` directories are shown before files. Default: `False`.
84
+ * `on_file_name`: (deprecated) Use on_file_open instead.
85
+ * `start_directory`: (deprecated) Use directory instead.
86
+ """
87
+ if start_directory is not None:
88
+ directory = start_directory # pragma: no cover
89
+ if directory is None:
90
+ directory = os.getcwd() # pragma: no cover
91
+ if isinstance(directory, str):
92
+ directory = Path(directory)
93
+ current_dir = solara.use_reactive(directory)
94
+ selected, set_selected = solara.use_state(None)
95
+ double_clicked, set_double_clicked = solara.use_state(None)
96
+ warning, set_warning = solara.use_state(cast(Optional[str], None))
97
+ scroll_pos_stack, set_scroll_pos_stack = solara.use_state(cast(List[int], []))
98
+ scroll_pos, set_scroll_pos = solara.use_state(0)
99
+ selected, set_selected = solara.use_state(None)
100
+
101
+ def change_dir(new_dir: str):
102
+ if os.access(new_dir, os.R_OK):
103
+ current_dir.value = Path(new_dir)
104
+ if on_directory_change:
105
+ on_directory_change(Path(new_dir))
106
+ set_warning(None)
107
+ return True
108
+ else:
109
+ set_warning(f"[no read access to {new_dir}]")
110
+
111
+ def on_item(item, double_click):
112
+ if item is None:
113
+ if can_select and on_path_select:
114
+ on_path_select(None)
115
+ return
116
+ if item["name"] == "..":
117
+ current_dir_str = str(current_dir.value)
118
+ new_dir = current_dir_str[: current_dir_str.rfind(os.path.sep)]
119
+ action_change_directory = (can_select and double_click) or (not can_select and not double_click)
120
+ if action_change_directory and change_dir(new_dir):
121
+ if scroll_pos_stack:
122
+ last_pos = scroll_pos_stack[-1]
123
+ set_scroll_pos_stack(scroll_pos_stack[:-1])
124
+ set_scroll_pos(last_pos)
125
+ set_selected(None)
126
+ set_double_clicked(None)
127
+ if on_path_select and can_select:
128
+ on_path_select(None)
129
+ if can_select and not double_click:
130
+ if on_path_select:
131
+ on_path_select(Path(new_dir))
132
+ return
133
+
134
+ path = os.path.join(current_dir.value, item["name"])
135
+ is_file = item["is_file"]
136
+ if (can_select and double_click) or (not can_select and not double_click):
137
+ if is_file:
138
+ if on_file_open:
139
+ on_file_open(Path(path))
140
+ if on_file_name is not None:
141
+ on_file_name(path)
142
+ else:
143
+ if change_dir(path):
144
+ set_scroll_pos_stack(scroll_pos_stack + [scroll_pos])
145
+ set_scroll_pos(0)
146
+ set_selected(None)
147
+ set_double_clicked(None)
148
+ if on_path_select and can_select:
149
+ on_path_select(None)
150
+ elif can_select and not double_click:
151
+ if on_path_select:
152
+ on_path_select(Path(path))
153
+ else: # not can_select and double_click is ignored
154
+ raise RuntimeError("Combination should not happen") # pragma: no cover
155
+
156
+ def on_click(item):
157
+ set_selected(item)
158
+ on_item(item, False)
159
+
160
+ def on_double_click(item):
161
+ set_double_clicked(item)
162
+ if can_select:
163
+ on_item(item, True)
164
+ # otherwise we can ignore it, single click will handle it
165
+
166
+ files = [{"name": "..", "is_file": False}] + list_dir(current_dir.value, filter=filter, directory_first=directory_first)
167
+ with Div(class_="solara-file-browser") as main:
168
+ Div(children=[str(current_dir.value)])
169
+ FileListWidget.element(
170
+ files=files,
171
+ selected=selected,
172
+ clicked=selected,
173
+ on_clicked=on_click,
174
+ double_clicked=double_clicked,
175
+ on_double_clicked=on_double_click,
176
+ scroll_pos=scroll_pos,
177
+ on_scroll_pos=set_scroll_pos,
178
+ ).key("FileList")
179
+ if warning:
180
+ Div(style_="font-weight: bold; color: red", children=[warning])
181
+
182
+ return main
@@ -0,0 +1,199 @@
1
+ from pathlib import Path
2
+ from typing import BinaryIO, Callable, List, Optional, Union, cast
3
+
4
+ import ipyvuetify as vy
5
+ import ipywidgets as widgets
6
+ import traitlets
7
+
8
+ import solara
9
+
10
+
11
+ class FileDownloadWidget(vy.VuetifyTemplate):
12
+ template_file = (__file__, "download.vue")
13
+ children = traitlets.List(cast(List[solara.Element], [])).tag(sync=True, **widgets.widget_serialization)
14
+ filename = traitlets.Unicode().tag(sync=True)
15
+ bytes = traitlets.Bytes(None, allow_none=True).tag(sync=True)
16
+ mime_type = traitlets.Unicode("application/octet-stream").tag(sync=True)
17
+ request_download = traitlets.Bool(False).tag(sync=True)
18
+
19
+
20
+ @solara.component
21
+ def FileDownload(
22
+ data: Union[str, bytes, BinaryIO, Callable[[], Union[str, bytes, BinaryIO]]],
23
+ filename: Optional[str] = None,
24
+ label: Optional[str] = None,
25
+ icon_name: Optional[str] = "mdi-cloud-download-outline",
26
+ close_file: bool = True,
27
+ mime_type: str = "application/octet-stream",
28
+ string_encoding: str = "utf-8",
29
+ children=[],
30
+ ):
31
+ """Download a file or data.
32
+
33
+ ## Simple usage
34
+
35
+ By default, if no children are provided, a button is created with the label "Download: {filename}".
36
+
37
+ ```solara
38
+ import solara
39
+
40
+ data = "This is the content of the file"
41
+
42
+ @solara.component
43
+ def Page():
44
+ solara.FileDownload(data, filename="solara-download.txt", label="Download file")
45
+ ```
46
+
47
+ ## Advanced usage
48
+
49
+ If children are provided, they are displayed instead of the button. The children can be any solara component,
50
+ including a button, markdown text, or an image.
51
+
52
+ ```solara
53
+ import solara
54
+
55
+ data = "This is the content of the file"
56
+
57
+ @solara.component
58
+ def Page():
59
+ with solara.FileDownload(data, "solara-download-2.txt"):
60
+ solara.Markdown("Any text, or even an image")
61
+ solara.Image("https://solara.dev/static/public/beach.jpeg", width="200px")
62
+ ```
63
+
64
+ ## Custom button
65
+
66
+ If children are provided, they are displayed instead of the button. The children can be any solara component,
67
+ including a button, markdown text, or an image.
68
+
69
+ ```solara
70
+ import solara
71
+
72
+ data = "This is the content of the file"
73
+
74
+ @solara.component
75
+ def Page():
76
+ with solara.FileDownload(data, "solara-download-2.txt"):
77
+ solara.Button("Custom download button", icon_name="mdi-cloud-download-outline", color="primary")
78
+ ```
79
+
80
+ ## Usage with file
81
+
82
+ A file object can be used as data. The file will be closed after downloading by default.
83
+
84
+ ```solara
85
+ import solara
86
+ import pandas as pd
87
+
88
+ df = pd.DataFrame({"id": [1, 2, 3], "name": ["John", "Mary", "Bob"]})
89
+
90
+ @solara.component
91
+ def Page():
92
+ file_object = df.to_csv(index=False)
93
+ solara.FileDownload(file_object, "users.csv", mime_type="application/vnd.ms-excel")
94
+ ```
95
+
96
+ If a file like object is used, we try to base the filename on the file object.
97
+ ```solara
98
+ import solara
99
+ import solara.website.pages
100
+ import os
101
+
102
+ filename = os.path.dirname(solara.website.__file__) + "/public/beach.jpeg"
103
+
104
+ @solara.component
105
+ def Page():
106
+ # only open the file once by using use_memo
107
+ file_object = solara.use_memo(lambda: open(filename, "rb"), [])
108
+ # no filename is provided, but we can extract it from the file object
109
+ solara.FileDownload(file_object, mime_type="image/jpeg", close_file=False)
110
+ ```
111
+
112
+ ## Lazy reading
113
+
114
+ Not only is the data lazily uploaded to the browser, but also the data is only read when the download is requested.
115
+ This happens for files by default, but can also be used by passing in a callback function.
116
+
117
+ ```solara
118
+ import solara
119
+ import time
120
+
121
+ @solara.component
122
+ def Page():
123
+ def get_data():
124
+ # I run in a thread, so I can do some heavy processing
125
+ time.sleep(3)
126
+ # I only get called when the download is requested
127
+ return "This is the content of the file"
128
+ solara.FileDownload(get_data, "solara-lazy-download.txt")
129
+ ```
130
+
131
+ ## Arguments
132
+
133
+ * `data`: The data to download. Can be a string, bytes, or a file like object, or a function that returns one of these.
134
+ * `filename`: The name of the file the user will see as default when downloading (default name is "solara-download.dat").
135
+ If a file object is provided, the filename will be extracted from the file object if possible.
136
+ * `label`: The label of the button. If not provided, the label will be "Download: {filename}".
137
+ - `icon_name`: The name of the icon to display on the button ([Overview of available icons](https://pictogrammers.github.io/@mdi/font/4.9.95/)).
138
+ * `close_file`: If a file object is provided, close the file after downloading (default True).
139
+ * `mime_type`: The mime type of the file. If not provided, the mime type will be "application/octet-stream",
140
+ For instance setting it to "application/vnd.ms-excel" will allow the user OS to directly open the
141
+ file into Excel.
142
+ * `string_encoding`: The encoding to use when converting a string to bytes (default "utf-8").
143
+
144
+ ## Note on file size
145
+
146
+ Note that the data will be kept in memory when downloading.
147
+ If the file is large (>10 MB), and when using [Solara server](/documentation/advanced/understanding/solara-server), we recommend using the
148
+ [static files directory](/documentation/advanced/reference/static-files) instead.
149
+
150
+ """
151
+ request_download, set_request_download = solara.use_state(False)
152
+
153
+ # if the data changes, we 'reset'
154
+ def reset():
155
+ nonlocal request_download
156
+ request_download = False
157
+ set_request_download(False)
158
+
159
+ solara.use_memo(reset, [data])
160
+
161
+ # we only upload to the frontend if clicked
162
+ def get_data() -> Optional[bytes]:
163
+ if request_download:
164
+ if callable(data):
165
+ data_non_lazy = data()
166
+ else:
167
+ data_non_lazy = data
168
+ if hasattr(data_non_lazy, "read"):
169
+ if hasattr(data_non_lazy, "seek"):
170
+ if hasattr(data_non_lazy, "tell") and data_non_lazy.tell() != 0:
171
+ data_non_lazy.seek(0)
172
+ content = data_non_lazy.read() # type: ignore
173
+ if close_file:
174
+ data_non_lazy.close() # type: ignore
175
+ return content
176
+ elif isinstance(data_non_lazy, str):
177
+ return data_non_lazy.encode(string_encoding)
178
+ else:
179
+ return cast(bytes, data_non_lazy)
180
+ return None
181
+
182
+ bytes_result: solara.Result[Optional[bytes]] = solara.use_thread(get_data, dependencies=[request_download, data])
183
+ if filename is None and hasattr(data, "name"):
184
+ try:
185
+ filename = Path(data.name).name # type: ignore
186
+ except Exception:
187
+ pass
188
+ filename = filename or "solara-download.dat"
189
+ label = label or ("Download: " + filename)
190
+ FileDownloadWidget.element(
191
+ filename=filename,
192
+ bytes=bytes_result.value if bytes_result.state == solara.ResultState.FINISHED else None,
193
+ request_download=request_download,
194
+ on_request_download=set_request_download,
195
+ children=children or [solara.Button(label, loading=bytes_result.state == solara.ResultState.RUNNING, icon_name=icon_name)],
196
+ mime_type=mime_type,
197
+ )
198
+ if bytes_result.state == solara.ResultState.ERROR and bytes_result.error:
199
+ raise bytes_result.error
@@ -0,0 +1,139 @@
1
+ import threading
2
+ import typing
3
+ from typing import Any, Callable, List, Optional, Union, cast
4
+
5
+ import traitlets
6
+ from ipyvue import Template
7
+ from ipyvuetify.extra import FileInput
8
+ from ipywidgets import widget_serialization
9
+ from typing_extensions import TypedDict
10
+
11
+ import solara
12
+ import solara.hooks as hooks
13
+
14
+
15
+ class FileInfo(TypedDict):
16
+ name: str
17
+ size: int
18
+ file_obj: typing.BinaryIO
19
+ data: Optional[bytes]
20
+
21
+
22
+ class FileDropZone(FileInput):
23
+ # override to narrow traitlet of FileInput
24
+ template = traitlets.Instance(Template).tag(sync=True, **widget_serialization)
25
+ template_file = (__file__, "file_drop.vue")
26
+ items = traitlets.List(default_value=cast(List[Any], [])).tag(sync=True)
27
+ label = traitlets.Unicode().tag(sync=True)
28
+ multiple = traitlets.Bool(True).tag(sync=True)
29
+
30
+
31
+ @solara.component
32
+ def _FileDrop(
33
+ label="Drop file(s) here",
34
+ on_total_progress: Optional[Callable[[float], None]] = None,
35
+ on_file: Optional[Callable[[Union[FileInfo, List[FileInfo]]], None]] = None,
36
+ lazy: bool = True,
37
+ multiple: bool = False,
38
+ ):
39
+ """Generic implementation used by FileDrop and FileDropMultiple.
40
+
41
+ If multiple=True, multiple files can be uploaded.
42
+ """
43
+
44
+ file_info, set_file_info = solara.use_state(None)
45
+ wired_files, set_wired_files = solara.use_state(cast(Optional[typing.List[FileInfo]], None))
46
+
47
+ file_drop = FileDropZone.element(label=label, on_total_progress=on_total_progress, on_file_info=set_file_info, multiple=multiple) # type: ignore
48
+
49
+ def wire_files():
50
+ if not file_info:
51
+ return
52
+
53
+ real = cast(FileDropZone, solara.get_widget(file_drop))
54
+
55
+ # workaround for @observe being cleared
56
+ real.version += 1
57
+ real.reset_stats()
58
+
59
+ set_wired_files(cast(typing.List[FileInfo], real.get_files()))
60
+
61
+ solara.use_side_effect(wire_files, [file_info])
62
+
63
+ def handle_file(cancel: threading.Event):
64
+ if not wired_files:
65
+ return
66
+ if on_file:
67
+ for i in range(len(wired_files)):
68
+ if not lazy:
69
+ wired_files[i]["data"] = wired_files[i]["file_obj"].read()
70
+ else:
71
+ wired_files[i]["data"] = None
72
+ if multiple:
73
+ on_file(wired_files)
74
+ else:
75
+ on_file(wired_files[0])
76
+
77
+ result: solara.Result = hooks.use_thread(handle_file, [wired_files])
78
+ if result.error:
79
+ raise result.error
80
+
81
+ return file_drop
82
+
83
+
84
+ @solara.component
85
+ def FileDrop(
86
+ label="Drop file here",
87
+ on_total_progress: Optional[Callable[[float], None]] = None,
88
+ on_file: Optional[Callable[[FileInfo], None]] = None,
89
+ lazy: bool = True,
90
+ ):
91
+ """Region a user can drop a file into for file uploading.
92
+
93
+ If lazy=True, no file content will be loaded into memory,
94
+ nor will any data be transferred by default.
95
+ If lazy=False, file content will be loaded into memory and passed to the `on_file` callback via the `FileInfo.data` attribute.
96
+
97
+
98
+ A file object is of the following argument type:
99
+ ```python
100
+ class FileInfo(typing.TypedDict):
101
+ name: str # file name
102
+ size: int # file size in bytes
103
+ file_obj: typing.BinaryIO
104
+ data: Optional[bytes]: bytes # only present if lazy=False
105
+ ```
106
+
107
+
108
+ ## Arguments
109
+ * `on_total_progress`: Will be called with the progress in % of the file upload.
110
+ * `on_file`: Will be called with a `FileInfo` object, which contains the file `.name`, `.length` and a `.file_obj` object.
111
+ * `lazy`: Whether to load the file contents into memory or not. If `False`,
112
+ the file contents will be loaded into memory via the `.data` attribute of file object(s).
113
+
114
+ """
115
+
116
+ return _FileDrop(label=label, on_total_progress=on_total_progress, on_file=on_file, lazy=lazy, multiple=False)
117
+
118
+
119
+ @solara.component
120
+ def FileDropMultiple(
121
+ label="Drop files here",
122
+ on_total_progress: Optional[Callable[[float], None]] = None,
123
+ on_file: Optional[Callable[[List[FileInfo]], None]] = None,
124
+ lazy: bool = True,
125
+ ):
126
+ """Region a user can drop multiple files into for file uploading.
127
+
128
+ Almost identical to `FileDrop` except that multiple files can be dropped and `on_file` is called
129
+ with a list of `FileInfo` objects.
130
+
131
+ ## Arguments
132
+ * `on_total_progress`: Will be called with the progress in % of the file(s) upload.
133
+ * `on_file`: Will be called with a `List[FileInfo]`.
134
+ Each `FileInfo` contains the file `.name`, `.length`, `.file_obj` object, and `.data` attributes.
135
+ * `lazy`: Whether to load the file contents into memory or not.
136
+
137
+ """
138
+
139
+ return _FileDrop(label=label, on_total_progress=on_total_progress, on_file=on_file, lazy=lazy, multiple=True)
@@ -0,0 +1,83 @@
1
+ <template>
2
+ <div ref="dropzone" class="solara-file-drop" effectAllowed="move">
3
+ <template v-if="file_info && file_info.length > 0">
4
+ <template v-if="multiple">
5
+ <div v-for="file in file_info">
6
+ {{ file.name }}
7
+ </div>
8
+ </template>
9
+ <template v-else>
10
+ {{ file_info[0].name }}
11
+ </template>
12
+ </template>
13
+ <template v-else>
14
+ {{ label }}
15
+ </template>
16
+ </div>
17
+ </template>
18
+
19
+ <script>
20
+ module.exports = {
21
+ mounted() {
22
+ this.chunk_size = 2 * 1024 * 1024;
23
+ this.$refs.dropzone.addEventListener('dragover', event => {
24
+ event.preventDefault();
25
+ });
26
+
27
+ this.$refs.dropzone.addEventListener('drop', async event => {
28
+ event.preventDefault();
29
+ const items = await Promise.all([...event.dataTransfer.items]);
30
+ const files = items.map(i => i.webkitGetAsEntry())
31
+ const fileHolders = files.filter(f => f.isFile)
32
+ const nativeFilesPromises = fileHolders.map(fileHolder => new Promise((rs, rj) => fileHolder.file(rs, rj)))
33
+ const nativeFiles = await Promise.all(nativeFilesPromises)
34
+
35
+ this.native_file_info = nativeFiles
36
+ this.file_info = this.native_file_info.map(
37
+ ({name, size}) => ({
38
+ name,
39
+ isFile: true,
40
+ size,
41
+ }));
42
+ });
43
+ },
44
+ methods: {
45
+ jupyter_clear() {
46
+ this.native_file_info = [];
47
+ this.file_info = [];
48
+ },
49
+ jupyter_read(chunk) {
50
+ const {id, file_index, offset, length} = chunk;
51
+ let to_do = length;
52
+ let sub_offset = offset;
53
+
54
+ (async () => {
55
+ while (to_do > 0) {
56
+ console.log(this.chunk_size, to_do);
57
+ const sub_length = Math.min(to_do, this.chunk_size);
58
+
59
+ const file = this.native_file_info[file_index];
60
+ const blob = file.slice(sub_offset, sub_offset + sub_length);
61
+ const buff = await blob.arrayBuffer();
62
+
63
+ const msg = {id, file_index, offset: sub_offset, length: sub_length}
64
+ this.upload(msg, [buff]);
65
+
66
+ to_do -= sub_length
67
+ sub_offset += sub_length
68
+ }
69
+ })();
70
+ }
71
+ }
72
+ }
73
+ </script>
74
+
75
+ <style id="solara-file-drop">
76
+ .solara-file-drop {
77
+ height: 100px;
78
+ border: 1px dashed gray;
79
+ margin: 8px 0;
80
+ padding: 8px;
81
+ overflow: auto;
82
+ }
83
+ </style>
@@ -0,0 +1,78 @@
1
+ <template>
2
+ <v-sheet class="solara-file-list" ref="scrollpane"
3
+ @click="clicked = null"
4
+ >
5
+ <v-list
6
+ @click="clicked = null"
7
+ >
8
+ <v-list-item
9
+ v-for="{name, is_file, size} in files"
10
+ :key="name + '|' + is_file"
11
+ @click.stop="clicked = { name, is_file }"
12
+ @dblclick="double_clicked = { name, is_file }"
13
+ :class="(clicked && clicked.name == name) ? 'solara-file-list-selected': ''"
14
+ >
15
+ <v-list-item-icon>
16
+ <v-icon>{{ name === '..' ? 'mdi-keyboard-backspace' : is_file ? 'mdi-file-document' : 'mdi-folder' }}</v-icon>
17
+ </v-list-item-icon>
18
+
19
+ <v-list-item-content>
20
+ <v-list-item-title :class="'solara-file-list-' + (is_file ? 'file' : 'dir')">
21
+ {{ name }}<span v-if="size"> - {{ size }}</span>
22
+ </v-list-item-title>
23
+ </v-list-item-content>
24
+ </v-list-item>
25
+ </v-list>
26
+ </v-sheet>
27
+ </template>
28
+
29
+ <script>
30
+ module.exports = {
31
+ mounted() {
32
+ const element = this.$refs.scrollpane.$el
33
+ element.scrollTop = this.scroll_pos
34
+
35
+ this._scrollListener = _.debounce((e) => {
36
+ this.scroll_pos = Math.round(element.scrollTop)
37
+ }, 50)
38
+ element.addEventListener('scroll', this._scrollListener)
39
+ },
40
+ watch: {
41
+ scroll_pos(v) {
42
+ this.$nextTick(() => this.$refs.scrollpane.$el.scrollTop = v);
43
+ }
44
+ }
45
+ }
46
+ </script>
47
+
48
+ <style id="solara-file-list">
49
+ .solara-file-list {
50
+ height: 400px;
51
+ overflow: auto;
52
+ }
53
+
54
+ .solara-file-list-dir {
55
+ font-weight: bold;
56
+ }
57
+
58
+ .solara-file-list-selected {
59
+ background-color: #3333;
60
+
61
+ }
62
+
63
+ .solara-file-list .v-list-item__icon,
64
+ .solara-file-list .v-list-item__list {
65
+ margin-top: 0;
66
+ margin-bottom: 0;
67
+ }
68
+
69
+ .v-application--is-ltr .solara-file-list .v-list-item__icon {
70
+ margin-right: 8px;
71
+ }
72
+
73
+ .solara-file-list .v-list-item {
74
+ height: 28px;
75
+ min-height: 0;
76
+ padding-left: 0;
77
+ }
78
+ </style>