@deepfuture/dui-map 1.1.0

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 (50) hide show
  1. package/README.md +214 -0
  2. package/cluster-layer/index.d.ts +2 -0
  3. package/cluster-layer/index.js +2 -0
  4. package/cluster-layer/map-cluster-layer.d.ts +53 -0
  5. package/cluster-layer/map-cluster-layer.js +337 -0
  6. package/controls/index.d.ts +2 -0
  7. package/controls/index.js +2 -0
  8. package/controls/map-controls.d.ts +37 -0
  9. package/controls/map-controls.js +344 -0
  10. package/heatmap/index.d.ts +2 -0
  11. package/heatmap/index.js +2 -0
  12. package/heatmap/map-heatmap.d.ts +39 -0
  13. package/heatmap/map-heatmap.js +330 -0
  14. package/index.d.ts +10 -0
  15. package/index.js +9 -0
  16. package/map/index.d.ts +5 -0
  17. package/map/index.js +3 -0
  18. package/map/map-context.d.ts +8 -0
  19. package/map/map-context.js +2 -0
  20. package/map/map.d.ts +120 -0
  21. package/map/map.js +628 -0
  22. package/marker/index.d.ts +9 -0
  23. package/marker/index.js +7 -0
  24. package/marker/map-marker-content.d.ts +20 -0
  25. package/marker/map-marker-content.js +135 -0
  26. package/marker/map-marker-label.d.ts +21 -0
  27. package/marker/map-marker-label.js +126 -0
  28. package/marker/map-marker-popup.d.ts +25 -0
  29. package/marker/map-marker-popup.js +158 -0
  30. package/marker/map-marker-tooltip.d.ts +22 -0
  31. package/marker/map-marker-tooltip.js +159 -0
  32. package/marker/map-marker.d.ts +48 -0
  33. package/marker/map-marker.js +220 -0
  34. package/marker/marker-context.d.ts +8 -0
  35. package/marker/marker-context.js +2 -0
  36. package/package.json +70 -0
  37. package/popup/index.d.ts +2 -0
  38. package/popup/index.js +2 -0
  39. package/popup/map-popup.d.ts +29 -0
  40. package/popup/map-popup.js +184 -0
  41. package/region/index.d.ts +2 -0
  42. package/region/index.js +2 -0
  43. package/region/map-region.d.ts +41 -0
  44. package/region/map-region.js +276 -0
  45. package/route/index.d.ts +2 -0
  46. package/route/index.js +2 -0
  47. package/route/map-route.d.ts +33 -0
  48. package/route/map-route.js +245 -0
  49. package/theme/map-theme.d.ts +16 -0
  50. package/theme/map-theme.js +233 -0
package/map/map.js ADDED
@@ -0,0 +1,628 @@
1
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
2
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
3
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
4
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
5
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
6
+ var _, done = false;
7
+ for (var i = decorators.length - 1; i >= 0; i--) {
8
+ var context = {};
9
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
10
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
11
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
12
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
13
+ if (kind === "accessor") {
14
+ if (result === void 0) continue;
15
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
16
+ if (_ = accept(result.get)) descriptor.get = _;
17
+ if (_ = accept(result.set)) descriptor.set = _;
18
+ if (_ = accept(result.init)) initializers.unshift(_);
19
+ }
20
+ else if (_ = accept(result)) {
21
+ if (kind === "field") initializers.unshift(_);
22
+ else descriptor[key] = _;
23
+ }
24
+ }
25
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
26
+ done = true;
27
+ };
28
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
29
+ var useValue = arguments.length > 2;
30
+ for (var i = 0; i < initializers.length; i++) {
31
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
32
+ }
33
+ return useValue ? value : void 0;
34
+ };
35
+ var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) {
36
+ if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
37
+ return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
38
+ };
39
+ import { css, html, LitElement } from "lit";
40
+ import { property, state } from "lit/decorators.js";
41
+ import { provide } from "@lit/context";
42
+ import { base } from "@deepfuture/dui-primitives/core/base";
43
+ import { customEvent } from "@deepfuture/dui-primitives/core/event";
44
+ import { mapThemeStyles } from "../theme/map-theme.js";
45
+ import MapLibreGL from "maplibre-gl";
46
+ // @ts-ignore — loaded as text via esbuild cssRawTextPlugin
47
+ import maplibreCssText from "maplibre-gl/dist/maplibre-gl.css";
48
+ import { mapContext } from "./map-context.js";
49
+ const DEFAULT_STYLES = {
50
+ dark: "https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json",
51
+ light: "https://basemaps.cartocdn.com/gl/positron-gl-style/style.json",
52
+ };
53
+ /** Fired when the map viewport changes (pan, zoom, rotate, pitch). */
54
+ export const viewportChangeEvent = customEvent("dui-map-viewport-change", { bubbles: true, composed: true });
55
+ /** Fired when the map finishes initial load. */
56
+ export const mapLoadEvent = customEvent("dui-map-load", { bubbles: true, composed: true });
57
+ /** Fired on single click on the map canvas. */
58
+ export const mapClickEvent = customEvent("dui-map-click", { bubbles: true, composed: true });
59
+ /** Fired on double-click on the map canvas. */
60
+ export const mapDblClickEvent = customEvent("dui-map-dblclick", { bubbles: true, composed: true });
61
+ /** Fired on right-click / long-press on the map canvas. */
62
+ export const mapContextMenuEvent = customEvent("dui-map-contextmenu", { bubbles: true, composed: true });
63
+ function getDocumentTheme() {
64
+ if (typeof document === "undefined")
65
+ return null;
66
+ if (document.documentElement.getAttribute("data-theme") === "dark")
67
+ return "dark";
68
+ if (document.documentElement.getAttribute("data-theme") === "light")
69
+ return "light";
70
+ // Fallback: check class (for compatibility with next-themes, etc.)
71
+ if (document.documentElement.classList.contains("dark"))
72
+ return "dark";
73
+ if (document.documentElement.classList.contains("light"))
74
+ return "light";
75
+ return null;
76
+ }
77
+ function getSystemTheme() {
78
+ if (typeof window === "undefined")
79
+ return "light";
80
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
81
+ }
82
+ /** MapLibre CSS adopted into shadow DOM. */
83
+ const maplibreSheet = new CSSStyleSheet();
84
+ maplibreSheet.replaceSync(maplibreCssText);
85
+ /** Structural styles only — layout and behavioral CSS. */
86
+ const styles = css `
87
+ :host {
88
+ display: block;
89
+ position: relative;
90
+ width: 100%;
91
+ height: 100%;
92
+ }
93
+
94
+ [part="container"] {
95
+ width: 100%;
96
+ height: 100%;
97
+ position: relative;
98
+ }
99
+
100
+ [part="loader"] {
101
+ position: absolute;
102
+ inset: 0;
103
+ z-index: 10;
104
+ display: flex;
105
+ align-items: center;
106
+ justify-content: center;
107
+ }
108
+
109
+ .loader-dots {
110
+ display: flex;
111
+ gap: 4px;
112
+ }
113
+
114
+ .loader-dot {
115
+ width: 6px;
116
+ height: 6px;
117
+ border-radius: 50%;
118
+ animation: pulse 1s ease-in-out infinite;
119
+ }
120
+
121
+ .loader-dot:nth-child(2) { animation-delay: 150ms; }
122
+ .loader-dot:nth-child(3) { animation-delay: 300ms; }
123
+
124
+ @keyframes pulse {
125
+ 0%, 100% { opacity: 0.4; }
126
+ 50% { opacity: 1; }
127
+ }
128
+ `;
129
+ /**
130
+ * `<dui-map>` — Root map component wrapping MapLibre GL JS.
131
+ *
132
+ * Initializes a MapLibre map inside its shadow DOM with CSS properly adopted.
133
+ * Provides map context to child components via Lit Context.
134
+ * Auto-detects light/dark theme from `data-theme` attribute on `<html>`.
135
+ *
136
+ * @slot - Map overlay content (controls, markers, popups, routes, etc.)
137
+ * @csspart container - The map container div.
138
+ * @csspart loader - The loading indicator overlay.
139
+ * @fires dui-map-viewport-change - Fired on pan/zoom/rotate/pitch. Detail: MapViewport
140
+ * @fires dui-map-load - Fired when map finishes loading.
141
+ * @fires dui-map-click - Fired on single click. Detail: MapClickDetail
142
+ * @fires dui-map-dblclick - Fired on double-click. Detail: MapClickDetail
143
+ * @fires dui-map-contextmenu - Fired on right-click / long-press. Detail: MapClickDetail
144
+ */
145
+ let DuiMap = (() => {
146
+ let _classSuper = LitElement;
147
+ let _center_decorators;
148
+ let _center_initializers = [];
149
+ let _center_extraInitializers = [];
150
+ let _zoom_decorators;
151
+ let _zoom_initializers = [];
152
+ let _zoom_extraInitializers = [];
153
+ let _bearing_decorators;
154
+ let _bearing_initializers = [];
155
+ let _bearing_extraInitializers = [];
156
+ let _pitch_decorators;
157
+ let _pitch_initializers = [];
158
+ let _pitch_extraInitializers = [];
159
+ let _theme_decorators;
160
+ let _theme_initializers = [];
161
+ let _theme_extraInitializers = [];
162
+ let _styleLight_decorators;
163
+ let _styleLight_initializers = [];
164
+ let _styleLight_extraInitializers = [];
165
+ let _styleDark_decorators;
166
+ let _styleDark_initializers = [];
167
+ let _styleDark_extraInitializers = [];
168
+ let _loading_decorators;
169
+ let _loading_initializers = [];
170
+ let _loading_extraInitializers = [];
171
+ let _noWorldCopies_decorators;
172
+ let _noWorldCopies_initializers = [];
173
+ let _noWorldCopies_extraInitializers = [];
174
+ let _controlled_decorators;
175
+ let _controlled_initializers = [];
176
+ let _controlled_extraInitializers = [];
177
+ let _minZoom_decorators;
178
+ let _minZoom_initializers = [];
179
+ let _minZoom_extraInitializers = [];
180
+ let _maxZoom_decorators;
181
+ let _maxZoom_initializers = [];
182
+ let _maxZoom_extraInitializers = [];
183
+ let _maxBounds_decorators;
184
+ let _maxBounds_initializers = [];
185
+ let _maxBounds_extraInitializers = [];
186
+ let _bounds_decorators;
187
+ let _bounds_initializers = [];
188
+ let _bounds_extraInitializers = [];
189
+ let _boundsPadding_decorators;
190
+ let _boundsPadding_initializers = [];
191
+ let _boundsPadding_extraInitializers = [];
192
+ let _private_mapInstance_decorators;
193
+ let _private_mapInstance_initializers = [];
194
+ let _private_mapInstance_extraInitializers = [];
195
+ let _private_mapInstance_descriptor;
196
+ let _private_isLoaded_decorators;
197
+ let _private_isLoaded_initializers = [];
198
+ let _private_isLoaded_extraInitializers = [];
199
+ let _private_isLoaded_descriptor;
200
+ let _private_isStyleLoaded_decorators;
201
+ let _private_isStyleLoaded_initializers = [];
202
+ let _private_isStyleLoaded_extraInitializers = [];
203
+ let _private_isStyleLoaded_descriptor;
204
+ let _private_resolvedTheme_decorators;
205
+ let _private_resolvedTheme_initializers = [];
206
+ let _private_resolvedTheme_extraInitializers = [];
207
+ let _private_resolvedTheme_descriptor;
208
+ let __ctx_decorators;
209
+ let __ctx_initializers = [];
210
+ let __ctx_extraInitializers = [];
211
+ return class DuiMap extends _classSuper {
212
+ static {
213
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
214
+ _center_decorators = [property({ type: Array })];
215
+ _zoom_decorators = [property({ type: Number })];
216
+ _bearing_decorators = [property({ type: Number })];
217
+ _pitch_decorators = [property({ type: Number })];
218
+ _theme_decorators = [property()];
219
+ _styleLight_decorators = [property({ attribute: "style-light" })];
220
+ _styleDark_decorators = [property({ attribute: "style-dark" })];
221
+ _loading_decorators = [property({ type: Boolean })];
222
+ _noWorldCopies_decorators = [property({ type: Boolean, attribute: "no-world-copies" })];
223
+ _controlled_decorators = [property({ type: Boolean })];
224
+ _minZoom_decorators = [property({ type: Number, attribute: "min-zoom" })];
225
+ _maxZoom_decorators = [property({ type: Number, attribute: "max-zoom" })];
226
+ _maxBounds_decorators = [property({ type: Array })];
227
+ _bounds_decorators = [property({ type: Array })];
228
+ _boundsPadding_decorators = [property({ type: Number, attribute: "bounds-padding" })];
229
+ _private_mapInstance_decorators = [state()];
230
+ _private_isLoaded_decorators = [state()];
231
+ _private_isStyleLoaded_decorators = [state()];
232
+ _private_resolvedTheme_decorators = [state()];
233
+ __ctx_decorators = [provide({ context: mapContext }), state()];
234
+ __esDecorate(this, null, _center_decorators, { kind: "accessor", name: "center", static: false, private: false, access: { has: obj => "center" in obj, get: obj => obj.center, set: (obj, value) => { obj.center = value; } }, metadata: _metadata }, _center_initializers, _center_extraInitializers);
235
+ __esDecorate(this, null, _zoom_decorators, { kind: "accessor", name: "zoom", static: false, private: false, access: { has: obj => "zoom" in obj, get: obj => obj.zoom, set: (obj, value) => { obj.zoom = value; } }, metadata: _metadata }, _zoom_initializers, _zoom_extraInitializers);
236
+ __esDecorate(this, null, _bearing_decorators, { kind: "accessor", name: "bearing", static: false, private: false, access: { has: obj => "bearing" in obj, get: obj => obj.bearing, set: (obj, value) => { obj.bearing = value; } }, metadata: _metadata }, _bearing_initializers, _bearing_extraInitializers);
237
+ __esDecorate(this, null, _pitch_decorators, { kind: "accessor", name: "pitch", static: false, private: false, access: { has: obj => "pitch" in obj, get: obj => obj.pitch, set: (obj, value) => { obj.pitch = value; } }, metadata: _metadata }, _pitch_initializers, _pitch_extraInitializers);
238
+ __esDecorate(this, null, _theme_decorators, { kind: "accessor", name: "theme", static: false, private: false, access: { has: obj => "theme" in obj, get: obj => obj.theme, set: (obj, value) => { obj.theme = value; } }, metadata: _metadata }, _theme_initializers, _theme_extraInitializers);
239
+ __esDecorate(this, null, _styleLight_decorators, { kind: "accessor", name: "styleLight", static: false, private: false, access: { has: obj => "styleLight" in obj, get: obj => obj.styleLight, set: (obj, value) => { obj.styleLight = value; } }, metadata: _metadata }, _styleLight_initializers, _styleLight_extraInitializers);
240
+ __esDecorate(this, null, _styleDark_decorators, { kind: "accessor", name: "styleDark", static: false, private: false, access: { has: obj => "styleDark" in obj, get: obj => obj.styleDark, set: (obj, value) => { obj.styleDark = value; } }, metadata: _metadata }, _styleDark_initializers, _styleDark_extraInitializers);
241
+ __esDecorate(this, null, _loading_decorators, { kind: "accessor", name: "loading", static: false, private: false, access: { has: obj => "loading" in obj, get: obj => obj.loading, set: (obj, value) => { obj.loading = value; } }, metadata: _metadata }, _loading_initializers, _loading_extraInitializers);
242
+ __esDecorate(this, null, _noWorldCopies_decorators, { kind: "accessor", name: "noWorldCopies", static: false, private: false, access: { has: obj => "noWorldCopies" in obj, get: obj => obj.noWorldCopies, set: (obj, value) => { obj.noWorldCopies = value; } }, metadata: _metadata }, _noWorldCopies_initializers, _noWorldCopies_extraInitializers);
243
+ __esDecorate(this, null, _controlled_decorators, { kind: "accessor", name: "controlled", static: false, private: false, access: { has: obj => "controlled" in obj, get: obj => obj.controlled, set: (obj, value) => { obj.controlled = value; } }, metadata: _metadata }, _controlled_initializers, _controlled_extraInitializers);
244
+ __esDecorate(this, null, _minZoom_decorators, { kind: "accessor", name: "minZoom", static: false, private: false, access: { has: obj => "minZoom" in obj, get: obj => obj.minZoom, set: (obj, value) => { obj.minZoom = value; } }, metadata: _metadata }, _minZoom_initializers, _minZoom_extraInitializers);
245
+ __esDecorate(this, null, _maxZoom_decorators, { kind: "accessor", name: "maxZoom", static: false, private: false, access: { has: obj => "maxZoom" in obj, get: obj => obj.maxZoom, set: (obj, value) => { obj.maxZoom = value; } }, metadata: _metadata }, _maxZoom_initializers, _maxZoom_extraInitializers);
246
+ __esDecorate(this, null, _maxBounds_decorators, { kind: "accessor", name: "maxBounds", static: false, private: false, access: { has: obj => "maxBounds" in obj, get: obj => obj.maxBounds, set: (obj, value) => { obj.maxBounds = value; } }, metadata: _metadata }, _maxBounds_initializers, _maxBounds_extraInitializers);
247
+ __esDecorate(this, null, _bounds_decorators, { kind: "accessor", name: "bounds", static: false, private: false, access: { has: obj => "bounds" in obj, get: obj => obj.bounds, set: (obj, value) => { obj.bounds = value; } }, metadata: _metadata }, _bounds_initializers, _bounds_extraInitializers);
248
+ __esDecorate(this, null, _boundsPadding_decorators, { kind: "accessor", name: "boundsPadding", static: false, private: false, access: { has: obj => "boundsPadding" in obj, get: obj => obj.boundsPadding, set: (obj, value) => { obj.boundsPadding = value; } }, metadata: _metadata }, _boundsPadding_initializers, _boundsPadding_extraInitializers);
249
+ __esDecorate(this, _private_mapInstance_descriptor = { get: __setFunctionName(function () { return this.#mapInstance_accessor_storage; }, "#mapInstance", "get"), set: __setFunctionName(function (value) { this.#mapInstance_accessor_storage = value; }, "#mapInstance", "set") }, _private_mapInstance_decorators, { kind: "accessor", name: "#mapInstance", static: false, private: true, access: { has: obj => #mapInstance in obj, get: obj => obj.#mapInstance, set: (obj, value) => { obj.#mapInstance = value; } }, metadata: _metadata }, _private_mapInstance_initializers, _private_mapInstance_extraInitializers);
250
+ __esDecorate(this, _private_isLoaded_descriptor = { get: __setFunctionName(function () { return this.#isLoaded_accessor_storage; }, "#isLoaded", "get"), set: __setFunctionName(function (value) { this.#isLoaded_accessor_storage = value; }, "#isLoaded", "set") }, _private_isLoaded_decorators, { kind: "accessor", name: "#isLoaded", static: false, private: true, access: { has: obj => #isLoaded in obj, get: obj => obj.#isLoaded, set: (obj, value) => { obj.#isLoaded = value; } }, metadata: _metadata }, _private_isLoaded_initializers, _private_isLoaded_extraInitializers);
251
+ __esDecorate(this, _private_isStyleLoaded_descriptor = { get: __setFunctionName(function () { return this.#isStyleLoaded_accessor_storage; }, "#isStyleLoaded", "get"), set: __setFunctionName(function (value) { this.#isStyleLoaded_accessor_storage = value; }, "#isStyleLoaded", "set") }, _private_isStyleLoaded_decorators, { kind: "accessor", name: "#isStyleLoaded", static: false, private: true, access: { has: obj => #isStyleLoaded in obj, get: obj => obj.#isStyleLoaded, set: (obj, value) => { obj.#isStyleLoaded = value; } }, metadata: _metadata }, _private_isStyleLoaded_initializers, _private_isStyleLoaded_extraInitializers);
252
+ __esDecorate(this, _private_resolvedTheme_descriptor = { get: __setFunctionName(function () { return this.#resolvedTheme_accessor_storage; }, "#resolvedTheme", "get"), set: __setFunctionName(function (value) { this.#resolvedTheme_accessor_storage = value; }, "#resolvedTheme", "set") }, _private_resolvedTheme_decorators, { kind: "accessor", name: "#resolvedTheme", static: false, private: true, access: { has: obj => #resolvedTheme in obj, get: obj => obj.#resolvedTheme, set: (obj, value) => { obj.#resolvedTheme = value; } }, metadata: _metadata }, _private_resolvedTheme_initializers, _private_resolvedTheme_extraInitializers);
253
+ __esDecorate(this, null, __ctx_decorators, { kind: "accessor", name: "_ctx", static: false, private: false, access: { has: obj => "_ctx" in obj, get: obj => obj._ctx, set: (obj, value) => { obj._ctx = value; } }, metadata: _metadata }, __ctx_initializers, __ctx_extraInitializers);
254
+ if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
255
+ }
256
+ static tagName = "dui-map";
257
+ static styles = [base, styles, mapThemeStyles];
258
+ #center_accessor_storage = __runInitializers(this, _center_initializers, [0, 0]);
259
+ /**
260
+ * Center coordinates as `[longitude, latitude]`.
261
+ * Accepts a JSON array string or is set programmatically.
262
+ */
263
+ get center() { return this.#center_accessor_storage; }
264
+ set center(value) { this.#center_accessor_storage = value; }
265
+ #zoom_accessor_storage = (__runInitializers(this, _center_extraInitializers), __runInitializers(this, _zoom_initializers, 1));
266
+ /** Zoom level (0–22). */
267
+ get zoom() { return this.#zoom_accessor_storage; }
268
+ set zoom(value) { this.#zoom_accessor_storage = value; }
269
+ #bearing_accessor_storage = (__runInitializers(this, _zoom_extraInitializers), __runInitializers(this, _bearing_initializers, 0));
270
+ /** Bearing (rotation) in degrees. */
271
+ get bearing() { return this.#bearing_accessor_storage; }
272
+ set bearing(value) { this.#bearing_accessor_storage = value; }
273
+ #pitch_accessor_storage = (__runInitializers(this, _bearing_extraInitializers), __runInitializers(this, _pitch_initializers, 0));
274
+ /** Pitch (tilt) in degrees. */
275
+ get pitch() { return this.#pitch_accessor_storage; }
276
+ set pitch(value) { this.#pitch_accessor_storage = value; }
277
+ #theme_accessor_storage = (__runInitializers(this, _pitch_extraInitializers), __runInitializers(this, _theme_initializers, undefined));
278
+ /** Force a specific theme. When unset, auto-detects from document. */
279
+ get theme() { return this.#theme_accessor_storage; }
280
+ set theme(value) { this.#theme_accessor_storage = value; }
281
+ #styleLight_accessor_storage = (__runInitializers(this, _theme_extraInitializers), __runInitializers(this, _styleLight_initializers, undefined));
282
+ /** Custom style URL for light theme. */
283
+ get styleLight() { return this.#styleLight_accessor_storage; }
284
+ set styleLight(value) { this.#styleLight_accessor_storage = value; }
285
+ #styleDark_accessor_storage = (__runInitializers(this, _styleLight_extraInitializers), __runInitializers(this, _styleDark_initializers, undefined));
286
+ /** Custom style URL for dark theme. */
287
+ get styleDark() { return this.#styleDark_accessor_storage; }
288
+ set styleDark(value) { this.#styleDark_accessor_storage = value; }
289
+ #loading_accessor_storage = (__runInitializers(this, _styleDark_extraInitializers), __runInitializers(this, _loading_initializers, false));
290
+ /** Show loading overlay. */
291
+ get loading() { return this.#loading_accessor_storage; }
292
+ set loading(value) { this.#loading_accessor_storage = value; }
293
+ #noWorldCopies_accessor_storage = (__runInitializers(this, _loading_extraInitializers), __runInitializers(this, _noWorldCopies_initializers, false));
294
+ /** Disable world copies (repeating map). */
295
+ get noWorldCopies() { return this.#noWorldCopies_accessor_storage; }
296
+ set noWorldCopies(value) { this.#noWorldCopies_accessor_storage = value; }
297
+ #controlled_accessor_storage = (__runInitializers(this, _noWorldCopies_extraInitializers), __runInitializers(this, _controlled_initializers, false));
298
+ /** Whether the viewport is controlled externally. */
299
+ get controlled() { return this.#controlled_accessor_storage; }
300
+ set controlled(value) { this.#controlled_accessor_storage = value; }
301
+ #minZoom_accessor_storage = (__runInitializers(this, _controlled_extraInitializers), __runInitializers(this, _minZoom_initializers, 0));
302
+ /** Minimum zoom level (0–22). */
303
+ get minZoom() { return this.#minZoom_accessor_storage; }
304
+ set minZoom(value) { this.#minZoom_accessor_storage = value; }
305
+ #maxZoom_accessor_storage = (__runInitializers(this, _minZoom_extraInitializers), __runInitializers(this, _maxZoom_initializers, 22));
306
+ /** Maximum zoom level (0–22). */
307
+ get maxZoom() { return this.#maxZoom_accessor_storage; }
308
+ set maxZoom(value) { this.#maxZoom_accessor_storage = value; }
309
+ #maxBounds_accessor_storage = (__runInitializers(this, _maxZoom_extraInitializers), __runInitializers(this, _maxBounds_initializers, undefined));
310
+ /** SW and NE corners constraining the viewable area. */
311
+ get maxBounds() { return this.#maxBounds_accessor_storage; }
312
+ set maxBounds(value) { this.#maxBounds_accessor_storage = value; }
313
+ #bounds_accessor_storage = (__runInitializers(this, _maxBounds_extraInitializers), __runInitializers(this, _bounds_initializers, undefined));
314
+ /** SW and NE corners as [[swLng, swLat], [neLng, neLat]]. Flies to fit when set. */
315
+ get bounds() { return this.#bounds_accessor_storage; }
316
+ set bounds(value) { this.#bounds_accessor_storage = value; }
317
+ #boundsPadding_accessor_storage = (__runInitializers(this, _bounds_extraInitializers), __runInitializers(this, _boundsPadding_initializers, 50));
318
+ /** Padding in pixels applied to fitBounds calls. */
319
+ get boundsPadding() { return this.#boundsPadding_accessor_storage; }
320
+ set boundsPadding(value) { this.#boundsPadding_accessor_storage = value; }
321
+ #mapInstance_accessor_storage = (__runInitializers(this, _boundsPadding_extraInitializers), __runInitializers(this, _private_mapInstance_initializers, null));
322
+ get #mapInstance() { return _private_mapInstance_descriptor.get.call(this); }
323
+ set #mapInstance(value) { return _private_mapInstance_descriptor.set.call(this, value); }
324
+ #isLoaded_accessor_storage = (__runInitializers(this, _private_mapInstance_extraInitializers), __runInitializers(this, _private_isLoaded_initializers, false));
325
+ get #isLoaded() { return _private_isLoaded_descriptor.get.call(this); }
326
+ set #isLoaded(value) { return _private_isLoaded_descriptor.set.call(this, value); }
327
+ #isStyleLoaded_accessor_storage = (__runInitializers(this, _private_isLoaded_extraInitializers), __runInitializers(this, _private_isStyleLoaded_initializers, false));
328
+ get #isStyleLoaded() { return _private_isStyleLoaded_descriptor.get.call(this); }
329
+ set #isStyleLoaded(value) { return _private_isStyleLoaded_descriptor.set.call(this, value); }
330
+ #resolvedTheme_accessor_storage = (__runInitializers(this, _private_isStyleLoaded_extraInitializers), __runInitializers(this, _private_resolvedTheme_initializers, getDocumentTheme() ?? getSystemTheme()));
331
+ get #resolvedTheme() { return _private_resolvedTheme_descriptor.get.call(this); }
332
+ set #resolvedTheme(value) { return _private_resolvedTheme_descriptor.set.call(this, value); }
333
+ #currentStyle = (__runInitializers(this, _private_resolvedTheme_extraInitializers), null);
334
+ #themeObserver = null;
335
+ #mediaQuery = null;
336
+ #mediaHandler = null;
337
+ #internalUpdate = false;
338
+ #resizeObserver = null;
339
+ #_ctx_accessor_storage = __runInitializers(this, __ctx_initializers, { map: null, isLoaded: false });
340
+ get _ctx() { return this.#_ctx_accessor_storage; }
341
+ set _ctx(value) { this.#_ctx_accessor_storage = value; }
342
+ #getMapStyle() {
343
+ if (this.#resolvedTheme === "dark") {
344
+ return this.styleDark ?? DEFAULT_STYLES.dark;
345
+ }
346
+ return this.styleLight ?? DEFAULT_STYLES.light;
347
+ }
348
+ connectedCallback() {
349
+ super.connectedCallback();
350
+ // Adopt MapLibre CSS into shadow root
351
+ this.shadowRoot.adoptedStyleSheets = [
352
+ ...this.shadowRoot.adoptedStyleSheets,
353
+ maplibreSheet,
354
+ ];
355
+ this.#startThemeDetection();
356
+ }
357
+ disconnectedCallback() {
358
+ super.disconnectedCallback();
359
+ this.#stopThemeDetection();
360
+ this.#destroyMap();
361
+ }
362
+ firstUpdated() {
363
+ this.#initMap();
364
+ }
365
+ updated(changed) {
366
+ // Theme change → swap style
367
+ if (this.#mapInstance && this.#currentStyle !== this.#getMapStyle()) {
368
+ this.#isStyleLoaded = false;
369
+ this.#currentStyle = this.#getMapStyle();
370
+ this.#mapInstance.setStyle(this.#currentStyle, { diff: true });
371
+ }
372
+ // Controlled viewport sync
373
+ if (this.controlled && this.#mapInstance && !this.#mapInstance.isMoving()) {
374
+ if (changed.has("center") || changed.has("zoom") || changed.has("bearing") || changed.has("pitch")) {
375
+ this.#syncViewport();
376
+ }
377
+ }
378
+ // Min/Max zoom
379
+ if (this.#mapInstance && changed.has("minZoom")) {
380
+ this.#mapInstance.setMinZoom(this.minZoom);
381
+ }
382
+ if (this.#mapInstance && changed.has("maxZoom")) {
383
+ this.#mapInstance.setMaxZoom(this.maxZoom);
384
+ }
385
+ // Max bounds
386
+ if (this.#mapInstance && changed.has("maxBounds")) {
387
+ this.#mapInstance.setMaxBounds(this.maxBounds ?? null);
388
+ }
389
+ // Bounds — fly to fit
390
+ if (this.#mapInstance && changed.has("bounds") && this.bounds) {
391
+ this.fitBounds(this.bounds, { padding: this.boundsPadding, duration: 500 });
392
+ }
393
+ // Update context only when values actually change
394
+ const isLoaded = this.#isLoaded && this.#isStyleLoaded;
395
+ if (this._ctx.map !== this.#mapInstance || this._ctx.isLoaded !== isLoaded) {
396
+ this._ctx = { map: this.#mapInstance, isLoaded };
397
+ }
398
+ }
399
+ /** Get the raw MapLibre GL instance. */
400
+ getMapInstance() {
401
+ return this.#mapInstance;
402
+ }
403
+ /**
404
+ * Suppress viewport-change events during an animation, then dispatch
405
+ * a single final event on moveend.
406
+ */
407
+ #animateAndDispatch(action) {
408
+ if (!this.#mapInstance)
409
+ return;
410
+ this.#internalUpdate = true;
411
+ action();
412
+ this.#mapInstance.once("moveend", () => {
413
+ this.#internalUpdate = false;
414
+ const c = this.#mapInstance.getCenter();
415
+ this.dispatchEvent(viewportChangeEvent({
416
+ center: [c.lng, c.lat],
417
+ zoom: this.#mapInstance.getZoom(),
418
+ bearing: this.#mapInstance.getBearing(),
419
+ pitch: this.#mapInstance.getPitch(),
420
+ }));
421
+ });
422
+ }
423
+ /** Animate to a position with a parabolic flight path. */
424
+ flyTo(options) {
425
+ this.#animateAndDispatch(() => {
426
+ this.#mapInstance.flyTo({
427
+ ...options,
428
+ duration: options.duration ?? 1500,
429
+ curve: options.curve ?? 1.42,
430
+ });
431
+ });
432
+ }
433
+ /** Animate to a position with a linear ease. */
434
+ easeTo(options) {
435
+ this.#animateAndDispatch(() => {
436
+ this.#mapInstance.easeTo({
437
+ ...options,
438
+ duration: options.duration ?? 500,
439
+ });
440
+ });
441
+ }
442
+ /** Fly to fit the given bounds. */
443
+ fitBounds(bounds, options) {
444
+ this.#animateAndDispatch(() => {
445
+ this.#mapInstance.fitBounds(bounds, {
446
+ padding: options?.padding ?? this.boundsPadding,
447
+ maxZoom: options?.maxZoom,
448
+ duration: options?.duration ?? 500,
449
+ });
450
+ });
451
+ }
452
+ /** Compute a bounding box from all child dui-map-marker elements and fly to fit them. */
453
+ fitToMarkers(options) {
454
+ const markers = this.querySelectorAll("dui-map-marker");
455
+ if (!markers.length)
456
+ return;
457
+ let minLng = Infinity, minLat = Infinity, maxLng = -Infinity, maxLat = -Infinity;
458
+ for (const marker of markers) {
459
+ const lng = marker.longitude;
460
+ const lat = marker.latitude;
461
+ if (lng < minLng)
462
+ minLng = lng;
463
+ if (lng > maxLng)
464
+ maxLng = lng;
465
+ if (lat < minLat)
466
+ minLat = lat;
467
+ if (lat > maxLat)
468
+ maxLat = lat;
469
+ }
470
+ this.fitBounds([[minLng, minLat], [maxLng, maxLat]], options);
471
+ }
472
+ #initMap() {
473
+ const container = this.shadowRoot.querySelector("[part='container']");
474
+ if (!container)
475
+ return;
476
+ const initialStyle = this.#getMapStyle();
477
+ this.#currentStyle = initialStyle;
478
+ const map = new MapLibreGL.Map({
479
+ container,
480
+ style: initialStyle,
481
+ center: this.center,
482
+ zoom: this.zoom,
483
+ bearing: this.bearing,
484
+ pitch: this.pitch,
485
+ minZoom: this.minZoom,
486
+ maxZoom: this.maxZoom,
487
+ maxBounds: this.maxBounds,
488
+ renderWorldCopies: !this.noWorldCopies,
489
+ attributionControl: { compact: true },
490
+ });
491
+ map.on("load", () => {
492
+ this.#isLoaded = true;
493
+ this.requestUpdate();
494
+ this.dispatchEvent(mapLoadEvent());
495
+ });
496
+ map.on("styledata", () => {
497
+ // Small delay to ensure style is fully processed
498
+ setTimeout(() => {
499
+ this.#isStyleLoaded = true;
500
+ this.requestUpdate();
501
+ }, 100);
502
+ });
503
+ map.on("move", () => {
504
+ if (this.#internalUpdate)
505
+ return;
506
+ const c = map.getCenter();
507
+ this.dispatchEvent(viewportChangeEvent({
508
+ center: [c.lng, c.lat],
509
+ zoom: map.getZoom(),
510
+ bearing: map.getBearing(),
511
+ pitch: map.getPitch(),
512
+ }));
513
+ });
514
+ // Map interaction events
515
+ map.on("click", (e) => {
516
+ this.dispatchEvent(mapClickEvent({
517
+ lngLat: { lng: e.lngLat.lng, lat: e.lngLat.lat },
518
+ point: { x: e.point.x, y: e.point.y },
519
+ }));
520
+ });
521
+ map.on("dblclick", (e) => {
522
+ this.dispatchEvent(mapDblClickEvent({
523
+ lngLat: { lng: e.lngLat.lng, lat: e.lngLat.lat },
524
+ point: { x: e.point.x, y: e.point.y },
525
+ }));
526
+ });
527
+ map.on("contextmenu", (e) => {
528
+ this.dispatchEvent(mapContextMenuEvent({
529
+ lngLat: { lng: e.lngLat.lng, lat: e.lngLat.lat },
530
+ point: { x: e.point.x, y: e.point.y },
531
+ }));
532
+ });
533
+ // ResizeObserver so map resizes when host element resizes
534
+ this.#resizeObserver = new ResizeObserver(() => {
535
+ map.resize();
536
+ });
537
+ this.#resizeObserver.observe(this);
538
+ this.#mapInstance = map;
539
+ // Context is updated in updated() — just trigger re-render
540
+ this.requestUpdate();
541
+ }
542
+ #destroyMap() {
543
+ this.#resizeObserver?.disconnect();
544
+ this.#resizeObserver = null;
545
+ if (this.#mapInstance) {
546
+ this.#mapInstance.remove();
547
+ this.#mapInstance = null;
548
+ }
549
+ this.#isLoaded = false;
550
+ this.#isStyleLoaded = false;
551
+ this._ctx = { map: null, isLoaded: false };
552
+ }
553
+ #syncViewport() {
554
+ const map = this.#mapInstance;
555
+ const current = map.getCenter();
556
+ const c = this.center;
557
+ if (current.lng === c[0] &&
558
+ current.lat === c[1] &&
559
+ map.getZoom() === this.zoom &&
560
+ map.getBearing() === this.bearing &&
561
+ map.getPitch() === this.pitch)
562
+ return;
563
+ this.#internalUpdate = true;
564
+ map.jumpTo({
565
+ center: this.center,
566
+ zoom: this.zoom,
567
+ bearing: this.bearing,
568
+ pitch: this.pitch,
569
+ });
570
+ this.#internalUpdate = false;
571
+ }
572
+ #startThemeDetection() {
573
+ if (this.theme) {
574
+ this.#resolvedTheme = this.theme;
575
+ return;
576
+ }
577
+ // Watch data-theme and class changes on <html>
578
+ this.#themeObserver = new MutationObserver(() => {
579
+ const docTheme = getDocumentTheme();
580
+ if (docTheme)
581
+ this.#resolvedTheme = docTheme;
582
+ });
583
+ this.#themeObserver.observe(document.documentElement, {
584
+ attributes: true,
585
+ attributeFilter: ["data-theme", "class"],
586
+ });
587
+ // Watch system preference
588
+ this.#mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
589
+ this.#mediaHandler = (e) => {
590
+ if (!getDocumentTheme()) {
591
+ this.#resolvedTheme = e.matches ? "dark" : "light";
592
+ }
593
+ };
594
+ this.#mediaQuery.addEventListener("change", this.#mediaHandler);
595
+ }
596
+ #stopThemeDetection() {
597
+ this.#themeObserver?.disconnect();
598
+ this.#themeObserver = null;
599
+ if (this.#mediaQuery && this.#mediaHandler) {
600
+ this.#mediaQuery.removeEventListener("change", this.#mediaHandler);
601
+ }
602
+ this.#mediaQuery = null;
603
+ this.#mediaHandler = null;
604
+ }
605
+ render() {
606
+ return html `
607
+ <div part="container">
608
+ ${(!this.#isLoaded || this.loading) ? html `
609
+ <div part="loader">
610
+ <div class="loader-dots">
611
+ <div class="loader-dot"></div>
612
+ <div class="loader-dot"></div>
613
+ <div class="loader-dot"></div>
614
+ </div>
615
+ </div>
616
+ ` : ""}
617
+ ${this.#mapInstance ? html `<slot></slot>` : ""}
618
+ </div>
619
+ `;
620
+ }
621
+ constructor() {
622
+ super(...arguments);
623
+ __runInitializers(this, __ctx_extraInitializers);
624
+ }
625
+ };
626
+ })();
627
+ export { DuiMap };
628
+ customElements.define(DuiMap.tagName, DuiMap);
@@ -0,0 +1,9 @@
1
+ import { DuiMapMarker, dragStartEvent, dragEvent, dragEndEvent } from "./map-marker.js";
2
+ import { DuiMapMarkerContent } from "./map-marker-content.js";
3
+ import { DuiMapMarkerPopup } from "./map-marker-popup.js";
4
+ import { DuiMapMarkerTooltip } from "./map-marker-tooltip.js";
5
+ import { DuiMapMarkerLabel } from "./map-marker-label.js";
6
+ export { DuiMapMarker, DuiMapMarkerContent, DuiMapMarkerPopup, DuiMapMarkerTooltip, DuiMapMarkerLabel, dragStartEvent, dragEvent, dragEndEvent, };
7
+ export { markerContext } from "./marker-context.js";
8
+ export type { MarkerContext } from "./marker-context.js";
9
+ export type { LngLat } from "./map-marker.js";
@@ -0,0 +1,7 @@
1
+ import { DuiMapMarker, dragStartEvent, dragEvent, dragEndEvent } from "./map-marker.js";
2
+ import { DuiMapMarkerContent } from "./map-marker-content.js";
3
+ import { DuiMapMarkerPopup } from "./map-marker-popup.js";
4
+ import { DuiMapMarkerTooltip } from "./map-marker-tooltip.js";
5
+ import { DuiMapMarkerLabel } from "./map-marker-label.js";
6
+ export { DuiMapMarker, DuiMapMarkerContent, DuiMapMarkerPopup, DuiMapMarkerTooltip, DuiMapMarkerLabel, dragStartEvent, dragEvent, dragEndEvent, };
7
+ export { markerContext } from "./marker-context.js";