Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
giswqs
GitHub Repository: giswqs/geemap
Path: blob/master/js/container.ts
2313 views
1
import type { RenderProps } from "@anywidget/types";
2
import { css, html, HTMLTemplateResult, nothing, TemplateResult } from "lit";
3
import { property } from "lit/decorators.js";
4
import { classMap } from "lit/directives/class-map.js";
5
6
import { legacyStyles } from "./ipywidgets_styles";
7
import { LitWidget } from "./lit_widget";
8
import { materialStyles } from "./styles";
9
10
export interface ContainerModel {
11
icon: string;
12
title: string;
13
collapsed: boolean;
14
hide_close_button: boolean;
15
}
16
17
export class Container extends LitWidget<ContainerModel, Container> {
18
static get componentName(): string {
19
return `widget-container`;
20
}
21
22
static override styles = [
23
legacyStyles,
24
materialStyles,
25
css`
26
.container {
27
background: var(--jp-layout-color1);
28
border-radius: 4.5px;
29
box-shadow: 4px 5px 8px 0px #9e9e9e;
30
}
31
32
div {
33
background-color: var(--colab-primary-surface-color, --jp-layout-color1, white);
34
}
35
36
.header {
37
display: flex;
38
gap: 4px;
39
padding: 4px;
40
}
41
42
.reversed {
43
flex-direction: row-reverse;
44
}
45
46
.icon {
47
align-items: center;
48
display: flex;
49
font-size: 20px;
50
height: 28px;
51
justify-content: center;
52
padding: 0 4px;
53
}
54
55
.widget-container {
56
padding: 8px 12px 12px 12px;
57
}
58
59
.hidden {
60
display: none;
61
}
62
63
.header-button {
64
font-size: 16px;
65
height: 28px;
66
width: 28px;
67
}
68
69
.compact-header-button {
70
background: transparent;
71
font-size: 16px;
72
height: 28px;
73
width: 28px;
74
}
75
76
.header-text {
77
align-content: center;
78
flex-grow: 1;
79
padding: 0 12px 0 0;
80
}
81
82
.left-padding {
83
padding-left: 8px;
84
}
85
`,
86
];
87
88
@property({ type: String }) icon: string = "";
89
@property({ type: String }) override title: string = "";
90
@property({ type: Boolean }) collapsed: boolean = false;
91
@property({ type: Boolean }) hideCloseButton: boolean = false;
92
@property({ type: Boolean }) compactMode: boolean = false;
93
@property({ type: Boolean }) noHeader: boolean = false;
94
@property({ type: Boolean }) reverseHeader: boolean = false;
95
96
modelNameToViewName(): Map<keyof ContainerModel, keyof Container | null> {
97
return new Map([
98
["icon", "icon"],
99
["collapsed", "collapsed"],
100
["title", "title"],
101
["hide_close_button", "hideCloseButton"],
102
]);
103
}
104
105
override render() {
106
return html`
107
<div class="container">
108
${this.noHeader ? nothing : this.renderHeader()}
109
<div class="widget-container ${this.collapsed ? "hidden" : ""}">
110
<slot></slot>
111
</div>
112
</div>
113
`;
114
}
115
116
private renderHeader(): TemplateResult {
117
return this.compactMode ? this.renderCompactHeader() : html`
118
<div class="header ${this.reverseHeader ? "reversed" : ""}">
119
${this.renderIcon()}
120
${this.title ? this.renderTitle() : nothing}
121
${this.renderCollapseButton()}
122
${this.renderCloseButton()}
123
</div>`;
124
}
125
126
private renderCompactHeader(): TemplateResult {
127
return html`<div class="header ${this.reverseHeader ? "reversed" : ""}">
128
${this.renderCollapseButton()}
129
${(this.title && !this.collapsed) ? this.renderTitle() : nothing}
130
${this.renderCloseButton()}
131
</div>`;
132
}
133
134
private renderCloseButton(): HTMLTemplateResult | typeof nothing {
135
if (this.hideCloseButton) {
136
return nothing;
137
}
138
return html`
139
<button
140
class="legacy-button primary header-button"
141
@click="${this.onCloseButtonClicked}"
142
>
143
<span class="material-symbols-outlined">&#xe5cd;</span>
144
</button>
145
`;
146
}
147
148
private renderTitle(): HTMLTemplateResult {
149
return html`<span
150
class="${classMap({
151
"legacy-text": true,
152
"header-text": true,
153
"left-padding":
154
this.compactMode && this.title && !this.reverseHeader,
155
})}"
156
>${this.title}</span
157
>`;
158
}
159
160
private onCloseButtonClicked(): void {
161
this.dispatchEvent(new CustomEvent("close-clicked", {}));
162
}
163
164
private onCollapseToggled(): void {
165
this.collapsed = !this.collapsed;
166
this.dispatchEvent(new CustomEvent("collapse-clicked", {}));
167
}
168
169
private renderIcon(): TemplateResult {
170
return html`<span class="icon material-symbols-outlined">
171
${this.icon}
172
</span>`
173
}
174
175
private renderCollapseButton(): TemplateResult {
176
let icon: TemplateResult;
177
if (this.compactMode) {
178
icon = this.renderIcon();
179
} else if (this.collapsed) {
180
icon = html`<span class="material-symbols-outlined"
181
>&#xf830;</span
182
>`;
183
} else {
184
icon = html`<span class="material-symbols-outlined">&#xf507;</span>`;
185
}
186
return html`<button
187
class="${classMap({
188
'legacy-button': true,
189
'header-button': !this.compactMode,
190
'compact-header-button': this.compactMode,
191
'active': !this.collapsed,
192
})}"
193
class="legacy-button header-button"
194
@click="${this.onCollapseToggled}"
195
>
196
${icon}
197
</button>`
198
}
199
}
200
201
// Without this check, there's a component registry issue when developing locally.
202
if (!customElements.get(Container.componentName)) {
203
customElements.define(Container.componentName, Container);
204
}
205
206
async function render({ model, el }: RenderProps<ContainerModel>) {
207
const manager = document.createElement(
208
Container.componentName
209
) as Container;
210
manager.model = model;
211
el.appendChild(manager);
212
}
213
214
export default { render };
215