@deck.gl/widgets 9.1.12 → 9.2.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/compass-widget.d.ts +11 -34
- package/dist/compass-widget.d.ts.map +1 -1
- package/dist/compass-widget.js +27 -62
- package/dist/compass-widget.js.map +1 -1
- package/dist/context-menu-widget.d.ts +37 -0
- package/dist/context-menu-widget.d.ts.map +1 -0
- package/dist/context-menu-widget.js +74 -0
- package/dist/context-menu-widget.js.map +1 -0
- package/dist/dist.dev.js +2271 -581
- package/dist/fps-widget.d.ts +29 -0
- package/dist/fps-widget.d.ts.map +1 -0
- package/dist/fps-widget.js +51 -0
- package/dist/fps-widget.js.map +1 -0
- package/dist/fullscreen-widget.d.ts +15 -33
- package/dist/fullscreen-widget.d.ts.map +1 -1
- package/dist/fullscreen-widget.js +20 -51
- package/dist/fullscreen-widget.js.map +1 -1
- package/dist/geocoder-widget.d.ts +51 -0
- package/dist/geocoder-widget.d.ts.map +1 -0
- package/dist/geocoder-widget.js +138 -0
- package/dist/geocoder-widget.js.map +1 -0
- package/dist/gimbal-widget.d.ts +33 -0
- package/dist/gimbal-widget.d.ts.map +1 -0
- package/dist/gimbal-widget.js +116 -0
- package/dist/gimbal-widget.js.map +1 -0
- package/dist/index.cjs +1587 -341
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +37 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +27 -7
- package/dist/index.js.map +1 -1
- package/dist/info-widget.d.ts +37 -0
- package/dist/info-widget.d.ts.map +1 -0
- package/dist/info-widget.js +183 -0
- package/dist/info-widget.js.map +1 -0
- package/dist/lib/components/button-group.d.ts +8 -0
- package/dist/lib/components/button-group.d.ts.map +1 -0
- package/dist/lib/components/button-group.js +7 -0
- package/dist/lib/components/button-group.js.map +1 -0
- package/dist/lib/components/dropdown-menu.d.ts +8 -0
- package/dist/lib/components/dropdown-menu.d.ts.map +1 -0
- package/dist/lib/components/dropdown-menu.js +55 -0
- package/dist/lib/components/dropdown-menu.js.map +1 -0
- package/dist/lib/components/grouped-icon-button.d.ts +8 -0
- package/dist/lib/components/grouped-icon-button.d.ts.map +1 -0
- package/dist/lib/components/grouped-icon-button.js +7 -0
- package/dist/lib/components/grouped-icon-button.js.map +1 -0
- package/dist/lib/components/icon-button.d.ts +11 -0
- package/dist/lib/components/icon-button.d.ts.map +1 -0
- package/dist/lib/components/icon-button.js +7 -0
- package/dist/lib/components/icon-button.js.map +1 -0
- package/dist/lib/components/icon-menu.d.ts +16 -0
- package/dist/lib/components/icon-menu.d.ts.map +1 -0
- package/dist/lib/components/icon-menu.js +49 -0
- package/dist/lib/components/icon-menu.js.map +1 -0
- package/dist/lib/components/simple-menu.d.ts +16 -0
- package/dist/lib/components/simple-menu.d.ts.map +1 -0
- package/dist/lib/components/simple-menu.js +30 -0
- package/dist/lib/components/simple-menu.js.map +1 -0
- package/dist/lib/geocode/geocoder-history.d.ts +23 -0
- package/dist/lib/geocode/geocoder-history.d.ts.map +1 -0
- package/dist/lib/geocode/geocoder-history.js +64 -0
- package/dist/lib/geocode/geocoder-history.js.map +1 -0
- package/dist/lib/geocode/geocoder.d.ts +15 -0
- package/dist/lib/geocode/geocoder.d.ts.map +1 -0
- package/dist/lib/geocode/geocoder.js +5 -0
- package/dist/lib/geocode/geocoder.js.map +1 -0
- package/dist/lib/geocode/geocoders.d.ts +68 -0
- package/dist/lib/geocode/geocoders.d.ts.map +1 -0
- package/dist/lib/geocode/geocoders.js +182 -0
- package/dist/lib/geocode/geocoders.js.map +1 -0
- package/dist/loading-widget.d.ts +26 -0
- package/dist/loading-widget.d.ts.map +1 -0
- package/dist/loading-widget.js +41 -0
- package/dist/loading-widget.js.map +1 -0
- package/dist/reset-view-widget.d.ts +4 -4
- package/dist/reset-view-widget.d.ts.map +1 -1
- package/dist/reset-view-widget.js +7 -10
- package/dist/reset-view-widget.js.map +1 -1
- package/dist/scale-widget.d.ts +28 -0
- package/dist/scale-widget.d.ts.map +1 -0
- package/dist/scale-widget.js +111 -0
- package/dist/scale-widget.js.map +1 -0
- package/dist/screenshot-widget.d.ts +4 -4
- package/dist/screenshot-widget.d.ts.map +1 -1
- package/dist/screenshot-widget.js +7 -14
- package/dist/screenshot-widget.js.map +1 -1
- package/dist/splitter-widget.d.ts +32 -0
- package/dist/splitter-widget.d.ts.map +1 -0
- package/dist/splitter-widget.js +123 -0
- package/dist/splitter-widget.js.map +1 -0
- package/dist/stats-widget.d.ts +36 -0
- package/dist/stats-widget.d.ts.map +1 -0
- package/dist/stats-widget.js +115 -0
- package/dist/stats-widget.js.map +1 -0
- package/dist/stylesheet.css +121 -4
- package/dist/theme-widget.d.ts +31 -0
- package/dist/theme-widget.d.ts.map +1 -0
- package/dist/theme-widget.js +83 -0
- package/dist/theme-widget.js.map +1 -0
- package/dist/themes.d.ts +65 -36
- package/dist/themes.d.ts.map +1 -1
- package/dist/themes.js +20 -8
- package/dist/themes.js.map +1 -1
- package/dist/timeline-widget.d.ts +59 -0
- package/dist/timeline-widget.d.ts.map +1 -0
- package/dist/timeline-widget.js +83 -0
- package/dist/timeline-widget.js.map +1 -0
- package/dist/view-selector-widget.d.ts +33 -0
- package/dist/view-selector-widget.d.ts.map +1 -0
- package/dist/view-selector-widget.js +62 -0
- package/dist/view-selector-widget.js.map +1 -0
- package/dist/zoom-widget.d.ts +14 -43
- package/dist/zoom-widget.d.ts.map +1 -1
- package/dist/zoom-widget.js +14 -56
- package/dist/zoom-widget.js.map +1 -1
- package/dist.min.js +3 -1
- package/package.json +4 -3
- package/src/compass-widget.tsx +44 -106
- package/src/context-menu-widget.tsx +115 -0
- package/src/fps-widget.tsx +67 -0
- package/src/fullscreen-widget.tsx +33 -86
- package/src/geocoder-widget.tsx +209 -0
- package/src/gimbal-widget.tsx +188 -0
- package/src/index.ts +58 -8
- package/src/info-widget.tsx +225 -0
- package/src/lib/components/button-group.tsx +16 -0
- package/src/lib/components/dropdown-menu.tsx +98 -0
- package/src/lib/components/grouped-icon-button.tsx +24 -0
- package/src/lib/components/icon-button.tsx +30 -0
- package/src/lib/components/icon-menu.tsx +89 -0
- package/src/lib/components/simple-menu.tsx +52 -0
- package/src/lib/geocode/geocoder-history.ts +73 -0
- package/src/lib/geocode/geocoder.ts +15 -0
- package/src/lib/geocode/geocoders.ts +199 -0
- package/src/loading-widget.tsx +67 -0
- package/src/reset-view-widget.tsx +8 -11
- package/src/scale-widget.tsx +183 -0
- package/src/screenshot-widget.tsx +9 -11
- package/src/splitter-widget.tsx +179 -0
- package/src/stats-widget.tsx +166 -0
- package/src/stylesheet.css +121 -4
- package/src/theme-widget.tsx +120 -0
- package/src/themes.ts +45 -12
- package/src/timeline-widget.tsx +155 -0
- package/src/view-selector-widget.tsx +108 -0
- package/src/zoom-widget.tsx +39 -113
- package/dist/components.d.ts +0 -4
- package/dist/components.d.ts.map +0 -1
- package/dist/components.js +0 -17
- package/dist/components.js.map +0 -1
- package/dist/widget-impl.d.ts +0 -29
- package/dist/widget-impl.d.ts.map +0 -1
- package/dist/widget-impl.js +0 -60
- package/dist/widget-impl.js.map +0 -1
- package/src/components.tsx +0 -38
- package/src/widget-impl.ts +0 -88
package/src/stylesheet.css
CHANGED
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
flex-direction: column;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
/* Common button styles */
|
|
38
|
+
/* Common button background styles */
|
|
39
39
|
.deck-widget-button-group button,
|
|
40
40
|
.deck-widget-button button {
|
|
41
41
|
width: calc(var(--button-size, 28px) - 2px);
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
border-bottom-left-radius: 0;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
/* Icon button styles */
|
|
82
|
+
/* Icon button foreground styles */
|
|
83
83
|
.deck-widget button .deck-widget-icon {
|
|
84
84
|
background-color: var(--button-icon-idle, #616166);
|
|
85
85
|
background-position: 50%;
|
|
@@ -116,6 +116,16 @@
|
|
|
116
116
|
);
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
+
@keyframes spin {
|
|
120
|
+
to {
|
|
121
|
+
transform: rotate(360deg);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.deck-widget.deck-widget-loading button.deck-widget-spinner-icon .deck-widget-icon {
|
|
126
|
+
animation: spin 1s linear infinite;
|
|
127
|
+
}
|
|
128
|
+
|
|
119
129
|
.deck-pseudo-fullscreen {
|
|
120
130
|
height: 100% !important;
|
|
121
131
|
left: 0 !important;
|
|
@@ -152,10 +162,117 @@
|
|
|
152
162
|
.deck-widget.deck-widget-screenshot button.deck-widget-camera .deck-widget-icon {
|
|
153
163
|
mask-image: var(
|
|
154
164
|
--icon-camera,
|
|
155
|
-
url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="black"><path d="M480-260q75 0 127.5-52.5T660-440q0-75-52.5-127.5T480-620q-75 0-127.5 52.5T300-440q0 75 52.5 127.5T480-260Zm0-80q-42 0-71-29t-29-71q0-42 29-71t71-29q42 0 71 29t29 71q0 42-29 71t-71 29ZM160-120q-33 0-56.5-23.5T80-200v-480q0-33 23.5-56.5T160-760h126l74-80h240l74 80h126q33 0 56.5 23.5T880-680v480q0 33-23.5 56.5T800-120H160Zm0-80h640v-480H638l-73-80H395l-73 80H160v480Zm320-240Z"/></svg>')
|
|
165
|
+
url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 -960 960 960" fill="black"><path d="M480-260q75 0 127.5-52.5T660-440q0-75-52.5-127.5T480-620q-75 0-127.5 52.5T300-440q0 75 52.5 127.5T480-260Zm0-80q-42 0-71-29t-29-71q0-42 29-71t71-29q42 0 71 29t29 71q0 42-29 71t-71 29ZM160-120q-33 0-56.5-23.5T80-200v-480q0-33 23.5-56.5T160-760h126l74-80h240l74 80h126q33 0 56.5 23.5T880-680v480q0 33-23.5 56.5T800-120H160Zm0-80h640v-480H638l-73-80H395l-73 80H160v480Zm320-240Z"/></svg>')
|
|
156
166
|
);
|
|
157
167
|
-webkit-mask-image: var(
|
|
158
168
|
--icon-camera,
|
|
159
|
-
url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="black"><path d="M480-260q75 0 127.5-52.5T660-440q0-75-52.5-127.5T480-620q-75 0-127.5 52.5T300-440q0 75 52.5 127.5T480-260Zm0-80q-42 0-71-29t-29-71q0-42 29-71t71-29q42 0 71 29t29 71q0 42-29 71t-71 29ZM160-120q-33 0-56.5-23.5T80-200v-480q0-33 23.5-56.5T160-760h126l74-80h240l74 80h126q33 0 56.5 23.5T880-680v480q0 33-23.5 56.5T800-120H160Zm0-80h640v-480H638l-73-80H395l-73 80H160v480Zm320-240Z"/></svg>')
|
|
169
|
+
url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 -960 960 960" fill="black"><path d="M480-260q75 0 127.5-52.5T660-440q0-75-52.5-127.5T480-620q-75 0-127.5 52.5T300-440q0 75 52.5 127.5T480-260Zm0-80q-42 0-71-29t-29-71q0-42 29-71t71-29q42 0 71 29t29 71q0 42-29 71t-71 29ZM160-120q-33 0-56.5-23.5T80-200v-480q0-33 23.5-56.5T160-760h126l74-80h240l74 80h126q33 0 56.5 23.5T880-680v480q0 33-23.5 56.5T800-120H160Zm0-80h640v-480H638l-73-80H395l-73 80H160v480Zm320-240Z"/></svg>')
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/* Theme widget styles */
|
|
174
|
+
.deck-widget.deck-widget-theme button.deck-widget-sun .deck-widget-icon {
|
|
175
|
+
mask-image: var(
|
|
176
|
+
--icon-sun,
|
|
177
|
+
url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 24 24" fill="black" stroke="black"><g ><circle cx="12" cy="12" r="6" /><line x1="12" y1="1" x2="12" y2="3" /><line x1="12" y1="21" x2="12" y2="23" /><line x1="4.22" y1="4.22" x2="5.64" y2="5.64" /><line x1="18.36" y1="18.36" x2="19.78" y2="19.78" /><line x1="1" y1="12" x2="3" y2="12" /><line x1="21" y1="12" x2="23" y2="12" /><line x1="4.22" y1="19.78" x2="5.64" y2="18.36" /><line x1="18.36" y1="5.64" x2="19.78" y2="4.22" /></g></svg>')
|
|
160
178
|
);
|
|
161
179
|
}
|
|
180
|
+
|
|
181
|
+
.deck-widget.deck-widget-theme button.deck-widget-moon .deck-widget-icon {
|
|
182
|
+
mask-image: var(
|
|
183
|
+
--icon-moon,
|
|
184
|
+
url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 24 24" ><circle cx="12" cy="12" r="6" fill="black" mask="url(%23moon-mask)" /><mask id="moon-mask" viewBox="0 0 24 24" ><rect x="0" y="0" width="24" height="24" fill="white" /><circle cx="24" cy="10" r="12" fill="black"/></mask></svg>')
|
|
185
|
+
);
|
|
186
|
+
-webbit-mask-image: var(
|
|
187
|
+
--icon-moon,
|
|
188
|
+
url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 24 24"><circle x="12" cy="12" r="6" /></svg>')
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/* Reset view styles */
|
|
193
|
+
.deck-widget.deck-widget-reset-view button.deck-widget-reset-focus .deck-widget-icon {
|
|
194
|
+
mask-image: var(
|
|
195
|
+
--icon-camera,
|
|
196
|
+
url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="black"><path d="M480-320v-100q0-25 17.5-42.5T540-480h100v60H540v100h-60Zm60 240q-25 0-42.5-17.5T480-140v-100h60v100h100v60H540Zm280-240v-100H720v-60h100q25 0 42.5 17.5T880-420v100h-60ZM720-80v-60h100v-100h60v100q0 25-17.5 42.5T820-80H720Zm111-480h-83q-26-88-99-144t-169-56q-117 0-198.5 81.5T200-480q0 72 32.5 132t87.5 98v-110h80v240H160v-80h94q-62-50-98-122.5T120-480q0-75 28.5-140.5t77-114q48.5-48.5 114-77T480-840q129 0 226.5 79.5T831-560Z"/></svg>')
|
|
197
|
+
);
|
|
198
|
+
-webkit-mask-image: var(
|
|
199
|
+
--icon-camera,
|
|
200
|
+
url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="black"><path d="M480-320v-100q0-25 17.5-42.5T540-480h100v60H540v100h-60Zm60 240q-25 0-42.5-17.5T480-140v-100h60v100h100v60H540Zm280-240v-100H720v-60h100q25 0 42.5 17.5T880-420v100h-60ZM720-80v-60h100v-100h60v100q0 25-17.5 42.5T820-80H720Zm111-480h-83q-26-88-99-144t-169-56q-117 0-198.5 81.5T200-480q0 72 32.5 132t87.5 98v-110h80v240H160v-80h94q-62-50-98-122.5T120-480q0-75 28.5-140.5t77-114q48.5-48.5 114-77T480-840q129 0 226.5 79.5T831-560Z"/></svg>')
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/* Timeline widget styles */
|
|
205
|
+
.deck-widget.deck-widget-timeline {
|
|
206
|
+
display: flex;
|
|
207
|
+
align-items: center;
|
|
208
|
+
pointer-events: 'auto';
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.deck-widget.deck-widget-timeline .timeline-slider {
|
|
212
|
+
margin: 0 8px;
|
|
213
|
+
flex: 1;
|
|
214
|
+
pointer-events: 'auto';
|
|
215
|
+
cursor: pointer;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.deck-widget.deck-widget-timeline button.timeline-play-pause {
|
|
219
|
+
background: var(--button-background, #fff);
|
|
220
|
+
border: var(--button-inner-stroke, unset);
|
|
221
|
+
border-radius: var(--button-corner-radius, 4px);
|
|
222
|
+
width: var(--button-size, 28px);
|
|
223
|
+
height: var(--button-size, 28px);
|
|
224
|
+
cursor: pointer;
|
|
225
|
+
display: flex;
|
|
226
|
+
align-items: center;
|
|
227
|
+
justify-content: center;
|
|
228
|
+
padding: 0;
|
|
229
|
+
pointer-events: 'auto';
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.deck-widget-spinner-icon {
|
|
233
|
+
mask-image: var(
|
|
234
|
+
--loading-icon,
|
|
235
|
+
url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" ><path d="M21 12a9 9 0 1 1-6.219-8.56" /></svg>')
|
|
236
|
+
);
|
|
237
|
+
-webkit-mask-image: var(
|
|
238
|
+
--loading-icon,
|
|
239
|
+
url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" ><path d="M21 12a9 9 0 1 1-6.219-8.56" /></svg>')
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.deck-widget .deck-widget-scale {
|
|
244
|
+
background-color: var(--button-icon-idle, #616166);
|
|
245
|
+
background-position: 50%;
|
|
246
|
+
display: block;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.deck-widget .deck-widget-geolocate {
|
|
250
|
+
pointer-events: auto;
|
|
251
|
+
cursor: pointer;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Reusable styles for widgets
|
|
256
|
+
*/
|
|
257
|
+
.deck-widget-common {
|
|
258
|
+
font-family:
|
|
259
|
+
'SF Mono',
|
|
260
|
+
/* macOS */
|
|
261
|
+
'Menlo',
|
|
262
|
+
/* macOS */
|
|
263
|
+
'Consolas',
|
|
264
|
+
/* Windows */
|
|
265
|
+
'DejaVu Sans Mono',
|
|
266
|
+
/* Linux */
|
|
267
|
+
'Liberation Mono',
|
|
268
|
+
/* Linux */
|
|
269
|
+
monospace;
|
|
270
|
+
background-color: var(--button-background, #fff);
|
|
271
|
+
color: #333;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.deck-widget-stats-container {
|
|
275
|
+
font-size: 0.7rem;
|
|
276
|
+
/* Approximately 14px */
|
|
277
|
+
line-height: 1.6;
|
|
278
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// deck.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
import {log, _deepEqual as deepEqual, _applyStyles as applyStyles} from '@deck.gl/core';
|
|
6
|
+
import {Widget, WidgetProps, WidgetPlacement} from '@deck.gl/core';
|
|
7
|
+
import {render} from 'preact';
|
|
8
|
+
// import {useCallback} from 'preact/hooks';
|
|
9
|
+
import {IconButton} from './lib/components/icon-button';
|
|
10
|
+
import type {DeckWidgetTheme} from './themes';
|
|
11
|
+
import {LightGlassTheme, DarkGlassTheme} from './themes';
|
|
12
|
+
|
|
13
|
+
export type ThemeWidgetProps = WidgetProps & {
|
|
14
|
+
/** Widget positioning within the view. Default 'top-left'. */
|
|
15
|
+
placement?: WidgetPlacement;
|
|
16
|
+
/** Tooltip message when dark mode is selected. */
|
|
17
|
+
lightModeLabel?: string;
|
|
18
|
+
/** Styles for light mode theme */
|
|
19
|
+
lightModeTheme?: DeckWidgetTheme;
|
|
20
|
+
/** Tooltip message when light mode is selected. */
|
|
21
|
+
darkModeLabel?: string;
|
|
22
|
+
/** Styles for dark mode theme */
|
|
23
|
+
darkModeTheme?: DeckWidgetTheme;
|
|
24
|
+
/** Initial theme mode. 'auto' reads the browser default setting */
|
|
25
|
+
initialThemeMode?: 'auto' | 'light' | 'dark';
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export class ThemeWidget extends Widget<ThemeWidgetProps> {
|
|
29
|
+
static defaultProps: Required<ThemeWidgetProps> = {
|
|
30
|
+
...Widget.defaultProps,
|
|
31
|
+
id: 'theme',
|
|
32
|
+
placement: 'top-left',
|
|
33
|
+
lightModeLabel: 'Light Mode',
|
|
34
|
+
lightModeTheme: LightGlassTheme,
|
|
35
|
+
darkModeLabel: 'Dark Mode',
|
|
36
|
+
darkModeTheme: DarkGlassTheme,
|
|
37
|
+
initialThemeMode: 'auto'
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
className = 'deck-widget-theme';
|
|
41
|
+
placement: WidgetPlacement = 'top-left';
|
|
42
|
+
themeMode: 'light' | 'dark' = 'dark';
|
|
43
|
+
|
|
44
|
+
constructor(props: ThemeWidgetProps = {}) {
|
|
45
|
+
super(props, ThemeWidget.defaultProps);
|
|
46
|
+
this.placement = props.placement ?? this.placement;
|
|
47
|
+
this.themeMode = this._getInitialThemeMode();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// eslint-disable-next-line complexity
|
|
51
|
+
setProps(props: Partial<ThemeWidgetProps>) {
|
|
52
|
+
const {lightModeTheme, darkModeTheme} = this.props;
|
|
53
|
+
this.placement = props.placement ?? this.placement;
|
|
54
|
+
super.setProps(props);
|
|
55
|
+
|
|
56
|
+
// Update if current theme definition changed
|
|
57
|
+
switch (this.themeMode) {
|
|
58
|
+
case 'light':
|
|
59
|
+
if (props.lightModeTheme && !deepEqual(props.lightModeTheme, lightModeTheme, 1)) {
|
|
60
|
+
this._setThemeMode('light');
|
|
61
|
+
}
|
|
62
|
+
break;
|
|
63
|
+
case 'dark':
|
|
64
|
+
if (props.darkModeTheme && !deepEqual(props.darkModeTheme, darkModeTheme, 1)) {
|
|
65
|
+
this._setThemeMode('dark');
|
|
66
|
+
}
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
onRenderHTML(rootElement: HTMLElement): void {
|
|
72
|
+
const {lightModeLabel, darkModeLabel} = this.props;
|
|
73
|
+
// const onClick = useCallback(this._handleClick.bind(this), [this._handleClick]);
|
|
74
|
+
|
|
75
|
+
render(
|
|
76
|
+
<IconButton
|
|
77
|
+
onClick={this._handleClick.bind(this)}
|
|
78
|
+
label={this.themeMode === 'dark' ? darkModeLabel : lightModeLabel}
|
|
79
|
+
className={this.themeMode === 'dark' ? 'deck-widget-moon' : 'deck-widget-sun'}
|
|
80
|
+
/>,
|
|
81
|
+
rootElement
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
onAdd() {
|
|
86
|
+
// Note: theme styling is applied in here onAdd() once DOM element is created
|
|
87
|
+
this._setThemeMode(this.themeMode);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
_handleClick() {
|
|
91
|
+
const newThemeMode = this.themeMode === 'dark' ? 'light' : 'dark';
|
|
92
|
+
this._setThemeMode(newThemeMode);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
_setThemeMode(themeMode: 'light' | 'dark') {
|
|
96
|
+
this.themeMode = themeMode;
|
|
97
|
+
const container = this.rootElement?.closest<HTMLDivElement>('.deck-widget-container');
|
|
98
|
+
if (container) {
|
|
99
|
+
const themeStyle =
|
|
100
|
+
themeMode === 'dark' ? this.props.darkModeTheme : this.props.lightModeTheme;
|
|
101
|
+
applyStyles(container, themeStyle);
|
|
102
|
+
|
|
103
|
+
const label =
|
|
104
|
+
this.themeMode === 'dark' ? this.props.darkModeLabel : this.props.lightModeLabel;
|
|
105
|
+
log.log(1, `Switched theme to ${label}`, themeStyle);
|
|
106
|
+
|
|
107
|
+
this.updateHTML();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Read browser preference */
|
|
112
|
+
_getInitialThemeMode(): 'light' | 'dark' {
|
|
113
|
+
const {initialThemeMode} = this.props;
|
|
114
|
+
return initialThemeMode === 'auto'
|
|
115
|
+
? window.matchMedia('(prefers-color-scheme: dark)').matches
|
|
116
|
+
? 'dark'
|
|
117
|
+
: 'light'
|
|
118
|
+
: initialThemeMode;
|
|
119
|
+
}
|
|
120
|
+
}
|
package/src/themes.ts
CHANGED
|
@@ -2,7 +2,31 @@
|
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* A Deck Theme is a set of CSS variables that control CSS styling of the official widgets.
|
|
7
|
+
*/
|
|
8
|
+
export type DeckWidgetTheme = {
|
|
9
|
+
// layout
|
|
10
|
+
'--widget-margin'?: string;
|
|
11
|
+
// button and button group
|
|
12
|
+
'--button-size'?: string;
|
|
13
|
+
'--button-corner-radius'?: string;
|
|
14
|
+
'--button-background'?: string;
|
|
15
|
+
'--button-stroke'?: string;
|
|
16
|
+
'--button-inner-stroke'?: string;
|
|
17
|
+
'--button-shadow'?: string;
|
|
18
|
+
'--button-backdrop-filter'?: string;
|
|
19
|
+
'--button-icon-idle'?: string;
|
|
20
|
+
'--button-icon-hover'?: string;
|
|
21
|
+
// inter-icon color
|
|
22
|
+
'--icon-compass-north-color'?: string;
|
|
23
|
+
'--icon-compass-south-color'?: string;
|
|
24
|
+
};
|
|
25
|
+
|
|
5
26
|
export const LightTheme = {
|
|
27
|
+
'--widget-margin': '12px',
|
|
28
|
+
'--button-size': '28px',
|
|
29
|
+
'--button-corner-radius': '8px',
|
|
6
30
|
'--button-background': '#fff',
|
|
7
31
|
'--button-stroke': 'rgba(255, 255, 255, 0.3)',
|
|
8
32
|
'--button-inner-stroke': 'unset',
|
|
@@ -10,11 +34,14 @@ export const LightTheme = {
|
|
|
10
34
|
'--button-backdrop-filter': 'unset',
|
|
11
35
|
'--button-icon-idle': 'rgba(97, 97, 102, 1)',
|
|
12
36
|
'--button-icon-hover': 'rgba(24, 24, 26, 1)',
|
|
13
|
-
'--icon-compass-north-color': '
|
|
14
|
-
'--icon-compass-south-color': '
|
|
15
|
-
}
|
|
37
|
+
'--icon-compass-north-color': 'rgb(240, 92, 68)',
|
|
38
|
+
'--icon-compass-south-color': 'rgb(204, 204, 204)'
|
|
39
|
+
} as const satisfies Required<DeckWidgetTheme>;
|
|
16
40
|
|
|
17
41
|
export const DarkTheme = {
|
|
42
|
+
'--widget-margin': '12px',
|
|
43
|
+
'--button-size': '28px',
|
|
44
|
+
'--button-corner-radius': '8px',
|
|
18
45
|
'--button-background': 'rgba(18, 18, 20, 1)',
|
|
19
46
|
'--button-stroke': 'rgba(18, 18, 20, 0.30)',
|
|
20
47
|
'--button-inner-stroke': 'unset',
|
|
@@ -22,11 +49,14 @@ export const DarkTheme = {
|
|
|
22
49
|
'--button-backdrop-filter': 'unset',
|
|
23
50
|
'--button-icon-idle': 'rgba(158, 157, 168, 1)',
|
|
24
51
|
'--button-icon-hover': 'rgba(215, 214, 229, 1)',
|
|
25
|
-
'--icon-compass-north-color': '
|
|
26
|
-
'--icon-compass-south-color': '
|
|
27
|
-
}
|
|
52
|
+
'--icon-compass-north-color': 'rgb(240, 92, 68)',
|
|
53
|
+
'--icon-compass-south-color': 'rgb(200, 199, 209)'
|
|
54
|
+
} as const satisfies Required<DeckWidgetTheme>;
|
|
28
55
|
|
|
29
56
|
export const LightGlassTheme = {
|
|
57
|
+
'--widget-margin': '12px',
|
|
58
|
+
'--button-size': '28px',
|
|
59
|
+
'--button-corner-radius': '8px',
|
|
30
60
|
'--button-background': 'rgba(255, 255, 255, 0.6)',
|
|
31
61
|
'--button-stroke': 'rgba(255, 255, 255, 0.3)',
|
|
32
62
|
'--button-inner-stroke': '1px solid rgba(255, 255, 255, 0.6)',
|
|
@@ -35,11 +65,14 @@ export const LightGlassTheme = {
|
|
|
35
65
|
'--button-backdrop-filter': 'blur(4px)',
|
|
36
66
|
'--button-icon-idle': 'rgba(97, 97, 102, 1)',
|
|
37
67
|
'--button-icon-hover': 'rgba(24, 24, 26, 1)',
|
|
38
|
-
'--icon-compass-north-color': '
|
|
39
|
-
'--icon-compass-south-color': '
|
|
40
|
-
}
|
|
68
|
+
'--icon-compass-north-color': 'rgb(240, 92, 68)',
|
|
69
|
+
'--icon-compass-south-color': 'rgb(204, 204, 204)'
|
|
70
|
+
} as const satisfies Required<DeckWidgetTheme>;
|
|
41
71
|
|
|
42
72
|
export const DarkGlassTheme = {
|
|
73
|
+
'--widget-margin': '12px',
|
|
74
|
+
'--button-size': '28px',
|
|
75
|
+
'--button-corner-radius': '8px',
|
|
43
76
|
'--button-background': 'rgba(18, 18, 20, 0.75)',
|
|
44
77
|
'--button-stroke': 'rgba(18, 18, 20, 0.30)',
|
|
45
78
|
'--button-inner-stroke': '1px solid rgba(18, 18, 20, 0.75)',
|
|
@@ -48,6 +81,6 @@ export const DarkGlassTheme = {
|
|
|
48
81
|
'--button-backdrop-filter': 'blur(4px)',
|
|
49
82
|
'--button-icon-idle': 'rgba(158, 157, 168, 1)',
|
|
50
83
|
'--button-icon-hover': 'rgba(215, 214, 229, 1)',
|
|
51
|
-
'--icon-compass-north-color': '
|
|
52
|
-
'--icon-compass-south-color': '
|
|
53
|
-
}
|
|
84
|
+
'--icon-compass-north-color': 'rgb(240, 92, 68)',
|
|
85
|
+
'--icon-compass-south-color': 'rgb(200, 199, 209)'
|
|
86
|
+
} as const satisfies Required<DeckWidgetTheme>;
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
// deck.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
import {Widget, type WidgetPlacement} from '@deck.gl/core';
|
|
6
|
+
import {render} from 'preact';
|
|
7
|
+
|
|
8
|
+
export type TimelineWidgetProps = {
|
|
9
|
+
/**
|
|
10
|
+
* Widget id
|
|
11
|
+
*/
|
|
12
|
+
id?: string;
|
|
13
|
+
/**
|
|
14
|
+
* CSS inline style overrides.
|
|
15
|
+
*/
|
|
16
|
+
style?: Partial<CSSStyleDeclaration>;
|
|
17
|
+
/**
|
|
18
|
+
* Additional CSS class.
|
|
19
|
+
*/
|
|
20
|
+
className?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Widget placement.
|
|
23
|
+
*/
|
|
24
|
+
placement?: WidgetPlacement;
|
|
25
|
+
/**
|
|
26
|
+
* Slider timeRange [min, max].
|
|
27
|
+
*/
|
|
28
|
+
timeRange?: [number, number];
|
|
29
|
+
/**
|
|
30
|
+
* Slider step.
|
|
31
|
+
*/
|
|
32
|
+
step?: number;
|
|
33
|
+
/**
|
|
34
|
+
* Initial slider value.
|
|
35
|
+
*/
|
|
36
|
+
initialTime?: number;
|
|
37
|
+
/**
|
|
38
|
+
* Callback when value changes.
|
|
39
|
+
*/
|
|
40
|
+
onTimeChange?: (value: number) => void;
|
|
41
|
+
/**
|
|
42
|
+
* Play interval in milliseconds.
|
|
43
|
+
*/
|
|
44
|
+
playInterval?: number;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export class TimelineWidget extends Widget<TimelineWidgetProps> {
|
|
48
|
+
id = 'timeline';
|
|
49
|
+
className = 'deck-widget-timeline';
|
|
50
|
+
placement: WidgetPlacement = 'bottom-left';
|
|
51
|
+
|
|
52
|
+
private playing = false;
|
|
53
|
+
private timerId: number | null = null;
|
|
54
|
+
currentTime: number;
|
|
55
|
+
|
|
56
|
+
static defaultProps: Required<TimelineWidgetProps> = {
|
|
57
|
+
...Widget.defaultProps,
|
|
58
|
+
id: 'timeline',
|
|
59
|
+
placement: 'bottom-left' as const,
|
|
60
|
+
timeRange: [0, 100],
|
|
61
|
+
step: 1,
|
|
62
|
+
initialTime: undefined!,
|
|
63
|
+
onTimeChange: () => {},
|
|
64
|
+
playInterval: 1000
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
constructor(props: TimelineWidgetProps = {}) {
|
|
68
|
+
super(props, TimelineWidget.defaultProps);
|
|
69
|
+
this.currentTime = this.props.initialTime ?? this.props.timeRange[0];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
setProps(props: Partial<TimelineWidgetProps>): void {
|
|
73
|
+
this.placement = props.placement || this.placement;
|
|
74
|
+
super.setProps(props);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
onAdd(): void {
|
|
78
|
+
this.playing = false;
|
|
79
|
+
this.timerId = null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
onRemove(): void {
|
|
83
|
+
this.stop();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
onRenderHTML(rootElement: HTMLElement): void {
|
|
87
|
+
render(
|
|
88
|
+
<div style={{display: 'flex', alignItems: 'center', pointerEvents: 'auto'}}>
|
|
89
|
+
<button
|
|
90
|
+
type="button"
|
|
91
|
+
className="timeline-play-pause"
|
|
92
|
+
title={this.playing ? 'Pause' : 'Play'}
|
|
93
|
+
onClick={this.handlePlayPause}
|
|
94
|
+
>
|
|
95
|
+
{this.playing ? '⏸' : '▶'}
|
|
96
|
+
</button>
|
|
97
|
+
<input
|
|
98
|
+
type="range"
|
|
99
|
+
className="timeline-slider"
|
|
100
|
+
min={this.props.timeRange[0]}
|
|
101
|
+
max={this.props.timeRange[1]}
|
|
102
|
+
step={this.props.step}
|
|
103
|
+
value={this.currentTime}
|
|
104
|
+
onInput={this.handleSliderChange}
|
|
105
|
+
/>
|
|
106
|
+
</div>,
|
|
107
|
+
rootElement
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private handlePlayPause = (): void => {
|
|
112
|
+
if (this.playing) {
|
|
113
|
+
this.stop();
|
|
114
|
+
} else {
|
|
115
|
+
this.start();
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
private handleSliderChange = (e: Event): void => {
|
|
120
|
+
const input = e.target as HTMLInputElement;
|
|
121
|
+
const val = Number(input.value);
|
|
122
|
+
this.currentTime = val;
|
|
123
|
+
this.props.onTimeChange(val);
|
|
124
|
+
this.updateHTML();
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
private start(): void {
|
|
128
|
+
this.playing = true;
|
|
129
|
+
this.updateHTML();
|
|
130
|
+
this.tick();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
private stop(): void {
|
|
134
|
+
this.playing = false;
|
|
135
|
+
if (this.timerId !== null) {
|
|
136
|
+
window.clearTimeout(this.timerId);
|
|
137
|
+
this.timerId = null;
|
|
138
|
+
}
|
|
139
|
+
this.updateHTML();
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
private tick = (): void => {
|
|
143
|
+
const [min, max] = this.props.timeRange;
|
|
144
|
+
let next = this.currentTime + this.props.step;
|
|
145
|
+
if (next > max) {
|
|
146
|
+
next = min;
|
|
147
|
+
}
|
|
148
|
+
this.currentTime = next;
|
|
149
|
+
this.props.onTimeChange(next);
|
|
150
|
+
this.updateHTML();
|
|
151
|
+
if (this.playing) {
|
|
152
|
+
this.timerId = window.setTimeout(this.tick, this.props.playInterval);
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// ViewSelectorWidget.tsx
|
|
2
|
+
// deck.gl
|
|
3
|
+
// SPDX-License-Identifier: MIT
|
|
4
|
+
// Copyright (c) vis.gl contributors
|
|
5
|
+
|
|
6
|
+
import {render, JSX} from 'preact';
|
|
7
|
+
import {Widget, type WidgetProps, type WidgetPlacement} from '@deck.gl/core';
|
|
8
|
+
import {IconMenu} from './lib/components/icon-menu';
|
|
9
|
+
|
|
10
|
+
/** The available view modes */
|
|
11
|
+
export type ViewMode = 'single' | 'split-horizontal' | 'split-vertical';
|
|
12
|
+
|
|
13
|
+
/** Properties for the ViewSelectorWidget */
|
|
14
|
+
export type ViewSelectorWidgetProps = WidgetProps & {
|
|
15
|
+
/** Widget positioning within the view. Default 'top-left'. */
|
|
16
|
+
placement?: WidgetPlacement;
|
|
17
|
+
/** Tooltip label */
|
|
18
|
+
label?: string;
|
|
19
|
+
/** The initial view mode. Defaults to 'single'. */
|
|
20
|
+
initialViewMode?: ViewMode;
|
|
21
|
+
/** Callback invoked when the view mode changes */
|
|
22
|
+
onViewModeChange?: (mode: ViewMode) => void;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* A widget that renders a popup menu for selecting a view mode.
|
|
27
|
+
* It displays a button with the current view mode icon. Clicking the button
|
|
28
|
+
* toggles a popup that shows three icons for:
|
|
29
|
+
* - Single view
|
|
30
|
+
* - Two views, split horizontally
|
|
31
|
+
* - Two views, split vertically
|
|
32
|
+
*/
|
|
33
|
+
export class ViewSelectorWidget extends Widget<ViewSelectorWidgetProps> {
|
|
34
|
+
static defaultProps: Required<ViewSelectorWidgetProps> = {
|
|
35
|
+
...Widget.defaultProps,
|
|
36
|
+
id: 'view-selector-widget',
|
|
37
|
+
placement: 'top-left',
|
|
38
|
+
label: 'Split View',
|
|
39
|
+
initialViewMode: 'single',
|
|
40
|
+
onViewModeChange: (viewMode: string) => {
|
|
41
|
+
// eslint-disable-next-line no-console
|
|
42
|
+
console.log(viewMode);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
className = 'deck-widget-view-selector';
|
|
47
|
+
placement: WidgetPlacement = 'top-left';
|
|
48
|
+
viewMode: ViewMode;
|
|
49
|
+
|
|
50
|
+
constructor(props: ViewSelectorWidgetProps = {}) {
|
|
51
|
+
super(props, ViewSelectorWidget.defaultProps);
|
|
52
|
+
this.placement = this.props.placement;
|
|
53
|
+
this.viewMode = this.props.initialViewMode;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
setProps(props: Partial<ViewSelectorWidgetProps>) {
|
|
57
|
+
super.setProps(props);
|
|
58
|
+
this.placement = props.placement ?? this.placement;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
onRenderHTML(rootElement: HTMLElement) {
|
|
62
|
+
render(
|
|
63
|
+
<IconMenu<ViewMode>
|
|
64
|
+
className="deck-widget-view-selector"
|
|
65
|
+
menuItems={MENU_ITEMS}
|
|
66
|
+
initialItem={this.props.initialViewMode}
|
|
67
|
+
onItemSelected={this.handleSelectMode}
|
|
68
|
+
/>,
|
|
69
|
+
rootElement
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
handleSelectMode = (viewMode: ViewMode) => {
|
|
74
|
+
this.viewMode = viewMode;
|
|
75
|
+
this.updateHTML();
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Define common icon style.
|
|
80
|
+
const ICON_STYLE = {width: '24px', height: '24px'};
|
|
81
|
+
|
|
82
|
+
// Define inline SVG icons for each view mode.
|
|
83
|
+
const ICONS: Record<ViewMode, () => JSX.Element> = {
|
|
84
|
+
single: () => (
|
|
85
|
+
<svg width="24" height="24" style={ICON_STYLE}>
|
|
86
|
+
<rect x="4" y="4" width="16" height="16" stroke="black" fill="none" strokeWidth="2" />
|
|
87
|
+
</svg>
|
|
88
|
+
),
|
|
89
|
+
'split-horizontal': () => (
|
|
90
|
+
<svg width="24" height="24" style={ICON_STYLE}>
|
|
91
|
+
<rect x="4" y="4" width="16" height="7" stroke="black" fill="none" strokeWidth="2" />
|
|
92
|
+
<rect x="4" y="13" width="16" height="7" stroke="black" fill="none" strokeWidth="2" />
|
|
93
|
+
</svg>
|
|
94
|
+
),
|
|
95
|
+
'split-vertical': () => (
|
|
96
|
+
<svg width="24" height="24" style={ICON_STYLE}>
|
|
97
|
+
<rect x="4" y="4" width="7" height="16" stroke="black" fill="none" strokeWidth="2" />
|
|
98
|
+
<rect x="13" y="4" width="7" height="16" stroke="black" fill="none" strokeWidth="2" />
|
|
99
|
+
</svg>
|
|
100
|
+
)
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// Define menu items for the popup menu.
|
|
104
|
+
const MENU_ITEMS: Array<{value: ViewMode; icon: () => JSX.Element; label: string}> = [
|
|
105
|
+
{value: 'single', icon: ICONS.single, label: 'Single View'},
|
|
106
|
+
{value: 'split-horizontal', icon: ICONS['split-horizontal'], label: 'Split Horizontal'},
|
|
107
|
+
{value: 'split-vertical', icon: ICONS['split-vertical'], label: 'Split Vertical'}
|
|
108
|
+
];
|