solara-ui 1.40.0__py2.py3-none-any.whl → 1.41.0__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. solara/__init__.py +1 -1
  2. solara/__main__.py +23 -10
  3. solara/components/component_vue.py +3 -2
  4. solara/server/assets/style.css +2 -0
  5. solara/server/qt.py +113 -0
  6. solara/server/settings.py +1 -0
  7. solara/server/static/main-vuetify.js +10 -0
  8. solara/server/static/solara_bootstrap.py +1 -1
  9. solara/server/templates/loader-solara.html +1 -1
  10. solara/server/templates/solara.html.j2 +6 -1
  11. solara/website/components/sidebar.py +3 -1
  12. solara/website/pages/__init__.py +13 -7
  13. solara/website/pages/documentation/advanced/content/20-understanding/40-routing.md +17 -1
  14. solara/website/pages/documentation/examples/__init__.py +13 -21
  15. solara/website/pages/documentation/examples/ai/chatbot.py +1 -1
  16. solara/website/pages/documentation/examples/general/vue_component.py +1 -1
  17. solara/website/pages/documentation/examples/libraries/altair.py +1 -0
  18. solara/website/pages/documentation/examples/libraries/bqplot.py +1 -1
  19. solara/website/pages/documentation/examples/libraries/ipyleaflet.py +1 -1
  20. solara/website/pages/documentation/examples/libraries/ipyleaflet_advanced.py +1 -1
  21. solara/website/pages/documentation/examples/utilities/countdown_timer.py +18 -20
  22. solara/website/pages/documentation/examples/visualization/annotator.py +1 -3
  23. solara/website/pages/documentation/examples/visualization/linked_views.py +4 -4
  24. solara/website/pages/documentation/getting_started/content/00-quickstart.md +18 -0
  25. solara/widgets/vue/navigator.vue +46 -16
  26. solara/widgets/vue/vegalite.vue +18 -0
  27. {solara_ui-1.40.0.dist-info → solara_ui-1.41.0.dist-info}/METADATA +1 -1
  28. {solara_ui-1.40.0.dist-info → solara_ui-1.41.0.dist-info}/RECORD +32 -31
  29. {solara_ui-1.40.0.data → solara_ui-1.41.0.data}/data/etc/jupyter/jupyter_notebook_config.d/solara.json +0 -0
  30. {solara_ui-1.40.0.data → solara_ui-1.41.0.data}/data/etc/jupyter/jupyter_server_config.d/solara.json +0 -0
  31. {solara_ui-1.40.0.dist-info → solara_ui-1.41.0.dist-info}/WHEEL +0 -0
  32. {solara_ui-1.40.0.dist-info → solara_ui-1.41.0.dist-info}/licenses/LICENSE +0 -0
solara/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  """Build webapps using IPywidgets"""
2
2
 
3
- __version__ = "1.40.0"
3
+ __version__ = "1.41.0"
4
4
  github_url = "https://github.com/widgetti/solara"
5
5
  git_branch = "master"
6
6
 
solara/__main__.py CHANGED
@@ -261,6 +261,12 @@ if "SOLARA_MODE" in os.environ:
261
261
  default=True,
262
262
  help="Check installed version again pypi version.",
263
263
  )
264
+ @click.option(
265
+ "--qt",
266
+ is_flag=True,
267
+ default=False,
268
+ help="Instead of opening a browser, open a Qt window. Will also stop the server when the window is closed. (experimental)",
269
+ )
264
270
  def run(
265
271
  app,
266
272
  host,
@@ -290,6 +296,7 @@ def run(
290
296
  ssg: bool,
291
297
  search: bool,
292
298
  check_version: bool = True,
299
+ qt=False,
293
300
  ):
294
301
  """Run a Solara app."""
295
302
  if dev is not None:
@@ -365,9 +372,16 @@ def run(
365
372
  while not failed and (server is None or not server.started):
366
373
  time.sleep(0.1)
367
374
  if not failed:
368
- webbrowser.open(url)
375
+ if qt:
376
+ from .server.qt import run_qt
369
377
 
370
- if open:
378
+ run_qt(url)
379
+ else:
380
+ webbrowser.open(url)
381
+
382
+ # with qt, we open the browser in the main thread (qt wants that)
383
+ # otherwise, we open the browser in a separate thread
384
+ if open and not qt:
371
385
  threading.Thread(target=open_browser, daemon=True).start()
372
386
 
373
387
  rich.print(f"Solara server is starting at {url}")
@@ -397,7 +411,7 @@ def run(
397
411
  settings.main.timing = timing
398
412
  items = (
399
413
  "theme_variant_user_selectable dark theme_variant theme_loader use_pdb server open_browser open url failed dev tracer"
400
- " timing ssg search check_version production".split()
414
+ " timing ssg search check_version production qt".split()
401
415
  )
402
416
  for item in items:
403
417
  del kwargs[item]
@@ -451,14 +465,13 @@ def run(
451
465
 
452
466
  build_index("")
453
467
 
454
- start_server()
455
-
456
468
  # TODO: if we want to use webview, it should be sth like this
457
- # server_thread = threading.Thread(target=start_server)
458
- # server_thread.start()
459
- # if open:
460
- # # open_webview()
461
- # open_browser()
469
+ if qt:
470
+ server_thread = threading.Thread(target=start_server, daemon=True)
471
+ server_thread.start()
472
+ open_browser()
473
+ else:
474
+ start_server()
462
475
  # server_thread.join()
463
476
 
464
477
 
@@ -1,4 +1,5 @@
1
1
  import inspect
2
+ import os
2
3
  from typing import Any, Callable, Dict, Type
3
4
 
4
5
  import ipyvue as vue
@@ -48,10 +49,10 @@ def _widget_from_signature(classname, base_class: Type[widgets.Widget], func: Ca
48
49
  def _widget_vue(vue_path: str, vuetify=True) -> Callable[[Callable[P, None]], Type[v.VuetifyTemplate]]:
49
50
  def decorator(func: Callable[P, None]):
50
51
  class VuetifyWidgetSolara(v.VuetifyTemplate):
51
- template_file = (inspect.getfile(func), vue_path)
52
+ template_file = (os.path.abspath(inspect.getfile(func)), vue_path)
52
53
 
53
54
  class VueWidgetSolara(vue.VueTemplate):
54
- template_file = (inspect.getfile(func), vue_path)
55
+ template_file = (os.path.abspath(inspect.getfile(func)), vue_path)
55
56
 
56
57
  base_class = VuetifyWidgetSolara if vuetify else VueWidgetSolara
57
58
  widget_class = _widget_from_signature("VueWidgetSolaraSub", base_class, func, "vue_")
@@ -1,6 +1,7 @@
1
1
  html {
2
2
  /* override vuetify's css reset ress.css */
3
3
  overflow-y: auto;
4
+ scroll-behavior: smooth;
4
5
  }
5
6
 
6
7
  .jupyter-widgets code {
@@ -124,6 +125,7 @@ div.highlight {
124
125
 
125
126
  .solara-autorouter-content {
126
127
  height: 100%;
128
+ max-width: 100%;
127
129
  }
128
130
 
129
131
  /* originally from index.css */
solara/server/qt.py ADDED
@@ -0,0 +1,113 @@
1
+ import sys
2
+ from typing import List
3
+ import webbrowser
4
+ from qtpy.QtWidgets import QApplication
5
+ from qtpy.QtWebEngineWidgets import QWebEngineView
6
+ from qtpy.QtWebChannel import QWebChannel
7
+ from qtpy import QtCore, QtGui
8
+ import signal
9
+ from pathlib import Path
10
+
11
+ HERE = Path(__file__).parent
12
+
13
+
14
+ # setUrlRequestInterceptor, navigationRequested and acceptNavigationRequest
15
+ # all trigger the websocket to disconnect, so we need to block cross origin
16
+ # requests on the frontend/browser side by intercepting clicks on links
17
+
18
+ cross_origin_block_js = """
19
+ var script = document.createElement('script');
20
+ script.src = 'qrc:///qtwebchannel/qwebchannel.js';
21
+ document.head.appendChild(script);
22
+ script.onload = function() {
23
+ new QWebChannel(qt.webChannelTransport, function(channel) {
24
+ let py_callback = channel.objects.py_callback;
25
+
26
+ document.addEventListener('click', function(event) {
27
+ let target = event.target;
28
+ while (target && target.tagName !== 'A') {
29
+ target = target.parentNode;
30
+ }
31
+
32
+ if (target && target.tagName === 'A') {
33
+ const linkOrigin = new URL(target.href).origin;
34
+ const currentOrigin = window.location.origin;
35
+
36
+ if (linkOrigin !== currentOrigin) {
37
+ event.preventDefault();
38
+ console.log("Blocked cross-origin navigation to:", target.href);
39
+ py_callback.open_link(target.href); // Call Python method
40
+ }
41
+ }
42
+ }, true);
43
+ });
44
+ };
45
+ """
46
+
47
+
48
+ class PyCallback(QtCore.QObject):
49
+ @QtCore.Slot(str)
50
+ def open_link(self, url):
51
+ webbrowser.open(url)
52
+
53
+
54
+ class QWebEngineViewWithPopup(QWebEngineView):
55
+ # keep a strong reference to all windows
56
+ windows: List = []
57
+
58
+ def __init__(self):
59
+ super().__init__()
60
+ self.page().newWindowRequested.connect(self.handle_new_window_request)
61
+
62
+ # Set up WebChannel and py_callback object
63
+ self.py_callback = PyCallback()
64
+ self.channel = QWebChannel()
65
+ self.channel.registerObject("py_callback", self.py_callback)
66
+ self.page().setWebChannel(self.channel)
67
+
68
+ self.loadFinished.connect(self._inject_javascript)
69
+
70
+ def _inject_javascript(self, ok):
71
+ self.page().runJavaScript(cross_origin_block_js)
72
+
73
+ def handle_new_window_request(self, info):
74
+ webview = QWebEngineViewWithPopup()
75
+ geometry = info.requestedGeometry()
76
+ webview.resize(geometry.width(), geometry.height())
77
+ webview.setUrl(info.requestedUrl())
78
+ webview.show()
79
+ QWebEngineViewWithPopup.windows.append(webview)
80
+ return webview
81
+
82
+
83
+ def run_qt(url):
84
+ app = QApplication([])
85
+ web = QWebEngineViewWithPopup()
86
+ web.setUrl(QtCore.QUrl(url))
87
+ web.resize(1024, 1024)
88
+ web.show()
89
+
90
+ app_name = "Solara"
91
+ app.setApplicationDisplayName(app_name)
92
+ app.setApplicationName(app_name)
93
+ web.setWindowTitle(app_name)
94
+ app.setWindowIcon(QtGui.QIcon(str(HERE.parent / "website/public/logo.svg")))
95
+ if sys.platform.startswith("darwin"):
96
+ # Set app name, if PyObjC is installed
97
+ # Python 2 has PyObjC preinstalled
98
+ # Python 3: pip3 install pyobjc-framework-Cocoa
99
+ try:
100
+ from Foundation import NSBundle
101
+
102
+ bundle = NSBundle.mainBundle()
103
+ if bundle:
104
+ app_info = bundle.localizedInfoDictionary() or bundle.infoDictionary()
105
+ if app_info is not None:
106
+ app_info["CFBundleName"] = app_name
107
+ app_info["CFBundleDisplayName"] = app_name
108
+ except ModuleNotFoundError:
109
+ pass
110
+
111
+ # without this, ctrl-c does not work in the terminal
112
+ signal.signal(signal.SIGINT, signal.SIG_DFL)
113
+ app.exec_()
solara/server/settings.py CHANGED
@@ -37,6 +37,7 @@ class ThemeVariant(str, Enum):
37
37
  class ThemeSettings(BaseSettings):
38
38
  variant: ThemeVariant = ThemeVariant.light
39
39
  loader: str = "solara"
40
+ show_banner: bool = True
40
41
 
41
42
  class Config:
42
43
  env_prefix = "solara_theme_"
@@ -138,15 +138,25 @@ async function solaraInit(mountId, appName) {
138
138
  });
139
139
 
140
140
  window.addEventListener('solara.router', function (event) {
141
+ app.$data.urlHasChanged = true;
141
142
  if(kernel.status == 'busy') {
142
143
  app.$data.loadingPage = true;
143
144
  }
144
145
  });
145
146
  kernel.statusChanged.connect(() => {
147
+ // When navigation is triggered from the front-end, kernel.status becoming busy and
148
+ // solara.router event happen in a different order than when navigating through Python, so
149
+ // if the URL has changed when the kernel becomes busy, we set loadingPage to true
150
+ if (kernel.status == 'busy' && app.$data.urlHasChanged) {
151
+ app.$data.loadingPage = true;
152
+ }
146
153
  // the first idle after a loadingPage == true (a router event)
147
154
  // will be used as indicator that the page is loaded
148
155
  if (app.$data.loadingPage && kernel.status == 'idle') {
149
156
  app.$data.loadingPage = false;
157
+ app.$data.urlHasChanged = false;
158
+ const event = new Event('solara.pageReady');
159
+ window.dispatchEvent(event);
150
160
  }
151
161
  });
152
162
 
@@ -119,7 +119,7 @@ async def main():
119
119
  ]
120
120
  for dep in requirements:
121
121
  await micropip.install(dep, keep_going=True)
122
- await micropip.install("/wheels/solara-1.40.0-py2.py3-none-any.whl", keep_going=True)
122
+ await micropip.install("/wheels/solara-1.41.0-py2.py3-none-any.whl", keep_going=True)
123
123
  import solara
124
124
 
125
125
  el = solara.Warning("lala")
@@ -32,7 +32,7 @@
32
32
  <jupyter-widget-mount-point mount-id="solara-main">
33
33
  A widget with mount-id="solara-main" should go here
34
34
  </jupyter-widget-mount-point>
35
- <div style="position: absolute; right: 0px; bottom: 0px; padding: 10px;">
35
+ <div v-if="showBanner" style="position: absolute; right: 0px; bottom: 0px; padding: 10px;">
36
36
  <b>This website runs on <a href="https://solara.dev">Solara</a></b>
37
37
  </div>
38
38
  </div>
@@ -172,7 +172,7 @@
172
172
  </script>
173
173
  {% endraw -%}
174
174
 
175
- <body data-base-url="{{root_path}}/static/">
175
+ <body data-base-url="{{root_path}}/jupyter/">
176
176
  {% if perform_check %}
177
177
  <iframe src="https://solara.dev/static/public/success.html?system=solara&check=html&version={{solara_version}}" style="display: none"></iframe>
178
178
  {% endif %}
@@ -296,6 +296,10 @@
296
296
  this.forceUpdateTrigger += 1;
297
297
  original_$forceUpdate();
298
298
  });
299
+ // in case we are showing a popop (e.g. using ipypopout), hide the banner
300
+ if(searchParams.has('modelid')) {
301
+ this.showBanner = false;
302
+ }
299
303
  },
300
304
  mounted() {
301
305
  document.querySelector('#app').removeAttribute("style");
@@ -413,6 +417,7 @@
413
417
  loadingPage: false,
414
418
  _lastBusyTimer: null,
415
419
  kernelBusyLong: false,
420
+ showBanner: theme.show_banner,
416
421
  // outputMessages: [{ name: 'stderr', text: 'lala' }],
417
422
  }
418
423
  }
@@ -15,7 +15,9 @@ def Sidebar():
15
15
  break
16
16
 
17
17
  with solara.v.List(
18
- expand=True, nav=True, style_="height: 100%; display: flex; flex-direction: column; background-color: var(--color-material-background);"
18
+ expand=True,
19
+ nav=True,
20
+ style_="height: 100%; max-height: 100vh; display: flex; flex-direction: column; background-color: var(--color-material-background); overflow-y: auto;",
19
21
  ) as main:
20
22
  with solara.v.ListItemGroup(v_model=router.path):
21
23
  # e.g. getting_started, examples, components, api, advanced, faq
@@ -280,13 +280,19 @@ def Layout(children=[]):
280
280
  justify="center" if route_current is not None and route_current.path in ["documentation", "showcase"] else "start",
281
281
  ):
282
282
  if route_current is not None and route_current.module is not None and hasattr(route_current.module, "Sidebar"):
283
- with solara.v.NavigationDrawer(
284
- clipped=True,
285
- class_="d-none d-md-block",
286
- height="unset",
287
- style_="min-height: calc(100vh - 64px);",
288
- width="20rem",
289
- v_model=True, # Forces menu to display even if it had somehow been closed
283
+ with solara.v.Sheet(
284
+ style_="""
285
+ height: 100vh;
286
+ width: 20rem;
287
+ overflow: auto;
288
+ border-right: 1px solid var(--color-border-appbar);
289
+ position: sticky;
290
+ top: 0;
291
+ flex-direction: column;
292
+ gap: 0;
293
+ """,
294
+ class_="d-md-flex d-none",
295
+ elevation=0,
290
296
  ):
291
297
  route_current.module.Sidebar()
292
298
  with rv.Col(
@@ -196,7 +196,7 @@ Note that all routes are relative, since a component does not know if it is embe
196
196
 
197
197
 
198
198
  Therefore you should never use the `route.path` for navigation since the route object has no knowledge of the full url
199
- (e.g. `/docs/basics/ipywigets`) but only knows its small piece of the pathname (e.g. `ipywidgets`)
199
+ (e.g. `/docs/basics/ipywidgets`) but only knows its small piece of the pathname (e.g. `ipywidgets`)
200
200
 
201
201
  Using [`resolve_path`](/documentation/api/routing/resolve_path) we can request the full url for navigation.
202
202
 
@@ -219,6 +219,22 @@ def LinkToIpywidgets():
219
219
  return main
220
220
  ```
221
221
 
222
+ ### Linking to Sections of a Page
223
+
224
+ The `solara.Link` component also supports linking to HTML elements identified by id. Although most Solara components don't directly support the id attribute, you can assign ids to all ipyvuetify components, using the `attributes` argument:
225
+
226
+ ```python
227
+ solara.v.Btn(attributes={"id": "my-id"}, ...)
228
+ ```
229
+
230
+ You can then link to a particular element by appending `#` followed by its id to your link, i.e. `solara.Link(route_or_path="/page#my-id")`. If you want the page to smoothly scroll to the linked element, you should give an element that contains it (for instance the `html`-element) the following CSS rule:
231
+
232
+ ```css
233
+ html {
234
+ scroll-behaviour: smooth;
235
+ }
236
+ ```
237
+
222
238
  ## Fully manual routing
223
239
 
224
240
  If you want to do routing fully manually, you can use the [`solara.use_router`](/documentation/api/routing/use_router) hook, and use the `.path` attribute.
@@ -25,28 +25,20 @@ def Layout(children):
25
25
  assert module is not None
26
26
  github_url = solara.util.github_url(module.__file__)
27
27
 
28
- with solara.HBox(grow=False) as main:
29
- if route_current.path == "fullscreen":
30
- with solara.Padding(4, children=children):
31
- pass
32
- else:
33
- with solara.VBox(grow=True, align_items="baseline"):
34
- doc = module.__doc__
35
- if doc:
36
- with solara.VBox(grow=True):
37
- MarkdownWithMetadata(doc)
38
- with solara.HBox():
39
- if route_current.path != "/":
40
- solara.Button("View source code on GitHub", icon_name="mdi-github-circle", href=github_url, class_="ma-2", target="_blank", text=True)
41
- # code = inspect.getsource(module)
42
-
43
- # code_quoted = urllib.parse.quote_plus(code)
44
- # url = f"https://test.solara.dev/try?code={code_quoted}"
45
- # solara.Button("Run on solara.dev", icon_name="mdi-pencil", href=url, class_="ma-2", target="_blank")
46
- # with solara.HBox():
28
+ if route_current.path == "fullscreen":
29
+ with solara.Padding(4, children=children):
30
+ pass
31
+ else:
32
+ with solara.Column(align="center", style={"max-width": "100%"}):
33
+ doc = module.__doc__
34
+ if doc:
35
+ with solara.Column():
36
+ MarkdownWithMetadata(doc)
37
+ with solara.Column(style={"max-width": "min(100%, 1024px)", "width": "100%"}):
38
+ if route_current.path != "/":
39
+ solara.Button("View source code on GitHub", icon_name="mdi-github-circle", href=github_url, class_="ma-2", target="_blank", text=True)
47
40
  if not hasattr(module, "Page"):
48
41
  solara.Error(f"No Page component found in {module}")
49
42
  else:
50
- with solara.Padding(4, children=children):
43
+ with solara.Div(children=children):
51
44
  pass
52
- return main
@@ -77,7 +77,7 @@ def Page():
77
77
  task = solara.lab.use_task(call_openai, dependencies=[user_message_count]) # type: ignore
78
78
 
79
79
  with solara.Column(
80
- style={"width": "700px", "height": "50vh"},
80
+ style={"width": "100%", "height": "50vh"},
81
81
  ):
82
82
  with solara.lab.ChatBox():
83
83
  for item in messages.value:
@@ -35,7 +35,7 @@ def Page():
35
35
  sales_data = np.floor(np.cumsum(gen.random(7) - 0.5) * 100 + 100)
36
36
  show_report = solara.use_reactive(False)
37
37
 
38
- with solara.Column(style={"min-width": "600px"}):
38
+ with solara.Column():
39
39
  if show_report.value:
40
40
  with solara.Card("Report"):
41
41
  solara.Markdown("Lorum ipsum dolor sit amet")
@@ -38,6 +38,7 @@ def Page():
38
38
  )
39
39
  .configure_view(step=13, strokeWidth=0)
40
40
  .configure_axis(domain=False)
41
+ .properties(width="container")
41
42
  )
42
43
  with solara.Card("Annual Weather Heatmap for Seattle, WA"):
43
44
  solara.AltairChart(chart, on_click=on_click)
@@ -34,6 +34,6 @@ def Page(x=x0, ymax=5):
34
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
35
  x_axis = bqplot.Axis(scale=x_scale)
36
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={"min_width": "800px"})
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
38
 
39
39
  # return main
@@ -15,7 +15,7 @@ bounds = solara.reactive(None)
15
15
  @solara.component
16
16
  def Page():
17
17
  # Isolation is required to prevent the map from overlapping navigation (when screen width < 960px)
18
- with solara.Column(style={"min-width": "500px", "height": "500px", "isolation": "isolate"}):
18
+ with solara.Column(style={"width": "100%", "height": "500px", "isolation": "isolate"}):
19
19
  # solara components support reactive variables
20
20
  solara.SliderInt(label="Zoom level", value=zoom, min=1, max=20)
21
21
  # using 3rd party widget library require wiring up the events manually
@@ -31,7 +31,7 @@ def Page():
31
31
  # do things with the location
32
32
  marker_location.set(location)
33
33
 
34
- with solara.Column(style={"min-width": "500px", "height": "500px"}):
34
+ with solara.Column(style={"width": "100%", "height": "500px"}):
35
35
  solara.Markdown(f"Market set to: {marker_location.value}", style={"color": "#6e6e6e"})
36
36
 
37
37
  map = maps[map_name.value]
@@ -9,7 +9,6 @@ The UI code demonstrates a lot of conditional rendering.
9
9
  import time
10
10
 
11
11
  import solara
12
- from solara.alias import rv
13
12
 
14
13
 
15
14
  @solara.component
@@ -41,24 +40,23 @@ def Page():
41
40
 
42
41
  solara.use_thread(run_timer, dependencies=[duration, running])
43
42
 
44
- with solara.VBox() as main:
45
- if not running:
46
- if duration < 1:
47
- solara.Error("Duration must be at least 1 second")
48
- else:
49
- solara.Markdown(f"# Timer set to {seconds} seconds")
43
+ if not running:
44
+ if duration < 1:
45
+ solara.Error("Duration must be at least 1 second")
50
46
  else:
51
- if seconds:
52
- solara.Markdown(f"# {seconds} seconds left")
53
- else:
54
- solara.solara.Markdown("# Time's up!")
55
- rv.TextField(type="number", v_model=duration, on_v_model=on_duration, disabled=running)
56
- with solara.HBox():
57
- if running:
58
- solara.Button("Stop", on_click=lambda: set_running(False), icon_name="mdi-stop")
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")
59
61
  else:
60
- if duration != seconds:
61
- solara.Button("Reset", on_click=lambda: set_seconds(duration), icon_name="mdi-restart")
62
- else:
63
- solara.Button("Start", on_click=lambda: set_running(True), icon_name="mdi-play", disabled=seconds < 1)
64
- return main
62
+ solara.Button("Start", on_click=lambda: set_running(True), icon_name="mdi-play", disabled=seconds < 1)
@@ -45,9 +45,7 @@ def Page():
45
45
  fig = go.FigureWidget(
46
46
  layout=go.Layout(
47
47
  showlegend=False,
48
- autosize=False,
49
- width=600,
50
- height=600,
48
+ autosize=True,
51
49
  dragmode="drawrect",
52
50
  modebar={
53
51
  "add": [
@@ -49,8 +49,8 @@ def ClickScatter(df, x, y, color, click_row, on_click: Callable[[ClickPoint], No
49
49
  click_y = df[y].values[click_row]
50
50
  fig.add_trace(px.scatter(x=[click_x], y=[click_y], text=["⭐️"]).data[0])
51
51
  # make the figure a bit smaller
52
- fig.update_layout(width=400)
53
- with solara.VBox() as main:
52
+ fig.update_layout(width=340)
53
+ with solara.Column(style={"width": "340px"}) as main:
54
54
  solara.FigurePlotly(fig, on_click=on_click_trace)
55
55
  solara.Select(label="X-axis", value=x, values=columns, on_value=set_x)
56
56
  solara.Select(label="Y-axis", value=y, values=columns, on_value=set_y)
@@ -65,8 +65,8 @@ def Page():
65
65
  else:
66
66
  clicked_row = None
67
67
 
68
- with solara.VBox() as main:
69
- with solara.HBox():
68
+ with solara.Column() as main:
69
+ with solara.Row(justify="center", style={"flex-wrap": "wrap"}):
70
70
  ClickScatter(df, "sepal_length", "sepal_width", "species", clicked_row, on_click=set_click_point)
71
71
  ClickScatter(df, "petal_length", "petal_width", "species", clicked_row, on_click=set_click_point)
72
72
  if click_point is not None:
@@ -87,3 +87,21 @@ In case you forgot how to start a notebook server:
87
87
  Or the more modern Jupyter lab:
88
88
 
89
89
  $ jupyter lab
90
+
91
+
92
+ ## Run as app (experimental)
93
+
94
+ You can also run the script as a standalone app. This requires the extra packages `qtpy` and `PySide6` (or `PyQt6`) to be installed.
95
+
96
+ ```bash
97
+ $ pip install pip install qtpy PySide6
98
+ ```
99
+
100
+ Run from the command line in the same directory where you put your file (`sol.py`):
101
+
102
+ ```bash
103
+ $ solara run sol.py --qt
104
+ ```
105
+
106
+
107
+ <img src="https://dxhl76zpt6fap.cloudfront.net/public/solara-quickstart-app.webp" alt="Markdown Monster icon"/>
@@ -14,43 +14,37 @@ modules.export = {
14
14
  }
15
15
  window.solara.router.push = (href) => {
16
16
  console.log("external router push", href);
17
- // take of the anchor
18
- if (href.indexOf("#") !== -1) {
19
- href = href.slice(0, href.indexOf("#"));
20
- }
21
- this.location = href;
17
+ const url = new URL(href, window.location.origin + solara.rootPath);
18
+ this.location = url.pathname + url.search;
19
+ this.hash = url.hash;
22
20
  };
23
21
  let location = window.location.pathname.slice(solara.rootPath.length);
24
- // take of the anchor
25
- if (location.indexOf("#") !== -1) {
26
- location = location.slice(0, location.indexOf("#"));
27
- }
28
22
  this.location = location + window.location.search;
23
+ this.hash = window.location.hash;
29
24
  window.addEventListener("popstate", this.onPopState);
30
25
  window.addEventListener("scroll", this.onScroll);
26
+ window.addEventListener("hashchange", this.onHashChange);
27
+ window.addEventListener("solara.pageReady", this.onPageLoad);
31
28
  },
32
29
  destroyed() {
33
30
  window.removeEventListener("popstate", this.onPopState);
34
31
  window.removeEventListener("scroll", this.onScroll);
32
+ window.removeEventListener("hashchange", this.onHashChange);
33
+ window.removeEventListener("solara.pageReady", this.onPageLoad);
35
34
  },
36
35
  methods: {
37
36
  onScroll() {
38
37
  window.history.replaceState(
39
38
  { top: document.documentElement.scrollTop },
40
39
  null,
41
- solara.rootPath + this.location
40
+ window.location.href
42
41
  );
43
42
  },
44
43
  onPopState(event) {
45
- console.log("pop state!", event.state, window.location.href);
46
44
  if (!window.location.pathname.startsWith(solara.rootPath)) {
47
45
  throw `window.location.pathname = ${window.location.pathname}, but it should start with the solara.rootPath = ${solara.rootPath}`;
48
46
  }
49
47
  let newLocation = window.location.pathname.slice(solara.rootPath.length);
50
- // the router/server shouldn't care about the hash, that's for the frontend
51
- if (newLocation.indexOf("#") !== -1) {
52
- newLocation = newLocation.slice(0, newLocation.indexOf("#"));
53
- }
54
48
  this.location = newLocation + window.location.search;
55
49
  if (event.state) {
56
50
  const top = event.state.top;
@@ -63,6 +57,32 @@ modules.export = {
63
57
  */
64
58
  }
65
59
  },
60
+ onHashChange(event) {
61
+ if (!window.location.pathname.startsWith(solara.rootPath)) {
62
+ throw `window.location.pathname = ${window.location.pathname}, but it should start with the solara.rootPath = ${solara.rootPath}`;
63
+ }
64
+ this.hash = window.location.hash;
65
+ },
66
+ onPageLoad(event) {
67
+ if (!window.location.pathname.startsWith(solara.rootPath)) {
68
+ throw `window.location.pathname = ${window.location.pathname}, but it should start with the solara.rootPath = ${solara.rootPath}`;
69
+ }
70
+ // If we've navigated to a hash with the same name on a different page the watch on hash won't trigger
71
+ if (this.hash && this.hash === window.location.hash) {
72
+ this.navigateToHash(this.hash);
73
+ }
74
+ this.hash = window.location.hash;
75
+ },
76
+ makeFullRelativeUrl() {
77
+ const url = new URL(this.location, window.location.origin + solara.rootPath);
78
+ return url.pathname + this.hash + url.search;
79
+ },
80
+ navigateToHash(hash) {
81
+ const targetEl = document.getElementById(hash.slice(1));
82
+ if (targetEl) {
83
+ targetEl.scrollIntoView();
84
+ }
85
+ },
66
86
  },
67
87
  watch: {
68
88
  location(value) {
@@ -89,7 +109,7 @@ modules.export = {
89
109
  document.documentElement.scrollTop
90
110
  );
91
111
  if (oldLocation != this.location) {
92
- window.history.pushState({ top: 0 }, null, solara.rootPath + this.location);
112
+ window.history.pushState({ top: 0 }, null, this.makeFullRelativeUrl());
93
113
  if (pathnameNew != pathnameOld) {
94
114
  // we scroll to the top only when we change page, not when we change
95
115
  // the search string
@@ -99,6 +119,16 @@ modules.export = {
99
119
  window.dispatchEvent(event);
100
120
  }
101
121
  },
122
+ hash(value) {
123
+ if (value) {
124
+ this.navigateToHash(value);
125
+ }
126
+ },
127
+ },
128
+ data() {
129
+ return {
130
+ hash: "",
131
+ };
102
132
  },
103
133
  };
104
134
  </script>
@@ -15,6 +15,11 @@ module.exports = {
15
15
  mounted() {
16
16
  this.do_plot_debounced();
17
17
  },
18
+ destroyed() {
19
+ if (this.observer) {
20
+ this.observer.disconnect();
21
+ }
22
+ },
18
23
  watch: {
19
24
  spec() {
20
25
  this.do_plot_debounced();
@@ -29,7 +34,15 @@ module.exports = {
29
34
  (async () => {
30
35
  const spec = {
31
36
  ...this.spec,
37
+ "renderer": "svg",
32
38
  };
39
+ if (spec.width === "container") {
40
+ this.$refs.plotElement.classList.add("width-container")
41
+ this.observer = new ResizeObserver(() => {
42
+ view.resize();
43
+ });
44
+ this.observer.observe(this.$refs.plotElement);
45
+ }
33
46
  const { view } = await vegaEmbed(this.$refs.plotElement, spec);
34
47
  // events https://github.com/vega/vega-view#event-handling
35
48
  if (this.listen_to_click) {
@@ -110,3 +123,8 @@ module.exports = {
110
123
  },
111
124
  }
112
125
  </script>
126
+ <style id="vega-embed-container-width">
127
+ .width-container.vega-embed {
128
+ width: 100%;
129
+ }
130
+ </style>
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: solara-ui
3
- Version: 1.40.0
3
+ Version: 1.41.0
4
4
  Dynamic: Summary
5
5
  Project-URL: Home, https://www.github.com/widgetti/solara
6
6
  Project-URL: Documentation, https://solara.dev
@@ -1,7 +1,7 @@
1
1
  prefix/etc/jupyter/jupyter_notebook_config.d/solara.json,sha256=3UhTBQi6z7F7pPjmqXxfddv79c8VGR9H7zStDLp6AwY,115
2
2
  prefix/etc/jupyter/jupyter_server_config.d/solara.json,sha256=D9J-rYxAzyD5GOqWvuPjacGUVFHsYtTfZ4FUbRzRvIA,113
3
- solara/__init__.py,sha256=tpKKpduPHdeO3pVlyMAwK0CthK4sLiFWFAPWNS5BOTI,3647
4
- solara/__main__.py,sha256=6ZmzjN3qiBTlR4triE69008KY-TvSFPKqepZyOL4WoY,23876
3
+ solara/__init__.py,sha256=l1mOv4ngBpoXaXv6PDfspwaZ3lCYhGNgEuiTayMGZrM,3647
4
+ solara/__main__.py,sha256=-OSjoLAVqu7-h15I5X1XFi6FyHpM0XT1z7qTXlyuDqM,24339
5
5
  solara/alias.py,sha256=9vfLzud77NP8in3OID9b5mmIO8NyrnFjN2_aE0lSb1k,216
6
6
  solara/autorouting.py,sha256=iQ-jP5H-kdu1uZyLEFeiHG1IsOLZLzwKVtQPyXSgGSM,23093
7
7
  solara/cache.py,sha256=rZEW_xVIj3vvajntsQDnaglniTQ90izkX8vOqe1mMvE,10500
@@ -32,7 +32,7 @@ solara/components/checkbox.py,sha256=MLQ9Hxvtv5aKLj4XO3ILWtGc6nKOUH560A2bBt0Z030
32
32
  solara/components/code_highlight_css.py,sha256=J0fZHuEu8jeEKAq_HKbzgiMR1-VwMVnKA4dAOKE0AQU,235
33
33
  solara/components/code_highlight_css.vue,sha256=UX4jtEetV1W25Uvu8xQ-TbEaBzbp_7DlXtXDO9SdZfY,5776
34
34
  solara/components/columns.py,sha256=bGCUU9MLxkt2OiS31oLHWrEOlskxT1Xo65dBxXhmhbQ,5564
35
- solara/components/component_vue.py,sha256=_WNF_MMM0pENBeokFJziro3iBm67uvNlIR9D2gx53gs,4335
35
+ solara/components/component_vue.py,sha256=zw7vEfBWDO-jxPHD03e1d96Gci8yGbr6koh0d1Bzfoo,4379
36
36
  solara/components/cross_filter.py,sha256=Q5vOkerWXNCtRbSboHjXcnjoys8bHv5b7G_fH1A1lio,13663
37
37
  solara/components/dataframe.py,sha256=9Zr-usCz9UkO2xpNlDpooRGu-Bwtn49Cy4cdAaO_KGg,21033
38
38
  solara/components/datatable.py,sha256=A64-BRM3d8ZKUURbYSfHCsqqJg7MKQhFpnJ9uqCBGMg,7836
@@ -113,9 +113,10 @@ solara/server/jupytertools.py,sha256=cYFIUjLX7n0uuEXqWVWvmV6sV7R_MNg8ZZlabQgw8vk
113
113
  solara/server/kernel.py,sha256=3mwRRBw6BOcKLACL4fCUGgtI_RZ5KTSM1MlAtRlDbmA,11092
114
114
  solara/server/kernel_context.py,sha256=RrNVAkoev6u6LZBvDfG86zyVs7eDVUsrp_4Au_FLlgY,16718
115
115
  solara/server/patch.py,sha256=W-UG_TXKIbQRV0B9rGkJzg21EGV00ra5kQZAZGQquZc,19111
116
+ solara/server/qt.py,sha256=74ffA2Agk5a1edEeF6_8KS1FlQlJoHrFOkULI2PxT4k,3762
116
117
  solara/server/reload.py,sha256=BBH7QhrV1-e9RVyNE3uz1oPj1DagC3t_XSqGPNz0nJE,9747
117
118
  solara/server/server.py,sha256=fUb9BpvjCNLlSAOUIjkge6PUO07VGEetdQi1chEFzRM,16569
118
- solara/server/settings.py,sha256=8QpVW_hYe4QvSVvDMeobpUEFa_jjCAGrSKgCGzjZ3As,7340
119
+ solara/server/settings.py,sha256=b82BNWOntcWithynahDDAZFQyx3-kmyll7FwqIOn1sg,7369
119
120
  solara/server/shell.py,sha256=xKox0fvDxdcWleE8p2ffCkihvjLJsWn2FujMbgUjYn0,8677
120
121
  solara/server/starlette.py,sha256=yuXCJbpD5tq2JoX0KoRh5YMh67fp33rVCDb3zuwgHxk,29054
121
122
  solara/server/telemetry.py,sha256=GPKGA5kCIqJb76wgxQ2_U2uV_s0r-1tKqv-GVxo5hs8,6038
@@ -126,7 +127,7 @@ solara/server/assets/custom.css,sha256=4p04-uxHTobfr6Xkvf1iOrYiks8NciWLT_EwHZSy6
126
127
  solara/server/assets/custom.js,sha256=YT-UUYzA5uI5-enmbIsrRhofY_IJAO-HanaMwiNUEos,16
127
128
  solara/server/assets/favicon.png,sha256=Ssgmi5eZeGIGABOrxW8AH3hyvy5a9avdDIDYsmEUMpM,1924
128
129
  solara/server/assets/favicon.svg,sha256=HXAji-JQGBaGi2_iyk3vHgEDgdFYtsWTVqOE6QmVLKc,1240
129
- solara/server/assets/style.css,sha256=gjohelmLh9uBja4JgvUbTtvsm-oDVAEvGzNNQ0tsEcE,40819
130
+ solara/server/assets/style.css,sha256=UYfYkMO5Fs_5L5qLMaA2HCL-CDyHI4EOnjg2HN2YpvI,40867
130
131
  solara/server/assets/theme-dark.css,sha256=w9a0BDQoXnhoLC4Uz8QdCiFvZsDYV4XvOL4CoSyAnBM,16733
131
132
  solara/server/assets/theme-light.css,sha256=zYjHebS5dGq9o4wNcS8nFyuE1oiqSmhcxVHNf3FYZ3Q,15637
132
133
  solara/server/assets/theme.js,sha256=kwXC-5gj9JKcwb8JMaV2sZ5t_F26c6ypqfozLZZ8Izo,21
@@ -141,18 +142,18 @@ solara/server/pyinstaller/hook-solara.py,sha256=8-tQOtgiNgf3btngI69YPeZp9lLgJpVj
141
142
  solara/server/static/ansi.js,sha256=Oa3cXY3u5vSSq8-P6JnAqa2S9cymxY0iL6wG449jFJk,7797
142
143
  solara/server/static/highlight-dark.css,sha256=xO8-vta9vG4s1OfJNHXWqiLWzx_gM03jouSmQvRmj-I,6809
143
144
  solara/server/static/highlight.css,sha256=k8ZdT5iwrGQ5tXTQHAXuxvZrSUq3kwCdEpy3mlFoZjs,2637
144
- solara/server/static/main-vuetify.js,sha256=SujoF_ECeS-KfyEnab3XA55fqO5Cv-cg3X8liBSYXEs,8920
145
+ solara/server/static/main-vuetify.js,sha256=R3qM4xMlstMpRUdRaul78p34z_Av2ONSTXksg2V9TqQ,9503
145
146
  solara/server/static/main.js,sha256=mcx4JNQ4Lg4pNdUIqMoZos1mZyYFS48yd_JNFFJUqIE,5679
146
- solara/server/static/solara_bootstrap.py,sha256=mB7uV_BraGdPTZ3PDExW2mufBUXVuUu_39zkJ-ozJTc,3195
147
+ solara/server/static/solara_bootstrap.py,sha256=e5_ztDjhDG8AjekuOm_fHFxGT5hhFJbiFg76cvqOQCg,3195
147
148
  solara/server/static/sun.svg,sha256=jEKBAGCr7b9zNYv0VUb7lMWKjnU2dX69_Ye_DZWGXJI,6855
148
149
  solara/server/static/webworker.js,sha256=cjAFz7-SygStHJnYlJUlJs-gE_7YQeQ-WBDcmKYyjvo,1372
149
150
  solara/server/templates/index.html.j2,sha256=JXQo1M-STFHLBOFetgG7509cAq8xUP0VAEtYDzz35fY,31
150
151
  solara/server/templates/loader-plain.css,sha256=SjZEbU8s2aUQk9UYwmbWMKXlGZe0XTvy4dfFTBeUWWo,205
151
152
  solara/server/templates/loader-plain.html,sha256=VEtMDC8MQj75o2iWJ_gR70Jp05oOoyRBKbhS4o-FXVI,718
152
153
  solara/server/templates/loader-solara.css,sha256=QerfzwlenkSJMq8uk_qEtoSdcI-DKMRrH9XXDEPsrUA,1670
153
- solara/server/templates/loader-solara.html,sha256=bgp3GHOAhfzU0rcAAYDsqhGlemfZo4YNhRsYIvhU7YM,2726
154
+ solara/server/templates/loader-solara.html,sha256=wFPnTevFBcRXQj6ZCZdgkOGTMwAAiOmNlgFdzdJLpXA,2744
154
155
  solara/server/templates/plain.html,sha256=yO1r2hidA3bxOclaxtI_vTZtdDTFn2KKeeoldJuinXk,2762
155
- solara/server/templates/solara.html.j2,sha256=lKRRNK7fChhN_VG7k1mvpWFtg8_DAFAv4ZmkhhQAlP4,21595
156
+ solara/server/templates/solara.html.j2,sha256=qbhRj-KYUr-HMlUpFOblGCNXg4ko6QXArIywvpCCirM,21850
156
157
  solara/template/button.py,sha256=HM382prl4bNLF8sLBd9Sh43ReMGedG_z_h4XN4mDYRI,311
157
158
  solara/template/markdown.py,sha256=31G3ezFooiveSrUH5afz5_nJ8SStjbx-_x5YLXv_hPk,1137
158
159
  solara/template/portal/.flake8,sha256=wxWLwamdP33Jm1mPa1sVe3uT0AZkG_wHPbY3Ci7j5-g,136
@@ -197,8 +198,8 @@ solara/website/components/mailchimp.vue,sha256=f2cFKUfl7gL9FJbGLCtPRUFBghxS8kcGu
197
198
  solara/website/components/markdown.py,sha256=jWqDYQWiN7_aNIUNjhUePT_weO5UoSowh4P0wZF7bjw,1497
198
199
  solara/website/components/markdown_nav.vue,sha256=VK6TBDcocPyfLyripFR1BQITj00tLe0fwauumYQUExE,988
199
200
  solara/website/components/notebook.py,sha256=MM73_c5l49SSpK63O4TYMsQ-mA43CwfhfU7VKXjfNC0,6867
200
- solara/website/components/sidebar.py,sha256=5XnJn-KDpfocMg-hJvfl64cSsMEj4Wb9I8wpsRLCsPg,6017
201
- solara/website/pages/__init__.py,sha256=HFdm-9g1cnesBJ-t4DqD7ukkTiatbEszGPWC3hfxy3I,20947
201
+ solara/website/components/sidebar.py,sha256=VRbxGkhsOx26H458gkW1p44NCoTFn8EhWqpyB4ahFso,6071
202
+ solara/website/pages/__init__.py,sha256=h-mETi0N10iKWTs9xYKC1ruAJBYzco0-bWDmjBSsdFY,21181
202
203
  solara/website/pages/doc_use_download.py,sha256=wTzDT21FRcHwfDAAxZPmHFqF5lyLvkHZ2mieZ4kfz9Y,3127
203
204
  solara/website/pages/docutils.py,sha256=2ne991oUtK4dMj-qN18NtsVYxSfCT1c6o5yYThQnxUE,736
204
205
  solara/website/pages/home.vue,sha256=1L3TVvBY7qXkkR0jIW49olDc5ZpglzA8pm06JLMkFQc,43617
@@ -248,7 +249,7 @@ solara/website/pages/documentation/advanced/content/20-understanding/15-anatomy.
248
249
  solara/website/pages/documentation/advanced/content/20-understanding/17-rules-of-hooks.md,sha256=A-wHZQwNPcZg1S_hcaE36VG24H1Hx_HXP4jEuWNR5zk,5088
249
250
  solara/website/pages/documentation/advanced/content/20-understanding/18-containers.md,sha256=Bkl22GXxO0MhTVpUK1q0l5h_wBWNgkR1ZoCG28p7r40,4905
250
251
  solara/website/pages/documentation/advanced/content/20-understanding/20-solara.md,sha256=sNK-mmgbj9rDHOXu5JaP7OMQdX0chOZ72-aMdOEOkug,751
251
- solara/website/pages/documentation/advanced/content/20-understanding/40-routing.md,sha256=7-efGbXIVhUkLCFtG9rCBxKcDcQMEt_GMyt4GDCHRK8,9669
252
+ solara/website/pages/documentation/advanced/content/20-understanding/40-routing.md,sha256=lb_TDXOv43oq3hqnOwjmUpSWCEhaO5l2ZQSPBL6riEQ,10365
252
253
  solara/website/pages/documentation/advanced/content/20-understanding/50-solara-server.md,sha256=Svb6I84nFJFPr1D-nGcHc5TummZ6TqAU7suCoUWbg5c,6336
253
254
  solara/website/pages/documentation/advanced/content/20-understanding/60-voila.md,sha256=jlL0kyzzDdHytNizBBLPx7buFFforlIDdMF724C2RLE,1132
254
255
  solara/website/pages/documentation/advanced/content/30-enterprise/00-overview.md,sha256=MmrZWt4KyKVGw7kX3nlcAIgf814RHmf3A5BUQiDZIYA,381
@@ -367,10 +368,10 @@ solara/website/pages/documentation/components/viz/echarts.py,sha256=__uayej4ttWZ
367
368
  solara/website/pages/documentation/components/viz/matplotlib.py,sha256=YEvCQyy5lmuV_6NArZ8qYucLMN6ah7pVJNk-xkouDAg,761
368
369
  solara/website/pages/documentation/components/viz/plotly.py,sha256=t54SJLkdf7jfO7XwAnbuArotUCq_6aX_CCsXi_Z7c1k,1377
369
370
  solara/website/pages/documentation/components/viz/plotly_express.py,sha256=dnBKzdr1IQF5bkSN2f8hkNbW4u7mfEwhNEufmaaDcEM,957
370
- solara/website/pages/documentation/examples/__init__.py,sha256=-EvZQUFwyHVqIqIZL7Ab_OHbXOXw5WChRjYJdhRq6Vk,2102
371
+ solara/website/pages/documentation/examples/__init__.py,sha256=8bBzOr0LLRIHyaHMFAKkumrXYdcWcoU50_GITvAlIEc,1676
371
372
  solara/website/pages/documentation/examples/ipycanvas.py,sha256=58iN7Hby5aeQglhCkDrXQDejszMf_aFvvEQWAEdccPE,1846
372
373
  solara/website/pages/documentation/examples/ai/__init__.py,sha256=ZicYzTHeFnnVnfQitWJ8t3-VGUDlMK5g-mXc3Y2HmkY,192
373
- solara/website/pages/documentation/examples/ai/chatbot.py,sha256=BWFfaMaJTVfi76QDe6wTY5SMkUN9R7nxQKJ8mBH3jco,2878
374
+ solara/website/pages/documentation/examples/ai/chatbot.py,sha256=JP_L61nVdaWIaeG2gRsqBsRZTpvMEqqb2M2p_asBM5s,2877
374
375
  solara/website/pages/documentation/examples/ai/tokenizer.py,sha256=vA_ut_9lka-uoDI86qfouzB7CcXu-1OYHTFQKNXtFao,3701
375
376
  solara/website/pages/documentation/examples/basics/__init__.py,sha256=1GvAS0idpN-CcfBwmcVZMA6XjoewDjZ75-Vq16QCpQU,159
376
377
  solara/website/pages/documentation/examples/basics/sine.py,sha256=0xTkCwBajwAl5z-ayT47kzS5ziRfsa48A7XxQeXgxtQ,554
@@ -388,24 +389,24 @@ solara/website/pages/documentation/examples/general/live_update.py,sha256=Zte8ii
388
389
  solara/website/pages/documentation/examples/general/login_oauth.py,sha256=STckaXaDxdEnltl5PkgkSmw-FASqUqr4T5llGI-UwNA,2551
389
390
  solara/website/pages/documentation/examples/general/mycard.vue,sha256=j1p32TyRHYpi4OW__K1UxwMElif3R9J-POlTb8ACCMg,1359
390
391
  solara/website/pages/documentation/examples/general/pokemon_search.py,sha256=ff6DBH5pCKU175A99VGlvNDEnzO1P27nMVUNcDNo-ag,2079
391
- solara/website/pages/documentation/examples/general/vue_component.py,sha256=HVy7-Evl7S2CiZDNPGE0W9T3g2PRswM1O3hyxpgPU80,1757
392
+ solara/website/pages/documentation/examples/general/vue_component.py,sha256=RjzyeGrOtpQzwvAx9Dn5jM4uhDpkD0c_SNM7VrgmI_g,1729
392
393
  solara/website/pages/documentation/examples/libraries/__init__.py,sha256=x7Hy8EmHugarFZIP2Wl4K7ACs_70iC4KmOhMVHXQqEo,144
393
- solara/website/pages/documentation/examples/libraries/altair.py,sha256=bPkikVQsTVrXEx4svH_QqMobvD-oiP6gtBTG5zbT5yc,2141
394
- solara/website/pages/documentation/examples/libraries/bqplot.py,sha256=kssz938QYBTyFwv4ZwPnqtg-Ep70JemUejHNJWyAKh4,1164
395
- solara/website/pages/documentation/examples/libraries/ipyleaflet.py,sha256=T2kSAW-dowAsccaSE9jChDVfJL7CxAn-bqJ1t7-tcmk,1168
396
- solara/website/pages/documentation/examples/libraries/ipyleaflet_advanced.py,sha256=1jabLNxoA6_p5xo9WgUJ5AVjmrXPKd1uoR9uWoIsFj8,2297
394
+ solara/website/pages/documentation/examples/libraries/altair.py,sha256=nphFgEWxlgkI14OwRcP59AnL0MMTAIin01-L8_kJAhU,2180
395
+ solara/website/pages/documentation/examples/libraries/bqplot.py,sha256=6b6X5htldc8DzvB4avJRUZkqLONU17ut2gW9cGfzBQE,1180
396
+ solara/website/pages/documentation/examples/libraries/ipyleaflet.py,sha256=zqXX1HZHvfAvVDUc1YUE-9EBx7qH4Zs0_-ijRpw3I3Y,1163
397
+ solara/website/pages/documentation/examples/libraries/ipyleaflet_advanced.py,sha256=IhFr1OHiEAyonDNiUHkpKRVVakZ1MyPqY8pQWrVMKsI,2292
397
398
  solara/website/pages/documentation/examples/utilities/__init__.py,sha256=5AtOFUlZpWTOya9fn0jSzKiJ-tpOg_fDzFcb9aJQiFM,155
398
399
  solara/website/pages/documentation/examples/utilities/calculator.py,sha256=ysDgp0LRK7E3OeEBalJn07u8-fQagg6hmeG5Juosejs,5529
399
- solara/website/pages/documentation/examples/utilities/countdown_timer.py,sha256=E61jZ0RLZt7XUHAWrpSs-Mo0OoR88OoRSOQbs35J230,2163
400
+ solara/website/pages/documentation/examples/utilities/countdown_timer.py,sha256=0krBNsGghKZ2iPJL3DJWeTOpIukYk694SLiYJ8z_KlI,2017
400
401
  solara/website/pages/documentation/examples/utilities/todo.py,sha256=tFsCt429TaOLyWLjb7UW-1ji64Uwv3JhN8y6EQHJHXM,6480
401
402
  solara/website/pages/documentation/examples/visualization/__init__.py,sha256=OaLTp4A4J6y0lZS6mVgY78eNRQ0SagOK261KNY4LEVQ,105
402
- solara/website/pages/documentation/examples/visualization/annotator.py,sha256=68tukoY_1eCtILXBwCIsijIQEvv96HXxv4Ae_5osB2o,1809
403
- solara/website/pages/documentation/examples/visualization/linked_views.py,sha256=Tc4hMTOXFN7R_ivIzvbbwQAGwQ2-hLYgB-s10Q5i_pQ,2700
403
+ solara/website/pages/documentation/examples/visualization/annotator.py,sha256=CAXT3mjQE9RBQMmaDCJjSHZr1Fv66M0ESR3foFTqUWo,1761
404
+ solara/website/pages/documentation/examples/visualization/linked_views.py,sha256=kPmSGig5Tkyh_Jjye32yKOwjpW6IOVMwc9KKjrJ7jIk,2772
404
405
  solara/website/pages/documentation/examples/visualization/plotly.py,sha256=33kKSV-h8cyU6KJ3XfiTrkHtIrtUg7SbYlz0XWLNBN0,1268
405
406
  solara/website/pages/documentation/faq/__init__.py,sha256=GcdqdTEWC-xDgIWECQleZbbnmacelt9K1ZyTw2nf9Wc,278
406
407
  solara/website/pages/documentation/faq/content/99-faq.md,sha256=UWBlt5nx_GXAJP8b87e7Hw1agiuY6-nCIh9WPLvSTr4,3939
407
408
  solara/website/pages/documentation/getting_started/__init__.py,sha256=bLLvasuqVVWJxGN89m77ChZhDivEhVavw9-_CiG3IZA,414
408
- solara/website/pages/documentation/getting_started/content/00-quickstart.md,sha256=uhD8imzC8bTE1mO1Qq-I4n7XrA8GOxJwx93Dwhhfuj8,3011
409
+ solara/website/pages/documentation/getting_started/content/00-quickstart.md,sha256=UP80_MSeh9odXMncnZHYTs6bPRXQVN2WVKpuodznpus,3465
409
410
  solara/website/pages/documentation/getting_started/content/01-introduction.md,sha256=43EhX3JhwFICQademwwFgALuCc2chYa2xkUKp8pkid4,6609
410
411
  solara/website/pages/documentation/getting_started/content/02-installing.md,sha256=zYn_4b4TR2rsMyi-UloAAI3D0qWaM1Wsbf0Uzz_XYj0,5609
411
412
  solara/website/pages/documentation/getting_started/content/80-what-is-lab.md,sha256=4CLyCZYkApsWNdXJ3N6YYShj5s4tJhYH1V6svtVgCcE,307
@@ -450,11 +451,11 @@ solara/widgets/__init__.py,sha256=D3RfEez9dllmst64_nyzzII-NZXoNMEPDnEog4ov3VE,43
450
451
  solara/widgets/widgets.py,sha256=AIRcMhSDFpESQ1JzUszlb2NH5FwSImLnmd4kqcc9jkY,2452
451
452
  solara/widgets/vue/gridlayout.vue,sha256=hk10RsEQBxkknTmqa0wtBia9LWQGdDsXlejnAj7USU8,3441
452
453
  solara/widgets/vue/html.vue,sha256=48K5rjp0AdJDeRV6F3nOHW3J0WXPeHn55r5pGClK2fU,112
453
- solara/widgets/vue/navigator.vue,sha256=SLrzBI0Eiys-7maXA4e8yyD13-O5b4AnCGE9wKuJDHE,3646
454
- solara/widgets/vue/vegalite.vue,sha256=E3dlfhR-Ol7nqQZN6wCZC_3Tz98CJW0i_EU39mj0XHw,3986
455
- solara_ui-1.40.0.data/data/etc/jupyter/jupyter_notebook_config.d/solara.json,sha256=3UhTBQi6z7F7pPjmqXxfddv79c8VGR9H7zStDLp6AwY,115
456
- solara_ui-1.40.0.data/data/etc/jupyter/jupyter_server_config.d/solara.json,sha256=D9J-rYxAzyD5GOqWvuPjacGUVFHsYtTfZ4FUbRzRvIA,113
457
- solara_ui-1.40.0.dist-info/METADATA,sha256=w9fIolVVb8jepl4XavaQsY5e2Wzh1qihDf8HB1uvkVI,7285
458
- solara_ui-1.40.0.dist-info/WHEEL,sha256=L5_n4Kc1NmrSdVgbp6hdnwwVwBnoYOCnbHBRMD-qNJ4,105
459
- solara_ui-1.40.0.dist-info/licenses/LICENSE,sha256=fFJUz-CWzZ9nEc4QZKu44jMEoDr5fEW-SiqljKpD82E,1086
460
- solara_ui-1.40.0.dist-info/RECORD,,
454
+ solara/widgets/vue/navigator.vue,sha256=7fkX-4_YSnnMIPUMKMvQVVEzrmhY9BFAYvHMqZqTXpI,4790
455
+ solara/widgets/vue/vegalite.vue,sha256=zhocRsUCNIRQCEbD16er5sYnuHU0YThatRHnorA3P18,4596
456
+ solara_ui-1.41.0.data/data/etc/jupyter/jupyter_notebook_config.d/solara.json,sha256=3UhTBQi6z7F7pPjmqXxfddv79c8VGR9H7zStDLp6AwY,115
457
+ solara_ui-1.41.0.data/data/etc/jupyter/jupyter_server_config.d/solara.json,sha256=D9J-rYxAzyD5GOqWvuPjacGUVFHsYtTfZ4FUbRzRvIA,113
458
+ solara_ui-1.41.0.dist-info/METADATA,sha256=hy_TH8LcVZ6PfXD3xNx53kNzx3dfmlMKSW3P5zNxjwU,7285
459
+ solara_ui-1.41.0.dist-info/WHEEL,sha256=L5_n4Kc1NmrSdVgbp6hdnwwVwBnoYOCnbHBRMD-qNJ4,105
460
+ solara_ui-1.41.0.dist-info/licenses/LICENSE,sha256=fFJUz-CWzZ9nEc4QZKu44jMEoDr5fEW-SiqljKpD82E,1086
461
+ solara_ui-1.41.0.dist-info/RECORD,,