Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VDOM as a Gateway to Plugins #72

Open
rmorshea opened this issue Sep 16, 2018 · 5 comments
Open

VDOM as a Gateway to Plugins #72

rmorshea opened this issue Sep 16, 2018 · 5 comments

Comments

@rmorshea
Copy link
Contributor

rmorshea commented Sep 16, 2018

What if you could load React components that were registered as "plugins" using vdom...

{
  "tagName": "MyCoolPlugin",
  "attributes": {
    "data-stuff-my-plugin-uses": "something-super-cool"
  },
}

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.

@rmorshea rmorshea changed the title VDOM as a Gateway to Extensions VDOM as a Gateway to Plugin Sep 16, 2018
@rmorshea rmorshea changed the title VDOM as a Gateway to Plugin VDOM as a Gateway to Plugins Sep 16, 2018
@rmorshea
Copy link
Contributor Author

rmorshea commented Oct 3, 2018

ping: @mpacer

@rgbkrk
Copy link
Member

rgbkrk commented Oct 26, 2018

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).

@gnestor
Copy link
Contributor

gnestor commented Oct 26, 2018

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. vdom_react).

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'
    ]
)

image

A few notes:

  • jspm.io serves npm packages as ES modules that modern browsers can import (and provides polyfills for almost every Node.js API), so jspm.io makes almost every npm packages available in the browser
  • The result should be rendered in an iframe to prevent malicious Javascript from taking over your computer or unintentional CSS overriding your Jupyter client's styles
  • This example doesn't use vdom at all but I could imagine a function called import_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)

@rmorshea
Copy link
Contributor Author

rmorshea commented Oct 26, 2018

@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?

@gnestor
Copy link
Contributor

gnestor commented Oct 26, 2018

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants