@bokeh/bokehjs
Version:
Interactive, novel data visualization
192 lines • 5.57 kB
JavaScript
import { View } from "./view";
import { create_element, empty, InlineStyleSheet, ClassList } from "./dom";
import { isString } from "./util/types";
import { assert } from "./util/assert";
import base_css from "../styles/base.css";
export class DOMView extends View {
static __name__ = "DOMView";
static tag_name = "div";
static aria_role;
el;
shadow_el;
get bbox() {
return undefined;
}
serializable_state() {
const state = super.serializable_state();
const { bbox } = this;
return bbox != null ? { ...state, bbox: bbox.round() } : state;
}
get children_el() {
return this.shadow_el ?? this.el;
}
initialize() {
super.initialize();
this.el = this._create_element();
}
remove() {
this.el.remove();
super.remove();
}
stylesheets() {
return [];
}
css_classes() {
return [];
}
rerender() {
this.render();
this.r_after_render();
}
render_to(target) {
this.render();
target.appendChild(this.el);
}
after_render() {
this.reposition();
}
r_after_render() {
for (const child_view of this.children()) {
if (child_view instanceof DOMView) {
child_view.r_after_render();
}
}
this.after_render();
this._was_built = true;
}
_create_element() {
return create_element(this.constructor.tag_name, { role: this.constructor.aria_role });
}
reposition(_displayed) { }
_was_built = false;
/**
* Build a top-level DOM view (e.g. during embedding).
*/
build(target) {
assert(this.is_root);
this.render_to(target);
this.r_after_render();
this.notify_finished();
}
/**
* Define where to render this element or let the parent decide.
*
* This is useful when creating "floating" components or adding
* components to canvas' layers.
*/
rendering_target() {
return null;
}
}
export class DOMElementView extends DOMView {
static __name__ = "DOMElementView";
class_list;
initialize() {
super.initialize();
this.class_list = new ClassList(this.el.classList);
}
get self_target() {
return this.el;
}
}
export class DOMComponentView extends DOMElementView {
static __name__ = "DOMComponentView";
get self_target() {
return this.shadow_el;
}
initialize() {
super.initialize();
this.shadow_el = this.el.attachShadow({ mode: "open" });
}
_base_style = new InlineStyleSheet(base_css, "base");
_css_vars = new InlineStyleSheet("", "vars");
stylesheets() {
return [...super.stylesheets(), this._base_style];
}
/**
* Baseline stylesheets, e.g. imported CSS modules.
*/
static_stylesheets() {
return this.stylesheets();
}
/**
* Stylesheets computed by the component.
*/
computed_stylesheets() {
return [this._css_vars];
}
/**
* Other stylesheets, e.g. provided by user.
*/
user_stylesheets() {
return [];
}
empty() {
empty(this.shadow_el);
this.class_list.clear();
this._applied_css_classes = [];
this._applied_stylesheets = [];
for (const stylesheet of this.computed_stylesheets()) {
if (!stylesheet.persistent) {
stylesheet.clear();
}
}
}
render() {
this.empty();
this._update_stylesheets();
this._apply_html_attributes();
}
_applied_html_attributes = [];
_apply_html_attributes() {
this._update_css_classes();
}
reposition(_displayed) {
this._update_css_variables(); // TODO remove this when node invalidation is implemented
}
*_stylesheets() {
yield* this.static_stylesheets();
yield* this.computed_stylesheets();
yield* this.user_stylesheets();
}
*_css_classes() {
yield `bk-${this.model.type.replace(/\./g, "-")}`;
yield* this.css_classes();
}
*_css_variables() { }
_applied_stylesheets = [];
_apply_stylesheets(stylesheets) {
const resolved_stylesheets = stylesheets.map((style) => isString(style) ? new InlineStyleSheet(style) : style);
this._applied_stylesheets.push(...resolved_stylesheets);
resolved_stylesheets.forEach((stylesheet) => stylesheet.install(this.shadow_el));
}
_applied_css_classes = [];
_apply_css_classes(classes) {
this._applied_css_classes.push(...classes);
this.class_list.add(...classes);
}
_update_stylesheets() {
this._applied_stylesheets.forEach((stylesheet) => stylesheet.uninstall());
this._applied_stylesheets = [];
this._apply_stylesheets([...this._stylesheets()]);
}
_update_css_classes() {
this.class_list.remove(this._applied_css_classes);
this._applied_css_classes = [];
this._apply_css_classes([...this._css_classes()]);
}
_update_css_variables() {
const vars = [];
for (const [name, value] of this._css_variables()) {
const full_name = name.startsWith("--") ? name : `--${name}`;
vars.push(`${full_name}: ${value};\n`);
}
if (vars.length == 0) {
this._css_vars.clear();
}
else {
this._css_vars.replace(`:host {\n${vars}}`);
}
}
}
//# sourceMappingURL=dom_view.js.map