@bokeh/bokehjs
Version:
Interactive, novel data visualization
113 lines • 4.22 kB
JavaScript
import { Model } from "../../model";
import { Node } from "../coordinates/node";
import { Styles } from "../dom/styles";
import { StyleSheet as BaseStyleSheet } from "../dom/stylesheets";
import { DOMComponentView } from "../../core/dom_view";
import { apply_styles } from "../../core/css";
import { InlineStyleSheet } from "../../core/dom";
import { entries } from "../../core/util/object";
import { isNumber, isString } from "../../core/util/types";
import { List, Or, Ref, Str, Dict, Nullable } from "../../core/kinds";
export const StylesLike = Or(Dict(Nullable(Str)), Ref(Styles)); // TODO: add validation for CSSStyles
export const StyleSheets = List(Or(Ref(BaseStyleSheet), Str, Dict(StylesLike)));
export const CSSVariables = Dict(Or(Ref(Node), Str));
export class StyledElementView extends DOMComponentView {
static __name__ = "StyledElementView";
/**
* Computed styles applied to self.
*/
style = new InlineStyleSheet("", "style"); // TODO rename to `self_style`
/**
* Computed styles append by the parent.
*/
parent_style = new InlineStyleSheet("", "parent", true);
computed_stylesheets() {
return [...super.computed_stylesheets(), this.style, this.parent_style];
}
connect_signals() {
super.connect_signals();
const { html_attributes, html_id, styles, css_classes, css_variables, stylesheets } = this.model.properties;
this.on_change([html_attributes, html_id, css_classes, styles], () => this._apply_html_attributes());
this.on_transitive_change(css_variables, () => this._apply_html_attributes());
this.on_transitive_change(stylesheets, () => this._update_stylesheets());
}
*_css_classes() {
yield* super._css_classes();
yield* this.model.css_classes;
}
*_css_variables() {
yield* super._css_variables();
for (const [key, val] of entries(this.model.css_variables)) {
if (val instanceof Node) {
const value = this.resolve_coordinate(val);
if (isNumber(value)) {
yield [key, `${value}px`];
}
else if (isString(value)) {
yield [key, value];
}
}
else {
yield [key, val];
}
}
}
user_stylesheets() {
return [...super.user_stylesheets(), ...this._user_stylesheets()];
}
*_user_stylesheets() {
for (const stylesheet of this.model.stylesheets) {
if (stylesheet instanceof BaseStyleSheet) {
yield stylesheet.underlying();
}
else {
yield new InlineStyleSheet(stylesheet);
}
}
}
_apply_html_attributes() {
for (const key of this._applied_html_attributes) {
this.el.removeAttribute(key);
}
this._applied_html_attributes = [];
this._update_css_classes();
for (const [key, val] of entries(this.model.html_attributes)) {
if (key == "class") {
const classes = val.split(/ +/);
this._applied_css_classes.push(...classes);
this.class_list.add(...classes);
}
else {
this.el.setAttribute(key, val);
this._applied_html_attributes.push(key);
}
}
const id = this.model.html_id;
if (id != null) {
this.el.setAttribute("id", id);
this._applied_html_attributes.push("id");
}
this._apply_styles();
this._update_css_variables();
}
_apply_styles() {
apply_styles(this.el.style, this.model.styles);
}
}
export class StyledElement extends Model {
static __name__ = "StyledElement";
constructor(attrs) {
super(attrs);
}
static {
this.define({
html_attributes: [Dict(Str), {}],
html_id: [Nullable(Str), null],
css_classes: [List(Str), []],
css_variables: [CSSVariables, {}],
styles: [StylesLike, {}],
stylesheets: [StyleSheets, []],
});
}
}
//# sourceMappingURL=styled_element.js.map