solara-ui 1.45.0__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 +765 -0
- solara/_stores.py +297 -0
- solara/alias.py +6 -0
- solara/autorouting.py +555 -0
- solara/cache.py +305 -0
- solara/checks.html +71 -0
- solara/checks.py +227 -0
- solara/comm.py +28 -0
- solara/components/__init__.py +77 -0
- solara/components/alert.py +155 -0
- solara/components/applayout.py +397 -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 +134 -0
- solara/components/cross_filter.py +335 -0
- solara/components/dataframe.py +546 -0
- solara/components/datatable.py +214 -0
- solara/components/datatable.vue +175 -0
- solara/components/details.py +56 -0
- solara/components/download.vue +35 -0
- solara/components/echarts.py +86 -0
- solara/components/echarts.vue +139 -0
- solara/components/figure_altair.py +39 -0
- solara/components/file_browser.py +181 -0
- solara/components/file_download.py +199 -0
- solara/components/file_drop.py +159 -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 +456 -0
- solara/components/input_text_area.py +86 -0
- solara/components/link.py +55 -0
- solara/components/markdown.py +441 -0
- solara/components/markdown_editor.py +33 -0
- solara/components/markdown_editor.vue +359 -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 +45 -0
- solara/components/sql_code.py +41 -0
- solara/components/sql_code.vue +125 -0
- solara/components/style.py +105 -0
- solara/components/switch.py +71 -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/core.py +42 -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 +151 -0
- solara/hooks/use_thread.py +129 -0
- solara/kitchensink.py +8 -0
- solara/lab/__init__.py +34 -0
- solara/lab/components/__init__.py +7 -0
- solara/lab/components/chat.py +215 -0
- solara/lab/components/confirmation_dialog.py +163 -0
- solara/lab/components/cross_filter.py +7 -0
- solara/lab/components/input_date.py +339 -0
- solara/lab/components/input_time.py +133 -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 +2 -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 +165 -0
- solara/lab/utils/headers.py +5 -0
- solara/layout.py +44 -0
- solara/lifecycle.py +46 -0
- solara/minisettings.py +141 -0
- solara/py.typed +0 -0
- solara/reactive.py +99 -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 +527 -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 +1681 -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 +91 -0
- solara/server/esm.py +71 -0
- solara/server/fastapi.py +5 -0
- solara/server/flask.py +297 -0
- solara/server/jupyter/__init__.py +2 -0
- solara/server/jupyter/cdn_handler.py +28 -0
- solara/server/jupyter/server_extension.py +40 -0
- solara/server/jupyter/solara.py +91 -0
- solara/server/jupytertools.py +46 -0
- solara/server/kernel.py +388 -0
- solara/server/kernel_context.py +467 -0
- solara/server/patch.py +564 -0
- solara/server/pyinstaller/__init__.py +9 -0
- solara/server/pyinstaller/hook-ipyreact.py +5 -0
- solara/server/pyinstaller/hook-ipyvuetify.py +5 -0
- solara/server/pyinstaller/hook-solara.py +9 -0
- solara/server/qt.py +113 -0
- solara/server/reload.py +251 -0
- solara/server/server.py +484 -0
- solara/server/settings.py +249 -0
- solara/server/shell.py +269 -0
- solara/server/starlette.py +770 -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 +272 -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 +486 -0
- solara/server/threaded.py +84 -0
- solara/server/utils.py +44 -0
- solara/server/websocket.py +45 -0
- solara/settings.py +86 -0
- solara/tasks.py +893 -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 +783 -0
- solara/toestand.py +998 -0
- solara/util.py +348 -0
- solara/validate_hooks.py +258 -0
- solara/website/__init__.py +0 -0
- solara/website/assets/custom.css +444 -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.py +6 -0
- solara/website/components/algolia.vue +24 -0
- solara/website/components/algolia_api.vue +202 -0
- solara/website/components/breadcrumbs.py +28 -0
- solara/website/components/contact.py +144 -0
- solara/website/components/docs.py +143 -0
- solara/website/components/header.py +75 -0
- solara/website/components/mailchimp.py +12 -0
- solara/website/components/mailchimp.vue +47 -0
- solara/website/components/markdown.py +99 -0
- solara/website/components/markdown_nav.vue +34 -0
- solara/website/components/notebook.py +171 -0
- solara/website/components/sidebar.py +105 -0
- solara/website/pages/__init__.py +370 -0
- solara/website/pages/about/__init__.py +9 -0
- solara/website/pages/about/about.md +3 -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/careers/__init__.py +27 -0
- solara/website/pages/changelog/__init__.py +10 -0
- solara/website/pages/changelog/changelog.md +372 -0
- solara/website/pages/contact/__init__.py +34 -0
- solara/website/pages/doc_use_download.py +85 -0
- solara/website/pages/documentation/__init__.py +90 -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 +417 -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 +50 -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 +72 -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 +192 -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 +256 -0
- solara/website/pages/documentation/advanced/content/20-understanding/50-solara-server.md +108 -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 +7 -0
- solara/website/pages/documentation/advanced/content/30-enterprise/10-oauth.md +187 -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 +22 -0
- solara/website/pages/documentation/api/cross_filter/cross_filter_report.py +20 -0
- solara/website/pages/documentation/api/cross_filter/cross_filter_select.py +20 -0
- solara/website/pages/documentation/api/cross_filter/cross_filter_slider.py +20 -0
- solara/website/pages/documentation/api/hooks/__init__.py +9 -0
- solara/website/pages/documentation/api/hooks/use_cross_filter.py +23 -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 +31 -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 +30 -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 +66 -0
- solara/website/pages/documentation/api/hooks/use_thread.md +64 -0
- solara/website/pages/documentation/api/hooks/use_thread.py +42 -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 +29 -0
- solara/website/pages/documentation/api/routing/use_route.py +76 -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 +44 -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 +25 -0
- solara/website/pages/documentation/components/advanced/meta.py +17 -0
- solara/website/pages/documentation/components/advanced/style.py +43 -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 +30 -0
- solara/website/pages/documentation/components/input/file_drop.py +76 -0
- solara/website/pages/documentation/components/input/input.py +43 -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/input_time.py +15 -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 +74 -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 +66 -0
- solara/website/pages/documentation/components/layout/details.py +13 -0
- solara/website/pages/documentation/components/layout/griddraggable.py +62 -0
- solara/website/pages/documentation/components/layout/gridfixed.py +19 -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 +19 -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 +83 -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 +15 -0
- solara/website/pages/documentation/components/page/title.py +25 -0
- solara/website/pages/documentation/components/status/__init__.py +9 -0
- solara/website/pages/documentation/components/status/error.py +39 -0
- solara/website/pages/documentation/components/status/info.py +39 -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 +77 -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 +54 -0
- solara/website/pages/documentation/examples/ai/__init__.py +11 -0
- solara/website/pages/documentation/examples/ai/chatbot.py +113 -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 +32 -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 +65 -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 +62 -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 +67 -0
- solara/website/pages/documentation/examples/visualization/linked_views.py +81 -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 +112 -0
- solara/website/pages/documentation/getting_started/__init__.py +9 -0
- solara/website/pages/documentation/getting_started/content/00-quickstart.md +107 -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 +65 -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 +1021 -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 +228 -0
- solara/website/pages/documentation/getting_started/content/05-fundamentals/50-state-management.md +278 -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 +305 -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/home.vue +1199 -0
- solara/website/pages/our_team/__init__.py +83 -0
- solara/website/pages/pricing/__init__.py +31 -0
- solara/website/pages/roadmap/__init__.py +11 -0
- solara/website/pages/roadmap/roadmap.md +47 -0
- solara/website/pages/scale_ipywidgets.py +45 -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 +107 -0
- solara/widgets/vue/html.vue +4 -0
- solara/widgets/vue/navigator.vue +134 -0
- solara/widgets/vue/vegalite.vue +130 -0
- solara/widgets/widgets.py +74 -0
- solara_ui-1.45.0.data/data/etc/jupyter/jupyter_notebook_config.d/solara.json +7 -0
- solara_ui-1.45.0.data/data/etc/jupyter/jupyter_server_config.d/solara.json +7 -0
- solara_ui-1.45.0.dist-info/METADATA +162 -0
- solara_ui-1.45.0.dist-info/RECORD +464 -0
- solara_ui-1.45.0.dist-info/WHEEL +4 -0
- solara_ui-1.45.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,339 @@
|
|
|
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
|
+
date_picker_type: str = "date",
|
|
47
|
+
min_date: Optional[str] = None,
|
|
48
|
+
max_date: Optional[str] = None,
|
|
49
|
+
):
|
|
50
|
+
"""
|
|
51
|
+
Show a textfield, which when clicked, opens a datepicker. The input date should be of type `datetime.date`.
|
|
52
|
+
|
|
53
|
+
## Basic Example
|
|
54
|
+
|
|
55
|
+
```solara
|
|
56
|
+
import solara
|
|
57
|
+
import solara.lab
|
|
58
|
+
import datetime as dt
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@solara.component
|
|
62
|
+
def Page():
|
|
63
|
+
date = solara.use_reactive(dt.date.today())
|
|
64
|
+
|
|
65
|
+
solara.lab.InputDate(date)
|
|
66
|
+
solara.Text(str(date.value))
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Arguments
|
|
70
|
+
|
|
71
|
+
* value: Reactive variable of type `datetime.date`, or `None`. This date is selected the first time the component is rendered.
|
|
72
|
+
* on_value: a callback function for when value changes. The callback function receives the new value as an argument.
|
|
73
|
+
* label: Text used to label the text field that triggers the datepicker.
|
|
74
|
+
* children: List of Elements to be rendered under the calendar. If empty, a close button is rendered.
|
|
75
|
+
* open_value: Controls and communicates the state of the datepicker. If True, the datepicker is open. If False, the datepicker is closed.
|
|
76
|
+
Intended to be used in conjunction with a custom set of controls to close the datepicker.
|
|
77
|
+
* on_open_value: a callback function for when open_value changes. Also receives the new value as an argument.
|
|
78
|
+
* optional: Determines whether to show an error when value is `None`. If `True`, no error is shown.
|
|
79
|
+
* date_format: Sets the format of the date displayed in the text field. Defaults to `"%Y/%m/%d"`. For more information, see
|
|
80
|
+
<a href="https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes" target="_blank">the Python documentation</a>.
|
|
81
|
+
* 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.
|
|
82
|
+
* style: CSS style to apply to the text field. Either a string or a dictionary of CSS properties (i.e. `{"property": "value"}`).
|
|
83
|
+
* classes: List of CSS classes to apply to the text field.
|
|
84
|
+
* date_picker_type: Sets the type of the datepicker. Use `"date"` for date selection or `"month"` for month selection. Defaults to `"date"`.
|
|
85
|
+
* min_date: Earliest allowed date/month (ISO 8601 format). If not specified, there is no limit.
|
|
86
|
+
* max_date: Latest allowed date/month (ISO 8601 format). If not specified, there is no limit.
|
|
87
|
+
"""
|
|
88
|
+
value_reactive = solara.use_reactive(value, on_value) # type: ignore
|
|
89
|
+
del value, on_value
|
|
90
|
+
datepicker_is_open = solara.use_reactive(open_value, on_open_value) # type: ignore
|
|
91
|
+
del open_value, on_open_value
|
|
92
|
+
|
|
93
|
+
if date_picker_type == "date":
|
|
94
|
+
internal_date_format = "%Y-%m-%d"
|
|
95
|
+
elif date_picker_type == "month":
|
|
96
|
+
internal_date_format = "%Y-%m"
|
|
97
|
+
else:
|
|
98
|
+
raise ValueError("date_picker_type must be either 'date' or 'month'.")
|
|
99
|
+
|
|
100
|
+
def set_date_typed_cast(value: Optional[str]):
|
|
101
|
+
if value:
|
|
102
|
+
try:
|
|
103
|
+
date_value = dt.datetime.strptime(value, date_format).date()
|
|
104
|
+
return date_value
|
|
105
|
+
except ValueError:
|
|
106
|
+
raise ValueError(f"Date {value} does not match format {date_format.replace('%', '')}")
|
|
107
|
+
elif optional:
|
|
108
|
+
return None
|
|
109
|
+
else:
|
|
110
|
+
raise ValueError("Date cannot be empty")
|
|
111
|
+
|
|
112
|
+
def date_to_str(date: Optional[dt.date]) -> str:
|
|
113
|
+
if date is not None:
|
|
114
|
+
return date.strftime(date_format)
|
|
115
|
+
return ""
|
|
116
|
+
|
|
117
|
+
def set_date_cast(new_value: Optional[str]):
|
|
118
|
+
if new_value:
|
|
119
|
+
date_value = dt.datetime.strptime(new_value, internal_date_format).date()
|
|
120
|
+
datepicker_is_open.set(False)
|
|
121
|
+
value_reactive.value = date_value
|
|
122
|
+
|
|
123
|
+
def standard_strfy(date: Optional[dt.date]):
|
|
124
|
+
if date is None:
|
|
125
|
+
return None
|
|
126
|
+
else:
|
|
127
|
+
return date.strftime(internal_date_format)
|
|
128
|
+
|
|
129
|
+
date_standard_str = standard_strfy(value_reactive.value)
|
|
130
|
+
|
|
131
|
+
style_flat = solara.util._flatten_style(style)
|
|
132
|
+
|
|
133
|
+
internal_value, error_message, set_value_cast = _use_input_type(value_reactive, set_date_typed_cast, date_to_str)
|
|
134
|
+
|
|
135
|
+
if error_message:
|
|
136
|
+
label += f" ({error_message})"
|
|
137
|
+
input = solara.v.TextField(
|
|
138
|
+
label=label,
|
|
139
|
+
v_model=internal_value,
|
|
140
|
+
on_v_model=set_value_cast,
|
|
141
|
+
append_icon="mdi-calendar",
|
|
142
|
+
error=bool(error_message),
|
|
143
|
+
style_="min-width: 290px;" + style_flat,
|
|
144
|
+
class_=", ".join(classes) if classes else "",
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
use_close_menu(input, datepicker_is_open)
|
|
148
|
+
|
|
149
|
+
with solara.lab.Menu(
|
|
150
|
+
activator=input,
|
|
151
|
+
close_on_content_click=False,
|
|
152
|
+
open_value=datepicker_is_open,
|
|
153
|
+
use_activator_width=False,
|
|
154
|
+
):
|
|
155
|
+
with solara.v.DatePicker(
|
|
156
|
+
v_model=date_standard_str,
|
|
157
|
+
on_v_model=set_date_cast,
|
|
158
|
+
first_day_of_week=first_day_of_the_week,
|
|
159
|
+
style_="width: 100%;",
|
|
160
|
+
max=max_date,
|
|
161
|
+
min=min_date,
|
|
162
|
+
type=date_picker_type,
|
|
163
|
+
):
|
|
164
|
+
if len(children) > 0:
|
|
165
|
+
solara.display(*children)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
@solara.component
|
|
169
|
+
def InputDateRange(
|
|
170
|
+
value: Union[solara.Reactive[Tuple[Optional[dt.date], Optional[dt.date]]], Tuple[Optional[dt.date], Optional[dt.date]]],
|
|
171
|
+
on_value: Optional[Callable[[Optional[Tuple[Optional[dt.date], Optional[dt.date]]]], None]] = None,
|
|
172
|
+
label: str = "Select dates",
|
|
173
|
+
children: List[solara.Element] = [],
|
|
174
|
+
open_value: Union[solara.Reactive[bool], bool] = False,
|
|
175
|
+
on_open_value: Optional[Callable[[bool], None]] = None,
|
|
176
|
+
optional: bool = False,
|
|
177
|
+
date_format: str = "%Y/%m/%d",
|
|
178
|
+
first_day_of_the_week: int = 1,
|
|
179
|
+
style: Optional[Union[str, Dict[str, str]]] = None,
|
|
180
|
+
classes: Optional[List[str]] = None,
|
|
181
|
+
date_picker_type: str = "date",
|
|
182
|
+
min_date: Optional[str] = None,
|
|
183
|
+
max_date: Optional[str] = None,
|
|
184
|
+
sort: Optional[bool] = False,
|
|
185
|
+
):
|
|
186
|
+
"""
|
|
187
|
+
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.
|
|
188
|
+
The input dates should be stored in a reactive tuple of type `datetime.date`. The list should contain either precisely two elements.
|
|
189
|
+
For an empty pre-selection of dates, pass a reactive empty list.
|
|
190
|
+
|
|
191
|
+
## Basic Example
|
|
192
|
+
|
|
193
|
+
```solara
|
|
194
|
+
import solara
|
|
195
|
+
import solara.lab
|
|
196
|
+
import datetime as dt
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
@solara.component
|
|
200
|
+
def Page():
|
|
201
|
+
dates = solara.use_reactive(tuple([dt.date.today(), dt.date.today() + dt.timedelta(days=1)]))
|
|
202
|
+
|
|
203
|
+
solara.lab.InputDateRange(dates)
|
|
204
|
+
solara.Text(str(dates.value))
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Arguments
|
|
208
|
+
|
|
209
|
+
* value: Tuple with elements of type `datetime.date`. For an empty pre-selection of dates, pass an empty tuple.
|
|
210
|
+
* on_value: a callback function for when value changes. The callback function receives the new value as an argument.
|
|
211
|
+
* label: Text used to label the text field that triggers the datepicker.
|
|
212
|
+
* children: List of Elements to be rendered under the calendar. If empty, a close button is rendered.
|
|
213
|
+
* open_value: Controls and communicates the state of the datepicker. If True, the datepicker is open. If False, the datepicker is closed.
|
|
214
|
+
Intended to be used in conjunction with a custom set of controls to close the datepicker.
|
|
215
|
+
* on_open_value: a callback function for when open_value changes. Also receives the new value as an argument.
|
|
216
|
+
* date_format: Sets the format of the date displayed in the text field. Defaults to `"%Y/%m/%d"`. For more information,
|
|
217
|
+
see <a href="https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes" target="_blank">the Python documentation</a>.
|
|
218
|
+
* optional: Determines whether go show an error when value is `None`. If `True`, no error is shown.
|
|
219
|
+
* 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.
|
|
220
|
+
* style: CSS style to apply to the text field. Either a string or a dictionary of CSS properties (i.e. `{"property": "value"}`).
|
|
221
|
+
* classes: List of CSS classes to apply to the text field.
|
|
222
|
+
* date_picker_type: Sets the type of the datepicker. Use `"date"` for date selection or `"month"` for month selection. Defaults to `"date"`.
|
|
223
|
+
* min_date: Earliest allowed date/month (ISO 8601 format). If not specified, there is no limit.
|
|
224
|
+
* max_date: Latest allowed date/month (ISO 8601 format). If not specified, there is no limit.
|
|
225
|
+
* sort: If True, selected dates will be sorted in ascending order, regardless of the order they were picked. If False, preserves the order the
|
|
226
|
+
dates were selected.
|
|
227
|
+
|
|
228
|
+
## A More Advanced Example
|
|
229
|
+
|
|
230
|
+
```solara
|
|
231
|
+
import solara
|
|
232
|
+
import solara.lab
|
|
233
|
+
import datetime as dt
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
@solara.component
|
|
237
|
+
def Page():
|
|
238
|
+
date = solara.use_reactive(tuple([dt.date.today(), None]))
|
|
239
|
+
range_is_open = solara.use_reactive(False)
|
|
240
|
+
stay_length = solara.use_reactive(1)
|
|
241
|
+
|
|
242
|
+
def set_end_date(value):
|
|
243
|
+
if value and value[0]:
|
|
244
|
+
value = value[0]
|
|
245
|
+
second_date = value + dt.timedelta(days=stay_length.value)
|
|
246
|
+
date.set([value, second_date])
|
|
247
|
+
|
|
248
|
+
def book():
|
|
249
|
+
# Do some stuff here
|
|
250
|
+
range_is_open.set(False)
|
|
251
|
+
|
|
252
|
+
solara.use_memo(lambda: set_end_date(date.value), [stay_length.value])
|
|
253
|
+
|
|
254
|
+
with solara.Column(style="width: 400px;"):
|
|
255
|
+
solara.IntSlider("Length of stay", stay_length, min=1, max=10)
|
|
256
|
+
with solara.lab.InputDateRange(
|
|
257
|
+
date,
|
|
258
|
+
on_value=set_end_date,
|
|
259
|
+
open_value=range_is_open,
|
|
260
|
+
):
|
|
261
|
+
with solara.Row(justify="end", style="width: 100%;"):
|
|
262
|
+
solara.Button(
|
|
263
|
+
label="Book",
|
|
264
|
+
color="primary",
|
|
265
|
+
on_click=book,
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
```
|
|
269
|
+
"""
|
|
270
|
+
value_reactive = solara.use_reactive(value, on_value) # type: ignore
|
|
271
|
+
del value, on_value
|
|
272
|
+
|
|
273
|
+
if date_picker_type == "date":
|
|
274
|
+
internal_date_format = "%Y-%m-%d"
|
|
275
|
+
elif date_picker_type == "month":
|
|
276
|
+
internal_date_format = "%Y-%m"
|
|
277
|
+
else:
|
|
278
|
+
raise ValueError("date_picker_type must be either 'date' or 'month'.")
|
|
279
|
+
|
|
280
|
+
date_standard_strings = [date.strftime(internal_date_format) for date in value_reactive.value if date is not None]
|
|
281
|
+
datepicker_is_open = solara.use_reactive(open_value, on_open_value) # type: ignore
|
|
282
|
+
del open_value, on_open_value
|
|
283
|
+
style_flat = solara.util._flatten_style(style)
|
|
284
|
+
|
|
285
|
+
def dates_to_string(dates: Tuple[Optional[dt.date], Optional[dt.date]]):
|
|
286
|
+
string_dates = [date.strftime(date_format) if date is not None else "" for date in dates]
|
|
287
|
+
if (len(dates) < 2 or dates[1] is None) and not optional:
|
|
288
|
+
return string_dates[0], f"Please select two {date_picker_type}s"
|
|
289
|
+
return " - ".join(string_dates), None
|
|
290
|
+
|
|
291
|
+
def set_dates_cast(values):
|
|
292
|
+
date_value = cast(
|
|
293
|
+
Tuple[Optional[dt.date], Optional[dt.date]],
|
|
294
|
+
tuple([(dt.datetime.strptime(item, internal_date_format).date() if item is not None else None) for item in values]),
|
|
295
|
+
)
|
|
296
|
+
if len(date_value) > 1 and date_value[1] is not None:
|
|
297
|
+
datepicker_is_open.set(False)
|
|
298
|
+
|
|
299
|
+
if sort:
|
|
300
|
+
date_value = cast(Tuple[dt.date, dt.date], tuple(sorted(date_value)))
|
|
301
|
+
|
|
302
|
+
value_reactive.value = date_value
|
|
303
|
+
|
|
304
|
+
string_dates, error_message = dates_to_string(value_reactive.value)
|
|
305
|
+
|
|
306
|
+
if error_message:
|
|
307
|
+
label += f" ({error_message})"
|
|
308
|
+
input = solara.v.TextField(
|
|
309
|
+
label=label,
|
|
310
|
+
v_model=string_dates,
|
|
311
|
+
append_icon="mdi-calendar",
|
|
312
|
+
error=bool(error_message),
|
|
313
|
+
style_="min-width: 290px;" + style_flat,
|
|
314
|
+
readonly=True,
|
|
315
|
+
class_=", ".join(classes) if classes else "",
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
# We include closing on tab in case users want to skip the field with tab
|
|
319
|
+
use_close_menu(input, datepicker_is_open)
|
|
320
|
+
|
|
321
|
+
with solara.lab.Menu(
|
|
322
|
+
activator=input,
|
|
323
|
+
close_on_content_click=False,
|
|
324
|
+
open_value=datepicker_is_open,
|
|
325
|
+
use_activator_width=False,
|
|
326
|
+
):
|
|
327
|
+
with solara.v.DatePicker(
|
|
328
|
+
v_model=date_standard_strings,
|
|
329
|
+
on_v_model=set_dates_cast,
|
|
330
|
+
range=True,
|
|
331
|
+
first_day_of_week=first_day_of_the_week,
|
|
332
|
+
style_="width: 100%;",
|
|
333
|
+
max=max_date,
|
|
334
|
+
min=min_date,
|
|
335
|
+
type=date_picker_type,
|
|
336
|
+
):
|
|
337
|
+
if len(children) > 0:
|
|
338
|
+
for el in children:
|
|
339
|
+
solara.display(el)
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import datetime as dt
|
|
2
|
+
from typing import Callable, Dict, List, Optional, Union
|
|
3
|
+
|
|
4
|
+
import solara
|
|
5
|
+
import solara.lab
|
|
6
|
+
from solara.lab.components.input_date import use_close_menu
|
|
7
|
+
from solara.components.input import _use_input_type
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@solara.component
|
|
11
|
+
def InputTime(
|
|
12
|
+
value: Union[solara.Reactive[Optional[dt.time]], Optional[dt.time]],
|
|
13
|
+
on_value: Optional[Callable[[Optional[dt.time]], None]] = None,
|
|
14
|
+
label: str = "Pick a time",
|
|
15
|
+
children: List[solara.Element] = [],
|
|
16
|
+
open_value: Union[solara.Reactive[bool], bool] = False,
|
|
17
|
+
on_open_value: Optional[Callable[[bool], None]] = None,
|
|
18
|
+
optional: bool = False,
|
|
19
|
+
twelve_hour_clock: bool = False,
|
|
20
|
+
use_seconds: bool = False,
|
|
21
|
+
allowed_minutes: Optional[List[int]] = None,
|
|
22
|
+
style: Optional[Union[str, Dict[str, str]]] = None,
|
|
23
|
+
classes: Optional[List[str]] = None,
|
|
24
|
+
):
|
|
25
|
+
"""
|
|
26
|
+
Show a textfield, which when clicked, opens a timepicker. The input time should be of type `datetime.time`.
|
|
27
|
+
|
|
28
|
+
## Basic Example
|
|
29
|
+
|
|
30
|
+
```solara {pycafe-link}
|
|
31
|
+
import solara
|
|
32
|
+
import solara.lab
|
|
33
|
+
import datetime as dt
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@solara.component
|
|
37
|
+
def Page():
|
|
38
|
+
time = solara.use_reactive(dt.time(12, 0))
|
|
39
|
+
|
|
40
|
+
solara.lab.InputTime(time, allowed_minutes=[0, 15, 30, 45])
|
|
41
|
+
solara.Text(str(time.value))
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Arguments
|
|
45
|
+
|
|
46
|
+
* value: Reactive variable of type `datetime.time`, or `None`. This time is selected the first time the component is rendered.
|
|
47
|
+
* on_value: a callback function for when value changes. The callback function receives the new value as an argument.
|
|
48
|
+
* label: Text used to label the text field that triggers the timepicker.
|
|
49
|
+
* children: List of Elements to be rendered under the timepicker. If empty, a close button is rendered.
|
|
50
|
+
* open_value: Controls and communicates the state of the timepicker. If True, the timepicker is open. If False, the timepicker is closed.
|
|
51
|
+
Intended to be used in conjunction with a custom set of controls to close the timepicker.
|
|
52
|
+
* on_open_value: a callback function for when open_value changes. Also receives the new value as an argument.
|
|
53
|
+
* optional: Determines whether to show an error when value is `None`. If `True`, no error is shown.
|
|
54
|
+
* twelve_hour_clock: If `True`, the timepicker will display in 12-hour format. If `False`, the timepicker will display in 24-hour format.
|
|
55
|
+
* use_seconds: If `True`, the timepicker will allow input of seconds.
|
|
56
|
+
* allowed_minutes: List of allowed minutes for the timepicker. Restricts the input to specific minute intervals.
|
|
57
|
+
* style: CSS style to apply to the text field. Either a string or a dictionary of CSS properties (i.e. `{"property": "value"}`).
|
|
58
|
+
* classes: List of CSS classes to apply to the text field.
|
|
59
|
+
"""
|
|
60
|
+
time_format_internal = f"%H:%M{':%S' if use_seconds else ''}"
|
|
61
|
+
time_format_display = f"%H:%M{':%S' if use_seconds else ''}"
|
|
62
|
+
if twelve_hour_clock:
|
|
63
|
+
time_format_display = f"%I:%M{':%S' if use_seconds else ''} %p"
|
|
64
|
+
value_reactive = solara.use_reactive(value, on_value) # type: ignore
|
|
65
|
+
del value, on_value
|
|
66
|
+
timepicker_is_open = solara.use_reactive(open_value, on_open_value) # type: ignore
|
|
67
|
+
del open_value, on_open_value
|
|
68
|
+
|
|
69
|
+
def set_time_typed_cast(value: Optional[str]):
|
|
70
|
+
if value:
|
|
71
|
+
try:
|
|
72
|
+
time_value = dt.datetime.strptime(value, time_format_display).time()
|
|
73
|
+
return time_value
|
|
74
|
+
except ValueError:
|
|
75
|
+
raise ValueError(f"Time {value} does not match format {time_format_display.replace('%', '')}")
|
|
76
|
+
elif optional:
|
|
77
|
+
return None
|
|
78
|
+
else:
|
|
79
|
+
raise ValueError("Time cannot be empty")
|
|
80
|
+
|
|
81
|
+
def time_to_str(time: Optional[dt.time]) -> str:
|
|
82
|
+
if time is not None:
|
|
83
|
+
return time.strftime(time_format_display)
|
|
84
|
+
return ""
|
|
85
|
+
|
|
86
|
+
def set_time_cast(new_value: Optional[str]):
|
|
87
|
+
if new_value:
|
|
88
|
+
time_value = dt.datetime.strptime(new_value, time_format_internal).time()
|
|
89
|
+
value_reactive.value = time_value
|
|
90
|
+
|
|
91
|
+
def standard_strfy(time: Optional[dt.time]):
|
|
92
|
+
if time is None:
|
|
93
|
+
return None
|
|
94
|
+
else:
|
|
95
|
+
return time.strftime(time_format_internal)
|
|
96
|
+
|
|
97
|
+
time_standard_str = standard_strfy(value_reactive.value)
|
|
98
|
+
|
|
99
|
+
style_flat = solara.util._flatten_style(style)
|
|
100
|
+
|
|
101
|
+
internal_value, error_message, set_value_cast = _use_input_type(value_reactive, set_time_typed_cast, time_to_str)
|
|
102
|
+
|
|
103
|
+
if error_message:
|
|
104
|
+
label += f" ({error_message})"
|
|
105
|
+
input = solara.v.TextField(
|
|
106
|
+
label=label,
|
|
107
|
+
v_model=internal_value,
|
|
108
|
+
on_v_model=set_value_cast,
|
|
109
|
+
append_icon="mdi-clock",
|
|
110
|
+
error=bool(error_message),
|
|
111
|
+
style_="min-width: 290px;" + style_flat,
|
|
112
|
+
class_=", ".join(classes) if classes else "",
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
use_close_menu(input, timepicker_is_open)
|
|
116
|
+
|
|
117
|
+
with solara.lab.Menu(
|
|
118
|
+
activator=input,
|
|
119
|
+
close_on_content_click=False,
|
|
120
|
+
open_value=timepicker_is_open,
|
|
121
|
+
use_activator_width=False,
|
|
122
|
+
):
|
|
123
|
+
with solara.v.TimePicker(
|
|
124
|
+
ampm_in_title=twelve_hour_clock,
|
|
125
|
+
v_model=time_standard_str,
|
|
126
|
+
on_v_model=set_time_cast,
|
|
127
|
+
format="24hr" if not twelve_hour_clock else "ampm",
|
|
128
|
+
allowed_minutes=allowed_minutes,
|
|
129
|
+
use_seconds=use_seconds,
|
|
130
|
+
style_="width: 100%;",
|
|
131
|
+
):
|
|
132
|
+
if len(children) > 0:
|
|
133
|
+
solara.display(*children)
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
from typing import Callable, Dict, List, Optional, Union
|
|
2
|
+
|
|
3
|
+
import solara
|
|
4
|
+
from solara.components.component_vue import component_vue
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@component_vue("menu.vue")
|
|
8
|
+
def MenuWidget(
|
|
9
|
+
activator: List[solara.Element],
|
|
10
|
+
show_menu: bool,
|
|
11
|
+
on_show_menu: Optional[Callable] = None,
|
|
12
|
+
close_on_content_click: bool = True,
|
|
13
|
+
children: List[solara.Element] = [],
|
|
14
|
+
style: Optional[str] = None,
|
|
15
|
+
context: bool = False,
|
|
16
|
+
use_absolute: bool = True,
|
|
17
|
+
use_activator_width: bool = True,
|
|
18
|
+
):
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@solara.component
|
|
23
|
+
def ClickMenu(
|
|
24
|
+
activator: Union[solara.Element, List[solara.Element]],
|
|
25
|
+
open_value: Union[solara.Reactive[bool], bool] = False,
|
|
26
|
+
on_open_value: Optional[Callable] = None,
|
|
27
|
+
children: List[solara.Element] = [],
|
|
28
|
+
style: Optional[Union[str, Dict[str, str]]] = None,
|
|
29
|
+
):
|
|
30
|
+
"""
|
|
31
|
+
Show a pop-up menu by clicking on the `activator` element. The menu appears at the cursor position.
|
|
32
|
+
|
|
33
|
+
```solara
|
|
34
|
+
import solara
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@solara.component
|
|
38
|
+
def Page():
|
|
39
|
+
image_url = "/static/public/beach.jpeg"
|
|
40
|
+
image = solara.Image(image=image_url)
|
|
41
|
+
|
|
42
|
+
with solara.lab.ClickMenu(activator=image):
|
|
43
|
+
with solara.Column(gap="0px"):
|
|
44
|
+
[solara.Button(f"Click me {i}!", text=True) for i in range(5)]
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
## Arguments
|
|
50
|
+
|
|
51
|
+
* activator: Clicking on this element will open the menu. Accepts either a `solara.Element`, or a list of elements.
|
|
52
|
+
* open_value: Controls and communicates the state of the menu. If True, the menu is open. If False, the menu is closed.
|
|
53
|
+
* on_open_value: Function to call when the menu is opened or closed.
|
|
54
|
+
* menu_contents: List of Elements to be contained in the menu.
|
|
55
|
+
* style: CSS style to apply. Applied directly onto the `v-menu` component.
|
|
56
|
+
"""
|
|
57
|
+
open_reactive = solara.use_reactive(open_value, on_open_value)
|
|
58
|
+
del open_value
|
|
59
|
+
|
|
60
|
+
style_flat = solara.util._flatten_style(style)
|
|
61
|
+
|
|
62
|
+
if not isinstance(activator, list):
|
|
63
|
+
activator = [activator]
|
|
64
|
+
|
|
65
|
+
return MenuWidget(
|
|
66
|
+
activator=activator,
|
|
67
|
+
children=children,
|
|
68
|
+
show_menu=open_reactive.value,
|
|
69
|
+
on_show_menu=open_reactive.set,
|
|
70
|
+
style=style_flat,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@solara.component
|
|
75
|
+
def ContextMenu(
|
|
76
|
+
activator: Union[solara.Element, List[solara.Element]],
|
|
77
|
+
open_value: Union[solara.Reactive[bool], bool] = False,
|
|
78
|
+
on_open_value: Optional[Callable] = None,
|
|
79
|
+
children: List[solara.Element] = [],
|
|
80
|
+
style: Optional[Union[str, Dict[str, str]]] = None,
|
|
81
|
+
):
|
|
82
|
+
"""
|
|
83
|
+
Show a context menu by triggering the contextmenu event on the `activator` element. The menu appears at the cursor position.
|
|
84
|
+
|
|
85
|
+
A contextmenu event is typically triggered by clicking the right mouse button, or by pressing the context menu key.
|
|
86
|
+
|
|
87
|
+
```solara
|
|
88
|
+
import solara
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@solara.component
|
|
92
|
+
def Page():
|
|
93
|
+
image_url = "/static/public/beach.jpeg"
|
|
94
|
+
image = solara.Image(image=image_url)
|
|
95
|
+
|
|
96
|
+
with solara.lab.ContextMenu(activator=image):
|
|
97
|
+
with solara.Column(gap="0px"):
|
|
98
|
+
[solara.Button(f"Click me {i}!", text=True) for i in range(5)]
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Arguments
|
|
103
|
+
|
|
104
|
+
* activator: Clicking on this element will open the menu. Accepts either a `solara.Element`, or a list of elements.
|
|
105
|
+
* open_value: Controls and communicates the state of the menu. If True, the menu is open. If False, the menu is closed.
|
|
106
|
+
* on_open_value: Function to call when the menu is opened or closed.
|
|
107
|
+
* children: List of Elements to be contained in the menu
|
|
108
|
+
* style: CSS style to apply. Applied directly onto the `v-menu` component.
|
|
109
|
+
"""
|
|
110
|
+
open_reactive = solara.use_reactive(open_value, on_open_value)
|
|
111
|
+
del open_value
|
|
112
|
+
style_flat = solara.util._flatten_style(style)
|
|
113
|
+
|
|
114
|
+
if not isinstance(activator, list):
|
|
115
|
+
activator = [activator]
|
|
116
|
+
|
|
117
|
+
return MenuWidget(
|
|
118
|
+
activator=activator,
|
|
119
|
+
children=children,
|
|
120
|
+
show_menu=open_reactive.value,
|
|
121
|
+
on_show_menu=open_reactive.set,
|
|
122
|
+
style=style_flat,
|
|
123
|
+
context=True,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
@solara.component
|
|
128
|
+
def Menu(
|
|
129
|
+
activator: Union[solara.Element, List[solara.Element]],
|
|
130
|
+
open_value: Union[solara.Reactive[bool], bool] = False,
|
|
131
|
+
on_open_value: Optional[Callable] = None,
|
|
132
|
+
close_on_content_click: bool = True,
|
|
133
|
+
children: List[solara.Element] = [],
|
|
134
|
+
style: Optional[Union[str, Dict[str, str]]] = None,
|
|
135
|
+
use_activator_width: bool = True,
|
|
136
|
+
):
|
|
137
|
+
"""
|
|
138
|
+
Show a pop-up menu by clicking on the `activator` element. The menu appears below the `activator` element.
|
|
139
|
+
|
|
140
|
+
```solara
|
|
141
|
+
import solara
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
@solara.component
|
|
145
|
+
def Page():
|
|
146
|
+
btn = solara.Button("Show suboptions")
|
|
147
|
+
|
|
148
|
+
with solara.lab.Menu(activator=btn):
|
|
149
|
+
with solara.Column(gap="0px"):
|
|
150
|
+
[solara.Button(f"Click me {str(i)}!", text=True) for i in range(5)]
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Arguments
|
|
155
|
+
|
|
156
|
+
* activator: Clicking on this element will open the menu. Accepts either a `solara.Element`, or a list of elements.
|
|
157
|
+
* open_value: Controls and communicates the state of the menu. If True, the menu is open. If False, the menu is closed.
|
|
158
|
+
* on_open_value: Function to call when the menu is opened or closed.
|
|
159
|
+
* children: List of Elements to be contained in the menu
|
|
160
|
+
* style: CSS style to apply. Applied directly onto the `v-menu` component.
|
|
161
|
+
* use_activator_width: If True, the menu will have a minimum width equal to the activator element.
|
|
162
|
+
If False, the menu width will be determined by the content.
|
|
163
|
+
"""
|
|
164
|
+
open_reactive = solara.use_reactive(open_value, on_open_value)
|
|
165
|
+
del open_value
|
|
166
|
+
|
|
167
|
+
style_flat = solara.util._flatten_style(style)
|
|
168
|
+
|
|
169
|
+
if not isinstance(activator, list):
|
|
170
|
+
activator = [activator]
|
|
171
|
+
|
|
172
|
+
return MenuWidget(
|
|
173
|
+
activator=activator,
|
|
174
|
+
children=children,
|
|
175
|
+
show_menu=open_reactive.value,
|
|
176
|
+
on_show_menu=open_reactive.set,
|
|
177
|
+
close_on_content_click=close_on_content_click,
|
|
178
|
+
style=style_flat,
|
|
179
|
+
use_absolute=False,
|
|
180
|
+
use_activator_width=use_activator_width,
|
|
181
|
+
)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-menu
|
|
3
|
+
v-model="show_menu"
|
|
4
|
+
:absolute="use_absolute"
|
|
5
|
+
offset-y
|
|
6
|
+
:close-on-content-click="close_on_content_click"
|
|
7
|
+
:min-width="use_activator_width ? null : 'auto'"
|
|
8
|
+
>
|
|
9
|
+
<template v-if="context" v-slot:activator="{ on }">
|
|
10
|
+
<div v-for="(element, index) in activator"
|
|
11
|
+
:key="index"
|
|
12
|
+
@contextmenu.prevent="show($event, on)">
|
|
13
|
+
<jupyter-widget :widget="element"></jupyter-widget>
|
|
14
|
+
</div>
|
|
15
|
+
</template>
|
|
16
|
+
<template v-else v-slot:activator="{ on }">
|
|
17
|
+
<jupyter-widget :widget="element" v-for="(element, index) in activator" :key="index" @click.native="on.click"></jupyter-widget>
|
|
18
|
+
</template>
|
|
19
|
+
<v-list v-for="(element, index) in children" :key="index" style="padding: 0;">
|
|
20
|
+
<jupyter-widget :widget="element" :style="style" ></jupyter-widget>
|
|
21
|
+
</v-list>
|
|
22
|
+
</v-menu>
|
|
23
|
+
</template>
|
|
24
|
+
|
|
25
|
+
<script>
|
|
26
|
+
module.exports = {
|
|
27
|
+
methods: {
|
|
28
|
+
show(e, on) {
|
|
29
|
+
// hide menu, and trigger the event on the next tick, otherwise vue does not see
|
|
30
|
+
// `show_menu` changing and will no do any animation
|
|
31
|
+
this.show_menu = false;
|
|
32
|
+
this.$nextTick(() => {
|
|
33
|
+
on.click(e)
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
</script>
|