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,203 @@
1
+ import uuid
2
+ from typing import Callable, Dict, List, Optional, Union
3
+
4
+ from typing_extensions import Literal
5
+
6
+ import solara
7
+ from solara.components.input import use_change
8
+
9
+
10
+ @solara.component
11
+ def ChatBox(
12
+ children: List[solara.Element] = [],
13
+ style: Optional[Union[str, Dict[str, str]]] = None,
14
+ classes: List[str] = [],
15
+ ):
16
+ """
17
+ The ChatBox component is a container for ChatMessage components.
18
+ Its primary use is to ensure the proper ordering of messages,
19
+ using `flex-direction: column-reverse` together with `reversed(messages)`.
20
+
21
+ # Arguments
22
+
23
+ * `children`: A list of child components.
24
+ * `style`: CSS styles to apply to the component. Either a string or a dictionary.
25
+ * `classes`: A list of CSS classes to apply to the component.
26
+ """
27
+ style_flat = solara.util._flatten_style(style)
28
+ if "flex-grow" not in style_flat:
29
+ style_flat += " flex-grow: 1;"
30
+ if "flex-direction" not in style_flat:
31
+ style_flat += " flex-direction: column-reverse;"
32
+ if "overflow-y" not in style_flat:
33
+ style_flat += " overflow-y: auto;"
34
+
35
+ classes += ["chat-box"]
36
+ with solara.Column(
37
+ style=style_flat,
38
+ classes=classes,
39
+ ):
40
+ for child in list(reversed(children)):
41
+ solara.display(child)
42
+
43
+
44
+ @solara.component
45
+ def ChatInput(
46
+ send_callback: Optional[Callable] = None,
47
+ disabled: bool = False,
48
+ style: Optional[Union[str, Dict[str, str]]] = None,
49
+ classes: List[str] = [],
50
+ ):
51
+ """
52
+ The ChatInput component renders a text input together with a send button.
53
+
54
+ # Arguments
55
+
56
+ * `send_callback`: A callback function for when the user presses enter or clicks the send button.
57
+ * `disabled`: Whether the input should be disabled. Useful for disabling sending further messages while a chatbot is replying,
58
+ among other things.
59
+ * `style`: CSS styles to apply to the component. Either a string or a dictionary. These styles are applied to the container component.
60
+ * `classes`: A list of CSS classes to apply to the component. Also applied to the container.
61
+ """
62
+ message, set_message = solara.use_state("") # type: ignore
63
+ style_flat = solara.util._flatten_style(style)
64
+
65
+ if "align-items" not in style_flat:
66
+ style_flat += " align-items: center;"
67
+
68
+ with solara.Row(style=style_flat, classes=classes):
69
+
70
+ def send(*ignore_args):
71
+ if message != "" and send_callback is not None:
72
+ send_callback(message)
73
+ set_message("")
74
+
75
+ message_input = solara.v.TextField(
76
+ label="Type a message...",
77
+ v_model=message,
78
+ on_v_model=set_message,
79
+ rounded=True,
80
+ filled=True,
81
+ hide_details=True,
82
+ style_="flex-grow: 1;",
83
+ disabled=disabled,
84
+ )
85
+
86
+ use_change(message_input, send, update_events=["keyup.enter"])
87
+
88
+ button = solara.v.Btn(color="primary", icon=True, children=[solara.v.Icon(children=["mdi-send"])], disabled=message == "")
89
+
90
+ use_change(button, send, update_events=["click"])
91
+
92
+
93
+ @solara.component
94
+ def ChatMessage(
95
+ children: Union[List[solara.Element], str],
96
+ user: bool = False,
97
+ avatar: Union[solara.Element, str, Literal[False], None] = None,
98
+ name: Optional[str] = None,
99
+ color: Optional[str] = "rgba(0,0,0,.06)",
100
+ avatar_background_color: Optional[str] = None,
101
+ border_radius: Optional[str] = None,
102
+ notch: bool = False,
103
+ style: Optional[Union[str, Dict[str, str]]] = None,
104
+ classes: List[str] = [],
105
+ ):
106
+ """
107
+ The ChatMessage component renders a message. Messages with `user=True` are rendered on the right side of the screen,
108
+ all others on the left.
109
+
110
+ # Arguments
111
+
112
+ * `children`: A list of child components.
113
+ * `user`: Whether the message is from the current user or not.
114
+ * `avatar`: An avatar to display next to the message. Can be a string representation of a URL or Material design icon name,
115
+ a solara Element, False to disable avatars altogether, or None to display initials based on `name`.
116
+ * `name`: The name of the user who sent the message.
117
+ * `color`: The background color of the message. Defaults to `rgba(0,0,0,.06)`. Can be any valid CSS color.
118
+ * `avatar_background_color`: The background color of the avatar. Defaults to `color` if left as `None`.
119
+ * `border_radius`: Sets the roundness of the corners of the message. Defaults to `None`,
120
+ which applies the default border radius of a `solara.Column`, i.e. `4px`.
121
+ * `notch`: Whether to display a speech bubble style notch on the side of the message.
122
+ * `style`: CSS styles to apply to the component. Either a string or a dictionary. Applied to the container of the message.
123
+ * `classes`: A list of CSS classes to apply to the component. Applied to the same container.
124
+ """
125
+ style_flat = solara.util._flatten_style(style)
126
+
127
+ if "border-radius" not in style_flat:
128
+ style_flat += f" border-radius: {border_radius if border_radius is not None else ''};"
129
+ if f"border-top-{'right' if user else 'left'}-radius" not in style_flat:
130
+ style_flat += f" border-top-{'right' if user else 'left'}-radius: 0;"
131
+ if "padding" not in style_flat:
132
+ style_flat += " padding: .5em 1.5em;"
133
+
134
+ msg_uuid = solara.use_memo(lambda: str(uuid.uuid4()), dependencies=[])
135
+ with solara.Row(
136
+ justify="end" if user else "start",
137
+ style={"flex-direction": "row-reverse" if user else "row", "padding": "5px"},
138
+ ):
139
+ if avatar is not False:
140
+ with solara.v.Avatar(color=avatar_background_color if avatar_background_color is not None else color):
141
+ if avatar is None and name is not None:
142
+ initials = "".join([word[:1] for word in name.split(" ")])
143
+ solara.HTML(tag="span", unsafe_innerHTML=initials, classes=["headline"])
144
+ elif isinstance(avatar, solara.Element):
145
+ solara.display(avatar)
146
+ elif isinstance(avatar, str) and avatar.startswith("mdi-"):
147
+ solara.v.Icon(children=[avatar])
148
+ else:
149
+ solara.HTML(tag="img", attributes={"src": avatar, "width": "100%"})
150
+ classes_new = classes + ["chat-message-" + msg_uuid, "right" if user else "left"]
151
+ with solara.Column(
152
+ classes=classes_new,
153
+ gap=0,
154
+ style=style_flat,
155
+ ):
156
+ if name is not None:
157
+ solara.Text(name, style="font-weight: bold;", classes=["message-name", "right" if user else "left"])
158
+ for child in children:
159
+ if isinstance(child, solara.Element):
160
+ solara.display(child)
161
+ else:
162
+ solara.Markdown(child)
163
+ # we use the uuid to generate 'scoped' CSS, i.e. css that only applies to the component instance.
164
+ extra_styles = (
165
+ f""".chat-message-{msg_uuid}:before{{
166
+ content: '';
167
+ position: absolute;
168
+ width: 0;
169
+ height: 0;
170
+ border: 6px solid;
171
+ top: 0;
172
+ }}
173
+ .chat-message-{msg_uuid}.left:before{{
174
+ left: -12px;
175
+ border-color: var(--color) var(--color) transparent transparent;
176
+ }}
177
+ .chat-message-{msg_uuid}.right:before{{
178
+ right: -12px;
179
+ border-color: var(--color) transparent transparent var(--color);
180
+ }}"""
181
+ if notch
182
+ else ""
183
+ )
184
+ solara.Style(
185
+ f"""
186
+ .chat-message-{msg_uuid}{{
187
+ --color: {color};
188
+ max-width: 75%;
189
+ position: relative;
190
+ }}
191
+ .chat-message-{msg_uuid}.left{{
192
+ border-top-left-radius: 0;
193
+ background-color:var(--color);
194
+ { "margin-left: 10px !important;" if notch else ""}
195
+ }}
196
+ .chat-message-{msg_uuid}.right{{
197
+ border-top-right-radius: 0;
198
+ background-color:var(--color);
199
+ { "margin-right: 10px !important;" if notch else ""}
200
+ }}
201
+ {extra_styles}
202
+ """
203
+ )
@@ -0,0 +1,163 @@
1
+ from typing import Callable, List, Union, overload
2
+
3
+ import reacton.ipyvuetify as v
4
+
5
+ import solara
6
+
7
+
8
+ @overload
9
+ def ConfirmationDialog(
10
+ open: solara.Reactive[bool],
11
+ *,
12
+ on_close: Union[None, Callable[[], None]] = None,
13
+ content: Union[str, solara.Element] = "",
14
+ title: str = "Confirm action",
15
+ ok: Union[str, solara.Element] = "OK",
16
+ on_ok: Callable[[], None] = lambda: None,
17
+ cancel: Union[str, solara.Element] = "Cancel",
18
+ on_cancel: Callable[[], None] = lambda: None,
19
+ children: List[solara.Element] = [],
20
+ max_width: Union[int, str] = 500,
21
+ persistent: bool = False,
22
+ ): ...
23
+
24
+
25
+ # when open is a boolean, on_close should be given, otherwise a dialog can never be closed
26
+ # TODO: copy this pattern to many other components
27
+ @overload
28
+ def ConfirmationDialog(
29
+ open: bool,
30
+ *,
31
+ on_close: Callable[[], None],
32
+ content: Union[str, solara.Element] = "",
33
+ title: str = "Confirm action",
34
+ ok: Union[str, solara.Element] = "OK",
35
+ on_ok: Callable[[], None] = lambda: None,
36
+ cancel: Union[str, solara.Element] = "Cancel",
37
+ on_cancel: Callable[[], None] = lambda: None,
38
+ children: List[solara.Element] = [],
39
+ max_width: Union[int, str] = 500,
40
+ persistent: bool = False,
41
+ ): ...
42
+
43
+
44
+ @solara.component
45
+ def ConfirmationDialog(
46
+ open: Union[solara.Reactive[bool], bool],
47
+ *,
48
+ on_close: Union[None, Callable[[], None]] = None,
49
+ content: Union[str, solara.Element] = "",
50
+ title: str = "Confirm action",
51
+ ok: Union[str, solara.Element] = "OK",
52
+ on_ok: Callable[[], None] = lambda: None,
53
+ cancel: Union[str, solara.Element] = "Cancel",
54
+ on_cancel: Callable[[], None] = lambda: None,
55
+ children: List[solara.Element] = [],
56
+ max_width: Union[int, str] = 500,
57
+ persistent: bool = False,
58
+ ):
59
+ """A dialog used to confirm a user action.
60
+
61
+ (*Note: [This component is experimental and its API may change in the future](/documentation/getting_started/what-is-lab).*)
62
+
63
+ By default, has a title, a text explaining the
64
+ decision to be made, and two buttons "OK" and "Cancel".
65
+
66
+ ## Basic examples
67
+
68
+ ```solara
69
+ import solara
70
+
71
+ open_delete_confirmation = solara.reactive(False)
72
+
73
+ def delete_user():
74
+ # put your code to perform the action here
75
+ print("User being deleted...")
76
+
77
+ @solara.component
78
+ def Page():
79
+ solara.Button(label="Delete user", on_click=lambda: open_delete_confirmation.set(True))
80
+ solara.lab.ConfirmationDialog(open_delete_confirmation, ok="Ok, Delete", on_ok=delete_user, content="Are you sure you want to delete this user?")
81
+ ```
82
+
83
+ ## Arguments
84
+
85
+ * `open`: Indicates whether the dialog is being shown or not.
86
+ * `on_open`: Callback to call when the dialog opens of closes.
87
+ * `content`: Message that is displayed.
88
+ * `title`: Title of the dialog.
89
+ * `ok`: If a string, this text will be displayed on the confirmation button (default is "OK"). If a Button, it will be used instead of the default button.
90
+ * `on_ok`: Callback to be called when the OK button is clicked.
91
+ * `cancel`: If a string, this text will be displayed on the cancellation button (default is "Cancel"). If a Button, it will be used instead of the default
92
+ button.
93
+ * `on_cancel`: Callback to be called when the Cancel button is clicked. When persistent is False, clicking outside of the element or pressing esc key will
94
+ also trigger cancel.
95
+ * `children`: Additional components that will be shown under the dialog message, but before the buttons.
96
+ * `max_width`: Maximum width of the dialog window.
97
+ * `persistent`: When False (the default), clicking outside of the element or pressing esc key will trigger cancel.
98
+
99
+ """
100
+
101
+ def on_open(open_value):
102
+ if not open_value:
103
+ if on_close:
104
+ on_close()
105
+
106
+ open_reactive = solara.use_reactive(open, on_open)
107
+ del open
108
+
109
+ def close():
110
+ open_reactive.set(False)
111
+
112
+ user_on_click_ok = None
113
+ user_on_click_cancel = None
114
+
115
+ def perform_ok():
116
+ if user_on_click_ok:
117
+ user_on_click_ok()
118
+ on_ok()
119
+ close()
120
+
121
+ def perform_cancel():
122
+ if user_on_click_cancel:
123
+ user_on_click_cancel()
124
+ on_cancel()
125
+ close()
126
+
127
+ def on_v_model(value):
128
+ if not value:
129
+ on_cancel()
130
+ open_reactive.set(value)
131
+
132
+ with v.Dialog(
133
+ v_model=open_reactive.value,
134
+ on_v_model=on_v_model,
135
+ persistent=persistent,
136
+ max_width=max_width,
137
+ ):
138
+ with solara.v.Card():
139
+ solara.v.CardTitle(children=[title])
140
+ with solara.v.CardText(style_="min-height: 64px"):
141
+ if isinstance(content, str):
142
+ solara.Text(content)
143
+ else:
144
+ solara.display(content)
145
+ if children:
146
+ solara.display(*children)
147
+ with solara.v.CardActions(class_="justify-end"):
148
+ if isinstance(cancel, str):
149
+ solara.Button(label=cancel, on_click=perform_cancel, text=True, classes=["grey--text", "text--darken-2"])
150
+ else:
151
+ # the user may have passed in on_click already
152
+ user_on_click_cancel = cancel.kwargs.get("on_click")
153
+ # override or add our own on_click handler
154
+ cancel.kwargs = {**cancel.kwargs, "on_click": perform_cancel}
155
+ solara.display(cancel)
156
+
157
+ # similar as cancel
158
+ if isinstance(ok, str):
159
+ solara.Button(label=ok, on_click=perform_ok, dark=True, color="primary", elevation=0)
160
+ else:
161
+ user_on_click_ok = ok.kwargs.get("on_click")
162
+ ok.kwargs = {**ok.kwargs, "on_click": perform_ok}
163
+ solara.display(ok)
@@ -0,0 +1,7 @@
1
+ # for backwards compatibility
2
+ from solara.components.cross_filter import ( # noqa: F401
3
+ CrossFilterDataFrame,
4
+ CrossFilterReport,
5
+ CrossFilterSelect,
6
+ CrossFilterSlider,
7
+ )
@@ -0,0 +1,298 @@
1
+ import datetime as dt
2
+ from typing import Callable, Dict, List, Optional, Tuple, Union, cast
3
+
4
+ import ipyvue
5
+ import reacton
6
+
7
+ import solara
8
+ import solara.lab
9
+ from solara.components.input import _use_input_type
10
+
11
+
12
+ def use_close_menu(el: reacton.core.Element, is_open: solara.Reactive[bool]):
13
+ is_open_ref = solara.use_ref(is_open)
14
+ is_open_ref.current = is_open
15
+
16
+ def monitor_events():
17
+ def close_menu(*ignore_args):
18
+ is_open_ref.current.set(False)
19
+
20
+ widget = cast(ipyvue.VueWidget, solara.get_widget(el))
21
+ widget.on_event("keyup.enter", close_menu)
22
+ widget.on_event("keydown.tab", close_menu)
23
+
24
+ def cleanup():
25
+ widget.on_event("keyup.enter", close_menu, remove=True)
26
+ widget.on_event("keydown.tab", close_menu, remove=True)
27
+
28
+ return cleanup
29
+
30
+ solara.use_effect(monitor_events, [])
31
+
32
+
33
+ @solara.component
34
+ def InputDate(
35
+ value: Union[solara.Reactive[Optional[dt.date]], Optional[dt.date]],
36
+ on_value: Optional[Callable[[Optional[dt.date]], None]] = None,
37
+ label: str = "Pick a date",
38
+ children: List[solara.Element] = [],
39
+ open_value: Union[solara.Reactive[bool], bool] = False,
40
+ on_open_value: Optional[Callable[[bool], None]] = None,
41
+ optional: bool = False,
42
+ date_format: str = "%Y/%m/%d",
43
+ first_day_of_the_week: int = 1,
44
+ style: Optional[Union[str, Dict[str, str]]] = None,
45
+ classes: Optional[List[str]] = None,
46
+ ):
47
+ """
48
+ Show a textfield, which when clicked, opens a datepicker. The input date should be of type `datetime.date`.
49
+
50
+ ## Basic Example
51
+
52
+ ```solara
53
+ import solara
54
+ import solara.lab
55
+ import datetime as dt
56
+
57
+
58
+ @solara.component
59
+ def Page():
60
+ date = solara.use_reactive(dt.date.today())
61
+
62
+ solara.lab.InputDate(date)
63
+ solara.Text(str(date.value))
64
+ ```
65
+
66
+ ## Arguments
67
+
68
+ * value: Reactive variable of type `datetime.date`, or `None`. This date is selected the first time the component is rendered.
69
+ * on_value: a callback function for when value changes. The callback function receives the new value as an argument.
70
+ * label: Text used to label the text field that triggers the datepicker.
71
+ * children: List of Elements to be rendered under the calendar. If empty, a close button is rendered.
72
+ * open_value: Controls and communicates the state of the datepicker. If True, the datepicker is open. If False, the datepicker is closed.
73
+ Intended to be used in conjunction with a custom set of controls to close the datepicker.
74
+ * on_open_value: a callback function for when open_value changes. Also receives the new value as an argument.
75
+ * optional: Determines whether to show an error when value is `None`. If `True`, no error is shown.
76
+ * date_format: Sets the format of the date displayed in the text field. Defaults to `"%Y/%m/%d"`. For more information, see
77
+ <a href="https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes" target="_blank">the Python documentation</a>.
78
+ * first_day_of_the_week: Sets the first day of the week, as an `int` starting count from Sunday (`=0`). Defaults to `1`, which is Monday.
79
+ * style: CSS style to apply to the text field. Either a string or a dictionary of CSS properties (i.e. `{"property": "value"}`).
80
+ * classes: List of CSS classes to apply to the text field.
81
+ """
82
+ value_reactive = solara.use_reactive(value, on_value) # type: ignore
83
+ del value, on_value
84
+ datepicker_is_open = solara.use_reactive(open_value, on_open_value) # type: ignore
85
+ del open_value, on_open_value
86
+
87
+ def set_date_typed_cast(value: Optional[str]):
88
+ if value:
89
+ try:
90
+ date_value = dt.datetime.strptime(value, date_format).date()
91
+ return date_value
92
+ except ValueError:
93
+ raise ValueError(f"Date {value} does not match format {date_format.replace('%', '')}")
94
+ elif optional:
95
+ return None
96
+ else:
97
+ raise ValueError("Date cannot be empty")
98
+
99
+ def date_to_str(date: Optional[dt.date]) -> str:
100
+ if date is not None:
101
+ return date.strftime(date_format)
102
+ return ""
103
+
104
+ def set_date_cast(new_value: Optional[str]):
105
+ if new_value:
106
+ date_value = dt.datetime.strptime(new_value, "%Y-%m-%d").date()
107
+ datepicker_is_open.set(False)
108
+ value_reactive.value = date_value
109
+
110
+ def standard_strfy(date: Optional[dt.date]):
111
+ if date is None:
112
+ return None
113
+ else:
114
+ return date.strftime("%Y-%m-%d")
115
+
116
+ date_standard_str = standard_strfy(value_reactive.value)
117
+
118
+ style_flat = solara.util._flatten_style(style)
119
+
120
+ internal_value, error_message, set_value_cast = _use_input_type(value_reactive, set_date_typed_cast, date_to_str)
121
+
122
+ if error_message:
123
+ label += f" ({error_message})"
124
+ input = solara.v.TextField(
125
+ label=label,
126
+ v_model=internal_value,
127
+ on_v_model=set_value_cast,
128
+ append_icon="mdi-calendar",
129
+ error=bool(error_message),
130
+ style_="min-width: 290px;" + style_flat,
131
+ class_=", ".join(classes) if classes else "",
132
+ )
133
+
134
+ use_close_menu(input, datepicker_is_open)
135
+
136
+ with solara.lab.Menu(
137
+ activator=input,
138
+ close_on_content_click=False,
139
+ open_value=datepicker_is_open,
140
+ use_activator_width=False,
141
+ ):
142
+ with solara.v.DatePicker(
143
+ v_model=date_standard_str,
144
+ on_v_model=set_date_cast,
145
+ first_day_of_week=first_day_of_the_week,
146
+ style_="width: 100%;",
147
+ ):
148
+ if len(children) > 0:
149
+ solara.display(*children)
150
+
151
+
152
+ @solara.component
153
+ def InputDateRange(
154
+ value: Union[solara.Reactive[Tuple[Optional[dt.date], Optional[dt.date]]], Tuple[Optional[dt.date], Optional[dt.date]]],
155
+ on_value: Optional[Callable[[Optional[Tuple[Optional[dt.date], Optional[dt.date]]]], None]] = None,
156
+ label: str = "Select dates",
157
+ children: List[solara.Element] = [],
158
+ open_value: Union[solara.Reactive[bool], bool] = False,
159
+ on_open_value: Optional[Callable[[bool], None]] = None,
160
+ optional: bool = False,
161
+ date_format: str = "%Y/%m/%d",
162
+ first_day_of_the_week: int = 1,
163
+ style: Optional[Union[str, Dict[str, str]]] = None,
164
+ classes: Optional[List[str]] = None,
165
+ ):
166
+ """
167
+ Show a textfield, which when clicked, opens a datepicker that allows users to select a range of dates by choosing a starting and ending date.
168
+ The input dates should be stored in a reactive tuple of type `datetime.date`. The list should contain either precisely two elements.
169
+ For an empty pre-selection of dates, pass a reactive empty list.
170
+
171
+ ## Basic Example
172
+
173
+ ```solara
174
+ import solara
175
+ import solara.lab
176
+ import datetime as dt
177
+
178
+
179
+ @solara.component
180
+ def Page():
181
+ dates = solara.use_reactive(tuple([dt.date.today(), dt.date.today() + dt.timedelta(days=1)]))
182
+
183
+ solara.lab.InputDateRange(dates)
184
+ solara.Text(str(dates.value))
185
+ ```
186
+
187
+ ## Arguments
188
+
189
+ * value: Tuple with elements of type `datetime.date`. For an empty pre-selection of dates, pass an empty tuple.
190
+ * on_value: a callback function for when value changes. The callback function receives the new value as an argument.
191
+ * label: Text used to label the text field that triggers the datepicker.
192
+ * children: List of Elements to be rendered under the calendar. If empty, a close button is rendered.
193
+ * open_value: Controls and communicates the state of the datepicker. If True, the datepicker is open. If False, the datepicker is closed.
194
+ Intended to be used in conjunction with a custom set of controls to close the datepicker.
195
+ * on_open_value: a callback function for when open_value changes. Also receives the new value as an argument.
196
+ * date_format: Sets the format of the date displayed in the text field. Defaults to `"%Y/%m/%d"`. For more information,
197
+ * optional: Determines whether go show an error when value is `None`. If `True`, no error is shown.
198
+ see <a href="https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes" target="_blank">the Python documentation</a>.
199
+ * first_day_of_the_week: Sets the first day of the week, as an `int` starting count from Sunday (`=0`). Defaults to `1`, which is Monday.
200
+ * style: CSS style to apply to the text field. Either a string or a dictionary of CSS properties (i.e. `{"property": "value"}`).
201
+ * classes: List of CSS classes to apply to the text field.
202
+
203
+ ## A More Advanced Example
204
+
205
+ ```solara
206
+ import solara
207
+ import solara.lab
208
+ import datetime as dt
209
+
210
+
211
+ @solara.component
212
+ def Page():
213
+ date = solara.use_reactive(tuple([dt.date.today(), None]))
214
+ range_is_open = solara.use_reactive(False)
215
+ stay_length = solara.use_reactive(1)
216
+
217
+ def set_end_date(value):
218
+ if value and value[0]:
219
+ value = value[0]
220
+ second_date = value + dt.timedelta(days=stay_length.value)
221
+ date.set([value, second_date])
222
+
223
+ def book():
224
+ # Do some stuff here
225
+ range_is_open.set(False)
226
+
227
+ solara.use_memo(lambda: set_end_date(date.value), [stay_length.value])
228
+
229
+ with solara.Column(style="width: 400px;"):
230
+ solara.IntSlider("Length of stay", stay_length, min=1, max=10)
231
+ with solara.lab.InputDateRange(
232
+ date,
233
+ on_value=set_end_date,
234
+ open_value=range_is_open,
235
+ ):
236
+ with solara.Row(justify="end", style="width: 100%;"):
237
+ solara.Button(
238
+ label="Book",
239
+ color="primary",
240
+ on_click=book,
241
+ )
242
+
243
+ ```
244
+ """
245
+ value_reactive = solara.use_reactive(value, on_value) # type: ignore
246
+ del value, on_value
247
+ date_standard_strings = [date.strftime("%Y-%m-%d") for date in value_reactive.value if date is not None]
248
+ datepicker_is_open = solara.use_reactive(open_value, on_open_value) # type: ignore
249
+ del open_value, on_open_value
250
+ style_flat = solara.util._flatten_style(style)
251
+
252
+ def dates_to_string(dates: Tuple[Optional[dt.date], Optional[dt.date]]):
253
+ string_dates = [date.strftime(date_format) if date is not None else "" for date in dates]
254
+ if (len(dates) < 2 or dates[1] is None) and not optional:
255
+ return string_dates[0], "Please select two dates"
256
+ return " - ".join(string_dates), None
257
+
258
+ def set_dates_cast(values):
259
+ date_value = cast(
260
+ Tuple[Optional[dt.date], Optional[dt.date]], tuple([dt.datetime.strptime(item, "%Y-%m-%d").date() if item is not None else None for item in values])
261
+ )
262
+ if len(date_value) > 1 and date_value[1] is not None:
263
+ datepicker_is_open.set(False)
264
+ value_reactive.value = date_value
265
+
266
+ string_dates, error_message = dates_to_string(value_reactive.value)
267
+
268
+ if error_message:
269
+ label += f" ({error_message})"
270
+ input = solara.v.TextField(
271
+ label=label,
272
+ v_model=string_dates,
273
+ append_icon="mdi-calendar",
274
+ error=bool(error_message),
275
+ style_="min-width: 290px;" + style_flat,
276
+ readonly=True,
277
+ class_=", ".join(classes) if classes else "",
278
+ )
279
+
280
+ # We include closing on tab in case users want to skip the field with tab
281
+ use_close_menu(input, datepicker_is_open)
282
+
283
+ with solara.lab.Menu(
284
+ activator=input,
285
+ close_on_content_click=False,
286
+ open_value=datepicker_is_open,
287
+ use_activator_width=False,
288
+ ):
289
+ with solara.v.DatePicker(
290
+ v_model=date_standard_strings,
291
+ on_v_model=set_dates_cast,
292
+ range=True,
293
+ first_day_of_week=first_day_of_the_week,
294
+ style_="width: 100%;",
295
+ ):
296
+ if len(children) > 0:
297
+ for el in children:
298
+ solara.display(el)