Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
giswqs
GitHub Repository: giswqs/geemap
Path: blob/master/js/tree_node.ts
2313 views
1
import {
2
css,
3
html,
4
LitElement,
5
nothing,
6
PropertyValues,
7
TemplateResult
8
} from "lit";
9
import { property } from "lit/decorators.js";
10
import { legacyStyles } from "./ipywidgets_styles";
11
import { materialStyles } from "./styles";
12
13
export interface Node {
14
label?: string;
15
children?: Array<Node>;
16
expanded?: boolean;
17
topLevel?: boolean;
18
}
19
20
export class TreeNode extends LitElement {
21
static get componentName() {
22
return `tree-node`;
23
}
24
25
static override styles = [
26
legacyStyles,
27
materialStyles,
28
css`
29
.node {
30
align-items: center;
31
cursor: pointer;
32
display: flex;
33
}
34
35
.node-text {
36
height: auto;
37
line-height: 24px;
38
}
39
40
.node:hover {
41
background-color: var(--jp-layout-color2);
42
margin-left: -100%;
43
padding-left: 100%;
44
}
45
46
.icon {
47
font-size: 13px;
48
width: 20px;
49
}
50
51
ul {
52
list-style: none;
53
padding-left: 20px;
54
margin: 0;
55
}
56
`,
57
];
58
59
@property() node: Node = {};
60
@property({ type: Boolean, reflect: true }) expanded: boolean = false;
61
62
override updated(changedProperties: PropertyValues<TreeNode>): void {
63
super.updated(changedProperties);
64
if (changedProperties.has("node") && this.node) {
65
if ("expanded" in this.node) {
66
this.expanded = this.node.expanded ?? false;
67
}
68
}
69
}
70
71
override render(): TemplateResult {
72
return html`
73
<div
74
class="node ${this.expanded ? "expanded" : ""}"
75
@click="${this.toggleExpand}"
76
>
77
${this.renderBullet()} ${this.renderIcon()}
78
<span class="legacy-text node-text">${this.node.label}</span>
79
</div>
80
${this.renderChildren()}
81
`;
82
}
83
84
private toggleExpand(): void {
85
this.expanded = !this.expanded;
86
}
87
88
private hasChildren(): boolean {
89
return !!this.node.children?.length;
90
}
91
92
private renderChildren(): TemplateResult | typeof nothing {
93
if (this.expanded && this.hasChildren()) {
94
return html`<ul>${this.node.children?.map(this.renderChild)}</ul>`;
95
}
96
return nothing;
97
}
98
99
private renderChild(child: Node): TemplateResult {
100
return html`<li><tree-node .node="${child}"></tree-node></li>`;
101
}
102
103
private renderBullet(): TemplateResult | typeof nothing {
104
if (this.node.topLevel) {
105
if (this.expanded) {
106
return html`
107
<span class="icon material-symbols-outlined"
108
>indeterminate_check_box</span
109
>
110
`;
111
}
112
return html`<span class="icon material-symbols-outlined">add_box</span>`;
113
} else if (this.hasChildren()) {
114
if (this.expanded) {
115
return html`<span class="icon material-symbols-outlined">remove</span>`;
116
}
117
return html`<span class="icon material-symbols-outlined">add</span>`;
118
}
119
return html`<span class="icon"></span>`;
120
}
121
122
private renderIcon(): TemplateResult | typeof nothing {
123
if (this.node.topLevel) {
124
return html`<span class="icon material-symbols-outlined"
125
>inventory_2</span
126
>`;
127
} else if (this.hasChildren()) {
128
if (this.expanded) {
129
return html`
130
<span class="icon material-symbols-outlined">folder_open</span>
131
`;
132
}
133
return html`<span class="icon material-symbols-outlined">folder</span>`;
134
}
135
return html`<span class="icon material-symbols-outlined">draft</span>`;
136
}
137
}
138
139
// Without this check, there's a component registry issue when developing locally.
140
if (!customElements.get(TreeNode.componentName)) {
141
customElements.define(TreeNode.componentName, TreeNode);
142
}
143