Open rmorshea opened 6 years ago
ping: @mpacer
Yeah I think @gnestor had hoped for a safelist of components, and that it would be those that are require
-able (straight from npm packages).
Hi @rmorshea! 👋
First, vdom doesn't support any tag names that are not native DOM elements. We can change that but that's the first blocker.
Second, this could (and probably should) be a separate Python library (e.g. _vdomreact).
Third, I was able to prototype this in the notebook:
# In[1]
from IPython.display import HTML
def render_component(package, module, props, stylesheets = []):
# Generate a unique id for the root DOM node (that React mounts to)
id = str(hash(package + str(props)))
# Optionally load stylesheets that the React component depends on
css = '\n'.join([f'<link href="{url}" rel="stylesheet" />' for url in stylesheets])
html = f'''
<div id="{id}" style="padding: 10px;""></div>
<script type="module">
import React from '//dev.jspm.io/react';
import ReactDOM from '//dev.jspm.io/react-dom';
import ImportedPackage from '//dev.jspm.io/{package}';
// Import a specific or the default module from the package
const ImportedComponent = '{module}' ?
ImportedPackage['{module}'] :
(ImportedPackage.default ? ImportedPackage.default : ImportedPackage);
ReactDOM.render(
React.createElement(ImportedComponent, {props}),
document.getElementById('{id}')
);
</script>
'''
return HTML(html + css)
# In[2]
render_component(
package='@blueprintjs/core',
module='Button',
props={
'intent': 'success',
'text': 'Click me'
}
)
# In[3]
render_component(
package='@blueprintjs/core',
module='RangeSlider',
props={
'min': 0,
'max': 100,
'stepSize': 5,
'labelStepSize': 25
},
stylesheets=[
'//dev.jspm.io/npm:@blueprintjs/core@3.6.1/lib/css/blueprint.css',
'//dev.jspm.io/npm:@blueprintjs/icons@3.1.0/lib/css/blueprint-icons.css',
'//dev.jspm.io/npm:normalize.css@8.0.0/normalize.css'
]
)
A few notes:
import
(and provides polyfills for almost every Node.js API), so jspm.io makes almost every npm packages available in the browserimport_component
(like vdom's create_component
):from vdom_react import import_component
range_slider = import_component(package='@blueprintjs/core', module='RangeSlider', stylesheets=[
'//dev.jspm.io/npm:@blueprintjs/core@3.6.1/lib/css/blueprint.css',
'//dev.jspm.io/npm:@blueprintjs/icons@3.1.0/lib/css/blueprint-icons.css',
'//dev.jspm.io/npm:normalize.css@8.0.0/normalize.css'
])
range_slider(min=0, max=100, steoSize=5, labelStepSize=25)
Now, combine that with event support in vdom:
def handle_change(event):
slider_value = event['target']['value']
my_slider.update(create_slider(value))
def create_slider(value):
return range_slider(
min=0,
max=100,
stepSize=5,
labelStepSize=25,
onChange=handle_change,
value=value
)
my_slider = create_slider(value=0)
@gnestor I'm a little too tired to take this in at the moment, but this is definitely interesting!
I haven't followed everything that's gone on with vdom
but is the my_slider.update
method something new that would be provided by the hypothetical vdom_react
library?
@rmorshea Understood 👌
my_slider
is a display handle (the result of IPython.display.display
or IPython.display.HTML
or any ipython display function). As of ~2 years ago, ipython also provides an update_display
function which allows the kernel-side to update a display on the front-end (even if it's in the output of another cell). Display handles also have an update
method which is just aconveniencee method for update_display
.
What if you could load React components that were registered as "plugins" using
vdom
...Assuming you had some sort of global plugin storage mechanism it seems like it would be relatively trivial to identify whether or not the
tagName
was novel or not before grabbing the appropriate plugin and dynamically mounting it.The part I don't know anything about is what that "global plugin storage" would look like, or how users would go about registering their plugin with
nteract
.