@deck.gl/widgets 9.2.11 → 9.3.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.
Files changed (152) hide show
  1. package/dist/compass-widget.js +5 -5
  2. package/dist/compass-widget.js.map +1 -1
  3. package/dist/context-menu-widget.d.ts +27 -20
  4. package/dist/context-menu-widget.d.ts.map +1 -1
  5. package/dist/context-menu-widget.js +45 -48
  6. package/dist/context-menu-widget.js.map +1 -1
  7. package/dist/dist.dev.js +3114 -869
  8. package/dist/fullscreen-widget.js +1 -1
  9. package/dist/fullscreen-widget.js.map +1 -1
  10. package/dist/geocoder-widget.d.ts +2 -4
  11. package/dist/geocoder-widget.d.ts.map +1 -1
  12. package/dist/geocoder-widget.js +16 -20
  13. package/dist/geocoder-widget.js.map +1 -1
  14. package/dist/gimbal-widget.d.ts +0 -3
  15. package/dist/gimbal-widget.d.ts.map +1 -1
  16. package/dist/gimbal-widget.js +4 -22
  17. package/dist/gimbal-widget.js.map +1 -1
  18. package/dist/icon-widget.d.ts +28 -0
  19. package/dist/icon-widget.d.ts.map +1 -0
  20. package/dist/icon-widget.js +35 -0
  21. package/dist/icon-widget.js.map +1 -0
  22. package/dist/index.cjs +1271 -561
  23. package/dist/index.cjs.map +4 -4
  24. package/dist/index.d.ts +16 -12
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +11 -10
  27. package/dist/index.js.map +1 -1
  28. package/dist/info-widget.d.ts +39 -17
  29. package/dist/info-widget.d.ts.map +1 -1
  30. package/dist/info-widget.js +46 -130
  31. package/dist/info-widget.js.map +1 -1
  32. package/dist/lib/components/dropdown-menu.d.ts +12 -5
  33. package/dist/lib/components/dropdown-menu.d.ts.map +1 -1
  34. package/dist/lib/components/dropdown-menu.js +20 -11
  35. package/dist/lib/components/dropdown-menu.js.map +1 -1
  36. package/dist/lib/components/icon-button.d.ts +3 -0
  37. package/dist/lib/components/icon-button.d.ts.map +1 -1
  38. package/dist/lib/components/icon-button.js +10 -2
  39. package/dist/lib/components/icon-button.js.map +1 -1
  40. package/dist/lib/components/popover.d.ts +30 -0
  41. package/dist/lib/components/popover.d.ts.map +1 -0
  42. package/dist/lib/components/popover.js +93 -0
  43. package/dist/lib/components/popover.js.map +1 -0
  44. package/dist/lib/components/range-input.d.ts +26 -0
  45. package/dist/lib/components/range-input.d.ts.map +1 -0
  46. package/dist/lib/components/range-input.js +261 -0
  47. package/dist/lib/components/range-input.js.map +1 -0
  48. package/dist/lib/components/user-content.d.ts +8 -0
  49. package/dist/lib/components/user-content.d.ts.map +1 -0
  50. package/dist/lib/components/user-content.js +15 -0
  51. package/dist/lib/components/user-content.js.map +1 -0
  52. package/dist/lib/data-url.d.ts +5 -0
  53. package/dist/lib/data-url.d.ts.map +1 -0
  54. package/dist/lib/data-url.js +7 -0
  55. package/dist/lib/data-url.js.map +1 -0
  56. package/dist/popup-widget.d.ts +64 -0
  57. package/dist/popup-widget.d.ts.map +1 -0
  58. package/dist/popup-widget.js +76 -0
  59. package/dist/popup-widget.js.map +1 -0
  60. package/dist/reset-view-widget.d.ts +1 -1
  61. package/dist/reset-view-widget.d.ts.map +1 -1
  62. package/dist/reset-view-widget.js +12 -11
  63. package/dist/reset-view-widget.js.map +1 -1
  64. package/dist/scrollbar-widget.d.ts +68 -0
  65. package/dist/scrollbar-widget.d.ts.map +1 -0
  66. package/dist/scrollbar-widget.js +181 -0
  67. package/dist/scrollbar-widget.js.map +1 -0
  68. package/dist/selector-widget.d.ts +44 -0
  69. package/dist/selector-widget.d.ts.map +1 -0
  70. package/dist/selector-widget.js +64 -0
  71. package/dist/selector-widget.js.map +1 -0
  72. package/dist/splitter-widget.d.ts +52 -11
  73. package/dist/splitter-widget.d.ts.map +1 -1
  74. package/dist/splitter-widget.js +177 -76
  75. package/dist/splitter-widget.js.map +1 -1
  76. package/dist/stats-widget.d.ts +6 -1
  77. package/dist/stats-widget.d.ts.map +1 -1
  78. package/dist/stats-widget.js +39 -10
  79. package/dist/stats-widget.js.map +1 -1
  80. package/dist/stylesheet.css +291 -39
  81. package/dist/theme-widget.d.ts.map +1 -1
  82. package/dist/theme-widget.js +7 -5
  83. package/dist/theme-widget.js.map +1 -1
  84. package/dist/themes.d.ts +30 -0
  85. package/dist/themes.d.ts.map +1 -1
  86. package/dist/themes.js +28 -4
  87. package/dist/themes.js.map +1 -1
  88. package/dist/timeline-widget.d.ts +25 -6
  89. package/dist/timeline-widget.d.ts.map +1 -1
  90. package/dist/timeline-widget.js +51 -18
  91. package/dist/timeline-widget.js.map +1 -1
  92. package/dist/toggle-widget.d.ts +38 -0
  93. package/dist/toggle-widget.d.ts.map +1 -0
  94. package/dist/toggle-widget.js +47 -0
  95. package/dist/toggle-widget.js.map +1 -0
  96. package/dist/zoom-widget.d.ts +2 -8
  97. package/dist/zoom-widget.d.ts.map +1 -1
  98. package/dist/zoom-widget.js +23 -18
  99. package/dist/zoom-widget.js.map +1 -1
  100. package/dist.min.js +2 -2
  101. package/package.json +4 -3
  102. package/src/compass-widget.tsx +5 -5
  103. package/src/context-menu-widget.tsx +88 -78
  104. package/src/fullscreen-widget.tsx +1 -1
  105. package/src/geocoder-widget.tsx +17 -24
  106. package/src/gimbal-widget.tsx +4 -26
  107. package/src/icon-widget.tsx +69 -0
  108. package/src/index.ts +22 -15
  109. package/src/info-widget.tsx +100 -157
  110. package/src/lib/components/dropdown-menu.tsx +58 -29
  111. package/src/lib/components/icon-button.tsx +15 -3
  112. package/src/lib/components/popover.tsx +167 -0
  113. package/src/lib/components/range-input.tsx +432 -0
  114. package/src/lib/components/user-content.tsx +30 -0
  115. package/src/lib/data-url.ts +5 -0
  116. package/src/popup-widget.tsx +170 -0
  117. package/src/reset-view-widget.tsx +12 -11
  118. package/src/scrollbar-widget.tsx +288 -0
  119. package/src/selector-widget.tsx +111 -0
  120. package/src/splitter-widget.tsx +281 -96
  121. package/src/stats-widget.tsx +59 -12
  122. package/src/stylesheet.css +291 -39
  123. package/src/theme-widget.tsx +7 -5
  124. package/src/themes.ts +35 -4
  125. package/src/timeline-widget.tsx +103 -33
  126. package/src/toggle-widget.tsx +101 -0
  127. package/src/zoom-widget.tsx +25 -21
  128. package/dist/fps-widget.d.ts +0 -28
  129. package/dist/fps-widget.d.ts.map +0 -1
  130. package/dist/fps-widget.js +0 -51
  131. package/dist/fps-widget.js.map +0 -1
  132. package/dist/lib/components/grouped-icon-button.d.ts +0 -10
  133. package/dist/lib/components/grouped-icon-button.d.ts.map +0 -1
  134. package/dist/lib/components/grouped-icon-button.js +0 -7
  135. package/dist/lib/components/grouped-icon-button.js.map +0 -1
  136. package/dist/lib/components/icon-menu.d.ts +0 -16
  137. package/dist/lib/components/icon-menu.d.ts.map +0 -1
  138. package/dist/lib/components/icon-menu.js +0 -34
  139. package/dist/lib/components/icon-menu.js.map +0 -1
  140. package/dist/lib/components/simple-menu.d.ts +0 -16
  141. package/dist/lib/components/simple-menu.d.ts.map +0 -1
  142. package/dist/lib/components/simple-menu.js +0 -30
  143. package/dist/lib/components/simple-menu.js.map +0 -1
  144. package/dist/view-selector-widget.d.ts +0 -35
  145. package/dist/view-selector-widget.d.ts.map +0 -1
  146. package/dist/view-selector-widget.js +0 -63
  147. package/dist/view-selector-widget.js.map +0 -1
  148. package/src/fps-widget.tsx +0 -77
  149. package/src/lib/components/grouped-icon-button.tsx +0 -27
  150. package/src/lib/components/icon-menu.tsx +0 -71
  151. package/src/lib/components/simple-menu.tsx +0 -52
  152. package/src/view-selector-widget.tsx +0 -151
package/dist/index.cjs CHANGED
@@ -21,37 +21,39 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var dist_exports = {};
22
22
  __export(dist_exports, {
23
23
  CompassWidget: () => CompassWidget,
24
+ ContextMenuWidget: () => ContextMenuWidget,
24
25
  DarkGlassTheme: () => DarkGlassTheme,
25
26
  DarkTheme: () => DarkTheme,
26
27
  FullscreenWidget: () => FullscreenWidget,
27
28
  GimbalWidget: () => GimbalWidget,
29
+ IconWidget: () => IconWidget,
30
+ InfoWidget: () => InfoWidget,
28
31
  LightGlassTheme: () => LightGlassTheme,
29
32
  LightTheme: () => LightTheme,
33
+ LoadingWidget: () => LoadingWidget,
34
+ PopupWidget: () => PopupWidget,
30
35
  ResetViewWidget: () => ResetViewWidget,
31
36
  ScreenshotWidget: () => ScreenshotWidget,
37
+ ScrollbarWidget: () => ScrollbarWidget,
38
+ SelectorWidget: () => SelectorWidget,
39
+ ThemeWidget: () => ThemeWidget,
40
+ ToggleWidget: () => ToggleWidget,
32
41
  ZoomWidget: () => ZoomWidget,
33
42
  _ButtonGroup: () => ButtonGroup,
34
- _ContextMenuWidget: () => ContextMenuWidget,
35
43
  _CoordinatesGeocoder: () => CoordinatesGeocoder,
36
44
  _CurrentLocationGeocoder: () => CurrentLocationGeocoder,
37
45
  _DropdownMenu: () => DropdownMenu,
38
- _FpsWidget: () => FpsWidget,
39
46
  _GeocoderWidget: () => GeocoderWidget,
40
47
  _GoogleGeocoder: () => GoogleGeocoder,
41
- _GroupedIconButton: () => GroupedIconButton,
42
48
  _IconButton: () => IconButton,
43
- _IconMenu: () => IconMenu,
44
- _InfoWidget: () => InfoWidget,
45
- _LoadingWidget: () => LoadingWidget,
46
49
  _MapboxGeocoder: () => MapboxGeocoder,
47
50
  _OpenCageGeocoder: () => OpenCageGeocoder,
51
+ _RangeInput: () => RangeInput,
48
52
  _ScaleWidget: () => ScaleWidget,
49
53
  _SimpleMenu: () => SimpleMenu,
50
54
  _SplitterWidget: () => SplitterWidget,
51
55
  _StatsWidget: () => StatsWidget,
52
- _ThemeWidget: () => ThemeWidget,
53
- _TimelineWidget: () => TimelineWidget,
54
- _ViewSelectorWidget: () => ViewSelectorWidget
56
+ _TimelineWidget: () => TimelineWidget
55
57
  });
56
58
  module.exports = __toCommonJS(dist_exports);
57
59
 
@@ -67,11 +69,28 @@ var ButtonGroup = (props) => {
67
69
  return (0, import_jsx_runtime.jsx)("div", { className: `deck-widget-button-group ${orientation}`, children });
68
70
  };
69
71
 
70
- // dist/lib/components/grouped-icon-button.js
72
+ // dist/lib/components/icon-button.js
71
73
  var import_jsx_runtime2 = require("preact/jsx-runtime");
72
- var GroupedIconButton = (props) => {
73
- const { className = "", label, onClick, children } = props;
74
- return (0, import_jsx_runtime2.jsx)("button", { className: `deck-widget-icon-button ${className}`, type: "button", onClick, title: label, children: children ? children : (0, import_jsx_runtime2.jsx)("div", { className: "deck-widget-icon" }) });
74
+ var import_hooks = require("preact/hooks");
75
+
76
+ // dist/lib/data-url.js
77
+ function getCSSMask(imageUrl) {
78
+ if (!imageUrl)
79
+ return void 0;
80
+ const cssUrl = `url("${imageUrl.replace(/"/g, `'`)}")`;
81
+ return { maskImage: cssUrl, WebkitMaskImage: cssUrl };
82
+ }
83
+
84
+ // dist/lib/components/icon-button.js
85
+ var IconButton = (props) => {
86
+ const { className = "", style, color, icon, label, onClick, children } = props;
87
+ const iconStyle = (0, import_hooks.useMemo)(() => {
88
+ const css = getCSSMask(icon);
89
+ if (!color)
90
+ return css;
91
+ return { ...css, backgroundColor: color };
92
+ }, [color, icon]);
93
+ return (0, import_jsx_runtime2.jsx)("div", { className: "deck-widget-button", style, children: (0, import_jsx_runtime2.jsx)("button", { className: `deck-widget-icon-button ${className}`, type: "button", onClick, title: label, children: children ? children : (0, import_jsx_runtime2.jsx)("div", { className: "deck-widget-icon", style: iconStyle }) }) });
75
94
  };
76
95
 
77
96
  // dist/zoom-widget.js
@@ -80,7 +99,6 @@ var ZoomWidget = class extends import_core.Widget {
80
99
  super(props);
81
100
  this.className = "deck-widget-zoom";
82
101
  this.placement = "top-left";
83
- this.viewports = {};
84
102
  this.setProps(this.props);
85
103
  }
86
104
  setProps(props) {
@@ -89,16 +107,22 @@ var ZoomWidget = class extends import_core.Widget {
89
107
  super.setProps(props);
90
108
  }
91
109
  onRenderHTML(rootElement) {
92
- const ui = (0, import_jsx_runtime3.jsxs)(ButtonGroup, { orientation: this.props.orientation, children: [(0, import_jsx_runtime3.jsx)(GroupedIconButton, { onClick: () => this.handleZoomIn(), label: this.props.zoomInLabel, className: "deck-widget-zoom-in" }), (0, import_jsx_runtime3.jsx)(GroupedIconButton, { onClick: () => this.handleZoomOut(), label: this.props.zoomOutLabel, className: "deck-widget-zoom-out" })] });
110
+ const ui = (0, import_jsx_runtime3.jsxs)(ButtonGroup, { orientation: this.props.orientation, children: [(0, import_jsx_runtime3.jsx)(IconButton, { onClick: () => this.handleZoomIn(), label: this.props.zoomInLabel, className: "deck-widget-zoom-in" }), (0, import_jsx_runtime3.jsx)(IconButton, { onClick: () => this.handleZoomOut(), label: this.props.zoomOutLabel, className: "deck-widget-zoom-out" })] });
93
111
  (0, import_preact.render)(ui, rootElement);
94
112
  }
95
- onViewportChange(viewport) {
96
- this.viewports[viewport.id] = viewport;
97
- }
98
- handleZoom(viewport, nextZoom) {
99
- const viewId = this.viewId || (viewport == null ? void 0 : viewport.id) || "default-view";
113
+ handleZoom(viewId, nextZoom) {
114
+ const viewState = this.getViewState(viewId);
115
+ if (viewState) {
116
+ const { minZoom, maxZoom } = viewState;
117
+ if (Number.isFinite(minZoom)) {
118
+ nextZoom = Math.max(minZoom, nextZoom);
119
+ }
120
+ if (Number.isFinite(maxZoom)) {
121
+ nextZoom = Math.min(maxZoom, nextZoom);
122
+ }
123
+ }
100
124
  const nextViewState = {
101
- ...viewport,
125
+ ...viewState,
102
126
  zoom: nextZoom
103
127
  };
104
128
  if (this.props.transitionDuration > 0) {
@@ -110,19 +134,21 @@ var ZoomWidget = class extends import_core.Widget {
110
134
  this.setViewState(viewId, nextViewState);
111
135
  }
112
136
  handleZoomIn() {
113
- for (const viewport of Object.values(this.viewports)) {
114
- this.handleZoom(viewport, viewport.zoom + 1);
137
+ var _a;
138
+ const viewIds = this.viewId ? [this.viewId] : ((_a = this.deck) == null ? void 0 : _a.getViews().map((v) => v.id)) ?? [];
139
+ for (const viewId of viewIds) {
140
+ const viewState = this.getViewState(viewId);
141
+ this.handleZoom(viewId, viewState.zoom + 1);
115
142
  }
116
143
  }
117
144
  handleZoomOut() {
118
- for (const viewport of Object.values(this.viewports)) {
119
- this.handleZoom(viewport, viewport.zoom - 1);
145
+ var _a;
146
+ const viewIds = this.viewId ? [this.viewId] : ((_a = this.deck) == null ? void 0 : _a.getViews().map((v) => v.id)) ?? [];
147
+ for (const viewId of viewIds) {
148
+ const viewState = this.getViewState(viewId);
149
+ this.handleZoom(viewId, viewState.zoom - 1);
120
150
  }
121
151
  }
122
- /** @todo - move to deck or widget manager */
123
- setViewState(viewId, viewState) {
124
- this.deck._onViewStateChange({ viewId, viewState, interactionState: {} });
125
- }
126
152
  };
127
153
  ZoomWidget.defaultProps = {
128
154
  ...import_core.Widget.defaultProps,
@@ -136,18 +162,9 @@ ZoomWidget.defaultProps = {
136
162
  };
137
163
 
138
164
  // dist/reset-view-widget.js
139
- var import_jsx_runtime5 = require("preact/jsx-runtime");
165
+ var import_jsx_runtime4 = require("preact/jsx-runtime");
140
166
  var import_preact2 = require("preact");
141
167
  var import_core2 = require("@deck.gl/core");
142
-
143
- // dist/lib/components/icon-button.js
144
- var import_jsx_runtime4 = require("preact/jsx-runtime");
145
- var IconButton = (props) => {
146
- const { className = "", label, onClick, children } = props;
147
- return (0, import_jsx_runtime4.jsx)("div", { className: "deck-widget-button", children: (0, import_jsx_runtime4.jsx)("button", { className: `deck-widget-icon-button ${className}`, type: "button", onClick, title: label, children: children ? children : (0, import_jsx_runtime4.jsx)("div", { className: "deck-widget-icon" }) }) });
148
- };
149
-
150
- // dist/reset-view-widget.js
151
168
  var ResetViewWidget = class extends import_core2.Widget {
152
169
  constructor(props = {}) {
153
170
  super(props);
@@ -161,22 +178,25 @@ var ResetViewWidget = class extends import_core2.Widget {
161
178
  super.setProps(props);
162
179
  }
163
180
  onRenderHTML(rootElement) {
164
- (0, import_preact2.render)((0, import_jsx_runtime5.jsx)(IconButton, { className: "deck-widget-reset-focus", label: this.props.label, onClick: this.handleClick.bind(this) }), rootElement);
181
+ (0, import_preact2.render)((0, import_jsx_runtime4.jsx)(IconButton, { className: "deck-widget-reset-focus", label: this.props.label, onClick: this.handleClick.bind(this) }), rootElement);
165
182
  }
166
183
  handleClick() {
167
184
  var _a;
168
185
  const initialViewState = this.props.initialViewState || ((_a = this.deck) == null ? void 0 : _a.props.initialViewState);
169
- this.setViewState(initialViewState);
186
+ this.resetViewState(initialViewState);
170
187
  }
171
- setViewState(viewState) {
172
- const viewId = this.props.viewId || "default-view";
173
- const nextViewState = {
174
- ...viewId !== "default-view" ? viewState == null ? void 0 : viewState[viewId] : viewState
175
- // only works for geospatial?
176
- // transitionDuration: this.props.transitionDuration,
177
- // transitionInterpolator: new FlyToInterpolator()
178
- };
179
- this.deck._onViewStateChange({ viewId, viewState: nextViewState, interactionState: {} });
188
+ resetViewState(viewState) {
189
+ var _a;
190
+ const viewIds = this.viewId ? [this.viewId] : ((_a = this.deck) == null ? void 0 : _a.getViews().map((v) => v.id)) ?? [];
191
+ for (const viewId of viewIds) {
192
+ const nextViewState = {
193
+ ...(viewState == null ? void 0 : viewState[viewId]) ?? viewState
194
+ // only works for geospatial?
195
+ // transitionDuration: this.props.transitionDuration,
196
+ // transitionInterpolator: new FlyToInterpolator()
197
+ };
198
+ this.setViewState(viewId, nextViewState);
199
+ }
180
200
  }
181
201
  };
182
202
  ResetViewWidget.defaultProps = {
@@ -189,7 +209,7 @@ ResetViewWidget.defaultProps = {
189
209
  };
190
210
 
191
211
  // dist/gimbal-widget.js
192
- var import_jsx_runtime6 = require("preact/jsx-runtime");
212
+ var import_jsx_runtime5 = require("preact/jsx-runtime");
193
213
  var import_core3 = require("@deck.gl/core");
194
214
  var import_preact3 = require("preact");
195
215
  var GimbalWidget = class extends import_core3.Widget {
@@ -210,21 +230,21 @@ var GimbalWidget = class extends import_core3.Widget {
210
230
  const viewId = this.viewId || ((_a = Object.values(this.viewports)[0]) == null ? void 0 : _a.id) || "default-view";
211
231
  const widgetViewport = this.viewports[viewId];
212
232
  const { rotationOrbit, rotationX } = this.getNormalizedRotation(widgetViewport);
213
- const ui = (0, import_jsx_runtime6.jsx)("div", { className: "deck-widget-button", style: { perspective: 100, pointerEvents: "auto" }, children: (0, import_jsx_runtime6.jsxs)("button", { type: "button", onClick: () => {
233
+ const ui = (0, import_jsx_runtime5.jsx)("div", { className: "deck-widget-button", style: { perspective: 100, pointerEvents: "auto" }, children: (0, import_jsx_runtime5.jsxs)("button", { type: "button", onClick: () => {
214
234
  for (const viewport of Object.values(this.viewports)) {
215
235
  this.resetOrbitView(viewport);
216
236
  }
217
- }, title: this.props.label, style: { position: "relative", width: 26, height: 26 }, children: [(0, import_jsx_runtime6.jsx)("svg", { className: "gimbal-outer-ring", width: "100%", height: "100%", viewBox: "0 0 26 26", style: {
237
+ }, title: this.props.label, style: { position: "relative", width: 26, height: 26 }, children: [(0, import_jsx_runtime5.jsx)("svg", { className: "gimbal-outer-ring", width: "100%", height: "100%", viewBox: "0 0 26 26", style: {
218
238
  position: "absolute",
219
239
  top: 0,
220
240
  left: 0,
221
241
  transform: `rotateY(${rotationOrbit}deg)`
222
- }, children: (0, import_jsx_runtime6.jsx)("circle", { cx: "13", cy: "13", r: "10", stroke: "var(--icon-gimbal-outer-color, rgb(68, 92, 204))", strokeWidth: this.props.strokeWidth, fill: "none" }) }), (0, import_jsx_runtime6.jsx)("svg", { className: "gimbal-inner-ring", width: "100%", height: "100%", viewBox: "0 0 26 26", style: {
242
+ }, children: (0, import_jsx_runtime5.jsx)("circle", { cx: "13", cy: "13", r: "10", stroke: "var(--icon-gimbal-outer-color, rgb(68, 92, 204))", strokeWidth: this.props.strokeWidth, fill: "none" }) }), (0, import_jsx_runtime5.jsx)("svg", { className: "gimbal-inner-ring", width: "100%", height: "100%", viewBox: "0 0 26 26", style: {
223
243
  position: "absolute",
224
244
  top: 0,
225
245
  left: 0,
226
246
  transform: `rotateX(${rotationX}deg)`
227
- }, children: (0, import_jsx_runtime6.jsx)("circle", { cx: "13", cy: "13", r: "7", stroke: "var(--icon-gimbal-inner-color, rgb(240, 92, 68))", strokeWidth: this.props.strokeWidth, fill: "none" }) })] }) });
247
+ }, children: (0, import_jsx_runtime5.jsx)("circle", { cx: "13", cy: "13", r: "7", stroke: "var(--icon-gimbal-inner-color, rgb(240, 92, 68))", strokeWidth: this.props.strokeWidth, fill: "none" }) })] }) });
228
248
  (0, import_preact3.render)(ui, rootElement);
229
249
  }
230
250
  onViewportChange(viewport) {
@@ -232,7 +252,7 @@ var GimbalWidget = class extends import_core3.Widget {
232
252
  this.updateHTML();
233
253
  }
234
254
  resetOrbitView(viewport) {
235
- const viewId = this.getViewId(viewport);
255
+ const viewId = this.viewId || (viewport == null ? void 0 : viewport.id) || "OrbitView";
236
256
  const viewState = this.getViewState(viewId);
237
257
  if ("rotationOrbit" in viewState || "rotationX" in viewState) {
238
258
  const nextViewState = {
@@ -244,11 +264,12 @@ var GimbalWidget = class extends import_core3.Widget {
244
264
  transitionProps: ["rotationOrbit", "rotationX"]
245
265
  })
246
266
  };
247
- this.deck._onViewStateChange({ viewId, viewState: nextViewState, interactionState: {} });
267
+ this.setViewState(viewId, nextViewState);
248
268
  }
249
269
  }
250
270
  getNormalizedRotation(viewport) {
251
- const viewState = this.getViewState(this.getViewId(viewport));
271
+ const viewId = this.viewId || (viewport == null ? void 0 : viewport.id) || "OrbitView";
272
+ const viewState = this.getViewState(viewId);
252
273
  const [rz, rx] = this.getRotation(viewState);
253
274
  const rotationOrbit = normalizeAndClampAngle(rz);
254
275
  const rotationX = normalizeAndClampAngle(rx);
@@ -260,24 +281,6 @@ var GimbalWidget = class extends import_core3.Widget {
260
281
  }
261
282
  return [0, 0];
262
283
  }
263
- // Move to Widget/WidgetManager?
264
- getViewId(viewport) {
265
- const viewId = this.viewId || (viewport == null ? void 0 : viewport.id) || "OrbitView";
266
- return viewId;
267
- }
268
- getViewState(viewId) {
269
- const viewManager = this.getViewManager();
270
- const viewState = viewId && viewManager.getViewState(viewId) || viewManager.viewState;
271
- return viewState;
272
- }
273
- getViewManager() {
274
- var _a;
275
- const viewManager = (_a = this.deck) == null ? void 0 : _a.viewManager;
276
- if (!viewManager) {
277
- throw new Error("wigdet must be added to a deck instance");
278
- }
279
- return viewManager;
280
- }
281
284
  };
282
285
  GimbalWidget.defaultProps = {
283
286
  ...import_core3.Widget.defaultProps,
@@ -303,7 +306,7 @@ function normalizeAndClampAngle(angle) {
303
306
  }
304
307
 
305
308
  // dist/compass-widget.js
306
- var import_jsx_runtime7 = require("preact/jsx-runtime");
309
+ var import_jsx_runtime6 = require("preact/jsx-runtime");
307
310
  var import_core4 = require("@deck.gl/core");
308
311
  var import_preact4 = require("preact");
309
312
  var CompassWidget = class extends import_core4.Widget {
@@ -321,14 +324,14 @@ var CompassWidget = class extends import_core4.Widget {
321
324
  }
322
325
  onRenderHTML(rootElement) {
323
326
  var _a;
324
- const viewId = this.viewId || ((_a = Object.values(this.viewports)[0]) == null ? void 0 : _a.id) || "default-view";
327
+ const viewId = this.viewId || ((_a = Object.values(this.viewports)[0]) == null ? void 0 : _a.id);
325
328
  const widgetViewport = this.viewports[viewId];
326
329
  const [rz, rx] = this.getRotation(widgetViewport);
327
- const ui = (0, import_jsx_runtime7.jsx)("div", { className: "deck-widget-button", style: { perspective: 100 }, children: (0, import_jsx_runtime7.jsx)("button", { type: "button", onClick: () => {
330
+ const ui = (0, import_jsx_runtime6.jsx)("div", { className: "deck-widget-button", style: { perspective: 100 }, children: (0, import_jsx_runtime6.jsx)("button", { type: "button", onClick: () => {
328
331
  for (const viewport of Object.values(this.viewports)) {
329
332
  this.handleCompassReset(viewport);
330
333
  }
331
- }, title: this.props.label, style: { transform: `rotateX(${rx}deg)` }, children: (0, import_jsx_runtime7.jsx)("svg", { fill: "none", width: "100%", height: "100%", viewBox: "0 0 26 26", children: (0, import_jsx_runtime7.jsxs)("g", { transform: `rotate(${rz},13,13)`, children: [(0, import_jsx_runtime7.jsx)("path", { d: "M10 13.0001L12.9999 5L15.9997 13.0001H10Z", fill: "var(--icon-compass-north-color, rgb(240, 92, 68))" }), (0, import_jsx_runtime7.jsx)("path", { d: "M16.0002 12.9999L13.0004 21L10.0005 12.9999H16.0002Z", fill: "var(--icon-compass-south-color, rgb(204, 204, 204))" })] }) }) }) });
334
+ }, title: this.props.label, style: { transform: `rotateX(${rx}deg)` }, children: (0, import_jsx_runtime6.jsx)("svg", { fill: "none", width: "100%", height: "100%", viewBox: "0 0 26 26", children: (0, import_jsx_runtime6.jsxs)("g", { transform: `rotate(${rz},13,13)`, children: [(0, import_jsx_runtime6.jsx)("path", { d: "M10 13.0001L12.9999 5L15.9997 13.0001H10Z", fill: "var(--icon-compass-north-color, rgb(240, 92, 68))" }), (0, import_jsx_runtime6.jsx)("path", { d: "M16.0002 12.9999L13.0004 21L10.0005 12.9999H16.0002Z", fill: "var(--icon-compass-south-color, rgb(204, 204, 204))" })] }) }) }) });
332
335
  (0, import_preact4.render)(ui, rootElement);
333
336
  }
334
337
  onViewportChange(viewport) {
@@ -346,16 +349,17 @@ var CompassWidget = class extends import_core4.Widget {
346
349
  return [0, 0];
347
350
  }
348
351
  handleCompassReset(viewport) {
349
- const viewId = this.viewId || viewport.id || "default-view";
352
+ const viewId = this.viewId || viewport.id;
350
353
  if (viewport instanceof import_core4.WebMercatorViewport) {
354
+ const viewState = this.getViewState(viewId);
351
355
  const nextViewState = {
352
- ...viewport,
356
+ ...viewState,
353
357
  bearing: 0,
354
358
  ...this.getRotation(viewport)[0] === 0 ? { pitch: 0 } : {},
355
359
  transitionDuration: this.props.transitionDuration,
356
360
  transitionInterpolator: new import_core4.FlyToInterpolator()
357
361
  };
358
- this.deck._onViewStateChange({ viewId, viewState: nextViewState, interactionState: {} });
362
+ this.setViewState(viewId, nextViewState);
359
363
  }
360
364
  }
361
365
  };
@@ -369,7 +373,7 @@ CompassWidget.defaultProps = {
369
373
  };
370
374
 
371
375
  // dist/scale-widget.js
372
- var import_jsx_runtime8 = require("preact/jsx-runtime");
376
+ var import_jsx_runtime7 = require("preact/jsx-runtime");
373
377
  var import_preact5 = require("preact");
374
378
  var import_core5 = require("@deck.gl/core");
375
379
  var ScaleWidget = class extends import_core5.Widget {
@@ -391,7 +395,7 @@ var ScaleWidget = class extends import_core5.Widget {
391
395
  const lineOffsetX = 50;
392
396
  const svgWidth = lineOffsetX + this.scaleWidth;
393
397
  const tickHeight = 10;
394
- (0, import_preact5.render)((0, import_jsx_runtime8.jsxs)("svg", { className: "deck-widget-scale", width: svgWidth, height: 30, style: { overflow: "visible", background: "transparent" }, onClick: this.handleClick.bind(this), children: [(0, import_jsx_runtime8.jsx)("text", { x: lineOffsetX + 5, y: "10", textAnchor: "end", alignmentBaseline: "middle", style: { fontSize: "16px", fill: "black", fontWeight: "bold", fontFamily: "sans-serif" }, children: this.scaleText }), (0, import_jsx_runtime8.jsx)("line", { x1: lineOffsetX, y1: "15", x2: lineOffsetX + this.scaleWidth, y2: "15", stroke: "black", strokeWidth: "6" }), (0, import_jsx_runtime8.jsx)("line", { x1: lineOffsetX, y1: "15", x2: lineOffsetX, y2: 15 - tickHeight, stroke: "black", strokeWidth: "6" }), (0, import_jsx_runtime8.jsx)("line", { x1: lineOffsetX + this.scaleWidth, y1: "15", x2: lineOffsetX + this.scaleWidth, y2: 15 - tickHeight, stroke: "black", strokeWidth: "6" })] }), rootElement);
398
+ (0, import_preact5.render)((0, import_jsx_runtime7.jsxs)("svg", { className: "deck-widget-scale", width: svgWidth, height: 30, style: { overflow: "visible", background: "transparent" }, onClick: this.handleClick.bind(this), children: [(0, import_jsx_runtime7.jsx)("text", { x: lineOffsetX + 5, y: "10", textAnchor: "end", alignmentBaseline: "middle", style: { fontSize: "16px", fill: "black", fontWeight: "bold", fontFamily: "sans-serif" }, children: this.scaleText }), (0, import_jsx_runtime7.jsx)("line", { x1: lineOffsetX, y1: "15", x2: lineOffsetX + this.scaleWidth, y2: "15", stroke: "black", strokeWidth: "6" }), (0, import_jsx_runtime7.jsx)("line", { x1: lineOffsetX, y1: "15", x2: lineOffsetX, y2: 15 - tickHeight, stroke: "black", strokeWidth: "6" }), (0, import_jsx_runtime7.jsx)("line", { x1: lineOffsetX + this.scaleWidth, y1: "15", x2: lineOffsetX + this.scaleWidth, y2: 15 - tickHeight, stroke: "black", strokeWidth: "6" })] }), rootElement);
395
399
  }
396
400
  onViewportChange(viewport) {
397
401
  if (!("latitude" in viewport))
@@ -454,14 +458,14 @@ function computeScaleCandidate(metersPerPixel) {
454
458
  }
455
459
 
456
460
  // dist/geocoder-widget.js
457
- var import_jsx_runtime10 = require("preact/jsx-runtime");
461
+ var import_jsx_runtime9 = require("preact/jsx-runtime");
458
462
  var import_core6 = require("@deck.gl/core");
459
463
  var import_core7 = require("@deck.gl/core");
460
464
  var import_preact6 = require("preact");
461
465
 
462
466
  // dist/lib/components/dropdown-menu.js
463
- var import_jsx_runtime9 = require("preact/jsx-runtime");
464
- var import_hooks = require("preact/hooks");
467
+ var import_jsx_runtime8 = require("preact/jsx-runtime");
468
+ var import_hooks2 = require("preact/hooks");
465
469
  function getMenuItemValue(item) {
466
470
  return typeof item === "string" ? item : item.value;
467
471
  }
@@ -472,30 +476,39 @@ function getMenuItemIcon(item) {
472
476
  return typeof item === "string" ? void 0 : item.icon;
473
477
  }
474
478
  var DropdownMenu = (props) => {
475
- const [isOpen, setIsOpen] = (0, import_hooks.useState)(false);
476
- const dropdownRef = (0, import_hooks.useRef)(null);
477
- const toggleDropdown = () => setIsOpen(!isOpen);
478
- const handleClickOutside = (event) => {
479
- if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
480
- setIsOpen(false);
481
- }
482
- };
483
- (0, import_hooks.useEffect)(() => {
479
+ const [isOpen, setIsOpen] = (0, import_hooks2.useState)(false);
480
+ return (0, import_jsx_runtime8.jsx)(SimpleMenu, { ...props, style: { ...props.style, position: "absolute" }, isOpen, onClose: () => setIsOpen(false), trigger: (0, import_jsx_runtime8.jsx)("button", { className: "deck-widget-dropdown-button", onClick: () => setIsOpen(!isOpen), children: (0, import_jsx_runtime8.jsx)("span", { className: `deck-widget-dropdown-icon ${isOpen ? "open" : ""}` }) }) });
481
+ };
482
+ var SimpleMenu = (props) => {
483
+ const dropdownRef = (0, import_hooks2.useRef)(null);
484
+ (0, import_hooks2.useEffect)(() => {
485
+ const handleClickOutside = (event) => {
486
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
487
+ props.onClose();
488
+ }
489
+ };
484
490
  document.addEventListener("mousedown", handleClickOutside);
485
491
  return () => {
486
492
  document.removeEventListener("mousedown", handleClickOutside);
487
493
  };
488
494
  }, []);
489
- const handleSelect = (item) => {
490
- props.onSelect(getMenuItemValue(item));
491
- setIsOpen(false);
495
+ const handleSelect = (value, item) => {
496
+ var _a, _b;
497
+ if (value) {
498
+ if (typeof item === "object") {
499
+ (_a = item.onSelect) == null ? void 0 : _a.call(item);
500
+ }
501
+ (_b = props.onSelect) == null ? void 0 : _b.call(props, value);
502
+ props.onClose();
503
+ }
492
504
  };
493
505
  if (props.menuItems.length === 0) {
494
506
  return null;
495
507
  }
496
- return (0, import_jsx_runtime9.jsxs)("div", { className: "deck-widget-dropdown-container", ref: dropdownRef, style: props.style, children: [(0, import_jsx_runtime9.jsx)("button", { className: "deck-widget-dropdown-button", onClick: toggleDropdown, children: (0, import_jsx_runtime9.jsx)("span", { className: `deck-widget-dropdown-icon ${isOpen ? "open" : ""}` }) }), isOpen && (0, import_jsx_runtime9.jsx)("ul", { className: "deck-widget-dropdown-menu", children: props.menuItems.map((item) => {
508
+ return (0, import_jsx_runtime8.jsxs)("div", { className: "deck-widget-dropdown-container", ref: dropdownRef, children: [props.trigger, props.isOpen && (0, import_jsx_runtime8.jsx)("ul", { className: "deck-widget-dropdown-menu", style: props.style, children: props.menuItems.map((item, i) => {
509
+ const value = getMenuItemValue(item);
497
510
  const icon = getMenuItemIcon(item);
498
- return (0, import_jsx_runtime9.jsxs)("li", { className: "deck-widget-dropdown-item", onClick: () => handleSelect(item), children: [icon && (0, import_jsx_runtime9.jsx)("span", { className: "deck-widget-dropdown-item-icon", style: { maskImage: `url("${icon}")`, WebkitMaskImage: `url("${icon}")` } }), getMenuItemLabel(item)] }, getMenuItemValue(item));
511
+ return (0, import_jsx_runtime8.jsxs)("li", { className: `deck-widget-dropdown-item ${value ? "" : "disabled"}`, onClick: () => handleSelect(value, item), children: [icon && (0, import_jsx_runtime8.jsx)("span", { className: "deck-widget-dropdown-item-icon", style: getCSSMask(icon) }), getMenuItemLabel(item)] }, i);
499
512
  }) })] });
500
513
  };
501
514
 
@@ -731,7 +744,7 @@ var GeocoderWidget = class extends import_core6.Widget {
731
744
  try {
732
745
  const coordinates = await CurrentLocationGeocoder.geocode();
733
746
  if (coordinates) {
734
- this.setViewState(coordinates);
747
+ this.flyTo(coordinates);
735
748
  }
736
749
  } catch (error) {
737
750
  this.geocodeHistory.errorText = error instanceof Error ? error.message : "Location error";
@@ -748,10 +761,9 @@ var GeocoderWidget = class extends import_core6.Widget {
748
761
  this.updateHTML();
749
762
  }
750
763
  if (coordinates) {
751
- this.setViewState(coordinates);
764
+ this.flyTo(coordinates);
752
765
  }
753
766
  };
754
- this.viewports = {};
755
767
  this.setProps(this.props);
756
768
  }
757
769
  setProps(props) {
@@ -765,7 +777,7 @@ var GeocoderWidget = class extends import_core6.Widget {
765
777
  }
766
778
  onRenderHTML(rootElement) {
767
779
  const menuItems = this.props._geolocation ? [CURRENT_LOCATION_ITEM, ...this.geocodeHistory.addressHistory] : [...this.geocodeHistory.addressHistory];
768
- (0, import_preact6.render)((0, import_jsx_runtime10.jsxs)("div", { className: "deck-widget-geocoder", children: [(0, import_jsx_runtime10.jsx)("input", {
780
+ (0, import_preact6.render)((0, import_jsx_runtime9.jsxs)("div", { className: "deck-widget-geocoder", children: [(0, import_jsx_runtime9.jsx)("input", {
769
781
  className: "deck-widget-geocoder-input",
770
782
  type: "text",
771
783
  placeholder: this.isGettingLocation ? "Finding your location..." : this.geocoder.placeholderLocation ?? "Enter address or location",
@@ -776,24 +788,23 @@ var GeocoderWidget = class extends import_core6.Widget {
776
788
  return this.setInput(((_a = e.target) == null ? void 0 : _a.value) || "");
777
789
  },
778
790
  onKeyPress: this.handleKeyPress
779
- }), (0, import_jsx_runtime10.jsx)(DropdownMenu, { menuItems, onSelect: this.handleSelect }), this.geocodeHistory.errorText && (0, import_jsx_runtime10.jsx)("div", { className: "deck-widget-geocoder-error", children: this.geocodeHistory.errorText })] }), rootElement);
791
+ }), (0, import_jsx_runtime9.jsx)(DropdownMenu, { menuItems, onSelect: this.handleSelect }), this.geocodeHistory.errorText && (0, import_jsx_runtime9.jsx)("div", { className: "deck-widget-geocoder-error", children: this.geocodeHistory.errorText })] }), rootElement);
780
792
  }
781
- // TODO - MOVE TO WIDGETIMPL?
782
- setViewState(viewState) {
783
- const viewId = this.props.viewId || (viewState == null ? void 0 : viewState.id) || "default-view";
784
- const viewport = this.viewports[viewId] || {};
785
- const nextViewState = {
786
- ...viewport,
787
- ...viewState
788
- };
789
- if (this.props.transitionDuration > 0) {
790
- nextViewState.transitionDuration = this.props.transitionDuration;
791
- nextViewState.transitionInterpolator = "latitude" in nextViewState ? new import_core7.FlyToInterpolator() : new import_core7.LinearInterpolator();
793
+ flyTo(viewState) {
794
+ var _a;
795
+ const viewIds = this.viewId ? [this.viewId] : ((_a = this.deck) == null ? void 0 : _a.getViews().map((v) => v.id)) ?? [];
796
+ for (const viewId of viewIds) {
797
+ const currentViewState = this.getViewState(viewId);
798
+ const nextViewState = {
799
+ ...currentViewState,
800
+ ...viewState
801
+ };
802
+ if (this.props.transitionDuration > 0) {
803
+ nextViewState.transitionDuration = this.props.transitionDuration;
804
+ nextViewState.transitionInterpolator = "latitude" in nextViewState ? new import_core7.FlyToInterpolator() : new import_core7.LinearInterpolator();
805
+ }
806
+ this.setViewState(viewId, nextViewState);
792
807
  }
793
- this.deck._onViewStateChange({ viewId, viewState: nextViewState, interactionState: {} });
794
- }
795
- onViewportChange(viewport) {
796
- this.viewports[viewport.id] = viewport;
797
808
  }
798
809
  };
799
810
  GeocoderWidget.defaultProps = {
@@ -829,7 +840,7 @@ function getGeocoder(props) {
829
840
  }
830
841
 
831
842
  // dist/fullscreen-widget.js
832
- var import_jsx_runtime11 = require("preact/jsx-runtime");
843
+ var import_jsx_runtime10 = require("preact/jsx-runtime");
833
844
  var import_core8 = require("@deck.gl/core");
834
845
  var import_preact7 = require("preact");
835
846
  var FullscreenWidget = class extends import_core8.Widget {
@@ -847,7 +858,7 @@ var FullscreenWidget = class extends import_core8.Widget {
847
858
  document.removeEventListener("fullscreenchange", this.onFullscreenChange.bind(this));
848
859
  }
849
860
  onRenderHTML(rootElement) {
850
- (0, import_preact7.render)((0, import_jsx_runtime11.jsx)(IconButton, { onClick: () => {
861
+ (0, import_preact7.render)((0, import_jsx_runtime10.jsx)(IconButton, { onClick: () => {
851
862
  this.handleClick().catch((err) => import_core8.log.error(err)());
852
863
  }, label: this.fullscreen ? this.props.exitLabel : this.props.enterLabel, className: this.fullscreen ? "deck-widget-fullscreen-exit" : "deck-widget-fullscreen-enter" }), rootElement);
853
864
  }
@@ -857,8 +868,8 @@ var FullscreenWidget = class extends import_core8.Widget {
857
868
  super.setProps(props);
858
869
  }
859
870
  getContainer() {
860
- var _a, _b;
861
- return this.props.container || ((_b = (_a = this.deck) == null ? void 0 : _a.getCanvas()) == null ? void 0 : _b.parentElement);
871
+ var _a, _b, _c;
872
+ return this.props.container || ((_a = this.deck) == null ? void 0 : _a.props.parent) || ((_c = (_b = this.deck) == null ? void 0 : _b.getCanvas()) == null ? void 0 : _c.parentElement);
862
873
  }
863
874
  onFullscreenChange() {
864
875
  const prevFullscreen = this.fullscreen;
@@ -907,36 +918,148 @@ FullscreenWidget.defaultProps = {
907
918
  };
908
919
 
909
920
  // dist/splitter-widget.js
910
- var import_jsx_runtime12 = require("preact/jsx-runtime");
921
+ var import_jsx_runtime11 = require("preact/jsx-runtime");
911
922
  var import_preact8 = require("preact");
912
- var import_hooks2 = require("preact/hooks");
923
+ var import_hooks3 = require("preact/hooks");
913
924
  var import_core9 = require("@deck.gl/core");
925
+ function parseViewLayout(root) {
926
+ const layoutsById = [];
927
+ const isViewLayout = (v) => "views" in v;
928
+ function createManagedViewLayout(l) {
929
+ const id = layoutsById.length;
930
+ const minSplit = l.minSplit ?? 0.05;
931
+ const maxSplit = l.maxSplit ?? 0.95;
932
+ const split = Math.min(Math.max(l.initialSplit ?? 0.5, minSplit), maxSplit);
933
+ const managed = {
934
+ id,
935
+ orientation: l.orientation,
936
+ views: l.views,
937
+ split,
938
+ editable: l.editable ?? true,
939
+ minSplit,
940
+ maxSplit,
941
+ x: 0,
942
+ y: 0,
943
+ width: 0,
944
+ height: 0
945
+ };
946
+ layoutsById.push(managed);
947
+ managed.views = [
948
+ isViewLayout(l.views[0]) ? createManagedViewLayout(l.views[0]) : l.views[0],
949
+ isViewLayout(l.views[1]) ? createManagedViewLayout(l.views[1]) : l.views[1]
950
+ ];
951
+ return managed;
952
+ }
953
+ createManagedViewLayout(root);
954
+ return layoutsById;
955
+ }
956
+ function evaluateViews(root) {
957
+ const views = [];
958
+ function evaluateViewLayout(l, x, y, width, height) {
959
+ l.x = x;
960
+ l.y = y;
961
+ l.width = width;
962
+ l.height = height;
963
+ const child1X = x;
964
+ const child1Y = y;
965
+ let child1Width = width;
966
+ let child1Height = height;
967
+ let child2X = x;
968
+ let child2Y = y;
969
+ let child2Width = width;
970
+ let child2Height = height;
971
+ if (l.orientation === "horizontal") {
972
+ child1Width = width * l.split;
973
+ child2X = x + child1Width;
974
+ child2Width = width - child1Width;
975
+ } else {
976
+ child1Height = height * l.split;
977
+ child2Y = y + child1Height;
978
+ child2Height = height - child1Height;
979
+ }
980
+ const [view1, view2] = l.views;
981
+ if ("views" in view1) {
982
+ evaluateViewLayout(view1, child1X, child1Y, child1Width, child1Height);
983
+ } else {
984
+ views.push(view1.clone({
985
+ x: `${child1X}%`,
986
+ y: `${child1Y}%`,
987
+ width: `${child1Width}%`,
988
+ height: `${child1Height}%`
989
+ }));
990
+ }
991
+ if ("views" in view2) {
992
+ evaluateViewLayout(view2, child2X, child2Y, child2Width, child2Height);
993
+ } else {
994
+ views.push(view2.clone({
995
+ x: `${child2X}%`,
996
+ y: `${child2Y}%`,
997
+ width: `${child2Width}%`,
998
+ height: `${child2Height}%`
999
+ }));
1000
+ }
1001
+ }
1002
+ evaluateViewLayout(root, 0, 0, 100, 100);
1003
+ return views;
1004
+ }
914
1005
  var SplitterWidget = class extends import_core9.Widget {
915
1006
  constructor(props) {
916
1007
  super(props);
917
1008
  this.className = "deck-widget-splitter";
918
1009
  this.placement = "fill";
1010
+ this.needsUpdate = true;
1011
+ this.viewLayouts = parseViewLayout(this.props.viewLayout);
919
1012
  }
920
1013
  setProps(props) {
1014
+ if (props.viewLayout && !(0, import_core9._deepEqual)(props.viewLayout, this.props.viewLayout, -1)) {
1015
+ this.viewLayouts = parseViewLayout(props.viewLayout);
1016
+ this.views = void 0;
1017
+ }
921
1018
  super.setProps(props);
922
1019
  }
1020
+ onRedraw() {
1021
+ super.updateHTML();
1022
+ }
1023
+ // Usually widgets rerender their DOM elements here
1024
+ // In this case we need the widget UI to synchronize with deck view states
1025
+ // so we update deck props here and rerender DOM in the next onRedraw
1026
+ updateHTML() {
1027
+ if (!this.views) {
1028
+ this.views = evaluateViews(this.viewLayouts[0]);
1029
+ this.props.onChange(this.views.slice());
1030
+ }
1031
+ requestAnimationFrame(() => {
1032
+ this.doUpdate();
1033
+ });
1034
+ }
1035
+ doUpdate() {
1036
+ if (this.deck) {
1037
+ const deckViews = this.deck.props.views;
1038
+ const isManagedExternally = (
1039
+ // is not empty
1040
+ deckViews && // is not set by us
1041
+ deckViews !== this.lastViews
1042
+ );
1043
+ if (!isManagedExternally && this.lastViews !== this.views) {
1044
+ this.lastViews = this.views;
1045
+ this.deck.setProps({ views: this.views });
1046
+ }
1047
+ }
1048
+ }
1049
+ onChange(newSplit, layout) {
1050
+ layout.split = newSplit;
1051
+ this.views = evaluateViews(this.viewLayouts[0]);
1052
+ this.props.onChange(this.views.slice());
1053
+ this.doUpdate();
1054
+ }
923
1055
  onRenderHTML(rootElement) {
924
- rootElement.style.position = "absolute";
925
- rootElement.style.top = "0";
926
- rootElement.style.left = "0";
927
- rootElement.style.width = "100%";
928
- rootElement.style.height = "100%";
929
- rootElement.style.margin = "0px";
930
- (0, import_preact8.render)((0, import_jsx_runtime12.jsx)(Splitter, { orientation: this.props.orientation, initialSplit: this.props.initialSplit, onChange: this.props.onChange, onDragStart: this.props.onDragStart, onDragEnd: this.props.onDragEnd }), rootElement);
1056
+ (0, import_preact8.render)((0, import_jsx_runtime11.jsx)(import_jsx_runtime11.Fragment, { children: this.viewLayouts.map((layout) => layout.editable && (0, import_jsx_runtime11.jsx)(Splitter, { ...layout, onChange: (newSplit) => this.onChange(newSplit, layout), onDragStart: () => this.props.onDragStart(), onDragEnd: () => this.props.onDragStart() })) }), rootElement);
931
1057
  }
932
1058
  };
933
1059
  SplitterWidget.defaultProps = {
934
1060
  ...import_core9.Widget.defaultProps,
935
1061
  id: "splitter-widget",
936
- viewId1: "",
937
- viewId2: "",
938
- orientation: "vertical",
939
- initialSplit: 0.5,
1062
+ viewLayout: void 0,
940
1063
  onChange: () => {
941
1064
  },
942
1065
  onDragStart: () => {
@@ -944,463 +1067,1034 @@ SplitterWidget.defaultProps = {
944
1067
  onDragEnd: () => {
945
1068
  }
946
1069
  };
947
- function Splitter({ orientation, initialSplit, onChange, onDragStart, onDragEnd }) {
948
- const [split, setSplit] = (0, import_hooks2.useState)(initialSplit);
949
- const dragging = (0, import_hooks2.useRef)(false);
950
- const containerRef = (0, import_hooks2.useRef)(null);
1070
+ function Splitter({ orientation, x, y, width, height, split, minSplit, maxSplit, onChange, onDragStart, onDragEnd }) {
1071
+ const [dragging, setDragging] = (0, import_hooks3.useState)(false);
1072
+ const containerRef = (0, import_hooks3.useRef)(null);
1073
+ (0, import_hooks3.useEffect)(() => {
1074
+ if (!dragging) {
1075
+ return void 0;
1076
+ }
1077
+ const handleDragging = (event) => {
1078
+ if (!containerRef.current)
1079
+ return;
1080
+ const rect = containerRef.current.getBoundingClientRect();
1081
+ let newSplit;
1082
+ if (orientation === "horizontal") {
1083
+ newSplit = (event.clientX - rect.left) / rect.width;
1084
+ } else {
1085
+ newSplit = (event.clientY - rect.top) / rect.height;
1086
+ }
1087
+ newSplit = Math.min(Math.max(newSplit, minSplit), maxSplit);
1088
+ onChange == null ? void 0 : onChange(newSplit);
1089
+ };
1090
+ const handleDragEnd = () => {
1091
+ onDragEnd == null ? void 0 : onDragEnd();
1092
+ setDragging(false);
1093
+ };
1094
+ document.addEventListener("pointermove", handleDragging);
1095
+ document.addEventListener("pointerup", handleDragEnd);
1096
+ document.addEventListener("pointerleave", handleDragEnd);
1097
+ return () => {
1098
+ document.removeEventListener("pointermove", handleDragging);
1099
+ document.removeEventListener("pointerup", handleDragEnd);
1100
+ document.removeEventListener("pointerleave", handleDragEnd);
1101
+ };
1102
+ }, [dragging]);
951
1103
  const handleDragStart = (event) => {
952
- dragging.current = true;
1104
+ setDragging(true);
953
1105
  onDragStart == null ? void 0 : onDragStart();
954
- document.addEventListener("mousemove", handleDragging);
955
- document.addEventListener("mouseup", handleDragEnd);
956
1106
  event.preventDefault();
957
1107
  };
958
- const handleDragging = (event) => {
959
- if (!dragging.current || !containerRef.current)
960
- return;
961
- const rect = containerRef.current.getBoundingClientRect();
962
- let newSplit;
963
- if (orientation === "vertical") {
964
- newSplit = (event.clientX - rect.left) / rect.width;
965
- } else {
966
- newSplit = (event.clientY - rect.top) / rect.height;
967
- }
968
- newSplit = Math.min(Math.max(newSplit, 0.05), 0.95);
969
- setSplit(newSplit);
970
- onChange == null ? void 0 : onChange(newSplit);
971
- };
972
- const handleDragEnd = (event) => {
973
- if (!dragging.current)
974
- return;
975
- dragging.current = false;
976
- onDragEnd == null ? void 0 : onDragEnd();
977
- document.removeEventListener("mousemove", handleDragging);
978
- document.removeEventListener("mouseup", handleDragEnd);
979
- };
980
- const splitterStyle = orientation === "vertical" ? {
981
- position: "absolute",
982
- top: 0,
983
- bottom: 0,
984
- left: `${split * 100}%`,
985
- width: "4px",
986
- cursor: "col-resize",
987
- background: "#ccc",
988
- zIndex: 10,
989
- pointerEvents: "auto",
990
- boxShadow: "inset -1px 0 0 white, inset 1px 0 0 white"
991
- } : {
992
- position: "absolute",
993
- left: 0,
994
- right: 0,
995
- top: `${split * 100}%`,
996
- height: "4px",
997
- cursor: "row-resize",
998
- background: "#ccc",
999
- zIndex: 10,
1000
- pointerEvents: "auto",
1001
- boxShadow: "inset -1px 0 0 white, inset 1px 0 0 white"
1002
- };
1108
+ const splitterStyle = orientation === "horizontal" ? { left: `${split * 100}%` } : { top: `${split * 100}%` };
1003
1109
  const containerStyle = {
1004
1110
  position: "absolute",
1005
- top: 0,
1006
- left: 0,
1007
- right: 0,
1008
- bottom: 0
1111
+ top: `${y}%`,
1112
+ left: `${x}%`,
1113
+ width: `${width}%`,
1114
+ height: `${height}%`
1009
1115
  };
1010
- return (0, import_jsx_runtime12.jsx)("div", { ref: containerRef, style: containerStyle, children: (0, import_jsx_runtime12.jsx)("div", { style: splitterStyle, onMouseDown: handleDragStart }) });
1116
+ return (0, import_jsx_runtime11.jsx)("div", { ref: containerRef, style: containerStyle, children: (0, import_jsx_runtime11.jsx)("div", { className: `deck-widget-splitter-handle deck-widget-splitter-handle--${orientation} ${dragging ? "active" : ""}`, style: splitterStyle, onPointerDown: handleDragStart }) });
1011
1117
  }
1012
1118
 
1013
- // dist/view-selector-widget.js
1119
+ // dist/info-widget.js
1014
1120
  var import_jsx_runtime14 = require("preact/jsx-runtime");
1015
- var import_preact9 = require("preact");
1016
1121
  var import_core10 = require("@deck.gl/core");
1122
+ var import_preact9 = require("preact");
1017
1123
 
1018
- // dist/lib/components/icon-menu.js
1019
- var import_jsx_runtime13 = require("preact/jsx-runtime");
1020
- var import_hooks3 = require("preact/hooks");
1021
- function IconMenu(props) {
1022
- const [menuOpen, setMenuOpen] = (0, import_hooks3.useState)(false);
1023
- const containerRef = (0, import_hooks3.useRef)(null);
1024
- const handleClickOutside = (event) => {
1025
- if (containerRef.current && !containerRef.current.contains(event.target)) {
1026
- setMenuOpen(false);
1027
- }
1124
+ // dist/lib/components/popover.js
1125
+ var import_jsx_runtime12 = require("preact/jsx-runtime");
1126
+ var import_hooks4 = require("preact/hooks");
1127
+ var import_dom = require("@floating-ui/dom");
1128
+ var Popover = ({ x, y, placement = "right", offset: pixelOffset = 0, arrow: arrowSize = false, arrowColor = "white", children }) => {
1129
+ const anchorRef = (0, import_hooks4.useRef)(null);
1130
+ const contentRef = (0, import_hooks4.useRef)(null);
1131
+ const arrowRef = (0, import_hooks4.useRef)(null);
1132
+ const updaterRef = (0, import_hooks4.useRef)();
1133
+ updaterRef.current = () => {
1134
+ if (!anchorRef.current || !contentRef.current)
1135
+ return;
1136
+ const arrowWidth = Array.isArray(arrowSize) ? arrowSize[0] : arrowSize || 0;
1137
+ const arrowHeight = Array.isArray(arrowSize) ? arrowSize[1] : arrowSize || 0;
1138
+ const padding = pixelOffset + Math.max(arrowHeight, arrowWidth);
1139
+ const middleware = placement.includes("-") ? [(0, import_dom.offset)(padding), (0, import_dom.flip)(), (0, import_dom.shift)()] : [(0, import_dom.offset)(padding), (0, import_dom.shift)(), (0, import_dom.flip)()];
1140
+ if (arrowRef.current)
1141
+ middleware.push((0, import_dom.arrow)({ element: arrowRef.current }));
1142
+ (0, import_dom.computePosition)(anchorRef.current, contentRef.current, {
1143
+ placement,
1144
+ strategy: "fixed",
1145
+ middleware
1146
+ }).then((popoverPos) => {
1147
+ if (contentRef.current) {
1148
+ Object.assign(contentRef.current.style, {
1149
+ left: `${popoverPos.x}px`,
1150
+ top: `${popoverPos.y}px`
1151
+ });
1152
+ }
1153
+ const arrowData = popoverPos.middlewareData.arrow;
1154
+ if (arrowData && arrowRef.current) {
1155
+ const arrowStyle = createArrow(arrowWidth, arrowHeight, arrowColor, popoverPos.placement);
1156
+ arrowStyle.transform = `translate(${arrowData.x || 0}px, ${arrowData.y || 0}px)`;
1157
+ Object.assign(arrowRef.current.style, arrowStyle);
1158
+ }
1159
+ });
1028
1160
  };
1029
- (0, import_hooks3.useEffect)(() => {
1030
- document.addEventListener("mousedown", handleClickOutside);
1161
+ (0, import_hooks4.useMemo)(() => {
1162
+ var _a;
1163
+ (_a = updaterRef.current) == null ? void 0 : _a.call(updaterRef);
1164
+ }, [x, y, placement, arrowSize, pixelOffset]);
1165
+ (0, import_hooks4.useEffect)(() => {
1166
+ if (contentRef.current) {
1167
+ contentRef.current.style.visibility = "visible";
1168
+ }
1169
+ const cleanup = (0, import_dom.autoUpdate)(anchorRef.current, contentRef.current, () => {
1170
+ var _a;
1171
+ return (_a = updaterRef.current) == null ? void 0 : _a.call(updaterRef);
1172
+ });
1031
1173
  return () => {
1032
- document.removeEventListener("mousedown", handleClickOutside);
1174
+ cleanup();
1033
1175
  };
1034
- }, [containerRef]);
1035
- const [selectedItem, setSelectedItem] = (0, import_hooks3.useState)(props.initialItem);
1036
- const handleSelectItem = (item) => {
1037
- setSelectedItem(item);
1038
- setMenuOpen(false);
1039
- props.onItemSelected(item);
1176
+ }, []);
1177
+ return (0, import_jsx_runtime12.jsx)("div", { style: { position: "absolute", left: x, top: y }, ref: anchorRef, children: (0, import_jsx_runtime12.jsxs)("div", { className: "deck-widget deck-widget-popover", style: { position: "fixed", visibility: "hidden", pointerEvents: "none" }, ref: contentRef, children: [Boolean(arrowSize) && (0, import_jsx_runtime12.jsx)("div", { className: "deck-widget-popover-arrow", style: { position: "absolute" }, ref: arrowRef }), children] }) });
1178
+ };
1179
+ function createArrow(width, height, color, placement) {
1180
+ const result = {
1181
+ width: 0,
1182
+ height: 0,
1183
+ top: "",
1184
+ bottom: "",
1185
+ left: "",
1186
+ right: ""
1040
1187
  };
1041
- const handleButtonClick = () => setMenuOpen(!menuOpen);
1042
- const selectedMenuItem = props.menuItems.find((item) => item.value === selectedItem);
1043
- const label = props.label || (selectedMenuItem == null ? void 0 : selectedMenuItem.label) || "";
1044
- const icon = props.icon || (selectedMenuItem == null ? void 0 : selectedMenuItem.icon);
1045
- return (0, import_jsx_runtime13.jsxs)("div", { style: { position: "relative", display: "inline-block" }, ref: containerRef, children: [(0, import_jsx_runtime13.jsx)(IconButton, { className: props.className, label, onClick: handleButtonClick, children: icon }), menuOpen && (0, import_jsx_runtime13.jsx)("div", { className: "deck-widget-icon-menu", children: (0, import_jsx_runtime13.jsx)(ButtonGroup, { orientation: "vertical", children: props.menuItems.map((item) => (0, import_jsx_runtime13.jsx)(GroupedIconButton, { label: item.label, onClick: () => handleSelectItem(item.value), children: item.icon }, item.value)) }) })] });
1188
+ if (placement.startsWith("bottom")) {
1189
+ result.borderLeft = `${width / 2}px solid transparent`;
1190
+ result.borderRight = `${width / 2}px solid transparent`;
1191
+ result.borderBottom = `${height}px solid ${color}`;
1192
+ result.borderTop = "";
1193
+ result.top = `${-height}px`;
1194
+ } else if (placement.startsWith("top")) {
1195
+ result.borderLeft = `${width / 2}px solid transparent`;
1196
+ result.borderRight = `${width / 2}px solid transparent`;
1197
+ result.borderTop = `${height}px solid ${color}`;
1198
+ result.borderBottom = "";
1199
+ result.bottom = `${-height}px`;
1200
+ } else if (placement.startsWith("right")) {
1201
+ result.borderTop = `${width / 2}px solid transparent`;
1202
+ result.borderBottom = `${width / 2}px solid transparent`;
1203
+ result.borderRight = `${height}px solid ${color}`;
1204
+ result.borderLeft = "";
1205
+ result.left = `${-height}px`;
1206
+ } else if (placement.startsWith("left")) {
1207
+ result.borderTop = `${width / 2}px solid transparent`;
1208
+ result.borderBottom = `${width / 2}px solid transparent`;
1209
+ result.borderLeft = `${height}px solid ${color}`;
1210
+ result.borderRight = "";
1211
+ result.right = `${-height}px`;
1212
+ }
1213
+ return result;
1046
1214
  }
1047
1215
 
1048
- // dist/view-selector-widget.js
1049
- var ViewSelectorWidget = class extends import_core10.Widget {
1050
- constructor(props = {}) {
1051
- super(props);
1052
- this.className = "deck-widget-view-selector";
1053
- this.placement = "top-left";
1054
- this.handleSelectMode = (viewMode) => {
1055
- this.viewMode = viewMode;
1056
- this.updateHTML();
1057
- this.props.onViewModeChange(viewMode);
1216
+ // dist/lib/components/user-content.js
1217
+ var import_jsx_runtime13 = require("preact/jsx-runtime");
1218
+ var import_hooks5 = require("preact/hooks");
1219
+ var UserContent = ({ text, html, element, ...props }) => {
1220
+ const containerRef = (0, import_hooks5.useRef)(null);
1221
+ (0, import_hooks5.useEffect)(() => {
1222
+ if (containerRef.current && element) {
1223
+ containerRef.current.append(element);
1224
+ }
1225
+ return () => {
1226
+ element == null ? void 0 : element.remove();
1058
1227
  };
1059
- this.viewMode = this.props.initialViewMode;
1228
+ }, [element]);
1229
+ return (0, import_jsx_runtime13.jsx)("div", { ref: containerRef, ...props, dangerouslySetInnerHTML: html ? { __html: html } : void 0, children: text });
1230
+ };
1231
+
1232
+ // dist/info-widget.js
1233
+ var InfoWidget = class extends import_core10.Widget {
1234
+ constructor(props) {
1235
+ super(props);
1236
+ this.className = "deck-widget-info";
1237
+ this.placement = "fill";
1238
+ this.tooltip = null;
1060
1239
  this.setProps(this.props);
1061
1240
  }
1062
1241
  setProps(props) {
1063
- this.placement = props.placement ?? this.placement;
1064
1242
  this.viewId = props.viewId ?? this.viewId;
1065
1243
  super.setProps(props);
1066
1244
  }
1245
+ onAdd({ deck }) {
1246
+ this.deck = deck;
1247
+ }
1248
+ onRemove() {
1249
+ if (this.rootElement) {
1250
+ (0, import_preact9.render)(null, this.rootElement);
1251
+ }
1252
+ }
1253
+ onViewportChange(viewport) {
1254
+ this.viewport = viewport;
1255
+ this.updateHTML();
1256
+ }
1257
+ onHover(info) {
1258
+ if (this.props.mode === "hover") {
1259
+ this.tooltip = this._getTooltip(info);
1260
+ }
1261
+ }
1262
+ onClick(info) {
1263
+ if (this.props.mode === "click") {
1264
+ this.tooltip = this._getTooltip(info);
1265
+ }
1266
+ }
1267
+ _getTooltip(info) {
1268
+ if (!this.props.getTooltip)
1269
+ return null;
1270
+ const content = this.props.getTooltip(info, this) ?? null;
1271
+ if (content === null)
1272
+ return null;
1273
+ const normalizedTooltip = typeof content === "string" ? { text: content } : content;
1274
+ const position = normalizedTooltip.position || info.coordinate;
1275
+ if (!position)
1276
+ return null;
1277
+ return {
1278
+ position,
1279
+ text: "",
1280
+ html: "",
1281
+ element: null,
1282
+ className: "",
1283
+ style: {},
1284
+ ...normalizedTooltip
1285
+ };
1286
+ }
1067
1287
  onRenderHTML(rootElement) {
1068
- (0, import_preact9.render)((0, import_jsx_runtime14.jsx)(IconMenu, { className: "deck-widget-view-selector", menuItems: MENU_ITEMS.map((item) => ({
1069
- ...item,
1070
- icon: item.icon()
1071
- })), initialItem: this.props.initialViewMode, onItemSelected: this.handleSelectMode }), rootElement);
1288
+ if (!this.viewport || this.tooltip === null) {
1289
+ (0, import_preact9.render)(null, rootElement);
1290
+ return;
1291
+ }
1292
+ const style = {
1293
+ ...this.props.style,
1294
+ ...this.tooltip.style
1295
+ };
1296
+ const [x, y] = this.viewport.project(this.tooltip.position);
1297
+ const ui = (0, import_jsx_runtime14.jsx)(Popover, { x, y, placement: this.props.placement, arrow: this.props.arrow, arrowColor: "var(--menu-background, #fff)", offset: this.props.offset, children: (0, import_jsx_runtime14.jsx)(UserContent, { className: `deck-widget-popup-content ${this.tooltip.className} ${this.props.className}`, style, html: this.tooltip.html, text: this.tooltip.text, element: this.tooltip.element }) });
1298
+ (0, import_preact9.render)(ui, rootElement);
1072
1299
  }
1073
1300
  };
1074
- ViewSelectorWidget.defaultProps = {
1301
+ InfoWidget.defaultProps = {
1075
1302
  ...import_core10.Widget.defaultProps,
1076
- id: "view-selector",
1077
- placement: "top-left",
1303
+ id: "info",
1078
1304
  viewId: null,
1079
- label: "Split View",
1080
- initialViewMode: "single",
1081
- onViewModeChange: () => {
1082
- }
1083
- };
1084
- var ICON_STYLE = { width: "24px", height: "24px" };
1085
- var ICONS = {
1086
- single: () => (0, import_jsx_runtime14.jsx)("svg", { width: "24", height: "24", style: ICON_STYLE, children: (0, import_jsx_runtime14.jsx)("rect", { x: "4", y: "4", width: "16", height: "16", stroke: "var(--button-icon-hover, rgb(24, 24, 26))", fill: "none", strokeWidth: "2" }) }),
1087
- "split-horizontal": () => (0, import_jsx_runtime14.jsxs)("svg", { width: "24", height: "24", style: ICON_STYLE, children: [(0, import_jsx_runtime14.jsx)("rect", { x: "4", y: "4", width: "16", height: "7", stroke: "var(--button-icon-hover, rgb(24, 24, 26))", fill: "none", strokeWidth: "2" }), (0, import_jsx_runtime14.jsx)("rect", { x: "4", y: "13", width: "16", height: "7", stroke: "var(--button-icon-hover, rgb(24, 24, 26))", fill: "none", strokeWidth: "2" })] }),
1088
- "split-vertical": () => (0, import_jsx_runtime14.jsxs)("svg", { width: "24", height: "24", style: ICON_STYLE, children: [(0, import_jsx_runtime14.jsx)("rect", { x: "4", y: "4", width: "7", height: "16", stroke: "var(--button-icon-hover, rgb(24, 24, 26))", fill: "none", strokeWidth: "2" }), (0, import_jsx_runtime14.jsx)("rect", { x: "13", y: "4", width: "7", height: "16", stroke: "var(--button-icon-hover, rgb(24, 24, 26))", fill: "none", strokeWidth: "2" })] })
1089
- };
1090
- var MENU_ITEMS = [
1091
- { value: "single", icon: ICONS.single, label: "Single View" },
1092
- { value: "split-horizontal", icon: ICONS["split-horizontal"], label: "Split Horizontal" },
1093
- { value: "split-vertical", icon: ICONS["split-vertical"], label: "Split Vertical" }
1094
- ];
1305
+ mode: "hover",
1306
+ getTooltip: void 0,
1307
+ placement: "right",
1308
+ offset: 10,
1309
+ arrow: 10
1310
+ };
1095
1311
 
1096
- // dist/info-widget.js
1312
+ // dist/popup-widget.js
1097
1313
  var import_jsx_runtime15 = require("preact/jsx-runtime");
1098
1314
  var import_core11 = require("@deck.gl/core");
1099
1315
  var import_preact10 = require("preact");
1100
- var InfoWidget = class extends import_core11.Widget {
1316
+ var PopupWidget = class extends import_core11.Widget {
1101
1317
  constructor(props) {
1102
1318
  super(props);
1103
- this.className = "deck-widget-info";
1319
+ this.className = "deck-widget-popup";
1104
1320
  this.placement = "fill";
1105
1321
  this.setProps(this.props);
1322
+ this.isOpen = this.props.defaultIsOpen;
1106
1323
  }
1107
1324
  setProps(props) {
1108
1325
  this.viewId = props.viewId ?? this.viewId;
1109
1326
  super.setProps(props);
1110
1327
  }
1111
- onCreateRootElement() {
1112
- const element = super.onCreateRootElement();
1113
- const style = { margin: "0px", top: "0px", left: "0px", position: "absolute" };
1114
- Object.entries(style).forEach(([key, value]) => element.style.setProperty(key, value));
1115
- return element;
1328
+ onAdd({ deck }) {
1329
+ this.deck = deck;
1330
+ }
1331
+ onRemove() {
1332
+ if (this.rootElement) {
1333
+ (0, import_preact10.render)(null, this.rootElement);
1334
+ }
1116
1335
  }
1117
1336
  onViewportChange(viewport) {
1118
1337
  this.viewport = viewport;
1119
1338
  this.updateHTML();
1120
1339
  }
1121
- onHover(info) {
1122
- if (this.props.mode === "hover" && this.props.getTooltip) {
1123
- const tooltip = this.props.getTooltip(info, this);
1124
- this.setProps({
1125
- visible: tooltip !== null,
1126
- ...tooltip,
1127
- style: { zIndex: "1", ...tooltip == null ? void 0 : tooltip.style }
1128
- });
1340
+ onClick() {
1341
+ if (this.props.closeOnClickOutside) {
1342
+ this._setIsOpen(false);
1129
1343
  }
1130
1344
  }
1131
- onClick(info) {
1345
+ _setIsOpen(isOpen) {
1132
1346
  var _a, _b;
1133
- if (this.props.mode === "click" && this.props.getTooltip) {
1134
- const tooltip = this.props.getTooltip(info, this);
1135
- this.setProps({
1136
- visible: tooltip !== null,
1137
- ...tooltip
1138
- });
1139
- return tooltip !== null;
1140
- }
1141
- return ((_b = (_a = this.props).onClick) == null ? void 0 : _b.call(_a, this, info)) || false;
1142
- }
1143
- onAdd({ deck, viewId }) {
1144
- this.deck = deck;
1145
- if (!viewId) {
1146
- this.viewport = deck.getViewports()[0];
1147
- } else {
1148
- this.viewport = deck.getViewports().find((viewport) => viewport.id === viewId);
1149
- }
1347
+ if (this.isOpen === isOpen)
1348
+ return;
1349
+ this.isOpen = isOpen;
1350
+ (_b = (_a = this.props).onOpenChange) == null ? void 0 : _b.call(_a, isOpen);
1351
+ this.updateHTML();
1150
1352
  }
1151
1353
  onRenderHTML(rootElement) {
1152
1354
  if (!this.viewport) {
1355
+ (0, import_preact10.render)(null, rootElement);
1153
1356
  return;
1154
1357
  }
1155
- const [longitude, latitude] = this.props.position;
1156
- const [x, y] = this.viewport.project([longitude, latitude]);
1157
- const minOffset = this.props.minOffset || 0;
1158
- const gap = 10;
1159
- const arrowHeight = 8;
1160
- const arrowWidth = 16;
1161
- const isAbove = y > this.viewport.height / 2;
1162
- const background = this.props.style && this.props.style.background || "rgba(255,255,255,0.9)";
1163
- const ui = this.props.visible ? (0, import_jsx_runtime15.jsxs)("div", { className: "popup-container", style: { position: "absolute", left: 0, top: 0 }, children: [(0, import_jsx_runtime15.jsx)("div", { className: "popup-content", style: {
1164
- background,
1165
- padding: "10px",
1166
- position: "relative",
1167
- // Include any additional styles
1168
- ...this.props.style
1169
- }, children: this.props.text }), (0, import_jsx_runtime15.jsx)("div", { className: "popup-arrow", style: { position: "absolute", width: "0px", height: "0px" } })] }) : null;
1358
+ const { marker, content, style } = this.props;
1359
+ const [x, y] = this.viewport.project(this.props.position);
1360
+ const ui = (0, import_jsx_runtime15.jsxs)("div", { children: [marker && (0, import_jsx_runtime15.jsx)("div", { style: { position: "absolute", left: x, top: y, pointerEvents: "all", cursor: "pointer" }, children: (0, import_jsx_runtime15.jsx)(UserContent, { ...marker, onClick: () => this._setIsOpen(true) }) }), this.isOpen && (0, import_jsx_runtime15.jsx)(Popover, { x, y, placement: this.props.placement, arrow: this.props.arrow, arrowColor: "var(--menu-background, #fff)", offset: this.props.offset, children: (0, import_jsx_runtime15.jsxs)("div", { className: `deck-widget-popup-content ${this.props.className}`, style, children: [this.props.closeButton && (0, import_jsx_runtime15.jsx)("div", { className: "deck-widget-popup-controls", style: { width: "100%", display: "flex", justifyContent: "end" }, children: (0, import_jsx_runtime15.jsx)(IconButton, { className: "deck-widget-popup-close-button", onClick: () => this._setIsOpen(false) }) }), (0, import_jsx_runtime15.jsx)(UserContent, { ...typeof content === "string" ? { text: content } : content })] }) })] });
1170
1361
  (0, import_preact10.render)(ui, rootElement);
1171
- requestAnimationFrame(() => {
1172
- if (!this.props.visible || !rootElement.firstChild || !this.viewport)
1173
- return;
1174
- const container = rootElement.firstChild;
1175
- const contentEl = container.querySelector(".popup-content");
1176
- const arrowEl = container.querySelector(".popup-arrow");
1177
- if (!contentEl || !arrowEl)
1178
- return;
1179
- const contentRect = contentEl.getBoundingClientRect();
1180
- const popupWidth = contentRect.width;
1181
- const popupHeight = contentRect.height;
1182
- let computedLeft = x - popupWidth / 2;
1183
- let computedTop;
1184
- if (isAbove) {
1185
- computedTop = y - gap - arrowHeight - popupHeight;
1186
- } else {
1187
- computedTop = y + gap + arrowHeight;
1188
- }
1189
- if (computedLeft < minOffset) {
1190
- computedLeft = minOffset;
1191
- }
1192
- if (computedLeft + popupWidth > this.viewport.width - minOffset) {
1193
- computedLeft = this.viewport.width - minOffset - popupWidth;
1194
- }
1195
- if (isAbove) {
1196
- if (computedTop < minOffset) {
1197
- computedTop = minOffset;
1198
- }
1199
- } else if (computedTop + popupHeight + arrowHeight > this.viewport.height - minOffset) {
1200
- computedTop = this.viewport.height - minOffset - popupHeight - arrowHeight;
1201
- }
1202
- container.style.left = `${computedLeft}px`;
1203
- container.style.top = `${computedTop}px`;
1204
- container.style.transform = "";
1205
- let arrowLeft = x - computedLeft - arrowWidth / 2;
1206
- arrowLeft = Math.max(arrowLeft, 0);
1207
- arrowLeft = Math.min(arrowLeft, popupWidth - arrowWidth);
1208
- if (isAbove) {
1209
- arrowEl.style.left = `${arrowLeft}px`;
1210
- arrowEl.style.bottom = `-${arrowHeight}px`;
1211
- arrowEl.style.top = "";
1212
- arrowEl.style.borderLeft = `${arrowWidth / 2}px solid transparent`;
1213
- arrowEl.style.borderRight = `${arrowWidth / 2}px solid transparent`;
1214
- arrowEl.style.borderTop = `${arrowHeight}px solid ${background}`;
1215
- arrowEl.style.borderBottom = "";
1216
- } else {
1217
- arrowEl.style.left = `${arrowLeft}px`;
1218
- arrowEl.style.top = `-${arrowHeight}px`;
1219
- arrowEl.style.bottom = "";
1220
- arrowEl.style.borderLeft = `${arrowWidth / 2}px solid transparent`;
1221
- arrowEl.style.borderRight = `${arrowWidth / 2}px solid transparent`;
1222
- arrowEl.style.borderBottom = `${arrowHeight}px solid ${background}`;
1223
- arrowEl.style.borderTop = "";
1224
- }
1225
- });
1226
1362
  }
1227
1363
  };
1228
- InfoWidget.defaultProps = {
1364
+ PopupWidget.defaultProps = {
1229
1365
  ...import_core11.Widget.defaultProps,
1230
1366
  id: "info",
1231
- position: [0, 0],
1232
- text: "",
1233
- visible: false,
1234
- minOffset: 0,
1235
1367
  viewId: null,
1236
- mode: "hover",
1237
- getTooltip: void 0,
1238
- onClick: void 0
1368
+ position: [0, 0],
1369
+ marker: null,
1370
+ defaultIsOpen: true,
1371
+ content: "",
1372
+ placement: "right",
1373
+ offset: 10,
1374
+ arrow: 10,
1375
+ closeButton: true,
1376
+ closeOnClickOutside: false,
1377
+ onOpenChange: () => {
1378
+ }
1239
1379
  };
1240
1380
 
1241
1381
  // dist/context-menu-widget.js
1242
- var import_jsx_runtime17 = require("preact/jsx-runtime");
1382
+ var import_jsx_runtime16 = require("preact/jsx-runtime");
1243
1383
  var import_core12 = require("@deck.gl/core");
1244
1384
  var import_preact11 = require("preact");
1245
-
1246
- // dist/lib/components/simple-menu.js
1247
- var import_jsx_runtime16 = require("preact/jsx-runtime");
1248
- var MENU_STYLE = {
1249
- position: "absolute",
1250
- top: "100%",
1251
- left: 0,
1252
- background: "white",
1253
- border: "1px solid #ccc",
1254
- borderRadius: "4px",
1255
- marginTop: "var(--menu-gap, 4px)",
1256
- zIndex: 100
1257
- };
1258
- var MENU_ITEM_STYLE = {
1259
- background: "white",
1260
- border: "none",
1261
- padding: "4px",
1262
- cursor: "pointer",
1263
- pointerEvents: "auto"
1264
- };
1265
- var SimpleMenu = (props) => {
1266
- const { menuItems, onItemSelected, position, style } = props;
1267
- const styleOverride = {
1268
- ...MENU_STYLE,
1269
- ...style,
1270
- left: `${position.x}px`,
1271
- top: `${position.y}px`
1272
- };
1273
- return (0, import_jsx_runtime16.jsx)("div", { style: styleOverride, children: menuItems.map(({ key, label }) => (0, import_jsx_runtime16.jsx)("button", { style: { ...MENU_ITEM_STYLE, display: "block" }, onClick: (_) => onItemSelected(key), children: label }, key)) });
1274
- };
1275
-
1276
- // dist/context-menu-widget.js
1277
- var MOUSE_BUTTON_RIGHT = 2;
1278
- var MOUSE_WHICH_RIGHT = 3;
1279
1385
  var ContextMenuWidget = class extends import_core12.Widget {
1280
1386
  constructor(props) {
1281
1387
  super(props);
1282
1388
  this.className = "deck-widget-context-menu";
1283
1389
  this.placement = "fill";
1284
- this.pickInfo = null;
1285
- this.pickInfo = null;
1390
+ this.menu = null;
1286
1391
  this.setProps(this.props);
1287
1392
  }
1288
1393
  onAdd({ deck }) {
1289
- var _a, _b;
1290
- const element = document.createElement("div");
1291
- element.classList.add("deck-widget", "deck-widget-context-menu");
1292
- const style = {
1293
- margin: "0px",
1294
- top: "0px",
1295
- left: "0px",
1296
- position: "absolute",
1297
- pointerEvents: "auto"
1394
+ var _a;
1395
+ (_a = deck.getCanvas()) == null ? void 0 : _a.addEventListener("contextmenu", (event) => this.handleContextMenu(event));
1396
+ }
1397
+ handleContextMenu(srcEvent) {
1398
+ var _a, _b, _c;
1399
+ const targetRect = srcEvent.target.getBoundingClientRect();
1400
+ const x = srcEvent.clientX - targetRect.x;
1401
+ const y = srcEvent.clientY - targetRect.y;
1402
+ const pickInfo = ((_a = this.deck) == null ? void 0 : _a.pickObject({ x, y })) || {
1403
+ x,
1404
+ y,
1405
+ picked: false,
1406
+ layer: null,
1407
+ color: null,
1408
+ index: -1,
1409
+ pixelRatio: 1
1298
1410
  };
1299
- Object.entries(style).forEach(([key, value]) => element.style.setProperty(key, value));
1300
- (_a = deck.getCanvas()) == null ? void 0 : _a.addEventListener("click", () => this.hide());
1301
- (_b = deck.getCanvas()) == null ? void 0 : _b.addEventListener("contextmenu", (event) => this.handleContextMenu(event));
1302
- return element;
1411
+ const menuItems = ((_c = (_b = this.props).getMenuItems) == null ? void 0 : _c.call(_b, pickInfo, this)) || this.props.menuItems;
1412
+ this.menu = menuItems.length > 0 ? {
1413
+ items: menuItems,
1414
+ pickInfo
1415
+ } : null;
1416
+ srcEvent.preventDefault();
1417
+ this.updateHTML();
1303
1418
  }
1304
1419
  onRenderHTML(rootElement) {
1305
- const { visible, position, menuItems } = this.props;
1306
- const ui = visible && menuItems.length ? (0, import_jsx_runtime17.jsx)(SimpleMenu, { menuItems, onItemSelected: (key) => this.props.onMenuItemSelected(key, this.pickInfo), position, style: { pointerEvents: "auto" } }) : null;
1420
+ if (!this.menu) {
1421
+ (0, import_preact11.render)(null, rootElement);
1422
+ return;
1423
+ }
1424
+ const { items, pickInfo } = this.menu;
1425
+ const style = {
1426
+ pointerEvents: "auto",
1427
+ position: "static",
1428
+ ...this.props.style
1429
+ };
1430
+ const ui = (0, import_jsx_runtime16.jsx)(Popover, { x: pickInfo.x, y: pickInfo.y, placement: this.props.placement, arrow: this.props.arrow, arrowColor: "var(--menu-background, #fff)", offset: this.props.offset, children: (0, import_jsx_runtime16.jsx)(SimpleMenu, { menuItems: items, onSelect: (value) => this.props.onMenuItemSelected(value, pickInfo), style, isOpen: true, onClose: () => this.hide() }) });
1307
1431
  (0, import_preact11.render)(ui, rootElement);
1308
1432
  }
1309
- handleContextMenu(srcEvent) {
1310
- var _a, _b, _c;
1311
- if (srcEvent && (srcEvent.button === MOUSE_BUTTON_RIGHT || srcEvent.which === MOUSE_WHICH_RIGHT)) {
1312
- this.pickInfo = ((_a = this.deck) == null ? void 0 : _a.pickObject({
1313
- x: srcEvent.clientX,
1314
- y: srcEvent.clientY
1315
- })) || null;
1316
- const menuItems = this.pickInfo && ((_c = (_b = this.props).getMenuItems) == null ? void 0 : _c.call(_b, this.pickInfo, this)) || [];
1317
- const visible = menuItems.length > 0;
1318
- this.setProps({
1319
- visible,
1320
- position: { x: srcEvent.clientX, y: srcEvent.clientY },
1321
- menuItems
1322
- });
1323
- this.updateHTML();
1324
- srcEvent.preventDefault();
1325
- return visible;
1326
- }
1327
- return false;
1328
- }
1329
1433
  hide() {
1330
- this.setProps({ visible: false });
1434
+ this.menu = null;
1435
+ this.updateHTML();
1331
1436
  }
1332
1437
  };
1333
1438
  ContextMenuWidget.defaultProps = {
1334
1439
  ...import_core12.Widget.defaultProps,
1335
1440
  id: "context",
1336
1441
  viewId: null,
1337
- visible: false,
1338
- position: { x: 0, y: 0 },
1339
- getMenuItems: void 0,
1340
1442
  menuItems: [],
1341
- // eslint-disable-next-line no-console
1342
- onMenuItemSelected: (key, pickInfo) => console.log("Context menu item selected:", key, pickInfo)
1443
+ getMenuItems: void 0,
1444
+ onMenuItemSelected: () => {
1445
+ },
1446
+ placement: "bottom-start",
1447
+ offset: 10,
1448
+ arrow: false
1343
1449
  };
1344
1450
 
1345
- // dist/timeline-widget.js
1451
+ // dist/scrollbar-widget.js
1346
1452
  var import_jsx_runtime18 = require("preact/jsx-runtime");
1347
1453
  var import_core13 = require("@deck.gl/core");
1348
1454
  var import_preact12 = require("preact");
1349
- var TimelineWidget = class extends import_core13.Widget {
1455
+
1456
+ // dist/lib/components/range-input.js
1457
+ var import_jsx_runtime17 = require("preact/jsx-runtime");
1458
+ var import_hooks6 = require("preact/hooks");
1459
+ var wheelListenerOptions = { passive: false };
1460
+ var clamp = (value, min, max) => {
1461
+ if (value < min) {
1462
+ return min;
1463
+ }
1464
+ if (value > max) {
1465
+ return max;
1466
+ }
1467
+ return value;
1468
+ };
1469
+ var getTrackDimension = (track, vertical) => {
1470
+ if (!track || !track.firstElementChild) {
1471
+ return [0, 0];
1472
+ }
1473
+ const rect = track.firstElementChild.getBoundingClientRect();
1474
+ if (vertical) {
1475
+ return [rect.top, rect.height];
1476
+ }
1477
+ return vertical ? [rect.top, rect.height] : [rect.left, rect.width];
1478
+ };
1479
+ var getEffectiveStep = (step, range) => {
1480
+ if (typeof step === "number" && !Number.isNaN(step) && step > 0) {
1481
+ return step;
1482
+ }
1483
+ return Math.max(1, range / 10 || 1);
1484
+ };
1485
+ var getEffectivePage = (pageSize, rangeSize) => {
1486
+ if (typeof pageSize === "number" && !Number.isNaN(pageSize) && pageSize > 0) {
1487
+ return pageSize;
1488
+ }
1489
+ return Math.max(1, rangeSize || 1);
1490
+ };
1491
+ function RangeInput(props) {
1492
+ const { className = "", min, max, step, value, orientation, pageSize, stepButtons = false, startButtonAriaLabel, endButtonAriaLabel, eventTarget, decorations = [], onChange } = props;
1493
+ const vertical = orientation !== "horizontal";
1494
+ const rootRef = (0, import_hooks6.useRef)(null);
1495
+ const trackRef = (0, import_hooks6.useRef)(null);
1496
+ const thumbRef = (0, import_hooks6.useRef)(null);
1497
+ const dragStateRef = (0, import_hooks6.useRef)(null);
1498
+ const [trackLength, setTrackLength] = (0, import_hooks6.useState)(0);
1499
+ const range = max - min;
1500
+ const rangeSize = Math.max(0, value[1] - value[0]);
1501
+ const maxStart = Math.max(0, range - rangeSize);
1502
+ const clampedStart = clamp(value[0], min, min + maxStart);
1503
+ const { thumbLength, thumbOffset } = (0, import_hooks6.useMemo)(() => {
1504
+ if (trackLength <= 0 || range <= 0) {
1505
+ return { thumbLength: 0, thumbOffset: 0 };
1506
+ }
1507
+ if (range <= rangeSize) {
1508
+ return { thumbLength: 1, thumbOffset: 0 };
1509
+ }
1510
+ const nextThumbLength = rangeSize / range;
1511
+ const travel = Math.max(0, 1 - nextThumbLength);
1512
+ const ratio = maxStart <= 0 ? 0 : clamp((clampedStart - min) / maxStart, 0, 1);
1513
+ return {
1514
+ thumbLength: Math.max(0, Math.min(nextThumbLength, 1)),
1515
+ thumbOffset: travel * ratio
1516
+ };
1517
+ }, [trackLength, range, rangeSize, maxStart, clampedStart, min]);
1518
+ const emitRange = (0, import_hooks6.useCallback)((nextStart) => {
1519
+ if (!onChange) {
1520
+ return;
1521
+ }
1522
+ const clamped = clamp(nextStart, min, min + maxStart);
1523
+ onChange([clamped, clamped + rangeSize]);
1524
+ }, [onChange, min, maxStart, rangeSize]);
1525
+ const handleStepNegative = (0, import_hooks6.useCallback)((event) => {
1526
+ event.stopPropagation();
1527
+ emitRange(clampedStart - getEffectiveStep(step, range));
1528
+ }, [emitRange, clampedStart, step, range]);
1529
+ const handleStepPositive = (0, import_hooks6.useCallback)((event) => {
1530
+ event.stopPropagation();
1531
+ emitRange(clampedStart + getEffectiveStep(step, range));
1532
+ }, [emitRange, clampedStart, step, range]);
1533
+ const handleTrackClick = (0, import_hooks6.useCallback)((event) => {
1534
+ if (event.button !== 0) {
1535
+ return;
1536
+ }
1537
+ const target = event.target;
1538
+ if ((target == null ? void 0 : target.dataset.scrollbarThumb) === "true") {
1539
+ return;
1540
+ }
1541
+ const track = trackRef.current;
1542
+ if (!track) {
1543
+ return;
1544
+ }
1545
+ event.preventDefault();
1546
+ event.stopPropagation();
1547
+ const [trackStart] = getTrackDimension(track, vertical);
1548
+ const coordinate = vertical ? event.clientY - trackStart : event.clientX - trackStart;
1549
+ const span = Math.max(1, 1 - thumbLength) * trackLength;
1550
+ const thumbCenter = thumbLength / 2 * trackLength;
1551
+ const ratio = span <= 0 ? 0 : clamp((coordinate - thumbCenter) / span, 0, 1);
1552
+ emitRange(min + ratio * maxStart);
1553
+ }, [vertical, trackLength, thumbLength, emitRange, min, maxStart]);
1554
+ const handleThumbPointerDown = (event) => {
1555
+ if (event.button !== 0) {
1556
+ return;
1557
+ }
1558
+ const track = trackRef.current;
1559
+ if (!track) {
1560
+ return;
1561
+ }
1562
+ dragStateRef.current = {
1563
+ pointerId: event.pointerId,
1564
+ startCoord: vertical ? event.clientY : event.clientX,
1565
+ startRatio: thumbOffset,
1566
+ min,
1567
+ max,
1568
+ maxStart
1569
+ };
1570
+ event.currentTarget.setPointerCapture(event.pointerId);
1571
+ event.preventDefault();
1572
+ event.stopPropagation();
1573
+ };
1574
+ const handleThumbPointerMove = (0, import_hooks6.useCallback)((event) => {
1575
+ const state = dragStateRef.current;
1576
+ if (!state || state.pointerId !== event.pointerId) {
1577
+ return;
1578
+ }
1579
+ const [trackStart, trackLength2] = getTrackDimension(trackRef.current, vertical);
1580
+ const coordinate = vertical ? event.clientY : event.clientX;
1581
+ const delta = coordinate - state.startCoord;
1582
+ const ratio = state.startRatio + delta / trackLength2;
1583
+ const nextStart = clamp(ratio * (state.max - state.min), 0, state.maxStart) + state.min;
1584
+ emitRange(nextStart);
1585
+ event.preventDefault();
1586
+ }, [emitRange, vertical]);
1587
+ const handleThumbPointerUp = (0, import_hooks6.useCallback)((event) => {
1588
+ var _a;
1589
+ const state = dragStateRef.current;
1590
+ if (state && state.pointerId === event.pointerId) {
1591
+ dragStateRef.current = null;
1592
+ (_a = thumbRef.current) == null ? void 0 : _a.releasePointerCapture(event.pointerId);
1593
+ event.preventDefault();
1594
+ }
1595
+ }, []);
1596
+ const handleKeyDown = (0, import_hooks6.useCallback)((event) => {
1597
+ switch (event.key) {
1598
+ case "ArrowUp":
1599
+ case "ArrowLeft":
1600
+ if (vertical && event.key === "ArrowUp" || !vertical && event.key === "ArrowLeft") {
1601
+ emitRange(clampedStart - getEffectiveStep(step, range));
1602
+ event.preventDefault();
1603
+ }
1604
+ break;
1605
+ case "ArrowDown":
1606
+ case "ArrowRight":
1607
+ if (vertical && event.key === "ArrowDown" || !vertical && event.key === "ArrowRight") {
1608
+ emitRange(clampedStart + getEffectiveStep(step, range));
1609
+ event.preventDefault();
1610
+ }
1611
+ break;
1612
+ case "PageUp":
1613
+ emitRange(clampedStart - getEffectivePage(pageSize, rangeSize));
1614
+ event.preventDefault();
1615
+ break;
1616
+ case "PageDown":
1617
+ emitRange(clampedStart + getEffectivePage(pageSize, rangeSize));
1618
+ event.preventDefault();
1619
+ break;
1620
+ case "Home":
1621
+ emitRange(min);
1622
+ event.preventDefault();
1623
+ break;
1624
+ case "End":
1625
+ emitRange(min + maxStart);
1626
+ event.preventDefault();
1627
+ break;
1628
+ default:
1629
+ break;
1630
+ }
1631
+ }, [vertical, emitRange, clampedStart, step, range, pageSize, rangeSize, min, maxStart]);
1632
+ const handleWheel = (0, import_hooks6.useCallback)((event) => {
1633
+ event.preventDefault();
1634
+ event.stopPropagation();
1635
+ if (maxStart === 0) {
1636
+ return;
1637
+ }
1638
+ let delta = vertical ? event.deltaY : event.deltaX;
1639
+ if (!vertical && delta === 0) {
1640
+ delta = event.deltaY;
1641
+ }
1642
+ if (event.deltaMode === WheelEvent.DOM_DELTA_LINE) {
1643
+ delta *= getEffectiveStep(step, range);
1644
+ } else if (event.deltaMode === WheelEvent.DOM_DELTA_PAGE) {
1645
+ delta *= getEffectivePage(pageSize, rangeSize);
1646
+ }
1647
+ if (delta === 0) {
1648
+ return;
1649
+ }
1650
+ emitRange(clampedStart + delta);
1651
+ }, [emitRange, clampedStart, maxStart, vertical, step, range, pageSize, rangeSize]);
1652
+ (0, import_hooks6.useLayoutEffect)(() => {
1653
+ setTrackLength(getTrackDimension(trackRef.current, vertical)[1]);
1654
+ }, [vertical]);
1655
+ (0, import_hooks6.useLayoutEffect)(() => {
1656
+ const track = trackRef.current;
1657
+ if (!track) {
1658
+ return void 0;
1659
+ }
1660
+ const update = () => {
1661
+ setTrackLength(getTrackDimension(track, vertical)[1]);
1662
+ };
1663
+ update();
1664
+ if (typeof ResizeObserver !== "undefined") {
1665
+ const observer = new ResizeObserver(update);
1666
+ observer.observe(track);
1667
+ return () => observer.disconnect();
1668
+ }
1669
+ if (typeof window !== "undefined") {
1670
+ window.addEventListener("resize", update);
1671
+ return () => window.removeEventListener("resize", update);
1672
+ }
1673
+ return void 0;
1674
+ }, [vertical]);
1675
+ (0, import_hooks6.useEffect)(() => {
1676
+ const eventRoot = eventTarget ?? rootRef.current;
1677
+ if (!eventRoot)
1678
+ return void 0;
1679
+ eventRoot.addEventListener("keydown", handleKeyDown);
1680
+ eventRoot.addEventListener("wheel", handleWheel, wheelListenerOptions);
1681
+ return () => {
1682
+ eventRoot.removeEventListener("keydown", handleKeyDown);
1683
+ eventRoot.removeEventListener("wheel", handleWheel, wheelListenerOptions);
1684
+ };
1685
+ }, [eventTarget, handleKeyDown, handleWheel]);
1686
+ const decorationElements = (0, import_hooks6.useMemo)(() => {
1687
+ if (!decorations.length || range <= 0) {
1688
+ return [];
1689
+ }
1690
+ return decorations.map((decoration, index) => {
1691
+ const [start, end] = decoration.position;
1692
+ const startRatio = (start - min) / range;
1693
+ const endRatio = (end - min) / range;
1694
+ const offsetPct = Math.round(startRatio * 1e3) / 10;
1695
+ const sizePct = Math.max(0, Math.round((endRatio - startRatio) * 1e3) / 10);
1696
+ const style = vertical ? {
1697
+ left: "0",
1698
+ width: "100%",
1699
+ top: `${offsetPct}%`,
1700
+ height: `${sizePct}%`
1701
+ } : {
1702
+ top: "0",
1703
+ height: "100%",
1704
+ left: `${offsetPct}%`,
1705
+ width: `${sizePct}%`
1706
+ };
1707
+ return (0, import_jsx_runtime17.jsx)("div", { className: "deck-widget-range__decoration", style, children: decoration.element }, `decoration-${index}`);
1708
+ });
1709
+ }, [decorations, range, min, vertical]);
1710
+ return (0, import_jsx_runtime17.jsxs)("div", { ref: rootRef, tabIndex: 0, role: "scrollbar", "aria-valuemin": min, "aria-valuemax": min + maxStart, "aria-valuenow": clampedStart, "aria-orientation": orientation, className: `${className} deck-widget-range deck-widget-range--${orientation} ${maxStart === 0 ? "deck-widget-range--disabled" : ""}`, children: [stepButtons && (0, import_jsx_runtime17.jsx)("button", { type: "button", className: "deck-widget-range__button deck-widget-range__button--start", "aria-label": startButtonAriaLabel, disabled: clampedStart <= min, onClick: handleStepNegative, children: (0, import_jsx_runtime17.jsx)("span", { className: "deck-widget-icon" }) }), (0, import_jsx_runtime17.jsxs)("div", { className: "deck-widget-range__track", ref: trackRef, onClick: handleTrackClick, children: [(0, import_jsx_runtime17.jsx)("div", { className: "deck-widget-range__decorations", children: decorationElements }), (0, import_jsx_runtime17.jsx)("div", { className: "deck-widget-range__thumb", "data-scrollbar-thumb": "true", ref: thumbRef, style: vertical ? { height: `${thumbLength * 100}%`, top: `${thumbOffset * 100}%` } : { width: `${thumbLength * 100}%`, left: `${thumbOffset * 100}%` }, onPointerDown: handleThumbPointerDown, onPointerMove: handleThumbPointerMove, onPointerUp: handleThumbPointerUp, onPointerCancel: handleThumbPointerUp })] }), stepButtons && (0, import_jsx_runtime17.jsx)("button", { type: "button", className: "deck-widget-range__button deck-widget-range__button--end", "aria-label": endButtonAriaLabel, disabled: clampedStart >= min + maxStart, onClick: handleStepPositive, children: (0, import_jsx_runtime17.jsx)("span", { className: "deck-widget-icon" }) })] });
1711
+ }
1712
+
1713
+ // dist/scrollbar-widget.js
1714
+ var clamp2 = (value, min, max) => {
1715
+ if (value < min) {
1716
+ return min;
1717
+ }
1718
+ if (value > max) {
1719
+ return max;
1720
+ }
1721
+ return value;
1722
+ };
1723
+ var ScrollbarWidget = class extends import_core13.Widget {
1724
+ constructor(props) {
1725
+ const resolved = {
1726
+ ...ScrollbarWidget.defaultProps,
1727
+ ...props
1728
+ };
1729
+ super(resolved);
1730
+ this.className = "deck-widget-scrollbar";
1731
+ this.placement = "fill";
1732
+ this.contentSize = 0;
1733
+ this.viewportSize = 0;
1734
+ this.scrollOffset = 0;
1735
+ this.handleRangeChange = (nextValue) => {
1736
+ this.emitScroll(nextValue[0]);
1737
+ };
1738
+ this.viewId = resolved.viewId ?? null;
1739
+ }
1740
+ onViewportChange(viewport) {
1741
+ this.viewport = viewport;
1742
+ this.onRenderHTML();
1743
+ }
1744
+ onRenderHTML() {
1745
+ const element = this.rootElement;
1746
+ if (!element) {
1747
+ return;
1748
+ }
1749
+ element.dataset.placement = this.props.placement;
1750
+ const viewport = this.viewport;
1751
+ this.updateViewport(viewport);
1752
+ const clampedOffset = this.getClampedOffset();
1753
+ const wheelTarget = this.getWheelEventTarget(this.props.captureWheel ? "global" : "local");
1754
+ const decorations = this.getDecorations(viewport);
1755
+ const isVertical = this.isVertical();
1756
+ const startLabel = this.props.startButtonAriaLabel ?? (isVertical ? "Scroll up" : "Scroll left");
1757
+ const endLabel = this.props.endButtonAriaLabel ?? (isVertical ? "Scroll down" : "Scroll right");
1758
+ const ui = (0, import_jsx_runtime18.jsx)(RangeInput, { min: 0, max: Math.max(0, this.contentSize), step: this.getEffectiveStep(), pageSize: this.getEffectivePage(), value: [clampedOffset, clampedOffset + this.viewportSize], orientation: this.props.orientation, stepButtons: true, startButtonAriaLabel: startLabel, endButtonAriaLabel: endLabel, eventTarget: wheelTarget, decorations, onChange: this.handleRangeChange });
1759
+ (0, import_preact12.render)(ui, element);
1760
+ }
1761
+ onRemove() {
1762
+ if (this.rootElement) {
1763
+ (0, import_preact12.render)(null, this.rootElement);
1764
+ }
1765
+ super.onRemove();
1766
+ }
1767
+ updateViewport(viewport) {
1768
+ if (!viewport) {
1769
+ this.contentSize = 0;
1770
+ this.scrollOffset = 0;
1771
+ this.viewportSize = 0;
1772
+ return;
1773
+ }
1774
+ const { contentBounds } = this.props;
1775
+ const isVertical = this.isVertical();
1776
+ const projectedBounds = contentBounds ? projectBounds(contentBounds, viewport, isVertical) : [0, 0];
1777
+ this.contentSize = projectedBounds[1] - projectedBounds[0];
1778
+ this.scrollOffset = -projectedBounds[0];
1779
+ this.viewportSize = isVertical ? viewport.height : viewport.width;
1780
+ }
1781
+ getDecorations(viewport) {
1782
+ const { decorations = [], contentBounds } = this.props;
1783
+ if (!viewport || !contentBounds || decorations.length === 0) {
1784
+ return [];
1785
+ }
1786
+ const isVertical = this.isVertical();
1787
+ const [contentStart] = projectBounds(contentBounds, viewport, isVertical);
1788
+ return decorations.map((decoration) => {
1789
+ const [start, end] = projectBounds(decoration.contentBounds, viewport, isVertical);
1790
+ const onClick = decoration.onClick ? (e) => {
1791
+ var _a;
1792
+ const handled = (_a = decoration.onClick) == null ? void 0 : _a.call(decoration, e);
1793
+ if (handled) {
1794
+ e.stopPropagation();
1795
+ e.preventDefault();
1796
+ }
1797
+ } : void 0;
1798
+ return {
1799
+ position: [start - contentStart, end - contentStart],
1800
+ element: (0, import_jsx_runtime18.jsx)("div", { style: {
1801
+ pointerEvents: onClick ? "all" : "none",
1802
+ width: "100%",
1803
+ height: "100%",
1804
+ backgroundColor: decoration.color
1805
+ }, title: decoration.title, onClick })
1806
+ };
1807
+ });
1808
+ }
1809
+ getWheelEventTarget(mode) {
1810
+ var _a, _b, _c;
1811
+ if (mode === null)
1812
+ return null;
1813
+ if (mode === "local")
1814
+ return this.rootElement;
1815
+ return ((_a = this.deck) == null ? void 0 : _a.props.parent) || ((_c = (_b = this.deck) == null ? void 0 : _b.getCanvas()) == null ? void 0 : _c.parentElement) || this.rootElement;
1816
+ }
1817
+ getMaxScroll() {
1818
+ return Math.max(0, this.contentSize - this.viewportSize);
1819
+ }
1820
+ getClampedOffset() {
1821
+ const maxScroll = this.getMaxScroll();
1822
+ return clamp2(this.scrollOffset, 0, maxScroll);
1823
+ }
1824
+ isVertical() {
1825
+ return this.props.orientation !== "horizontal";
1826
+ }
1827
+ getEffectiveStep() {
1828
+ if (typeof this.props.stepSize === "number" && !Number.isNaN(this.props.stepSize)) {
1829
+ return this.props.stepSize;
1830
+ }
1831
+ return Math.max(1, this.viewportSize / 10 || 1);
1832
+ }
1833
+ getEffectivePage() {
1834
+ if (typeof this.props.pageSize === "number" && !Number.isNaN(this.props.pageSize)) {
1835
+ return this.props.pageSize;
1836
+ }
1837
+ return this.viewportSize;
1838
+ }
1839
+ emitScroll(next) {
1840
+ const maxScroll = this.getMaxScroll();
1841
+ const target = clamp2(Math.round(next), 0, maxScroll);
1842
+ const viewport = this.viewport;
1843
+ if (viewport && target !== this.getClampedOffset()) {
1844
+ const pixel = viewport.project(viewport.position);
1845
+ if (this.isVertical()) {
1846
+ pixel[1] -= target - this.scrollOffset;
1847
+ } else {
1848
+ pixel[0] -= target - this.scrollOffset;
1849
+ }
1850
+ const { target: newTarget } = viewport.panByPosition(viewport.position, pixel);
1851
+ this.deck._onViewStateChange({
1852
+ viewId: viewport.id,
1853
+ viewState: {
1854
+ ...this.getViewState(viewport.id),
1855
+ target: newTarget
1856
+ },
1857
+ interactionState: {}
1858
+ });
1859
+ }
1860
+ }
1861
+ };
1862
+ ScrollbarWidget.defaultProps = {
1863
+ ...import_core13.Widget.defaultProps,
1864
+ contentBounds: null,
1865
+ placement: "top-right",
1866
+ viewId: null,
1867
+ orientation: "vertical",
1868
+ stepSize: null,
1869
+ pageSize: null,
1870
+ startButtonAriaLabel: "",
1871
+ endButtonAriaLabel: "",
1872
+ captureWheel: false,
1873
+ decorations: []
1874
+ };
1875
+ function projectBounds(bounds, viewport, isVertical) {
1876
+ return bounds.map(([x, y]) => viewport.project([x, y, 0])).reduce((range, [x, y]) => {
1877
+ const value = isVertical ? y : x;
1878
+ range[0] = Math.min(range[0], value);
1879
+ range[1] = Math.max(range[1], value);
1880
+ return range;
1881
+ }, [Infinity, -Infinity]);
1882
+ }
1883
+
1884
+ // dist/icon-widget.js
1885
+ var import_jsx_runtime19 = require("preact/jsx-runtime");
1886
+ var import_preact13 = require("preact");
1887
+ var import_core14 = require("@deck.gl/core");
1888
+ var IconWidget = class extends import_core14.Widget {
1889
+ constructor(props) {
1890
+ super(props);
1891
+ this.className = "";
1892
+ this.placement = "top-left";
1893
+ this.setProps(this.props);
1894
+ }
1895
+ setProps(props) {
1896
+ this.placement = props.placement ?? this.placement;
1897
+ this.viewId = props.viewId;
1898
+ super.setProps(props);
1899
+ }
1900
+ onRenderHTML(rootElement) {
1901
+ const { className, style, icon, color, label, onClick } = this.props;
1902
+ (0, import_preact13.render)((0, import_jsx_runtime19.jsx)(IconButton, { className, style, color, icon, label, onClick }), rootElement);
1903
+ }
1904
+ };
1905
+ IconWidget.defaultProps = {
1906
+ ...import_core14.Widget.defaultProps,
1907
+ id: "icon",
1908
+ placement: "top-left",
1909
+ viewId: null,
1910
+ icon: "",
1911
+ label: "",
1912
+ color: "",
1913
+ onClick: void 0
1914
+ };
1915
+
1916
+ // dist/toggle-widget.js
1917
+ var import_jsx_runtime20 = require("preact/jsx-runtime");
1918
+ var import_preact14 = require("preact");
1919
+ var import_core15 = require("@deck.gl/core");
1920
+ var ToggleWidget = class extends import_core15.Widget {
1921
+ constructor(props) {
1922
+ super(props);
1923
+ this.className = "deck-widget-toggle";
1924
+ this.placement = "top-left";
1925
+ this._toggle = () => {
1926
+ var _a, _b;
1927
+ this.checked = !this.checked;
1928
+ (_b = (_a = this.props).onChange) == null ? void 0 : _b.call(_a, this.checked);
1929
+ this.updateHTML();
1930
+ };
1931
+ this.checked = this.props.initialChecked;
1932
+ this.setProps(this.props);
1933
+ }
1934
+ setProps(props) {
1935
+ this.placement = props.placement ?? this.placement;
1936
+ this.viewId = props.viewId;
1937
+ super.setProps(props);
1938
+ }
1939
+ onRenderHTML(rootElement) {
1940
+ const { className, style, icon, label, color, onIcon = icon, onLabel = label, onColor = color } = this.props;
1941
+ const on = this.checked;
1942
+ rootElement.dataset.checked = String(on);
1943
+ (0, import_preact14.render)((0, import_jsx_runtime20.jsx)(IconButton, { className, style, icon: on ? onIcon : icon, label: on ? onLabel : label, color: on ? onColor : color, onClick: this._toggle }), rootElement);
1944
+ }
1945
+ };
1946
+ ToggleWidget.defaultProps = {
1947
+ ...import_core15.Widget.defaultProps,
1948
+ id: "icon",
1949
+ placement: "top-left",
1950
+ viewId: null,
1951
+ initialChecked: false,
1952
+ icon: "",
1953
+ onIcon: void 0,
1954
+ label: "",
1955
+ onLabel: void 0,
1956
+ color: "",
1957
+ onColor: void 0,
1958
+ onChange: void 0
1959
+ };
1960
+
1961
+ // dist/selector-widget.js
1962
+ var import_jsx_runtime21 = require("preact/jsx-runtime");
1963
+ var import_preact15 = require("preact");
1964
+ var import_core16 = require("@deck.gl/core");
1965
+ var SelectorWidget = class extends import_core16.Widget {
1966
+ constructor(props) {
1967
+ super(props);
1968
+ this.className = "deck-widget-selector";
1969
+ this.placement = "top-left";
1970
+ this.isOpen = false;
1971
+ this._toggleMenu = () => {
1972
+ if (this.isOpen) {
1973
+ this.isOpen = false;
1974
+ } else if (this.rootElement) {
1975
+ this.isOpen = {
1976
+ x: this.rootElement.offsetLeft,
1977
+ y: this.rootElement.offsetTop,
1978
+ placement: this.props.placement.includes("right") ? "left-start" : "right-start"
1979
+ };
1980
+ }
1981
+ this.updateHTML();
1982
+ };
1983
+ this._handleSelectMode = (value) => {
1984
+ this.value = value;
1985
+ this.props.onChange(value);
1986
+ this.updateHTML();
1987
+ };
1988
+ this.value = this.props.initialValue;
1989
+ this.setProps(this.props);
1990
+ }
1991
+ setProps(props) {
1992
+ this.placement = props.placement ?? this.placement;
1993
+ this.viewId = props.viewId ?? this.viewId;
1994
+ super.setProps(props);
1995
+ }
1996
+ onRenderHTML(rootElement) {
1997
+ const selectedOption = this.props.options.find((opt) => opt.value === this.value) ?? this.props.options[0];
1998
+ (0, import_preact15.render)((0, import_jsx_runtime21.jsxs)("div", { children: [(0, import_jsx_runtime21.jsx)(IconButton, { icon: selectedOption.icon, label: selectedOption.label, onClick: this._toggleMenu }), this.isOpen && (0, import_jsx_runtime21.jsx)(Popover, { ...this.isOpen, children: (0, import_jsx_runtime21.jsx)(SimpleMenu, { isOpen: true, style: { pointerEvents: "auto", position: "static" }, menuItems: this.props.options, onSelect: this._handleSelectMode, onClose: this._toggleMenu }) })] }), rootElement);
1999
+ }
2000
+ };
2001
+ SelectorWidget.defaultProps = {
2002
+ ...import_core16.Widget.defaultProps,
2003
+ id: "view-selector",
2004
+ placement: "top-left",
2005
+ viewId: null,
2006
+ initialValue: "",
2007
+ options: [],
2008
+ onChange: () => {
2009
+ }
2010
+ };
2011
+
2012
+ // dist/timeline-widget.js
2013
+ var import_jsx_runtime22 = require("preact/jsx-runtime");
2014
+ var import_core17 = require("@deck.gl/core");
2015
+ var import_preact16 = require("preact");
2016
+ var TimelineWidget = class extends import_core17.Widget {
1350
2017
  constructor(props = {}) {
2018
+ var _a;
1351
2019
  super(props);
1352
2020
  this.id = "timeline";
1353
2021
  this.className = "deck-widget-timeline";
1354
- this.placement = "bottom-left";
2022
+ this.placement = "fill";
1355
2023
  this.playing = false;
1356
2024
  this.timerId = null;
1357
2025
  this.handlePlayPause = () => {
1358
2026
  if (this.playing) {
1359
2027
  this.stop();
1360
2028
  } else {
1361
- this.start();
2029
+ this.play();
1362
2030
  }
1363
2031
  };
1364
- this.handleSliderChange = (e) => {
1365
- const input = e.target;
1366
- const val = Number(input.value);
1367
- this.currentTime = val;
1368
- this.props.onTimeChange(val);
2032
+ this.handleTimeChange = ([value]) => {
2033
+ var _a2;
2034
+ this.currentTime = value;
2035
+ (_a2 = this.props.timeline) == null ? void 0 : _a2.setTime(value);
2036
+ this.props.onTimeChange(value);
1369
2037
  this.updateHTML();
1370
2038
  };
1371
2039
  this.tick = () => {
1372
- const [min, max] = this.props.timeRange;
1373
- let next = this.currentTime + this.props.step;
1374
- if (next > max) {
1375
- next = min;
2040
+ const { timeRange: [min, max], step, loop } = this.props;
2041
+ if (step > 0) {
2042
+ let next = Math.round(this.currentTime / step) * step + step;
2043
+ if (next > max) {
2044
+ if (this.currentTime < max) {
2045
+ next = max;
2046
+ } else if (loop) {
2047
+ next = min;
2048
+ } else {
2049
+ next = max;
2050
+ this.playing = false;
2051
+ }
2052
+ }
2053
+ this.currentTime = next;
2054
+ this.props.onTimeChange(next);
2055
+ this.updateHTML();
1376
2056
  }
1377
- this.currentTime = next;
1378
- this.props.onTimeChange(next);
1379
- this.updateHTML();
1380
2057
  if (this.playing) {
1381
2058
  this.timerId = window.setTimeout(this.tick, this.props.playInterval);
2059
+ } else {
2060
+ this.timerId = null;
1382
2061
  }
1383
2062
  };
1384
2063
  this.currentTime = this.props.initialTime ?? this.props.timeRange[0];
2064
+ (_a = this.props.timeline) == null ? void 0 : _a.setTime(this.currentTime);
1385
2065
  this.setProps(this.props);
1386
2066
  }
1387
2067
  setProps(props) {
1388
- this.placement = props.placement ?? this.placement;
1389
2068
  this.viewId = props.viewId ?? this.viewId;
1390
2069
  super.setProps(props);
1391
2070
  }
1392
2071
  onAdd() {
1393
2072
  this.playing = false;
1394
2073
  this.timerId = null;
2074
+ if (this.props.autoPlay)
2075
+ this.play();
1395
2076
  }
1396
2077
  onRemove() {
1397
2078
  this.stop();
1398
2079
  }
1399
2080
  onRenderHTML(rootElement) {
1400
- (0, import_preact12.render)((0, import_jsx_runtime18.jsxs)("div", { style: { display: "flex", alignItems: "center", pointerEvents: "auto" }, children: [(0, import_jsx_runtime18.jsx)(IconButton, { label: this.playing ? "Pause" : "Play", onClick: this.handlePlayPause, children: (0, import_jsx_runtime18.jsx)("div", { className: "text", children: this.playing ? "\u23F8" : "\u25B6" }) }), (0, import_jsx_runtime18.jsx)("input", { type: "range", className: "timeline-slider", min: this.props.timeRange[0], max: this.props.timeRange[1], step: this.props.step, value: this.currentTime, onInput: this.handleSliderChange })] }), rootElement);
2081
+ const { timeRange, step, formatLabel } = this.props;
2082
+ const currentTime = this.currentTime;
2083
+ rootElement.dataset.placement = this.props.placement;
2084
+ (0, import_preact16.render)((0, import_jsx_runtime22.jsxs)("div", { className: "deck-widget-button-group", children: [this.playing ? (0, import_jsx_runtime22.jsx)(IconButton, { label: "Pause", className: "deck-widget-timeline-pause", onClick: this.handlePlayPause }) : (0, import_jsx_runtime22.jsx)(IconButton, { label: "Play", className: "deck-widget-timeline-play", onClick: this.handlePlayPause }), (0, import_jsx_runtime22.jsx)(RangeInput, { min: timeRange[0], max: timeRange[1], orientation: "horizontal", step, value: [currentTime, currentTime], onChange: this.handleTimeChange, decorations: [
2085
+ {
2086
+ position: [currentTime, currentTime + step],
2087
+ element: (0, import_jsx_runtime22.jsx)("div", { className: "deck-widget-timeline-label deck-widget-timeline-label--current", children: formatLabel(currentTime) })
2088
+ }
2089
+ ] })] }), rootElement);
1401
2090
  }
1402
- start() {
2091
+ play() {
1403
2092
  this.playing = true;
2093
+ const { timeRange: [min, max] } = this.props;
2094
+ if (this.currentTime >= max) {
2095
+ this.currentTime = min;
2096
+ this.props.onTimeChange(min);
2097
+ }
1404
2098
  this.updateHTML();
1405
2099
  this.tick();
1406
2100
  }
@@ -1414,23 +2108,27 @@ var TimelineWidget = class extends import_core13.Widget {
1414
2108
  }
1415
2109
  };
1416
2110
  TimelineWidget.defaultProps = {
1417
- ...import_core13.Widget.defaultProps,
2111
+ ...import_core17.Widget.defaultProps,
1418
2112
  id: "timeline",
1419
2113
  placement: "bottom-left",
1420
2114
  viewId: null,
2115
+ timeline: null,
1421
2116
  timeRange: [0, 100],
1422
2117
  step: 1,
1423
2118
  initialTime: void 0,
1424
2119
  onTimeChange: () => {
1425
2120
  },
1426
- playInterval: 1e3
2121
+ autoPlay: false,
2122
+ loop: false,
2123
+ playInterval: 1e3,
2124
+ formatLabel: String
1427
2125
  };
1428
2126
 
1429
2127
  // dist/screenshot-widget.js
1430
- var import_jsx_runtime19 = require("preact/jsx-runtime");
1431
- var import_preact13 = require("preact");
1432
- var import_core14 = require("@deck.gl/core");
1433
- var ScreenshotWidget = class extends import_core14.Widget {
2128
+ var import_jsx_runtime23 = require("preact/jsx-runtime");
2129
+ var import_preact17 = require("preact");
2130
+ var import_core18 = require("@deck.gl/core");
2131
+ var ScreenshotWidget = class extends import_core18.Widget {
1434
2132
  constructor(props = {}) {
1435
2133
  super(props);
1436
2134
  this.className = "deck-widget-screenshot";
@@ -1443,7 +2141,7 @@ var ScreenshotWidget = class extends import_core14.Widget {
1443
2141
  super.setProps(props);
1444
2142
  }
1445
2143
  onRenderHTML(rootElement) {
1446
- (0, import_preact13.render)((0, import_jsx_runtime19.jsx)(IconButton, { className: "deck-widget-camera", label: this.props.label, onClick: this.handleClick.bind(this) }), rootElement);
2144
+ (0, import_preact17.render)((0, import_jsx_runtime23.jsx)(IconButton, { className: "deck-widget-camera", label: this.props.label, onClick: this.handleClick.bind(this) }), rootElement);
1447
2145
  }
1448
2146
  handleClick() {
1449
2147
  if (this.props.onCapture) {
@@ -1470,7 +2168,7 @@ var ScreenshotWidget = class extends import_core14.Widget {
1470
2168
  }
1471
2169
  };
1472
2170
  ScreenshotWidget.defaultProps = {
1473
- ...import_core14.Widget.defaultProps,
2171
+ ...import_core18.Widget.defaultProps,
1474
2172
  id: "screenshot",
1475
2173
  placement: "top-left",
1476
2174
  viewId: null,
@@ -1481,10 +2179,10 @@ ScreenshotWidget.defaultProps = {
1481
2179
  };
1482
2180
 
1483
2181
  // dist/theme-widget.js
1484
- var import_jsx_runtime20 = require("preact/jsx-runtime");
1485
- var import_core15 = require("@deck.gl/core");
1486
- var import_core16 = require("@deck.gl/core");
1487
- var import_preact14 = require("preact");
2182
+ var import_jsx_runtime24 = require("preact/jsx-runtime");
2183
+ var import_core19 = require("@deck.gl/core");
2184
+ var import_core20 = require("@deck.gl/core");
2185
+ var import_preact18 = require("preact");
1488
2186
 
1489
2187
  // dist/themes.js
1490
2188
  var LightTheme = {
@@ -1507,7 +2205,13 @@ var LightTheme = {
1507
2205
  "--menu-border": "unset",
1508
2206
  "--menu-shadow": "0px 0px 8px 0px rgba(0, 0, 0, 0.25)",
1509
2207
  "--menu-text": "rgb(24, 24, 26, 1)",
1510
- "--menu-item-hover": "rgba(0, 0, 0, 0.08)"
2208
+ "--menu-item-hover": "rgba(0, 0, 0, 0.08)",
2209
+ "--range-step-button-size": "24px",
2210
+ "--range-track-size": "16px",
2211
+ "--range-thumb-size": "10px",
2212
+ "--range-track-color": "#d8d8e5",
2213
+ "--range-thumb-color": "#616166",
2214
+ "--range-decoration-active-color": "#f8dd50"
1511
2215
  };
1512
2216
  var DarkTheme = {
1513
2217
  "--widget-margin": "12px",
@@ -1529,7 +2233,13 @@ var DarkTheme = {
1529
2233
  "--menu-border": "unset",
1530
2234
  "--menu-shadow": "0px 0px 8px 0px rgba(0, 0, 0, 0.25)",
1531
2235
  "--menu-text": "rgb(215, 214, 229, 1)",
1532
- "--menu-item-hover": "rgba(255, 255, 255, 0.1)"
2236
+ "--menu-item-hover": "rgba(255, 255, 255, 0.1)",
2237
+ "--range-step-button-size": "24px",
2238
+ "--range-track-size": "16px",
2239
+ "--range-thumb-size": "10px",
2240
+ "--range-track-color": "#2c2c30",
2241
+ "--range-thumb-color": "#9e9da8",
2242
+ "--range-decoration-active-color": "#dd7d2c"
1533
2243
  };
1534
2244
  var LightGlassTheme = {
1535
2245
  "--widget-margin": "12px",
@@ -1551,7 +2261,13 @@ var LightGlassTheme = {
1551
2261
  "--menu-border": "1px solid rgba(255, 255, 255, 0.6)",
1552
2262
  "--menu-shadow": "0px 0px 8px 0px rgba(0, 0, 0, 0.25), 0px 0px 8px 0px rgba(0, 0, 0, 0.1) inset",
1553
2263
  "--menu-text": "rgb(24, 24, 26, 1)",
1554
- "--menu-item-hover": "rgba(0, 0, 0, 0.08)"
2264
+ "--menu-item-hover": "rgba(0, 0, 0, 0.08)",
2265
+ "--range-step-button-size": "24px",
2266
+ "--range-track-size": "16px",
2267
+ "--range-thumb-size": "10px",
2268
+ "--range-track-color": "rgba(215, 214, 229, 0.3)",
2269
+ "--range-thumb-color": "rgba(97, 97, 102, 1)",
2270
+ "--range-decoration-active-color": "rgba(255, 215, 0, 0.6)"
1555
2271
  };
1556
2272
  var DarkGlassTheme = {
1557
2273
  "--widget-margin": "12px",
@@ -1573,11 +2289,17 @@ var DarkGlassTheme = {
1573
2289
  "--menu-border": "1px solid rgba(18, 18, 20, 0.75)",
1574
2290
  "--menu-shadow": "0px 0px 8px 0px rgba(0, 0, 0, 0.25), 0px 0px 8px 0px rgba(0, 0, 0, 0.1) inset",
1575
2291
  "--menu-text": "rgb(215, 214, 229, 1)",
1576
- "--menu-item-hover": "rgba(255, 255, 255, 0.1)"
2292
+ "--menu-item-hover": "rgba(255, 255, 255, 0.1)",
2293
+ "--range-step-button-size": "24px",
2294
+ "--range-track-size": "16px",
2295
+ "--range-thumb-size": "10px",
2296
+ "--range-track-color": "rgba(24, 24, 26, 0.3)",
2297
+ "--range-thumb-color": "rgba(158, 157, 168, 1)",
2298
+ "--range-decoration-active-color": "rgba(255, 145, 0, 0.6)"
1577
2299
  };
1578
2300
 
1579
2301
  // dist/theme-widget.js
1580
- var ThemeWidget = class extends import_core16.Widget {
2302
+ var ThemeWidget = class extends import_core20.Widget {
1581
2303
  constructor(props = {}) {
1582
2304
  super(props);
1583
2305
  this.className = "deck-widget-theme";
@@ -1594,22 +2316,22 @@ var ThemeWidget = class extends import_core16.Widget {
1594
2316
  super.setProps(props);
1595
2317
  switch (this.themeMode) {
1596
2318
  case "light":
1597
- if (props.lightModeTheme && !(0, import_core15._deepEqual)(props.lightModeTheme, lightModeTheme, 1)) {
2319
+ if (props.lightModeTheme && !(0, import_core19._deepEqual)(props.lightModeTheme, lightModeTheme, 1)) {
1598
2320
  this._setThemeMode("light");
1599
2321
  }
1600
2322
  break;
1601
2323
  case "dark":
1602
- if (props.darkModeTheme && !(0, import_core15._deepEqual)(props.darkModeTheme, darkModeTheme, 1)) {
2324
+ if (props.darkModeTheme && !(0, import_core19._deepEqual)(props.darkModeTheme, darkModeTheme, 1)) {
1603
2325
  this._setThemeMode("dark");
1604
2326
  }
1605
2327
  break;
1606
2328
  default:
1607
- import_core15.log.warn(`Invalid theme mode ${this.themeMode}`)();
2329
+ import_core19.log.warn(`Invalid theme mode ${this.themeMode}`)();
1608
2330
  }
1609
2331
  }
1610
2332
  onRenderHTML(rootElement) {
1611
2333
  const { lightModeLabel, darkModeLabel } = this.props;
1612
- (0, import_preact14.render)((0, import_jsx_runtime20.jsx)(IconButton, { onClick: this._handleClick.bind(this), label: this.themeMode === "dark" ? darkModeLabel : lightModeLabel, className: this.themeMode === "dark" ? "deck-widget-moon" : "deck-widget-sun" }), rootElement);
2334
+ (0, import_preact18.render)((0, import_jsx_runtime24.jsx)(IconButton, { onClick: this._handleClick.bind(this), label: this.themeMode === "dark" ? darkModeLabel : lightModeLabel, className: this.themeMode === "dark" ? "deck-widget-moon" : "deck-widget-sun" }), rootElement);
1613
2335
  }
1614
2336
  onAdd() {
1615
2337
  this._setThemeMode(this.themeMode);
@@ -1624,20 +2346,26 @@ var ThemeWidget = class extends import_core16.Widget {
1624
2346
  const container = (_a = this.rootElement) == null ? void 0 : _a.closest(".deck-widget-container");
1625
2347
  if (container) {
1626
2348
  const themeStyle = themeMode === "dark" ? this.props.darkModeTheme : this.props.lightModeTheme;
1627
- (0, import_core15._applyStyles)(container, themeStyle);
2349
+ (0, import_core19._applyStyles)(container, themeStyle);
1628
2350
  const label = this.themeMode === "dark" ? this.props.darkModeLabel : this.props.lightModeLabel;
1629
- import_core15.log.log(1, `Switched theme to ${label}`, themeStyle)();
2351
+ import_core19.log.log(1, `Switched theme to ${label}`, themeStyle)();
1630
2352
  this.updateHTML();
1631
2353
  }
1632
2354
  }
1633
2355
  /** Read browser preference */
1634
2356
  _getInitialThemeMode() {
1635
2357
  const { initialThemeMode } = this.props;
1636
- return initialThemeMode === "auto" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : initialThemeMode;
2358
+ if (initialThemeMode !== "auto") {
2359
+ return initialThemeMode;
2360
+ }
2361
+ if (typeof window === "undefined") {
2362
+ return "light";
2363
+ }
2364
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
1637
2365
  }
1638
2366
  };
1639
2367
  ThemeWidget.defaultProps = {
1640
- ...import_core16.Widget.defaultProps,
2368
+ ...import_core20.Widget.defaultProps,
1641
2369
  id: "theme",
1642
2370
  placement: "top-left",
1643
2371
  viewId: null,
@@ -1649,10 +2377,10 @@ ThemeWidget.defaultProps = {
1649
2377
  };
1650
2378
 
1651
2379
  // dist/loading-widget.js
1652
- var import_jsx_runtime21 = require("preact/jsx-runtime");
1653
- var import_preact15 = require("preact");
1654
- var import_core17 = require("@deck.gl/core");
1655
- var LoadingWidget = class extends import_core17.Widget {
2380
+ var import_jsx_runtime25 = require("preact/jsx-runtime");
2381
+ var import_preact19 = require("preact");
2382
+ var import_core21 = require("@deck.gl/core");
2383
+ var LoadingWidget = class extends import_core21.Widget {
1656
2384
  constructor(props = {}) {
1657
2385
  super(props);
1658
2386
  this.className = "deck-widget-loading";
@@ -1666,9 +2394,9 @@ var LoadingWidget = class extends import_core17.Widget {
1666
2394
  super.setProps(props);
1667
2395
  }
1668
2396
  onRenderHTML(rootElement) {
1669
- (0, import_preact15.render)(
2397
+ (0, import_preact19.render)(
1670
2398
  // TODO(ibgreen) - this should not be a button, but styling is so nested that it is easier to reuse this component.
1671
- this.loading && (0, import_jsx_runtime21.jsx)(IconButton, { className: "deck-widget-spinner", label: this.props.label, onClick: this.handleClick.bind(this) }),
2399
+ this.loading && (0, import_jsx_runtime25.jsx)(IconButton, { className: "deck-widget-spinner", label: this.props.label, onClick: this.handleClick.bind(this) }),
1672
2400
  rootElement
1673
2401
  );
1674
2402
  }
@@ -1684,65 +2412,19 @@ var LoadingWidget = class extends import_core17.Widget {
1684
2412
  }
1685
2413
  };
1686
2414
  LoadingWidget.defaultProps = {
1687
- ...import_core17.Widget.defaultProps,
2415
+ ...import_core21.Widget.defaultProps,
1688
2416
  id: "loading",
1689
2417
  placement: "top-left",
1690
2418
  viewId: null,
1691
2419
  label: "Loading layer data"
1692
2420
  };
1693
2421
 
1694
- // dist/fps-widget.js
1695
- var import_jsx_runtime22 = require("preact/jsx-runtime");
1696
- var import_core18 = require("@deck.gl/core");
1697
- var import_preact16 = require("preact");
1698
- var FpsWidget = class extends import_core18.Widget {
1699
- constructor(props = {}) {
1700
- super(props);
1701
- this.className = "deck-widget-fps";
1702
- this.placement = "top-left";
1703
- this._lastFps = -1;
1704
- this.setProps(this.props);
1705
- }
1706
- setProps(props) {
1707
- this.placement = props.placement ?? this.placement;
1708
- this.viewId = props.viewId ?? this.viewId;
1709
- super.setProps(props);
1710
- }
1711
- onAdd({}) {
1712
- this._lastFps = this._getFps();
1713
- requestAnimationFrame(() => this._animate());
1714
- }
1715
- onRenderHTML(rootElement) {
1716
- const fps = this._getFps();
1717
- (0, import_preact16.render)((0, import_jsx_runtime22.jsx)(IconButton, { children: (0, import_jsx_runtime22.jsxs)("div", { className: "text", children: ["FPS", (0, import_jsx_runtime22.jsx)("br", {}), fps] }) }), rootElement);
1718
- }
1719
- _animate() {
1720
- const fps = this._getFps();
1721
- if (this._lastFps !== fps) {
1722
- this._lastFps = fps;
1723
- this.updateHTML();
1724
- }
1725
- requestAnimationFrame(() => this._animate());
1726
- }
1727
- _getFps() {
1728
- var _a;
1729
- return Math.round(((_a = this.deck) == null ? void 0 : _a.metrics.fps) ?? 0);
1730
- }
1731
- };
1732
- FpsWidget.defaultProps = {
1733
- ...import_core18.Widget.defaultProps,
1734
- id: "fps",
1735
- placement: "top-left",
1736
- viewId: null
1737
- };
1738
-
1739
2422
  // dist/stats-widget.js
1740
- var import_jsx_runtime23 = require("preact/jsx-runtime");
1741
- var import_core19 = require("@deck.gl/core");
1742
- var import_core20 = require("@luma.gl/core");
1743
- var import_preact17 = require("preact");
1744
- var RIGHT_ARROW = "\u25B6";
1745
- var DOWN_ARROW = "\u2B07";
2423
+ var import_jsx_runtime26 = require("preact/jsx-runtime");
2424
+ var import_core22 = require("@deck.gl/core");
2425
+ var import_core23 = require("@luma.gl/core");
2426
+ var import_preact20 = require("preact");
2427
+ var import_hooks7 = require("preact/hooks");
1746
2428
  var DEFAULT_COUNT_FORMATTER = (stat) => `${stat.name}: ${stat.count}`;
1747
2429
  function formatTime(time) {
1748
2430
  return time < 1e3 ? `${time.toFixed(2)}ms` : `${(time / 1e3).toFixed(2)}s`;
@@ -1758,7 +2440,7 @@ var DEFAULT_FORMATTERS = {
1758
2440
  fps: (stat) => `${stat.name}: ${Math.round(stat.getHz())}fps`,
1759
2441
  memory: (stat) => `${stat.name}: ${formatMemory(stat.count)}`
1760
2442
  };
1761
- var StatsWidget = class extends import_core19.Widget {
2443
+ var StatsWidget = class extends import_core22.Widget {
1762
2444
  constructor(props = {}) {
1763
2445
  super(props);
1764
2446
  this.className = "deck-widget-stats";
@@ -1769,8 +2451,13 @@ var StatsWidget = class extends import_core19.Widget {
1769
2451
  this.collapsed = !this.collapsed;
1770
2452
  this.updateHTML();
1771
2453
  };
2454
+ this._getFps = () => {
2455
+ var _a;
2456
+ return Math.round(((_a = this.deck) == null ? void 0 : _a.metrics.fps) ?? 0);
2457
+ };
1772
2458
  this._formatters = { ...DEFAULT_FORMATTERS };
1773
2459
  this._resetOnUpdate = { ...this.props.resetOnUpdate };
2460
+ this.collapsed = !props.defaultIsExpanded;
1774
2461
  this.setProps(props);
1775
2462
  }
1776
2463
  setProps(props) {
@@ -1787,31 +2474,39 @@ var StatsWidget = class extends import_core19.Widget {
1787
2474
  }
1788
2475
  super.setProps(props);
1789
2476
  }
1790
- onAdd() {
1791
- this.updateHTML();
2477
+ onRemove() {
2478
+ if (this.rootElement) {
2479
+ (0, import_preact20.render)(null, this.rootElement);
2480
+ }
1792
2481
  }
1793
2482
  onRenderHTML(rootElement) {
1794
- const stats = this._getStats();
1795
2483
  const collapsed = this.collapsed;
2484
+ if (collapsed) {
2485
+ (0, import_preact20.render)((0, import_jsx_runtime26.jsx)(FpsIcon, { getFps: this._getFps, onClick: this._toggleCollapsed }), rootElement);
2486
+ return;
2487
+ }
2488
+ const stats = this._getStats();
1796
2489
  const title = this.props.title || ("id" in stats ? stats.id : null) || "Stats";
1797
2490
  const items = [];
1798
- if (!collapsed && stats) {
2491
+ if (stats) {
1799
2492
  stats.forEach((stat) => {
1800
2493
  const lines = this._getLines(stat).split("\n");
1801
2494
  if (this._resetOnUpdate && this._resetOnUpdate[stat.name]) {
1802
2495
  stat.reset();
1803
2496
  }
1804
2497
  lines.forEach((line, i) => {
1805
- items.push((0, import_jsx_runtime23.jsx)("div", { style: { whiteSpace: "pre" }, children: line }, `${stat.name}-${i}`));
2498
+ items.push((0, import_jsx_runtime26.jsx)("div", { style: { whiteSpace: "pre" }, children: line }, `${stat.name}-${i}`));
1806
2499
  });
1807
2500
  });
1808
2501
  }
1809
- (0, import_preact17.render)((0, import_jsx_runtime23.jsxs)("div", { className: "deck-widget-stats-container", style: { cursor: "default" }, children: [(0, import_jsx_runtime23.jsxs)("div", { className: "deck-widget-stats-header", style: { cursor: "pointer", pointerEvents: "auto" }, onClick: this._toggleCollapsed, children: [collapsed ? RIGHT_ARROW : DOWN_ARROW, " ", title] }), !collapsed && (0, import_jsx_runtime23.jsx)("div", { className: "deck-widget-stats-content", children: items })] }), rootElement);
2502
+ (0, import_preact20.render)((0, import_jsx_runtime26.jsxs)("div", { className: "deck-widget-stats-container", style: { cursor: "default" }, children: [(0, import_jsx_runtime26.jsxs)("div", { className: "deck-widget-stats-header", style: { cursor: "pointer", pointerEvents: "auto" }, onClick: this._toggleCollapsed, children: [(0, import_jsx_runtime26.jsx)("b", { children: title }), (0, import_jsx_runtime26.jsx)("button", { className: "deck-widget-dropdown-button", children: (0, import_jsx_runtime26.jsx)("span", { className: "deck-widget-dropdown-icon open" }) })] }), (0, import_jsx_runtime26.jsx)("div", { className: "deck-widget-stats-content", children: items })] }), rootElement);
1810
2503
  }
1811
2504
  onRedraw() {
1812
- const framesPerUpdate = Math.max(1, this.props.framesPerUpdate || 1);
1813
- if (this._counter++ % framesPerUpdate === 0) {
1814
- this.updateHTML();
2505
+ if (!this.collapsed) {
2506
+ const framesPerUpdate = Math.max(1, this.props.framesPerUpdate || 1);
2507
+ if (this._counter++ % framesPerUpdate === 0) {
2508
+ this.updateHTML();
2509
+ }
1815
2510
  }
1816
2511
  }
1817
2512
  _getStats() {
@@ -1821,7 +2516,7 @@ var StatsWidget = class extends import_core19.Widget {
1821
2516
  const metrics = ((_a = this.deck) == null ? void 0 : _a.metrics) ?? {};
1822
2517
  return Object.entries(metrics);
1823
2518
  case "luma":
1824
- return Array.from(import_core20.luma.stats.stats.values())[0];
2519
+ return Array.from(import_core23.luma.stats.stats.values())[0];
1825
2520
  case "device":
1826
2521
  const device = (_b = this.deck) == null ? void 0 : _b.device;
1827
2522
  const stats = device == null ? void 0 : device.statsManager.stats.values();
@@ -1843,10 +2538,11 @@ var StatsWidget = class extends import_core19.Widget {
1843
2538
  }
1844
2539
  };
1845
2540
  StatsWidget.defaultProps = {
1846
- ...import_core19.Widget.defaultProps,
2541
+ ...import_core22.Widget.defaultProps,
1847
2542
  type: "deck",
1848
2543
  placement: "top-left",
1849
2544
  viewId: null,
2545
+ defaultIsExpanded: false,
1850
2546
  stats: void 0,
1851
2547
  title: "Stats",
1852
2548
  framesPerUpdate: 1,
@@ -1854,4 +2550,18 @@ StatsWidget.defaultProps = {
1854
2550
  resetOnUpdate: {},
1855
2551
  id: "stats"
1856
2552
  };
2553
+ function FpsIcon({ getFps, onClick }) {
2554
+ const [fps, setFps] = (0, import_hooks7.useState)(getFps());
2555
+ (0, import_hooks7.useEffect)(() => {
2556
+ const onUpdate = () => {
2557
+ setFps(getFps());
2558
+ timer = requestAnimationFrame(onUpdate);
2559
+ };
2560
+ let timer = requestAnimationFrame(onUpdate);
2561
+ return () => {
2562
+ cancelAnimationFrame(timer);
2563
+ };
2564
+ }, [getFps]);
2565
+ return (0, import_jsx_runtime26.jsx)(IconButton, { onClick, children: (0, import_jsx_runtime26.jsxs)("div", { className: "text", children: ["FPS", (0, import_jsx_runtime26.jsx)("br", {}), fps] }) });
2566
+ }
1857
2567
  //# sourceMappingURL=index.cjs.map