st-components 0.1.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.
- examples/README.md +113 -0
- examples/__init__.py +1 -0
- examples/_source.py +9 -0
- examples/basic.py +30 -0
- examples/dashboard.py +288 -0
- examples/data_dashboard.py +428 -0
- examples/flow.py +131 -0
- examples/functional.py +121 -0
- examples/functional_typed.py +146 -0
- examples/multipage/README.md +31 -0
- examples/multipage/app.py +105 -0
- examples/multipage/pages/report_page.py +82 -0
- examples/multipage/shared.py +60 -0
- examples/primitives.py +1228 -0
- examples/theme_editor.py +77 -0
- examples/typed_props.py +154 -0
- examples/typed_state.py +140 -0
- st_components/__init__.py +33 -0
- st_components/builtins/__init__.py +6 -0
- st_components/builtins/flow.py +122 -0
- st_components/builtins/theme.py +486 -0
- st_components/core/__init__.py +83 -0
- st_components/core/access.py +103 -0
- st_components/core/app.py +381 -0
- st_components/core/base.py +275 -0
- st_components/core/context.py +162 -0
- st_components/core/function_component.py +74 -0
- st_components/core/hooks.py +16 -0
- st_components/core/models.py +192 -0
- st_components/core/page.py +101 -0
- st_components/core/refs.py +46 -0
- st_components/core/router.py +55 -0
- st_components/core/store.py +167 -0
- st_components/elements/__init__.py +27 -0
- st_components/elements/_types.py +33 -0
- st_components/elements/_utils.py +43 -0
- st_components/elements/charts/__init__.py +35 -0
- st_components/elements/charts/altair_chart.py +25 -0
- st_components/elements/charts/area_chart.py +15 -0
- st_components/elements/charts/bar_chart.py +15 -0
- st_components/elements/charts/bokeh_chart.py +14 -0
- st_components/elements/charts/graphviz_chart.py +15 -0
- st_components/elements/charts/line_chart.py +15 -0
- st_components/elements/charts/map.py +15 -0
- st_components/elements/charts/plotly_chart.py +27 -0
- st_components/elements/charts/pydeck_chart.py +25 -0
- st_components/elements/charts/pyplot.py +15 -0
- st_components/elements/charts/scatter_chart.py +15 -0
- st_components/elements/charts/vega_lite_chart.py +27 -0
- st_components/elements/display/__init__.py +26 -0
- st_components/elements/display/basic.py +75 -0
- st_components/elements/display/data.py +86 -0
- st_components/elements/display/navigation.py +37 -0
- st_components/elements/feedback/__init__.py +17 -0
- st_components/elements/feedback/messages.py +50 -0
- st_components/elements/feedback/progress.py +41 -0
- st_components/elements/input/__init__.py +61 -0
- st_components/elements/input/_common.py +109 -0
- st_components/elements/input/boolean.py +51 -0
- st_components/elements/input/buttons.py +133 -0
- st_components/elements/input/data_editor.py +52 -0
- st_components/elements/input/datetime_widgets.py +106 -0
- st_components/elements/input/files.py +99 -0
- st_components/elements/input/select.py +229 -0
- st_components/elements/input/textual.py +89 -0
- st_components/elements/layout/__init__.py +27 -0
- st_components/elements/layout/containers.py +143 -0
- st_components/elements/layout/misc.py +27 -0
- st_components/elements/layout/overlays.py +80 -0
- st_components/elements/media/__init__.py +11 -0
- st_components/elements/media/core.py +74 -0
- st_components/elements/text/__init__.py +25 -0
- st_components/elements/text/_common.py +2 -0
- st_components/elements/text/body.py +47 -0
- st_components/elements/text/headings.py +31 -0
- st_components/elements/text/misc.py +31 -0
- st_components/examples/__init__.py +9 -0
- st_components/examples/__main__.py +28 -0
- st_components/examples/runner.py +48 -0
- st_components/py.typed +1 -0
- st_components-0.1.0.dist-info/METADATA +664 -0
- st_components-0.1.0.dist-info/RECORD +85 -0
- st_components-0.1.0.dist-info/WHEEL +5 -0
- st_components-0.1.0.dist-info/licenses/LICENSE +21 -0
- st_components-0.1.0.dist-info/top_level.txt +2 -0
examples/README.md
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Examples
|
|
2
|
+
|
|
3
|
+
Each example is a self-contained Streamlit app.
|
|
4
|
+
|
|
5
|
+
Installed package:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
python -m st_components.examples <name>
|
|
9
|
+
python -m st_components.examples --list
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
From the repository root, you can also run the files directly with `streamlit run`.
|
|
13
|
+
|
|
14
|
+
## basic.py
|
|
15
|
+
|
|
16
|
+
The minimal entry point. A single stateful `Counter` component — nothing else.
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
python -m st_components.examples basic
|
|
20
|
+
streamlit run examples/basic.py
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## data_dashboard.py
|
|
24
|
+
|
|
25
|
+
A data-science oriented dashboard that shows how Python computation (numpy signal analysis, histogram stats, least-squares regression) lives inside **component methods and callbacks**, keeping the render layer thin. Three panels: Signal Explorer (FFT + rolling mean), Distribution Analyzer (descriptive stats + histogram), Regression Playground (polyfit + R²).
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
python -m st_components.examples data_dashboard
|
|
29
|
+
streamlit run examples/data_dashboard.py
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## dashboard.py
|
|
33
|
+
|
|
34
|
+
A fuller tutorial that walks through the core patterns: local component state, `on_change(value)` callbacks, `Ref`, and layout composition.
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
python -m st_components.examples dashboard
|
|
38
|
+
streamlit run examples/dashboard.py
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## flow.py
|
|
42
|
+
|
|
43
|
+
Small demo of the flow built-ins: `Conditional`, `KeepAlive`, `Case`, and `Switch`/`Match`/`Default`.
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
python -m st_components.examples flow
|
|
47
|
+
streamlit run examples/flow.py
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## functional_typed.py
|
|
51
|
+
|
|
52
|
+
Typed state and props for functional components: `use_state()` with a `State` instance, `@component` with a typed `Props` annotation, and combining both.
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
python -m st_components.examples functional_typed
|
|
56
|
+
streamlit run examples/functional_typed.py
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## functional.py
|
|
60
|
+
|
|
61
|
+
Demonstrates the `@component` decorator and `use_state` hook for defining components as plain functions instead of classes.
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
python -m st_components.examples functional
|
|
65
|
+
streamlit run examples/functional.py
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## primitives.py
|
|
69
|
+
|
|
70
|
+
A kitchen-sink reference of every built-in element wrapper: inputs, layout, display, media, feedback, and charts.
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
python -m st_components.examples primitives
|
|
74
|
+
streamlit run examples/primitives.py
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## typed_state.py
|
|
78
|
+
|
|
79
|
+
Demonstrates typed state schemas using nested `State` subclasses: single-field state without `__init__`, multi-field structured state, and type validation at definition and assignment time.
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
python -m st_components.examples typed_state
|
|
83
|
+
streamlit run examples/typed_state.py
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## typed_props.py
|
|
87
|
+
|
|
88
|
+
Demonstrates typed props schemas using nested `Props` subclasses: default prop values, `extra="ignore"` for permissive pass-through components, and `extra="forbid"` for strict interface enforcement.
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
python -m st_components.examples typed_props
|
|
92
|
+
streamlit run examples/typed_props.py
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## theme_editor.py
|
|
96
|
+
|
|
97
|
+
Minimal demo of the `ThemeEditorButton` builtin. Open the dialog from a prewired button and edit the current `App` theme live.
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
python -m st_components.examples theme_editor
|
|
101
|
+
streamlit run examples/theme_editor.py
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## multipage/
|
|
105
|
+
|
|
106
|
+
A multipage app using `Router`, `Page`, and `shared_state`. Shows both inline component pages and file-backed pages synchronized through shared state.
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
python -m st_components.examples multipage
|
|
110
|
+
streamlit run examples/multipage/app.py
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
See [multipage/README.md](multipage/README.md) for details.
|
examples/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
examples/_source.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from st_components.elements import code, expander
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def source_view(path, *, key="source", label="View source"):
|
|
7
|
+
return expander(key=key, label=label, expanded=False)(
|
|
8
|
+
code(key="code", language="python")(Path(path).read_text())
|
|
9
|
+
)
|
examples/basic.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from st_components import Component, App
|
|
2
|
+
from st_components.elements import button, container
|
|
3
|
+
|
|
4
|
+
from examples._source import source_view
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Counter(Component):
|
|
8
|
+
|
|
9
|
+
def __init__(self, **props):
|
|
10
|
+
super().__init__(**props)
|
|
11
|
+
self.state = dict(count=0)
|
|
12
|
+
|
|
13
|
+
def increment(self):
|
|
14
|
+
self.state.count += 1
|
|
15
|
+
|
|
16
|
+
def render(self):
|
|
17
|
+
return button(key="btn", on_click=self.increment)(
|
|
18
|
+
f"Clicked {self.state.count} times"
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class BasicDemo(Component):
|
|
23
|
+
def render(self):
|
|
24
|
+
return container(key="page")(
|
|
25
|
+
Counter(key="counter"),
|
|
26
|
+
source_view(__file__),
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
App(root=BasicDemo(key="app")).render()
|
examples/dashboard.py
ADDED
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
from st_components import App, Component, Ref, get_component_state, get_element_value
|
|
3
|
+
from st_components.elements import (
|
|
4
|
+
button, caption, code, columns, container, divider, expander, header, info,
|
|
5
|
+
json, markdown, metric, sidebar, slider, subheader, success, tabs, text,
|
|
6
|
+
text_area, text_input, title, toggle, warning,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
from examples._source import source_view
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class CounterCard(Component):
|
|
13
|
+
"""Simple stateful component used across the tutorial."""
|
|
14
|
+
|
|
15
|
+
def __init__(self, **props):
|
|
16
|
+
super().__init__(**props)
|
|
17
|
+
self.state = dict(value=self.props.get("initial", 0))
|
|
18
|
+
|
|
19
|
+
def increment(self):
|
|
20
|
+
self.state.value += 1
|
|
21
|
+
|
|
22
|
+
def decrement(self):
|
|
23
|
+
self.state.value = max(0, self.state.value - 1)
|
|
24
|
+
|
|
25
|
+
def reset(self):
|
|
26
|
+
self.state.value = 0
|
|
27
|
+
|
|
28
|
+
def render(self):
|
|
29
|
+
return container(key="card", border=True)(
|
|
30
|
+
metric(key="metric", label=self.props.label, value=self.state.value),
|
|
31
|
+
columns(key="actions")(
|
|
32
|
+
button(key="dec", on_click=self.decrement, disabled=self.state.value == 0, width="stretch")("−"),
|
|
33
|
+
button(key="inc", on_click=self.increment, width="stretch")("+"),
|
|
34
|
+
button(key="rst", on_click=self.reset, width="stretch")("↺"),
|
|
35
|
+
),
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class IntroCard(Component):
|
|
40
|
+
def render(self):
|
|
41
|
+
today = datetime.date.today().strftime("%A, %B %d")
|
|
42
|
+
return container(key="intro", border=True)(
|
|
43
|
+
title(key="title")("st-components tutorial dashboard"),
|
|
44
|
+
caption(key="date")(today),
|
|
45
|
+
markdown(key="body")(
|
|
46
|
+
"`st-components` gives Streamlit a small component model:\n\n"
|
|
47
|
+
"- `Component` keeps local state across reruns.\n"
|
|
48
|
+
"- `Element` wraps Streamlit primitives.\n"
|
|
49
|
+
"- `on_change` handlers receive the current widget value.\n"
|
|
50
|
+
"- `Ref()` lets you reach a component or stateful element later without hardcoding full paths."
|
|
51
|
+
),
|
|
52
|
+
info(key="tip")(
|
|
53
|
+
"Use the tabs below in order. Each section is interactive and illustrates one part of the API."
|
|
54
|
+
),
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class LocalStateDemo(Component):
|
|
59
|
+
def render(self):
|
|
60
|
+
return container(key="panel", border=True)(
|
|
61
|
+
subheader(key="h")("1. Local component state"),
|
|
62
|
+
caption(key="c")(
|
|
63
|
+
"Each CounterCard is recreated every rerun, but its state is restored from its fiber."
|
|
64
|
+
),
|
|
65
|
+
columns(key="cards")(
|
|
66
|
+
CounterCard(key="tasks", label="Tasks done", initial=2),
|
|
67
|
+
CounterCard(key="reviews", label="PR reviews", initial=1),
|
|
68
|
+
CounterCard(key="bugs", label="Bugs fixed", initial=0),
|
|
69
|
+
),
|
|
70
|
+
code(key="snippet", language="python")(
|
|
71
|
+
"class CounterCard(Component):\n"
|
|
72
|
+
" def __init__(self, **props):\n"
|
|
73
|
+
" super().__init__(**props)\n"
|
|
74
|
+
" self.state = dict(value=0)\n"
|
|
75
|
+
"\n"
|
|
76
|
+
" def increment(self):\n"
|
|
77
|
+
" self.state.value += 1"
|
|
78
|
+
),
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class ElementValueDemo(Component):
|
|
83
|
+
def __init__(self, **props):
|
|
84
|
+
super().__init__(**props)
|
|
85
|
+
self.state = dict(
|
|
86
|
+
task="Prototype refs",
|
|
87
|
+
focus=7,
|
|
88
|
+
blocked=False,
|
|
89
|
+
notes="",
|
|
90
|
+
last_event="Waiting for a widget change",
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
def sync_task(self, value):
|
|
94
|
+
self.state.task = value
|
|
95
|
+
self.state.last_event = f"task -> {value!r}"
|
|
96
|
+
|
|
97
|
+
def sync_focus(self, value):
|
|
98
|
+
self.state.focus = value
|
|
99
|
+
self.state.last_event = f"focus -> {value}"
|
|
100
|
+
|
|
101
|
+
def sync_blocked(self, value):
|
|
102
|
+
self.state.blocked = value
|
|
103
|
+
self.state.last_event = f"blocked -> {value}"
|
|
104
|
+
|
|
105
|
+
def sync_notes(self, value):
|
|
106
|
+
self.state.notes = value
|
|
107
|
+
self.state.last_event = f"notes -> {len(value)} chars"
|
|
108
|
+
|
|
109
|
+
def render(self):
|
|
110
|
+
snapshot = {
|
|
111
|
+
"task": self.state.task,
|
|
112
|
+
"focus": self.state.focus,
|
|
113
|
+
"blocked": self.state.blocked,
|
|
114
|
+
"notes": self.state.notes,
|
|
115
|
+
"last_event": self.state.last_event,
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return container(key="panel", border=True)(
|
|
119
|
+
subheader(key="h")("2. Widget values in callbacks"),
|
|
120
|
+
caption(key="c")(
|
|
121
|
+
"Stateful Elements pass their current value to `on_change`, so simple widget-to-state sync stays explicit and lightweight."
|
|
122
|
+
),
|
|
123
|
+
text_input(key="task", value=self.state.task, on_change=self.sync_task)("Current task"),
|
|
124
|
+
slider(key="focus", min_value=0, max_value=10, value=self.state.focus, on_change=self.sync_focus)("Focus level"),
|
|
125
|
+
toggle(key="blocked", value=self.state.blocked, on_change=self.sync_blocked)("Blocked right now"),
|
|
126
|
+
text_area(
|
|
127
|
+
key="notes",
|
|
128
|
+
value=self.state.notes,
|
|
129
|
+
height=120,
|
|
130
|
+
on_change=self.sync_notes,
|
|
131
|
+
placeholder="Type here to update component state from a widget callback.",
|
|
132
|
+
)("Notes"),
|
|
133
|
+
columns(key="metrics")(
|
|
134
|
+
metric(key="task_metric", label="Task", value=self.state.task or "None"),
|
|
135
|
+
metric(key="focus_metric", label="Focus", value=self.state.focus),
|
|
136
|
+
metric(key="blocked_metric", label="Blocked", value="Yes" if self.state.blocked else "No"),
|
|
137
|
+
),
|
|
138
|
+
success(key="hint")(
|
|
139
|
+
f"Last callback: {self.state.last_event}"
|
|
140
|
+
),
|
|
141
|
+
json(key="snapshot")(snapshot),
|
|
142
|
+
code(key="snippet", language="python")(
|
|
143
|
+
"def sync_task(self, value):\n"
|
|
144
|
+
" self.state.task = value\n"
|
|
145
|
+
"\n"
|
|
146
|
+
"def render(self):\n"
|
|
147
|
+
" return text_input(key=\"task\", on_change=self.sync_task)(\"Current task\")"
|
|
148
|
+
),
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class RefInspectorDemo(Component):
|
|
153
|
+
def __init__(self, **props):
|
|
154
|
+
super().__init__(**props)
|
|
155
|
+
self.name_ref = Ref()
|
|
156
|
+
self.notes_ref = Ref()
|
|
157
|
+
self.counter_ref = Ref()
|
|
158
|
+
self.state = dict(
|
|
159
|
+
name="Shipping tutorial dashboard",
|
|
160
|
+
notes="Refs resolve to stable logical paths.",
|
|
161
|
+
snapshot={},
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
def capture_refs(self):
|
|
165
|
+
self.state.snapshot = {
|
|
166
|
+
"name_ref_path": self.name_ref.path,
|
|
167
|
+
"name_ref_value": get_element_value(self.name_ref),
|
|
168
|
+
"notes_ref_path": self.notes_ref.path,
|
|
169
|
+
"notes_ref_value": get_element_value(self.notes_ref),
|
|
170
|
+
"counter_ref_path": self.counter_ref.path,
|
|
171
|
+
"counter_ref_state": dict(get_component_state(self.counter_ref)),
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
def render(self):
|
|
175
|
+
return container(key="panel", border=True)(
|
|
176
|
+
subheader(key="h")("3. Reach things later with Ref()"),
|
|
177
|
+
caption(key="c")(
|
|
178
|
+
"Refs store logical paths, not Python instances. Render first, then pass them to helpers like get_element_value(...) or get_component_state(...)."
|
|
179
|
+
),
|
|
180
|
+
text_input(
|
|
181
|
+
key="name",
|
|
182
|
+
ref=self.name_ref,
|
|
183
|
+
value=self.state.name,
|
|
184
|
+
on_change=self.sync_state("name"),
|
|
185
|
+
)("Title tracked by ref"),
|
|
186
|
+
text_area(
|
|
187
|
+
key="notes",
|
|
188
|
+
ref=self.notes_ref,
|
|
189
|
+
value=self.state.notes,
|
|
190
|
+
height=100,
|
|
191
|
+
on_change=self.sync_state("notes"),
|
|
192
|
+
)("Notes tracked by ref"),
|
|
193
|
+
CounterCard(key="counter", ref=self.counter_ref, label="Counter reached through ref", initial=3),
|
|
194
|
+
button(key="read_refs", on_click=self.capture_refs, type="primary")("Read refs now"),
|
|
195
|
+
json(key="snapshot")(self.state.snapshot or {"status": "Click 'Read refs now' after changing the inputs or counter."}),
|
|
196
|
+
code(key="snippet", language="python")(
|
|
197
|
+
"name_ref = Ref()\n"
|
|
198
|
+
"counter_ref = Ref()\n"
|
|
199
|
+
"\n"
|
|
200
|
+
"text_input(key=\"name\", ref=name_ref)(\"Name\")\n"
|
|
201
|
+
"CounterCard(key=\"counter\", ref=counter_ref)\n"
|
|
202
|
+
"\n"
|
|
203
|
+
"snapshot = {\n"
|
|
204
|
+
" \"name\": get_element_value(name_ref),\n"
|
|
205
|
+
" \"count\": get_component_state(counter_ref).value,\n"
|
|
206
|
+
"}"
|
|
207
|
+
),
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
class CompositionDemo(Component):
|
|
212
|
+
def __init__(self, **props):
|
|
213
|
+
super().__init__(**props)
|
|
214
|
+
self.state = dict(saved=False)
|
|
215
|
+
|
|
216
|
+
def mark_dirty(self, value):
|
|
217
|
+
self.state.saved = False
|
|
218
|
+
|
|
219
|
+
def mark_saved(self):
|
|
220
|
+
self.state.saved = True
|
|
221
|
+
|
|
222
|
+
def render(self):
|
|
223
|
+
return container(key="panel", border=True)(
|
|
224
|
+
subheader(key="h")("4. Compose simple Elements into richer Components"),
|
|
225
|
+
caption(key="c")(
|
|
226
|
+
"The library stays small by making each base Element wrap one Streamlit primitive. Rich behavior lives in Components."
|
|
227
|
+
),
|
|
228
|
+
expander(key="notes_box", label="Mini editor built by composition", expanded=True)(
|
|
229
|
+
text_area(
|
|
230
|
+
key="draft",
|
|
231
|
+
height=140,
|
|
232
|
+
placeholder="Write something, then click save.",
|
|
233
|
+
on_change=self.mark_dirty,
|
|
234
|
+
)("Draft"),
|
|
235
|
+
columns(key="row")(
|
|
236
|
+
button(key="save", on_click=self.mark_saved, type="primary")("Save"),
|
|
237
|
+
success(key="saved")("Saved") if self.state.saved else warning(key="dirty")("Unsaved changes"),
|
|
238
|
+
),
|
|
239
|
+
),
|
|
240
|
+
markdown(key="body")(
|
|
241
|
+
"This mini editor is not a special built-in widget. It is just:\n\n"
|
|
242
|
+
"- `text_area`\n"
|
|
243
|
+
"- `button`\n"
|
|
244
|
+
"- feedback Elements\n"
|
|
245
|
+
"- a small `Component` holding local state"
|
|
246
|
+
),
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
class SidebarGuide(Component):
|
|
251
|
+
def render(self):
|
|
252
|
+
return sidebar(key="sidebar")(
|
|
253
|
+
header(key="h")("st-components"),
|
|
254
|
+
caption(key="c")("React-like patterns for Streamlit"),
|
|
255
|
+
divider(key="d1"),
|
|
256
|
+
markdown(key="agenda")(
|
|
257
|
+
"This dashboard demonstrates:\n\n"
|
|
258
|
+
"1. local component state\n"
|
|
259
|
+
"2. widget values in callbacks\n"
|
|
260
|
+
"3. `Ref()`\n"
|
|
261
|
+
"4. composition of simple Elements"
|
|
262
|
+
),
|
|
263
|
+
divider(key="d2"),
|
|
264
|
+
text(key="rule")("Mental model"),
|
|
265
|
+
markdown(key="model")(
|
|
266
|
+
"- Components own state through fibers.\n"
|
|
267
|
+
"- Widgets keep their value in `st.session_state`.\n"
|
|
268
|
+
"- Refs point to paths, not instances."
|
|
269
|
+
),
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
class Dashboard(Component):
|
|
274
|
+
def render(self):
|
|
275
|
+
return container(key="page")(
|
|
276
|
+
SidebarGuide(key="guide"),
|
|
277
|
+
IntroCard(key="intro"),
|
|
278
|
+
tabs(key="sections", tabs=["State", "Widget values", "Refs", "Composition"])(
|
|
279
|
+
LocalStateDemo(key="state_demo"),
|
|
280
|
+
ElementValueDemo(key="element_demo"),
|
|
281
|
+
RefInspectorDemo(key="ref_demo"),
|
|
282
|
+
CompositionDemo(key="composition_demo"),
|
|
283
|
+
),
|
|
284
|
+
source_view(__file__),
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
App(root=Dashboard(key="dashboard")).render()
|