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.
- prefix/etc/jupyter/jupyter_notebook_config.d/solara.json +7 -0
- prefix/etc/jupyter/jupyter_server_config.d/solara.json +7 -0
- solara/__init__.py +124 -0
- solara/__main__.py +734 -0
- solara/alias.py +6 -0
- solara/autorouting.py +546 -0
- solara/cache.py +303 -0
- solara/checks.html +71 -0
- solara/checks.py +224 -0
- solara/comm.py +28 -0
- solara/components/__init__.py +59 -0
- solara/components/alert.py +155 -0
- solara/components/applayout.py +393 -0
- solara/components/button.py +85 -0
- solara/components/card.py +87 -0
- solara/components/checkbox.py +50 -0
- solara/components/code_highlight_css.py +11 -0
- solara/components/code_highlight_css.vue +63 -0
- solara/components/columns.py +159 -0
- solara/components/component_vue.py +110 -0
- solara/components/cross_filter.py +335 -0
- solara/components/dataframe.py +546 -0
- solara/components/datatable.py +221 -0
- solara/components/datatable.vue +175 -0
- solara/components/details.py +21 -0
- solara/components/download.vue +35 -0
- solara/components/echarts.py +75 -0
- solara/components/echarts.vue +128 -0
- solara/components/figure_altair.py +39 -0
- solara/components/file_browser.py +182 -0
- solara/components/file_download.py +199 -0
- solara/components/file_drop.py +139 -0
- solara/components/file_drop.vue +83 -0
- solara/components/file_list_widget.vue +78 -0
- solara/components/head.py +27 -0
- solara/components/head_tag.py +49 -0
- solara/components/head_tag.vue +60 -0
- solara/components/image.py +173 -0
- solara/components/input.py +436 -0
- solara/components/link.py +55 -0
- solara/components/markdown.py +378 -0
- solara/components/markdown_editor.py +25 -0
- solara/components/markdown_editor.vue +362 -0
- solara/components/matplotlib.py +74 -0
- solara/components/meta.py +47 -0
- solara/components/misc.py +333 -0
- solara/components/pivot_table.py +258 -0
- solara/components/pivot_table.vue +158 -0
- solara/components/progress.py +47 -0
- solara/components/select.py +182 -0
- solara/components/select.vue +27 -0
- solara/components/slider.py +442 -0
- solara/components/slider_date.vue +56 -0
- solara/components/spinner-solara.vue +105 -0
- solara/components/spinner.py +30 -0
- solara/components/sql_code.py +33 -0
- solara/components/sql_code.vue +128 -0
- solara/components/style.py +105 -0
- solara/components/switch.py +68 -0
- solara/components/tab_navigation.py +37 -0
- solara/components/title.py +90 -0
- solara/components/title.vue +38 -0
- solara/components/togglebuttons.py +200 -0
- solara/components/tooltip.py +61 -0
- solara/datatypes.py +143 -0
- solara/express.py +241 -0
- solara/hooks/__init__.py +4 -0
- solara/hooks/dataframe.py +99 -0
- solara/hooks/misc.py +263 -0
- solara/hooks/use_reactive.py +129 -0
- solara/hooks/use_thread.py +129 -0
- solara/kitchensink.py +8 -0
- solara/lab/__init__.py +34 -0
- solara/lab/components/__init__.py +6 -0
- solara/lab/components/chat.py +203 -0
- solara/lab/components/confirmation_dialog.py +163 -0
- solara/lab/components/cross_filter.py +7 -0
- solara/lab/components/input_date.py +298 -0
- solara/lab/components/menu.py +181 -0
- solara/lab/components/menu.vue +38 -0
- solara/lab/components/tabs.py +274 -0
- solara/lab/components/theming.py +98 -0
- solara/lab/components/theming.vue +72 -0
- solara/lab/hooks/__init__.py +0 -0
- solara/lab/hooks/dataframe.py +12 -0
- solara/lab/toestand.py +3 -0
- solara/lab/utils/__init__.py +2 -0
- solara/lab/utils/cookies.py +5 -0
- solara/lab/utils/dataframe.py +115 -0
- solara/lab/utils/headers.py +5 -0
- solara/layout.py +44 -0
- solara/lifecycle.py +46 -0
- solara/minisettings.py +133 -0
- solara/py.typed +0 -0
- solara/reactive.py +93 -0
- solara/routing.py +268 -0
- solara/scope/__init__.py +88 -0
- solara/scope/types.py +55 -0
- solara/server/__init__.py +0 -0
- solara/server/app.py +491 -0
- solara/server/assets/custom.css +1 -0
- solara/server/assets/custom.js +1 -0
- solara/server/assets/favicon.png +0 -0
- solara/server/assets/favicon.svg +5 -0
- solara/server/assets/style.css +1665 -0
- solara/server/assets/theme-dark.css +437 -0
- solara/server/assets/theme-light.css +420 -0
- solara/server/assets/theme.js +3 -0
- solara/server/cdn_helper.py +77 -0
- solara/server/esm.py +69 -0
- solara/server/fastapi.py +5 -0
- solara/server/flask.py +286 -0
- solara/server/jupyter/__init__.py +2 -0
- solara/server/jupyter/cdn_handler.py +28 -0
- solara/server/jupyter/server_extension.py +29 -0
- solara/server/jupytertools.py +46 -0
- solara/server/kernel.py +338 -0
- solara/server/kernel_context.py +357 -0
- solara/server/patch.py +552 -0
- solara/server/reload.py +242 -0
- solara/server/server.py +456 -0
- solara/server/settings.py +215 -0
- solara/server/shell.py +251 -0
- solara/server/starlette.py +601 -0
- solara/server/static/ansi.js +270 -0
- solara/server/static/highlight-dark.css +82 -0
- solara/server/static/highlight.css +43 -0
- solara/server/static/main-vuetify.js +260 -0
- solara/server/static/main.js +163 -0
- solara/server/static/solara_bootstrap.py +129 -0
- solara/server/static/sun.svg +23 -0
- solara/server/static/webworker.js +42 -0
- solara/server/telemetry.py +212 -0
- solara/server/templates/index.html.j2 +1 -0
- solara/server/templates/loader-plain.css +11 -0
- solara/server/templates/loader-plain.html +20 -0
- solara/server/templates/loader-solara.css +111 -0
- solara/server/templates/loader-solara.html +40 -0
- solara/server/templates/plain.html +82 -0
- solara/server/templates/solara.html.j2 +446 -0
- solara/server/threaded.py +75 -0
- solara/server/utils.py +30 -0
- solara/server/websocket.py +45 -0
- solara/settings.py +56 -0
- solara/tasks.py +837 -0
- solara/template/button.py +16 -0
- solara/template/markdown.py +42 -0
- solara/template/portal/.flake8 +6 -0
- solara/template/portal/.pre-commit-config.yaml +28 -0
- solara/template/portal/LICENSE +21 -0
- solara/template/portal/Procfile +7 -0
- solara/template/portal/mypy.ini +3 -0
- solara/template/portal/pyproject.toml +26 -0
- solara/template/portal/solara_portal/__init__.py +4 -0
- solara/template/portal/solara_portal/components/__init__.py +2 -0
- solara/template/portal/solara_portal/components/article.py +28 -0
- solara/template/portal/solara_portal/components/data.py +28 -0
- solara/template/portal/solara_portal/components/header.py +6 -0
- solara/template/portal/solara_portal/components/layout.py +6 -0
- solara/template/portal/solara_portal/content/articles/equis-in-vidi.md +85 -0
- solara/template/portal/solara_portal/content/articles/substiterat-vati.md +70 -0
- solara/template/portal/solara_portal/data.py +60 -0
- solara/template/portal/solara_portal/pages/__init__.py +67 -0
- solara/template/portal/solara_portal/pages/article/__init__.py +26 -0
- solara/template/portal/solara_portal/pages/tabular.py +29 -0
- solara/template/portal/solara_portal/pages/viz/__init__.py +70 -0
- solara/template/portal/solara_portal/pages/viz/overview.py +14 -0
- solara/test/__init__.py +0 -0
- solara/test/pytest_plugin.py +697 -0
- solara/toestand.py +772 -0
- solara/util.py +308 -0
- solara/website/__init__.py +0 -0
- solara/website/assets/custom.css +468 -0
- solara/website/assets/images/logo-small.png +0 -0
- solara/website/assets/images/logo.svg +17 -0
- solara/website/assets/images/logo_white.svg +50 -0
- solara/website/assets/theme.js +8 -0
- solara/website/components/__init__.py +5 -0
- solara/website/components/algolia.vue +24 -0
- solara/website/components/algolia_api.vue +187 -0
- solara/website/components/docs.py +118 -0
- solara/website/components/header.py +72 -0
- solara/website/components/hero.py +15 -0
- solara/website/components/mailchimp.py +12 -0
- solara/website/components/mailchimp.vue +47 -0
- solara/website/components/markdown.py +30 -0
- solara/website/components/notebook.py +171 -0
- solara/website/pages/__init__.py +575 -0
- solara/website/pages/apps/__init__.py +16 -0
- solara/website/pages/apps/authorization/__init__.py +119 -0
- solara/website/pages/apps/authorization/admin.py +12 -0
- solara/website/pages/apps/authorization/users.py +12 -0
- solara/website/pages/apps/jupyter-dashboard-1.py +116 -0
- solara/website/pages/apps/layout-demo.py +40 -0
- solara/website/pages/apps/multipage/__init__.py +38 -0
- solara/website/pages/apps/multipage/page1.py +26 -0
- solara/website/pages/apps/multipage/page2.py +34 -0
- solara/website/pages/apps/scatter.py +136 -0
- solara/website/pages/apps/scrolling.py +63 -0
- solara/website/pages/apps/tutorial-streamlit.py +18 -0
- solara/website/pages/changelog/__init__.py +8 -0
- solara/website/pages/changelog/changelog.md +204 -0
- solara/website/pages/contact/__init__.py +8 -0
- solara/website/pages/contact/contact.md +17 -0
- solara/website/pages/doc_use_download.py +85 -0
- solara/website/pages/documentation/__init__.py +184 -0
- solara/website/pages/documentation/advanced/__init__.py +9 -0
- solara/website/pages/documentation/advanced/content/00-overview.md +1 -0
- solara/website/pages/documentation/advanced/content/10-howto/00-overview.md +6 -0
- solara/website/pages/documentation/advanced/content/10-howto/10-multipage.md +196 -0
- solara/website/pages/documentation/advanced/content/10-howto/20-layout.md +125 -0
- solara/website/pages/documentation/advanced/content/10-howto/30-testing.md +162 -0
- solara/website/pages/documentation/advanced/content/10-howto/31-debugging.md +69 -0
- solara/website/pages/documentation/advanced/content/10-howto/40-embed.md +49 -0
- solara/website/pages/documentation/advanced/content/10-howto/50-ipywidget_libraries.md +124 -0
- solara/website/pages/documentation/advanced/content/15-reference/00-overview.md +3 -0
- solara/website/pages/documentation/advanced/content/15-reference/40-static_files.md +31 -0
- solara/website/pages/documentation/advanced/content/15-reference/41-asset-files.md +36 -0
- solara/website/pages/documentation/advanced/content/15-reference/60-static-site-generation.md +59 -0
- solara/website/pages/documentation/advanced/content/15-reference/70-search.md +34 -0
- solara/website/pages/documentation/advanced/content/15-reference/80-reloading.md +34 -0
- solara/website/pages/documentation/advanced/content/15-reference/90-notebook-support.md +7 -0
- solara/website/pages/documentation/advanced/content/15-reference/95-caching.md +148 -0
- solara/website/pages/documentation/advanced/content/20-understanding/00-introduction.md +10 -0
- solara/website/pages/documentation/advanced/content/20-understanding/05-ipywidgets.md +35 -0
- solara/website/pages/documentation/advanced/content/20-understanding/06-ipyvuetify.md +42 -0
- solara/website/pages/documentation/advanced/content/20-understanding/10-reacton.md +28 -0
- solara/website/pages/documentation/advanced/content/20-understanding/12-reacton-basics.md +108 -0
- solara/website/pages/documentation/advanced/content/20-understanding/15-anatomy.md +23 -0
- solara/website/pages/documentation/advanced/content/20-understanding/17-rules-of-hooks.md +7 -0
- solara/website/pages/documentation/advanced/content/20-understanding/18-containers.md +166 -0
- solara/website/pages/documentation/advanced/content/20-understanding/20-solara.md +18 -0
- solara/website/pages/documentation/advanced/content/20-understanding/40-routing.md +240 -0
- solara/website/pages/documentation/advanced/content/20-understanding/50-solara-server.md +97 -0
- solara/website/pages/documentation/advanced/content/20-understanding/60-voila.md +12 -0
- solara/website/pages/documentation/advanced/content/30-enterprise/00-overview.md +1 -0
- solara/website/pages/documentation/advanced/content/30-enterprise/10-oauth.md +171 -0
- solara/website/pages/documentation/advanced/content/40-development/00-overview.md +0 -0
- solara/website/pages/documentation/advanced/content/40-development/01-contribute.md +45 -0
- solara/website/pages/documentation/advanced/content/40-development/10-setup.md +76 -0
- solara/website/pages/documentation/api/__init__.py +19 -0
- solara/website/pages/documentation/api/cross_filter/__init__.py +9 -0
- solara/website/pages/documentation/api/cross_filter/cross_filter_dataframe.py +23 -0
- solara/website/pages/documentation/api/cross_filter/cross_filter_report.py +22 -0
- solara/website/pages/documentation/api/cross_filter/cross_filter_select.py +22 -0
- solara/website/pages/documentation/api/cross_filter/cross_filter_slider.py +22 -0
- solara/website/pages/documentation/api/hooks/__init__.py +9 -0
- solara/website/pages/documentation/api/hooks/use_cross_filter.py +25 -0
- solara/website/pages/documentation/api/hooks/use_dark_effective.py +12 -0
- solara/website/pages/documentation/api/hooks/use_effect.md +43 -0
- solara/website/pages/documentation/api/hooks/use_effect.py +9 -0
- solara/website/pages/documentation/api/hooks/use_exception.py +33 -0
- solara/website/pages/documentation/api/hooks/use_memo.md +16 -0
- solara/website/pages/documentation/api/hooks/use_memo.py +9 -0
- solara/website/pages/documentation/api/hooks/use_previous.py +33 -0
- solara/website/pages/documentation/api/hooks/use_reactive.py +16 -0
- solara/website/pages/documentation/api/hooks/use_state.py +10 -0
- solara/website/pages/documentation/api/hooks/use_state_or_update.py +69 -0
- solara/website/pages/documentation/api/hooks/use_thread.md +58 -0
- solara/website/pages/documentation/api/hooks/use_thread.py +44 -0
- solara/website/pages/documentation/api/hooks/use_trait_observe.py +12 -0
- solara/website/pages/documentation/api/routing/__init__.py +9 -0
- solara/website/pages/documentation/api/routing/generate_routes.py +10 -0
- solara/website/pages/documentation/api/routing/generate_routes_directory.py +10 -0
- solara/website/pages/documentation/api/routing/resolve_path.py +35 -0
- solara/website/pages/documentation/api/routing/route.py +31 -0
- solara/website/pages/documentation/api/routing/use_route.py +80 -0
- solara/website/pages/documentation/api/routing/use_router.py +16 -0
- solara/website/pages/documentation/api/utilities/__init__.py +9 -0
- solara/website/pages/documentation/api/utilities/component_vue.py +10 -0
- solara/website/pages/documentation/api/utilities/computed.py +16 -0
- solara/website/pages/documentation/api/utilities/display.py +16 -0
- solara/website/pages/documentation/api/utilities/get_kernel_id.py +16 -0
- solara/website/pages/documentation/api/utilities/get_session_id.py +16 -0
- solara/website/pages/documentation/api/utilities/memoize.py +35 -0
- solara/website/pages/documentation/api/utilities/on_kernel_start.py +27 -0
- solara/website/pages/documentation/api/utilities/reactive.py +16 -0
- solara/website/pages/documentation/api/utilities/widget.py +104 -0
- solara/website/pages/documentation/components/__init__.py +12 -0
- solara/website/pages/documentation/components/advanced/__init__.py +9 -0
- solara/website/pages/documentation/components/advanced/link.py +27 -0
- solara/website/pages/documentation/components/advanced/meta.py +20 -0
- solara/website/pages/documentation/components/advanced/style.py +45 -0
- solara/website/pages/documentation/components/common.py +9 -0
- solara/website/pages/documentation/components/data/__init__.py +9 -0
- solara/website/pages/documentation/components/data/dataframe.py +44 -0
- solara/website/pages/documentation/components/data/pivot_table.py +81 -0
- solara/website/pages/documentation/components/enterprise/__init__.py +9 -0
- solara/website/pages/documentation/components/enterprise/avatar.py +24 -0
- solara/website/pages/documentation/components/enterprise/avatar_menu.py +25 -0
- solara/website/pages/documentation/components/input/__init__.py +9 -0
- solara/website/pages/documentation/components/input/button.py +23 -0
- solara/website/pages/documentation/components/input/checkbox.py +10 -0
- solara/website/pages/documentation/components/input/file_browser.py +32 -0
- solara/website/pages/documentation/components/input/file_drop.py +76 -0
- solara/website/pages/documentation/components/input/input.py +19 -0
- solara/website/pages/documentation/components/input/select.py +22 -0
- solara/website/pages/documentation/components/input/slider.py +29 -0
- solara/website/pages/documentation/components/input/switch.py +10 -0
- solara/website/pages/documentation/components/input/togglebuttons.py +21 -0
- solara/website/pages/documentation/components/lab/__init__.py +9 -0
- solara/website/pages/documentation/components/lab/chat.py +109 -0
- solara/website/pages/documentation/components/lab/confirmation_dialog.py +55 -0
- solara/website/pages/documentation/components/lab/cookies_headers.py +48 -0
- solara/website/pages/documentation/components/lab/input_date.py +20 -0
- solara/website/pages/documentation/components/lab/menu.py +22 -0
- solara/website/pages/documentation/components/lab/tab.py +25 -0
- solara/website/pages/documentation/components/lab/tabs.py +45 -0
- solara/website/pages/documentation/components/lab/task.py +11 -0
- solara/website/pages/documentation/components/lab/theming.py +72 -0
- solara/website/pages/documentation/components/lab/use_task.py +11 -0
- solara/website/pages/documentation/components/layout/__init__.py +9 -0
- solara/website/pages/documentation/components/layout/app_bar.py +16 -0
- solara/website/pages/documentation/components/layout/app_bar_title.py +16 -0
- solara/website/pages/documentation/components/layout/app_layout.py +24 -0
- solara/website/pages/documentation/components/layout/card.py +15 -0
- solara/website/pages/documentation/components/layout/card_actions.py +16 -0
- solara/website/pages/documentation/components/layout/column.py +30 -0
- solara/website/pages/documentation/components/layout/columns.py +27 -0
- solara/website/pages/documentation/components/layout/columns_responsive.py +68 -0
- solara/website/pages/documentation/components/layout/griddraggable.py +62 -0
- solara/website/pages/documentation/components/layout/gridfixed.py +21 -0
- solara/website/pages/documentation/components/layout/hbox.py +18 -0
- solara/website/pages/documentation/components/layout/row.py +30 -0
- solara/website/pages/documentation/components/layout/sidebar.py +24 -0
- solara/website/pages/documentation/components/layout/vbox.py +19 -0
- solara/website/pages/documentation/components/output/__init__.py +9 -0
- solara/website/pages/documentation/components/output/file_download.py +11 -0
- solara/website/pages/documentation/components/output/html.py +21 -0
- solara/website/pages/documentation/components/output/image.py +11 -0
- solara/website/pages/documentation/components/output/markdown.py +57 -0
- solara/website/pages/documentation/components/output/markdown_editor.py +51 -0
- solara/website/pages/documentation/components/output/sql_code.py +85 -0
- solara/website/pages/documentation/components/output/tooltip.py +11 -0
- solara/website/pages/documentation/components/page/__init__.py +9 -0
- solara/website/pages/documentation/components/page/head.py +18 -0
- solara/website/pages/documentation/components/page/title.py +27 -0
- solara/website/pages/documentation/components/status/__init__.py +9 -0
- solara/website/pages/documentation/components/status/error.py +40 -0
- solara/website/pages/documentation/components/status/info.py +40 -0
- solara/website/pages/documentation/components/status/progress.py +10 -0
- solara/website/pages/documentation/components/status/spinner.py +11 -0
- solara/website/pages/documentation/components/status/success.py +40 -0
- solara/website/pages/documentation/components/status/warning.py +47 -0
- solara/website/pages/documentation/components/viz/__init__.py +9 -0
- solara/website/pages/documentation/components/viz/altair.py +42 -0
- solara/website/pages/documentation/components/viz/echarts.py +75 -0
- solara/website/pages/documentation/components/viz/matplotlib.py +30 -0
- solara/website/pages/documentation/components/viz/plotly.py +63 -0
- solara/website/pages/documentation/components/viz/plotly_express.py +41 -0
- solara/website/pages/documentation/examples/__init__.py +52 -0
- solara/website/pages/documentation/examples/ai/__init__.py +11 -0
- solara/website/pages/documentation/examples/ai/chatbot.py +95 -0
- solara/website/pages/documentation/examples/ai/tokenizer.py +107 -0
- solara/website/pages/documentation/examples/basics/__init__.py +10 -0
- solara/website/pages/documentation/examples/basics/sine.py +28 -0
- solara/website/pages/documentation/examples/fullscreen/__init__.py +10 -0
- solara/website/pages/documentation/examples/fullscreen/authorization.py +3 -0
- solara/website/pages/documentation/examples/fullscreen/layout_demo.py +3 -0
- solara/website/pages/documentation/examples/fullscreen/multipage.py +3 -0
- solara/website/pages/documentation/examples/fullscreen/scatter.py +3 -0
- solara/website/pages/documentation/examples/fullscreen/scrolling.py +3 -0
- solara/website/pages/documentation/examples/fullscreen/tutorial_streamlit.py +3 -0
- solara/website/pages/documentation/examples/general/__init__.py +10 -0
- solara/website/pages/documentation/examples/general/custom_storage.py +70 -0
- solara/website/pages/documentation/examples/general/deploy_model.py +115 -0
- solara/website/pages/documentation/examples/general/live_update.py +38 -0
- solara/website/pages/documentation/examples/general/login_oauth.py +81 -0
- solara/website/pages/documentation/examples/general/mycard.vue +58 -0
- solara/website/pages/documentation/examples/general/pokemon_search.py +51 -0
- solara/website/pages/documentation/examples/general/vue_component.py +50 -0
- solara/website/pages/documentation/examples/ipycanvas.py +49 -0
- solara/website/pages/documentation/examples/libraries/__init__.py +10 -0
- solara/website/pages/documentation/examples/libraries/altair.py +64 -0
- solara/website/pages/documentation/examples/libraries/bqplot.py +39 -0
- solara/website/pages/documentation/examples/libraries/ipyleaflet.py +33 -0
- solara/website/pages/documentation/examples/libraries/ipyleaflet_advanced.py +66 -0
- solara/website/pages/documentation/examples/utilities/__init__.py +10 -0
- solara/website/pages/documentation/examples/utilities/calculator.py +157 -0
- solara/website/pages/documentation/examples/utilities/countdown_timer.py +64 -0
- solara/website/pages/documentation/examples/utilities/todo.py +196 -0
- solara/website/pages/documentation/examples/visualization/__init__.py +6 -0
- solara/website/pages/documentation/examples/visualization/annotator.py +69 -0
- solara/website/pages/documentation/examples/visualization/linked_views.py +84 -0
- solara/website/pages/documentation/examples/visualization/plotly.py +44 -0
- solara/website/pages/documentation/faq/__init__.py +12 -0
- solara/website/pages/documentation/faq/content/99-faq.md +76 -0
- solara/website/pages/documentation/getting_started/__init__.py +9 -0
- solara/website/pages/documentation/getting_started/content/00-quickstart.md +89 -0
- solara/website/pages/documentation/getting_started/content/01-introduction.md +125 -0
- solara/website/pages/documentation/getting_started/content/02-installing.md +134 -0
- solara/website/pages/documentation/getting_started/content/04-tutorials/00-overview.md +14 -0
- solara/website/pages/documentation/getting_started/content/04-tutorials/10_data_science.py +13 -0
- solara/website/pages/documentation/getting_started/content/04-tutorials/20-web-app.md +89 -0
- solara/website/pages/documentation/getting_started/content/04-tutorials/30-ipywidgets.md +124 -0
- solara/website/pages/documentation/getting_started/content/04-tutorials/40-streamlit.md +146 -0
- solara/website/pages/documentation/getting_started/content/04-tutorials/50-dash.md +144 -0
- solara/website/pages/documentation/getting_started/content/04-tutorials/60-jupyter-dashboard-part1.py +64 -0
- solara/website/pages/documentation/getting_started/content/04-tutorials/SF_crime_sample.csv.gz +0 -0
- solara/website/pages/documentation/getting_started/content/04-tutorials/_data_science.ipynb +445 -0
- solara/website/pages/documentation/getting_started/content/04-tutorials/_jupyter_dashboard_1.ipynb +1000 -0
- solara/website/pages/documentation/getting_started/content/05-fundamentals/00-overview.md +11 -0
- solara/website/pages/documentation/getting_started/content/05-fundamentals/10-components.md +223 -0
- solara/website/pages/documentation/getting_started/content/05-fundamentals/50-state-management.md +88 -0
- solara/website/pages/documentation/getting_started/content/07-deploying/00-overview.md +7 -0
- solara/website/pages/documentation/getting_started/content/07-deploying/10-self-hosted.md +273 -0
- solara/website/pages/documentation/getting_started/content/07-deploying/20-cloud-hosted.md +80 -0
- solara/website/pages/documentation/getting_started/content/80-what-is-lab.md +7 -0
- solara/website/pages/documentation/getting_started/content/90-troubleshoot.md +26 -0
- solara/website/pages/docutils.py +38 -0
- solara/website/pages/showcase/__init__.py +105 -0
- solara/website/pages/showcase/domino_code_assist.py +60 -0
- solara/website/pages/showcase/planeto_tessa.py +19 -0
- solara/website/pages/showcase/solara_dev.py +54 -0
- solara/website/pages/showcase/solarathon_2023_team_2.py +22 -0
- solara/website/pages/showcase/solarathon_2023_team_4.py +22 -0
- solara/website/pages/showcase/solarathon_2023_team_5.py +23 -0
- solara/website/pages/showcase/solarathon_2023_team_6.py +34 -0
- solara/website/pages/showcase/wanderlust.py +27 -0
- solara/website/public/beach.jpeg +0 -0
- solara/website/public/logo.svg +6 -0
- solara/website/public/social/discord.svg +1 -0
- solara/website/public/social/github.svg +1 -0
- solara/website/public/social/twitter.svg +3 -0
- solara/website/public/success.html +25 -0
- solara/website/templates/index.html.j2 +117 -0
- solara/website/utils.py +51 -0
- solara/widgets/__init__.py +1 -0
- solara/widgets/vue/gridlayout.vue +110 -0
- solara/widgets/vue/html.vue +4 -0
- solara/widgets/vue/navigator.vue +104 -0
- solara/widgets/vue/vegalite.vue +115 -0
- solara/widgets/widgets.py +66 -0
- solara_ui-1.31.0.data/data/etc/jupyter/jupyter_notebook_config.d/solara.json +7 -0
- solara_ui-1.31.0.data/data/etc/jupyter/jupyter_server_config.d/solara.json +7 -0
- solara_ui-1.31.0.dist-info/METADATA +158 -0
- solara_ui-1.31.0.dist-info/RECORD +439 -0
- solara_ui-1.31.0.dist-info/WHEEL +5 -0
- 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,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)
|