Streamlit component that listens for postMessage events and reports back
Project description
streamlit-notification_center-component
Streamlit component that listens to postMessage() traffic with a certain format.
Installation instructions
pip install streamlit_notification_center_component
Usage instructions
import streamlit as st
from streamlit_notification_center_component import notification_center
notification_center(key="globalnc")
Helper JavaScript methods
function ncSendMessage(target, body) {
Array.from(window.parent.frames).forEach((frame) => {
frame.postMessage({ type: 'nc', target: target, payload: body }, "*")
})
}
function ncClearTarget(target) {
Array.from(window.parent.frames).forEach((frame) => {
frame.postMessage({ type: 'nc', target: target, command: 'clear' }, "*")
})
}
function ncClearAll() {
Array.from(window.parent.frames).forEach((frame) => {
frame.postMessage({ type: 'nc', command: 'clear-all' }, "*")
})
}
Let's talk about what's going on here. Each of these three functions loop over all frames in the parent and invoke a postMessage on them. The type: 'nc' code MUST be present or the notification_center widget will ignore the message.
In cases where clearing the data from state on the streamlit side is desired, a command: property needs to be included. There are two possible values:
- 'clear': when present, a
target:property must also be included to identify what to clear - 'clear-all': when present, no other value than
type: 'nc'needs be present. All messages stored in thest.session_state._nc_datadict will be removed.
Lastly, when it comes to a normal message to be queued, the way this works is that streamlit will receive the value from the component's call to Streamlit.setComponentValue(). This will be a pre-vetted object conforming to the following TypeScript type:
export type NotificationMessage = {
type: 'nc';
target?: string;
payload?: any;
from?: string;
command?: null | 'clear' | 'clear-all';
}
When not sending a command to clear and type, target and payload are all present, then the dict st.session_state._nc_data will have its key .setdefault(target, []). This ensures that there is at least an empty array of values for the supplied target. Then the payload object is appended to this array. All streamlit code can check for and use values.
Helper Python Methods
These streamlit python functions are also defined
from streamlit_notification_center_component import nc_get, nc_get_last, nc_get_all, nc_set, nc_has, nc_clear, nc_clear_all
def nc_get(key, default_value=None):
"""
Retrieves the value associated with a given key from the session state.
Args:
key (str): The key for the value to retrieve.
default_value (optional): The value to return if the key is not found. Defaults to None.
Returns:
The value associated with the key if found, or the default value if the key is not found.
"""
if '_nc_data' not in st.session_state:
st.session_state._nc_data = {}
if st.session_state._nc_data.get(key) != None:
return st.session_state._nc_data[key]
else:
return default_value
def nc_get_last(key, default_value=None):
"""
Retrieves the value associated with a given key from the session state.
Args:
key (str): The key representing an array of messages with tis target
default_value (optional): The value to return if the key is not found. Defaults to None.
Returns:
The last value for the specified `key` rather than the whole array. If no
value is forthcoming, `default_value` is returned instead.
"""
if '_nc_data' not in st.session_state:
st.session_state._nc_data = {}
if st.session_state._nc_data.get(key) != None:
channel = st.session_state._nc_data.get(key)
if channel:
return channel[-1]
else:
return default_value
else:
return default_value
def nc_get_all():
"""
Retrieves all key-value pairs stored in the session state.
Returns:
dict: A dictionary containing all key-value pairs in the session state.
"""
return st.session_state._nc_data
def nc_set(key, value):
"""
Stores a value in the session state, associated with a given key.
Args:
key (str): The key to associate with the value.
value: The value to store.
"""
channel = st.session_state.setdefault('_nc_data', {}).setdefault(key, [])
channel.append(value)
def nc_has(key):
"""
Checks whether a given key exists in the session state.
Args:
key (str): The key to check for existence.
Returns:
bool: True if the key exists, False otherwise.
"""
return [False, True][nc_get(key) != None]
def nc_clear(key):
"""
Clears the value associated with a given key in the session state.
Args:
key (str): The key for the value to clear.
"""
nc_get(key, []).clear()
def nc_clear_all():
"""
Clears all key-value pairs stored in the session state.
"""
st.session_state._nc_data = {}
Usage Examples
Okay, down to brass tacks. The streamlit_notification_center_component's primary purpose is to allow code in other custom components to send data back to streamlit in one shared location or to allow HTML in a call to st.components.v1.html to communicate back to the Python streamlit side of things. Currently layout is very limited in streamlit from an HTML perspective. Being able to write a quick layout using something like a table or set of inline-block divs is doable using the st.components.v1.html approach. However as soon as you have an action or other feature that needs to send data back to streamlit, you've moved into custom component territory.
Working with st.components.v1.html
Let's take the most common example first. If you wanted to introduce the following HTML with a stylized link that looks like a button
notification_center(key="globalnc")
st.components.v1.html(
f'''
<a class="stylized-button" onclick="sendData()">Button</a>
<style>
a.stylized-button {{
padding: 0.25em;
margin: 0.1em;
border: 1px solid slategrey;
background-color: lightslategray;
border-radius: 5px;
color: lightyellow;
cursor: pointer;
display: inline-block;
user-select: none;
}}
</style>
<script>
function sendData() {{
ncSendMessage('stylized-button', {{msg: 'Stylized Button Pressed'}})
}}
function ncSendMessage(target, body) {{
Array.from(window.parent.frames).forEach((frame) => {{
frame.postMessage({{ type: 'nc', target: target, payload: body }}, "*")
}})
}}
</script>
'''
)
What's going on here? Well, first off we are creating a new instance of the notification_center() component. The key supplied can be anything but will positively identify this NotificationCenter instance from another should there be one. If debug printing is enabled (see below) then you'll see "[NotificationCenter(key)][target] value" strings in the python logs. Note that key will be the key= value supplied when the notification_center() component is created, target will be the key the array of messages will be appended to and value will be the array of values for that target.
Then we are injecting into the page a block of HTML with some CSS and JavaScript. You'll note in this example that the ncSendMessage function from above has been included in the block. This is the easiest way to handle sending a postMessage() call to all frames in the parent of the iframe this code will reside in. The NotificationCenter component will be residing in another iframe with how streamlit works.
We now have the ability to inject custom HTML that can speak back to streamlit into your streamlit pages. Something that was not provided by default behavior.
Working with custom components
Other components should be able to import notification_center and use the nc- prefixed python functions for communicating with NotificationCenter data. As components send messages to the NotificationCenter, those values can be checked on the python side and can be worked with.
Debug messaging
If you're running into trouble, turn on debug messaging. This is a runtime variable that is set in
st.session_state.setdefault('_nc_debug', False)
To turn it on, simply change the value to True
st.session_state._nc_debug = True
Visual examples
After this point you'll see NotificationCenter messages appearing in your Python console.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file streamlit_notification_center_component-0.0.3.tar.gz.
File metadata
- Download URL: streamlit_notification_center_component-0.0.3.tar.gz
- Upload date:
- Size: 451.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.11.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7a0f22a7bbb84763d3fed1b9a615f3acac84cf14e2f034d02fefb056fb3cfcda
|
|
| MD5 |
bc2d937046312ee47e4dca3dacb8a7de
|
|
| BLAKE2b-256 |
7790fdf30daf7c1e36dbfa0db8e73c369d63a98f2adfa3df903be624ed48f7ac
|
File details
Details for the file streamlit_notification_center_component-0.0.3-py3-none-any.whl.
File metadata
- Download URL: streamlit_notification_center_component-0.0.3-py3-none-any.whl
- Upload date:
- Size: 453.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.11.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1e66165258637293588b5d3e73cb53988fef6569547ee66098b6020d08e73cde
|
|
| MD5 |
0734d695b335df4c8dc416cb2e190760
|
|
| BLAKE2b-256 |
b0dbdea858885f71a5133ac5b65fab9eee545aa56f7082d1c3791e770cd254af
|