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 } 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(Ref(Node));
export class StyledElementView extends DOMComponentView {
    static __name__ = "StyledElementView";
    style = new InlineStyleSheet();
    connect_signals() {
        super.connect_signals();
        const { styles, css_classes, css_variables, stylesheets } = this.model.properties;
        this.on_change(styles, () => this._update_styles());
        this.on_change(css_classes, () => this._update_css_classes());
        this.on_transitive_change(css_variables, () => this._update_css_variables());
        this.on_change(stylesheets, () => this._update_stylesheets());
    }
    render() {
        super.render();
        this._apply_styles();
    }
    *_css_classes() {
        yield* super._css_classes();
        yield* this.model.css_classes;
    }
    *_css_variables() {
        yield* super._css_variables();
        for (const [name, node] of entries(this.model.css_variables)) {
            const value = this.resolve_coordinate(node);
            if (isNumber(value)) {
                yield [name, `${value}px`];
            }
        }
    }
    *_stylesheets() {
        yield* super._stylesheets();
        yield this.style;
        yield* this._computed_stylesheets();
    }
    *_computed_stylesheets() {
        for (const stylesheet of this.model.stylesheets) {
            if (stylesheet instanceof BaseStyleSheet) {
                yield stylesheet.underlying();
            }
            else {
                yield new InlineStyleSheet(stylesheet);
            }
        }
    }
    _apply_styles() {
        apply_styles(this.el.style, this.model.styles);
    }
    _update_styles() {
        this.el.removeAttribute("style"); // TODO: maintain _applied_styles
        this._apply_styles();
    }
}
export class StyledElement extends Model {
    static __name__ = "StyledElement";
    constructor(attrs) {
        super(attrs);
    }
    static {
        this.define(({ List, Str }) => ({
            css_classes: [List(Str), []],
            css_variables: [CSSVariables, {}],
            styles: [StylesLike, {}],
            stylesheets: [StyleSheets, []],
        }));
    }
}
//# sourceMappingURL=styled_element.js.map