/
card.ts
151 lines (127 loc) · 4.99 KB
/
card.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import {Column, ColumnView} from "@bokehjs/models/layouts/column"
import * as DOM from "@bokehjs/core/dom"
import * as p from "@bokehjs/core/properties"
export class CardView extends ColumnView {
model: Card
button_el: HTMLButtonElement
header_el: HTMLElement
connect_signals(): void {
super.connect_signals()
const {active_header_background, children, collapsed, header_background, header_color, hide_header} = this.model.properties
this.on_change(children, () => this.render())
this.on_change(collapsed, () => this._collapse())
this.on_change([header_color, hide_header], () => this.render())
this.on_change([active_header_background, collapsed, header_background], () => {
const header_background = this.header_background
if (header_background == null)
return
this.child_views[0].el.style.backgroundColor = header_background
this.header_el.style.backgroundColor = header_background
})
}
get header_background(): string | null {
let header_background = this.model.header_background
if (!this.model.collapsed && this.model.active_header_background)
header_background = this.model.active_header_background
return header_background
}
render(): void {
this.empty()
this._update_stylesheets()
this._update_css_classes()
this._apply_styles()
this._apply_visible()
this.class_list.add(...this.css_classes())
const {button_css_classes, header_color, header_tag, header_css_classes} = this.model
const header_background = this.header_background
const header = this.child_views[0]
let header_el
if (this.model.collapsible) {
this.button_el = DOM.createElement("button", {type: "button", class: header_css_classes})
const icon = DOM.createElement("div", {class: button_css_classes})
icon.innerHTML = this.model.collapsed ? "\u25ba" : "\u25bc"
this.button_el.appendChild(icon)
this.button_el.style.backgroundColor = header_background != null ? header_background : ""
header.el.style.backgroundColor = header_background != null ? header_background : ""
this.button_el.appendChild(header.el)
this.button_el.onclick = () => this._toggle_button()
header_el = this.button_el
} else {
header_el = DOM.createElement((header_tag as any), {class: header_css_classes})
header_el.style.backgroundColor = header_background != null ? header_background : ""
header_el.appendChild(header.el)
}
this.header_el = header_el
if (!this.model.hide_header) {
header_el.style.color = header_color != null ? header_color : ""
this.shadow_el.appendChild(header_el)
header.render()
header.after_render()
}
for (const child_view of this.child_views.slice(1)) {
if (!this.model.collapsed)
this.shadow_el.appendChild(child_view.el)
child_view.render()
child_view.after_render()
}
}
async update_children(): Promise<void> {
await this.build_child_views()
this.render()
this.invalidate_layout()
}
_toggle_button(): void {
this.model.collapsed = !this.model.collapsed
}
_collapse(): void {
for (const child_view of this.child_views.slice(1)) {
if (this.model.collapsed)
this.shadow_el.removeChild(child_view.el)
else
this.shadow_el.appendChild(child_view.el)
}
this.button_el.children[0].innerHTML = this.model.collapsed ? "\u25ba" : "\u25bc"
this.invalidate_layout()
}
protected _createElement(): HTMLElement {
return DOM.createElement((this.model.tag as any), {class: this.css_classes()})
}
}
export namespace Card {
export type Attrs = p.AttrsOf<Props>
export type Props = Column.Props & {
active_header_background: p.Property<string | null>
button_css_classes: p.Property<string[]>
collapsed: p.Property<boolean>
collapsible: p.Property<boolean>
header_background: p.Property<string | null>
header_color: p.Property<string | null>
header_css_classes: p.Property<string[]>
header_tag: p.Property<string>
hide_header: p.Property<boolean>
tag: p.Property<string>
}
}
export interface Card extends Card.Attrs {}
export class Card extends Column {
properties: Card.Props
constructor(attrs?: Partial<Card.Attrs>) {
super(attrs)
}
static __module__ = "panel.models.layout"
static {
this.prototype.default_view = CardView
this.define<Card.Props>(({Array, Boolean, Nullable, String}) => ({
active_header_background: [ Nullable(String), null ],
button_css_classes: [ Array(String), [] ],
collapsed: [ Boolean, true ],
collapsible: [ Boolean, true ],
header_background: [ Nullable(String), null ],
header_color: [ Nullable(String), null ],
header_css_classes: [ Array(String), [] ],
header_tag: [ String, "div" ],
hide_header: [ Boolean, false ],
tag: [ String, "div" ],
}))
}
}