-
-
Notifications
You must be signed in to change notification settings - Fork 525
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
Add ReactiveHTML #1894
Add ReactiveHTML #1894
Conversation
Codecov Report
@@ Coverage Diff @@
## master #1894 +/- ##
========================================
Coverage 84.42% 84.43%
========================================
Files 179 180 +1
Lines 20776 21109 +333
========================================
+ Hits 17541 17824 +283
- Misses 3235 3285 +50
Continue to review full report at Codecov.
|
@mattpap I'd actually love to hear how crazy you think what I'm doing here is. |
I've been considering implementing something similar in bokeh together with the new CSS-based layout. As to the implementation, I need to look closer at this first. One thing that I would like to support in my approach, is allowing observing changes to CSS styles (actual stylesheets not |
ExamplesSlideshowAdvances image on click class Slideshow(ReactiveHTML):
index = param.Integer(default=0)
_html = '<img id="img" width=400 src="https://picsum.photos/800/300?image=${index}"></img>'
_dom_events = {'img': ['click']}
def _img_click(self, event):
self.index += 1
Slideshow(height=150, index=0) Simple Text Inputclass Input(ReactiveHTML):
value = param.String()
_html = '<input id="input" value="${value}"></input>'
_dom_events = {'input': ['change']}
i = Input()
pn.Row(i, i.param.value) Adding childrenclass Div(ReactiveHTML):
children = param.List()
_html = '<div id="div">${children}</div>'
Div(children=[Slideshow(index=4, width=300, height=150),
Slideshow(index=2, width=300, height=150)],
height=300) |
Seems quite powerful. Did you invent the API your self? Is it inspired by IDOM or something else? I'm just thinking that when you/ we want to communicate this. It would be powerful if there was already an existing user base familiar with the api or wanting to learn the api. And existing documentation and examples. Could we say that now you can build components in Panel using the React, Preact or IDOM API? Or what is this? |
Would this replace a lot of the custom bokeh extensions that we create? For example would I wrap the Fast widgets using this api instead of as custom bokeh extensions? |
This API is close to a game changer because it will let users easily extend and customize Panel. But then the "competition" will more be on how performant the server and bokeh js library is for example. Some of the "competing solutions" are using other servers that might be even faster than tornado and maybe have a smaller code base which can run faster or take advantage or never features of the Python language. And there is also the Bokeh layout engine slowing things down. And then maybe the confusion between the "original" components implemented using bokeh extensions and then these components. |
Not for long anymore. A CSS-based layout is scheduled to be worked on in near future. |
It's pretty similar to React htm syntax templating, except the state is represented as a bokeh
I would say yes, that's the goal, but we should have a detailed look at performance tradeoffs.
As @mattpap said I'm hoping we can close the gap on the layout performance front in the near future. In terms of server support I think the performance tradeoffs aren't huge for real world applications (correct me if you think I'm wrong here). That said the server infrastructure in Bokeh is definitely pluggable, and if a massively more performant server were to exist I think we could use that instead. |
How would a user/ package include css and js with a ReactiveHTML component? For example if they want to distribute it as a package. For example with paulopes components the css and js is a part of the component and when served the css and js files are extracted and included in the template. But of course only once for each css or js file. |
If you delegate to IDOM you will also be dependent on IDOM and it's development+success. |
I've tried to get the branch up and running. But I'm stuck when trying to $ panel build panel
Working directory: C:\repos\private\panel\panel
Using different version of bokeh, rebuilding from scratch.
Running npm install.
audited 53 packages in 0.794s
1 package is looking for funding
run `npm fund` for details
found 0 vulnerabilities
Using C:\repos\private\panel\panel\tsconfig.json
Compiling TypeScript (41 files)
panel/models/file_download.ts:3:26 - error TS2306: File 'C:/repos/private/panel/panel/node_modules/@bokeh/bokehjs/build/js/types/styles/buttons.css.d.ts' is not a module.
3 import * as buttons from "@bokehjs/styles/buttons.css"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
panel/models/reactive_html.ts:28:17 - error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
28 return !isNaN(str) && !isNaN(parseFloat(str))
~~~
panel/models/singleselect.ts:6:25 - error TS2306: File 'C:/repos/private/panel/panel/node_modules/@bokeh/bokehjs/build/js/types/styles/widgets/inputs.css.d.ts' is not a module.
6 import * as inputs from "@bokehjs/styles/widgets/inputs.css"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Linking modules
Output written to C:\repos\private\panel\panel\dist npm list
@holoviz/panel@0.11.0-a6 C:\repos\private\panel\panel
+-- @bokeh/bokehjs@2.3.0-dev.9
| +-- @bokeh/numbro@1.6.2
| +-- @bokeh/slickgrid@2.4.2702
| | +-- @types/slickgrid@2.1.30
| | | `-- @types/jquery@3.5.5
| | | `-- @types/sizzle@2.3.2
| | +-- jquery@3.5.1
| | +-- jquery-ui@1.12.1
| | `-- tslib@1.14.1 |
See #1889, I'm seeing the same thing, hopefully those will be fixed once Bokeh 2.3.0dev10 is out. That said those do not prevent the compiled bundle from being emitted which means despite those errors it should all still work.
Would imagine a similar mechanism, basically I would bundle them like all other CSS/JS dependencies, serve them on the server and then automatically interpolate them into the template. |
Thanks. I got the Can you also use Panel components as parameter values? If yes then you would have solved the TemplatedHTML PR also. And it could be really powerful. |
I've created a preliminary example here #1896 of a Lottie Files player. There are things I cannot get working. Some hints would be appreciated. Then I will continue such that it could end up as a reference example. |
I've created a preliminary and alternative Lottie example using the Lottie |
Do those interpolations do any sanitizations at all? If not, it will be easy to mix HTML into values, leading to possibility for cross-site scripting. The reason IDOM's API is bulky (and why bokehjs' DOM APIs are designed the way they are designed), is because they don't allow mixing HTML with raw strings, in principle not allowing cross-site scripting. |
This is absolutely vulnerable to potential cross-site scripting right now. It's also very much experimental for now and before deciding in what form to merge it I will add sanitization. If you have suggestions on how best to do that I'd love to see it. There's zero need to ever interpolate raw HTML into one of these templates. |
7aea258
to
a503c2a
Compare
a503c2a
to
006c138
Compare
I now use |
32da181
to
58b11ff
Compare
When compiling panel I get this error:
|
Yeah, will push a fix up soon. Note that Typescript checking is not strict though and it still emits a working panel.js bundle. |
Thanks, will fix both issues shortly. |
Allows wrapping arbitrary HTML and subscribing to attributes on specified DOM nodes. The way it works is that you provide an HTML template and declare a number of parameters, which are linked via template variables. Any DOM nodes you want to sync with Python must have an
id
of the formid='name
and any additional variables may also be templated in based on declared parameters. TheReactiveHTML
bokeh model will install aMutationObserver
on all objects which is linked to a parameter. Additionally you may also declare DOM events to subscribe to, e.g. for a button you subscribe to a'click'
event.ReactiveHTML
_html
The
_html
template supports a number of features via template variables (${variable}
):id
which can be used to refer to the specific node.${parameter_name}
can be used in the template to set and link attributes/properties (this works bi-directionally)onclick
oronchange
will call that Python method<div>${children}</div>
will render those children, however these must be list parameters and all contents will be treated as other panel ccomponents.The Preact (re-)rendering will only be triggered if one or more of the template variables has changed.
_scripts
In addition to templating HTML an arbitrary set of scripts may be declared on the
_scripts
attribute. These too will only execute if any of the template variables changes._scripts
takes the form of{parameter: ['JavaScript code']}
and are executed when the declared parameter/attribute changes. The scripts are given thedata
model as an argument in the namespace allowing it to access the current parameter/attribute state. Multiple scripts can be added to support distinct actions._dom_events
Named nodes can be subscribed to by declaring
_dom_events
, which takes the form of{node_name: [event, ...]}
. Available events depend on the type of HTML node but include things likeclick
andchange
. These events may then be watched by adding a method to the class_{node_name}_{event}
, which will be called whenever the event is triggered. Additionally these events may be watched using theon_event
method. Note that after a DOM event fires on a particular node all the parameters linked to that node are also updated, this allows non-reflected attributes to be synced, which do not fire a MutationObserver.Here is an example using Microsoft's Fast Design system: