streamlit-react-components 0.1.0__tar.gz → 1.0.0__tar.gz
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.
- streamlit_react_components-1.0.0/PKG-INFO +854 -0
- streamlit_react_components-1.0.0/README.md +835 -0
- {streamlit_react_components-0.1.0 → streamlit_react_components-1.0.0}/pyproject.toml +1 -1
- {streamlit_react_components-0.1.0 → streamlit_react_components-1.0.0}/src/streamlit_react_components/__init__.py +2 -0
- streamlit_react_components-1.0.0/src/streamlit_react_components/_frontend/index.css +1 -0
- streamlit_react_components-1.0.0/src/streamlit_react_components/_frontend/index.js +3920 -0
- {streamlit_react_components-0.1.0 → streamlit_react_components-1.0.0}/src/streamlit_react_components/common/__init__.py +2 -0
- {streamlit_react_components-0.1.0 → streamlit_react_components-1.0.0}/src/streamlit_react_components/common/button_group.py +13 -1
- streamlit_react_components-1.0.0/src/streamlit_react_components/common/plotly_chart.py +216 -0
- {streamlit_react_components-0.1.0 → streamlit_react_components-1.0.0}/src/streamlit_react_components/common/section_header.py +33 -3
- {streamlit_react_components-0.1.0 → streamlit_react_components-1.0.0}/src/streamlit_react_components/common/stat_card.py +10 -1
- {streamlit_react_components-0.1.0 → streamlit_react_components-1.0.0}/src/streamlit_react_components/form/form_slider.py +12 -1
- streamlit_react_components-1.0.0/src/streamlit_react_components.egg-info/PKG-INFO +854 -0
- {streamlit_react_components-0.1.0 → streamlit_react_components-1.0.0}/src/streamlit_react_components.egg-info/SOURCES.txt +2 -0
- streamlit_react_components-0.1.0/PKG-INFO +0 -18
- streamlit_react_components-0.1.0/src/streamlit_react_components/_frontend/index.css +0 -1
- streamlit_react_components-0.1.0/src/streamlit_react_components/_frontend/index.js +0 -63
- streamlit_react_components-0.1.0/src/streamlit_react_components.egg-info/PKG-INFO +0 -18
- {streamlit_react_components-0.1.0 → streamlit_react_components-1.0.0}/MANIFEST.in +0 -0
- {streamlit_react_components-0.1.0 → streamlit_react_components-1.0.0}/setup.cfg +0 -0
- {streamlit_react_components-0.1.0 → streamlit_react_components-1.0.0}/src/streamlit_react_components/_frontend/index.html +0 -0
- {streamlit_react_components-0.1.0 → streamlit_react_components-1.0.0}/src/streamlit_react_components/common/chart_legend.py +0 -0
- {streamlit_react_components-0.1.0 → streamlit_react_components-1.0.0}/src/streamlit_react_components/common/data_table.py +0 -0
- {streamlit_react_components-0.1.0 → streamlit_react_components-1.0.0}/src/streamlit_react_components/common/metric_row.py +0 -0
- {streamlit_react_components-0.1.0 → streamlit_react_components-1.0.0}/src/streamlit_react_components/common/panel.py +0 -0
- {streamlit_react_components-0.1.0 → streamlit_react_components-1.0.0}/src/streamlit_react_components/common/step_indicator.py +0 -0
- {streamlit_react_components-0.1.0 → streamlit_react_components-1.0.0}/src/streamlit_react_components/form/__init__.py +0 -0
- {streamlit_react_components-0.1.0 → streamlit_react_components-1.0.0}/src/streamlit_react_components/form/checkbox_group.py +0 -0
- {streamlit_react_components-0.1.0 → streamlit_react_components-1.0.0}/src/streamlit_react_components/form/form_select.py +0 -0
- {streamlit_react_components-0.1.0 → streamlit_react_components-1.0.0}/src/streamlit_react_components.egg-info/dependency_links.txt +0 -0
- {streamlit_react_components-0.1.0 → streamlit_react_components-1.0.0}/src/streamlit_react_components.egg-info/requires.txt +0 -0
- {streamlit_react_components-0.1.0 → streamlit_react_components-1.0.0}/src/streamlit_react_components.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,854 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: streamlit-react-components
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Reusable React-based Streamlit components with Tailwind CSS styling
|
|
5
|
+
License: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/your-org/streamlit-react-components
|
|
7
|
+
Classifier: Development Status :: 3 - Alpha
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Requires-Python: >=3.8
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
Requires-Dist: streamlit>=1.24.0
|
|
19
|
+
|
|
20
|
+
# Streamlit React Components
|
|
21
|
+
|
|
22
|
+
A collection of 12 reusable React-based Streamlit components with Tailwind CSS styling. All components support custom inline styles and Tailwind class names.
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install streamlit-react-components
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Quick Start
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
import streamlit as st
|
|
34
|
+
from streamlit_react_components import (
|
|
35
|
+
panel, section_header, stat_card, metric_row,
|
|
36
|
+
data_table, step_indicator, button_group, chart_legend,
|
|
37
|
+
plotly_chart, form_select, form_slider, checkbox_group
|
|
38
|
+
)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Styling
|
|
44
|
+
|
|
45
|
+
All components accept two styling parameters:
|
|
46
|
+
|
|
47
|
+
| Parameter | Type | Description |
|
|
48
|
+
|-----------|------|-------------|
|
|
49
|
+
| `style` | `dict` | Inline CSS as Python dict (e.g., `{"background": "#1e293b", "padding": "16px"}`) |
|
|
50
|
+
| `class_name` | `str` | Tailwind CSS classes (e.g., `"bg-slate-900 p-4 rounded-lg"`) |
|
|
51
|
+
|
|
52
|
+
### Example
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
stat_card(
|
|
56
|
+
label="Revenue",
|
|
57
|
+
value="$50K",
|
|
58
|
+
color="blue",
|
|
59
|
+
style={"minWidth": "200px", "boxShadow": "0 4px 6px rgba(0,0,0,0.3)"},
|
|
60
|
+
class_name="border border-blue-500"
|
|
61
|
+
)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Components
|
|
67
|
+
|
|
68
|
+
### 1. Panel
|
|
69
|
+
|
|
70
|
+
A styled container/card wrapper.
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
panel(
|
|
74
|
+
children: str = "", # HTML content
|
|
75
|
+
style: dict = None,
|
|
76
|
+
class_name: str = "",
|
|
77
|
+
key: str = None
|
|
78
|
+
) -> None
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
#### Example
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
panel(
|
|
85
|
+
children="<h3 style='color: white;'>Title</h3><p style='color: #94a3b8;'>Content here</p>",
|
|
86
|
+
class_name="border border-blue-500"
|
|
87
|
+
)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
#### Default Styling
|
|
91
|
+
- Background: `bg-slate-900`
|
|
92
|
+
- Border radius: `rounded-lg`
|
|
93
|
+
- Padding: `p-4`
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
### 2. Section Header
|
|
98
|
+
|
|
99
|
+
A section title with optional action buttons.
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
section_header(
|
|
103
|
+
title: str, # Header text
|
|
104
|
+
icon: str = "", # Emoji or icon prefix
|
|
105
|
+
actions: list = None, # List of action buttons
|
|
106
|
+
style: dict = None,
|
|
107
|
+
class_name: str = "",
|
|
108
|
+
key: str = None
|
|
109
|
+
) -> str | None # Returns clicked action ID
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
#### Actions Format
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
actions = [
|
|
116
|
+
{"id": "refresh", "label": "Refresh", "color": "blue"},
|
|
117
|
+
{"id": "export", "icon": "📥", "label": "Export", "color": "green"}
|
|
118
|
+
]
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
| Action Key | Type | Description |
|
|
122
|
+
|------------|------|-------------|
|
|
123
|
+
| `id` | `str` | Unique identifier (returned on click) |
|
|
124
|
+
| `label` | `str` | Button text (optional) |
|
|
125
|
+
| `icon` | `str` | Emoji/icon (optional) |
|
|
126
|
+
| `color` | `str` | Preset (`"blue"`, `"green"`, `"red"`, `"yellow"`, `"purple"`, `"slate"`) or hex (e.g., `"#94a3b8"`) |
|
|
127
|
+
| `style` | `dict` | Inline CSS styles for this button (optional) |
|
|
128
|
+
| `className` | `str` | Tailwind classes for this button (optional) |
|
|
129
|
+
| `href` | `str` | URL for link actions. External URLs (http/https) open in new tab (optional) |
|
|
130
|
+
|
|
131
|
+
#### Example
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
# Using preset colors
|
|
135
|
+
clicked = section_header(
|
|
136
|
+
title="Executive Summary",
|
|
137
|
+
icon="📊",
|
|
138
|
+
actions=[
|
|
139
|
+
{"id": "refresh", "label": "Refresh", "color": "blue"},
|
|
140
|
+
{"id": "settings", "icon": "⚙️", "color": "slate"}
|
|
141
|
+
]
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
# Using hex colors and custom styling
|
|
145
|
+
clicked = section_header(
|
|
146
|
+
title="Custom Actions",
|
|
147
|
+
actions=[
|
|
148
|
+
{"id": "custom", "label": "Custom", "color": "#ff5733"},
|
|
149
|
+
{"id": "styled", "label": "Styled", "style": {"padding": "12px", "borderRadius": "20px"}}
|
|
150
|
+
]
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
# External link (opens in new tab)
|
|
154
|
+
section_header(
|
|
155
|
+
title="Resources",
|
|
156
|
+
actions=[
|
|
157
|
+
{"id": "docs", "label": "Documentation", "href": "https://docs.example.com", "icon": "📚"},
|
|
158
|
+
{"id": "github", "label": "GitHub", "href": "https://github.com", "color": "slate"}
|
|
159
|
+
]
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
# Internal page navigation
|
|
163
|
+
clicked = section_header(
|
|
164
|
+
title="Settings",
|
|
165
|
+
actions=[{"id": "home", "label": "Home", "icon": "🏠"}]
|
|
166
|
+
)
|
|
167
|
+
if clicked == "home":
|
|
168
|
+
st.switch_page("pages/home.py")
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
### 3. Stat Card
|
|
174
|
+
|
|
175
|
+
A statistics display card with colored accent.
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
stat_card(
|
|
179
|
+
label: str, # Description text
|
|
180
|
+
value: str | int | float, # The statistic value
|
|
181
|
+
color: str = "blue", # Accent color
|
|
182
|
+
icon: str = "", # Optional icon
|
|
183
|
+
style: dict = None,
|
|
184
|
+
class_name: str = "",
|
|
185
|
+
key: str = None
|
|
186
|
+
) -> None
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
#### Colors
|
|
190
|
+
|
|
191
|
+
Supports preset color names or hex values:
|
|
192
|
+
|
|
193
|
+
| Preset | Border | Text |
|
|
194
|
+
|--------|--------|------|
|
|
195
|
+
| `"blue"` | `border-blue-500` | `text-blue-400` |
|
|
196
|
+
| `"green"` | `border-green-500` | `text-green-400` |
|
|
197
|
+
| `"red"` | `border-red-500` | `text-red-400` |
|
|
198
|
+
| `"yellow"` | `border-yellow-500` | `text-yellow-400` |
|
|
199
|
+
| `"purple"` | `border-purple-500` | `text-purple-400` |
|
|
200
|
+
| `"slate"` | `border-slate-500` | `text-slate-400` |
|
|
201
|
+
| `"#xxxxxx"` | Custom hex color | Custom hex color |
|
|
202
|
+
|
|
203
|
+
#### Example
|
|
204
|
+
|
|
205
|
+
```python
|
|
206
|
+
col1, col2, col3, col4 = st.columns(4)
|
|
207
|
+
|
|
208
|
+
with col1:
|
|
209
|
+
stat_card(label="Within Threshold", value="4", color="green")
|
|
210
|
+
with col2:
|
|
211
|
+
stat_card(label="Above (Risk)", value="2", color="red")
|
|
212
|
+
with col3:
|
|
213
|
+
stat_card(label="Below (Underutil)", value="1", color="yellow")
|
|
214
|
+
with col4:
|
|
215
|
+
stat_card(label="Avg OEE", value="78.4%", color="blue")
|
|
216
|
+
|
|
217
|
+
# Using hex color
|
|
218
|
+
stat_card(label="Custom Color", value="42", color="#ff5733")
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
### 4. Metric Row
|
|
224
|
+
|
|
225
|
+
A key-value display row.
|
|
226
|
+
|
|
227
|
+
```python
|
|
228
|
+
metric_row(
|
|
229
|
+
label: str, # Left-side label
|
|
230
|
+
value: str, # Right-side value
|
|
231
|
+
value_color: str = "", # Tailwind text color class
|
|
232
|
+
style: dict = None,
|
|
233
|
+
class_name: str = "",
|
|
234
|
+
key: str = None
|
|
235
|
+
) -> None
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
#### Example
|
|
239
|
+
|
|
240
|
+
```python
|
|
241
|
+
metric_row(label="Mean", value="78.4%")
|
|
242
|
+
metric_row(label="Median", value="79.0%")
|
|
243
|
+
metric_row(label="Outliers", value="3", value_color="text-red-400")
|
|
244
|
+
metric_row(label="Trend", value="↑ +0.4%/mo", value_color="text-green-400")
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
#### Common Value Colors
|
|
248
|
+
|
|
249
|
+
| Color | Class |
|
|
250
|
+
|-------|-------|
|
|
251
|
+
| Green | `text-green-400` |
|
|
252
|
+
| Red | `text-red-400` |
|
|
253
|
+
| Yellow | `text-yellow-400` |
|
|
254
|
+
| Blue | `text-blue-400` |
|
|
255
|
+
| Gray | `text-slate-400` |
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
### 5. Data Table
|
|
260
|
+
|
|
261
|
+
A styled data table with row click support.
|
|
262
|
+
|
|
263
|
+
```python
|
|
264
|
+
data_table(
|
|
265
|
+
columns: list, # Column definitions
|
|
266
|
+
rows: list, # Row data
|
|
267
|
+
show_header: bool = True,
|
|
268
|
+
style: dict = None,
|
|
269
|
+
class_name: str = "",
|
|
270
|
+
key: str = None
|
|
271
|
+
) -> dict | None # Returns {rowIndex, rowData} on click
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
#### Column Definition
|
|
275
|
+
|
|
276
|
+
```python
|
|
277
|
+
columns = [
|
|
278
|
+
{"key": "name", "label": "Name"},
|
|
279
|
+
{"key": "value", "label": "Value", "align": "right", "format": "number"},
|
|
280
|
+
{"key": "percent", "label": "%", "align": "center", "format": "percent"},
|
|
281
|
+
{"key": "status", "label": "Status", "colorByValue": True}
|
|
282
|
+
]
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
| Column Key | Type | Description |
|
|
286
|
+
|------------|------|-------------|
|
|
287
|
+
| `key` | `str` | Data key in row dict |
|
|
288
|
+
| `label` | `str` | Column header text |
|
|
289
|
+
| `align` | `str` | `"left"`, `"center"`, `"right"` |
|
|
290
|
+
| `format` | `str` | `"number"` (adds commas), `"percent"` (adds %) |
|
|
291
|
+
| `colorByValue` | `bool` | Color based on status values |
|
|
292
|
+
|
|
293
|
+
#### Auto-Colored Values
|
|
294
|
+
|
|
295
|
+
When `colorByValue: True`, these values get automatic colors:
|
|
296
|
+
|
|
297
|
+
| Value | Color |
|
|
298
|
+
|-------|-------|
|
|
299
|
+
| `"above"` | Red |
|
|
300
|
+
| `"below"` | Yellow |
|
|
301
|
+
| `"within"` | Green |
|
|
302
|
+
| `"approved"` | Green |
|
|
303
|
+
| `"rejected"` | Red |
|
|
304
|
+
| `"submitted"` | Yellow |
|
|
305
|
+
| `"draft"` | Gray |
|
|
306
|
+
|
|
307
|
+
#### Example
|
|
308
|
+
|
|
309
|
+
```python
|
|
310
|
+
columns = [
|
|
311
|
+
{"key": "site", "label": "Site"},
|
|
312
|
+
{"key": "line", "label": "Line"},
|
|
313
|
+
{"key": "util", "label": "Utilization", "align": "right", "format": "percent"},
|
|
314
|
+
{"key": "volume", "label": "Volume", "align": "right", "format": "number"},
|
|
315
|
+
{"key": "status", "label": "Status", "align": "center", "colorByValue": True}
|
|
316
|
+
]
|
|
317
|
+
|
|
318
|
+
rows = [
|
|
319
|
+
{"site": "AML_14", "line": "L1", "util": 94, "volume": 125000, "status": "above"},
|
|
320
|
+
{"site": "ADL", "line": "L2", "util": 72, "volume": 98000, "status": "within"},
|
|
321
|
+
{"site": "Devens", "line": "L3", "util": 58, "volume": 45000, "status": "below"}
|
|
322
|
+
]
|
|
323
|
+
|
|
324
|
+
clicked = data_table(columns=columns, rows=rows)
|
|
325
|
+
|
|
326
|
+
if clicked:
|
|
327
|
+
st.write(f"Selected row {clicked['rowIndex']}: {clicked['rowData']}")
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
### 6. Step Indicator
|
|
333
|
+
|
|
334
|
+
A multi-step wizard progress indicator.
|
|
335
|
+
|
|
336
|
+
```python
|
|
337
|
+
step_indicator(
|
|
338
|
+
steps: list, # List of step labels
|
|
339
|
+
current_step: int, # Current step (1-indexed)
|
|
340
|
+
style: dict = None,
|
|
341
|
+
class_name: str = "",
|
|
342
|
+
key: str = None
|
|
343
|
+
) -> int | None # Returns clicked step number
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
#### Example
|
|
347
|
+
|
|
348
|
+
```python
|
|
349
|
+
if "step" not in st.session_state:
|
|
350
|
+
st.session_state.step = 1
|
|
351
|
+
|
|
352
|
+
clicked = step_indicator(
|
|
353
|
+
steps=["Supply Plan", "Configure Levers", "Review & Submit"],
|
|
354
|
+
current_step=st.session_state.step
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
if clicked:
|
|
358
|
+
st.session_state.step = clicked
|
|
359
|
+
st.rerun()
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
#### Visual States
|
|
363
|
+
|
|
364
|
+
| State | Appearance |
|
|
365
|
+
|-------|------------|
|
|
366
|
+
| Completed (< current) | Green circle with ✓ |
|
|
367
|
+
| Current | Blue circle with number |
|
|
368
|
+
| Future (> current) | Gray circle with number |
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
### 7. Button Group
|
|
373
|
+
|
|
374
|
+
A group of action buttons.
|
|
375
|
+
|
|
376
|
+
```python
|
|
377
|
+
button_group(
|
|
378
|
+
buttons: list, # List of button configs
|
|
379
|
+
style: dict = None,
|
|
380
|
+
class_name: str = "",
|
|
381
|
+
key: str = None
|
|
382
|
+
) -> str | None # Returns clicked button ID
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
#### Button Definition
|
|
386
|
+
|
|
387
|
+
```python
|
|
388
|
+
buttons = [
|
|
389
|
+
{"id": "view", "icon": "👁️"},
|
|
390
|
+
{"id": "edit", "icon": "✏️", "label": "Edit"},
|
|
391
|
+
{"id": "approve", "icon": "✓", "color": "green"},
|
|
392
|
+
{"id": "reject", "icon": "✕", "color": "red", "disabled": True}
|
|
393
|
+
]
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
| Button Key | Type | Description |
|
|
397
|
+
|------------|------|-------------|
|
|
398
|
+
| `id` | `str` | Unique identifier (returned on click) |
|
|
399
|
+
| `label` | `str` | Button text (optional) |
|
|
400
|
+
| `icon` | `str` | Emoji/icon (optional) |
|
|
401
|
+
| `color` | `str` | Preset (`"blue"`, `"green"`, `"red"`, `"yellow"`, `"purple"`, `"slate"`) or hex (e.g., `"#94a3b8"`) |
|
|
402
|
+
| `disabled` | `bool` | Disable the button |
|
|
403
|
+
| `style` | `dict` | Inline CSS styles for this button (optional) |
|
|
404
|
+
| `className` | `str` | Tailwind classes for this button (optional) |
|
|
405
|
+
|
|
406
|
+
#### Example
|
|
407
|
+
|
|
408
|
+
```python
|
|
409
|
+
# Using preset colors
|
|
410
|
+
clicked = button_group(
|
|
411
|
+
buttons=[
|
|
412
|
+
{"id": "view", "icon": "👁️", "label": "View"},
|
|
413
|
+
{"id": "edit", "icon": "✏️", "label": "Edit"},
|
|
414
|
+
{"id": "delete", "icon": "🗑️", "color": "red"}
|
|
415
|
+
]
|
|
416
|
+
)
|
|
417
|
+
|
|
418
|
+
# Using hex colors and custom styling
|
|
419
|
+
clicked = button_group(
|
|
420
|
+
buttons=[
|
|
421
|
+
{"id": "custom", "icon": "🎨", "color": "#ff5733"},
|
|
422
|
+
{"id": "styled", "label": "Styled", "style": {"padding": "12px"}}
|
|
423
|
+
]
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
if clicked == "delete":
|
|
427
|
+
st.warning("Delete clicked!")
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
---
|
|
431
|
+
|
|
432
|
+
### 8. Chart Legend
|
|
433
|
+
|
|
434
|
+
A legend for charts with colored indicators.
|
|
435
|
+
|
|
436
|
+
```python
|
|
437
|
+
chart_legend(
|
|
438
|
+
items: list, # List of legend items
|
|
439
|
+
style: dict = None,
|
|
440
|
+
class_name: str = "",
|
|
441
|
+
key: str = None
|
|
442
|
+
) -> None
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
#### Items Format
|
|
446
|
+
|
|
447
|
+
```python
|
|
448
|
+
items = [
|
|
449
|
+
{"color": "#94a3b8", "label": "Historical"},
|
|
450
|
+
{"color": "#ef4444", "label": "Outlier"},
|
|
451
|
+
{"color": "#8b5cf6", "label": "Prophet"},
|
|
452
|
+
{"color": "#10b981", "label": "ARIMA"}
|
|
453
|
+
]
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
#### Example
|
|
457
|
+
|
|
458
|
+
```python
|
|
459
|
+
# Display a chart (using st.line_chart, plotly, etc.)
|
|
460
|
+
st.line_chart(data)
|
|
461
|
+
|
|
462
|
+
# Add legend below
|
|
463
|
+
chart_legend(
|
|
464
|
+
items=[
|
|
465
|
+
{"color": "#3b82f6", "label": "Actual"},
|
|
466
|
+
{"color": "#ef4444", "label": "Upper Threshold"},
|
|
467
|
+
{"color": "#eab308", "label": "Lower Threshold"},
|
|
468
|
+
{"color": "#8b5cf6", "label": "Forecast"}
|
|
469
|
+
]
|
|
470
|
+
)
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
---
|
|
474
|
+
|
|
475
|
+
### 9. Plotly Chart
|
|
476
|
+
|
|
477
|
+
Render Plotly charts with full interactivity and event callbacks.
|
|
478
|
+
|
|
479
|
+
```python
|
|
480
|
+
plotly_chart(
|
|
481
|
+
# Data source (one required)
|
|
482
|
+
figure: Any = None, # Plotly figure or dict
|
|
483
|
+
data: DataFrame = None, # pandas DataFrame
|
|
484
|
+
|
|
485
|
+
# DataFrame options (when using data=)
|
|
486
|
+
x: str = None, # Column name for x-axis
|
|
487
|
+
y: str | list = None, # Column name(s) for y-axis
|
|
488
|
+
color: str = None, # Column name for color grouping
|
|
489
|
+
chart_type: str = "line", # "line", "bar", "scatter", "area", "pie", "histogram"
|
|
490
|
+
title: str = None, # Chart title
|
|
491
|
+
|
|
492
|
+
# Plotly config
|
|
493
|
+
config: dict = None, # Plotly config options
|
|
494
|
+
|
|
495
|
+
# Event callbacks
|
|
496
|
+
on_click: bool = False, # Enable click events
|
|
497
|
+
on_select: bool = False, # Enable selection events
|
|
498
|
+
on_hover: bool = False, # Enable hover events
|
|
499
|
+
on_relayout: bool = False, # Enable zoom/pan events
|
|
500
|
+
|
|
501
|
+
# Styling
|
|
502
|
+
style: dict = None,
|
|
503
|
+
class_name: str = "",
|
|
504
|
+
key: str = None
|
|
505
|
+
) -> dict | None # Returns event dict or None
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
#### Using Plotly Figure
|
|
509
|
+
|
|
510
|
+
```python
|
|
511
|
+
import plotly.graph_objects as go
|
|
512
|
+
|
|
513
|
+
fig = go.Figure(
|
|
514
|
+
data=[
|
|
515
|
+
go.Scatter(x=[1,2,3,4,5], y=[10,15,13,17,20], mode='lines+markers', name='Sales'),
|
|
516
|
+
go.Bar(x=[1,2,3,4,5], y=[5,8,6,9,12], name='Orders')
|
|
517
|
+
],
|
|
518
|
+
layout=go.Layout(title='Sales Dashboard')
|
|
519
|
+
)
|
|
520
|
+
|
|
521
|
+
event = plotly_chart(
|
|
522
|
+
figure=fig,
|
|
523
|
+
on_click=True,
|
|
524
|
+
on_select=True,
|
|
525
|
+
style={"height": "400px"}
|
|
526
|
+
)
|
|
527
|
+
|
|
528
|
+
if event and event['type'] == 'click':
|
|
529
|
+
st.write(f"Clicked: {event['points']}")
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
#### Using DataFrame
|
|
533
|
+
|
|
534
|
+
```python
|
|
535
|
+
import pandas as pd
|
|
536
|
+
|
|
537
|
+
df = pd.DataFrame({
|
|
538
|
+
'month': ['Jan', 'Feb', 'Mar', 'Apr'],
|
|
539
|
+
'sales': [100, 150, 120, 180],
|
|
540
|
+
'orders': [50, 75, 60, 90]
|
|
541
|
+
})
|
|
542
|
+
|
|
543
|
+
# Simple line chart
|
|
544
|
+
event = plotly_chart(
|
|
545
|
+
data=df,
|
|
546
|
+
x='month',
|
|
547
|
+
y='sales',
|
|
548
|
+
chart_type='line',
|
|
549
|
+
title='Monthly Sales'
|
|
550
|
+
)
|
|
551
|
+
|
|
552
|
+
# Multiple y columns as bar chart
|
|
553
|
+
event = plotly_chart(
|
|
554
|
+
data=df,
|
|
555
|
+
x='month',
|
|
556
|
+
y=['sales', 'orders'],
|
|
557
|
+
chart_type='bar',
|
|
558
|
+
title='Sales vs Orders'
|
|
559
|
+
)
|
|
560
|
+
|
|
561
|
+
# Scatter with color grouping
|
|
562
|
+
event = plotly_chart(
|
|
563
|
+
data=df,
|
|
564
|
+
x='sales',
|
|
565
|
+
y='orders',
|
|
566
|
+
color='month',
|
|
567
|
+
chart_type='scatter'
|
|
568
|
+
)
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
#### Chart Types (DataFrame mode)
|
|
572
|
+
|
|
573
|
+
| Type | Description |
|
|
574
|
+
|------|-------------|
|
|
575
|
+
| `"line"` | Line chart with connected points |
|
|
576
|
+
| `"scatter"` | Scatter plot with markers only |
|
|
577
|
+
| `"bar"` | Vertical bar chart |
|
|
578
|
+
| `"area"` | Area chart (filled line) |
|
|
579
|
+
| `"pie"` | Pie chart (x=labels, y=values) |
|
|
580
|
+
| `"histogram"` | Histogram of x values |
|
|
581
|
+
|
|
582
|
+
#### Event Types
|
|
583
|
+
|
|
584
|
+
| Event | When Triggered | Data Returned |
|
|
585
|
+
|-------|----------------|---------------|
|
|
586
|
+
| `click` | User clicks a data point | `{type: 'click', points: [...]}` |
|
|
587
|
+
| `select` | User box/lasso selects points | `{type: 'select', points: [...]}` |
|
|
588
|
+
| `hover` | User hovers over a point | `{type: 'hover', points: [...]}` |
|
|
589
|
+
| `relayout` | User zooms/pans the chart | `{type: 'relayout', relayout: {...}}` |
|
|
590
|
+
|
|
591
|
+
#### Point Data Structure
|
|
592
|
+
|
|
593
|
+
Each point in the `points` array contains:
|
|
594
|
+
|
|
595
|
+
```python
|
|
596
|
+
{
|
|
597
|
+
"curveNumber": 0, # Index of the trace
|
|
598
|
+
"pointNumber": 2, # Index of the point in the trace
|
|
599
|
+
"pointIndex": 2, # Same as pointNumber
|
|
600
|
+
"x": "Mar", # X value
|
|
601
|
+
"y": 120, # Y value
|
|
602
|
+
"customdata": None # Custom data if provided
|
|
603
|
+
}
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
---
|
|
607
|
+
|
|
608
|
+
### 10. Form Select
|
|
609
|
+
|
|
610
|
+
A styled dropdown select input.
|
|
611
|
+
|
|
612
|
+
```python
|
|
613
|
+
form_select(
|
|
614
|
+
label: str, # Label text
|
|
615
|
+
options: list, # Options list
|
|
616
|
+
value: str = "", # Selected value
|
|
617
|
+
groups: list = None, # Option groups (for optgroup)
|
|
618
|
+
style: dict = None,
|
|
619
|
+
class_name: str = "",
|
|
620
|
+
key: str = None
|
|
621
|
+
) -> str # Returns selected value
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
#### Simple Options
|
|
625
|
+
|
|
626
|
+
```python
|
|
627
|
+
options = ["Option A", "Option B", "Option C"]
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
#### Options with Labels
|
|
631
|
+
|
|
632
|
+
```python
|
|
633
|
+
options = [
|
|
634
|
+
{"value": "a", "label": "Option A"},
|
|
635
|
+
{"value": "b", "label": "Option B"}
|
|
636
|
+
]
|
|
637
|
+
```
|
|
638
|
+
|
|
639
|
+
#### Grouped Options
|
|
640
|
+
|
|
641
|
+
```python
|
|
642
|
+
groups = [
|
|
643
|
+
{"label": "Baselines", "options": ["Baseline v7", "Baseline v6"]},
|
|
644
|
+
{"label": "Scenarios", "options": ["Q2 Demand Surge", "OEE Initiative"]}
|
|
645
|
+
]
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
#### Example
|
|
649
|
+
|
|
650
|
+
```python
|
|
651
|
+
# Simple
|
|
652
|
+
site = form_select(
|
|
653
|
+
label="Site",
|
|
654
|
+
options=["AML_14", "ADL", "Devens"],
|
|
655
|
+
value="AML_14"
|
|
656
|
+
)
|
|
657
|
+
|
|
658
|
+
# With groups
|
|
659
|
+
scenario = form_select(
|
|
660
|
+
label="Base On",
|
|
661
|
+
groups=[
|
|
662
|
+
{"label": "Baselines", "options": ["Baseline v7 (Current)", "Baseline v6"]},
|
|
663
|
+
{"label": "Scenarios", "options": ["Q2 Demand Surge", "OEE Initiative"]}
|
|
664
|
+
],
|
|
665
|
+
class_name="max-w-xs"
|
|
666
|
+
)
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
---
|
|
670
|
+
|
|
671
|
+
### 11. Form Slider
|
|
672
|
+
|
|
673
|
+
A styled range slider input.
|
|
674
|
+
|
|
675
|
+
```python
|
|
676
|
+
form_slider(
|
|
677
|
+
label: str, # Label text
|
|
678
|
+
value: float, # Current value
|
|
679
|
+
min_val: float, # Minimum value
|
|
680
|
+
max_val: float, # Maximum value
|
|
681
|
+
step: float = 1, # Step increment
|
|
682
|
+
unit: str = "", # Unit suffix (e.g., "%", "hrs")
|
|
683
|
+
color: str = "blue", # Preset or hex color (e.g., "#94a3b8")
|
|
684
|
+
style: dict = None,
|
|
685
|
+
class_name: str = "",
|
|
686
|
+
key: str = None
|
|
687
|
+
) -> float # Returns current value
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
#### Example
|
|
691
|
+
|
|
692
|
+
```python
|
|
693
|
+
# Percentage slider with preset color
|
|
694
|
+
threshold = form_slider(
|
|
695
|
+
label="Upper Threshold",
|
|
696
|
+
value=90,
|
|
697
|
+
min_val=75,
|
|
698
|
+
max_val=100,
|
|
699
|
+
unit="%",
|
|
700
|
+
color="red"
|
|
701
|
+
)
|
|
702
|
+
|
|
703
|
+
# Time slider
|
|
704
|
+
hold_time = form_slider(
|
|
705
|
+
label="VPHP Hold Time",
|
|
706
|
+
value=5.0,
|
|
707
|
+
min_val=2.0,
|
|
708
|
+
max_val=8.0,
|
|
709
|
+
step=0.5,
|
|
710
|
+
unit=" hrs",
|
|
711
|
+
color="blue"
|
|
712
|
+
)
|
|
713
|
+
|
|
714
|
+
# Slider with hex color
|
|
715
|
+
custom_slider = form_slider(
|
|
716
|
+
label="Custom Color",
|
|
717
|
+
value=50,
|
|
718
|
+
min_val=0,
|
|
719
|
+
max_val=100,
|
|
720
|
+
color="#ff5733"
|
|
721
|
+
)
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
---
|
|
725
|
+
|
|
726
|
+
### 12. Checkbox Group
|
|
727
|
+
|
|
728
|
+
A group of checkboxes.
|
|
729
|
+
|
|
730
|
+
```python
|
|
731
|
+
checkbox_group(
|
|
732
|
+
items: list, # List of checkbox items
|
|
733
|
+
label: str = "", # Optional group label
|
|
734
|
+
style: dict = None,
|
|
735
|
+
class_name: str = "",
|
|
736
|
+
key: str = None
|
|
737
|
+
) -> list # Returns list of checked item IDs
|
|
738
|
+
```
|
|
739
|
+
|
|
740
|
+
#### Items Format
|
|
741
|
+
|
|
742
|
+
```python
|
|
743
|
+
items = [
|
|
744
|
+
{"id": "opt1", "label": "Option 1", "checked": True},
|
|
745
|
+
{"id": "opt2", "label": "Option 2", "checked": True},
|
|
746
|
+
{"id": "opt3", "label": "Option 3"} # checked defaults to False
|
|
747
|
+
]
|
|
748
|
+
```
|
|
749
|
+
|
|
750
|
+
#### Example
|
|
751
|
+
|
|
752
|
+
```python
|
|
753
|
+
selected = checkbox_group(
|
|
754
|
+
label="Parameters to Optimize",
|
|
755
|
+
items=[
|
|
756
|
+
{"id": "vphp", "label": "VPHP Hold Time", "checked": True},
|
|
757
|
+
{"id": "lot_co", "label": "Lot Changeover", "checked": True},
|
|
758
|
+
{"id": "campaign_co", "label": "Campaign Changeover"},
|
|
759
|
+
{"id": "batch", "label": "Batch Size"}
|
|
760
|
+
]
|
|
761
|
+
)
|
|
762
|
+
|
|
763
|
+
st.write(f"Selected parameters: {selected}")
|
|
764
|
+
# Output: ['vphp', 'lot_co']
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
---
|
|
768
|
+
|
|
769
|
+
## Complete Example App
|
|
770
|
+
|
|
771
|
+
```python
|
|
772
|
+
import streamlit as st
|
|
773
|
+
from streamlit_react_components import (
|
|
774
|
+
section_header, stat_card, data_table,
|
|
775
|
+
form_select, form_slider, checkbox_group
|
|
776
|
+
)
|
|
777
|
+
|
|
778
|
+
st.set_page_config(page_title="Dashboard", layout="wide")
|
|
779
|
+
|
|
780
|
+
# Header
|
|
781
|
+
action = section_header(
|
|
782
|
+
title="Production Dashboard",
|
|
783
|
+
icon="🏭",
|
|
784
|
+
actions=[{"id": "refresh", "label": "Refresh", "color": "blue"}]
|
|
785
|
+
)
|
|
786
|
+
|
|
787
|
+
# Stats row
|
|
788
|
+
col1, col2, col3 = st.columns(3)
|
|
789
|
+
with col1:
|
|
790
|
+
stat_card(label="Lines Active", value="12", color="green")
|
|
791
|
+
with col2:
|
|
792
|
+
stat_card(label="At Risk", value="3", color="red")
|
|
793
|
+
with col3:
|
|
794
|
+
stat_card(label="Avg Utilization", value="82%", color="blue")
|
|
795
|
+
|
|
796
|
+
# Filters
|
|
797
|
+
st.markdown("### Filters")
|
|
798
|
+
col1, col2 = st.columns(2)
|
|
799
|
+
with col1:
|
|
800
|
+
site = form_select(label="Site", options=["All", "AML", "ADL", "Devens"])
|
|
801
|
+
with col2:
|
|
802
|
+
threshold = form_slider(label="Risk Threshold", value=90, min_val=80, max_val=100, unit="%")
|
|
803
|
+
|
|
804
|
+
# Data table
|
|
805
|
+
st.markdown("### Lines Overview")
|
|
806
|
+
clicked = data_table(
|
|
807
|
+
columns=[
|
|
808
|
+
{"key": "line", "label": "Line"},
|
|
809
|
+
{"key": "util", "label": "Utilization", "format": "percent", "align": "right"},
|
|
810
|
+
{"key": "status", "label": "Status", "colorByValue": True}
|
|
811
|
+
],
|
|
812
|
+
rows=[
|
|
813
|
+
{"line": "L1", "util": 94, "status": "above"},
|
|
814
|
+
{"line": "L2", "util": 82, "status": "within"},
|
|
815
|
+
{"line": "L3", "util": 65, "status": "below"}
|
|
816
|
+
]
|
|
817
|
+
)
|
|
818
|
+
|
|
819
|
+
if clicked:
|
|
820
|
+
st.info(f"Selected: {clicked['rowData']['line']}")
|
|
821
|
+
```
|
|
822
|
+
|
|
823
|
+
---
|
|
824
|
+
|
|
825
|
+
## Tailwind CSS Classes Reference
|
|
826
|
+
|
|
827
|
+
Since components use Tailwind CSS, here are commonly used classes:
|
|
828
|
+
|
|
829
|
+
### Spacing
|
|
830
|
+
- `p-1` to `p-8`: Padding
|
|
831
|
+
- `m-1` to `m-8`: Margin
|
|
832
|
+
- `mt-4`, `mb-4`, `ml-4`, `mr-4`: Directional margin
|
|
833
|
+
|
|
834
|
+
### Layout
|
|
835
|
+
- `w-full`: Full width
|
|
836
|
+
- `max-w-xs`, `max-w-sm`, `max-w-md`: Max width
|
|
837
|
+
- `flex`, `grid`: Display types
|
|
838
|
+
- `gap-2`, `gap-4`: Gap between items
|
|
839
|
+
|
|
840
|
+
### Colors (Dark Theme)
|
|
841
|
+
- `bg-slate-900`, `bg-slate-800`: Backgrounds
|
|
842
|
+
- `text-white`, `text-slate-400`: Text colors
|
|
843
|
+
- `border-slate-700`: Border colors
|
|
844
|
+
|
|
845
|
+
### Effects
|
|
846
|
+
- `rounded`, `rounded-lg`: Border radius
|
|
847
|
+
- `shadow`, `shadow-lg`: Box shadows
|
|
848
|
+
- `opacity-50`: Transparency
|
|
849
|
+
|
|
850
|
+
---
|
|
851
|
+
|
|
852
|
+
## License
|
|
853
|
+
|
|
854
|
+
MIT
|