-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathmodal.py
121 lines (100 loc) · 4.18 KB
/
modal.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
from contextlib import contextmanager
import streamlit
import streamlit.components.v1 as components
# This is a custom version of the "streamlit-modal" third-party library
# The original library is not compatible with streamlit 1.30+
# https://github.com/teamtv/streamlit_modal/issues/19
# This is temporary until we replace our modals with the new native st.dialog feature
# https://docs.streamlit.io/develop/api-reference/execution-flow/st.dialog
class Modal:
def __init__(self, title, key, padding=20, max_width=None):
self.title = title
self.padding = padding
self.max_width = max_width
self.key = key
def is_open(self):
return streamlit.session_state.get(f"{self.key}-opened", False)
def open(self):
streamlit.session_state[f"{self.key}-opened"] = True
streamlit.rerun()
def close(self, rerun=True):
streamlit.session_state[f"{self.key}-opened"] = False
if rerun:
streamlit.rerun()
@contextmanager
def container(self):
streamlit.markdown(self._modal_styles(), unsafe_allow_html=True)
with streamlit.container():
_container = streamlit.container()
if self.title:
_container.markdown(f"<h2>{self.title}</h2>", unsafe_allow_html=True)
close_ = streamlit.button("X", key=f"{self.key}-close")
if close_:
self.close()
if not close_:
components.html(self._modal_script(), height=0, width=0)
with _container:
yield _container
def _modal_styles(self) -> str:
max_width = f"{self.max_width}px" if self.max_width else "unset"
return f"""
<style>
div[data-modal-container='true'][key='{self.key}'] {{
position: fixed;
width: 100vw !important;
left: 0;
z-index: 1001;
}}
div[data-modal-container='true'][key='{self.key}'] > div:first-child {{
margin: auto;
}}
div[data-modal-container='true'][key='{self.key}'] h1 a {{
display: none
}}
div[data-modal-container='true'][key='{self.key}']::before {{
position: fixed;
content: ' ';
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 1000;
background-color: rgba(0, 0, 0, 0.5);
}}
div[data-modal-container='true'][key='{self.key}'] > div:first-child {{
max-width: {max_width};
}}
div[data-modal-container='true'][key='{self.key}'] > div:first-child > div:first-child {{
width: unset !important;
background-color: #fff;
padding: {self.padding}px;
margin-top: {2*self.padding}px;
margin-left: -{self.padding}px;
margin-right: -{self.padding}px;
margin-bottom: -{2*self.padding}px;
z-index: 1001;
border-radius: 5px;
}}
div[data-modal-container='true'][key='{self.key}'] > div > div:nth-child(1 of .element-container) {{
z-index: 1003;
position: absolute;
}}
div[data-modal-container='true'][key='{self.key}'] > div > div:nth-child(1 of .element-container) > div {{
text-align: right;
padding-right: {self.padding}px;
max-width: {max_width};
}}
div[data-modal-container='true'][key='{self.key}'] > div > div:nth-child(1 of .element-container) > div > button {{
right: 0;
margin-top: {2*self.padding + 14}px;
}}
</style>
"""
def _modal_script(self) -> str:
return f"""
<script type="text/javascript">
const modalContainer = window.frameElement.parentElement.parentElement.parentElement;
modalContainer.setAttribute('data-modal-container', 'true');
modalContainer.setAttribute('key', '{self.key}');
</script>
"""