streamlit-react-components 1.7.3__py3-none-any.whl → 1.7.4__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 +21 -1
- streamlit_react_components/_frontend/index.js +71 -71
- streamlit_react_components/form/checkbox_group.py +17 -1
- streamlit_react_components/form/form_select.py +17 -1
- streamlit_react_components/form/form_slider.py +19 -1
- streamlit_react_components/form/radio_group.py +17 -1
- streamlit_react_components/styled_container.py +193 -0
- streamlit_react_components/tailwind.py +1536 -0
- {streamlit_react_components-1.7.3.dist-info → streamlit_react_components-1.7.4.dist-info}/METADATA +1 -1
- {streamlit_react_components-1.7.3.dist-info → streamlit_react_components-1.7.4.dist-info}/RECORD +12 -10
- {streamlit_react_components-1.7.3.dist-info → streamlit_react_components-1.7.4.dist-info}/WHEEL +0 -0
- {streamlit_react_components-1.7.3.dist-info → streamlit_react_components-1.7.4.dist-info}/top_level.txt +0 -0
|
@@ -19,6 +19,7 @@ def checkbox_group(
|
|
|
19
19
|
style: Optional[Dict[str, Any]] = None,
|
|
20
20
|
class_name: str = "",
|
|
21
21
|
theme: Optional[Dict[str, Any]] = None,
|
|
22
|
+
defer_update: bool = False,
|
|
22
23
|
key: Optional[str] = None,
|
|
23
24
|
) -> List[str]:
|
|
24
25
|
"""
|
|
@@ -36,7 +37,10 @@ def checkbox_group(
|
|
|
36
37
|
class_name: Tailwind CSS classes
|
|
37
38
|
theme: Optional theme dictionary. If None, uses active global theme.
|
|
38
39
|
Set to False to disable theming for this component.
|
|
39
|
-
|
|
40
|
+
defer_update: If True, don't trigger Streamlit rerun on change.
|
|
41
|
+
Value is stored locally and sent on next rerun (e.g., Apply button).
|
|
42
|
+
Requires 'key' to be set.
|
|
43
|
+
key: Unique key for the component (required if defer_update=True)
|
|
40
44
|
|
|
41
45
|
Returns:
|
|
42
46
|
List of checked item IDs
|
|
@@ -60,6 +64,16 @@ def checkbox_group(
|
|
|
60
64
|
items=[...],
|
|
61
65
|
layout="horizontal"
|
|
62
66
|
)
|
|
67
|
+
|
|
68
|
+
# Deferred update (no rerun until Apply button clicked)
|
|
69
|
+
selected = checkbox_group(
|
|
70
|
+
label="Parameters",
|
|
71
|
+
items=[...],
|
|
72
|
+
defer_update=True,
|
|
73
|
+
key="params_checkbox"
|
|
74
|
+
)
|
|
75
|
+
if st.button("Apply"):
|
|
76
|
+
st.rerun()
|
|
63
77
|
"""
|
|
64
78
|
# Get default checked items
|
|
65
79
|
default_checked = [item["id"] for item in items if item.get("checked", False)]
|
|
@@ -78,6 +92,8 @@ def checkbox_group(
|
|
|
78
92
|
style=style,
|
|
79
93
|
className=class_name,
|
|
80
94
|
theme=resolved_theme,
|
|
95
|
+
deferUpdate=defer_update,
|
|
96
|
+
componentKey=key,
|
|
81
97
|
key=key,
|
|
82
98
|
default=default_checked,
|
|
83
99
|
)
|
|
@@ -20,6 +20,7 @@ def form_select(
|
|
|
20
20
|
style: Optional[Dict[str, Any]] = None,
|
|
21
21
|
class_name: str = "",
|
|
22
22
|
theme: Optional[Dict[str, Any]] = None,
|
|
23
|
+
defer_update: bool = False,
|
|
23
24
|
key: Optional[str] = None,
|
|
24
25
|
) -> str:
|
|
25
26
|
"""
|
|
@@ -36,7 +37,10 @@ def form_select(
|
|
|
36
37
|
class_name: Tailwind CSS classes
|
|
37
38
|
theme: Optional theme dictionary. If None, uses active global theme.
|
|
38
39
|
Set to False to disable theming for this component.
|
|
39
|
-
|
|
40
|
+
defer_update: If True, don't trigger Streamlit rerun on change.
|
|
41
|
+
Value is stored locally and sent on next rerun (e.g., Apply button).
|
|
42
|
+
Requires 'key' to be set.
|
|
43
|
+
key: Unique key for the component (required if defer_update=True)
|
|
40
44
|
|
|
41
45
|
Returns:
|
|
42
46
|
The currently selected value
|
|
@@ -57,6 +61,16 @@ def form_select(
|
|
|
57
61
|
{"label": "Scenarios", "options": ["Q2 Demand Surge"]}
|
|
58
62
|
]
|
|
59
63
|
)
|
|
64
|
+
|
|
65
|
+
# Deferred update (no rerun until Apply button clicked)
|
|
66
|
+
site = form_select(
|
|
67
|
+
label="Site",
|
|
68
|
+
options=["AML_14", "ADL", "Devens"],
|
|
69
|
+
defer_update=True,
|
|
70
|
+
key="site_select"
|
|
71
|
+
)
|
|
72
|
+
if st.button("Apply"):
|
|
73
|
+
st.rerun()
|
|
60
74
|
"""
|
|
61
75
|
# Resolve theme (None = use global, False = disable)
|
|
62
76
|
from ..themes import get_active_theme
|
|
@@ -73,6 +87,8 @@ def form_select(
|
|
|
73
87
|
style=style,
|
|
74
88
|
className=class_name,
|
|
75
89
|
theme=resolved_theme,
|
|
90
|
+
deferUpdate=defer_update,
|
|
91
|
+
componentKey=key,
|
|
76
92
|
key=key,
|
|
77
93
|
default=value,
|
|
78
94
|
)
|
|
@@ -23,6 +23,7 @@ def form_slider(
|
|
|
23
23
|
style: Optional[Dict[str, Any]] = None,
|
|
24
24
|
class_name: str = "",
|
|
25
25
|
theme: Optional[Dict[str, Any]] = None,
|
|
26
|
+
defer_update: bool = False,
|
|
26
27
|
key: Optional[str] = None,
|
|
27
28
|
) -> float:
|
|
28
29
|
"""
|
|
@@ -41,7 +42,10 @@ def form_slider(
|
|
|
41
42
|
class_name: Tailwind CSS classes
|
|
42
43
|
theme: Optional theme dictionary. If None, uses active global theme.
|
|
43
44
|
Set to False to disable theming for this component.
|
|
44
|
-
|
|
45
|
+
defer_update: If True, don't trigger Streamlit rerun on change.
|
|
46
|
+
Value is stored locally and sent on next rerun (e.g., Apply button).
|
|
47
|
+
Requires 'key' to be set.
|
|
48
|
+
key: Unique key for the component (required if defer_update=True)
|
|
45
49
|
|
|
46
50
|
Returns:
|
|
47
51
|
The current slider value
|
|
@@ -65,6 +69,18 @@ def form_slider(
|
|
|
65
69
|
max_val=100,
|
|
66
70
|
color="#ff5733"
|
|
67
71
|
)
|
|
72
|
+
|
|
73
|
+
# Deferred update (no rerun until Apply button clicked)
|
|
74
|
+
threshold = form_slider(
|
|
75
|
+
label="Threshold",
|
|
76
|
+
value=50,
|
|
77
|
+
min_val=0,
|
|
78
|
+
max_val=100,
|
|
79
|
+
defer_update=True,
|
|
80
|
+
key="threshold_slider"
|
|
81
|
+
)
|
|
82
|
+
if st.button("Apply"):
|
|
83
|
+
st.rerun()
|
|
68
84
|
"""
|
|
69
85
|
# Resolve theme (None = use global, False = disable)
|
|
70
86
|
from ..themes import get_active_theme
|
|
@@ -84,6 +100,8 @@ def form_slider(
|
|
|
84
100
|
style=style,
|
|
85
101
|
className=class_name,
|
|
86
102
|
theme=resolved_theme,
|
|
103
|
+
deferUpdate=defer_update,
|
|
104
|
+
componentKey=key,
|
|
87
105
|
key=key,
|
|
88
106
|
default=value,
|
|
89
107
|
)
|
|
@@ -19,6 +19,7 @@ def radio_group(
|
|
|
19
19
|
style: Optional[Dict[str, Any]] = None,
|
|
20
20
|
class_name: str = "",
|
|
21
21
|
theme: Optional[Dict[str, Any]] = None,
|
|
22
|
+
defer_update: bool = False,
|
|
22
23
|
key: Optional[str] = None,
|
|
23
24
|
) -> Optional[str]:
|
|
24
25
|
"""
|
|
@@ -36,7 +37,10 @@ def radio_group(
|
|
|
36
37
|
class_name: Tailwind CSS classes
|
|
37
38
|
theme: Optional theme dictionary. If None, uses active global theme.
|
|
38
39
|
Set to False to disable theming for this component.
|
|
39
|
-
|
|
40
|
+
defer_update: If True, don't trigger Streamlit rerun on change.
|
|
41
|
+
Value is stored locally and sent on next rerun (e.g., Apply button).
|
|
42
|
+
Requires 'key' to be set.
|
|
43
|
+
key: Unique key for the component (required if defer_update=True)
|
|
40
44
|
|
|
41
45
|
Returns:
|
|
42
46
|
ID of the selected item (string), or None if nothing selected
|
|
@@ -51,6 +55,16 @@ def radio_group(
|
|
|
51
55
|
]
|
|
52
56
|
)
|
|
53
57
|
# Returns: "credit" (only one can be selected)
|
|
58
|
+
|
|
59
|
+
# Deferred update (no rerun until Apply button clicked)
|
|
60
|
+
selected = radio_group(
|
|
61
|
+
label="Payment Method",
|
|
62
|
+
items=[...],
|
|
63
|
+
defer_update=True,
|
|
64
|
+
key="payment_radio"
|
|
65
|
+
)
|
|
66
|
+
if st.button("Apply"):
|
|
67
|
+
st.rerun()
|
|
54
68
|
"""
|
|
55
69
|
# Get default selected item (first checked item)
|
|
56
70
|
default_selected = None
|
|
@@ -73,6 +87,8 @@ def radio_group(
|
|
|
73
87
|
style=style,
|
|
74
88
|
className=class_name,
|
|
75
89
|
theme=resolved_theme,
|
|
90
|
+
deferUpdate=defer_update,
|
|
91
|
+
componentKey=key,
|
|
76
92
|
key=key,
|
|
77
93
|
default=default_selected,
|
|
78
94
|
)
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Styled container component for wrapping native Streamlit components with Tailwind styling.
|
|
3
|
+
|
|
4
|
+
This module provides a context manager that enables Tailwind CSS-like styling
|
|
5
|
+
for native Streamlit components (st.slider, st.button, st.text_input, etc.).
|
|
6
|
+
|
|
7
|
+
Supports:
|
|
8
|
+
- All Tailwind utility classes
|
|
9
|
+
- Opacity modifiers (bg-blue-500/50)
|
|
10
|
+
- Hover, focus, and active variants
|
|
11
|
+
- Transitions and animations
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from contextlib import contextmanager
|
|
15
|
+
from typing import Dict, Any, Optional, Generator
|
|
16
|
+
import uuid
|
|
17
|
+
|
|
18
|
+
import streamlit as st
|
|
19
|
+
|
|
20
|
+
from .tailwind import parse_tailwind_classes
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@contextmanager
|
|
24
|
+
def styled_container(
|
|
25
|
+
*classes: str,
|
|
26
|
+
style: Optional[Dict[str, Any]] = None,
|
|
27
|
+
key: Optional[str] = None,
|
|
28
|
+
) -> Generator[None, None, None]:
|
|
29
|
+
"""
|
|
30
|
+
Context manager for styling native Streamlit components with Tailwind classes.
|
|
31
|
+
|
|
32
|
+
Wraps Streamlit components in a styled container with support for Tailwind CSS
|
|
33
|
+
utility classes, including hover:, focus:, and active: variants.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
*classes: Tailwind CSS class names (e.g., "bg-slate-800", "hover:bg-slate-700")
|
|
37
|
+
style: Optional dict of additional inline CSS properties to merge
|
|
38
|
+
key: Optional unique key for the container (auto-generated if not provided)
|
|
39
|
+
|
|
40
|
+
Yields:
|
|
41
|
+
None - use as a context manager with 'with' statement
|
|
42
|
+
|
|
43
|
+
Example:
|
|
44
|
+
Basic usage with Tailwind classes::
|
|
45
|
+
|
|
46
|
+
with styled_container("bg-slate-800", "border", "border-blue-500", "rounded-xl", "p-4"):
|
|
47
|
+
st.slider("Risk Threshold", 0, 100, 75)
|
|
48
|
+
st.button("Apply")
|
|
49
|
+
|
|
50
|
+
With hover and focus states::
|
|
51
|
+
|
|
52
|
+
with styled_container(
|
|
53
|
+
"bg-slate-800",
|
|
54
|
+
"border-2",
|
|
55
|
+
"border-slate-600",
|
|
56
|
+
"rounded-xl",
|
|
57
|
+
"p-6",
|
|
58
|
+
"transition-all",
|
|
59
|
+
"duration-200",
|
|
60
|
+
"hover:bg-slate-700",
|
|
61
|
+
"hover:border-blue-500",
|
|
62
|
+
"focus:border-blue-400"
|
|
63
|
+
):
|
|
64
|
+
st.text_input("Username")
|
|
65
|
+
st.text_input("Password", type="password")
|
|
66
|
+
st.button("Login")
|
|
67
|
+
|
|
68
|
+
With opacity modifiers::
|
|
69
|
+
|
|
70
|
+
with styled_container(
|
|
71
|
+
"bg-rose-500/20",
|
|
72
|
+
"border",
|
|
73
|
+
"border-rose-500/50",
|
|
74
|
+
"rounded-lg",
|
|
75
|
+
"p-4"
|
|
76
|
+
):
|
|
77
|
+
st.write("Rose-tinted container")
|
|
78
|
+
|
|
79
|
+
With gradient backgrounds::
|
|
80
|
+
|
|
81
|
+
with styled_container(
|
|
82
|
+
"bg-gradient-to-br",
|
|
83
|
+
"from-slate-800",
|
|
84
|
+
"to-slate-900",
|
|
85
|
+
"rounded-2xl",
|
|
86
|
+
"p-6"
|
|
87
|
+
):
|
|
88
|
+
st.metric("Revenue", "$12,450", "+8.2%")
|
|
89
|
+
|
|
90
|
+
With custom inline styles::
|
|
91
|
+
|
|
92
|
+
with styled_container(
|
|
93
|
+
"bg-slate-800",
|
|
94
|
+
"rounded-lg",
|
|
95
|
+
style={"min-height": "200px", "box-shadow": "0 0 20px rgba(59,130,246,0.3)"}
|
|
96
|
+
):
|
|
97
|
+
st.write("Custom styled container")
|
|
98
|
+
|
|
99
|
+
Note:
|
|
100
|
+
- The focus: variant uses :focus-within, which triggers when any child
|
|
101
|
+
element (like an input) receives focus
|
|
102
|
+
- Transitions work with hover/focus states for smooth animations
|
|
103
|
+
- Gradient classes (from-, to-, via-) work with bg-gradient-to-* classes
|
|
104
|
+
"""
|
|
105
|
+
# Generate unique container ID
|
|
106
|
+
container_id = key or f"stc-{uuid.uuid4().hex[:8]}"
|
|
107
|
+
|
|
108
|
+
# Parse classes into categorized CSS dicts
|
|
109
|
+
parsed = parse_tailwind_classes(classes)
|
|
110
|
+
|
|
111
|
+
# Merge with custom style dict
|
|
112
|
+
if style:
|
|
113
|
+
parsed["base"].update(style)
|
|
114
|
+
|
|
115
|
+
# Build CSS rules for each state
|
|
116
|
+
css_blocks = []
|
|
117
|
+
|
|
118
|
+
# Use a more specific selector that targets the container's parent block
|
|
119
|
+
selector = f'[data-testid="stVerticalBlock"]:has(> [data-stc-id="{container_id}"])'
|
|
120
|
+
|
|
121
|
+
# Base styles
|
|
122
|
+
if parsed["base"]:
|
|
123
|
+
base_css = "; ".join(f"{k}: {v}" for k, v in parsed["base"].items())
|
|
124
|
+
css_blocks.append(f"{selector} {{ {base_css} }}")
|
|
125
|
+
|
|
126
|
+
# Hover styles
|
|
127
|
+
if parsed["hover"]:
|
|
128
|
+
hover_css = "; ".join(f"{k}: {v}" for k, v in parsed["hover"].items())
|
|
129
|
+
css_blocks.append(f"{selector}:hover {{ {hover_css} }}")
|
|
130
|
+
|
|
131
|
+
# Focus styles (uses :focus-within for child focus)
|
|
132
|
+
if parsed["focus"]:
|
|
133
|
+
focus_css = "; ".join(f"{k}: {v}" for k, v in parsed["focus"].items())
|
|
134
|
+
css_blocks.append(f"{selector}:focus-within {{ {focus_css} }}")
|
|
135
|
+
|
|
136
|
+
# Active styles
|
|
137
|
+
if parsed["active"]:
|
|
138
|
+
active_css = "; ".join(f"{k}: {v}" for k, v in parsed["active"].items())
|
|
139
|
+
css_blocks.append(f"{selector}:active {{ {active_css} }}")
|
|
140
|
+
|
|
141
|
+
# Inject CSS and marker element
|
|
142
|
+
css_content = "\n ".join(css_blocks)
|
|
143
|
+
st.markdown(
|
|
144
|
+
f"""
|
|
145
|
+
<style>
|
|
146
|
+
{css_content}
|
|
147
|
+
</style>
|
|
148
|
+
<div data-stc-id="{container_id}" style="display:none;"></div>
|
|
149
|
+
""",
|
|
150
|
+
unsafe_allow_html=True,
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
yield
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
# Convenience function for inline style conversion
|
|
157
|
+
def css(*classes: str, **extra_styles: str) -> str:
|
|
158
|
+
"""
|
|
159
|
+
Convert Tailwind classes to an inline CSS string.
|
|
160
|
+
|
|
161
|
+
Useful for applying Tailwind-like styles to st.markdown HTML content.
|
|
162
|
+
|
|
163
|
+
Args:
|
|
164
|
+
*classes: Tailwind CSS class names
|
|
165
|
+
**extra_styles: Additional CSS properties as keyword arguments
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
CSS string suitable for inline style attribute
|
|
169
|
+
|
|
170
|
+
Example:
|
|
171
|
+
>>> css("bg-slate-800", "p-4", "rounded-lg")
|
|
172
|
+
'background-color: #1e293b; padding: 1rem; border-radius: 0.5rem'
|
|
173
|
+
|
|
174
|
+
>>> css("text-blue-500", font_size="20px")
|
|
175
|
+
'color: #3b82f6; font-size: 20px'
|
|
176
|
+
|
|
177
|
+
With st.markdown::
|
|
178
|
+
|
|
179
|
+
st.markdown(
|
|
180
|
+
f'<div style="{css("bg-slate-800", "p-4", "rounded-lg")}">Content</div>',
|
|
181
|
+
unsafe_allow_html=True
|
|
182
|
+
)
|
|
183
|
+
"""
|
|
184
|
+
from .tailwind import tw
|
|
185
|
+
|
|
186
|
+
styles = tw(*classes)
|
|
187
|
+
|
|
188
|
+
# Add extra styles (convert underscores to hyphens)
|
|
189
|
+
for key, value in extra_styles.items():
|
|
190
|
+
css_key = key.replace("_", "-")
|
|
191
|
+
styles[css_key] = value
|
|
192
|
+
|
|
193
|
+
return "; ".join(f"{k}: {v}" for k, v in styles.items())
|