streamlit-react-components 1.0.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.
- streamlit_react_components/__init__.py +42 -0
- streamlit_react_components/_frontend/index.css +1 -0
- streamlit_react_components/_frontend/index.html +13 -0
- streamlit_react_components/_frontend/index.js +3920 -0
- streamlit_react_components/common/__init__.py +23 -0
- streamlit_react_components/common/button_group.py +69 -0
- streamlit_react_components/common/chart_legend.py +49 -0
- streamlit_react_components/common/data_table.py +65 -0
- streamlit_react_components/common/metric_row.py +47 -0
- streamlit_react_components/common/panel.py +43 -0
- streamlit_react_components/common/plotly_chart.py +216 -0
- streamlit_react_components/common/section_header.py +89 -0
- streamlit_react_components/common/stat_card.py +63 -0
- streamlit_react_components/common/step_indicator.py +51 -0
- streamlit_react_components/form/__init__.py +11 -0
- streamlit_react_components/form/checkbox_group.py +61 -0
- streamlit_react_components/form/form_select.py +69 -0
- streamlit_react_components/form/form_slider.py +80 -0
- streamlit_react_components-1.0.0.dist-info/METADATA +854 -0
- streamlit_react_components-1.0.0.dist-info/RECORD +22 -0
- streamlit_react_components-1.0.0.dist-info/WHEEL +5 -0
- streamlit_react_components-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Common display components."""
|
|
2
|
+
|
|
3
|
+
from .panel import panel
|
|
4
|
+
from .section_header import section_header
|
|
5
|
+
from .stat_card import stat_card
|
|
6
|
+
from .metric_row import metric_row
|
|
7
|
+
from .data_table import data_table
|
|
8
|
+
from .step_indicator import step_indicator
|
|
9
|
+
from .button_group import button_group
|
|
10
|
+
from .chart_legend import chart_legend
|
|
11
|
+
from .plotly_chart import plotly_chart
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"panel",
|
|
15
|
+
"section_header",
|
|
16
|
+
"stat_card",
|
|
17
|
+
"metric_row",
|
|
18
|
+
"data_table",
|
|
19
|
+
"step_indicator",
|
|
20
|
+
"button_group",
|
|
21
|
+
"chart_legend",
|
|
22
|
+
"plotly_chart",
|
|
23
|
+
]
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""ButtonGroup component - A group of action buttons."""
|
|
2
|
+
|
|
3
|
+
import streamlit.components.v1 as components
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Dict, Any, List, Optional
|
|
6
|
+
|
|
7
|
+
_FRONTEND_DIR = Path(__file__).parent.parent / "_frontend"
|
|
8
|
+
|
|
9
|
+
_component = components.declare_component(
|
|
10
|
+
"streamlit_react_components",
|
|
11
|
+
path=str(_FRONTEND_DIR),
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def button_group(
|
|
16
|
+
buttons: List[Dict[str, Any]],
|
|
17
|
+
style: Optional[Dict[str, Any]] = None,
|
|
18
|
+
class_name: str = "",
|
|
19
|
+
key: Optional[str] = None,
|
|
20
|
+
) -> Optional[str]:
|
|
21
|
+
"""
|
|
22
|
+
Display a group of action buttons.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
buttons: List of button configs, each with:
|
|
26
|
+
- id: Unique identifier
|
|
27
|
+
- label: Button text (optional)
|
|
28
|
+
- icon: Button icon/emoji (optional)
|
|
29
|
+
- color: Preset name ("blue", "green", "red", "yellow", "purple",
|
|
30
|
+
"slate") or hex value like "#94a3b8" (optional)
|
|
31
|
+
- disabled: Whether button is disabled (optional)
|
|
32
|
+
- style: Inline CSS styles dict for this button (optional)
|
|
33
|
+
- className: Tailwind CSS classes for this button (optional)
|
|
34
|
+
style: Inline CSS styles as a dictionary
|
|
35
|
+
class_name: Tailwind CSS classes
|
|
36
|
+
key: Unique key for the component
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
The ID of the clicked button, or None if no click
|
|
40
|
+
|
|
41
|
+
Example:
|
|
42
|
+
# Using preset colors
|
|
43
|
+
clicked = button_group(
|
|
44
|
+
buttons=[
|
|
45
|
+
{"id": "view", "icon": "👁️"},
|
|
46
|
+
{"id": "edit", "icon": "✏️"},
|
|
47
|
+
{"id": "approve", "icon": "✓", "color": "green"},
|
|
48
|
+
{"id": "reject", "icon": "✕", "color": "red"}
|
|
49
|
+
]
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# Using hex colors and custom styling
|
|
53
|
+
clicked = button_group(
|
|
54
|
+
buttons=[
|
|
55
|
+
{"id": "custom", "icon": "🎨", "color": "#ff5733"},
|
|
56
|
+
{"id": "styled", "label": "Styled", "style": {"padding": "12px"}}
|
|
57
|
+
]
|
|
58
|
+
)
|
|
59
|
+
if clicked == "approve":
|
|
60
|
+
approve_item()
|
|
61
|
+
"""
|
|
62
|
+
return _component(
|
|
63
|
+
component="button_group",
|
|
64
|
+
buttons=buttons,
|
|
65
|
+
style=style,
|
|
66
|
+
className=class_name,
|
|
67
|
+
key=key,
|
|
68
|
+
default=None,
|
|
69
|
+
)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""ChartLegend component - A chart legend with colored indicators."""
|
|
2
|
+
|
|
3
|
+
import streamlit.components.v1 as components
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Dict, Any, List, Optional
|
|
6
|
+
|
|
7
|
+
_FRONTEND_DIR = Path(__file__).parent.parent / "_frontend"
|
|
8
|
+
|
|
9
|
+
_component = components.declare_component(
|
|
10
|
+
"streamlit_react_components",
|
|
11
|
+
path=str(_FRONTEND_DIR),
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def chart_legend(
|
|
16
|
+
items: List[Dict[str, str]],
|
|
17
|
+
style: Optional[Dict[str, Any]] = None,
|
|
18
|
+
class_name: str = "",
|
|
19
|
+
key: Optional[str] = None,
|
|
20
|
+
) -> None:
|
|
21
|
+
"""
|
|
22
|
+
Display a chart legend with colored indicators.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
items: List of legend items, each with:
|
|
26
|
+
- color: CSS color value (e.g., "#3b82f6", "rgb(59,130,246)")
|
|
27
|
+
- label: Legend label text
|
|
28
|
+
style: Inline CSS styles as a dictionary
|
|
29
|
+
class_name: Tailwind CSS classes
|
|
30
|
+
key: Unique key for the component
|
|
31
|
+
|
|
32
|
+
Example:
|
|
33
|
+
chart_legend(
|
|
34
|
+
items=[
|
|
35
|
+
{"color": "#94a3b8", "label": "Historical"},
|
|
36
|
+
{"color": "#ef4444", "label": "Outlier"},
|
|
37
|
+
{"color": "#8b5cf6", "label": "Prophet"},
|
|
38
|
+
{"color": "#10b981", "label": "ARIMA"}
|
|
39
|
+
]
|
|
40
|
+
)
|
|
41
|
+
"""
|
|
42
|
+
_component(
|
|
43
|
+
component="chart_legend",
|
|
44
|
+
items=items,
|
|
45
|
+
style=style,
|
|
46
|
+
className=class_name,
|
|
47
|
+
key=key,
|
|
48
|
+
default=None,
|
|
49
|
+
)
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""DataTable component - A styled data table with click support."""
|
|
2
|
+
|
|
3
|
+
import streamlit.components.v1 as components
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Dict, Any, List, Optional
|
|
6
|
+
|
|
7
|
+
_FRONTEND_DIR = Path(__file__).parent.parent / "_frontend"
|
|
8
|
+
|
|
9
|
+
_component = components.declare_component(
|
|
10
|
+
"streamlit_react_components",
|
|
11
|
+
path=str(_FRONTEND_DIR),
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def data_table(
|
|
16
|
+
columns: List[Dict[str, Any]],
|
|
17
|
+
rows: List[Dict[str, Any]],
|
|
18
|
+
show_header: bool = True,
|
|
19
|
+
style: Optional[Dict[str, Any]] = None,
|
|
20
|
+
class_name: str = "",
|
|
21
|
+
key: Optional[str] = None,
|
|
22
|
+
) -> Optional[Dict[str, Any]]:
|
|
23
|
+
"""
|
|
24
|
+
Display a styled data table with row click support.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
columns: List of column definitions, each with:
|
|
28
|
+
- key: Data key in each row
|
|
29
|
+
- label: Column header text
|
|
30
|
+
- align: "left", "center", or "right" (optional)
|
|
31
|
+
- format: "number" or "percent" (optional)
|
|
32
|
+
- colorByValue: True to color based on status values (optional)
|
|
33
|
+
rows: List of row data dictionaries
|
|
34
|
+
show_header: Whether to show the header row (default True)
|
|
35
|
+
style: Inline CSS styles as a dictionary
|
|
36
|
+
class_name: Tailwind CSS classes
|
|
37
|
+
key: Unique key for the component
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
Dictionary with rowIndex and rowData when a row is clicked, None otherwise
|
|
41
|
+
|
|
42
|
+
Example:
|
|
43
|
+
columns = [
|
|
44
|
+
{"key": "site", "label": "Site"},
|
|
45
|
+
{"key": "util", "label": "Utilization", "align": "right", "format": "percent"},
|
|
46
|
+
{"key": "status", "label": "Status", "colorByValue": True}
|
|
47
|
+
]
|
|
48
|
+
rows = [
|
|
49
|
+
{"site": "AML_14", "util": 94, "status": "above"},
|
|
50
|
+
{"site": "ADL", "util": 72, "status": "within"}
|
|
51
|
+
]
|
|
52
|
+
clicked = data_table(columns=columns, rows=rows)
|
|
53
|
+
if clicked:
|
|
54
|
+
st.write(f"Clicked row: {clicked['rowData']}")
|
|
55
|
+
"""
|
|
56
|
+
return _component(
|
|
57
|
+
component="data_table",
|
|
58
|
+
columns=columns,
|
|
59
|
+
rows=rows,
|
|
60
|
+
showHeader=show_header,
|
|
61
|
+
style=style,
|
|
62
|
+
className=class_name,
|
|
63
|
+
key=key,
|
|
64
|
+
default=None,
|
|
65
|
+
)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""MetricRow component - A key-value display row."""
|
|
2
|
+
|
|
3
|
+
import streamlit.components.v1 as components
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Dict, Any, Optional
|
|
6
|
+
|
|
7
|
+
_FRONTEND_DIR = Path(__file__).parent.parent / "_frontend"
|
|
8
|
+
|
|
9
|
+
_component = components.declare_component(
|
|
10
|
+
"streamlit_react_components",
|
|
11
|
+
path=str(_FRONTEND_DIR),
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def metric_row(
|
|
16
|
+
label: str,
|
|
17
|
+
value: str,
|
|
18
|
+
value_color: str = "",
|
|
19
|
+
style: Optional[Dict[str, Any]] = None,
|
|
20
|
+
class_name: str = "",
|
|
21
|
+
key: Optional[str] = None,
|
|
22
|
+
) -> None:
|
|
23
|
+
"""
|
|
24
|
+
Display a key-value metric row.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
label: The metric label (left side)
|
|
28
|
+
value: The metric value (right side)
|
|
29
|
+
value_color: Tailwind text color class for the value (e.g., "text-green-400")
|
|
30
|
+
style: Inline CSS styles as a dictionary
|
|
31
|
+
class_name: Tailwind CSS classes
|
|
32
|
+
key: Unique key for the component
|
|
33
|
+
|
|
34
|
+
Example:
|
|
35
|
+
metric_row(label="Mean", value="78.4%")
|
|
36
|
+
metric_row(label="Trend", value="↑ +0.4%/mo", value_color="text-green-400")
|
|
37
|
+
"""
|
|
38
|
+
_component(
|
|
39
|
+
component="metric_row",
|
|
40
|
+
label=label,
|
|
41
|
+
value=value,
|
|
42
|
+
valueColor=value_color,
|
|
43
|
+
style=style,
|
|
44
|
+
className=class_name,
|
|
45
|
+
key=key,
|
|
46
|
+
default=None,
|
|
47
|
+
)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""Panel component - A styled container wrapper."""
|
|
2
|
+
|
|
3
|
+
import streamlit.components.v1 as components
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Dict, Any, Optional
|
|
6
|
+
|
|
7
|
+
_FRONTEND_DIR = Path(__file__).parent.parent / "_frontend"
|
|
8
|
+
|
|
9
|
+
_component = components.declare_component(
|
|
10
|
+
"streamlit_react_components",
|
|
11
|
+
path=str(_FRONTEND_DIR),
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def panel(
|
|
16
|
+
children: str = "",
|
|
17
|
+
style: Optional[Dict[str, Any]] = None,
|
|
18
|
+
class_name: str = "",
|
|
19
|
+
key: Optional[str] = None,
|
|
20
|
+
) -> None:
|
|
21
|
+
"""
|
|
22
|
+
Display a styled panel/card container.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
children: HTML content to render inside the panel
|
|
26
|
+
style: Inline CSS styles as a dictionary (e.g., {"background": "#1e293b"})
|
|
27
|
+
class_name: Tailwind CSS classes (e.g., "bg-slate-900 p-4")
|
|
28
|
+
key: Unique key for the component
|
|
29
|
+
|
|
30
|
+
Example:
|
|
31
|
+
panel(
|
|
32
|
+
children="<h3>Title</h3><p>Content here</p>",
|
|
33
|
+
class_name="mt-4"
|
|
34
|
+
)
|
|
35
|
+
"""
|
|
36
|
+
_component(
|
|
37
|
+
component="panel",
|
|
38
|
+
children=children,
|
|
39
|
+
style=style,
|
|
40
|
+
className=class_name,
|
|
41
|
+
key=key,
|
|
42
|
+
default=None,
|
|
43
|
+
)
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"""PlotlyChart component - Render Plotly charts with full interactivity."""
|
|
2
|
+
|
|
3
|
+
import streamlit.components.v1 as components
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Dict, Any, Optional, List, Union
|
|
6
|
+
|
|
7
|
+
_FRONTEND_DIR = Path(__file__).parent.parent / "_frontend"
|
|
8
|
+
|
|
9
|
+
_component = components.declare_component(
|
|
10
|
+
"streamlit_react_components",
|
|
11
|
+
path=str(_FRONTEND_DIR),
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _dataframe_to_figure(
|
|
16
|
+
data: Any,
|
|
17
|
+
x: Optional[str],
|
|
18
|
+
y: Optional[Union[str, List[str]]],
|
|
19
|
+
color: Optional[str],
|
|
20
|
+
chart_type: str,
|
|
21
|
+
title: Optional[str],
|
|
22
|
+
) -> Dict[str, Any]:
|
|
23
|
+
"""Convert a DataFrame to a Plotly figure dict."""
|
|
24
|
+
traces = []
|
|
25
|
+
layout: Dict[str, Any] = {}
|
|
26
|
+
|
|
27
|
+
if title:
|
|
28
|
+
layout["title"] = title
|
|
29
|
+
|
|
30
|
+
# Determine y columns
|
|
31
|
+
y_cols = [y] if isinstance(y, str) else (y or [])
|
|
32
|
+
|
|
33
|
+
# Color grouping
|
|
34
|
+
if color and color in data.columns:
|
|
35
|
+
groups = data[color].unique()
|
|
36
|
+
for group in groups:
|
|
37
|
+
group_data = data[data[color] == group]
|
|
38
|
+
for y_col in y_cols:
|
|
39
|
+
trace = _create_trace(
|
|
40
|
+
chart_type,
|
|
41
|
+
group_data[x].tolist() if x else list(range(len(group_data))),
|
|
42
|
+
group_data[y_col].tolist(),
|
|
43
|
+
f"{group}" if len(y_cols) == 1 else f"{group} - {y_col}",
|
|
44
|
+
)
|
|
45
|
+
traces.append(trace)
|
|
46
|
+
else:
|
|
47
|
+
# No color grouping
|
|
48
|
+
x_data = data[x].tolist() if x else list(range(len(data)))
|
|
49
|
+
for y_col in y_cols:
|
|
50
|
+
trace = _create_trace(
|
|
51
|
+
chart_type,
|
|
52
|
+
x_data,
|
|
53
|
+
data[y_col].tolist(),
|
|
54
|
+
y_col if len(y_cols) > 1 else None,
|
|
55
|
+
)
|
|
56
|
+
traces.append(trace)
|
|
57
|
+
|
|
58
|
+
return {"data": traces, "layout": layout}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _create_trace(
|
|
62
|
+
chart_type: str,
|
|
63
|
+
x_data: List[Any],
|
|
64
|
+
y_data: List[Any],
|
|
65
|
+
name: Optional[str],
|
|
66
|
+
) -> Dict[str, Any]:
|
|
67
|
+
"""Create a single Plotly trace based on chart type."""
|
|
68
|
+
base: Dict[str, Any] = {"x": x_data, "y": y_data}
|
|
69
|
+
if name:
|
|
70
|
+
base["name"] = name
|
|
71
|
+
|
|
72
|
+
if chart_type == "line":
|
|
73
|
+
return {"type": "scatter", "mode": "lines", **base}
|
|
74
|
+
elif chart_type == "scatter":
|
|
75
|
+
return {"type": "scatter", "mode": "markers", **base}
|
|
76
|
+
elif chart_type == "bar":
|
|
77
|
+
return {"type": "bar", **base}
|
|
78
|
+
elif chart_type == "area":
|
|
79
|
+
return {"type": "scatter", "mode": "lines", "fill": "tozeroy", **base}
|
|
80
|
+
elif chart_type == "histogram":
|
|
81
|
+
return {"type": "histogram", "x": x_data}
|
|
82
|
+
elif chart_type == "pie":
|
|
83
|
+
return {"type": "pie", "labels": x_data, "values": y_data}
|
|
84
|
+
else:
|
|
85
|
+
# Default to scatter with lines
|
|
86
|
+
return {"type": "scatter", "mode": "lines", **base}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def plotly_chart(
|
|
90
|
+
figure: Optional[Any] = None,
|
|
91
|
+
data: Optional[Any] = None,
|
|
92
|
+
x: Optional[str] = None,
|
|
93
|
+
y: Optional[Union[str, List[str]]] = None,
|
|
94
|
+
color: Optional[str] = None,
|
|
95
|
+
chart_type: str = "line",
|
|
96
|
+
title: Optional[str] = None,
|
|
97
|
+
config: Optional[Dict[str, Any]] = None,
|
|
98
|
+
on_click: bool = False,
|
|
99
|
+
on_select: bool = False,
|
|
100
|
+
on_hover: bool = False,
|
|
101
|
+
on_relayout: bool = False,
|
|
102
|
+
style: Optional[Dict[str, Any]] = None,
|
|
103
|
+
class_name: str = "",
|
|
104
|
+
key: Optional[str] = None,
|
|
105
|
+
) -> Optional[Dict[str, Any]]:
|
|
106
|
+
"""
|
|
107
|
+
Render a Plotly chart with full interactivity and custom styling.
|
|
108
|
+
|
|
109
|
+
Supports two modes:
|
|
110
|
+
1. Pass a Plotly figure object directly
|
|
111
|
+
2. Pass a pandas DataFrame with chart configuration
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
figure: Plotly figure object (go.Figure) or dict with 'data' and 'layout'.
|
|
115
|
+
Takes precedence over `data` parameter.
|
|
116
|
+
data: pandas DataFrame for quick chart creation
|
|
117
|
+
x: Column name for x-axis (when using DataFrame)
|
|
118
|
+
y: Column name(s) for y-axis - string or list of strings (when using DataFrame)
|
|
119
|
+
color: Column name for color grouping (when using DataFrame)
|
|
120
|
+
chart_type: Chart type when using DataFrame - "line", "bar", "scatter",
|
|
121
|
+
"area", "pie", or "histogram" (default "line")
|
|
122
|
+
title: Chart title (when using DataFrame)
|
|
123
|
+
config: Plotly config options (displayModeBar, scrollZoom, etc.)
|
|
124
|
+
on_click: Enable click events (returns clicked points)
|
|
125
|
+
on_select: Enable selection events (box/lasso selection)
|
|
126
|
+
on_hover: Enable hover events (returns hovered points)
|
|
127
|
+
on_relayout: Enable relayout events (zoom/pan state)
|
|
128
|
+
style: Inline CSS styles as a dictionary
|
|
129
|
+
class_name: Tailwind CSS classes
|
|
130
|
+
key: Unique key for the component
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
Event dict with 'type' and event data, or None if no event.
|
|
134
|
+
Event types: 'click', 'select', 'hover', 'relayout'
|
|
135
|
+
|
|
136
|
+
Example using Plotly figure:
|
|
137
|
+
import plotly.graph_objects as go
|
|
138
|
+
|
|
139
|
+
fig = go.Figure(
|
|
140
|
+
data=[go.Scatter(x=[1,2,3], y=[4,5,6], mode='lines+markers')],
|
|
141
|
+
layout=go.Layout(title='My Chart')
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
event = plotly_chart(
|
|
145
|
+
figure=fig,
|
|
146
|
+
on_click=True,
|
|
147
|
+
on_select=True,
|
|
148
|
+
style={"height": "400px"}
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
if event and event['type'] == 'click':
|
|
152
|
+
st.write(f"Clicked: {event['points']}")
|
|
153
|
+
|
|
154
|
+
Example using DataFrame:
|
|
155
|
+
import pandas as pd
|
|
156
|
+
|
|
157
|
+
df = pd.DataFrame({
|
|
158
|
+
'month': ['Jan', 'Feb', 'Mar', 'Apr'],
|
|
159
|
+
'sales': [100, 150, 120, 180],
|
|
160
|
+
'orders': [50, 75, 60, 90]
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
# Simple line chart
|
|
164
|
+
event = plotly_chart(
|
|
165
|
+
data=df,
|
|
166
|
+
x='month',
|
|
167
|
+
y='sales',
|
|
168
|
+
chart_type='line',
|
|
169
|
+
title='Monthly Sales',
|
|
170
|
+
on_click=True
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
# Multiple y columns as bar chart
|
|
174
|
+
event = plotly_chart(
|
|
175
|
+
data=df,
|
|
176
|
+
x='month',
|
|
177
|
+
y=['sales', 'orders'],
|
|
178
|
+
chart_type='bar',
|
|
179
|
+
title='Sales vs Orders'
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
# Scatter with color grouping
|
|
183
|
+
event = plotly_chart(
|
|
184
|
+
data=df,
|
|
185
|
+
x='sales',
|
|
186
|
+
y='orders',
|
|
187
|
+
color='month',
|
|
188
|
+
chart_type='scatter'
|
|
189
|
+
)
|
|
190
|
+
"""
|
|
191
|
+
# Determine figure dict
|
|
192
|
+
if figure is not None:
|
|
193
|
+
# Convert Plotly figure to dict if needed
|
|
194
|
+
if hasattr(figure, "to_dict"):
|
|
195
|
+
figure_dict = figure.to_dict()
|
|
196
|
+
else:
|
|
197
|
+
figure_dict = figure
|
|
198
|
+
elif data is not None:
|
|
199
|
+
# Create figure from DataFrame
|
|
200
|
+
figure_dict = _dataframe_to_figure(data, x, y, color, chart_type, title)
|
|
201
|
+
else:
|
|
202
|
+
raise ValueError("Either 'figure' or 'data' parameter is required")
|
|
203
|
+
|
|
204
|
+
return _component(
|
|
205
|
+
component="plotly_chart",
|
|
206
|
+
figure=figure_dict,
|
|
207
|
+
config=config,
|
|
208
|
+
onClickEnabled=on_click,
|
|
209
|
+
onSelectEnabled=on_select,
|
|
210
|
+
onHoverEnabled=on_hover,
|
|
211
|
+
onRelayoutEnabled=on_relayout,
|
|
212
|
+
style=style,
|
|
213
|
+
className=class_name,
|
|
214
|
+
key=key,
|
|
215
|
+
default=None,
|
|
216
|
+
)
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""SectionHeader component - A styled section title with optional actions."""
|
|
2
|
+
|
|
3
|
+
import streamlit.components.v1 as components
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Dict, Any, List, Optional
|
|
6
|
+
|
|
7
|
+
_FRONTEND_DIR = Path(__file__).parent.parent / "_frontend"
|
|
8
|
+
|
|
9
|
+
_component = components.declare_component(
|
|
10
|
+
"streamlit_react_components",
|
|
11
|
+
path=str(_FRONTEND_DIR),
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def section_header(
|
|
16
|
+
title: str,
|
|
17
|
+
icon: str = "",
|
|
18
|
+
actions: Optional[List[Dict[str, Any]]] = None,
|
|
19
|
+
style: Optional[Dict[str, Any]] = None,
|
|
20
|
+
class_name: str = "",
|
|
21
|
+
key: Optional[str] = None,
|
|
22
|
+
) -> Optional[str]:
|
|
23
|
+
"""
|
|
24
|
+
Display a section header with optional action buttons.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
title: The header title text
|
|
28
|
+
icon: Optional emoji or icon to display before the title
|
|
29
|
+
actions: List of action button configs, each with:
|
|
30
|
+
- id: Unique identifier for the action
|
|
31
|
+
- label: Button text (optional)
|
|
32
|
+
- icon: Button icon (optional)
|
|
33
|
+
- color: Preset name ("blue", "green", "red", "yellow", "purple",
|
|
34
|
+
"slate") or hex value like "#94a3b8" (optional)
|
|
35
|
+
- style: Inline CSS styles dict for this button (optional)
|
|
36
|
+
- className: Tailwind CSS classes for this button (optional)
|
|
37
|
+
- href: URL for link actions. External URLs (http/https) open
|
|
38
|
+
in a new tab. Internal paths return the ID for use with
|
|
39
|
+
st.switch_page() (optional)
|
|
40
|
+
style: Inline CSS styles as a dictionary
|
|
41
|
+
class_name: Tailwind CSS classes
|
|
42
|
+
key: Unique key for the component
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
The ID of the clicked action button, or None if no click
|
|
46
|
+
|
|
47
|
+
Example:
|
|
48
|
+
# Using preset colors
|
|
49
|
+
clicked = section_header(
|
|
50
|
+
title="Dashboard",
|
|
51
|
+
icon="📊",
|
|
52
|
+
actions=[{"id": "refresh", "label": "Refresh", "color": "blue"}]
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
# Using hex colors and custom styling
|
|
56
|
+
clicked = section_header(
|
|
57
|
+
title="Dashboard",
|
|
58
|
+
actions=[
|
|
59
|
+
{"id": "custom", "label": "Custom", "color": "#94a3b8"},
|
|
60
|
+
{"id": "styled", "label": "Styled", "style": {"padding": "12px"}}
|
|
61
|
+
]
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
# External link (opens in new tab)
|
|
65
|
+
clicked = section_header(
|
|
66
|
+
title="Resources",
|
|
67
|
+
actions=[
|
|
68
|
+
{"id": "docs", "label": "Documentation", "href": "https://docs.example.com", "icon": "📚"}
|
|
69
|
+
]
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# Internal navigation
|
|
73
|
+
clicked = section_header(
|
|
74
|
+
title="Settings",
|
|
75
|
+
actions=[{"id": "home", "label": "Home", "icon": "🏠"}]
|
|
76
|
+
)
|
|
77
|
+
if clicked == "home":
|
|
78
|
+
st.switch_page("pages/home.py")
|
|
79
|
+
"""
|
|
80
|
+
return _component(
|
|
81
|
+
component="section_header",
|
|
82
|
+
title=title,
|
|
83
|
+
icon=icon,
|
|
84
|
+
actions=actions or [],
|
|
85
|
+
style=style,
|
|
86
|
+
className=class_name,
|
|
87
|
+
key=key,
|
|
88
|
+
default=None,
|
|
89
|
+
)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""StatCard component - A styled statistics display card."""
|
|
2
|
+
|
|
3
|
+
import streamlit.components.v1 as components
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Dict, Any, Optional, Union
|
|
6
|
+
|
|
7
|
+
_FRONTEND_DIR = Path(__file__).parent.parent / "_frontend"
|
|
8
|
+
|
|
9
|
+
_component = components.declare_component(
|
|
10
|
+
"streamlit_react_components",
|
|
11
|
+
path=str(_FRONTEND_DIR),
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def stat_card(
|
|
16
|
+
label: str,
|
|
17
|
+
value: Union[str, int, float],
|
|
18
|
+
color: str = "blue",
|
|
19
|
+
icon: str = "",
|
|
20
|
+
style: Optional[Dict[str, Any]] = None,
|
|
21
|
+
class_name: str = "",
|
|
22
|
+
key: Optional[str] = None,
|
|
23
|
+
) -> None:
|
|
24
|
+
"""
|
|
25
|
+
Display a styled statistics card with a label and value.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
label: The description label (e.g., "Total Users")
|
|
29
|
+
value: The statistic value to display
|
|
30
|
+
color: Accent color - preset name ("blue", "green", "red", "yellow",
|
|
31
|
+
"purple", "slate") or hex value (e.g., "#94a3b8")
|
|
32
|
+
icon: Optional emoji or icon to display with the label
|
|
33
|
+
style: Inline CSS styles as a dictionary
|
|
34
|
+
class_name: Tailwind CSS classes
|
|
35
|
+
key: Unique key for the component
|
|
36
|
+
|
|
37
|
+
Example:
|
|
38
|
+
# Using preset color
|
|
39
|
+
stat_card(
|
|
40
|
+
label="Within Threshold",
|
|
41
|
+
value="4",
|
|
42
|
+
color="green",
|
|
43
|
+
style={"minWidth": "150px"}
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
# Using hex color
|
|
47
|
+
stat_card(
|
|
48
|
+
label="Custom Color",
|
|
49
|
+
value="42",
|
|
50
|
+
color="#ff5733"
|
|
51
|
+
)
|
|
52
|
+
"""
|
|
53
|
+
_component(
|
|
54
|
+
component="stat_card",
|
|
55
|
+
label=label,
|
|
56
|
+
value=str(value),
|
|
57
|
+
color=color,
|
|
58
|
+
icon=icon,
|
|
59
|
+
style=style,
|
|
60
|
+
className=class_name,
|
|
61
|
+
key=key,
|
|
62
|
+
default=None,
|
|
63
|
+
)
|