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,49 @@
|
|
|
1
|
+
# Disabled, sometimes crashes the webpage.
|
|
2
|
+
# import ipycanvas
|
|
3
|
+
# import numpy as np
|
|
4
|
+
# import solara
|
|
5
|
+
# from reacton import ipycanvas as c
|
|
6
|
+
# from reacton import ipywidgets as w
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# def polygon(canvas, x, y, radius1, radius2, n_points):
|
|
10
|
+
# index = np.arange(n_points)
|
|
11
|
+
# angles = (2 * np.pi / n_points) * index
|
|
12
|
+
|
|
13
|
+
# radius = np.where(index % 2, radius1, radius2)
|
|
14
|
+
# v_x = x + np.cos(angles) * radius
|
|
15
|
+
# v_y = y + np.sin(angles) * radius
|
|
16
|
+
|
|
17
|
+
# points = np.stack((v_x, v_y), axis=1)
|
|
18
|
+
|
|
19
|
+
# canvas.fill_polygon(points)
|
|
20
|
+
# canvas.stroke_polygon(points)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# @solara.component
|
|
24
|
+
# def Page():
|
|
25
|
+
# width, height = 800, 800
|
|
26
|
+
# view_count, set_view_count = solara.use_state(0)
|
|
27
|
+
# with w.ViewcountVBox(set_view_count) as main:
|
|
28
|
+
# fill = w.color("#63934e", "fill color")
|
|
29
|
+
# stroke = w.color("#4e6393", "stroke color")
|
|
30
|
+
# line_width = w.slider_int(4, description="line width", min=0, max=30)
|
|
31
|
+
# n_points = w.slider_int(5, "Points", min=1, max=8) * 2
|
|
32
|
+
# radius_inner = w.slider_float(30, "Inner radius", min=0, max=100)
|
|
33
|
+
# radius_outer = w.slider_float(80, "Outer radius", min=0, max=100)
|
|
34
|
+
|
|
35
|
+
# def real_drawing():
|
|
36
|
+
# canvas: ipycanvas.Canvas = solara.core.get_widget(canvas_element)
|
|
37
|
+
|
|
38
|
+
# with ipycanvas.hold_canvas(canvas):
|
|
39
|
+
# canvas.clear()
|
|
40
|
+
# canvas.fill_style = fill
|
|
41
|
+
# canvas.stroke_style = stroke
|
|
42
|
+
# canvas.line_width = line_width
|
|
43
|
+
# radius = width // 3
|
|
44
|
+
# polygon(canvas, width // 2, height // 2, radius * radius_inner / 100, radius * radius_outer / 100, n_points)
|
|
45
|
+
|
|
46
|
+
# solara.use_effect(real_drawing, [fill, stroke, line_width, n_points, view_count, radius_inner, radius_outer])
|
|
47
|
+
# canvas_element = c.Canvas(width=width, height=height)
|
|
48
|
+
|
|
49
|
+
# return main
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""# Altair
|
|
2
|
+
|
|
3
|
+
[Altair](https://altair-viz.github.io/index.html) is a declarative statistical visualization library for Python.
|
|
4
|
+
|
|
5
|
+
This example show how to use the [on_click handler](/documentation/components/viz/altair) to display data for a specific day in the chart.
|
|
6
|
+
|
|
7
|
+
Based on [an Altair example](https://altair-viz.github.io/gallery/annual_weather_heatmap.html)
|
|
8
|
+
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import altair as alt
|
|
12
|
+
import pandas as pd
|
|
13
|
+
import solara
|
|
14
|
+
from vega_datasets import data
|
|
15
|
+
|
|
16
|
+
# title = "Altair visualization"
|
|
17
|
+
source = data.seattle_weather()
|
|
18
|
+
|
|
19
|
+
selected_datum = solara.reactive(None)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@solara.component
|
|
23
|
+
def Page():
|
|
24
|
+
def on_click(datum):
|
|
25
|
+
selected_datum.value = datum
|
|
26
|
+
|
|
27
|
+
chart = (
|
|
28
|
+
alt.Chart(source, title="Daily Max Temperatures (C) in Seattle, WA")
|
|
29
|
+
.mark_rect()
|
|
30
|
+
.encode(
|
|
31
|
+
alt.X("date(date):O").title("Day").axis(format="%e", labelAngle=0),
|
|
32
|
+
alt.Y("month(date):O").title("Month"),
|
|
33
|
+
alt.Color("max(temp_max)").title(None),
|
|
34
|
+
tooltip=[
|
|
35
|
+
alt.Tooltip("monthdate(date)", title="Date"),
|
|
36
|
+
alt.Tooltip("max(temp_max)", title="Max Temp"),
|
|
37
|
+
],
|
|
38
|
+
)
|
|
39
|
+
.configure_view(step=13, strokeWidth=0)
|
|
40
|
+
.configure_axis(domain=False)
|
|
41
|
+
.properties(width="container")
|
|
42
|
+
)
|
|
43
|
+
with solara.Card("Annual Weather Heatmap for Seattle, WA"):
|
|
44
|
+
solara.AltairChart(chart, on_click=on_click)
|
|
45
|
+
df = source
|
|
46
|
+
if selected_datum.value:
|
|
47
|
+
month_date = selected_datum.value["monthdate_date_end"]
|
|
48
|
+
dt = pd.to_datetime(month_date)
|
|
49
|
+
df = df[(df["date"].dt.month == dt.month) & (df["date"].dt.day == dt.day)]
|
|
50
|
+
solara.Markdown(f"Day of year: {dt.month_name()} - {dt.day}")
|
|
51
|
+
solara.Button("Clear selection", on_click=lambda: selected_datum.set(None))
|
|
52
|
+
solara.display(df)
|
|
53
|
+
|
|
54
|
+
with solara.Details("Click data"):
|
|
55
|
+
solara.Markdown(
|
|
56
|
+
f"""
|
|
57
|
+
Click data:
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
{selected_datum.value}
|
|
61
|
+
```
|
|
62
|
+
"""
|
|
63
|
+
)
|
|
64
|
+
else:
|
|
65
|
+
solara.Markdown("Click on the chart to see data for a specific day")
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""
|
|
2
|
+
# bqplot
|
|
3
|
+
|
|
4
|
+
[bqplot](https://github.com/bqplot/bqplot) is a 2-D visualization system for Jupyter, based on the constructs of the Grammar of Graphics.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
import reacton.bqplot as bqplot
|
|
9
|
+
|
|
10
|
+
import solara
|
|
11
|
+
|
|
12
|
+
x0 = np.linspace(0, 2, 100)
|
|
13
|
+
|
|
14
|
+
exponent = solara.reactive(1.0)
|
|
15
|
+
log_scale = solara.reactive(False)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@solara.component
|
|
19
|
+
def Page(x=x0, ymax=5):
|
|
20
|
+
y = x**exponent.value
|
|
21
|
+
color = "red"
|
|
22
|
+
display_legend = True
|
|
23
|
+
label = "bqplot graph"
|
|
24
|
+
|
|
25
|
+
solara.SliderFloat(value=exponent, min=0.1, max=3, label="Exponent")
|
|
26
|
+
solara.Checkbox(value=log_scale, label="Log scale")
|
|
27
|
+
|
|
28
|
+
x_scale = bqplot.LinearScale()
|
|
29
|
+
if log_scale.value:
|
|
30
|
+
y_scale = bqplot.LogScale(min=0.1, max=ymax)
|
|
31
|
+
else:
|
|
32
|
+
y_scale = bqplot.LinearScale(min=0, max=ymax)
|
|
33
|
+
|
|
34
|
+
lines = bqplot.Lines(x=x, y=y, scales={"x": x_scale, "y": y_scale}, stroke_width=3, colors=[color], display_legend=display_legend, labels=[label])
|
|
35
|
+
x_axis = bqplot.Axis(scale=x_scale)
|
|
36
|
+
y_axis = bqplot.Axis(scale=y_scale, orientation="vertical")
|
|
37
|
+
bqplot.Figure(axes=[x_axis, y_axis], marks=[lines], scale_x=x_scale, scale_y=y_scale, layout={"max_width": "100%", "width": "100%"})
|
|
38
|
+
|
|
39
|
+
# return main
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""
|
|
2
|
+
# ipyleaflet
|
|
3
|
+
Map visualization using [ipyleaflet](https://ipyleaflet.readthedocs.io/), a ipywidgets wrapper for [leaflet.js](https://leafletjs.com/)
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import ipyleaflet
|
|
7
|
+
|
|
8
|
+
import solara
|
|
9
|
+
|
|
10
|
+
zoom = solara.reactive(5)
|
|
11
|
+
center = solara.reactive((53.2305799, 6.5323552))
|
|
12
|
+
bounds = solara.reactive(None)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@solara.component
|
|
16
|
+
def Page():
|
|
17
|
+
# Isolation is required to prevent the map from overlapping navigation (when screen width < 960px)
|
|
18
|
+
with solara.Column(style={"width": "100%", "height": "500px", "isolation": "isolate"}):
|
|
19
|
+
# solara components support reactive variables
|
|
20
|
+
solara.SliderInt(label="Zoom level", value=zoom, min=1, max=20)
|
|
21
|
+
# using 3rd party widget library require wiring up the events manually
|
|
22
|
+
# using zoom.value and zoom.set
|
|
23
|
+
ipyleaflet.Map.element( # type: ignore
|
|
24
|
+
zoom=zoom.value,
|
|
25
|
+
on_zoom=zoom.set,
|
|
26
|
+
center=center.value,
|
|
27
|
+
on_center=center.set,
|
|
28
|
+
on_bounds=bounds.set,
|
|
29
|
+
scroll_wheel_zoom=True,
|
|
30
|
+
)
|
|
31
|
+
solara.Text(f"Zoom: {zoom.value}")
|
|
32
|
+
solara.Text(f"Center: {center.value}")
|
|
33
|
+
solara.Text(f"Bounds: {bounds.value}")
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""
|
|
2
|
+
# ipyleaflet advanced
|
|
3
|
+
|
|
4
|
+
Extends the [basic ipyleaflet example](/documentation/examples/libraries/ipyleaflet) with a marker that can be dragged around, and a
|
|
5
|
+
dropdown to select the map style. Two buttons allow to reset the map to the default zoom and center and to zoom
|
|
6
|
+
to the marker.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import ipyleaflet
|
|
10
|
+
|
|
11
|
+
import solara
|
|
12
|
+
|
|
13
|
+
center_default = (53.2305799, 6.5323552)
|
|
14
|
+
zoom_default = 5
|
|
15
|
+
maps = {
|
|
16
|
+
"OpenStreetMap.Mapnik": ipyleaflet.basemaps.OpenStreetMap.Mapnik,
|
|
17
|
+
"OpenTopoMap": ipyleaflet.basemaps.OpenTopoMap,
|
|
18
|
+
"Esri.WorldTopoMap": ipyleaflet.basemaps.Esri.WorldTopoMap,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
zoom = solara.reactive(zoom_default)
|
|
22
|
+
center = solara.reactive(center_default)
|
|
23
|
+
marker_location = solara.reactive(center_default)
|
|
24
|
+
|
|
25
|
+
map_name = solara.reactive(list(maps)[0])
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@solara.component
|
|
29
|
+
def Page():
|
|
30
|
+
def location_changed(location):
|
|
31
|
+
# do things with the location
|
|
32
|
+
marker_location.set(location)
|
|
33
|
+
|
|
34
|
+
with solara.Column(style={"width": "100%", "height": "500px"}):
|
|
35
|
+
solara.Markdown(f"Market set to: {marker_location.value}", style={"color": "#6e6e6e"})
|
|
36
|
+
|
|
37
|
+
map = maps[map_name.value]
|
|
38
|
+
url = map.build_url()
|
|
39
|
+
|
|
40
|
+
def goto_marker():
|
|
41
|
+
center.value = marker_location.value
|
|
42
|
+
zoom.value = 13
|
|
43
|
+
|
|
44
|
+
def reset_view():
|
|
45
|
+
center.value = center_default
|
|
46
|
+
zoom.value = zoom_default
|
|
47
|
+
|
|
48
|
+
solara.Select(label="Map", value=map_name, values=list(maps))
|
|
49
|
+
solara.SliderInt(label="Zoom level", value=zoom, min=1, max=20)
|
|
50
|
+
with solara.Row():
|
|
51
|
+
solara.Button(label="Zoom to marker", on_click=goto_marker)
|
|
52
|
+
solara.Button(label="Reset view", on_click=reset_view)
|
|
53
|
+
|
|
54
|
+
# Isolation is required to prevent the map from overlapping navigation (when screen width < 960px)
|
|
55
|
+
with solara.Column(style={"isolation": "isolate"}):
|
|
56
|
+
ipyleaflet.Map.element( # type: ignore
|
|
57
|
+
zoom=zoom.value,
|
|
58
|
+
on_zoom=zoom.set,
|
|
59
|
+
center=center.value,
|
|
60
|
+
on_center=center.set,
|
|
61
|
+
scroll_wheel_zoom=True,
|
|
62
|
+
layers=[
|
|
63
|
+
ipyleaflet.TileLayer.element(url=url),
|
|
64
|
+
ipyleaflet.Marker.element(location=marker_location.value, draggable=True, on_location=location_changed),
|
|
65
|
+
],
|
|
66
|
+
)
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"""# Calculator
|
|
2
|
+
|
|
3
|
+
This shows how to use `use_reducer` to implement a simple calculator.
|
|
4
|
+
|
|
5
|
+
Note that the `reducer` implements all the logic of the calculator, and the `Calculator` component is just a thin wrapper around it.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import ast
|
|
12
|
+
import dataclasses
|
|
13
|
+
import operator
|
|
14
|
+
from typing import Any, Optional
|
|
15
|
+
|
|
16
|
+
import solara
|
|
17
|
+
|
|
18
|
+
DEBUG = False
|
|
19
|
+
operator_map = {
|
|
20
|
+
"x": operator.mul,
|
|
21
|
+
"/": operator.truediv,
|
|
22
|
+
"+": operator.add,
|
|
23
|
+
"-": operator.sub,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclasses.dataclass(frozen=True)
|
|
28
|
+
class CalculatorState:
|
|
29
|
+
input: str = ""
|
|
30
|
+
output: str = ""
|
|
31
|
+
left: float = 0
|
|
32
|
+
right: Optional[float] = None
|
|
33
|
+
operator: Any = operator.add
|
|
34
|
+
error: str = ""
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
initial_state = CalculatorState()
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def calculate(state: CalculatorState):
|
|
41
|
+
result = state.operator(state.left, state.right)
|
|
42
|
+
return dataclasses.replace(state, left=result)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def calculator_reducer(state: CalculatorState, action):
|
|
46
|
+
action_type, payload = action
|
|
47
|
+
if DEBUG:
|
|
48
|
+
print("reducer", state, action_type, payload) # noqa
|
|
49
|
+
state = dataclasses.replace(state, error="")
|
|
50
|
+
|
|
51
|
+
if action_type == "digit":
|
|
52
|
+
digit = payload
|
|
53
|
+
input = state.input + digit
|
|
54
|
+
return dataclasses.replace(state, input=input, output=input)
|
|
55
|
+
elif action_type == "percent":
|
|
56
|
+
if state.input:
|
|
57
|
+
try:
|
|
58
|
+
value = ast.literal_eval(state.input)
|
|
59
|
+
except Exception as e:
|
|
60
|
+
return dataclasses.replace(state, error=str(e))
|
|
61
|
+
state = dataclasses.replace(state, right=value / 100)
|
|
62
|
+
state = calculate(state)
|
|
63
|
+
output = f"{value / 100:,}"
|
|
64
|
+
return dataclasses.replace(state, output=output, input="")
|
|
65
|
+
else:
|
|
66
|
+
output = f"{state.left / 100:,}"
|
|
67
|
+
return dataclasses.replace(state, left=state.left / 100, output=output)
|
|
68
|
+
elif action_type == "negate":
|
|
69
|
+
if state.input:
|
|
70
|
+
input = state.output
|
|
71
|
+
input = input[1:] if input[0] == "-" else "-" + input
|
|
72
|
+
output = input
|
|
73
|
+
return dataclasses.replace(state, input=input, output=output)
|
|
74
|
+
else:
|
|
75
|
+
output = f"{-state.left:,}"
|
|
76
|
+
return dataclasses.replace(state, left=-state.left, output=output)
|
|
77
|
+
elif action_type == "clear":
|
|
78
|
+
return dataclasses.replace(state, input="", output="")
|
|
79
|
+
elif action_type == "reset":
|
|
80
|
+
return initial_state
|
|
81
|
+
elif action_type == "calculate":
|
|
82
|
+
if state.input:
|
|
83
|
+
try:
|
|
84
|
+
value = ast.literal_eval(state.input)
|
|
85
|
+
except Exception as e:
|
|
86
|
+
return dataclasses.replace(state, error=str(e))
|
|
87
|
+
state = dataclasses.replace(state, right=value)
|
|
88
|
+
state = calculate(state)
|
|
89
|
+
output = f"{state.left:,}"
|
|
90
|
+
state = dataclasses.replace(state, output=output, input="")
|
|
91
|
+
return state
|
|
92
|
+
elif action_type == "operator":
|
|
93
|
+
if state.input:
|
|
94
|
+
state = calculator_reducer(state, ("calculate", None))
|
|
95
|
+
state = dataclasses.replace(state, operator=payload, input="")
|
|
96
|
+
else:
|
|
97
|
+
# e.g. 2+3=*= should give 5,25
|
|
98
|
+
state = dataclasses.replace(state, operator=payload, right=state.left)
|
|
99
|
+
return state
|
|
100
|
+
else:
|
|
101
|
+
print("invalid action", action) # noqa
|
|
102
|
+
return state
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@solara.component
|
|
106
|
+
def Calculator():
|
|
107
|
+
state, dispatch = solara.use_reducer(calculator_reducer, initial_state)
|
|
108
|
+
if DEBUG:
|
|
109
|
+
print("->", state) # noqa
|
|
110
|
+
with solara.Card("Calculator", elevation=10, classes=["ma-4"]) as main:
|
|
111
|
+
with solara.VBox(grow=False):
|
|
112
|
+
solara.Text(state.error or state.output or "0")
|
|
113
|
+
class_ = "pa-0 ma-1"
|
|
114
|
+
|
|
115
|
+
with solara.HBox(grow=False):
|
|
116
|
+
if state.input:
|
|
117
|
+
solara.Button("C", on_click=lambda: dispatch(("clear", None)), dark=True, class_=class_)
|
|
118
|
+
else:
|
|
119
|
+
solara.Button("AC", on_click=lambda: dispatch(("reset", None)), dark=True, class_=class_)
|
|
120
|
+
solara.Button("+/-", on_click=lambda: dispatch(("negate", None)), dark=True, class_=class_)
|
|
121
|
+
solara.Button("%", on_click=lambda: dispatch(("percent", None)), dark=True, class_=class_)
|
|
122
|
+
solara.Button("/", color="primary", on_click=lambda: dispatch(("operator", operator_map["/"])), class_=class_)
|
|
123
|
+
|
|
124
|
+
column_op = ["x", "-", "+"]
|
|
125
|
+
for i in range(3):
|
|
126
|
+
with solara.HBox(grow=False):
|
|
127
|
+
for j in range(3):
|
|
128
|
+
digit = str(j + (2 - i) * 3 + 1)
|
|
129
|
+
|
|
130
|
+
def on_click(digit=digit):
|
|
131
|
+
dispatch(("digit", digit))
|
|
132
|
+
|
|
133
|
+
solara.Button(digit, on_click=on_click, class_=class_)
|
|
134
|
+
op_symbol = column_op[i]
|
|
135
|
+
op = operator_map[op_symbol]
|
|
136
|
+
|
|
137
|
+
def on_click_op(op=op):
|
|
138
|
+
dispatch(("operator", op))
|
|
139
|
+
|
|
140
|
+
solara.Button(op_symbol, color="primary", on_click=on_click_op, class_=class_)
|
|
141
|
+
with solara.HBox(grow=False):
|
|
142
|
+
|
|
143
|
+
def boom():
|
|
144
|
+
print("boom") # noqa
|
|
145
|
+
raise ValueError("lala")
|
|
146
|
+
|
|
147
|
+
solara.Button("?", on_click=boom, class_=class_)
|
|
148
|
+
|
|
149
|
+
solara.Button("0", on_click=lambda: dispatch(("digit", "0")), class_=class_)
|
|
150
|
+
solara.Button(".", on_click=lambda: dispatch(("digit", ".")), class_=class_)
|
|
151
|
+
|
|
152
|
+
solara.Button("=", color="primary", on_click=lambda: dispatch(("calculate", None)), class_=class_)
|
|
153
|
+
|
|
154
|
+
return main
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
Page = Calculator
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""# Countdown timer.
|
|
2
|
+
|
|
3
|
+
This example shows how to use [use_thread](/documentation/api/hooks/use_thread) to create a countdown timer.
|
|
4
|
+
|
|
5
|
+
The UI code demonstrates a lot of conditional rendering.
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import time
|
|
10
|
+
|
|
11
|
+
import solara
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@solara.component
|
|
15
|
+
def Page():
|
|
16
|
+
seconds, set_seconds = solara.use_state(5)
|
|
17
|
+
running, set_running = solara.use_state(False)
|
|
18
|
+
duration, set_duration = solara.use_state(seconds)
|
|
19
|
+
|
|
20
|
+
def on_duration(duration):
|
|
21
|
+
try:
|
|
22
|
+
set_duration(int(duration))
|
|
23
|
+
set_seconds(int(duration))
|
|
24
|
+
except ValueError:
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
def run_timer():
|
|
28
|
+
if running:
|
|
29
|
+
time_start = time.time()
|
|
30
|
+
next_tick = time_start + 1
|
|
31
|
+
i = seconds
|
|
32
|
+
while i:
|
|
33
|
+
# instead of sleeping for 1 second, we sleep until the next second
|
|
34
|
+
# this takes into account overhead and makes the timer more accurate
|
|
35
|
+
time.sleep(max(0, next_tick - time.time()))
|
|
36
|
+
i -= 1
|
|
37
|
+
set_seconds(i)
|
|
38
|
+
next_tick += 1
|
|
39
|
+
set_running(False)
|
|
40
|
+
|
|
41
|
+
solara.use_thread(run_timer, dependencies=[duration, running])
|
|
42
|
+
|
|
43
|
+
if not running:
|
|
44
|
+
if duration < 1:
|
|
45
|
+
solara.Error("Duration must be at least 1 second")
|
|
46
|
+
else:
|
|
47
|
+
solara.Markdown(f"# Timer set to {seconds} seconds")
|
|
48
|
+
else:
|
|
49
|
+
if seconds:
|
|
50
|
+
solara.Markdown(f"# {seconds} seconds left")
|
|
51
|
+
else:
|
|
52
|
+
solara.solara.Markdown("# Time's up!")
|
|
53
|
+
|
|
54
|
+
solara.v.TextField(type="number", v_model=duration, on_v_model=on_duration, disabled=running)
|
|
55
|
+
with solara.Row():
|
|
56
|
+
if running:
|
|
57
|
+
solara.Button("Stop", on_click=lambda: set_running(False), icon_name="mdi-stop")
|
|
58
|
+
else:
|
|
59
|
+
if duration != seconds:
|
|
60
|
+
solara.Button("Reset", on_click=lambda: set_seconds(duration), icon_name="mdi-restart")
|
|
61
|
+
else:
|
|
62
|
+
solara.Button("Start", on_click=lambda: set_running(True), icon_name="mdi-play", disabled=seconds < 1)
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"""# Todo application
|
|
2
|
+
|
|
3
|
+
Demonstrates the use of reactive variables in combinations with dataclasses.
|
|
4
|
+
|
|
5
|
+
With solara we can get a type safe view onto a field in a dataclass, pydantic model, or
|
|
6
|
+
attr object.
|
|
7
|
+
|
|
8
|
+
This is using the experimental `solara.lab.Ref` class, which is not yet part of the
|
|
9
|
+
official API.
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
```python
|
|
13
|
+
import dataclasses
|
|
14
|
+
import solara
|
|
15
|
+
from solara.lab import Ref
|
|
16
|
+
|
|
17
|
+
@dataclasses.dataclass(frozen=True)
|
|
18
|
+
class TodoItem:
|
|
19
|
+
text: str
|
|
20
|
+
done: bool
|
|
21
|
+
|
|
22
|
+
todo_item = solara.reactive(TodoItem("Buy milk", False))
|
|
23
|
+
|
|
24
|
+
# now text is a reactive variable that is always in sync with todo_item.text
|
|
25
|
+
text = Ref(todo_item.fields.text)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# we can now modify the reactive text variable
|
|
29
|
+
# and see its value reflect in the todo_item
|
|
30
|
+
text.value = "Buy skimmed milk"
|
|
31
|
+
assert todo_item.value.text == "Buy skimmed milk"
|
|
32
|
+
|
|
33
|
+
# Or, the other way around
|
|
34
|
+
todo_item.value = TodoItem("Buy whole milk", False)
|
|
35
|
+
assert text.value == "Buy whole milk"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Apart from dataclasses, pydantic models etc, we also supports dictionaries and lists.
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
todo_items = solara.reactive([TodoItem("Buy milk", False), TodoItem("Buy eggs", False)])
|
|
42
|
+
todo_item_eggs = Ref(todo_items.fields[1])
|
|
43
|
+
todo_item_eggs.value = TodoItem("Buy eggs", True)
|
|
44
|
+
assert todo_items.value[1].done == True
|
|
45
|
+
|
|
46
|
+
# However, if a list becomes shorter, and the valid index is now out of range, the
|
|
47
|
+
# reactive variables will act as if it is "not connected", and will not trigger
|
|
48
|
+
# updates anymore. Accessing the value will raise an IndexError.
|
|
49
|
+
|
|
50
|
+
todo_items.value = [TodoItem("Buy milk", False)]
|
|
51
|
+
# anyone listening to todo_item_eggs will *not* be notified.
|
|
52
|
+
try:
|
|
53
|
+
value = todo_item_eggs.value
|
|
54
|
+
except IndexError:
|
|
55
|
+
print("this is expected")
|
|
56
|
+
else:
|
|
57
|
+
raise AssertionError("Expected an IndexError")
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
import dataclasses
|
|
63
|
+
from typing import Callable
|
|
64
|
+
|
|
65
|
+
import reacton.ipyvuetify as v
|
|
66
|
+
|
|
67
|
+
import solara
|
|
68
|
+
from solara.lab.toestand import Ref
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# our model for a todo item, immutable/frozen avoids common bugs
|
|
72
|
+
@dataclasses.dataclass(frozen=True)
|
|
73
|
+
class TodoItem:
|
|
74
|
+
text: str
|
|
75
|
+
done: bool
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@solara.component
|
|
79
|
+
def TodoEdit(todo_item: solara.Reactive[TodoItem], on_delete: Callable[[], None], on_close: Callable[[], None]):
|
|
80
|
+
"""Takes a reactive todo item and allows editing it. Will not modify the original item until 'save' is clicked."""
|
|
81
|
+
copy = solara.use_reactive(todo_item.value)
|
|
82
|
+
|
|
83
|
+
def save():
|
|
84
|
+
todo_item.value = copy.value
|
|
85
|
+
on_close()
|
|
86
|
+
|
|
87
|
+
with solara.Card("Edit", margin=0):
|
|
88
|
+
solara.InputText(label="", value=Ref(copy.fields.text))
|
|
89
|
+
with solara.CardActions():
|
|
90
|
+
v.Spacer()
|
|
91
|
+
solara.Button("Save", icon_name="mdi-content-save", on_click=save, outlined=True, text=True)
|
|
92
|
+
solara.Button("Close", icon_name="mdi-window-close", on_click=on_close, outlined=True, text=True)
|
|
93
|
+
solara.Button("Delete", icon_name="mdi-delete", on_click=on_delete, outlined=True, text=True)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@solara.component
|
|
97
|
+
def TodoListItem(todo_item: solara.Reactive[TodoItem], on_delete: Callable[[TodoItem], None]):
|
|
98
|
+
"""Displays a single todo item, modifications are done 'in place'.
|
|
99
|
+
|
|
100
|
+
For demonstration purposes, we allow editing the item in a dialog as well.
|
|
101
|
+
This will not modify the original item until 'save' is clicked.
|
|
102
|
+
"""
|
|
103
|
+
edit, set_edit = solara.use_state(False)
|
|
104
|
+
with v.ListItem():
|
|
105
|
+
solara.Button(icon_name="mdi-delete", icon=True, on_click=lambda: on_delete(todo_item.value))
|
|
106
|
+
solara.Checkbox(value=Ref(todo_item.fields.done)) # , color="success")
|
|
107
|
+
solara.InputText(label="", value=Ref(todo_item.fields.text))
|
|
108
|
+
solara.Button(icon_name="mdi-pencil", icon=True, on_click=lambda: set_edit(True))
|
|
109
|
+
with v.Dialog(v_model=edit, persistent=True, max_width="500px", on_v_model=set_edit):
|
|
110
|
+
if edit: # 'reset' the component state on open/close
|
|
111
|
+
|
|
112
|
+
def on_delete_in_edit():
|
|
113
|
+
on_delete(todo_item.value)
|
|
114
|
+
set_edit(False)
|
|
115
|
+
|
|
116
|
+
TodoEdit(todo_item, on_delete=on_delete_in_edit, on_close=lambda: set_edit(False))
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
@solara.component
|
|
120
|
+
def TodoNew(on_new: Callable[[TodoItem], None]):
|
|
121
|
+
"""Component that managed entering new todo items"""
|
|
122
|
+
new_text, set_new_text = solara.use_state("")
|
|
123
|
+
text_field = v.TextField(v_model=new_text, on_v_model=set_new_text, label="Enter a new todo item")
|
|
124
|
+
|
|
125
|
+
def create_new_item(*ignore_args):
|
|
126
|
+
if not new_text:
|
|
127
|
+
return
|
|
128
|
+
new_item = TodoItem(text=new_text, done=False)
|
|
129
|
+
on_new(new_item)
|
|
130
|
+
# reset text
|
|
131
|
+
set_new_text("")
|
|
132
|
+
|
|
133
|
+
v.use_event(text_field, "keydown.enter", create_new_item)
|
|
134
|
+
return text_field
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
initial_items = [
|
|
138
|
+
TodoItem("Learn Solara", done=True),
|
|
139
|
+
TodoItem("Write cool apps", done=False),
|
|
140
|
+
TodoItem("Relax", done=False),
|
|
141
|
+
]
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
# We store out reactive state, and our logic in a class for organization
|
|
145
|
+
# purposes, but this is not required.
|
|
146
|
+
# Note that all the above components do not refer to this class, but only
|
|
147
|
+
# to do the Todo items.
|
|
148
|
+
# This means all above components are reusable, and can be used in other
|
|
149
|
+
# places, while the components below use 'application'/'global' state.
|
|
150
|
+
# They are not suited for reuse.
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
class State:
|
|
154
|
+
todos = solara.reactive(initial_items)
|
|
155
|
+
|
|
156
|
+
@staticmethod
|
|
157
|
+
def on_new(item: TodoItem):
|
|
158
|
+
State.todos.value = [item] + State.todos.value
|
|
159
|
+
|
|
160
|
+
@staticmethod
|
|
161
|
+
def on_delete(item: TodoItem):
|
|
162
|
+
new_items = list(State.todos.value)
|
|
163
|
+
new_items.remove(item)
|
|
164
|
+
State.todos.value = new_items
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
@solara.component
|
|
168
|
+
def TodoStatus():
|
|
169
|
+
"""Status of our todo list"""
|
|
170
|
+
items = State.todos.value
|
|
171
|
+
count = len(items)
|
|
172
|
+
items_done = [item for item in items if item.done]
|
|
173
|
+
count_done = len(items_done)
|
|
174
|
+
|
|
175
|
+
if count != count_done:
|
|
176
|
+
with solara.Row():
|
|
177
|
+
percent = count_done / count * 100
|
|
178
|
+
solara.ProgressLinear(value=percent)
|
|
179
|
+
with solara.Row():
|
|
180
|
+
solara.Text(f"Remaining: {count - count_done}")
|
|
181
|
+
solara.Text(f"Completed: {count_done}")
|
|
182
|
+
else:
|
|
183
|
+
solara.Success("All done, awesome!", dense=True)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
@solara.component
|
|
187
|
+
def Page():
|
|
188
|
+
with solara.Card("Todo list", style="min-width: 500px"):
|
|
189
|
+
TodoNew(on_new=State.on_new)
|
|
190
|
+
if State.todos.value:
|
|
191
|
+
TodoStatus()
|
|
192
|
+
for index, item in enumerate(State.todos.value):
|
|
193
|
+
todo_item = Ref(State.todos.fields[index])
|
|
194
|
+
TodoListItem(todo_item, on_delete=State.on_delete)
|
|
195
|
+
else:
|
|
196
|
+
solara.Info("No todo items, enter some text above, and hit enter")
|